/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ /* 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/. */ /* eslint-env mozilla/frame-script */ /* eslint no-unused-vars: ["error", {args: "none"}] */ /* global sendAsyncMessage */ ChromeUtils.import("resource://gre/modules/Services.jsm"); ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); ChromeUtils.import("resource://gre/modules/ActorManagerChild.jsm"); ActorManagerChild.attach(this); ChromeUtils.defineModuleGetter(this, "AutoCompletePopup", "resource://gre/modules/AutoCompletePopupContent.jsm"); ChromeUtils.defineModuleGetter(this, "AutoScrollController", "resource://gre/modules/AutoScrollController.jsm"); ChromeUtils.defineModuleGetter(this, "BrowserUtils", "resource://gre/modules/BrowserUtils.jsm"); ChromeUtils.defineModuleGetter(this, "SelectContentHelper", "resource://gre/modules/SelectContentHelper.jsm"); ChromeUtils.defineModuleGetter(this, "FindContent", "resource://gre/modules/FindContent.jsm"); ChromeUtils.defineModuleGetter(this, "PrintingContent", "resource://gre/modules/PrintingContent.jsm"); ChromeUtils.defineModuleGetter(this, "RemoteFinder", "resource://gre/modules/RemoteFinder.jsm"); XPCOMUtils.defineLazyServiceGetter(this, "formFill", "@mozilla.org/satchel/form-fill-controller;1", "nsIFormFillController"); var global = this; XPCOMUtils.defineLazyProxy(this, "PopupBlocking", () => { let tmp = {}; ChromeUtils.import("resource://gre/modules/PopupBlocking.jsm", tmp); return new tmp.PopupBlocking(global); }); XPCOMUtils.defineLazyProxy(this, "ShieldFrameListener", () => { let tmp = {}; ChromeUtils.import("resource://normandy-content/ShieldFrameListener.jsm", tmp); return new tmp.ShieldFrameListener(global); }); XPCOMUtils.defineLazyProxy(this, "UITourListener", () => { let tmp = {}; ChromeUtils.import("resource:///modules/ContentUITour.jsm", tmp); return new tmp.UITourListener(global); }); XPCOMUtils.defineLazyProxy(this, "SelectionSourceContent", "resource://gre/modules/SelectionSourceContent.jsm"); XPCOMUtils.defineLazyProxy(this, "WebChannelContent", "resource://gre/modules/WebChannelContent.jsm"); XPCOMUtils.defineLazyProxy(this, "DateTimePickerContent", () => { let tmp = {}; ChromeUtils.import("resource://gre/modules/DateTimePickerContent.jsm", tmp); return new tmp.DateTimePickerContent(this); }); XPCOMUtils.defineLazyProxy(this, "FindBarChild", () => { let tmp = {}; ChromeUtils.import("resource://gre/modules/FindBarChild.jsm", tmp); return new tmp.FindBarChild(this); }, {inQuickFind: false, inPassThrough: false}); // Lazily load the finder code addMessageListener("Finder:Initialize", function() { let {RemoteFinderListener} = ChromeUtils.import("resource://gre/modules/RemoteFinder.jsm", {}); new RemoteFinderListener(global); }); var AutoScrollListener = { handleEvent(event) { if (event.isTrusted & !event.defaultPrevented && event.button == 1) { if (!this._controller) { this._controller = new AutoScrollController(global); } this._controller.handleEvent(event); } } }; Services.els.addSystemEventListener(global, "mousedown", AutoScrollListener, true); addEventListener("MozOpenDateTimePicker", DateTimePickerContent); addEventListener("DOMPopupBlocked", PopupBlocking, true); var Printing = { MESSAGES: [ "Printing:Preview:Enter", "Printing:Preview:Exit", "Printing:Preview:Navigate", "Printing:Preview:ParseDocument", "Printing:Print", ], init() { this.MESSAGES.forEach(msgName => addMessageListener(msgName, this)); addEventListener("PrintingError", this, true); addEventListener("printPreviewUpdate", this, true); this.init = null; }, handleEvent(event) { return PrintingContent.handleEvent(global, event); }, receiveMessage(message) { return PrintingContent.receiveMessage(global, message); }, }; Printing.init(); var FindBar = { /** * _findKey and _findModifiers are used to determine whether a keypress * is a user attempting to use the find shortcut, after which we'll * route keypresses to the parent until we know the findbar has focus * there. To do this, we need shortcut data from the parent. */ _findKey: null, init() { Services.els.addSystemEventListener(global, "keypress", this.onKeypress.bind(this), false); this.init = null; }, /** * Check whether this key event will start the findbar in the parent, * in which case we should pass any further key events to the parent to avoid * them being lost. * @param aEvent the key event to check. */ eventMatchesFindShortcut(aEvent) { if (!this._findKey) { this._findKey = Services.cpmm.sharedData.get("Findbar:Shortcut"); if (!this._findKey) { return false; } } for (let k in this._findKey) { if (this._findKey[k] != aEvent[k]) { return false; } } return true; }, onKeypress(event) { if (!FindBarChild.inPassThrough && this.eventMatchesFindShortcut(event)) { return FindBarChild.start(event); } if (event.ctrlKey || event.altKey || event.metaKey || event.defaultPrevented || !BrowserUtils.canFastFind(content)) { return null; } if (FindBarChild.inPassThrough || FindBarChild.inQuickFind) { return FindBarChild.onKeypress(event); } if (event.charCode && BrowserUtils.shouldFastFind(event.target)) { let key = String.fromCharCode(event.charCode); if ((key == "/" || key == "'") && RemoteFinder._manualFAYT) { return FindBarChild.startQuickFind(event); } if (key != " " && RemoteFinder._findAsYouType) { return FindBarChild.startQuickFind(event, true); } } return null; }, }; FindBar.init(); addEventListener("WebChannelMessageToChrome", WebChannelContent, true, true); addMessageListener("WebChannelMessageToContent", WebChannelContent); var UnselectedTabHoverObserver = { init() { addMessageListener("Browser:UnselectedTabHover", this); addEventListener("UnselectedTabHover:Enable", this); addEventListener("UnselectedTabHover:Disable", this); this.init = null; }, receiveMessage(message) { Services.obs.notifyObservers(content.window, "unselected-tab-hover", message.data.hovered); }, handleEvent(event) { sendAsyncMessage("UnselectedTabHover:Toggle", { enable: event.type == "UnselectedTabHover:Enable" }); } }; UnselectedTabHoverObserver.init(); var AudibleAutoplayObserver = { init() { addEventListener("AudibleAutoplayMediaOccurred", this); }, handleEvent(event) { sendAsyncMessage("AudibleAutoplayMediaOccurred"); } }; AudibleAutoplayObserver.init(); addMessageListener("Browser:PurgeSessionHistory", function BrowserPurgeHistory() { let sessionHistory = docShell.QueryInterface(Ci.nsIWebNavigation).sessionHistory; if (!sessionHistory) { return; } // place the entry at current index at the end of the history list, so it won't get removed if (sessionHistory.index < sessionHistory.count - 1) { let legacy = sessionHistory.legacySHistory; legacy.QueryInterface(Ci.nsISHistoryInternal); let indexEntry = legacy.getEntryAtIndex(sessionHistory.index, false); indexEntry.QueryInterface(Ci.nsISHEntry); legacy.addEntry(indexEntry, true); } let purge = sessionHistory.count; if (global.content.location.href != "about:blank") { --purge; // Don't remove the page the user's staring at from shistory } if (purge > 0) { sessionHistory.legacySHistory.PurgeHistory(purge); } }); addMessageListener("ViewSource:GetSelection", SelectionSourceContent); let AutoComplete = { _connected: false, init() { addEventListener("unload", this, {once: true}); addEventListener("DOMContentLoaded", this, {once: true}); // WebExtension browserAction is preloaded and does not receive DCL, wait // on pageshow so we can hookup the formfill controller. addEventListener("pageshow", this, {capture: true, once: true}); XPCOMUtils.defineLazyProxy(this, "popup", () => new AutoCompletePopup(global), {QueryInterface: null}); this.init = null; }, handleEvent(event) { switch (event.type) { case "DOMContentLoaded": case "pageshow": // We need to wait for a content viewer to be available // before we can attach our AutoCompletePopup handler, // since nsFormFillController assumes one will exist // when we call attachToBrowser. if (!this._connected) { formFill.attachToBrowser(docShell, this.popup); this._connected = true; } break; case "unload": if (this._connected) { formFill.detachFromBrowser(docShell); this._connected = false; } break; } }, }; AutoComplete.init(); addEventListener("mozshowdropdown", event => { if (!event.isTrusted) return; if (!SelectContentHelper.open) { new SelectContentHelper(event.target, {isOpenedViaTouch: false}, this); } }); addEventListener("mozshowdropdown-sourcetouch", event => { if (!event.isTrusted) return; if (!SelectContentHelper.open) { new SelectContentHelper(event.target, {isOpenedViaTouch: true}, this); } }); let ExtFind = { init() { addMessageListener("ext-Finder:CollectResults", this); addMessageListener("ext-Finder:HighlightResults", this); addMessageListener("ext-Finder:clearHighlighting", this); this.init = null; }, _findContent: null, async receiveMessage(message) { if (!this._findContent) { this._findContent = new FindContent(docShell); } let data; switch (message.name) { case "ext-Finder:CollectResults": this.finderInited = true; data = await this._findContent.findRanges(message.data); sendAsyncMessage("ext-Finder:CollectResultsFinished", data); break; case "ext-Finder:HighlightResults": data = this._findContent.highlightResults(message.data); sendAsyncMessage("ext-Finder:HighlightResultsFinished", data); break; case "ext-Finder:clearHighlighting": this._findContent.highlighter.highlight(false); break; } }, }; ExtFind.init(); addEventListener("ShieldPageEvent", ShieldFrameListener, false, true); addEventListener("mozUITour", UITourListener, false, true);