toolkit/content/widgets/findbar.xml

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 <?xml version="1.0"?>
     3 <!-- This Source Code Form is subject to the terms of the Mozilla Public
     4    - License, v. 2.0. If a copy of the MPL was not distributed with this
     5    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
     7 <!DOCTYPE bindings [
     8 <!ENTITY % findBarDTD SYSTEM "chrome://global/locale/findbar.dtd" >
     9 %findBarDTD;
    10 ]>
    12 <bindings id="findbarBindings"
    13    xmlns="http://www.mozilla.org/xbl"
    14    xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
    15    xmlns:xbl="http://www.mozilla.org/xbl">
    17   <!-- Private binding -->
    18   <binding id="findbar-textbox"
    19            extends="chrome://global/content/bindings/textbox.xml#textbox">
    20     <implementation>
    22       <field name="_findbar">null</field>
    23       <property name="findbar" readonly="true">
    24         <getter>
    25           return this._findbar ?
    26                  this._findbar : this._findbar = document.getBindingParent(this);
    27         </getter>
    28       </property>
    30       <method name="_handleEnter">
    31         <parameter name="aEvent"/>
    32         <body><![CDATA[
    33           if (this.findbar._findMode == this.findbar.FIND_NORMAL) {
    34             let findString = this.findbar._findField;
    35             if (!findString.value)
    36               return;
    37 #ifdef XP_MACOSX
    38             if (aEvent.metaKey) {
    39 #else
    40             if (aEvent.ctrlKey) {
    41 #endif
    42               this.findbar.getElement("highlight").click();
    43               return;
    44             }
    46             this.findbar.onFindAgainCommand(aEvent.shiftKey);
    47           } else {
    48             this.findbar._finishFAYT(aEvent);
    49           }
    50         ]]></body>
    51       </method>
    53       <method name="_handleTab">
    54         <parameter name="aEvent"/>
    55         <body><![CDATA[
    56           let shouldHandle = !aEvent.altKey && !aEvent.ctrlKey &&
    57                              !aEvent.metaKey;
    58           if (shouldHandle &&
    59               this.findbar._findMode != this.findbar.FIND_NORMAL) {
    61             this.findbar._finishFAYT(aEvent);
    62           }
    63         ]]></body>
    64       </method>
    65     </implementation>
    67     <handlers>
    68       <handler event="input"><![CDATA[
    69         // We should do nothing during composition.  E.g., composing string
    70         // before converting may matches a forward word of expected word.
    71         // After that, even if user converts the composition string to the
    72         // expected word, it may find second or later searching word in the
    73         // document.
    74         if (this.findbar._isIMEComposing) {
    75           return;
    76         }
    77         this.findbar._find(this.value);
    78       ]]></handler>
    80       <handler event="keypress"><![CDATA[
    81         let shouldHandle = !event.altKey && !event.ctrlKey &&
    82                            !event.metaKey && !event.shiftKey;
    84         switch (event.keyCode) {
    85           case KeyEvent.DOM_VK_RETURN:
    86             this._handleEnter(event);
    87             break;
    88           case KeyEvent.DOM_VK_TAB:
    89             this._handleTab(event);
    90             break;
    91           case KeyEvent.DOM_VK_PAGE_UP:
    92           case KeyEvent.DOM_VK_PAGE_DOWN:
    93             if (shouldHandle) {
    94               this.findbar.browser.finder.keyPress(event);
    95               event.preventDefault();
    96             }
    97             break;
    98           case KeyEvent.DOM_VK_UP:
    99           case KeyEvent.DOM_VK_DOWN:
   100             this.findbar.browser.finder.keyPress(event);
   101             event.preventDefault();
   102             break;
   103         }
   104       ]]></handler>
   106       <handler event="blur"><![CDATA[
   107         let findbar = this.findbar;
   108         // Note: This code used to remove the selection
   109         // if it matched an editable.
   110         findbar.browser.finder.enableSelection();
   111       ]]></handler>
   113 #ifdef XP_MACOSX
   114       <handler event="focus"><![CDATA[
   115         let findbar = this.findbar;
   116         findbar._onFindFieldFocus();
   117       ]]></handler>
   118 #endif
   120       <handler event="compositionstart"><![CDATA[
   121         // Don't close the find toolbar while IME is composing.
   122         let findbar = this.findbar;
   123         findbar._isIMEComposing = true;
   124         if (findbar._quickFindTimeout) {
   125           clearTimeout(findbar._quickFindTimeout);
   126           findbar._quickFindTimeout = null;
   127         }
   128       ]]></handler>
   130       <handler event="compositionend"><![CDATA[
   131         let findbar = this.findbar;
   132         findbar._isIMEComposing = false;
   133         if (findbar._findMode != findbar.FIND_NORMAL)
   134           findbar._setFindCloseTimeout();
   135       ]]></handler>
   137       <handler event="dragover"><![CDATA[
   138         if (event.dataTransfer.types.contains("text/plain"))
   139           event.preventDefault();
   140       ]]></handler>
   142       <handler event="drop"><![CDATA[
   143         let value = event.dataTransfer.getData("text/plain");
   144         this.value = value;
   145         this.findbar._find(value);
   146         event.stopPropagation();
   147         event.preventDefault();
   148       ]]></handler>
   149     </handlers>
   150   </binding>
   152   <binding id="findbar"
   153            extends="chrome://global/content/bindings/toolbar.xml#toolbar">
   154     <resources>
   155       <stylesheet src="chrome://global/skin/findBar.css"/>
   156     </resources>
   158     <content hidden="true">
   159     <xul:hbox anonid="findbar-container" class="findbar-container" flex="1" align="center">
   160       <xul:hbox anonid="findbar-textbox-wrapper" align="stretch">
   161         <xul:textbox anonid="findbar-textbox"
   162                      class="findbar-textbox findbar-find-fast"
   163                      xbl:inherits="flash"/>
   164         <xul:toolbarbutton anonid="find-previous"
   165                            class="findbar-find-previous tabbable"
   166                            tooltiptext="&previous.tooltip;"
   167                            oncommand="onFindAgainCommand(true);"
   168                            disabled="true"
   169                            xbl:inherits="accesskey=findpreviousaccesskey"/>
   170         <xul:toolbarbutton anonid="find-next"
   171                            class="findbar-find-next tabbable"
   172                            tooltiptext="&next.tooltip;"
   173                            oncommand="onFindAgainCommand(false);"
   174                            disabled="true"
   175                            xbl:inherits="accesskey=findnextaccesskey"/>
   176       </xul:hbox>
   177       <xul:toolbarbutton anonid="highlight"
   178                          class="findbar-highlight tabbable"
   179                          label="&highlightAll.label;"
   180                          accesskey="&highlightAll.accesskey;"
   181                          tooltiptext="&highlightAll.tooltiptext;"
   182                          oncommand="toggleHighlight(this.checked);"
   183                          type="checkbox"
   184                          xbl:inherits="accesskey=highlightaccesskey"/>
   185       <xul:toolbarbutton anonid="find-case-sensitive"
   186                          class="findbar-case-sensitive tabbable"
   187                          label="&caseSensitive.label;"
   188                          accesskey="&caseSensitive.accesskey;"
   189                          tooltiptext="&caseSensitive.tooltiptext;"
   190                          oncommand="_setCaseSensitivity(this.checked);"
   191                          type="checkbox"
   192                          xbl:inherits="accesskey=matchcaseaccesskey"/>
   193       <xul:label anonid="match-case-status" class="findbar-find-fast"/>
   194       <xul:image anonid="find-status-icon" class="findbar-find-fast find-status-icon"/>
   195       <xul:description anonid="find-status"
   196                        control="findbar-textbox"
   197                        class="findbar-find-fast findbar-find-status">
   198       <!-- Do not use value, first child is used because it provides a11y with text change events -->
   199       </xul:description>
   200     </xul:hbox>
   201     <xul:toolbarbutton anonid="find-closebutton"
   202                        class="findbar-closebutton close-icon"
   203                        tooltiptext="&findCloseButton.tooltip;"
   204                        oncommand="close();"/>
   205     </content>
   207     <implementation implements="nsIDOMEventListener, nsIEditActionListener">
   208       <field name="FIND_NORMAL">0</field>
   209       <field name="FIND_TYPEAHEAD">1</field>
   210       <field name="FIND_LINKS">2</field>
   212       <field name="_findMode">0</field>
   214       <field name="_flashFindBar">0</field>
   215       <field name="_initialFlashFindBarCount">6</field>
   217       <property name="prefillWithSelection"
   218                 onget="return this.getAttribute('prefillwithselection') != 'false'"
   219                 onset="this.setAttribute('prefillwithselection', val); return val;"/>
   220       <field name="_selectionMaxLen">150</field>
   222       <method name="getElement">
   223         <parameter name="aAnonymousID"/>
   224         <body><![CDATA[
   225           return document.getAnonymousElementByAttribute(this,
   226                                                          "anonid",
   227                                                          aAnonymousID)
   228         ]]></body>
   229       </method>
   231       <property name="findMode"
   232                 readonly="true"
   233                 onget="return this._findMode;"/>
   235       <property name="canClear" readonly="true">
   236         <getter><![CDATA[
   237           if (this._findField.value)
   238             return true;
   240           // Watch out for lazy editor init
   241           if (this._findField.editor) {
   242             let tm = this._findField.editor.transactionManager;
   243             return !!(tm.numberOfUndoItems || tm.numberOfRedoItems);
   244           }
   245           return false;
   246         ]]></getter>
   247       </property>
   249       <field name="_browser">null</field>
   250       <property name="browser">
   251         <getter><![CDATA[
   252           if (!this._browser) {
   253             this._browser =
   254               document.getElementById(this.getAttribute("browserid"));
   255           }
   256           return this._browser;
   257         ]]></getter>
   258         <setter><![CDATA[
   259           if (this._browser) {
   260             this._browser.removeEventListener("keypress", this, false);
   261             this._browser.removeEventListener("mouseup", this, false);
   262             let finder = this._browser.finder;
   263             if (finder)
   264               finder.removeResultListener(this);
   265           }
   267           this._browser = val;
   268           if (this._browser) {
   269             this._browser.addEventListener("keypress", this, false);
   270             this._browser.addEventListener("mouseup", this, false);
   271             this._browser.finder.addResultListener(this);
   273             this._findField.value = this._browser._lastSearchString;
   274             this.toggleHighlight(this.browser._lastSearchHighlight);
   275           }
   276           return val;
   277         ]]></setter>
   278       </property>
   280       <field name="_observer"><![CDATA[({
   281         _self: this,
   283         QueryInterface: function(aIID) {
   284           if (aIID.equals(Components.interfaces.nsIObserver) ||
   285               aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
   286               aIID.equals(Components.interfaces.nsISupports))
   287             return this;
   289           throw Components.results.NS_ERROR_NO_INTERFACE;
   290         },
   292         observe: function(aSubject, aTopic, aPrefName) {
   293           if (aTopic != "nsPref:changed")
   294             return;
   296           let prefsvc =
   297             aSubject.QueryInterface(Components.interfaces.nsIPrefBranch);
   299           switch (aPrefName) {
   300             case "accessibility.typeaheadfind":
   301               this._self._useTypeAheadFind = prefsvc.getBoolPref(aPrefName);
   302               break;
   303             case "accessibility.typeaheadfind.linksonly":
   304               this._self._typeAheadLinksOnly = prefsvc.getBoolPref(aPrefName);
   305               break;
   306             case "accessibility.typeaheadfind.casesensitive":
   307               this._self._typeAheadCaseSensitive = prefsvc.getIntPref(aPrefName);
   308               this._self._updateCaseSensitivity();
   309               if (this._self.getElement("highlight").checked)
   310                 this._self._setHighlightTimeout();
   311               break;
   312           }
   313         }
   314       })]]></field>
   316       <field name="_destroyed">false</field>
   318       <constructor><![CDATA[
   319         // These elements are accessed frequently and are therefore cached
   320         this._findField = this.getElement("findbar-textbox");
   321         this._findStatusIcon = this.getElement("find-status-icon");
   322         this._findStatusDesc = this.getElement("find-status");
   324         this._foundURL = null;
   326         let prefsvc =
   327           Components.classes["@mozilla.org/preferences-service;1"]
   328                     .getService(Components.interfaces.nsIPrefBranch);
   330         this._quickFindTimeoutLength =
   331           prefsvc.getIntPref("accessibility.typeaheadfind.timeout");
   332         this._flashFindBar =
   333           prefsvc.getIntPref("accessibility.typeaheadfind.flashBar");
   335         prefsvc.addObserver("accessibility.typeaheadfind",
   336                             this._observer, false);
   337         prefsvc.addObserver("accessibility.typeaheadfind.linksonly",
   338                             this._observer, false);
   339         prefsvc.addObserver("accessibility.typeaheadfind.casesensitive",
   340                             this._observer, false);
   342         this._useTypeAheadFind =
   343           prefsvc.getBoolPref("accessibility.typeaheadfind");
   344         this._typeAheadLinksOnly =
   345           prefsvc.getBoolPref("accessibility.typeaheadfind.linksonly");
   346         this._typeAheadCaseSensitive =
   347           prefsvc.getIntPref("accessibility.typeaheadfind.casesensitive");
   349         // Convenience
   350         this.nsITypeAheadFind = Components.interfaces.nsITypeAheadFind;
   351         this.nsISelectionController = Components.interfaces.nsISelectionController;
   352         this._findSelection = this.nsISelectionController.SELECTION_FIND;
   354         this._findResetTimeout = -1;
   356         // Make sure the FAYT keypress listener is attached by initializing the
   357         // browser property
   358         if (this.getAttribute("browserid"))
   359           setTimeout(function(aSelf) { aSelf.browser = aSelf.browser; }, 0, this);
   360       ]]></constructor>
   362       <destructor><![CDATA[
   363         this.destroy();
   364       ]]></destructor>
   366       <!-- This is necessary because the destructor isn't called when
   367            we are removed from a document that is not destroyed. This
   368            needs to be explicitly called in this case -->
   369       <method name="destroy">
   370         <body><![CDATA[
   371           if (this._destroyed)
   372             return;
   373           this._destroyed = true;
   375           this.browser = null;
   377           let prefsvc =
   378             Components.classes["@mozilla.org/preferences-service;1"]
   379                       .getService(Components.interfaces.nsIPrefBranch);
   380           prefsvc.removeObserver("accessibility.typeaheadfind",
   381                                  this._observer);
   382           prefsvc.removeObserver("accessibility.typeaheadfind.linksonly",
   383                                  this._observer);
   384           prefsvc.removeObserver("accessibility.typeaheadfind.casesensitive",
   385                                  this._observer);
   387           // Clear all timers that might still be running.
   388           this._cancelTimers();
   389         ]]></body>
   390       </method>
   392       <method name="_cancelTimers">
   393         <body><![CDATA[
   394           if (this._flashFindBarTimeout) {
   395             clearInterval(this._flashFindBarTimeout);
   396             this._flashFindBarTimeout = null;
   397           }
   398           if (this._quickFindTimeout) {
   399             clearTimeout(this._quickFindTimeout);
   400             this._quickFindTimeout = null;
   401           }
   402           if (this._highlightTimeout) {
   403             clearTimeout(this._highlightTimeout);
   404             this._highlightTimeout = null;
   405           }
   406           if (this._findResetTimeout) {
   407             clearTimeout(this._findResetTimeout);
   408             this._findResetTimeout = null;
   409           }
   410         ]]></body>
   411       </method>
   413       <method name="_setFindCloseTimeout">
   414         <body><![CDATA[
   415           if (this._quickFindTimeout)
   416             clearTimeout(this._quickFindTimeout);
   418           // Don't close the find toolbar while IME is composing OR when the
   419           // findbar is already hidden.
   420           if (this._isIMEComposing || this.hidden) {
   421             this._quickFindTimeout = null;
   422             return;
   423           }
   425           this._quickFindTimeout = setTimeout(() => {
   426              if (this._findMode != this.FIND_NORMAL)
   427                this.close();
   428              this._quickFindTimeout = null;
   429            }, this._quickFindTimeoutLength);
   430         ]]></body>
   431       </method>
   433       <!--
   434         - Turns highlight on or off.
   435         - @param aHighlight (boolean)
   436         -        Whether to turn the highlight on or off
   437         -->
   438       <method name="toggleHighlight">
   439         <parameter name="aHighlight"/>
   440         <body><![CDATA[
   441           if (!this._dispatchFindEvent("highlightallchange"))
   442             return;
   444           let word = this._findField.value;
   445           // Bug 429723. Don't attempt to highlight ""
   446           if (aHighlight && !word)
   447             return;
   449           this.browser._lastSearchHighlight = aHighlight;
   450           this.browser.finder.highlight(aHighlight, word);
   451         ]]></body>
   452       </method>
   454       <!--
   455         - Updates the case-sensitivity mode of the findbar and its UI.
   456         - @param [optional] aString
   457         -        The string for which case sensitivity might be turned on.
   458         -        This only used when case-sensitivity is in auto mode,
   459         -        @see _shouldBeCaseSensitive. The default value for this
   460         -        parameter is the find-field value.
   461         -->
   462       <method name="_updateCaseSensitivity">
   463         <parameter name="aString"/>
   464         <body><![CDATA[
   465           let val = aString || this._findField.value;
   467           let caseSensitive = this._shouldBeCaseSensitive(val);
   468           let checkbox = this.getElement("find-case-sensitive");
   469           let statusLabel = this.getElement("match-case-status");
   470           checkbox.checked = caseSensitive;
   472           statusLabel.value = caseSensitive ? this._caseSensitiveStr : "";
   474           // Show the checkbox on the full Find bar in non-auto mode.
   475           // Show the label in all other cases.
   476           let hideCheckbox = this._findMode != this.FIND_NORMAL ||
   477             (this._typeAheadCaseSensitive != 0 &&
   478              this._typeAheadCaseSensitive != 1);
   479           checkbox.hidden = hideCheckbox;
   480           statusLabel.hidden = !hideCheckbox;
   482           this.browser.finder.caseSensitive = caseSensitive;
   483         ]]></body>
   484       </method>
   486       <!--
   487         - Sets the findbar case-sensitivity mode
   488         - @param aCaseSensitive (boolean)
   489         -        Whether or not case-sensitivity should be turned on.
   490         -->
   491       <method name="_setCaseSensitivity">
   492         <parameter name="aCaseSensitive"/>
   493         <body><![CDATA[
   494           let prefsvc =
   495             Components.classes["@mozilla.org/preferences-service;1"]
   496                       .getService(Components.interfaces.nsIPrefBranch);
   498           // Just set the pref; our observer will change the find bar behavior
   499           prefsvc.setIntPref("accessibility.typeaheadfind.casesensitive",
   500                              aCaseSensitive ? 1 : 0);
   502           this._dispatchFindEvent("casesensitivitychange");
   503         ]]></body>
   504       </method>
   506       <!--
   507         - Opens and displays the find bar.
   508         -
   509         - @param aMode
   510         -        the find mode to be used, which is either FIND_NORMAL,
   511         -        FIND_TYPEAHEAD or FIND_LINKS. If not passed, the last
   512         -        find mode if any or FIND_NORMAL.
   513         - @returns true if the find bar wasn't previously open, false otherwise.
   514         -->
   515       <method name="open">
   516         <parameter name="aMode"/>
   517         <body><![CDATA[
   518           if (aMode != undefined)
   519             this._findMode = aMode;
   521           if (!this._notFoundStr) {
   522             let stringsBundle =
   523               Components.classes["@mozilla.org/intl/stringbundle;1"]
   524                         .getService(Components.interfaces.nsIStringBundleService)
   525                         .createBundle("chrome://global/locale/findbar.properties");
   526             this._notFoundStr = stringsBundle.GetStringFromName("NotFound");
   527             this._wrappedToTopStr =
   528               stringsBundle.GetStringFromName("WrappedToTop");
   529             this._wrappedToBottomStr =
   530               stringsBundle.GetStringFromName("WrappedToBottom");
   531             this._normalFindStr =
   532               stringsBundle.GetStringFromName("NormalFind");
   533             this._fastFindStr =
   534               stringsBundle.GetStringFromName("FastFind");
   535             this._fastFindLinksStr =
   536               stringsBundle.GetStringFromName("FastFindLinks");
   537             this._caseSensitiveStr =
   538               stringsBundle.GetStringFromName("CaseSensitive");
   539           }
   541           this._findFailedString = null;
   543           this._updateFindUI();
   544           if (this.hidden) {
   545             this.hidden = false;
   547             this._updateStatusUI(this.nsITypeAheadFind.FIND_FOUND);
   549             let event = document.createEvent("Events");
   550             event.initEvent("findbaropen", true, false);
   551             this.dispatchEvent(event);
   553             return true;
   554           }
   555           return false;
   556         ]]></body>
   557       </method>
   559       <!--
   560         - Closes the findbar.
   561         -->
   562       <method name="close">
   563         <body><![CDATA[
   564           if (this.hidden)
   565             return;
   567           this.hidden = true;
   569           this.browser.finder.focusContent();
   570           this.browser.finder.enableSelection();
   571           this._findField.blur();
   573           this._cancelTimers();
   575           this._findFailedString = null;
   576         ]]></body>
   577       </method>
   579       <method name="clear">
   580         <body><![CDATA[
   581           this.browser.finder.removeSelection();
   582           this._findField.reset();
   583           this.toggleHighlight(false);
   584           this._updateStatusUI();
   585           this._enableFindButtons(false);
   586         ]]></body>
   587       </method>
   589       <method name="_dispatchKeypressEvent">
   590         <parameter name="aTarget"/>
   591         <parameter name="aEvent"/>
   592         <body><![CDATA[
   593           if (!aTarget)
   594             return;
   596           let event = document.createEvent("KeyEvents");
   597           event.initKeyEvent(aEvent.type, aEvent.bubbles, aEvent.cancelable,
   598                              aEvent.view, aEvent.ctrlKey, aEvent.altKey,
   599                              aEvent.shiftKey, aEvent.metaKey, aEvent.keyCode,
   600                              aEvent.charCode);
   601           aTarget.dispatchEvent(event);
   602         ]]></body>
   603       </method>
   605       <field name="_xulBrowserWindow">null</field>
   606       <method name="_updateStatusUIBar">
   607         <parameter name="aFoundURL"/>
   608         <body><![CDATA[
   609           if (!this._xulBrowserWindow) {
   610             try {
   611               this._xulBrowserWindow =
   612                 window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
   613                       .getInterface(Components.interfaces.nsIWebNavigation)
   614                       .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
   615                       .treeOwner
   616                       .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
   617                       .getInterface(Components.interfaces.nsIXULWindow)
   618                       .XULBrowserWindow;
   619             }
   620             catch(ex) { }
   621             if (!this._xulBrowserWindow)
   622               return false;
   623           }
   625           // Call this has the same effect like hovering over link,
   626           // the browser shows the URL as a tooltip.
   627           this._xulBrowserWindow.setOverLink(aFoundURL || "", null);
   628           return true;
   629         ]]></body>
   630       </method>
   632       <method name="_finishFAYT">
   633         <parameter name="aKeypressEvent"/>
   634         <body><![CDATA[
   635           this.browser.finder.focusContent();
   637           if (aKeypressEvent)
   638             aKeypressEvent.preventDefault();
   640           this.browser.finder.keyPress(aKeypressEvent);
   642           this.close();
   643           return true;
   644         ]]></body>
   645       </method>
   647       <!--
   648         - Returns true if |aMimeType| is text-based, or false otherwise.
   649         -
   650         - @param aMimeType
   651         -        The MIME type to check.
   652         -
   653         - if adding types to this function, please see the similar function
   654         - in browser/base/content/browser.js
   655         -->
   656       <method name="_mimeTypeIsTextBased">
   657         <parameter name="aMimeType"/>
   658         <body><![CDATA[
   659           return /^text\/|\+xml$/.test(aMimeType) ||
   660                  aMimeType == "application/x-javascript" ||
   661                  aMimeType == "application/javascript" ||
   662                  aMimeType == "application/json" ||
   663                  aMimeType == "application/xml";
   664         ]]></body>
   665       </method>
   667       <!--
   668         - Returns whether FAYT can be used for the given event in
   669         - the current content state.
   670         -->
   671       <method name="_shouldFastFind">
   672         <parameter name="aEvent"/>
   673         <body><![CDATA[
   674           if (aEvent.ctrlKey || aEvent.altKey || aEvent.metaKey ||
   675               aEvent.defaultPrevented)
   676             return false;
   678           let {BrowserUtils} = Components.utils.import("resource://gre/modules/BrowserUtils.jsm", {});
   679           let [elt, win] = BrowserUtils.getFocusSync(document);
   681           if (elt) {
   682             if (elt instanceof HTMLInputElement && elt.mozIsTextField(false))
   683               return false;
   685             if (elt.isContentEditable)
   686               return false;
   688             if (elt instanceof HTMLTextAreaElement ||
   689                 elt instanceof HTMLSelectElement ||
   690                 elt instanceof HTMLObjectElement ||
   691                 elt instanceof HTMLEmbedElement)
   692               return false;
   693           }
   695           if (win && !this._mimeTypeIsTextBased(win.document.contentType))
   696               return false;
   698           // disable FAYT in about:blank to prevent FAYT opening unexpectedly.
   699           let url = this.browser.currentURI;
   700           if (url.spec == "about:blank")
   701             return false;
   703           // disable FAYT in documents that ask for it to be disabled.
   704           if ((url.schemeIs("about") || url.schemeIs("chrome")) &&
   705               (win.document.documentElement &&
   706                win.document.documentElement.getAttribute("disablefastfind") == "true"))
   707             return false;
   709           if (win) {
   710             try {
   711               let editingSession = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
   712                                    .getInterface(Components.interfaces.nsIWebNavigation)
   713                                    .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
   714                                    .getInterface(Components.interfaces.nsIEditingSession);
   715               if (editingSession.windowIsEditable(win))
   716                 return false;
   717             }
   718             catch (e) {
   719               // If someone built with composer disabled, we can't get an editing session.
   720             }
   721          }
   723           return true;
   724         ]]></body>
   725       </method>
   727       <method name="_shouldBeCaseSensitive">
   728         <parameter name="aString"/>
   729         <body><![CDATA[
   730           if (this._typeAheadCaseSensitive == 0)
   731             return false;
   732           if (this._typeAheadCaseSensitive == 1)
   733             return true;
   735           return aString != aString.toLowerCase();
   736         ]]></body>
   737       </method>
   739       <method name="_onBrowserKeypress">
   740         <parameter name="aEvent"/>
   741         <body><![CDATA[
   742           const TAF_LINKS_KEY = "'";
   743           const TAF_TEXT_KEY = "/";
   745           if (!this._shouldFastFind(aEvent))
   746             return;
   748           if (this._findMode != this.FIND_NORMAL && this._quickFindTimeout) {
   749             if (!aEvent.charCode)
   750               return;
   752             this._findField.select();
   753             this._findField.focus();
   754             this._dispatchKeypressEvent(this._findField.inputField, aEvent);
   755             aEvent.preventDefault();
   756             return;
   757           }
   759           let key = aEvent.charCode ? String.fromCharCode(aEvent.charCode) : null;
   760           let manualstartFAYT = (key == TAF_LINKS_KEY || key == TAF_TEXT_KEY);
   761           let autostartFAYT = !manualstartFAYT && this._useTypeAheadFind &&
   762                               key && key != " ";
   763           if (manualstartFAYT || autostartFAYT) {
   764             let mode = (key == TAF_LINKS_KEY ||
   765                         (autostartFAYT && this._typeAheadLinksOnly)) ?
   766               this.FIND_LINKS : this.FIND_TYPEAHEAD;
   768             // Clear bar first, so that when openFindBar() calls setCaseSensitivity()
   769             // it doesn't get confused by a lingering value
   770             this._findField.value = "";
   772             this.open(mode);
   773             this._setFindCloseTimeout();
   774             this._findField.select();
   775             this._findField.focus();
   777             if (autostartFAYT)
   778               this._dispatchKeypressEvent(this._findField.inputField, aEvent);
   779             else
   780               this._updateStatusUI(this.nsITypeAheadFind.FIND_FOUND);
   782             aEvent.preventDefault();
   783           }
   784         ]]></body>
   785       </method>
   787       <!-- See nsIDOMEventListener -->
   788       <method name="handleEvent">
   789         <parameter name="aEvent"/>
   790         <body><![CDATA[
   791           switch (aEvent.type) {
   792             case "mouseup":
   793               if (!this.hidden && this._findMode != this.FIND_NORMAL)
   794                 this.close();
   796               break;
   797             case "keypress":
   798               this._onBrowserKeypress(aEvent);
   799               break;
   800           }
   801         ]]></body>
   802       </method>
   804       <method name="_enableFindButtons">
   805         <parameter name="aEnable"/>
   806         <body><![CDATA[
   807           this.getElement("find-next").disabled =
   808             this.getElement("find-previous").disabled = !aEnable;
   809         ]]></body>
   810       </method>
   812       <!--
   813         - Determines whether minimalist or general-purpose search UI is to be
   814         - displayed when the find bar is activated.
   815         -->
   816       <method name="_updateFindUI">
   817         <body><![CDATA[
   818           let showMinimalUI = this._findMode != this.FIND_NORMAL;
   820           let nodes = this.getElement("findbar-container").childNodes;
   821           let wrapper = this.getElement("findbar-textbox-wrapper");
   822           for (let node of nodes) {
   823             if (node == wrapper)
   824                continue;
   825             node.hidden = showMinimalUI;
   826           }
   827           this.getElement("find-next").hidden =
   828             this.getElement("find-previous").hidden = showMinimalUI;
   829           this._updateCaseSensitivity();
   831           if (showMinimalUI)
   832             this._findField.classList.add("minimal");
   833           else
   834             this._findField.classList.remove("minimal");
   836           if (this._findMode == this.FIND_TYPEAHEAD)
   837             this._findField.placeholder = this._fastFindStr;
   838           else if (this._findMode == this.FIND_LINKS)
   839             this._findField.placeholder = this._fastFindLinksStr;
   840           else
   841             this._findField.placeholder = this._normalFindStr;
   842         ]]></body>
   843       </method>
   845       <method name="_find">
   846         <parameter name="aValue"/>
   847         <body><![CDATA[
   848           if (!this._dispatchFindEvent(""))
   849             return;
   851           let val = aValue || this._findField.value;
   853           // We have to carry around an explicit version of this,
   854           // because finder.searchString doesn't update on failed
   855           // searches.
   856           this.browser._lastSearchString = val;
   858           // Only search on input if we don't have a last-failed string,
   859           // or if the current search string doesn't start with it.
   860           if (!this._findFailedString ||
   861               !val.startsWith(this._findFailedString))
   862           {
   863             this._enableFindButtons(val);
   864             if (this.getElement("highlight").checked)
   865               this._setHighlightTimeout();
   867             this._updateCaseSensitivity(val);
   869             this.browser.finder.fastFind(val, this._findMode == this.FIND_LINKS,
   870                                          this._findMode != this.FIND_NORMAL);
   871           }
   873           if (this._findMode != this.FIND_NORMAL)
   874             this._setFindCloseTimeout();
   876           if (this._findResetTimeout != -1)
   877             clearTimeout(this._findResetTimeout);
   879           // allow a search to happen on input again after a second has
   880           // expired since the previous input, to allow for dynamic
   881           // content and/or page loading
   882           this._findResetTimeout = setTimeout(() => {
   883             this._findFailedString = null;
   884             this._findResetTimeout = -1;
   885           }, 1000);
   886         ]]></body>
   887       </method>
   889       <method name="_flash">
   890         <body><![CDATA[
   891           if (this._flashFindBarCount === undefined)
   892             this._flashFindBarCount = this._initialFlashFindBarCount;
   894           if (this._flashFindBarCount-- == 0) {
   895             clearInterval(this._flashFindBarTimeout);
   896             this.removeAttribute("flash");
   897             this._flashFindBarCount = 6;
   898             return;
   899           }
   901           this.setAttribute("flash",
   902                             (this._flashFindBarCount % 2 == 0) ?
   903                             "false" : "true");
   904         ]]></body>
   905       </method>
   907       <method name="_setHighlightTimeout">
   908         <body><![CDATA[
   909           if (this._highlightTimeout)
   910             clearTimeout(this._highlightTimeout);
   911           this._highlightTimeout =
   912             setTimeout(function(aSelf) {
   913                          aSelf.toggleHighlight(false);
   914                          aSelf.toggleHighlight(true);
   915                        }, 500, this);
   916         ]]></body>
   917       </method>
   919       <method name="_findAgain">
   920         <parameter name="aFindPrevious"/>
   921         <body><![CDATA[
   922           this.browser.finder.findAgain(aFindPrevious,
   923                                         this._findMode == this.FIND_LINKS,
   924                                         this._findMode != this.FIND_NORMAL);
   925         ]]></body>
   926       </method>
   928       <method name="_updateStatusUI">
   929         <parameter name="res"/>
   930         <parameter name="aFindPrevious"/>
   931         <body><![CDATA[
   932           switch (res) {
   933             case this.nsITypeAheadFind.FIND_WRAPPED:
   934               this._findStatusIcon.setAttribute("status", "wrapped");
   935               this._findStatusDesc.textContent =
   936                 aFindPrevious ? this._wrappedToBottomStr : this._wrappedToTopStr;
   937               this._findField.removeAttribute("status");
   938               break;
   939             case this.nsITypeAheadFind.FIND_NOTFOUND:
   940               this._findStatusIcon.setAttribute("status", "notfound");
   941               this._findStatusDesc.textContent = this._notFoundStr;
   942               this._findField.setAttribute("status", "notfound");
   943               break;
   944             case this.nsITypeAheadFind.FIND_PENDING:
   945               this._findStatusIcon.setAttribute("status", "pending");
   946               this._findStatusDesc.textContent = "";
   947               this._findField.removeAttribute("status");
   948               break;
   949             case this.nsITypeAheadFind.FIND_FOUND:
   950             default:
   951               this._findStatusIcon.removeAttribute("status");
   952               this._findStatusDesc.textContent = "";
   953               this._findField.removeAttribute("status");
   954               break;
   955           }
   956         ]]></body>
   957       </method>
   959       <method name="updateControlState">
   960         <parameter name="aResult"/>
   961         <parameter name="aFindPrevious"/>
   962         <body><![CDATA[
   963           this._updateStatusUI(aResult, aFindPrevious);
   964           this._enableFindButtons(aResult !== this.nsITypeAheadFind.FIND_NOTFOUND);
   965         ]]></body>
   966       </method>
   968       <method name="_getInitialSelection">
   969         <body><![CDATA[
   970           let focusedElement = document.commandDispatcher.focusedElement;
   971           let selText;
   973           if (focusedElement instanceof Components.interfaces.nsIDOMNSEditableElement &&
   974               focusedElement.editor &&
   975               focusedElement.ownerDocument.defaultView.top == this._browser.contentWindow)
   976           {
   977             // The user may have a selection in an input or textarea
   978             selText = focusedElement.editor.selectionController
   979               .getSelection(Components.interfaces.nsISelectionController.SELECTION_NORMAL)
   980               .toString();
   981           }
   982           else {
   983             // Look for any selected text on the actual page
   984             let focusedWindow = document.commandDispatcher.focusedWindow;
   985             if (focusedWindow.top == this._browser.contentWindow)
   986               selText = focusedWindow.getSelection().toString();
   987           }
   989           if (!selText)
   990             return "";
   992           // Process our text to get rid of unwanted characters
   993           if (selText.length > this._selectionMaxLen) {
   994             let pattern = new RegExp("^(?:\\s*.){0," + this._selectionMaxLen + "}");
   995             pattern.test(selText);
   996             selText = RegExp.lastMatch;
   997           }
   998           return selText.replace(/^\s+/, "")
   999                         .replace(/\s+$/, "")
  1000                         .replace(/\s+/g, " ")
  1001                         .substr(0, this._selectionMaxLen);
  1002         ]]></body>
  1003       </method>
  1005       <method name="_dispatchFindEvent">
  1006         <parameter name="aType"/>
  1007         <parameter name="aFindPrevious"/>
  1008         <body><![CDATA[
  1009           let event = document.createEvent("CustomEvent");
  1010           event.initCustomEvent("find" + aType, true, true, {
  1011             query: this._findField.value,
  1012             caseSensitive: !!this._typeAheadCaseSensitive,
  1013             highlightAll: this.getElement("highlight").checked,
  1014             findPrevious: aFindPrevious
  1015           });
  1016           return this.dispatchEvent(event);
  1017         ]]></body>
  1018       </method>
  1021       <!--
  1022         - Opens the findbar, focuses the findfield and selects its contents.
  1023         - Also flashes the findbar the first time it's used.
  1024         - @param aMode
  1025         -        the find mode to be used, which is either FIND_NORMAL,
  1026         -        FIND_TYPEAHEAD or FIND_LINKS. If not passed, the last
  1027         -        find mode if any or FIND_NORMAL.
  1028         -->
  1029       <method name="startFind">
  1030         <parameter name="aMode"/>
  1031         <body><![CDATA[
  1032           let prefsvc =
  1033             Components.classes["@mozilla.org/preferences-service;1"]
  1034                       .getService(Components.interfaces.nsIPrefBranch);
  1035           let userWantsPrefill = true;
  1036           this.open(aMode);
  1038           if (this._flashFindBar) {
  1039             this._flashFindBarTimeout = setInterval(() => this._flash(), 500);
  1040             prefsvc.setIntPref("accessibility.typeaheadfind.flashBar",
  1041                                --this._flashFindBar);
  1044           if (this.prefillWithSelection)
  1045             userWantsPrefill =
  1046               prefsvc.getBoolPref("accessibility.typeaheadfind.prefillwithselection");
  1048           let initialString = null;
  1049           if (this.prefillWithSelection && userWantsPrefill)
  1050             initialString = this._getInitialSelection();
  1051 #ifdef XP_MACOSX
  1052           if (!initialString) {
  1053             let clipboardSearchString = this.browser.finder.clipboardSearchString;
  1054             if (clipboardSearchString)
  1055               initialString = clipboardSearchString;
  1057 #endif
  1059           if (initialString)
  1060             this._findField.value = initialString;
  1062           this._enableFindButtons(!!this._findField.value);
  1064           this._findField.select();
  1065           this._findField.focus();
  1066         ]]></body>
  1067       </method>
  1069       <!--
  1070         - Convenient alias to startFind(gFindBar.FIND_NORMAL);
  1072         - You should generally map the window's find command to this method.
  1073         -   e.g. <command name="cmd_find" oncommand="gFindBar.onFindCommand();"/>
  1074         -->
  1075       <method name="onFindCommand">
  1076         <body><![CDATA[
  1077           this.startFind(this.FIND_NORMAL);
  1078         ]]></body>
  1079       </method>
  1081       <!--
  1082         - Stub for find-next and find-previous commands
  1083         - @param aFindPrevious
  1084         -        true for find-previous, false otherwise.
  1085         -->
  1086       <method name="onFindAgainCommand">
  1087         <parameter name="aFindPrevious"/>
  1088         <body><![CDATA[
  1089           let findString = this._browser.finder.searchString || this._findField.value;
  1090           if (!findString) {
  1091             this.startFind();
  1092             return;
  1095           // We dispatch the findAgain event here instead of in _findAgain since
  1096           // if there is a find event handler that prevents the default then
  1097           // finder.searchString will never get updated which in turn means
  1098           // there would never be findAgain events because of the logic below.
  1099           if (!this._dispatchFindEvent("again", aFindPrevious))
  1100             return;
  1102           // user explicitly requested another search, so do it even if we think it'll fail
  1103           this._findFailedString = null;
  1105           // Ensure the stored SearchString is in sync with what we want to find
  1106           if (this._findField.value != this._browser.finder.searchString)
  1107             this._find(this._findField.value);
  1108           else
  1109             this._findAgain(aFindPrevious);
  1111         ]]></body>
  1112       </method>
  1114 #ifdef XP_MACOSX
  1115       <!--
  1116         - Fetches the currently selected text and sets that as the text to search
  1117         - next. This is a MacOS specific feature.
  1118       -->
  1119       <method name="onFindSelectionCommand">
  1120         <body><![CDATA[
  1121           let searchString = this.browser.finder.setSearchStringToSelection();
  1122           if (searchString)
  1123             this._findField.value = searchString;
  1124         ]]></body>
  1125       </method>
  1127       <method name="_onFindFieldFocus">
  1128         <body><![CDATA[
  1129           let prefsvc =
  1130             Components.classes["@mozilla.org/preferences-service;1"]
  1131                       .getService(Components.interfaces.nsIPrefBranch);
  1132           const kPref = "accessibility.typeaheadfind.prefillwithselection";
  1133           if (this.prefillWithSelection && prefsvc.getBoolPref(kPref))
  1134             return;
  1136           let clipboardSearchString = this._browser.finder.clipboardSearchString;
  1137           if (clipboardSearchString && this._findField.value != clipboardSearchString) {
  1138             this._findField.value = clipboardSearchString;
  1139             // Changing the search string makes the previous status invalid, so
  1140             // we better clear it here.
  1141             this._updateStatusUI();
  1143         ]]></body>
  1144       </method>
  1145 #endif
  1147       <!--
  1148         - This handles all the result changes for both
  1149         - type-ahead-find and highlighting.
  1150         - @param aResult
  1151         -   One of the nsITypeAheadFind.FIND_* constants
  1152         -   indicating the result of a search operation.
  1153         - @param aFindBackwards
  1154         -   If the search was done from the bottom to
  1155         -   the top. This is used for right error messages
  1156         -   when reaching "the end of the page".
  1157         - @param aLinkURL
  1158         -   When a link matched then its URK. Always null
  1159         -   when not in FIND_LINKS mode.
  1160         -->
  1161       <method name="onFindResult">
  1162         <parameter name="aData"/>
  1163         <body><![CDATA[
  1164           if (aData.storeResult && this._findField.value != this.browser.finder.searchString)
  1165             this._findField.value = this.browser.finder.searchString;
  1166           this._updateStatusUI(aData.result, aData.findBackwards);
  1167           this._updateStatusUIBar(aData.linkURL);
  1169           if (aData.result == this.nsITypeAheadFind.FIND_NOTFOUND)
  1170             this._findFailedString = aData.searchString;
  1171           else
  1172             this._findFailedString = null;
  1174           if (this._findMode != this.FIND_NORMAL)
  1175             this._setFindCloseTimeout();
  1176         ]]></body>
  1177       </method>
  1179       <!--
  1180         - This handler may cancel a request to focus content by returning |false|
  1181         - explicitly.
  1182         -->
  1183       <method name="shouldFocusContent">
  1184         <body><![CDATA[
  1185           const fm = Components.classes["@mozilla.org/focus-manager;1"]
  1186                                .getService(Components.interfaces.nsIFocusManager);
  1187           if (fm.focusedWindow != window)
  1188             return false;
  1190           let focusedElement = fm.focusedElement;
  1191           if (!focusedElement)
  1192             return false;
  1194           let bindingParent = document.getBindingParent(focusedElement);
  1195           if (bindingParent != this && bindingParent != this._findField)
  1196             return false;
  1198           return true;
  1199         ]]></body>
  1200       </method>
  1202     </implementation>
  1204     <handlers>
  1205       <!--
  1206         - We have to guard against `this.close` being |null| due to an unknown
  1207         - issue, which is tracked in bug 957999.
  1208         -->
  1209       <handler event="keypress" keycode="VK_ESCAPE" phase="capturing"
  1210                action="if (this.close) this.close();" preventdefault="true"/>
  1211     </handlers>
  1212   </binding>
  1213 </bindings>

mercurial