forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			654 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			654 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| // -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
 | |
| // vim: set ts=2 sw=2 sts=2 et tw=80: */
 | |
| // This Source Code Form is subject to the terms of the Mozilla Public
 | |
| // License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
| // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 | |
| 
 | |
| const kModalHighlightPref = "findbar.modalHighlight";
 | |
| const kSoundEnabledPref = "accessibility.typeaheadfind.enablesound";
 | |
| const kNotFoundSoundPref = "accessibility.typeaheadfind.soundURL";
 | |
| 
 | |
| import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
 | |
| 
 | |
| const lazy = {};
 | |
| 
 | |
| ChromeUtils.defineESModuleGetters(lazy, {
 | |
|   GetClipboardSearchString: "resource://gre/modules/Finder.sys.mjs",
 | |
|   RFPHelper: "resource://gre/modules/RFPHelper.sys.mjs",
 | |
|   Rect: "resource://gre/modules/Geometry.sys.mjs",
 | |
| });
 | |
| 
 | |
| const kPrefLetterboxing = "privacy.resistFingerprinting.letterboxing";
 | |
| 
 | |
| XPCOMUtils.defineLazyPreferenceGetter(
 | |
|   lazy,
 | |
|   "isLetterboxingEnabled",
 | |
|   kPrefLetterboxing,
 | |
|   false
 | |
| );
 | |
| 
 | |
| XPCOMUtils.defineLazyPreferenceGetter(
 | |
|   lazy,
 | |
|   "isSoundEnabled",
 | |
|   kSoundEnabledPref,
 | |
|   false
 | |
| );
 | |
| 
 | |
| XPCOMUtils.defineLazyPreferenceGetter(
 | |
|   lazy,
 | |
|   "notFoundSoundURL",
 | |
|   kNotFoundSoundPref,
 | |
|   ""
 | |
| );
 | |
| 
 | |
| export function FinderParent(browser) {
 | |
|   this._listeners = new Set();
 | |
|   this._searchString = "";
 | |
|   this._foundSearchString = null;
 | |
|   this._lastFoundBrowsingContext = null;
 | |
| 
 | |
|   // The correct states of these will be updated when the findbar is opened.
 | |
|   this._caseSensitive = false;
 | |
|   this._entireWord = false;
 | |
|   this._matchDiacritics = false;
 | |
| 
 | |
|   this.swapBrowser(browser);
 | |
| }
 | |
| 
 | |
| let gSound = null;
 | |
| 
 | |
