summaryrefslogtreecommitdiffstats
path: root/toolkit/content/widgets/browser.xml
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/content/widgets/browser.xml')
-rw-r--r--toolkit/content/widgets/browser.xml1571
1 files changed, 1571 insertions, 0 deletions
diff --git a/toolkit/content/widgets/browser.xml b/toolkit/content/widgets/browser.xml
new file mode 100644
index 000000000..a5f37b62a
--- /dev/null
+++ b/toolkit/content/widgets/browser.xml
@@ -0,0 +1,1571 @@
+<?xml version="1.0"?>
+
+<!-- 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/. -->
+
+<bindings id="browserBindings"
+ xmlns="http://www.mozilla.org/xbl"
+ xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <binding id="browser" extends="xul:browser" role="outerdoc">
+ <content clickthrough="never">
+ <children/>
+ </content>
+ <implementation type="application/javascript" implements="nsIObserver, nsIDOMEventListener, nsIMessageListener, nsIBrowser">
+ <property name="autoscrollEnabled">
+ <getter>
+ <![CDATA[
+ if (this.getAttribute("autoscroll") == "false")
+ return false;
+
+ var enabled = true;
+ try {
+ enabled = this.mPrefs.getBoolPref("general.autoScroll");
+ }
+ catch (ex) {
+ }
+
+ return enabled;
+ ]]>
+ </getter>
+ </property>
+
+ <property name="canGoBack"
+ onget="return this.webNavigation.canGoBack;"
+ readonly="true"/>
+
+ <property name="canGoForward"
+ onget="return this.webNavigation.canGoForward;"
+ readonly="true"/>
+
+ <method name="_wrapURIChangeCall">
+ <parameter name="fn"/>
+ <body>
+ <![CDATA[
+ if (!this.isRemoteBrowser) {
+ this.inLoadURI = true;
+ try {
+ fn();
+ } finally {
+ this.inLoadURI = false;
+ }
+ } else {
+ fn();
+ }
+ ]]>
+ </body>
+ </method>
+
+
+ <method name="goBack">
+ <body>
+ <![CDATA[
+ var webNavigation = this.webNavigation;
+ if (webNavigation.canGoBack)
+ this._wrapURIChangeCall(() => webNavigation.goBack());
+ ]]>
+ </body>
+ </method>
+
+ <method name="goForward">
+ <body>
+ <![CDATA[
+ var webNavigation = this.webNavigation;
+ if (webNavigation.canGoForward)
+ this._wrapURIChangeCall(() => webNavigation.goForward());
+ ]]>
+ </body>
+ </method>
+
+ <method name="reload">
+ <body>
+ <![CDATA[
+ const nsIWebNavigation = Components.interfaces.nsIWebNavigation;
+ const flags = nsIWebNavigation.LOAD_FLAGS_NONE;
+ this.reloadWithFlags(flags);
+ ]]>
+ </body>
+ </method>
+
+ <method name="reloadWithFlags">
+ <parameter name="aFlags"/>
+ <body>
+ <![CDATA[
+ this.webNavigation.reload(aFlags);
+ ]]>
+ </body>
+ </method>
+
+ <method name="stop">
+ <body>
+ <![CDATA[
+ const nsIWebNavigation = Components.interfaces.nsIWebNavigation;
+ const flags = nsIWebNavigation.STOP_ALL;
+ this.webNavigation.stop(flags);
+ ]]>
+ </body>
+ </method>
+
+ <!-- throws exception for unknown schemes -->
+ <method name="loadURI">
+ <parameter name="aURI"/>
+ <parameter name="aReferrerURI"/>
+ <parameter name="aCharset"/>
+ <body>
+ <![CDATA[
+ const nsIWebNavigation = Components.interfaces.nsIWebNavigation;
+ const flags = nsIWebNavigation.LOAD_FLAGS_NONE;
+ this._wrapURIChangeCall(() =>
+ this.loadURIWithFlags(aURI, flags, aReferrerURI, aCharset));
+ ]]>
+ </body>
+ </method>
+
+ <!-- throws exception for unknown schemes -->
+ <method name="loadURIWithFlags">
+ <parameter name="aURI"/>
+ <parameter name="aFlags"/>
+ <parameter name="aReferrerURI"/>
+ <parameter name="aCharset"/>
+ <parameter name="aPostData"/>
+ <body>
+ <![CDATA[
+ if (!aURI)
+ aURI = "about:blank";
+
+ var aReferrerPolicy = Components.interfaces.nsIHttpChannel.REFERRER_POLICY_DEFAULT;
+
+ // Check for loadURIWithFlags(uri, { ... });
+ var params = arguments[1];
+ if (params && typeof(params) == "object") {
+ aFlags = params.flags;
+ aReferrerURI = params.referrerURI;
+ if ('referrerPolicy' in params) {
+ aReferrerPolicy = params.referrerPolicy;
+ }
+ aCharset = params.charset;
+ aPostData = params.postData;
+ }
+
+ this._wrapURIChangeCall(() =>
+ this.webNavigation.loadURIWithOptions(
+ aURI, aFlags, aReferrerURI, aReferrerPolicy,
+ aPostData, null, null));
+ ]]>
+ </body>
+ </method>
+
+ <method name="goHome">
+ <body>
+ <![CDATA[
+ try {
+ this.loadURI(this.homePage);
+ }
+ catch (e) {
+ }
+ ]]>
+ </body>
+ </method>
+
+ <property name="homePage">
+ <getter>
+ <![CDATA[
+ var uri;
+
+ if (this.hasAttribute("homepage"))
+ uri = this.getAttribute("homepage");
+ else
+ uri = "http://www.mozilla.org/"; // widget pride
+
+ return uri;
+ ]]>
+ </getter>
+ <setter>
+ <![CDATA[
+ this.setAttribute("homepage", val);
+ return val;
+ ]]>
+ </setter>
+ </property>
+
+ <method name="gotoIndex">
+ <parameter name="aIndex"/>
+ <body>
+ <![CDATA[
+ this._wrapURIChangeCall(() => this.webNavigation.gotoIndex(aIndex));
+ ]]>
+ </body>
+ </method>
+
+ <property name="currentURI" readonly="true">
+ <getter><![CDATA[
+ if (this.webNavigation) {
+ return this.webNavigation.currentURI;
+ }
+ return null;
+ ]]>
+ </getter>
+ </property>
+
+ <!--
+ Used by session restore to ensure that currentURI is set so
+ that switch-to-tab works before the tab is fully
+ restored. This function also invokes onLocationChanged
+ listeners in tabbrowser.xml.
+ -->
+ <method name="_setCurrentURI">
+ <parameter name="aURI"/>
+ <body><![CDATA[
+ this.docShell.setCurrentURI(aURI);
+ ]]></body>
+ </method>
+
+ <property name="documentURI"
+ onget="return this.contentDocument.documentURIObject;"
+ readonly="true"/>
+
+ <property name="documentContentType"
+ onget="return this.contentDocument ? this.contentDocument.contentType : null;"
+ readonly="true"/>
+
+ <property name="preferences"
+ onget="return this.mPrefs.QueryInterface(Components.interfaces.nsIPrefService);"
+ readonly="true"/>
+
+ <!--
+ Weak reference to the related browser (see
+ nsIBrowser.getRelatedBrowser).
+ -->
+ <field name="_relatedBrowser">null</field>
+ <property name="relatedBrowser">
+ <getter><![CDATA[
+ return this._relatedBrowser && this._relatedBrowser.get();
+ ]]></getter>
+ <setter><![CDATA[
+ this._relatedBrowser = Cu.getWeakReference(val);
+ ]]></setter>
+ </property>
+
+ <field name="_docShell">null</field>
+
+ <property name="docShell" readonly="true">
+ <getter><![CDATA[
+ if (this._docShell)
+ return this._docShell;
+
+ let frameLoader = this.QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader;
+ if (!frameLoader)
+ return null;
+ this._docShell = frameLoader.docShell;
+ return this._docShell;
+ ]]></getter>
+ </property>
+
+ <field name="_loadContext">null</field>
+
+ <property name="loadContext" readonly="true">
+ <getter><![CDATA[
+ if (this._loadContext)
+ return this._loadContext;
+
+ let frameLoader = this.QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader;
+ if (!frameLoader)
+ return null;
+ this._loadContext = frameLoader.loadContext;
+ return this._loadContext;
+ ]]></getter>
+ </property>
+
+ <property name="autoCompletePopup"
+ onget="return document.getElementById(this.getAttribute('autocompletepopup'))"
+ readonly="true"/>
+
+ <property name="dateTimePicker"
+ onget="return document.getElementById(this.getAttribute('datetimepicker'))"
+ readonly="true"/>
+
+ <property name="docShellIsActive">
+ <getter>
+ <![CDATA[
+ return this.docShell && this.docShell.isActive;
+ ]]>
+ </getter>
+ <setter>
+ <![CDATA[
+ if (this.docShell)
+ return this.docShell.isActive = val;
+ return false;
+ ]]>
+ </setter>
+ </property>
+
+ <method name="preserveLayers">
+ <parameter name="preserve"/>
+ <body>
+ // Only useful for remote browsers.
+ </body>
+ </method>
+
+ <method name="makePrerenderedBrowserActive">
+ <body>
+ <![CDATA[
+ let frameLoader = this.QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader;
+ if (frameLoader) {
+ frameLoader.makePrerenderedLoaderActive();
+ }
+ ]]>
+ </body>
+ </method>
+
+ <property name="imageDocument"
+ readonly="true">
+ <getter>
+ <![CDATA[
+ var document = this.contentDocument;
+ if (!document || !(document instanceof Components.interfaces.nsIImageDocument))
+ return null;
+
+ try {
+ return {width: document.imageRequest.image.width, height: document.imageRequest.image.height };
+ } catch (e) {}
+ return null;
+ ]]>
+ </getter>
+ </property>
+
+ <property name="isRemoteBrowser"
+ onget="return (this.getAttribute('remote') == 'true');"
+ readonly="true"/>
+
+ <property name="messageManager"
+ readonly="true">
+ <getter>
+ <![CDATA[
+ var owner = this.QueryInterface(Components.interfaces.nsIFrameLoaderOwner);
+ if (!owner.frameLoader) {
+ return null;
+ }
+ return owner.frameLoader.messageManager;
+ ]]>
+ </getter>
+
+ </property>
+
+ <field name="_webNavigation">null</field>
+
+ <property name="webNavigation"
+ readonly="true">
+ <getter>
+ <![CDATA[
+ if (!this._webNavigation) {
+ if (!this.docShell) {
+ return null;
+ }
+ this._webNavigation = this.docShell.QueryInterface(Components.interfaces.nsIWebNavigation);
+ }
+ return this._webNavigation;
+ ]]>
+ </getter>
+ </property>
+
+ <field name="_webBrowserFind">null</field>
+
+ <property name="webBrowserFind"
+ readonly="true">
+ <getter>
+ <![CDATA[
+ if (!this._webBrowserFind)
+ this._webBrowserFind = this.docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIWebBrowserFind);
+ return this._webBrowserFind;
+ ]]>
+ </getter>
+ </property>
+
+ <method name="getTabBrowser">
+ <body>
+ <![CDATA[
+ var tabBrowser = this.parentNode;
+ while (tabBrowser && tabBrowser.localName != "tabbrowser")
+ tabBrowser = tabBrowser.parentNode;
+ return tabBrowser;
+ ]]>
+ </body>
+ </method>
+
+ <field name="_finder">null</field>
+
+ <property name="finder" readonly="true">
+ <getter><![CDATA[
+ if (!this._finder) {
+ if (!this.docShell)
+ return null;
+
+ let Finder = Components.utils.import("resource://gre/modules/Finder.jsm", {}).Finder;
+ this._finder = new Finder(this.docShell);
+ }
+ return this._finder;
+ ]]></getter>
+ </property>
+
+ <field name="_fastFind">null</field>
+ <property name="fastFind" readonly="true">
+ <getter><![CDATA[
+ if (!this._fastFind) {
+ if (!("@mozilla.org/typeaheadfind;1" in Components.classes))
+ return null;
+
+ var tabBrowser = this.getTabBrowser();
+ if (tabBrowser && "fastFind" in tabBrowser)
+ return this._fastFind = tabBrowser.fastFind;
+
+ if (!this.docShell)
+ return null;
+
+ this._fastFind = Components.classes["@mozilla.org/typeaheadfind;1"]
+ .createInstance(Components.interfaces.nsITypeAheadFind);
+ this._fastFind.init(this.docShell);
+ }
+ return this._fastFind;
+ ]]></getter>
+ </property>
+
+ <property name="outerWindowID" readonly="true">
+ <getter><![CDATA[
+ return this.contentWindow
+ .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIDOMWindowUtils)
+ .outerWindowID;
+ ]]></getter>
+ </property>
+
+ <property name="innerWindowID" readonly="true">
+ <getter><![CDATA[
+ try {
+ return this.contentWindow
+ .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIDOMWindowUtils)
+ .currentInnerWindowID;
+ } catch (e) {
+ if (e.result != Cr.NS_ERROR_NOT_AVAILABLE) {
+ throw e;
+ }
+ return null;
+ }
+ ]]></getter>
+ </property>
+
+ <field name="_lastSearchString">null</field>
+
+ <property name="webProgress"
+ readonly="true"
+ onget="return this.docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIWebProgress);"/>
+
+ <field name="_contentWindow">null</field>
+
+ <property name="contentWindow"
+ readonly="true"
+ onget="return this._contentWindow || (this._contentWindow = this.docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindow));"/>
+
+ <property name="contentWindowAsCPOW"
+ readonly="true"
+ onget="return this.contentWindow;"/>
+
+ <property name="sessionHistory"
+ onget="return this.webNavigation.sessionHistory;"
+ readonly="true"/>
+
+ <property name="markupDocumentViewer"
+ onget="return this.docShell.contentViewer;"
+ readonly="true"/>
+
+ <property name="contentViewerEdit"
+ onget="return this.docShell.contentViewer.QueryInterface(Components.interfaces.nsIContentViewerEdit);"
+ readonly="true"/>
+
+ <property name="contentViewerFile"
+ onget="return this.docShell.contentViewer.QueryInterface(Components.interfaces.nsIContentViewerFile);"
+ readonly="true"/>
+
+ <property name="contentDocument"
+ onget="return this.webNavigation.document;"
+ readonly="true"/>
+
+ <property name="contentDocumentAsCPOW"
+ onget="return this.contentDocument;"
+ readonly="true"/>
+
+ <property name="contentTitle"
+ onget="return this.contentDocument.title;"
+ readonly="true"/>
+
+ <property name="characterSet"
+ onget="return this.docShell.charset;">
+ <setter><![CDATA[
+ this.docShell.charset = val;
+ this.docShell.gatherCharsetMenuTelemetry();
+ ]]></setter>
+ </property>
+
+ <property name="mayEnableCharacterEncodingMenu"
+ onget="return this.docShell.mayEnableCharacterEncodingMenu;"
+ readonly="true"/>
+
+ <property name="contentPrincipal"
+ onget="return this.contentDocument.nodePrincipal;"
+ readonly="true"/>
+
+ <property name="showWindowResizer"
+ onset="if (val) this.setAttribute('showresizer', 'true');
+ else this.removeAttribute('showresizer');
+ return val;"
+ onget="return this.getAttribute('showresizer') == 'true';"/>
+
+ <property name="manifestURI"
+ readonly="true">
+ <getter><![CDATA[
+ return this.contentDocument.documentElement &&
+ this.contentDocument.documentElement.getAttribute("manifest");
+ ]]></getter>
+ </property>
+
+ <property name="fullZoom">
+ <getter><![CDATA[
+ return this.markupDocumentViewer.fullZoom;
+ ]]></getter>
+ <setter><![CDATA[
+ this.markupDocumentViewer.fullZoom = val;
+ ]]></setter>
+ </property>
+
+ <property name="textZoom">
+ <getter><![CDATA[
+ return this.markupDocumentViewer.textZoom;
+ ]]></getter>
+ <setter><![CDATA[
+ this.markupDocumentViewer.textZoom = val;
+ ]]></setter>
+ </property>
+
+ <property name="isSyntheticDocument">
+ <getter><![CDATA[
+ return this.contentDocument.mozSyntheticDocument;
+ ]]></getter>
+ </property>
+
+ <property name="hasContentOpener">
+ <getter><![CDATA[
+ return !!this.contentWindow.opener;
+ ]]></getter>
+ </property>
+
+ <field name="mPrefs" readonly="true">
+ Components.classes['@mozilla.org/preferences-service;1']
+ .getService(Components.interfaces.nsIPrefBranch);
+ </field>
+
+ <field name="_mStrBundle">null</field>
+
+ <property name="mStrBundle">
+ <getter>
+ <![CDATA[
+ if (!this._mStrBundle) {
+ // need to create string bundle manually instead of using <xul:stringbundle/>
+ // see bug 63370 for details
+ this._mStrBundle = Components.classes["@mozilla.org/intl/stringbundle;1"]
+ .getService(Components.interfaces.nsIStringBundleService)
+ .createBundle("chrome://global/locale/browser.properties");
+ }
+ return this._mStrBundle;
+ ]]></getter>
+ </property>
+
+ <method name="addProgressListener">
+ <parameter name="aListener"/>
+ <parameter name="aNotifyMask"/>
+ <body>
+ <![CDATA[
+ if (!aNotifyMask) {
+ aNotifyMask = Components.interfaces.nsIWebProgress.NOTIFY_ALL;
+ }
+ this.webProgress.addProgressListener(aListener, aNotifyMask);
+ ]]>
+ </body>
+ </method>
+
+ <method name="removeProgressListener">
+ <parameter name="aListener"/>
+ <body>
+ <![CDATA[
+ this.webProgress.removeProgressListener(aListener);
+ ]]>
+ </body>
+ </method>
+
+ <method name="findChildShell">
+ <parameter name="aDocShell"/>
+ <parameter name="aSoughtURI"/>
+ <body>
+ <![CDATA[
+ if (aDocShell.QueryInterface(Components.interfaces.nsIWebNavigation)
+ .currentURI.spec == aSoughtURI.spec)
+ return aDocShell;
+ var node = aDocShell.QueryInterface(
+ Components.interfaces.nsIDocShellTreeItem);
+ for (var i = 0; i < node.childCount; ++i) {
+ var docShell = node.getChildAt(i);
+ docShell = this.findChildShell(docShell, aSoughtURI);
+ if (docShell)
+ return docShell;
+ }
+ return null;
+ ]]>
+ </body>
+ </method>
+
+ <method name="onPageHide">
+ <parameter name="aEvent"/>
+ <body>
+ <![CDATA[
+ // Delete the feeds cache if we're hiding the topmost page
+ // (as opposed to one of its iframes).
+ if (this.feeds && aEvent.target == this.contentDocument)
+ this.feeds = null;
+ if (!this.docShell || !this.fastFind)
+ return;
+ var tabBrowser = this.getTabBrowser();
+ if (!tabBrowser || !("fastFind" in tabBrowser) ||
+ tabBrowser.selectedBrowser == this)
+ this.fastFind.setDocShell(this.docShell);
+ ]]>
+ </body>
+ </method>
+
+ <method name="updateBlockedPopups">
+ <body>
+ <![CDATA[
+ let event = document.createEvent("Events");
+ event.initEvent("DOMUpdatePageReport", true, true);
+ this.dispatchEvent(event);
+ ]]>
+ </body>
+ </method>
+
+ <method name="retrieveListOfBlockedPopups">
+ <body>
+ <![CDATA[
+ this.messageManager.sendAsyncMessage("PopupBlocking:GetBlockedPopupList", null);
+ return new Promise(resolve => {
+ let self = this;
+ this.messageManager.addMessageListener("PopupBlocking:ReplyGetBlockedPopupList",
+ function replyReceived(msg) {
+ self.messageManager.removeMessageListener("PopupBlocking:ReplyGetBlockedPopupList",
+ replyReceived);
+ resolve(msg.data.popupData);
+ }
+ );
+ });
+ ]]>
+ </body>
+ </method>
+
+ <method name="unblockPopup">
+ <parameter name="aPopupIndex"/>
+ <body><![CDATA[
+ this.messageManager.sendAsyncMessage("PopupBlocking:UnblockPopup",
+ {index: aPopupIndex});
+ ]]></body>
+ </method>
+
+ <field name="blockedPopups">null</field>
+
+ <!-- Obsolete name for blockedPopups. Used by android. -->
+ <property name="pageReport"
+ onget="return this.blockedPopups;"
+ readonly="true"/>
+
+ <method name="audioPlaybackStarted">
+ <body>
+ <![CDATA[
+ let event = document.createEvent("Events");
+ event.initEvent("DOMAudioPlaybackStarted", true, false);
+ this.dispatchEvent(event);
+ if (this._audioBlocked) {
+ this._audioBlocked = false;
+ event = document.createEvent("Events");
+ event.initEvent("DOMAudioPlaybackBlockStopped", true, false);
+ this.dispatchEvent(event);
+ }
+ ]]>
+ </body>
+ </method>
+
+ <method name="audioPlaybackStopped">
+ <body>
+ <![CDATA[
+ let event = document.createEvent("Events");
+ event.initEvent("DOMAudioPlaybackStopped", true, false);
+ this.dispatchEvent(event);
+ ]]>
+ </body>
+ </method>
+
+ <method name="audioPlaybackBlocked">
+ <body>
+ <![CDATA[
+ this._audioBlocked = true;
+ let event = document.createEvent("Events");
+ event.initEvent("DOMAudioPlaybackBlockStarted", true, false);
+ this.dispatchEvent(event);
+ ]]>
+ </body>
+ </method>
+
+ <field name="_audioMuted">false</field>
+ <property name="audioMuted"
+ onget="return this._audioMuted;"
+ readonly="true"/>
+
+
+ <field name="_audioBlocked">false</field>
+ <property name="audioBlocked"
+ onget="return this._audioBlocked;"
+ readonly="true"/>
+
+ <method name="mute">
+ <body>
+ <![CDATA[
+ this._audioMuted = true;
+ this.messageManager.sendAsyncMessage("AudioPlayback",
+ {type: "mute"});
+ ]]>
+ </body>
+ </method>
+
+ <method name="unmute">
+ <body>
+ <![CDATA[
+ this._audioMuted = false;
+ this.messageManager.sendAsyncMessage("AudioPlayback",
+ {type: "unmute"});
+ ]]>
+ </body>
+ </method>
+
+ <method name="pauseMedia">
+ <parameter name="disposable"/>
+ <body>
+ <![CDATA[
+ let suspendedReason;
+ if (disposable) {
+ suspendedReason = "mediaControlPaused";
+ } else {
+ suspendedReason = "lostAudioFocusTransiently";
+ }
+
+ this.messageManager.sendAsyncMessage("AudioPlayback",
+ {type: suspendedReason});
+ ]]>
+ </body>
+ </method>
+
+ <method name="stopMedia">
+ <body>
+ <![CDATA[
+ this.messageManager.sendAsyncMessage("AudioPlayback",
+ {type: "mediaControlStopped"});
+ ]]>
+ </body>
+ </method>
+
+ <method name="blockMedia">
+ <body>
+ <![CDATA[
+ this._audioBlocked = true;
+ this.messageManager.sendAsyncMessage("AudioPlayback",
+ {type: "blockInactivePageMedia"});
+ ]]>
+ </body>
+ </method>
+
+ <method name="resumeMedia">
+ <body>
+ <![CDATA[
+ this._audioBlocked = false;
+ this.messageManager.sendAsyncMessage("AudioPlayback",
+ {type: "resumeMedia"});
+ let event = document.createEvent("Events");
+ event.initEvent("DOMAudioPlaybackBlockStopped", true, false);
+ this.dispatchEvent(event);
+ ]]>
+ </body>
+ </method>
+
+ <property name="securityUI">
+ <getter>
+ <![CDATA[
+ if (!this.docShell.securityUI) {
+ const SECUREBROWSERUI_CONTRACTID = "@mozilla.org/secure_browser_ui;1";
+ if (!this.hasAttribute("disablesecurity") &&
+ SECUREBROWSERUI_CONTRACTID in Components.classes) {
+ var securityUI = Components.classes[SECUREBROWSERUI_CONTRACTID]
+ .createInstance(Components.interfaces.nsISecureBrowserUI);
+ securityUI.init(this.contentWindow);
+ }
+ }
+
+ return this.docShell.securityUI;
+ ]]>
+ </getter>
+ <setter>
+ <![CDATA[
+ this.docShell.securityUI = val;
+ ]]>
+ </setter>
+ </property>
+
+ <!-- increases or decreases the browser's network priority -->
+ <method name="adjustPriority">
+ <parameter name="adjustment"/>
+ <body><![CDATA[
+ let loadGroup = this.webNavigation.QueryInterface(Components.interfaces.nsIDocumentLoader)
+ .loadGroup.QueryInterface(Components.interfaces.nsISupportsPriority);
+ loadGroup.adjustPriority(adjustment);
+ ]]></body>
+ </method>
+
+ <!-- sets the browser's network priority to a discrete value -->
+ <method name="setPriority">
+ <parameter name="priority"/>
+ <body><![CDATA[
+ let loadGroup = this.webNavigation.QueryInterface(Components.interfaces.nsIDocumentLoader)
+ .loadGroup.QueryInterface(Components.interfaces.nsISupportsPriority);
+ loadGroup.priority = priority;
+ ]]></body>
+ </method>
+
+ <field name="urlbarChangeTracker">
+ ({
+ _startedLoadSinceLastUserTyping: false,
+
+ startedLoad() {
+ this._startedLoadSinceLastUserTyping = true;
+ },
+ finishedLoad() {
+ this._startedLoadSinceLastUserTyping = false;
+ },
+ userTyped() {
+ this._startedLoadSinceLastUserTyping = false;
+ },
+ })
+ </field>
+
+ <method name="didStartLoadSinceLastUserTyping">
+ <body><![CDATA[
+ return !this.inLoadURI &&
+ this.urlbarChangeTracker._startedLoadSinceLastUserTyping;
+ ]]></body>
+ </method>
+
+ <field name="_userTypedValue">
+ null
+ </field>
+
+ <property name="userTypedValue"
+ onget="return this._userTypedValue;">
+ <setter><![CDATA[
+ this.urlbarChangeTracker.userTyped();
+ this._userTypedValue = val;
+ return val;
+ ]]></setter>
+ </property>
+
+ <field name="mFormFillAttached">
+ false
+ </field>
+
+ <field name="isShowingMessage">
+ false
+ </field>
+
+ <field name="droppedLinkHandler">
+ null
+ </field>
+
+ <field name="mIconURL">null</field>
+
+ <!-- This is managed by the tabbrowser -->
+ <field name="lastURI">null</field>
+
+ <field name="mDestroyed">false</field>
+
+ <constructor>
+ <![CDATA[
+ try {
+ // |webNavigation.sessionHistory| will have been set by the frame
+ // loader when creating the docShell as long as this xul:browser
+ // doesn't have the 'disablehistory' attribute set.
+ if (this.docShell && this.webNavigation.sessionHistory) {
+ var os = Components.classes["@mozilla.org/observer-service;1"]
+ .getService(Components.interfaces.nsIObserverService);
+ os.addObserver(this, "browser:purge-session-history", true);
+
+ // enable global history if we weren't told otherwise
+ if (!this.hasAttribute("disableglobalhistory") && !this.isRemoteBrowser) {
+ try {
+ this.docShell.useGlobalHistory = true;
+ } catch (ex) {
+ // This can occur if the Places database is locked
+ Components.utils.reportError("Error enabling browser global history: " + ex);
+ }
+ }
+ }
+ }
+ catch (e) {
+ Components.utils.reportError(e);
+ }
+ try {
+ var securityUI = this.securityUI;
+ }
+ catch (e) {
+ }
+
+ // XXX tabbrowser.xml sets "relatedBrowser" as a direct property on
+ // some browsers before they are put into a DOM (and get a binding).
+ // This hack makes sure that we hold a weak reference to the other
+ // browser (and go through the proper getter and setter).
+ if (this.hasOwnProperty("relatedBrowser")) {
+ var relatedBrowser = this.relatedBrowser;
+ delete this.relatedBrowser;
+ this.relatedBrowser = relatedBrowser;
+ }
+
+ if (!this.isRemoteBrowser) {
+ this.addEventListener("pagehide", this.onPageHide, true);
+ }
+
+ if (this.messageManager) {
+ this.messageManager.addMessageListener("PopupBlocking:UpdateBlockedPopups", this);
+ this.messageManager.addMessageListener("Autoscroll:Start", this);
+ this.messageManager.addMessageListener("Autoscroll:Cancel", this);
+ this.messageManager.addMessageListener("AudioPlayback:Start", this);
+ this.messageManager.addMessageListener("AudioPlayback:Stop", this);
+ this.messageManager.addMessageListener("AudioPlayback:Block", this);
+ }
+ ]]>
+ </constructor>
+
+ <destructor>
+ <![CDATA[
+ this.destroy();
+ ]]>
+ </destructor>
+
+ <!-- This is necessary because the destructor doesn't always get called when
+ we are removed from a tabbrowser. This will be explicitly called by tabbrowser.
+
+ Note: this function is overriden in remote-browser.xml, so any clean-up that
+ also applies to browser.isRemoteBrowser = true must be duplicated there. -->
+ <method name="destroy">
+ <body>
+ <![CDATA[
+ if (this.mDestroyed)
+ return;
+ this.mDestroyed = true;
+
+ if (this.docShell && this.webNavigation.sessionHistory) {
+ var os = Components.classes["@mozilla.org/observer-service;1"]
+ .getService(Components.interfaces.nsIObserverService);
+ try {
+ os.removeObserver(this, "browser:purge-session-history");
+ } catch (ex) {
+ // It's not clear why this sometimes throws an exception.
+ }
+ }
+
+ this._fastFind = null;
+ this._webBrowserFind = null;
+
+ // The feeds cache can keep the document inside this browser alive.
+ this.feeds = null;
+
+ this.lastURI = null;
+
+ if (!this.isRemoteBrowser) {
+ this.removeEventListener("pagehide", this.onPageHide, true);
+ }
+
+ if (this._autoScrollNeedsCleanup) {
+ // we polluted the global scope, so clean it up
+ this._autoScrollPopup.parentNode.removeChild(this._autoScrollPopup);
+ }
+ ]]>
+ </body>
+ </method>
+
+ <!--
+ We call this _receiveMessage (and alias receiveMessage to it) so that
+ bindings that inherit from this one can delegate to it.
+ -->
+ <method name="_receiveMessage">
+ <parameter name="aMessage"/>
+ <body><![CDATA[
+ let data = aMessage.data;
+ switch (aMessage.name) {
+ case "PopupBlocking:UpdateBlockedPopups": {
+ this.blockedPopups = {
+ length: data.count,
+ reported: !data.freshPopup,
+ };
+
+ this.updateBlockedPopups();
+ break;
+ }
+ case "Autoscroll:Start": {
+ if (!this.autoscrollEnabled) {
+ return false;
+ }
+ this.startScroll(data.scrolldir, data.screenX, data.screenY);
+ return true;
+ }
+ case "Autoscroll:Cancel":
+ this._autoScrollPopup.hidePopup();
+ break;
+ case "AudioPlayback:Start":
+ this.audioPlaybackStarted();
+ break;
+ case "AudioPlayback:Stop":
+ this.audioPlaybackStopped();
+ break;
+ case "AudioPlayback:Block":
+ this.audioPlaybackBlocked();
+ break;
+ }
+ return undefined;
+ ]]></body>
+ </method>
+
+ <method name="receiveMessage">
+ <parameter name="aMessage"/>
+ <body><![CDATA[
+ return this._receiveMessage(aMessage);
+ ]]></body>
+ </method>
+
+ <method name="observe">
+ <parameter name="aSubject"/>
+ <parameter name="aTopic"/>
+ <parameter name="aState"/>
+ <body>
+ <![CDATA[
+ if (aTopic != "browser:purge-session-history")
+ return;
+
+ this.purgeSessionHistory();
+ ]]>
+ </body>
+ </method>
+
+ <method name="purgeSessionHistory">
+ <body>
+ <![CDATA[
+ this.messageManager.sendAsyncMessage("Browser:PurgeSessionHistory");
+ ]]>
+ </body>
+ </method>
+
+ <method name="createAboutBlankContentViewer">
+ <parameter name="aPrincipal"/>
+ <body>
+ <![CDATA[
+ let principal = BrowserUtils.principalWithMatchingOA(aPrincipal, this.contentPrincipal);
+ this.docShell.createAboutBlankContentViewer(principal);
+ ]]>
+ </body>
+ </method>
+
+ <field name="_AUTOSCROLL_SNAP">10</field>
+ <field name="_scrolling">false</field>
+ <field name="_startX">null</field>
+ <field name="_startY">null</field>
+ <field name="_autoScrollPopup">null</field>
+ <field name="_autoScrollNeedsCleanup">false</field>
+
+ <method name="stopScroll">
+ <body>
+ <![CDATA[
+ if (this._scrolling) {
+ this._scrolling = false;
+ window.removeEventListener("mousemove", this, true);
+ window.removeEventListener("mousedown", this, true);
+ window.removeEventListener("mouseup", this, true);
+ window.removeEventListener("DOMMouseScroll", this, true);
+ window.removeEventListener("contextmenu", this, true);
+ window.removeEventListener("keydown", this, true);
+ window.removeEventListener("keypress", this, true);
+ window.removeEventListener("keyup", this, true);
+ this.messageManager.sendAsyncMessage("Autoscroll:Stop");
+ }
+ ]]>
+ </body>
+ </method>
+
+ <method name="_createAutoScrollPopup">
+ <body>
+ <![CDATA[
+ const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+ var popup = document.createElementNS(XUL_NS, "panel");
+ popup.className = "autoscroller";
+ // We set this attribute on the element so that mousemove
+ // events can be handled by browser-content.js.
+ popup.setAttribute("mousethrough", "always");
+ popup.setAttribute("rolluponmousewheel", "true");
+ return popup;
+ ]]>
+ </body>
+ </method>
+
+ <method name="startScroll">
+ <parameter name="scrolldir"/>
+ <parameter name="screenX"/>
+ <parameter name="screenY"/>
+ <body><![CDATA[
+ if (!this._autoScrollPopup) {
+ if (this.hasAttribute("autoscrollpopup")) {
+ // our creator provided a popup to share
+ this._autoScrollPopup = document.getElementById(this.getAttribute("autoscrollpopup"));
+ }
+ else {
+ // we weren't provided a popup; we have to use the global scope
+ this._autoScrollPopup = this._createAutoScrollPopup();
+ document.documentElement.appendChild(this._autoScrollPopup);
+ this._autoScrollNeedsCleanup = true;
+ }
+ }
+
+ // we need these attributes so themers don't need to create per-platform packages
+ if (screen.colorDepth > 8) { // need high color for transparency
+ // Exclude second-rate platforms
+ this._autoScrollPopup.setAttribute("transparent", !/BeOS|OS\/2/.test(navigator.appVersion));
+ // Enable translucency on Windows and Mac
+ this._autoScrollPopup.setAttribute("translucent", /Win|Mac/.test(navigator.platform));
+ }
+
+ this._autoScrollPopup.setAttribute("noautofocus", "true");
+ this._autoScrollPopup.setAttribute("scrolldir", scrolldir);
+ this._autoScrollPopup.addEventListener("popuphidden", this, true);
+ this._autoScrollPopup.showPopup(document.documentElement,
+ screenX,
+ screenY,
+ "popup", null, null);
+ this._ignoreMouseEvents = true;
+ this._scrolling = true;
+ this._startX = screenX;
+ this._startY = screenY;
+
+ window.addEventListener("mousemove", this, true);
+ window.addEventListener("mousedown", this, true);
+ window.addEventListener("mouseup", this, true);
+ window.addEventListener("DOMMouseScroll", this, true);
+ window.addEventListener("contextmenu", this, true);
+ window.addEventListener("keydown", this, true);
+ window.addEventListener("keypress", this, true);
+ window.addEventListener("keyup", this, true);
+ ]]>
+ </body>
+ </method>
+
+ <method name="handleEvent">
+ <parameter name="aEvent"/>
+ <body>
+ <![CDATA[
+ if (this._scrolling) {
+ switch (aEvent.type) {
+ case "mousemove": {
+ var x = aEvent.screenX - this._startX;
+ var y = aEvent.screenY - this._startY;
+
+ if ((x > this._AUTOSCROLL_SNAP || x < -this._AUTOSCROLL_SNAP) ||
+ (y > this._AUTOSCROLL_SNAP || y < -this._AUTOSCROLL_SNAP))
+ this._ignoreMouseEvents = false;
+ break;
+ }
+ case "mouseup":
+ case "mousedown":
+ case "contextmenu": {
+ if (!this._ignoreMouseEvents) {
+ // Use a timeout to prevent the mousedown from opening the popup again.
+ // Ideally, we could use preventDefault here, but contenteditable
+ // and middlemouse paste don't interact well. See bug 1188536.
+ setTimeout(() => this._autoScrollPopup.hidePopup(), 0);
+ }
+ this._ignoreMouseEvents = false;
+ break;
+ }
+ case "DOMMouseScroll": {
+ this._autoScrollPopup.hidePopup();
+ event.preventDefault();
+ break;
+ }
+ case "popuphidden": {
+ this._autoScrollPopup.removeEventListener("popuphidden", this, true);
+ this.stopScroll();
+ break;
+ }
+ case "keydown": {
+ if (aEvent.keyCode == aEvent.DOM_VK_ESCAPE) {
+ // the escape key will be processed by
+ // nsXULPopupManager::KeyDown and the panel will be closed.
+ // So, don't consume the key event here.
+ break;
+ }
+ // don't break here. we need to eat keydown events.
+ }
+ case "keypress":
+ case "keyup": {
+ // All keyevents should be eaten here during autoscrolling.
+ aEvent.stopPropagation();
+ aEvent.preventDefault();
+ break;
+ }
+ }
+ }
+ ]]>
+ </body>
+ </method>
+
+ <method name="closeBrowser">
+ <body>
+ <![CDATA[
+ // The request comes from a XPCOM component, we'd want to redirect
+ // the request to tabbrowser.
+ let tabbrowser = this.getTabBrowser();
+ if (tabbrowser) {
+ let tab = tabbrowser.getTabForBrowser(this);
+ if (tab) {
+ tabbrowser.removeTab(tab);
+ return;
+ }
+ }
+
+ throw new Error("Closing a browser which was not attached to a tabbrowser is unsupported.");
+ ]]>
+ </body>
+ </method>
+
+ <method name="swapBrowsers">
+ <parameter name="aOtherBrowser"/>
+ <body>
+ <![CDATA[
+ // The request comes from a XPCOM component, we'd want to redirect
+ // the request to tabbrowser so tabbrowser will be setup correctly,
+ // and it will eventually call swapDocShells.
+ let tabbrowser = this.getTabBrowser();
+ if (tabbrowser) {
+ let tab = tabbrowser.getTabForBrowser(this);
+ if (tab) {
+ tabbrowser.swapBrowsers(tab, aOtherBrowser);
+ return;
+ }
+ }
+
+ // If we're not attached to a tabbrowser, just swap.
+ this.swapDocShells(aOtherBrowser);
+ ]]>
+ </body>
+ </method>
+
+ <method name="swapDocShells">
+ <parameter name="aOtherBrowser"/>
+ <body>
+ <![CDATA[
+ if (this.isRemoteBrowser != aOtherBrowser.isRemoteBrowser)
+ throw new Error("Can only swap docshells between browsers in the same process.");
+
+ // Give others a chance to swap state.
+ // IMPORTANT: Since a swapDocShells call does not swap the messageManager
+ // instances attached to a browser to aOtherBrowser, others
+ // will need to add the message listeners to the new
+ // messageManager.
+ // This is not a bug in swapDocShells or the FrameLoader,
+ // merely a design decision: If message managers were swapped,
+ // so that no new listeners were needed, the new
+ // aOtherBrowser.messageManager would have listeners pointing
+ // to the JS global of the current browser, which would rather
+ // easily create leaks while swapping.
+ // IMPORTANT2: When the current browser element is removed from DOM,
+ // which is quite common after a swpDocShells call, its
+ // frame loader is destroyed, and that destroys the relevant
+ // message manager, which will remove the listeners.
+ let event = new CustomEvent("SwapDocShells", {"detail": aOtherBrowser});
+ this.dispatchEvent(event);
+ event = new CustomEvent("SwapDocShells", {"detail": this});
+ aOtherBrowser.dispatchEvent(event);
+
+ // We need to swap fields that are tied to our docshell or related to
+ // the loaded page
+ // Fields which are built as a result of notifactions (pageshow/hide,
+ // DOMLinkAdded/Removed, onStateChange) should not be swapped here,
+ // because these notifications are dispatched again once the docshells
+ // are swapped.
+ var fieldsToSwap = [
+ "_docShell",
+ "_webBrowserFind",
+ "_contentWindow",
+ "_webNavigation"
+ ];
+
+ if (this.isRemoteBrowser) {
+ fieldsToSwap.push(...[
+ "_remoteWebNavigation",
+ "_remoteWebNavigationImpl",
+ "_remoteWebProgressManager",
+ "_remoteWebProgress",
+ "_remoteFinder",
+ "_securityUI",
+ "_documentURI",
+ "_documentContentType",
+ "_contentTitle",
+ "_characterSet",
+ "_contentPrincipal",
+ "_imageDocument",
+ "_fullZoom",
+ "_textZoom",
+ "_isSyntheticDocument",
+ "_innerWindowID",
+ "_manifestURI",
+ ]);
+ }
+
+ var ourFieldValues = {};
+ var otherFieldValues = {};
+ for (let field of fieldsToSwap) {
+ ourFieldValues[field] = this[field];
+ otherFieldValues[field] = aOtherBrowser[field];
+ }
+
+ if (window.PopupNotifications)
+ PopupNotifications._swapBrowserNotifications(aOtherBrowser, this);
+
+ try {
+ this.swapFrameLoaders(aOtherBrowser);
+ } catch (ex) {
+ // This may not be implemented for browser elements that are not
+ // attached to a BrowserDOMWindow.
+ }
+
+ for (let field of fieldsToSwap) {
+ this[field] = otherFieldValues[field];
+ aOtherBrowser[field] = ourFieldValues[field];
+ }
+
+ if (!this.isRemoteBrowser) {
+ // Null the current nsITypeAheadFind instances so that they're
+ // lazily re-created on access. We need to do this because they
+ // might have attached the wrong docShell.
+ this._fastFind = aOtherBrowser._fastFind = null;
+ }
+ else {
+ // Rewire the remote listeners
+ this._remoteWebNavigationImpl.swapBrowser(this);
+ aOtherBrowser._remoteWebNavigationImpl.swapBrowser(aOtherBrowser);
+
+ if (this._remoteWebProgressManager && aOtherBrowser._remoteWebProgressManager) {
+ this._remoteWebProgressManager.swapBrowser(this);
+ aOtherBrowser._remoteWebProgressManager.swapBrowser(aOtherBrowser);
+ }
+
+ if (this._remoteFinder)
+ this._remoteFinder.swapBrowser(this);
+ if (aOtherBrowser._remoteFinder)
+ aOtherBrowser._remoteFinder.swapBrowser(aOtherBrowser);
+ }
+
+ event = new CustomEvent("EndSwapDocShells", {"detail": aOtherBrowser});
+ this.dispatchEvent(event);
+ event = new CustomEvent("EndSwapDocShells", {"detail": this});
+ aOtherBrowser.dispatchEvent(event);
+ ]]>
+ </body>
+ </method>
+
+ <method name="getInPermitUnload">
+ <parameter name="aCallback"/>
+ <body>
+ <![CDATA[
+ if (!this.docShell || !this.docShell.contentViewer) {
+ aCallback(false);
+ return;
+ }
+ aCallback(this.docShell.contentViewer.inPermitUnload);
+ ]]>
+ </body>
+ </method>
+
+ <method name="permitUnload">
+ <body>
+ <![CDATA[
+ if (!this.docShell || !this.docShell.contentViewer) {
+ return {permitUnload: true, timedOut: false};
+ }
+ return {permitUnload: this.docShell.contentViewer.permitUnload(), timedOut: false};
+ ]]>
+ </body>
+ </method>
+
+ <method name="print">
+ <parameter name="aOuterWindowID"/>
+ <parameter name="aPrintSettings"/>
+ <parameter name="aPrintProgressListener"/>
+ <body>
+ <![CDATA[
+ var owner = this.QueryInterface(Components.interfaces.nsIFrameLoaderOwner);
+ if (!owner.frameLoader) {
+ throw Components.Exception("No frame loader.",
+ Components.results.NS_ERROR_FAILURE);
+ }
+
+ owner.frameLoader.print(aOuterWindowID, aPrintSettings,
+ aPrintProgressListener);
+ ]]>
+ </body>
+ </method>
+
+ <method name="dropLinks">
+ <parameter name="aLinksCount"/>
+ <parameter name="aLinks"/>
+ <body><![CDATA[
+ if (!this.droppedLinkHandler) {
+ return false;
+ }
+ let links = [];
+ for (let i = 0; i < aLinksCount; i += 3) {
+ links.push({
+ url: aLinks[i],
+ name: aLinks[i + 1],
+ type: aLinks[i + 2],
+ });
+ }
+ this.droppedLinkHandler(null, links);
+ return true;
+ ]]></body>
+ </method>
+ </implementation>
+
+ <handlers>
+ <handler event="keypress" keycode="VK_F7" group="system">
+ <![CDATA[
+ if (event.defaultPrevented || !event.isTrusted)
+ return;
+
+ const kPrefShortcutEnabled = "accessibility.browsewithcaret_shortcut.enabled";
+ const kPrefWarnOnEnable = "accessibility.warn_on_browsewithcaret";
+ const kPrefCaretBrowsingOn = "accessibility.browsewithcaret";
+
+ var isEnabled = this.mPrefs.getBoolPref(kPrefShortcutEnabled);
+ if (!isEnabled)
+ return;
+
+ // Toggle browse with caret mode
+ var browseWithCaretOn = false;
+ var warn = true;
+
+ try {
+ warn = this.mPrefs.getBoolPref(kPrefWarnOnEnable);
+ } catch (ex) {
+ }
+
+ try {
+ browseWithCaretOn = this.mPrefs.getBoolPref(kPrefCaretBrowsingOn);
+ } catch (ex) {
+ }
+ if (warn && !browseWithCaretOn) {
+ var checkValue = {value:false};
+ var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
+ .getService(Components.interfaces.nsIPromptService);
+
+ var buttonPressed = promptService.confirmEx(window,
+ this.mStrBundle.GetStringFromName('browsewithcaret.checkWindowTitle'),
+ this.mStrBundle.GetStringFromName('browsewithcaret.checkLabel'),
+ // Make "No" the default:
+ promptService.STD_YES_NO_BUTTONS | promptService.BUTTON_POS_1_DEFAULT,
+ null, null, null, this.mStrBundle.GetStringFromName('browsewithcaret.checkMsg'),
+ checkValue);
+ if (buttonPressed != 0) {
+ if (checkValue.value) {
+ try {
+ this.mPrefs.setBoolPref(kPrefShortcutEnabled, false);
+ } catch (ex) {
+ }
+ }
+ return;
+ }
+ if (checkValue.value) {
+ try {
+ this.mPrefs.setBoolPref(kPrefWarnOnEnable, false);
+ }
+ catch (ex) {
+ }
+ }
+ }
+
+ // Toggle the pref
+ try {
+ this.mPrefs.setBoolPref(kPrefCaretBrowsingOn, !browseWithCaretOn);
+ } catch (ex) {
+ }
+ ]]>
+ </handler>
+ <handler event="dragover" group="system">
+ <![CDATA[
+ if (!this.droppedLinkHandler || event.defaultPrevented)
+ return;
+
+ // For drags that appear to be internal text (for example, tab drags),
+ // set the dropEffect to 'none'. This prevents the drop even if some
+ // other listener cancelled the event.
+ var types = event.dataTransfer.types;
+ if (types.includes("text/x-moz-text-internal") && !types.includes("text/plain")) {
+ event.dataTransfer.dropEffect = "none";
+ event.stopPropagation();
+ event.preventDefault();
+ }
+
+ // No need to handle "dragover" in e10s, since nsDocShellTreeOwner.cpp in the child process
+ // handles that case using "@mozilla.org/content/dropped-link-handler;1" service.
+ if (this.isRemoteBrowser)
+ return;
+
+ let linkHandler = Components.classes["@mozilla.org/content/dropped-link-handler;1"].
+ getService(Components.interfaces.nsIDroppedLinkHandler);
+ if (linkHandler.canDropLink(event, false))
+ event.preventDefault();
+ ]]>
+ </handler>
+ <handler event="drop" group="system">
+ <![CDATA[
+ // No need to handle "drop" in e10s, since nsDocShellTreeOwner.cpp in the child process
+ // handles that case using "@mozilla.org/content/dropped-link-handler;1" service.
+ if (!this.droppedLinkHandler || event.defaultPrevented || this.isRemoteBrowser)
+ return;
+
+ let name = { };
+ let linkHandler = Components.classes["@mozilla.org/content/dropped-link-handler;1"].
+ getService(Components.interfaces.nsIDroppedLinkHandler);
+ try {
+ // Pass true to prevent the dropping of javascript:/data: URIs
+ var links = linkHandler.dropLinks(event, true);
+ } catch (ex) {
+ return;
+ }
+
+ if (links.length) {
+ this.droppedLinkHandler(event, links);
+ }
+ ]]>
+ </handler>
+ </handlers>
+
+ </binding>
+
+</bindings>