зеркало из https://github.com/mozilla/gecko-dev.git
1540 строки
52 KiB
XML
1540 строки
52 KiB
XML
<?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);
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<method name="audioPlaybackStopped">
|
|
<body>
|
|
<![CDATA[
|
|
let event = document.createEvent("Events");
|
|
event.initEvent("DOMAudioPlaybackStopped", true, false);
|
|
this.dispatchEvent(event);
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<field name="_audioMuted">false</field>
|
|
<property name="audioMuted"
|
|
onget="return this._audioMuted;"
|
|
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.messageManager.sendAsyncMessage("AudioPlayback",
|
|
{type: "blockInactivePageMedia"});
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<method name="resumeMedia">
|
|
<body>
|
|
<![CDATA[
|
|
this.messageManager.sendAsyncMessage("AudioPlayback",
|
|
{type: "resumeMedia"});
|
|
]]>
|
|
</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);
|
|
}
|
|
]]>
|
|
</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;
|
|
}
|
|
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>
|