suite/browser/urlbarBindings.xml
author Robert Kaiser <kairo@kairo.at>
Mon, 18 Aug 2008 17:10:55 +0200
changeset 131 5dd97780d577ed346d9cf5198fbd4f05fd6c0f0b
parent 41 4cb9ccd2a1ca2a88d630c01adc67517615cfdaf0
child 3379 092911915d6089b9c8128c2ba83dd693332f281e
permissions -rw-r--r--
Backed out changeset bad4bd9c53c5 due to breakage on mac.

<?xml version="1.0"?>

<bindings id="urlbarBindings"
          xmlns="http://www.mozilla.org/xbl"
          xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
          xmlns:xbl="http://www.mozilla.org/xbl">

  <binding id="urlbar" extends="chrome://global/content/autocomplete.xml#autocomplete">
    <implementation>
      <constructor><![CDATA[
        var pbi = this.mPrefs.QueryInterface(Components.interfaces.nsIPrefBranch2);
        if (pbi)
          pbi.addObserver("browser.urlbar", this.mPrefObserver, false);
        
        this.updatePref("browser.urlbar.showPopup");
        this.updatePref("browser.urlbar.autoFill");
        this.updatePref("browser.urlbar.showSearch");
      ]]></constructor>

      <destructor><![CDATA[
        var pbi = this.mPrefs.QueryInterface(Components.interfaces.nsIPrefBranch2);
        if (pbi)
          pbi.removeObserver("browser.urlbar", this.mPrefObserver);
      ]]></destructor>

      <field name="mPrefs">
        var svc = Components.classes["@mozilla.org/preferences-service;1"]
                            .getService(Components.interfaces.nsIPrefService);
        svc.getBranch(null);
      </field>

      <field name="mPrefObserver"><![CDATA[
        ({
          urlbar: this,
          
          observe: function(aObserver, aBlah, aPref) {
            if (/^browser\.urlbar\./.test(aPref))
              this.urlbar.updatePref(aPref);
          }
        });
      ]]></field>

      <method name="updatePref">
        <parameter name="aPref"/>
        <body><![CDATA[
          if (aPref == "browser.urlbar.showPopup") {
            this.showPopup = this.mPrefs.getBoolPref("browser.urlbar.showPopup");
          } else if (aPref == "browser.urlbar.autoFill") {
            this.autoFill = this.mPrefs.getBoolPref("browser.urlbar.autoFill");
          } else if (aPref == "browser.urlbar.showSearch") {
            this.minResultsForPopup = this.mPrefs.getBoolPref("browser.urlbar.showSearch") ?
                                      0 : 1;
          }
        ]]></body>
      </method>
      
    </implementation>
  </binding>
  
  <binding id="autocomplete-result-popup" extends="chrome://global/content/autocomplete.xml#autocomplete-result-popup">
    <content>
      <xul:tree anonid="tree" class="autocomplete-tree plain" flex="1">
        <xul:treecols anonid="treecols">
          <xul:treecol class="autocomplete-treecol" id="treecolAutoCompleteValue" flex="2"/>
          <xul:treecol class="autocomplete-treecol" id="treecolAutoCompleteComment" flex="1" hidden="true"/>
        </xul:treecols>
        <xul:treechildren anonid="treebody" class="autocomplete-treebody" flex="1"/>
      </xul:tree>
      <xul:box role="search-box" class="autocomplete-search-box"/>
    </content>
    
    <implementation>
      <constructor><![CDATA[
        // listen for changes to default search engine
        var pbi = this.mPrefs.QueryInterface(Components.interfaces.nsIPrefBranch2);
        if (pbi) {
          pbi.addObserver("browser.search", this.mPrefObserver, false);
          pbi.addObserver("browser.urlbar", this.mPrefObserver, false);
        }
      ]]></constructor>

      <destructor><![CDATA[
        var pbi = this.mPrefs.QueryInterface(Components.interfaces.nsIPrefBranch2);
        if (pbi) {
          pbi.removeObserver("browser.search", this.mPrefObserver);
          pbi.removeObserver("browser.urlbar", this.mPrefObserver);
        }
      ]]></destructor>

      <property name="showSearch" onget="return this.mShowSearch;">
        <setter><![CDATA[
          this.mShowSearch = val;
          if (val) {
            this.updateEngines();
            this.mSearchBox.removeAttribute("hidden");
          } else {
            this.clearEngines();
            this.mSearchBox.setAttribute("hidden", "true");
          }
        ]]></setter>
      </property>
      
      <property name="defaultSearchEngine"
                onget="return this.textbox.getAttribute('defaultSearchEngine') == 'true';"
                onset="this.textbox.setAttribute('defaultSearchEngine', val); return val;"/>

      <field name="mSearchBox">
         document.getAnonymousElementByAttribute(this, "role", "search-box");
      </field>

      <field name="mPrefs">
        var svc = Components.classes["@mozilla.org/preferences-service;1"]
                            .getService(Components.interfaces.nsIPrefService);
        svc.getBranch(null);
      </field>

      <field name="mPrefObserver"><![CDATA[
        ({
          resultsPopup: this,
          
          observe: function(aObserver, aBlah, aPref) {
            if (/^browser\.search\./.test(aPref))
              this.resultsPopup.updateEngines();
            else if (/^browser\.urlbar\./.test(aPref))
              this.resultsPopup.updatePref(aPref);
          }
        });
      ]]></field>

      <field name="mInputListener"><![CDATA[
        (function(aEvent) {
          // "this" is the textbox, not the popup
          if (this.mSearchInputTO)
            window.clearTimeout(this.mSearchInputTO);
          this.mSearchInputTO = window.setTimeout(this.resultsPopup.mInputTimeout, this.timeout, this);
        });
      ]]></field>

      <field name="mInputTimeout"><![CDATA[
        (function(me) {
          me.resultsPopup.mSearchBox.searchValue = me.value;
          me.mSearchInputTO = 0;
        });
      ]]></field>

      <field name="mEnginesReady">false</field>
      
      <property name="overrideValue" readonly="true">
        <getter><![CDATA[
          if (this.mSearchBox.selectedIndex != -1) {
            // save the value.  RevealSearchPanel can close the popup
            var returnValue = this.mSearchBox.overrideValue;
            try {
              if (pref.getBoolPref("browser.search.opensidebarsearchpanel"))
                RevealSearchPanel();
            } catch (ex) {
            }
            return returnValue;
          }
          return null;
        ]]></getter>
      </property>

      <method name="updatePref">
        <parameter name="aPref"/>
        <body><![CDATA[
          if (aPref == "browser.urlbar.showSearch")
            this.showSearch = this.mPrefs.getBoolPref("browser.urlbar.showSearch");
        ]]></body>
      </method>
      
      <method name="addEngine">
        <parameter name="aEngineId"/>
        <parameter name="aName"/>
        <parameter name="aIcon"/>
        <parameter name="aSearchBarUrl"/>
        <body><![CDATA[
          var box = document.createElement("box");
          box.setAttribute("class", "autocomplete-search-engine");
          box.setAttribute("searchEngine", aEngineId);
          box.setAttribute("name", aName);
          box.setAttribute("icon", aIcon);
          box.setAttribute("searchBarUrl", aSearchBarUrl);
          box.setAttribute("engineIndex", this.childNodes.length);
          this.mSearchBox.appendChild(box);
        ]]></body>
      </method>

      <method name="clearEngines">
        <body><![CDATA[
          while (this.mSearchBox.hasChildNodes())
            this.mSearchBox.removeChild(this.mSearchBox.lastChild);
        ]]></body>
      </method>
   
      <method name="updateEngines">
        <body><![CDATA[
          var rdf = Components.classes["@mozilla.org/rdf/rdf-service;1"]
                      .getService(Components.interfaces.nsIRDFService);
          try {
            var ds = rdf.GetDataSource("rdf:internetsearch");
          } catch (ex) {
            // sometimes bad profiles cause this error, which horks the hold urlbar
            return;
          }
                              
          const kNC_Name = rdf.GetResource("http://home.netscape.com/NC-rdf#Name");
          const kNC_Icon = rdf.GetResource("http://home.netscape.com/NC-rdf#Icon");
          const kNC_searchBarUrl = rdf.GetResource("http://home.netscape.com/NC-rdf#actionBar");
        
          var defaultEngine = null;
          try {
            defaultEngine = this.mPrefs.getComplexValue("browser.search.defaultengine",
                                                        Components.interfaces.nsISupportsString).data;
          } catch(ex) {
            // this will re-invoke updateEngines via the pref observer if the pref changes
            this.ensureDefaultEnginePrefs(rdf, ds);
            return;
          }
          
          if (defaultEngine) {
            this.clearEngines();
            
            if (ds) {
              var res = rdf.GetResource(defaultEngine);
              try {
                var searchBarUrl = this.readRDFString(ds, res, kNC_searchBarUrl);
              } catch(ex) {
                searchBarUrl = null;
              }
              if (searchBarUrl == null) {
                // this will re-invoke updateEngines via the pref observer if the pref changes
                this.ensureDefaultEnginePrefs(rdf, ds);
                return;
              }
              this.addEngine(res.Value, 
                            this.readRDFString(ds, res, kNC_Name),
                            this.readRDFString(ds, res, kNC_Icon),
                            searchBarUrl);
            }
          }
          
          this.mEnginesReady = true;
        ]]></body>
      </method>

      <method name="ensureDefaultEnginePrefs">
        <parameter name="aRDF"/>
        <parameter name="aDS"/>
        <body><![CDATA[
          var defaultName = this.mPrefs.getComplexValue("browser.search.defaultenginename",
                                                        Components.interfaces.nsIPrefLocalizedString).data;
          const kNC_Root = aRDF.GetResource("NC:SearchEngineRoot");
          const kNC_child = aRDF.GetResource("http://home.netscape.com/NC-rdf#child");
          const kNC_Name = aRDF.GetResource("http://home.netscape.com/NC-rdf#Name");
          
          var arcs = aDS.GetTargets(kNC_Root, kNC_child, true);
          while (arcs.hasMoreElements()) {
            var engineRes = arcs.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
            var name = this.readRDFString(aDS, engineRes, kNC_Name);
            if (name == defaultName) {
              var str = Components.classes["@mozilla.org/supports-string;1"]
                                  .createInstance(Components.interfaces.nsISupportsString);
              str.data = engineRes.Value;
              this.mPrefs.setComplexValue("browser.search.defaultengine",
                                          Components.interfaces.nsISupportsString,
                                          str);
            }
          }
        ]]></body>
      </method>

      <method name="readRDFString">
        <parameter name="aDS"/>
        <parameter name="aRes"/>
        <parameter name="aProp"/>
        <body><![CDATA[
          var n = aDS.GetTarget(aRes, aProp, true);
          return n ? n.QueryInterface(Components.interfaces.nsIRDFLiteral).Value : null;
        ]]></body>
      </method>

      <method name="clearSelection">
        <body>
          this.view.selection.clearSelection();
          this.mSearchBox.selectedIndex = -1;
        </body>
      </method>

      <method name="selectBy">
        <parameter name="aReverse"/>
        <parameter name="aPage"/>
        <body><![CDATA[
          var sel;
          if (this.selectedIndex == -1 && aReverse ||
              this.mSearchBox.selectedIndex != -1) {
            sel = this.mSearchBox.selectBy(aReverse, aPage);
            if (sel != -1 || !aReverse)
              return -1;
          } 
          
          sel = this.getNextIndex(aReverse, aPage, this.selectedIndex, this.view.rowCount - 1);
          this.selectedIndex = sel;
          if (sel == -1 && !aReverse)
            this.mSearchBox.selectBy(aReverse, aPage);
          else if (this.mSearchBox.selectedIndex != -1)
            this.mSearchBox.selectedIndex = -1;
          return sel;
        ]]></body>
      </method>
    </implementation>

    <handlers>
      <handler event="popupshowing"><![CDATA[
        // sync up with prefs about showing search in the URL bar if
        // the URL bar hasn't finished initializing the default engine info
        //   -or-
        // the search sidebar tab was displayed already triggering a change
        // notification to the browser.search pref branch listener here which 
        // calls updateEngines but doesn't cause the ``Search for ...'' 
        // display string to be updated
        if ( (!this.mEnginesReady && this.defaultSearchEngine) ||
             !("mShowSearch" in this) ) 
          this.updatePref("browser.urlbar.showSearch");

        if (this.mShowSearch) {
          this.textbox.mSearchInputTO = 0;
          this.textbox.addEventListener("input", this.mInputListener, false);
          if ("searchValue" in this.mSearchBox)
            this.mSearchBox.searchValue = this.textbox.currentSearchString;
          else
            this.mSearchBox.setAttribute("searchvalue", this.textbox.currentSearchString);
        }
      ]]></handler>
      
      <handler event="popuphiding"><![CDATA[
        if (this.mShowSearch)
          this.textbox.removeEventListener("input", this.mInputListener, false);
      ]]></handler>      
    </handlers>
  </binding>

  <binding id="autocomplete-search-box">
    <content orient="vertical"/>
    
    <implementation>
      <constructor><![CDATA[
        this.navigatorBundle =
          Components.classes["@mozilla.org/intl/stringbundle;1"]
                    .getService(Components.interfaces.nsIStringBundleService)
                    .createBundle("chrome://navigator/locale/navigator.properties");

        var text = this.getAttribute("searchvalue");
        if (text)
          this.searchValue = text;
      ]]></constructor>

      <field name="mSelectedIndex">
        -1
      </field>

      <property name="activeChild" 
                onget="return this.childNodes[this.mSelectedIndex]"/>

      <property name="selectedIndex">
        <getter>return this.mSelectedIndex;</getter>
        
        <setter><![CDATA[
          if (this.mSelectedIndex != -1)
            this.activeChild.removeAttribute("menuactive");
          
          this.mSelectedIndex = val;

          if (val != -1)
            this.activeChild.setAttribute("menuactive", "true");
          return val;
        ]]></setter>
      
      </property>
      
      <property name="searchValue">
        <getter><![CDATA[
          return this.mSearchValue;
        ]]></getter>
        <setter><![CDATA[
          this.mSearchValue = val;

          const kids = this.childNodes;
          for (var i = 0; i < kids.length; ++i) {
            kids[i].setAttribute("label",
              this.navigatorBundle.formatStringFromName(
                "searchFor", [kids[i].getAttribute("name"), val], 2));
          }
        ]]></setter>
      </property>
      
      <method name="selectBy">
        <parameter name="aReverse"/>
        <parameter name="aPage"/>
        <body><![CDATA[
          return this.selectedIndex = this.parentNode.getNextIndex(aReverse, aPage, this.selectedIndex, this.childNodes.length - 1);
        ]]></body>
      </method>

      <property name="overrideValue" readonly="true">
        <getter><![CDATA[
          var item = this.activeChild;
          if (item) {
            const ISEARCH_CONTRACTID = "@mozilla.org/rdf/datasource;1?name=internetsearch";
            const nsIInternetSearchService = Components.interfaces.nsIInternetSearchService;           
            var searchService = Components.classes[ISEARCH_CONTRACTID].getService(nsIInternetSearchService);
            var searchEng = item.getAttribute("searchEngine");
            var searchEngUrl = item.getAttribute("searchBarUrl");
            var escapedSearch = encodeURIComponent(this.mSearchValue)
            if (searchEngUrl) {
                searchEngUrl += escapedSearch;
                return searchEngUrl;
            } else {
              return searchService.GetInternetSearchURL(item.getAttribute("searchEngine"),escapedSearch, 0, 0, {value:0});
            }
          }
          return null;
        ]]></getter>
      </property>

    </implementation>

    <handlers>
      <handler event="mouseup">
        this.parentNode.textbox.onResultClick();
      </handler>
    </handlers>

  </binding>

  <binding id="autocomplete-search-engine">
    <content>
      <xul:image class="autocomplete-search-engine-img" xbl:inherits="src=icon"/>
      <xul:label class="autocomplete-search-engine-text" xbl:inherits="value=label" crop="right" flex="1"/>
    </content>
    
    <handlers>
      <handler event="mouseover">
        this.parentNode.selectedIndex = Number(this.getAttribute("engineIndex"));
      </handler>

      <handler event="mouseout">
        this.parentNode.selectedIndex = -1;
      </handler>
    </handlers>
  </binding>
  
</bindings>