Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / browser / components / search / content / search.xml
blob90a2e7ac4a631d802ae66e9b8406f1707fc782e9
1 <?xml version="1.0"?>
2 # -*- Mode: HTML -*-
3 # ***** BEGIN LICENSE BLOCK *****
4 # Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 # The contents of this file are subject to the Mozilla Public License Version
7 # 1.1 (the "License"); you may not use this file except in compliance with
8 # the License. You may obtain a copy of the License at
9 # http://www.mozilla.org/MPL/
11 # Software distributed under the License is distributed on an "AS IS" basis,
12 # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 # for the specific language governing rights and limitations under the
14 # License.
16 # The Original Code is mozilla.org browser.
18 # The Initial Developer of the Original Code is
19 # Joe Hewitt.
20 # Portions created by the Initial Developer are Copyright (C) 2003
21 # the Initial Developer. All Rights Reserved.
23 # Contributor(s):
24 #   Pierre Chanial (v2) <p_ch@verizon.net>
25 #   Gavin Sharp (v3) <gavin@gavinsharp.com>
26 #   Ben Goodger <beng@google.com>
27 #   Pamela Greene <pamg.bugs@gmail.com>
28 #   Michael Ventnor <m.ventnor@gmail.com>
29 #   Ehsan Akhgari <ehsan.akhgari@gmail.com>
31 # Alternatively, the contents of this file may be used under the terms of
32 # either the GNU General Public License Version 2 or later (the "GPL"), or
33 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
34 # in which case the provisions of the GPL or the LGPL are applicable instead
35 # of those above. If you wish to allow use of your version of this file only
36 # under the terms of either the GPL or the LGPL, and not to allow others to
37 # use your version of this file under the terms of the MPL, indicate your
38 # decision by deleting the provisions above and replace them with the notice
39 # and other provisions required by the GPL or the LGPL. If you do not delete
40 # the provisions above, a recipient may use your version of this file under
41 # the terms of any one of the MPL, the GPL or the LGPL.
43 # ***** END LICENSE BLOCK *****
45 <!DOCTYPE bindings [
46 <!ENTITY % searchBarDTD SYSTEM "chrome://browser/locale/searchbar.dtd" >
47 %searchBarDTD;
48 <!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
49 %globalDTD;
50 <!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
51 %browserDTD;
54 <bindings id="SearchBindings"
55       xmlns="http://www.mozilla.org/xbl"
56       xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
57       xmlns:xbl="http://www.mozilla.org/xbl">
59   <binding id="searchbar">
60     <resources>
61       <stylesheet src="chrome://browser/content/search/searchbarBindings.css"/>
62       <stylesheet src="chrome://browser/skin/searchbar.css"/>
63     </resources>
64     <content>
65       <xul:stringbundle src="chrome://browser/locale/search.properties"
66                         anonid="searchbar-stringbundle"/>
68       <xul:textbox class="searchbar-textbox"
69                    anonid="searchbar-textbox"
70                    type="autocomplete"
71                    flex="1"
72                    autocompletepopup="PopupAutoComplete"
73                    autocompletesearch="search-autocomplete"
74                    autocompletesearchparam="searchbar-history"
75                    timeout="250"
76                    maxrows="10"
77                    completeselectedindex="true"
78                    showcommentcolumn="true"
79                    tabscrolling="true"
80                    xbl:inherits="disabled,disableautocomplete,searchengine,src,newlines">
81         <xul:button class="searchbar-engine-button"
82                     type="menu"
83                     anonid="searchbar-engine-button"
84                     popup="_child"
85                     chromedir="&locale.dir;">
86           <xul:image class="searchbar-engine-image" xbl:inherits="src"/>
87           <xul:image class="searchbar-dropmarker-image"/>
88           <xul:menupopup class="searchbar-popup"
89                          anonid="searchbar-popup"
90                          position="after_start">
91             <xul:menuseparator/>
92             <xul:menuitem class="open-engine-manager"
93                           anonid="open-engine-manager"
94                           label="&cmd_engineManager.label;"
95 # The empty tooltiptext attribute is here to avoid bug 336231
96                           tooltiptext=""
97                           oncommand="openManager(event);"/>
98           </xul:menupopup>
99         </xul:button>
100         <xul:hbox class="search-go-container" chromedir="&locale.dir;">
101           <xul:image class="search-go-button"
102                      anonid="search-go-button"
103                      chromedir="&locale.dir;"
104                      onclick="handleSearchCommand(event);"
105                      tooltiptext="&searchEndCap.label;" />
106         </xul:hbox>
107       </xul:textbox>
108     </content>
110     <implementation implements="nsIObserver">
112       <constructor><![CDATA[
113         if (this.parentNode.parentNode.localName == "toolbarpaletteitem")
114           return;
115         setTimeout(function (a) { a.init(); }, 0, this);
116       ]]></constructor>
118       <method name="init">
119         <body><![CDATA[
120           // Make sure we rebuild the popup in onpopupshowing
121           this._needToBuildPopup = true;
123           // Refresh the display (updating icon, etc)
124           this.updateDisplay();
126           var os =
127                Components.classes["@mozilla.org/observer-service;1"]
128                          .getService(Components.interfaces.nsIObserverService);
129           os.addObserver(this, "browser-search-engine-modified", false);
130           
131           this._addedObserver = true;
132         ]]></body>
133       </method>
135       <destructor><![CDATA[
136         if (this._addedObserver) {
137           var os = Components.classes["@mozilla.org/observer-service;1"]
138                              .getService(Components.interfaces.nsIObserverService);
139           os.removeObserver(this, "browser-search-engine-modified");
140         }
142         // Make sure to break the cycle from _texbox to us. Otherwise we leak
143         // the world. But make sure it's actually pointing to us.
144         if (this._textbox.mController.input == this)
145           this._textbox.mController.input = null;
146       ]]></destructor>
148       <field name="_stringBundle">document.getAnonymousElementByAttribute(this,
149           "anonid", "searchbar-stringbundle");</field>
150       <field name="_textbox">document.getAnonymousElementByAttribute(this,
151           "anonid", "searchbar-textbox");</field>
152       <field name="_popup">document.getAnonymousElementByAttribute(this,
153           "anonid", "searchbar-popup");</field>
154       <field name="_ss">null</field>
155       <field name="_engines">null</field>
157       <property name="engines" readonly="true">
158         <getter><![CDATA[
159           if (!this._engines)
160             this._engines = this.searchService.getVisibleEngines({ });
161           return this._engines;
162         ]]></getter>
163       </property>
165       <field name="searchButton">document.getAnonymousElementByAttribute(this,
166           "anonid", "searchbar-engine-button");</field>
168       <property name="currentEngine"
169                 onset="this.searchService.currentEngine = val; return val;">
170         <getter><![CDATA[
171           var currentEngine = this.searchService.currentEngine;
172           // Return a dummy engine if there is no currentEngine
173           return currentEngine || {name:"", uri:null};
174         ]]></getter>
175       </property>
177       <!-- textbox is used by sanitize.js to clear the undo history when
178            clearing form information. -->
179       <property name="textbox" readonly="true"
180                 onget="return this._textbox;"/>
182       <property name="searchService" readonly="true">
183         <getter><![CDATA[
184           if (!this._ss) {
185             const nsIBSS = Components.interfaces.nsIBrowserSearchService;
186             this._ss =
187                  Components.classes["@mozilla.org/browser/search-service;1"]
188                            .getService(nsIBSS);
189           }
190           return this._ss;
191         ]]></getter>
192       </property>
194       <property name="value" onget="return this._textbox.value;"
195                              onset="return this._textbox.value = val;"/>
197       <method name="focus">
198         <body><![CDATA[
199           this._textbox.focus();
200         ]]></body>
201       </method>
203       <method name="select">
204         <body><![CDATA[
205           this._textbox.select();
206         ]]></body>
207       </method>
209       <method name="observe">
210         <parameter name="aEngine"/>
211         <parameter name="aTopic"/>
212         <parameter name="aVerb"/>
213         <body><![CDATA[
214           if (aTopic == "browser-search-engine-modified") {
215             switch (aVerb) {
216             case "engine-removed":
217               this.offerNewEngine(aEngine);
218               break;
219             case "engine-added":
220               this.hideNewEngine(aEngine);
221               break;
222             case "engine-current":
223               // The current engine was changed.  Rebuilding the menu appears to
224               // confuse its idea of whether it should be open when it's just
225               // been clicked, so we force it to close now.
226               this._popup.hidePopup();
227               break;
228             case "engine-changed":
229               // An engine was removed (or hidden) or added, or an icon was
230               // changed.  Do nothing special.
231             }
233             // Make sure the engine list is refetched next time it's needed
234             this._engines = null;
236             // Rebuild the popup and update the display after any modification.
237             this.rebuildPopup();
238             this.updateDisplay();
239           }
240         ]]></body>
241       </method>
243       <!-- There are two seaprate lists of search engines, whose uses intersect
244       in this file.  The search service (nsIBrowserSearchService and
245       nsSearchService.js) maintains a list of Engine objects which is used to
246       populate the searchbox list of available engines and to perform queries.
247       That list is accessed here via this.SearchService, and it's that sort of
248       Engine that is passed to this binding's observer as aEngine.
250       In addition, browser.js fills two lists of autodetected search engines
251       (browser.engines and browser.hiddenEngines) as properties of
252       mCurrentBrowser.  Those lists contain unnamed JS objects of the form
253       { uri:, title:, icon: }, and that's what the searchbar uses to determine
254       whether to show any "Add <EngineName>" menu items in the drop-down.
256       The two types of engines are currently related by their identifying
257       titles (the Engine object's 'name'), although that may change; see bug
258       335102.  -->
260       <!-- If the engine that was just removed from the searchbox list was
261       autodetected on this page, move it to each browser's active list so it
262       will be offered to be added again. -->
263       <method name="offerNewEngine">
264         <parameter name="aEngine"/>
265         <body><![CDATA[
266           var allbrowsers = getBrowser().mPanelContainer.childNodes;
267           for (var tab = 0; tab < allbrowsers.length; tab++) {
268             var browser = getBrowser().getBrowserAtIndex(tab);
269             if (browser.hiddenEngines) {
270               // XXX This will need to be changed when engines are identified by
271               // URL rather than title; see bug 335102.
272               var removeTitle = aEngine.wrappedJSObject.name;
273               for (var i = 0; i < browser.hiddenEngines.length; i++) {
274                 if (browser.hiddenEngines[i].title == removeTitle) {
275                   if (!browser.engines)
276                     browser.engines = [];
277                   browser.engines.push(browser.hiddenEngines[i]);
278                   browser.hiddenEngines.splice(i, 1);
279                   break;
280                 }
281               }
282             }
283           }
284           BrowserSearch.updateSearchButton();
285         ]]></body>
286       </method>
288       <!-- If the engine that was just added to the searchbox list was
289       autodetected on this page, move it to each browser's hidden list so it is
290       no longer offered to be added. -->
291       <method name="hideNewEngine">
292         <parameter name="aEngine"/>
293         <body><![CDATA[
294           var allbrowsers = getBrowser().mPanelContainer.childNodes;
295           for (var tab = 0; tab < allbrowsers.length; tab++) {
296             var browser = getBrowser().getBrowserAtIndex(tab);
297             if (browser.engines) {
298               // XXX This will need to be changed when engines are identified by
299               // URL rather than title; see bug 335102.
300               var removeTitle = aEngine.wrappedJSObject.name;
301               for (var i = 0; i < browser.engines.length; i++) {
302                 if (browser.engines[i].title == removeTitle) {
303                   if (!browser.hiddenEngines)
304                     browser.hiddenEngines = [];
305                   browser.hiddenEngines.push(browser.engines[i]);
306                   browser.engines.splice(i, 1);
307                   break;
308                 }
309               }
310             }
311           }
312           BrowserSearch.updateSearchButton();
313         ]]></body>
314       </method>
316       <method name="updateDisplay">
317         <body><![CDATA[
318           var uri = this.currentEngine.iconURI;
319           this.setAttribute("src", uri ? uri.spec : "");
321           var name = this.currentEngine.name;
322           var text = this._stringBundle.getFormattedString("searchtip", [name]);
323           this._textbox.emptyText = name;
324           this._textbox.label = text;
325           this._textbox.tooltipText = text;
326         ]]></body>
327       </method>
329       <!-- Rebuilds the dynamic portion of the popup menu (i.e., the menu items
330            for new search engines that can be added to the available list).  This
331            is called each time the popup is shown.
332       -->
333       <method name="rebuildPopupDynamic">
334         <body><![CDATA[
335           // We might not have added the main popup items yet, do that first
336           // if needed.
337           if (this._needToBuildPopup)
338             this.rebuildPopup();
340           var popup = this._popup;
341           // Clear any addengine menuitems, including addengine-item entries and
342           // the addengine-separator.  Work backward to avoid invalidating the
343           // indexes as items are removed.
344           var items = popup.childNodes;
345           for (var i = items.length - 1; i >= 0; i--) {
346             if (items[i].getAttribute("class").indexOf("addengine") != -1)
347               popup.removeChild(items[i]);
348           }
350           var addengines = getBrowser().mCurrentBrowser.engines;
351           if (addengines && addengines.length > 0) {
352             const kXULNS =
353                "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
355             // Find the (first) separator in the remaining menu, or the first item
356             // if no separators are present.
357             var insertLocation = popup.firstChild;
358             while (insertLocation.nextSibling &&
359                    insertLocation.localName != "menuseparator") {
360               insertLocation = insertLocation.nextSibling;
361             }
362             if (insertLocation.localName != "menuseparator")
363               insertLocation = popup.firstChild;
365             var separator = document.createElementNS(kXULNS, "menuseparator");
366             separator.setAttribute("class", "addengine-separator");
367             popup.insertBefore(separator, insertLocation);
369             // Insert the "add this engine" items.
370             for (var i = 0; i < addengines.length; i++) {
371               var menuitem = document.createElement("menuitem");
372               var engineInfo = addengines[i];
373               var labelStr =
374                   this._stringBundle.getFormattedString("cmd_addFoundEngine",
375                                                         [engineInfo.title]);
376               menuitem = document.createElementNS(kXULNS, "menuitem");
377               menuitem.setAttribute("class", "menuitem-iconic addengine-item");
378               menuitem.setAttribute("label", labelStr);
379               menuitem.setAttribute("tooltiptext", engineInfo.uri);
380               menuitem.setAttribute("uri", engineInfo.uri);
381               if (engineInfo.icon)
382                 menuitem.setAttribute("src", engineInfo.icon);
383               menuitem.setAttribute("title", engineInfo.title);
384               popup.insertBefore(menuitem, insertLocation);
385             }
386           }
387         ]]></body>
388       </method>
390       <!-- Rebuilds the list of visible search engines in the menu.  Does not remove
391            or update any dynamic entries (i.e., "Add this engine" items) nor the
392            Manage Engines item.  This is called by the observer when the list of
393            visible engines, or the currently selected engine, has changed.
394       -->
395       <method name="rebuildPopup">
396         <body><![CDATA[
397           var popup = this._popup;
399           // Clear the popup, down to the first separator
400           while (popup.firstChild && popup.firstChild.localName != "menuseparator")
401             popup.removeChild(popup.firstChild);
403           const kXULNS =
404                "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
406           var engines = this.engines;
407           for (var i = engines.length - 1; i >= 0; --i) {
408             var menuitem = document.createElementNS(kXULNS, "menuitem");
409             var name = engines[i].name;
410             menuitem.setAttribute("label", name);
411             menuitem.setAttribute("id", name);
412             menuitem.setAttribute("class", "menuitem-iconic searchbar-engine-menuitem");
413             // Since this menu is rebuilt by the observer method whenever a new
414             // engine is selected, the "selected" attribute does not need to be
415             // explicitly cleared anywhere.
416             if (engines[i] == this.currentEngine)
417               menuitem.setAttribute("selected", "true");
418             var tooltip = this._stringBundle.getFormattedString("searchtip", [name]);
419             menuitem.setAttribute("tooltiptext", tooltip);
420             if (engines[i].iconURI)
421               menuitem.setAttribute("src", engines[i].iconURI.spec);
422             popup.insertBefore(menuitem, popup.firstChild);
423             menuitem.engine = engines[i];
424           }
426           this._needToBuildPopup = false;
427         ]]></body>
428       </method>
430       <method name="openManager">
431         <parameter name="aEvent"/>
432         <body><![CDATA[
433           var wm =
434                 Components.classes["@mozilla.org/appshell/window-mediator;1"]
435                           .getService(Components.interfaces.nsIWindowMediator);
437           var window = wm.getMostRecentWindow("Browser:SearchManager");
438           if (window)
439             window.focus()
440           else {
441             setTimeout(function () {
442               openDialog("chrome://browser/content/search/engineManager.xul",
443                          "_blank", "chrome,dialog,modal,centerscreen");
444             }, 0);
445           }
446         ]]></body>
447       </method>
449       <method name="selectEngine">
450         <parameter name="aEvent"/>
451         <parameter name="isNextEngine"/>
452         <body><![CDATA[
453           // Find the new index
454           var newIndex = this.engines.indexOf(this.currentEngine);
455           newIndex += (isNextEngine) ? 1 : -1;
457           if (newIndex >= 0 && newIndex < this.engines.length)
458             this.currentEngine = this.engines[newIndex];
460           aEvent.preventDefault();
461           aEvent.stopPropagation();
462         ]]></body>
463       </method>
465       <method name="handleSearchCommand">
466         <parameter name="aEvent"/>
467         <body><![CDATA[
468           var textBox = this._textbox;
469           var textValue = textBox.value;
471           var where = "current";
472           if (aEvent && aEvent.originalTarget.getAttribute("anonid") == "search-go-button") {
473             if (aEvent.button == 2)
474               return;
475             where = whereToOpenLink(aEvent, false, true);
476           }
477           else {
478             var newTabPref = textBox._prefBranch.getBoolPref("browser.search.openintab");
479             if ((aEvent && aEvent.altKey) ^ newTabPref)
480               where = "tab";
481           }
483           // Save the current value in the form history
484           if (textValue) {
485             textBox._formHistSvc.addEntry(textBox.getAttribute("autocompletesearchparam"),
486                                           textValue);
487           }
489           this.doSearch(textValue, where);
490         ]]></body>
491       </method>
493       <method name="doSearch">
494         <parameter name="aData"/>
495         <parameter name="aWhere"/>
496         <body><![CDATA[
497           // null parameter below specifies HTML response for search
498           var submission = this.currentEngine.getSubmission(aData, null);
499           openUILinkIn(submission.uri.spec, aWhere, null, submission.postData);
500         ]]></body>
501       </method>
503     </implementation>
505     <handlers>
506       <handler event="command"><![CDATA[
507         const target = event.originalTarget;
508         if (target.getAttribute("class").indexOf("addengine-item") != -1) {
509           var searchService =
510             Components.classes["@mozilla.org/browser/search-service;1"]
511                       .getService(Components.interfaces.nsIBrowserSearchService);
512           // We only detect OpenSearch files
513           var type = Components.interfaces.nsISearchEngine.DATA_XML;
514           searchService.addEngine(target.getAttribute("uri"), type,
515                                   target.getAttribute("src"), false);
516         }
517         else if (target.engine)
518           this.currentEngine = target.engine;
519         else
520           return;
522         this.focus();
523         this.select();
524       ]]></handler>
526       <handler event="popupshowing" action="this.rebuildPopupDynamic();"/>
528       <handler event="DOMMouseScroll"
529                phase="capturing"
530 #ifdef XP_MACOSX
531                action="if (event.metaKey) this.selectEngine(event, (event.detail > 0));"/>
532 #else
533                action="if (event.ctrlKey) this.selectEngine(event, (event.detail > 0));"/>
534 #endif
535     </handlers>
536   </binding>
538   <binding id="searchbar-textbox"
539       extends="chrome://global/content/bindings/autocomplete.xml#autocomplete">
540     <implementation implements="nsIObserver">
541       <constructor><![CDATA[
542         if (document.getBindingParent(this).parentNode.parentNode.localName ==
543             "toolbarpaletteitem")
544           return;
545         setTimeout(function(a) { a.initialize(); }, 0, this);
546       ]]></constructor>
548       <destructor><![CDATA[
549           var ps2 = Components.classes["@mozilla.org/preferences-service;1"]
550                               .getService(Components.interfaces.nsIPrefBranch2);
551           ps2.removeObserver("browser.search.suggest.enabled", this);
553         // Because XBL and the customize toolbar code interacts poorly,
554         // there may not be anything to remove here
555         try {
556           this.controllers.removeController(this.searchbarController);
557         } catch (ex) { }
558       ]]></destructor>
560       <field name="_stringBundle"/>
561       <field name="_formHistSvc"/>
562       <field name="_prefBranch"/>
563       <field name="_suggestMenuItem"/>
564       <field name="_suggestEnabled"/>
566       <method name="initialize">
567         <body><![CDATA[
568           const kXULNS =
569             "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
570           // Initialize fields
571           this._stringBundle = document.getBindingParent(this)._stringBundle;
572           this._formHistSvc =
573                    Components.classes["@mozilla.org/satchel/form-history;1"]
574                              .getService(Components.interfaces.nsIFormHistory2);
575           this._prefBranch =
576                     Components.classes["@mozilla.org/preferences-service;1"]
577                               .getService(Components.interfaces.nsIPrefBranch);
578           this._suggestEnabled =
579               this._prefBranch.getBoolPref("browser.search.suggest.enabled");
581           if (this._prefBranch.getBoolPref("browser.urlbar.clickSelectsAll"))
582             this.setAttribute("clickSelectsAll", true);
584           // Add items to context menu and attach controller to handle them
585           var textBox = document.getAnonymousElementByAttribute(this,
586                                                 "anonid", "textbox-input-box");
587           var cxmenu = document.getAnonymousElementByAttribute(textBox,
588                                             "anonid", "input-box-contextmenu");
590           var element = document.createElementNS(kXULNS, "menuseparator");
591           cxmenu.appendChild(element);
592           element = document.createElementNS(kXULNS, "menuitem");
593           var label = this._stringBundle.getString("cmd_clearHistory");
594           var akey = this._stringBundle.getString("cmd_clearHistory_accesskey");
595           element.setAttribute("label", label);
596           element.setAttribute("accesskey", akey);
597           element.setAttribute("cmd", "cmd_clearhistory");
599           cxmenu.appendChild(element);
601           element = document.createElementNS(kXULNS, "menuitem");
602           label = this._stringBundle.getString("cmd_showSuggestions");
603           akey = this._stringBundle.getString("cmd_showSuggestions_accesskey");
604           element.setAttribute("anonid", "toggle-suggest-item");
605           element.setAttribute("label", label);
606           element.setAttribute("accesskey", akey);
607           element.setAttribute("cmd", "cmd_togglesuggest");
608           element.setAttribute("type", "checkbox");
609           element.setAttribute("checked", this._suggestEnabled);
610           element.setAttribute("autocheck", "false");
612           this._suggestMenuItem = element;
613           cxmenu.appendChild(element);
615           this.controllers.appendController(this.searchbarController);
617           // Add observer for suggest preference
618           var ps2 = Components.classes["@mozilla.org/preferences-service;1"]
619                               .getService(Components.interfaces.nsIPrefBranch2);
620           ps2.addObserver("browser.search.suggest.enabled", this, false);
621         ]]></body>
622       </method>
624       <method name="openPopup">
625         <body><![CDATA[
626           var popup = this.popup;
627           if (!popup.mPopupOpen) {
628             // Initially the panel used for the searchbar (PopupAutoComplete
629             // in browser.xul) is hidden to avoid impacting startup / new
630             // window performance. The base binding's openPopup would normally
631             // call the overriden openAutocompletePopup in urlbarBindings.xml's
632             // browser-autocomplete-result-popup binding to unhide the popup,
633             // but since we're overriding openPopup we need to unhide the panel
634             // ourselves.
635             popup.hidden = false;
637             popup.mInput = this;
638             popup.view = this.controller.QueryInterface(Components.interfaces.nsITreeView);
639             popup.invalidate();
640             
641             popup.showCommentColumn = this.showCommentColumn;
642             popup.showImageColumn = this.showImageColumn;
644             document.popupNode = null;
646             var outerRect = this.getBoundingClientRect();
647             var innerRect = this.inputField.getBoundingClientRect();
648             var width = outerRect.right - innerRect.left;
649             popup.setAttribute("width", width > 100 ? width : 100);
651             // setConsumeRollupEvent() before we call openPopup(), 
652             // see bug #404438 for more details
653             popup.popupBoxObject.setConsumeRollupEvent(
654               this.consumeRollupEvent ? 
655                 Ci.nsIPopupBoxObject.ROLLUP_CONSUME : 
656                 Ci.nsIPopupBoxObject.ROLLUP_NO_CONSUME);
657             popup.openPopup(null, "", innerRect.left, outerRect.bottom, false, false);
658           }
659         ]]></body>
660       </method>
662       <method name="observe">
663         <parameter name="aSubject"/>
664         <parameter name="aTopic"/>
665         <parameter name="aData"/>
666         <body><![CDATA[
667           if (aTopic == "nsPref:changed") {
668             this._suggestEnabled =
669               this._prefBranch.getBoolPref("browser.search.suggest.enabled");
670             this._suggestMenuItem.setAttribute("checked", this._suggestEnabled);
671           }
672         ]]></body>
673       </method>
675       <method name="openSearch">
676         <body>
677           <![CDATA[
678             // Don't open search popup if history popup is open
679             if (!this.popupOpen) {
680               document.getBindingParent(this).searchButton.open = true;
681               return false;
682             }
683             return true;
684           ]]>
685         </body>
686       </method>
688       <!-- overload |onTextEntered| in autocomplete.xml -->
689       <method name="onTextEntered">
690         <parameter name="aEvent"/>
691         <body><![CDATA[
692           var evt = aEvent || this.mEnterEvent;
693           document.getBindingParent(this).handleSearchCommand(evt);
694           this.mEnterEvent = null;
695         ]]></body>
696       </method>
698       <!-- nsIController -->
699       <field name="searchbarController" readonly="true"><![CDATA[({
700         _self: this,
701         supportsCommand: function(aCommand) {
702           return aCommand == "cmd_clearhistory" ||
703                  aCommand == "cmd_togglesuggest";
704         },
706         isCommandEnabled: function(aCommand) {
707           if (aCommand == "cmd_clearhistory") {
708             var param = this._self.getAttribute("autocompletesearchparam");
709             return this._self._formHistSvc.nameExists(param);
710           }
711           return true;
712         },
714         doCommand: function (aCommand) {
715           switch (aCommand) {
716             case "cmd_clearhistory":
717               var param = this._self.getAttribute("autocompletesearchparam");
718               this._self._formHistSvc.removeEntriesForName(param);
719               this._self.value = "";
720               break;
721             case "cmd_togglesuggest":
722               // The pref observer will update _suggestEnabled and the menu
723               // checkmark.
724               this._self._prefBranch.setBoolPref("browser.search.suggest.enabled",
725                                                  !this._self._suggestEnabled);
726               break;
727             default:
728               // do nothing with unrecognized command
729           }
730         }
731       })]]></field>
733       <!-- DND Observer -->
734       <field name="searchbarDNDObserver" readonly="true"><![CDATA[({
735         mOuter: this,
737         onDrop: function (aEvent, aXferData, aDragSession) {
738           var data = transferUtils.retrieveURLFromData(aXferData.data,
739                          aXferData.flavour.contentType);
740           if (data) {
741             this.mOuter.value = data;
742             this.mOuter.onTextEntered(aEvent);
743           }
744         },
746         getSupportedFlavours: function () {
747           var flavourSet = new FlavourSet();
749           flavourSet.appendFlavour("text/unicode");
750           flavourSet.appendFlavour("text/x-moz-url");
751           flavourSet.appendFlavour("application/x-moz-file", "nsIFile");
752           return flavourSet;
753         }
754       })]]></field>
755     </implementation>
757     <handlers>
758       <handler event="keypress" keycode="VK_UP" modifiers="accel"
759                phase="capturing"
760                action="document.getBindingParent(this).selectEngine(event, false);"/>
762       <handler event="keypress" keycode="VK_DOWN" modifiers="accel"
763                phase="capturing"
764                action="document.getBindingParent(this).selectEngine(event, true);"/>
766       <handler event="keypress" keycode="VK_DOWN" modifiers="alt"
767                phase="capturing"
768                action="return this.openSearch();"/>
770       <handler event="keypress" keycode="VK_UP" modifiers="alt"
771                phase="capturing"
772                action="return this.openSearch();"/>
774 #ifndef XP_MACOSX
775       <handler event="keypress" keycode="VK_F4"
776                phase="capturing"
777                action="return this.openSearch();"/>
778 #endif
780       <handler event="drop" phase="capturing">
781         nsDragAndDrop.drop(event, this.searchbarDNDObserver);
782       </handler>
784     </handlers>
785   </binding>
786 </bindings>