| FinderParent.prototype = {
 | |
|   get browsingContext() {
 | |
|     return this._browser.browsingContext;
 | |
|   },
 | |
| 
 | |
|   get useRemoteSubframes() {
 | |
|     return this._browser.ownerGlobal.docShell.nsILoadContext.useRemoteSubframes;
 | |
|   },
 | |
| 
 | |
|   swapBrowser(aBrowser) {
 | |
|     this._browser = aBrowser;
 | |
|     // Ideally listeners would have removed themselves but that doesn't happen
 | |
|     // right now
 | |
|     this._listeners.clear();
 | |
|   },
 | |
| 
 | |
|   addResultListener(aListener) {
 | |
|     this._listeners.add(aListener);
 | |
|   },
 | |
| 
 | |
|   removeResultListener(aListener) {
 | |
|     this._listeners.delete(aListener);
 | |
|   },
 | |
| 
 | |
|   callListeners(aCallback, aArgs) {
 | |
|     for (let l of this._listeners) {
 | |
|       // Don't let one callback throwing stop us calling the rest
 | |
|       try {
 | |
|         l[aCallback].apply(l, aArgs);
 | |
|       } catch (e) {
 | |
|         if (!l[aCallback]) {
 | |
|           console.error(
 | |
|             `Missing ${aCallback} callback on RemoteFinderListener`
 | |
|           );
 | |
|         } else {
 | |
|           console.error(e);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   getLastFoundBrowsingContext(aList) {
 | |
|     // If a search was already performed, returned the last
 | |
|     // browsing context where the result was found. However,
 | |
|     // ensure that this browsing context is still valid, and
 | |
|     // if not, return null.
 | |
|     if (
 | |
|       aList.includes(this._lastFoundBrowsingContext) &&
 | |
|       !this._lastFoundBrowsingContext.isUnderHiddenEmbedderElement
 | |
|     ) {
 | |
|       return this._lastFoundBrowsingContext;
 | |
|     }
 | |
| 
 | |
|     this._lastFoundBrowsingContext = null;
 | |
|     return null;
 | |
|   },
 | |
| 
 | |
|   sendMessageToContext(aMessageName, aArgs = {}) {
 | |
|     // If there is a last found browsing context, use that. Otherwise,
 | |
|     // use the top-level browsing context.
 | |
|     let browsingContext = null;
 | |
|     if (this._lastFoundBrowsingContext) {
 | |
|       let list = this.gatherBrowsingContexts(this.browsingContext);
 | |
|       let lastBrowsingContext = this.getLastFoundBrowsingContext(list);
 | |
|       if (lastBrowsingContext) {
 | |
|         browsingContext = lastBrowsingContext;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (!browsingContext) {
 | |
|       browsingContext = this.browsingContext;
 | |
|     }
 | |
| 
 | |
|     let windowGlobal = browsingContext.currentWindowGlobal;
 | |
|     if (windowGlobal) {
 | |
|       let actor = windowGlobal.getActor("Finder");
 | |
|       actor.sendAsyncMessage(aMessageName, aArgs);
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   sendQueryToContext(aMessageName, aArgs, aBrowsingContext) {
 | |
|     let windowGlobal = aBrowsingContext.currentWindowGlobal;
 | |
|     if (windowGlobal) {
 | |
|       let actor = windowGlobal.getActor("Finder");
 | |
|       return actor.sendQuery(aMessageName, aArgs).then(
 | |
|         result => result,
 | |
|         r => {}
 | |
|       );
 | |
|     }
 | |
| 
 | |
|     return Promise.resolve({});
 | |
|   },
 | |
| 
 | |
|   sendMessageToAllContexts(aMessageName, aArgs = {}) {
 | |
|     let list = this.gatherBrowsingContexts(this.browsingContext);
 | |
|     for (let browsingContext of list) {
 | |
|       let windowGlobal = browsingContext.currentWindowGlobal;
 | |
|       if (windowGlobal) {
 | |
|         let actor = windowGlobal.getActor("Finder");
 | |
|         actor.sendAsyncMessage(aMessageName, aArgs);
 | |
|       }
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   gatherBrowsingContexts(aBrowsingContext) {
 | |
|     if (aBrowsingContext.isUnderHiddenEmbedderElement) {
 | |
|       return [];
 | |
|     }
 | |
| 
 | |
|     let list = [aBrowsingContext];
 | |
| 
 | |
|     for (let child of aBrowsingContext.children) {
 | |
|       list.push(...this.gatherBrowsingContexts(child));
 | |
|     }
 | |
| 
 | |
|     return list;
 | |
|   },
 | |
| 
 | |
|   // If the modal highlighter is on, and there are no out-of-process child
 | |
|   // frames, send a message only to the top-level frame and set the useSubFrames
 | |
|   // flag, so that the finder iterator iterates over subframes. If there is
 | |
|   // an out-of-process subframe, modal highlighting is disabled.
 | |
|   needSubFrameSearch(aList) {
 | |
|     let useSubFrames = false;
 | |
| 
 | |
|     let useModalHighlighter = Services.prefs.getBoolPref(kModalHighlightPref);
 | |
|     let hasOutOfProcessChild = false;
 | |
|     if (useModalHighlighter) {
 | |
|       if (this.useRemoteSubframes) {
 | |
|         return false;
 | |
|       }
 | |
| 
 | |
|       for (let browsingContext of aList) {
 | |
|         if (
 | |
|           browsingContext != this.browsingContext &&
 | |
|           browsingContext.currentWindowGlobal.isProcessRoot
 | |
|         ) {
 | |
|           hasOutOfProcessChild = true;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if (!hasOutOfProcessChild) {
 | |
|         aList.splice(0);
 | |
|         aList.push(this.browsingContext);
 | |
|         useSubFrames = true;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     return useSubFrames;
 | |
|   },
 | |
| 
 | |
|   onResultFound(aResponse) {
 | |
|     this._foundSearchString = aResponse.searchString;
 | |
|     // The rect stops being a Geometry.sys.mjs:Rect over IPC.
 | |
|     if (aResponse.rect) {
 | |
|       aResponse.rect = lazy.Rect.fromRect(aResponse.rect);
 | |
|     }
 | |
| 
 | |
|     this.callListeners("onFindResult", [aResponse]);
 | |
|   },
 | |
| 
 | |
|   get searchString() {
 | |
|     return this._foundSearchString;
 | |
|   },
 | |
| 
 | |
|   get clipboardSearchString() {
 | |
|     return lazy.GetClipboardSearchString(this._browser.loadContext);
 | |
|   },
 | |
| 
 | |
|   set caseSensitive(aSensitive) {
 | |
|     this._caseSensitive = aSensitive;
 | |
|     this.sendMessageToAllContexts("Finder:CaseSensitive", {
 | |
|       caseSensitive: aSensitive,
 | |
|     });
 | |
|   },
 | |
| 
 | |
|   set entireWord(aEntireWord) {
 | |
|     this._entireWord = aEntireWord;
 | |
|     this.sendMessageToAllContexts("Finder:EntireWord", {
 | |
|       entireWord: aEntireWord,
 | |
|     });
 | |
|   },
 | |
| 
 | |
|   set matchDiacritics(aMatchDiacritics) {
 | |
|     this._matchDiacritics = aMatchDiacritics;
 | |
|     this.sendMessageToAllContexts("Finder:MatchDiacritics", {
 | |
|       matchDiacritics: aMatchDiacritics,
 | |
|     });
 | |
|   },
 | |
| 
 | |
|   async setSearchStringToSelection() {
 | |
|     return this.setToSelection("Finder:SetSearchStringToSelection", false);
 | |
|   },
 | |
| 
 | |
|   async getInitialSelection() {
 | |
|     return this.setToSelection("Finder:GetInitialSelection", true);
 | |
|   },
 | |
| 
 | |
|   async setToSelection(aMessage, aInitial) {
 | |
|     let browsingContext = this.browsingContext;
 | |
| 
 | |
|     // Iterate over focused subframe descendants until one is found
 | |
|     // that has the selection.
 | |
|     let result;
 | |
|     do {
 | |
|       result = await this.sendQueryToContext(aMessage, {}, browsingContext);
 | |
|       if (!result || !result.focusedChildBrowserContextId) {
 | |
|         break;
 | |
|       }
 | |
| 
 | |
|       browsingContext = BrowsingContext.get(
 | |
|         result.focusedChildBrowserContextId
 | |
|       );
 | |
|     } while (browsingContext);
 | |
| 
 | |
|     if (result) {
 | |
|       this.callListeners("onCurrentSelection", [result.selectedText, aInitial]);
 | |
|     }
 | |
| 
 | |
|     return result;
 | |
|   },
 | |
| 
 | |
|   async doFind(aFindNext, aArgs) {
 | |
|     let rootBC = this.browsingContext;
 | |
|     let highlightList = this.gatherBrowsingContexts(rootBC);
 | |
| 
 | |
|     let canPlayNotFoundSound =
 | |
|       aArgs.searchString.length > this._searchString.length;
 | |
| 
 | |
|     this._searchString = aArgs.searchString;
 | |
| 
 | |
|     let initialBC = this.getLastFoundBrowsingContext(highlightList);
 | |
|     if (!initialBC) {
 | |
|       initialBC = rootBC;
 | |
|       aFindNext = false;
 | |
|     }
 | |
| 
 | |
|     // Make a copy of the list starting from the
 | |
|     // browsing context that was last searched from. The original
 | |
|     // list will be used for the highlighter where the search
 | |
|     // order doesn't matter.
 | |
|     let searchList = [];
 | |
|     for (let c = 0; c < highlightList.length; c++) {
 | |
|       if (highlightList[c] == initialBC) {
 | |
|         searchList = highlightList.slice(c);
 | |
|         searchList.push(...highlightList.slice(0, c));
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     let mode = Ci.nsITypeAheadFind.FIND_INITIAL;
 | |
|     if (aFindNext) {
 | |
|       mode = aArgs.findBackwards
 | |
|         ? Ci.nsITypeAheadFind.FIND_PREVIOUS
 | |
|         : Ci.nsITypeAheadFind.FIND_NEXT;
 | |
|     }
 | |
|     aArgs.findAgain = aFindNext;
 | |
| 
 | |
|     aArgs.caseSensitive = this._caseSensitive;
 | |
|     aArgs.matchDiacritics = this._matchDiacritics;
 | |
|     aArgs.entireWord = this._entireWord;
 | |
| 
 | |
|     aArgs.useSubFrames = this.needSubFrameSearch(searchList);
 | |
|     if (aArgs.useSubFrames) {
 | |
|       // Use the single frame for the highlight list as well.
 | |
|       highlightList = searchList;
 | |
|       // The typeaheadfind component will play the sound in this case.
 | |
|       canPlayNotFoundSound = false;
 | |
|     }
 | |
| 
 | |
|     if (canPlayNotFoundSound) {
 | |
|       this.initNotFoundSound();
 | |
|     }
 | |
| 
 | |
|     // Add the initial browsing context twice to allow looping around.
 | |
|     searchList = [...searchList, initialBC];
 | |
| 
 | |
|     if (aArgs.findBackwards) {
 | |
|       searchList.reverse();
 | |
|     }
 | |
| 
 | |
|     let response = null;
 | |
|     let wrapped = false;
 | |
|     let foundBC = null;
 | |
| 
 | |
|     for (let c = 0; c < searchList.length; c++) {
 | |
|       let currentBC = searchList[c];
 | |
|       aArgs.mode = mode;
 | |
| 
 | |
|       // A search has started for a different string, so
 | |
|       // ignore further searches of the old string.
 | |
|       if (this._searchString != aArgs.searchString) {
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|       response = await this.sendQueryToContext("Finder:Find", aArgs, currentBC);
 | |
| 
 | |
|       // This can happen if the tab is closed while the find is in progress.
 | |
|       if (!response) {
 | |
|         break;
 | |
|       }
 | |
| 
 | |
|       // If the search term was found, stop iterating.
 | |
|       if (response.result != Ci.nsITypeAheadFind.FIND_NOTFOUND) {
 | |
|         if (
 | |
|           this._lastFoundBrowsingContext &&
 | |
|           this._lastFoundBrowsingContext != currentBC
 | |
|         ) {
 | |
|           // If the new result is in a different frame than the previous result,
 | |
|           // clear the result from the old frame. If it is the same frame, the
 | |
|           // previous result will be cleared by the find component.
 | |
|           this.removeSelection(true);
 | |
|         }
 | |
|         this._lastFoundBrowsingContext = currentBC;
 | |
| 
 | |
|         // Set the wrapped result flag if needed.
 | |
|         if (wrapped) {
 | |
|           response.result = Ci.nsITypeAheadFind.FIND_WRAPPED;
 | |
|         }
 | |
| 
 | |
|         foundBC = currentBC;
 | |
|         break;
 | |
|       }
 | |
| 
 | |
|       if (aArgs.findBackwards && currentBC == rootBC) {
 | |
|         wrapped = true;
 | |
|       } else if (
 | |
|         !aArgs.findBackwards &&
 | |
|         c + 1 < searchList.length &&
 | |
|         searchList[c + 1] == rootBC
 | |
|       ) {
 | |
|         wrapped = true;
 | |
|       }
 | |
| 
 | |
|       mode = aArgs.findBackwards
 | |
|         ? Ci.nsITypeAheadFind.FIND_LAST
 | |
|         : Ci.nsITypeAheadFind.FIND_FIRST;
 | |
|     }
 | |
| 
 | |
|     if (response) {
 | |
|       response.useSubFrames = aArgs.useSubFrames;
 | |
|       // Update the highlight in all browsing contexts. This needs to happen separately
 | |
|       // once it is clear whether a match was found or not.
 | |
|       this.updateHighlightAndMatchCount({
 | |
|         list: highlightList,
 | |
|         message: "Finder:UpdateHighlightAndMatchCount",
 | |
|         args: response,
 | |
|         foundBrowsingContextId: foundBC ? foundBC.id : -1,
 | |
|         doHighlight: true,
 | |
|         doMatchCount: true,
 | |
|       });
 | |
| 
 | |
|       // Use the last result found.
 | |
|       this.onResultFound(response);
 | |
| 
 | |
|       if (
 | |
|         canPlayNotFoundSound &&
 | |
|         response.result == Ci.nsITypeAheadFind.FIND_NOTFOUND &&
 | |
|         !aFindNext &&
 | |
|         !response.entireWord
 | |
|       ) {
 | |
|         this.playNotFoundSound();
 | |
|       }
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   fastFind(aSearchString, aLinksOnly, aDrawOutline) {
 | |
|     this.doFind(false, {
 | |
|       searchString: aSearchString,
 | |
|       findBackwards: false,
 | |
|       linksOnly: aLinksOnly,
 | |
|       drawOutline: aDrawOutline,
 | |
|     });
 | |
|   },
 | |
| 
 | |
|   findAgain(aSearchString, aFindBackwards, aLinksOnly, aDrawOutline) {
 | |
|     this.doFind(true, {
 | |
|       searchString: aSearchString,
 | |
|       findBackwards: aFindBackwards,
 | |
|       linksOnly: aLinksOnly,
 | |
|       drawOutline: aDrawOutline,
 | |
|     });
 | |
|   },
 | |
| 
 | |
|   highlight(aHighlight, aWord, aLinksOnly) {
 | |
|     let list = this.gatherBrowsingContexts(this.browsingContext);
 | |
|     let args = {
 | |
|       highlight: aHighlight,
 | |
|       linksOnly: aLinksOnly,
 | |
|       searchString: aWord,
 | |
|     };
 | |
| 
 | |
|     args.useSubFrames = this.needSubFrameSearch(list);
 | |
| 
 | |
|     let lastBrowsingContext = this.getLastFoundBrowsingContext(list);
 | |
|     this.updateHighlightAndMatchCount({
 | |
|       list,
 | |
|       message: "Finder:Highlight",
 | |
|       args,
 | |
|       foundBrowsingContextId: lastBrowsingContext ? lastBrowsingContext.id : -1,
 | |
|       doHighlight: true,
 | |
|       doMatchCount: false,
 | |
|     });
 | |
|   },
 | |
| 
 | |
|   requestMatchesCount(aSearchString, aLinksOnly) {
 | |
|     let list = this.gatherBrowsingContexts(this.browsingContext);
 | |
|     let args = { searchString: aSearchString, linksOnly: aLinksOnly };
 | |
| 
 | |
|     args.useSubFrames = this.needSubFrameSearch(list);
 | |
| 
 | |
|     let lastBrowsingContext = this.getLastFoundBrowsingContext(list);
 | |
|     this.updateHighlightAndMatchCount({
 | |
|       list,
 | |
|       message: "Finder:MatchesCount",
 | |
|       args,
 | |
|       foundBrowsingContextId: lastBrowsingContext ? lastBrowsingContext.id : -1,
 | |
|       doHighlight: false,
 | |
|       doMatchCount: true,
 | |
|     });
 | |
|   },
 | |
| 
 | |
|   updateHighlightAndMatchCount(options) {
 | |
|     let promises = [];
 | |
|     let found = options.args.result != Ci.nsITypeAheadFind.FIND_NOTFOUND;
 | |
|     for (let browsingContext of options.list) {
 | |
|       options.args.foundInThisFrame =
 | |
|         options.foundBrowsingContextId != -1 &&
 | |
|         found &&
 | |
|         browsingContext.id == options.foundBrowsingContextId;
 | |
| 
 | |
|       // Don't wait for the result
 | |
|       let promise = this.sendQueryToContext(
 | |
|         options.message,
 | |
|         options.args,
 | |
|         browsingContext
 | |
|       );
 | |
|       promises.push(promise);
 | |
|     }
 | |
| 
 | |
|     Promise.all(promises).then(responses => {
 | |
|       if (options.doHighlight) {
 | |
|         let sendNotification = false;
 | |
|         let highlight = false;
 | |
|         let found = false;
 | |
|         for (let response of responses) {
 | |
|           if (!response) {
 | |
|             break;
 | |
|           }
 | |
| 
 | |
|           sendNotification = true;
 | |
|           if (response.found) {
 | |
|             found = true;
 | |
|           }
 | |
|           highlight = response.highlight;
 | |
|         }
 | |
| 
 | |
|         if (sendNotification) {
 | |
|           this.callListeners("onHighlightFinished", [
 | |
|             { searchString: options.args.searchString, highlight, found },
 | |
|           ]);
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if (options.doMatchCount) {
 | |
|         let sendNotification = false;
 | |
|         let current = 0;
 | |
|         let total = 0;
 | |
|         let limit = 0;
 | |
|         for (let response of responses) {
 | |
|           // A null response can happen if another search was started
 | |
|           // and this one became invalid.
 | |
|           if (!response || !("total" in response)) {
 | |
|             break;
 | |
|           }
 | |
| 
 | |
|           sendNotification = true;
 | |
| 
 | |
|           if (
 | |
|             options.args.useSubFrames ||
 | |
|             (options.foundBrowsingContextId >= 0 &&
 | |
|               response.browsingContextId == options.foundBrowsingContextId)
 | |
|           ) {
 | |
|             current = total + response.current;
 | |
|           }
 | |
|           total += response.total;
 | |
|           limit = response.limit;
 | |
|         }
 | |
| 
 | |
|         if (sendNotification) {
 | |
|           this.callListeners("onMatchesCountResult", [
 | |
|             { searchString: options.args.searchString, current, total, limit },
 | |
|           ]);
 | |
|         }
 | |
|       }
 | |
|     });
 | |
|   },
 | |
| 
 | |
|   enableSelection() {
 | |
|     this.sendMessageToContext("Finder:EnableSelection");
 | |
|   },
 | |
| 
 | |
|   removeSelection(aKeepHighlight) {
 | |
|     this.sendMessageToContext("Finder:RemoveSelection", {
 | |
|       keepHighlight: aKeepHighlight,
 | |
|     });
 | |
|   },
 | |
| 
 | |
|   focusContent() {
 | |
|     // Allow Finder listeners to cancel focusing the content.
 | |
|     for (let l of this._listeners) {
 | |
|       try {
 | |
|         if ("shouldFocusContent" in l && !l.shouldFocusContent()) {
 | |
|           return;
 | |
|         }
 | |
|       } catch (ex) {
 | |
|         console.error(ex);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     this._browser.focus();
 | |
|     this.sendMessageToContext("Finder:FocusContent");
 | |
|   },
 | |
| 
 | |
|   onFindbarClose() {
 | |
|     this._lastFoundBrowsingContext = null;
 | |
|     this.sendMessageToAllContexts("Finder:FindbarClose");
 | |
| 
 | |
|     if (lazy.isLetterboxingEnabled) {
 | |
|       let window = this._browser.ownerGlobal;
 | |
|       lazy.RFPHelper.contentSizeUpdated(window);
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   onFindbarOpen() {
 | |
|     this.sendMessageToAllContexts("Finder:FindbarOpen");
 | |
| 
 | |
|     if (lazy.isLetterboxingEnabled) {
 | |
|       let window = this._browser.ownerGlobal;
 | |
|       lazy.RFPHelper.contentSizeUpdated(window);
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   onModalHighlightChange(aUseModalHighlight) {
 | |
|     this.sendMessageToAllContexts("Finder:ModalHighlightChange", {
 | |
|       useModalHighlight: aUseModalHighlight,
 | |
|     });
 | |
|   },
 | |
| 
 | |
|   onHighlightAllChange(aHighlightAll) {
 | |
|     this.sendMessageToAllContexts("Finder:HighlightAllChange", {
 | |
|       highlightAll: aHighlightAll,
 | |
|     });
 | |
|   },
 | |
| 
 | |
|   keyPress(aEvent) {
 | |
|     this.sendMessageToContext("Finder:KeyPress", {
 | |
|       keyCode: aEvent.keyCode,
 | |
|       ctrlKey: aEvent.ctrlKey,
 | |
|       metaKey: aEvent.metaKey,
 | |
|       altKey: aEvent.altKey,
 | |
|       shiftKey: aEvent.shiftKey,
 | |
|     });
 | |
|   },
 | |
| 
 | |
|   initNotFoundSound() {
 | |
|     if (!gSound && lazy.isSoundEnabled && lazy.notFoundSoundURL) {
 | |
|       try {
 | |
|         gSound = Cc["@mozilla.org/sound;1"].getService(Ci.nsISound);
 | |
|         gSound.init();
 | |
|       } catch (ex) {}
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   playNotFoundSound() {
 | |
|     if (!lazy.isSoundEnabled || !lazy.notFoundSoundURL) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     this.initNotFoundSound();
 | |
|     if (!gSound) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     let soundUrl = lazy.notFoundSoundURL;
 | |
|     if (soundUrl == "beep") {
 | |
|       gSound.beep();
 | |
|     } else {
 | |
|       if (soundUrl == "default") {
 | |
|         soundUrl = "chrome://global/content/notfound.wav";
 | |
|       }
 | |
|       gSound.play(Services.io.newURI(soundUrl));
 | |
|     }
 | |
|   },
 | |
| };
 | 
