diff options
Diffstat (limited to 'toolkit/modules/RemoteFinder.jsm')
-rw-r--r-- | toolkit/modules/RemoteFinder.jsm | 332 |
1 files changed, 332 insertions, 0 deletions
diff --git a/toolkit/modules/RemoteFinder.jsm b/toolkit/modules/RemoteFinder.jsm new file mode 100644 index 000000000..ae20da450 --- /dev/null +++ b/toolkit/modules/RemoteFinder.jsm @@ -0,0 +1,332 @@ +// -*- 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/. + +this.EXPORTED_SYMBOLS = ["RemoteFinder", "RemoteFinderListener"]; + +const { interfaces: Ci, classes: Cc, utils: Cu } = Components; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Geometry.jsm"); + +XPCOMUtils.defineLazyGetter(this, "GetClipboardSearchString", + () => Cu.import("resource://gre/modules/Finder.jsm", {}).GetClipboardSearchString +); +XPCOMUtils.defineLazyGetter(this, "Rect", + () => Cu.import("resource://gre/modules/Geometry.jsm", {}).Rect +); + +function RemoteFinder(browser) { + this._listeners = new Set(); + this._searchString = null; + + this.swapBrowser(browser); +} + +RemoteFinder.prototype = { + destroy() {}, + + swapBrowser: function(aBrowser) { + if (this._messageManager) { + this._messageManager.removeMessageListener("Finder:Result", this); + this._messageManager.removeMessageListener("Finder:MatchesResult", this); + this._messageManager.removeMessageListener("Finder:CurrentSelectionResult", this); + this._messageManager.removeMessageListener("Finder:HighlightFinished", this); + } + else { + aBrowser.messageManager.sendAsyncMessage("Finder:Initialize"); + } + + this._browser = aBrowser; + this._messageManager = this._browser.messageManager; + this._messageManager.addMessageListener("Finder:Result", this); + this._messageManager.addMessageListener("Finder:MatchesResult", this); + this._messageManager.addMessageListener("Finder:CurrentSelectionResult", this); + this._messageManager.addMessageListener("Finder:HighlightFinished", this); + + // Ideally listeners would have removed themselves but that doesn't happen + // right now + this._listeners.clear(); + }, + + addResultListener: function (aListener) { + this._listeners.add(aListener); + }, + + removeResultListener: function (aListener) { + this._listeners.delete(aListener); + }, + + receiveMessage: function (aMessage) { + // Only Finder:Result messages have the searchString field. + let callback; + let params; + switch (aMessage.name) { + case "Finder:Result": + this._searchString = aMessage.data.searchString; + // The rect stops being a Geometry.jsm:Rect over IPC. + if (aMessage.data.rect) { + aMessage.data.rect = Rect.fromRect(aMessage.data.rect); + } + callback = "onFindResult"; + params = [ aMessage.data ]; + break; + case "Finder:MatchesResult": + callback = "onMatchesCountResult"; + params = [ aMessage.data ]; + break; + case "Finder:CurrentSelectionResult": + callback = "onCurrentSelection"; + params = [ aMessage.data.selection, aMessage.data.initial ]; + break; + case "Finder:HighlightFinished": + callback = "onHighlightFinished"; + params = [ aMessage.data ]; + break; + } + + for (let l of this._listeners) { + // Don't let one callback throwing stop us calling the rest + try { + l[callback].apply(l, params); + } catch (e) { + if (!l[callback]) { + Cu.reportError(`Missing ${callback} callback on RemoteFinderListener`); + } + Cu.reportError(e); + } + } + }, + + get searchString() { + return this._searchString; + }, + + get clipboardSearchString() { + return GetClipboardSearchString(this._browser.loadContext); + }, + + setSearchStringToSelection() { + this._browser.messageManager.sendAsyncMessage("Finder:SetSearchStringToSelection", {}); + }, + + set caseSensitive(aSensitive) { + this._browser.messageManager.sendAsyncMessage("Finder:CaseSensitive", + { caseSensitive: aSensitive }); + }, + + set entireWord(aEntireWord) { + this._browser.messageManager.sendAsyncMessage("Finder:EntireWord", + { entireWord: aEntireWord }); + }, + + getInitialSelection: function() { + this._browser.messageManager.sendAsyncMessage("Finder:GetInitialSelection", {}); + }, + + fastFind: function (aSearchString, aLinksOnly, aDrawOutline) { + this._browser.messageManager.sendAsyncMessage("Finder:FastFind", + { searchString: aSearchString, + linksOnly: aLinksOnly, + drawOutline: aDrawOutline }); + }, + + findAgain: function (aFindBackwards, aLinksOnly, aDrawOutline) { + this._browser.messageManager.sendAsyncMessage("Finder:FindAgain", + { findBackwards: aFindBackwards, + linksOnly: aLinksOnly, + drawOutline: aDrawOutline }); + }, + + highlight: function (aHighlight, aWord, aLinksOnly) { + this._browser.messageManager.sendAsyncMessage("Finder:Highlight", + { highlight: aHighlight, + linksOnly: aLinksOnly, + word: aWord }); + }, + + enableSelection: function () { + this._browser.messageManager.sendAsyncMessage("Finder:EnableSelection"); + }, + + removeSelection: function () { + this._browser.messageManager.sendAsyncMessage("Finder:RemoveSelection"); + }, + + focusContent: function () { + // Allow Finder listeners to cancel focusing the content. + for (let l of this._listeners) { + try { + if ("shouldFocusContent" in l && + !l.shouldFocusContent()) + return; + } catch (ex) { + Cu.reportError(ex); + } + } + + this._browser.focus(); + this._browser.messageManager.sendAsyncMessage("Finder:FocusContent"); + }, + + onFindbarClose: function () { + this._browser.messageManager.sendAsyncMessage("Finder:FindbarClose"); + }, + + onFindbarOpen: function () { + this._browser.messageManager.sendAsyncMessage("Finder:FindbarOpen"); + }, + + onModalHighlightChange: function(aUseModalHighlight) { + this._browser.messageManager.sendAsyncMessage("Finder:ModalHighlightChange", { + useModalHighlight: aUseModalHighlight + }); + }, + + onHighlightAllChange: function(aHighlightAll) { + this._browser.messageManager.sendAsyncMessage("Finder:HighlightAllChange", { + highlightAll: aHighlightAll + }); + }, + + keyPress: function (aEvent) { + this._browser.messageManager.sendAsyncMessage("Finder:KeyPress", + { keyCode: aEvent.keyCode, + ctrlKey: aEvent.ctrlKey, + metaKey: aEvent.metaKey, + altKey: aEvent.altKey, + shiftKey: aEvent.shiftKey }); + }, + + requestMatchesCount: function (aSearchString, aLinksOnly) { + this._browser.messageManager.sendAsyncMessage("Finder:MatchesCount", + { searchString: aSearchString, + linksOnly: aLinksOnly }); + } +} + +function RemoteFinderListener(global) { + let {Finder} = Cu.import("resource://gre/modules/Finder.jsm", {}); + this._finder = new Finder(global.docShell); + this._finder.addResultListener(this); + this._global = global; + + for (let msg of this.MESSAGES) { + global.addMessageListener(msg, this); + } +} + +RemoteFinderListener.prototype = { + MESSAGES: [ + "Finder:CaseSensitive", + "Finder:EntireWord", + "Finder:FastFind", + "Finder:FindAgain", + "Finder:SetSearchStringToSelection", + "Finder:GetInitialSelection", + "Finder:Highlight", + "Finder:HighlightAllChange", + "Finder:EnableSelection", + "Finder:RemoveSelection", + "Finder:FocusContent", + "Finder:FindbarClose", + "Finder:FindbarOpen", + "Finder:KeyPress", + "Finder:MatchesCount", + "Finder:ModalHighlightChange" + ], + + onFindResult: function (aData) { + this._global.sendAsyncMessage("Finder:Result", aData); + }, + + // When the child receives messages with results of requestMatchesCount, + // it passes them forward to the parent. + onMatchesCountResult: function (aData) { + this._global.sendAsyncMessage("Finder:MatchesResult", aData); + }, + + onHighlightFinished: function(aData) { + this._global.sendAsyncMessage("Finder:HighlightFinished", aData); + }, + + receiveMessage: function (aMessage) { + let data = aMessage.data; + + switch (aMessage.name) { + case "Finder:CaseSensitive": + this._finder.caseSensitive = data.caseSensitive; + break; + + case "Finder:EntireWord": + this._finder.entireWord = data.entireWord; + break; + + case "Finder:SetSearchStringToSelection": { + let selection = this._finder.setSearchStringToSelection(); + this._global.sendAsyncMessage("Finder:CurrentSelectionResult", + { selection: selection, + initial: false }); + break; + } + + case "Finder:GetInitialSelection": { + let selection = this._finder.getActiveSelectionText(); + this._global.sendAsyncMessage("Finder:CurrentSelectionResult", + { selection: selection, + initial: true }); + break; + } + + case "Finder:FastFind": + this._finder.fastFind(data.searchString, data.linksOnly, data.drawOutline); + break; + + case "Finder:FindAgain": + this._finder.findAgain(data.findBackwards, data.linksOnly, data.drawOutline); + break; + + case "Finder:Highlight": + this._finder.highlight(data.highlight, data.word, data.linksOnly); + break; + + case "Finder:HighlightAllChange": + this._finder.onHighlightAllChange(data.highlightAll); + break; + + case "Finder:EnableSelection": + this._finder.enableSelection(); + break; + + case "Finder:RemoveSelection": + this._finder.removeSelection(); + break; + + case "Finder:FocusContent": + this._finder.focusContent(); + break; + + case "Finder:FindbarClose": + this._finder.onFindbarClose(); + break; + + case "Finder:FindbarOpen": + this._finder.onFindbarOpen(); + break; + + case "Finder:KeyPress": + this._finder.keyPress(data); + break; + + case "Finder:MatchesCount": + this._finder.requestMatchesCount(data.searchString, data.linksOnly); + break; + + case "Finder:ModalHighlightChange": + this._finder.onModalHighlightChange(data.useModalHighlight); + break; + } + } +}; |