--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1044,26 +1044,19 @@ var gBrowserInit = {
_delayedStartup: function() {
let tmp = {};
Cu.import("resource://gre/modules/TelemetryTimestamps.jsm", tmp);
let TelemetryTimestamps = tmp.TelemetryTimestamps;
TelemetryTimestamps.add("delayedStartupStarted");
this._cancelDelayedStartup();
- // We need to set the MozApplicationManifest event listeners up
- // before we start loading the home pages in case a document has
- // a "manifest" attribute, in which the MozApplicationManifest event
- // will be fired.
- gBrowser.addEventListener("MozApplicationManifest",
- OfflineApps, false);
- // listen for offline apps on social
- let socialBrowser = document.getElementById("social-sidebar-browser");
- socialBrowser.addEventListener("MozApplicationManifest",
- OfflineApps, false);
+ // We need to set the OfflineApps message listeners up before we
+ // load homepages, which might need them.
+ OfflineApps.init();
// This pageshow listener needs to be registered before we may call
// swapBrowsersAndCloseOther() to receive pageshow events fired by that.
let mm = window.messageManager;
mm.addMessageListener("PageVisibility:Show", function(message) {
if (message.target == gBrowser.selectedBrowser) {
setTimeout(pageShowEventHandlers, 0, message.data.persisted);
}
@@ -1171,17 +1164,16 @@ var gBrowserInit = {
Services.obs.addObserver(gXPInstallObserver, "addon-install-blocked", false);
Services.obs.addObserver(gXPInstallObserver, "addon-install-origin-blocked", false);
Services.obs.addObserver(gXPInstallObserver, "addon-install-failed", false);
Services.obs.addObserver(gXPInstallObserver, "addon-install-confirmation", false);
Services.obs.addObserver(gXPInstallObserver, "addon-install-complete", false);
window.messageManager.addMessageListener("Browser:URIFixup", gKeywordURIFixup);
BrowserOffline.init();
- OfflineApps.init();
IndexedDBPromptHelper.init();
if (AppConstants.E10S_TESTING_ONLY)
gRemoteTabsUI.init();
// Initialize the full zoom setting.
// We do this before the session restore service gets initialized so we can
// apply full zoom settings to tabs restored by the session restore service.
@@ -1493,17 +1485,16 @@ var gBrowserInit = {
Cu.reportError(ex);
}
if (this.gmpInstallManager) {
this.gmpInstallManager.uninit();
}
BrowserOffline.uninit();
- OfflineApps.uninit();
IndexedDBPromptHelper.uninit();
LightweightThemeListener.uninit();
PanelUI.uninit();
}
// Final window teardown, do this last.
window.XULBrowserWindow = null;
window.QueryInterface(Ci.nsIInterfaceRequestor)
@@ -5740,283 +5731,153 @@ var BrowserOffline = {
if (offlineLocked)
this._uiElement.setAttribute("disabled", "true");
this._uiElement.setAttribute("checked", aOffline);
}
};
var OfflineApps = {
- /////////////////////////////////////////////////////////////////////////////
- // OfflineApps Public Methods
- init: function ()
- {
- Services.obs.addObserver(this, "offline-cache-update-completed", false);
- },
-
- uninit: function ()
- {
- Services.obs.removeObserver(this, "offline-cache-update-completed");
- },
-
- handleEvent: function(event) {
- if (event.type == "MozApplicationManifest") {
- this.offlineAppRequested(event.originalTarget.defaultView);
- }
- },
-
- /////////////////////////////////////////////////////////////////////////////
- // OfflineApps Implementation Methods
-
- // XXX: _getBrowserWindowForContentWindow and _getBrowserForContentWindow
- // were taken from browser/components/feeds/WebContentConverter.
- _getBrowserWindowForContentWindow: function(aContentWindow) {
- return aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIWebNavigation)
- .QueryInterface(Ci.nsIDocShellTreeItem)
- .rootTreeItem
- .QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindow)
- .wrappedJSObject;
- },
-
- _getBrowserForContentWindow: function(aBrowserWindow, aContentWindow) {
- // This depends on pseudo APIs of browser.js and tabbrowser.xml
- aContentWindow = aContentWindow.top;
- var browsers = aBrowserWindow.gBrowser.browsers;
- for (let browser of browsers) {
- if (browser.contentWindow == aContentWindow)
- return browser;
- }
- // handle other browser/iframe elements that may need popupnotifications
- let browser = aContentWindow
- .QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIWebNavigation)
- .QueryInterface(Ci.nsIDocShell)
- .chromeEventHandler;
- if (browser.getAttribute("popupnotificationanchor"))
- return browser;
- return null;
- },
-
- _getManifestURI: function(aWindow) {
- if (!aWindow.document.documentElement)
- return null;
-
- var attr = aWindow.document.documentElement.getAttribute("manifest");
- if (!attr)
- return null;
-
- try {
- var contentURI = makeURI(aWindow.location.href, null, null);
- return makeURI(attr, aWindow.document.characterSet, contentURI);
- } catch (e) {
- return null;
- }
- },
-
- // A cache update isn't tied to a specific window. Try to find
- // the best browser in which to warn the user about space usage
- _getBrowserForCacheUpdate: function(aCacheUpdate) {
- // Prefer the current browser
- var uri = this._getManifestURI(content);
- if (uri && uri.equals(aCacheUpdate.manifestURI)) {
- return gBrowser.selectedBrowser;
- }
-
- var browsers = gBrowser.browsers;
- for (let browser of browsers) {
- uri = this._getManifestURI(browser.contentWindow);
- if (uri && uri.equals(aCacheUpdate.manifestURI)) {
- return browser;
- }
- }
-
- // is this from a non-tab browser/iframe?
- browsers = document.querySelectorAll("iframe[popupnotificationanchor] | browser[popupnotificationanchor]");
- for (let browser of browsers) {
- uri = this._getManifestURI(browser.contentWindow);
- if (uri && uri.equals(aCacheUpdate.manifestURI)) {
- return browser;
- }
- }
-
- return null;
- },
-
- _warnUsage: function(aBrowser, aURI) {
- if (!aBrowser)
+ warnUsage(browser, uri) {
+ if (!browser)
return;
let mainAction = {
label: gNavigatorBundle.getString("offlineApps.manageUsage"),
accessKey: gNavigatorBundle.getString("offlineApps.manageUsageAccessKey"),
- callback: OfflineApps.manage
+ callback: this.manage
};
- let warnQuota = gPrefService.getIntPref("offline-apps.quota.warn");
+ let warnQuota = Services.prefs.getIntPref("offline-apps.quota.warn");
let message = gNavigatorBundle.getFormattedString("offlineApps.usage",
- [ aURI.host,
+ [ uri.host,
warnQuota / 1024 ]);
let anchorID = "indexedDB-notification-icon";
- PopupNotifications.show(aBrowser, "offline-app-usage", message,
+ PopupNotifications.show(browser, "offline-app-usage", message,
anchorID, mainAction);
// Now that we've warned once, prevent the warning from showing up
// again.
- Services.perms.add(aURI, "offline-app",
+ Services.perms.add(uri, "offline-app",
Ci.nsIOfflineCacheUpdateService.ALLOW_NO_WARN);
},
// XXX: duplicated in preferences/advanced.js
- _getOfflineAppUsage: function (host, groups)
- {
- var cacheService = Cc["@mozilla.org/network/application-cache-service;1"].
+ _getOfflineAppUsage(host) {
+ let cacheService = Cc["@mozilla.org/network/application-cache-service;1"].
getService(Ci.nsIApplicationCacheService);
- if (!groups)
- groups = cacheService.getGroups();
-
- var usage = 0;
+ let groups = cacheService.getGroups();
+ let usage = 0;
for (let group of groups) {
- var uri = Services.io.newURI(group, null, null);
+ let uri = Services.io.newURI(group, null, null);
if (uri.asciiHost == host) {
- var cache = cacheService.getActiveCache(group);
+ let cache = cacheService.getActiveCache(group);
usage += cache.usage;
}
}
return usage;
},
- _checkUsage: function(aURI) {
+ _checkUsage(uri) {
// if the user has already allowed excessive usage, don't bother checking
- if (Services.perms.testExactPermission(aURI, "offline-app") !=
+ if (Services.perms.testExactPermission(uri, "offline-app") !=
Ci.nsIOfflineCacheUpdateService.ALLOW_NO_WARN) {
- var usage = this._getOfflineAppUsage(aURI.asciiHost);
- var warnQuota = gPrefService.getIntPref("offline-apps.quota.warn");
+ let usage = this._getOfflineAppUsage(uri.asciiHost);
+ let warnQuota = Services.prefs.getIntPref("offline-apps.quota.warn");
if (usage >= warnQuota * 1024) {
return true;
}
}
return false;
},
- offlineAppRequested: function(aContentWindow) {
- if (!gPrefService.getBoolPref("browser.offline-apps.notify")) {
- return;
- }
-
- let browserWindow = this._getBrowserWindowForContentWindow(aContentWindow);
- let browser = this._getBrowserForContentWindow(browserWindow,
- aContentWindow);
-
- let currentURI = aContentWindow.document.documentURIObject;
-
- // don't bother showing UI if the user has already made a decision
- if (Services.perms.testExactPermission(currentURI, "offline-app") != Services.perms.UNKNOWN_ACTION)
- return;
-
- try {
- if (gPrefService.getBoolPref("offline-apps.allow_by_default")) {
- // all pages can use offline capabilities, no need to ask the user
- return;
- }
- } catch(e) {
- // this pref isn't set by default, ignore failures
- }
-
- let host = currentURI.asciiHost;
+ requestPermission(browser, docId, uri) {
+ let host = uri.asciiHost;
let notificationID = "offline-app-requested-" + host;
let notification = PopupNotifications.getNotification(notificationID, browser);
if (notification) {
- notification.options.documents.push(aContentWindow.document);
+ notification.options.controlledItems.push([
+ Cu.getWeakReference(browser), docId, uri
+ ]);
} else {
let mainAction = {
label: gNavigatorBundle.getString("offlineApps.allow"),
accessKey: gNavigatorBundle.getString("offlineApps.allowAccessKey"),
callback: function() {
- for (let document of notification.options.documents) {
- OfflineApps.allowSite(document);
+ for (let [browser, docId, uri] of notification.options.controlledItems) {
+ OfflineApps.allowSite(browser, docId, uri);
}
}
};
let secondaryActions = [{
label: gNavigatorBundle.getString("offlineApps.never"),
accessKey: gNavigatorBundle.getString("offlineApps.neverAccessKey"),
callback: function() {
- for (let document of notification.options.documents) {
- OfflineApps.disallowSite(document);
+ for (let [, , uri] of notification.options.controlledItems) {
+ OfflineApps.disallowSite(uri);
}
}
}];
let message = gNavigatorBundle.getFormattedString("offlineApps.available",
- [ host ]);
+ [host]);
let anchorID = "indexedDB-notification-icon";
- let options= {
- documents : [ aContentWindow.document ]
+ let options = {
+ controlledItems : [[Cu.getWeakReference(browser), docId, uri]]
};
notification = PopupNotifications.show(browser, notificationID, message,
anchorID, mainAction,
secondaryActions, options);
}
},
- allowSite: function(aDocument) {
- Services.perms.add(aDocument.documentURIObject, "offline-app", Services.perms.ALLOW_ACTION);
+ disallowSite(uri) {
+ Services.perms.add(uri, "offline-app", Services.perms.DENY_ACTION);
+ },
+
+ allowSite(browserRef, docId, uri) {
+ Services.perms.add(uri, "offline-app", Services.perms.ALLOW_ACTION);
// When a site is enabled while loading, manifest resources will
// start fetching immediately. This one time we need to do it
// ourselves.
- this._startFetching(aDocument);
- },
-
- disallowSite: function(aDocument) {
- Services.perms.add(aDocument.documentURIObject, "offline-app", Services.perms.DENY_ACTION);
- },
-
- manage: function() {
+ let browser = browserRef.get();
+ if (browser && browser.messageManager) {
+ browser.messageManager.sendAsyncMessage("OfflineApps:StartFetching", {
+ docId,
+ });
+ }
+ },
+
+ manage() {
openAdvancedPreferences("networkTab");
},
- _startFetching: function(aDocument) {
- if (!aDocument.documentElement)
- return;
-
- var manifest = aDocument.documentElement.getAttribute("manifest");
- if (!manifest)
- return;
-
- var manifestURI = makeURI(manifest, aDocument.characterSet,
- aDocument.documentURIObject);
-
- var updateService = Cc["@mozilla.org/offlinecacheupdate-service;1"].
- getService(Ci.nsIOfflineCacheUpdateService);
- updateService.scheduleUpdate(manifestURI, aDocument.documentURIObject,
- aDocument.nodePrincipal, window);
- },
-
- /////////////////////////////////////////////////////////////////////////////
- // nsIObserver
- observe: function (aSubject, aTopic, aState)
- {
- if (aTopic == "offline-cache-update-completed") {
- var cacheUpdate = aSubject.QueryInterface(Ci.nsIOfflineCacheUpdate);
-
- var uri = cacheUpdate.manifestURI;
- if (OfflineApps._checkUsage(uri)) {
- var browser = this._getBrowserForCacheUpdate(cacheUpdate);
- if (browser) {
- OfflineApps._warnUsage(browser, cacheUpdate.manifestURI);
+ receiveMessage(msg) {
+ switch (msg.name) {
+ case "OfflineApps:CheckUsage":
+ let uri = makeURI(msg.data.uri);
+ if (this._checkUsage(uri)) {
+ this.warnUsage(msg.target, uri);
}
- }
- }
- }
+ break;
+ case "OfflineApps:RequestPermission":
+ this.requestPermission(msg.target, msg.data.docId, makeURI(msg.data.uri));
+ break;
+ }
+ },
+
+ init() {
+ let mm = window.messageManager;
+ mm.addMessageListener("OfflineApps:CheckUsage", this);
+ mm.addMessageListener("OfflineApps:RequestPermission", this);
+ },
};
var IndexedDBPromptHelper = {
_permissionsPrompt: "indexedDB-permissions-prompt",
_permissionsResponse: "indexedDB-permissions-response",
_notificationIcon: "indexedDB-notification-icon",
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -1313,8 +1313,115 @@ var PageInfoListener = {
let middleRE = /\s+/g;
let endRE = /(^\s+)|(\s+$)/g;
text = text.replace(middleRE, " ");
return text.replace(endRE, "");
}
};
PageInfoListener.init();
+
+let OfflineApps = {
+ _docId: 0,
+ _docIdMap: new Map(),
+
+ _docManifestSet: new Set(),
+
+ _observerAdded: false,
+ registerWindow(aWindow) {
+ if (!this._observerAdded) {
+ this._observerAdded = true;
+ Services.obs.addObserver(this, "offline-cache-update-completed", true);
+ }
+ let manifestURI = this._getManifestURI(aWindow);
+ this._docManifestSet.add(manifestURI.spec);
+ },
+
+ handleEvent: function(event) {
+ if (event.type == "MozApplicationManifest") {
+ this.offlineAppRequested(event.originalTarget.defaultView);
+ }
+ },
+
+ _getManifestURI: function(aWindow) {
+ if (!aWindow.document.documentElement)
+ return null;
+
+ var attr = aWindow.document.documentElement.getAttribute("manifest");
+ if (!attr)
+ return null;
+
+ try {
+ var contentURI = BrowserUtils.makeURI(aWindow.location.href, null, null);
+ return BrowserUtils.makeURI(attr, aWindow.document.characterSet, contentURI);
+ } catch (e) {
+ return null;
+ }
+ },
+
+ offlineAppRequested: function(aContentWindow) {
+ this.registerWindow(aContentWindow);
+ if (!Services.prefs.getBoolPref("browser.offline-apps.notify")) {
+ return;
+ }
+
+ let currentURI = aContentWindow.document.documentURIObject;
+ // don't bother showing UI if the user has already made a decision
+ if (Services.perms.testExactPermission(currentURI, "offline-app") != Services.perms.UNKNOWN_ACTION)
+ return;
+
+ try {
+ if (Services.prefs.getBoolPref("offline-apps.allow_by_default")) {
+ // all pages can use offline capabilities, no need to ask the user
+ return;
+ }
+ } catch(e) {
+ // this pref isn't set by default, ignore failures
+ }
+ let docId = ++this._docId;
+ this._docIdMap.set(docId, Cu.getWeakReference(aContentWindow.document));
+ sendAsyncMessage("OfflineApps:RequestPermission", {
+ uri: currentURI.spec,
+ docId,
+ });
+ },
+
+ _startFetching: function(aDocument) {
+ if (!aDocument.documentElement)
+ return;
+
+ let manifestURI = this._getManifestURI(aDocument.defaultView);
+ if (!manifestURI)
+ return;
+
+ var updateService = Cc["@mozilla.org/offlinecacheupdate-service;1"].
+ getService(Ci.nsIOfflineCacheUpdateService);
+ updateService.scheduleUpdate(manifestURI, aDocument.documentURIObject,
+ aDocument.nodePrincipal, aDocument.defaultView);
+ },
+
+ receiveMessage(aMessage) {
+ if (aMessage.name == "OfflineApps:StartFetching") {
+ let doc = this._docIdMap.get(aMessage.data.docId);
+ doc = doc && doc.get();
+ if (doc) {
+ this._startFetching(doc);
+ }
+ this._docIdMap.delete(aMessage.data.docId);
+ }
+ },
+
+ observe(aSubject, aTopic, aState) {
+ if (aTopic == "offline-cache-update-completed") {
+ let cacheUpdate = aSubject.QueryInterface(Ci.nsIOfflineCacheUpdate);
+ let uri = cacheUpdate.manifestURI;
+ if (uri && this._docManifestSet.has(uri.spec)) {
+ sendAsyncMessage("OfflineApps:CheckUsage", {uri: uri.spec});
+ }
+ }
+ },
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
+ Ci.nsISupportsWeakReference]),
+};
+
+addEventListener("MozApplicationManifest", OfflineApps, false);
+addMessageListener("OfflineApps:StartFetching", OfflineApps);
+
--- a/browser/base/content/test/general/browser_offlineQuotaNotification.js
+++ b/browser/base/content/test/general/browser_offlineQuotaNotification.js
@@ -10,16 +10,18 @@ const URL = "http://mochi.test:8888/brow
registerCleanupFunction(function() {
// Clean up after ourself
let uri = Services.io.newURI(URL, null, null);
let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
Services.perms.removeFromPrincipal(principal, "offline-app");
Services.prefs.clearUserPref("offline-apps.quota.warn");
Services.prefs.clearUserPref("offline-apps.allow_by_default");
+ let {OfflineAppCacheHelper} = Components.utils.import("resource:///modules/offlineAppCache.jsm", {});
+ OfflineAppCacheHelper.clear();
});
// Same as the other one, but for in-content preferences
function checkInContentPreferences(win) {
let doc = win.document;
let sel = doc.getElementById("categories").selectedItems[0].id;
let tab = doc.getElementById("advancedPrefs").selectedTab.id;
is(gBrowser.currentURI.spec, "about:preferences#advanced", "about:preferences loaded");
@@ -39,40 +41,58 @@ function test() {
gBrowser.selectedTab = gBrowser.addTab(URL);
registerCleanupFunction(() => gBrowser.removeCurrentTab());
Promise.all([
// Wait for a notification that asks whether to allow offline storage.
promiseNotification(),
// Wait for the tab to load.
- BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser)
+ BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser),
]).then(() => {
- gBrowser.selectedBrowser.contentWindow.applicationCache.oncached = function() {
- executeSoon(function() {
- // We got cached - now we should have provoked the quota warning.
- let notification = PopupNotifications.getNotification('offline-app-usage');
- ok(notification, "have offline-app-usage notification");
- // select the default action - this should cause the preferences
- // tab to open - which we track via an "Initialized" event.
- PopupNotifications.panel.firstElementChild.button.click();
- let newTabBrowser = gBrowser.getBrowserForTab(gBrowser.selectedTab);
- newTabBrowser.addEventListener("Initialized", function PrefInit() {
- newTabBrowser.removeEventListener("Initialized", PrefInit, true);
- executeSoon(function() {
- checkInContentPreferences(newTabBrowser.contentWindow);
- })
- }, true);
+ info("Loaded page, adding onCached handler");
+ // Need a promise to keep track of when we've added our handler.
+ let onCachedAttached = new Promise(resolve => {
+ let onCachedAttached = msg => {
+ mm.removeMessageListener("Test:OnCachedAttached", onCachedAttached);
+ resolve();
+ };
+ let mm = gBrowser.selectedBrowser.messageManager;
+ mm.addMessageListener("Test:OnCachedAttached", onCachedAttached);
+ });
+ let gotCached = ContentTask.spawn(gBrowser.selectedBrowser, null, function*() {
+ return new Promise(resolve => {
+ content.window.applicationCache.oncached = function() {
+ setTimeout(resolve, 0);
+ };
+ sendAsyncMessage("Test:OnCachedAttached");
});
- };
- Services.prefs.setIntPref("offline-apps.quota.warn", 1);
+ });
+ gotCached.then(function() {
+ // We got cached - now we should have provoked the quota warning.
+ let notification = PopupNotifications.getNotification('offline-app-usage');
+ ok(notification, "have offline-app-usage notification");
+ // select the default action - this should cause the preferences
+ // tab to open - which we track via an "Initialized" event.
+ PopupNotifications.panel.firstElementChild.button.click();
+ let newTabBrowser = gBrowser.getBrowserForTab(gBrowser.selectedTab);
+ newTabBrowser.addEventListener("Initialized", function PrefInit() {
+ newTabBrowser.removeEventListener("Initialized", PrefInit, true);
+ executeSoon(function() {
+ checkInContentPreferences(newTabBrowser.contentWindow);
+ })
+ }, true);
+ });
+ onCachedAttached.then(function() {
+ Services.prefs.setIntPref("offline-apps.quota.warn", 1);
- // Click the notification panel's "Allow" button. This should kick
- // off updates which will call our oncached handler above.
- PopupNotifications.panel.firstElementChild.button.click();
+ // Click the notification panel's "Allow" button. This should kick
+ // off updates which will call our oncached handler above.
+ PopupNotifications.panel.firstElementChild.button.click();
+ });
});
}
function promiseNotification() {
return new Promise(resolve => {
PopupNotifications.panel.addEventListener("popupshown", function onShown() {
PopupNotifications.panel.removeEventListener("popupshown", onShown);
resolve();
--- a/toolkit/content/browser-content.js
+++ b/toolkit/content/browser-content.js
@@ -1125,8 +1125,20 @@ var ViewSelectionSource = {
// replace chars > 0x7f via nsIEntityConverter
str = str.replace(/[^\0-\u007f]/g, convertEntity);
return str;
}
};
ViewSelectionSource.init();
+
+addEventListener("MozApplicationManifest", function(e) {
+ let doc = e.target;
+ let info = {
+ uri: doc.documentURI,
+ characterSet: doc.characterSet,
+ manifest: doc.documentElement.getAttribute("manifest"),
+ principal: doc.nodePrincipal,
+ };
+ sendAsyncMessage("MozApplicationManifest", info);
+}, false);
+
--- a/toolkit/content/widgets/browser.xml
+++ b/toolkit/content/widgets/browser.xml
@@ -493,16 +493,23 @@
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>
@@ -1214,16 +1221,17 @@
"_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];
--- a/toolkit/content/widgets/remote-browser.xml
+++ b/toolkit/content/widgets/remote-browser.xml
@@ -254,16 +254,21 @@
<body><![CDATA[
// See the explanation for what this does in nsITabParent.ipdl
let {frameLoader} = this.QueryInterface(Components.interfaces.nsIFrameLoaderOwner);
frameLoader.tabParent.setDocShellIsActiveAndForeground(isActive);
]]></body>
</method>
+ <field name="_manifestURI"/>
+ <property name="manifestURI"
+ onget="return this._manifestURI"
+ readonly="true"/>
+
<field name="mDestroyed">false</field>
<field name="_permitUnloadId">0</field>
<method name="getInPermitUnload">
<parameter name="aCallback"/>
<body>
<![CDATA[
@@ -358,16 +363,17 @@
this.messageManager.addMessageListener("DOMTitleChanged", this);
this.messageManager.addMessageListener("ImageDocumentLoaded", this);
this.messageManager.addMessageListener("DocumentInserted", this);
this.messageManager.addMessageListener("FullZoomChange", this);
this.messageManager.addMessageListener("TextZoomChange", this);
this.messageManager.addMessageListener("ZoomChangeUsingMouseWheel", this);
this.messageManager.addMessageListener("DOMFullscreen:RequestExit", this);
this.messageManager.addMessageListener("DOMFullscreen:RequestRollback", this);
+ this.messageManager.addMessageListener("MozApplicationManifest", this);
this.messageManager.loadFrameScript("chrome://global/content/browser-child.js", true);
if (this.hasAttribute("selectmenulist")) {
this.messageManager.addMessageListener("Forms:ShowDropDown", this);
this.messageManager.addMessageListener("Forms:HideDropDown", this);
this.messageManager.loadFrameScript("chrome://global/content/select-child.js", true);
}
@@ -492,16 +498,20 @@
case "DOMFullscreen:RequestRollback": {
let windowUtils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils);
windowUtils.remoteFrameFullscreenReverted();
break;
}
+ case "MozApplicationManifest":
+ this._manifestURI = aMessage.data.manifest;
+ break;
+
default:
// Delegate to browser.xml.
return this._receiveMessage(aMessage);
break;
}
]]></body>
</method>