--- a/addon-sdk/source/lib/sdk/panel/utils.js
+++ b/addon-sdk/source/lib/sdk/panel/utils.js
@@ -4,16 +4,17 @@
"use strict";
module.metadata = {
"stability": "unstable"
};
const { Cc, Ci } = require("chrome");
+const { Services } = require("resource://gre/modules/Services.jsm");
const { setTimeout } = require("../timers");
const { platform } = require("../system");
const { getMostRecentBrowserWindow, getOwnerBrowserWindow,
getHiddenWindow, getScreenPixelsPerCSSPixel } = require("../window/utils");
const { create: createFrame, swapFrameLoaders, getDocShell } = require("../frame/utils");
const { window: addonWindow } = require("../addon/window");
const { isNil } = require("../lang/type");
@@ -181,16 +182,22 @@ function display(panel, options, anchor)
popupPosition = vertical + "center " + verticalInverse + horizontal;
// Allow panel to flip itself if the panel can't be displayed at the
// specified position (useful if we compute a bad position or if the
// user moves the window and panel remains visible)
panel.setAttribute("flip", "both");
}
+ panel.viewFrame = document.importNode(panel.backgroundFrame, false);
+ panel.appendChild(panel.viewFrame);
+
+ let principal = Services.scriptSecurityManager.createNullPrincipal({});
+ getDocShell(panel.viewFrame).createAboutBlankContentViewer(principal);
+
// Resize the iframe instead of using panel.sizeTo
// because sizeTo doesn't work with arrow panels
panel.firstChild.style.width = width + "px";
panel.firstChild.style.height = height + "px";
panel.openPopup(anchor, popupPosition, x, y);
}
exports.display = display;
@@ -246,61 +253,54 @@ function setupPanelFrame(frame) {
frame.style.padding = "1px";
}
}
function make(document, options) {
document = document || getMostRecentBrowserWindow().document;
let panel = document.createElementNS(XUL_NS, "panel");
panel.setAttribute("type", "arrow");
- panel.setAttribute("sdkscriptenabled", "" + options.allowJavascript);
+ panel.setAttribute("sdkscriptenabled", options.allowJavascript);
- // Note that panel is a parent of `viewFrame` who's `docShell` will be
- // configured at creation time. If `panel` and there for `viewFrame` won't
- // have an owner document attempt to access `docShell` will throw. There
- // for we attach panel to a document.
+ // The panel needs to be attached to a browser window in order for us
+ // to copy browser styles to the content document when it loads.
attach(panel, document);
let frameOptions = {
allowJavascript: options.allowJavascript,
allowPlugins: true,
allowAuth: true,
allowWindowControl: false,
// Need to override `nodeName` to use `iframe` as `browsers` save session
// history and in consequence do not dispatch "inner-window-destroyed"
// notifications.
browser: false,
- // Note that use of this URL let's use swap frame loaders earlier
- // than if we used default "about:blank".
- uri: "data:text/plain;charset=utf-8,"
};
let backgroundFrame = createFrame(addonWindow, frameOptions);
setupPanelFrame(backgroundFrame);
- let viewFrame = createFrame(panel, frameOptions);
- setupPanelFrame(viewFrame);
+ getDocShell(backgroundFrame).inheritPrivateBrowsingId = false;
- function onDisplayChange({type, target}) {
- // Events from child element like <select /> may propagate (dropdowns are
- // popups too), in which case frame loader shouldn't be swapped.
- // See Bug 886329
- if (target !== this) return;
+ function onPopupShowing({type, target}) {
+ if (target === this) {
+ let attrs = getDocShell(backgroundFrame).getOriginAttributes();
+ getDocShell(panel.viewFrame).setOriginAttributes(attrs);
- try {
- swapFrameLoaders(backgroundFrame, viewFrame);
- // We need to re-set this because... swapFrameLoaders. Or something.
- let shouldEnableScript = panel.getAttribute("sdkscriptenabled") == "true";
- getDocShell(backgroundFrame).allowJavascript = shouldEnableScript;
- getDocShell(viewFrame).allowJavascript = shouldEnableScript;
+ swapFrameLoaders(backgroundFrame, panel.viewFrame);
}
- catch(error) {
- console.exception(error);
+ }
+
+ function onPopupHiding({type, target}) {
+ if (target === this) {
+ swapFrameLoaders(backgroundFrame, panel.viewFrame);
+
+ panel.viewFrame.remove();
+ panel.viewFrame = null;
}
- events.emit(type, { subject: panel });
}
function onContentReady({target, type}) {
if (target === getContentDocument(panel)) {
style(panel);
events.emit(type, { subject: panel });
}
}
@@ -310,42 +310,42 @@ function make(document, options) {
events.emit(type, { subject: panel });
}
function onContentChange({subject: document, type}) {
if (document === getContentDocument(panel) && document.defaultView)
events.emit(type, { subject: panel });
}
- function onPanelStateChange({type}) {
- events.emit(type, { subject: panel })
+ function onPanelStateChange({target, type}) {
+ if (target === this)
+ events.emit(type, { subject: panel })
}
- panel.addEventListener("popupshowing", onDisplayChange, false);
- panel.addEventListener("popuphiding", onDisplayChange, false);
- panel.addEventListener("popupshown", onPanelStateChange, false);
- panel.addEventListener("popuphidden", onPanelStateChange, false);
+ panel.addEventListener("popupshowing", onPopupShowing);
+ panel.addEventListener("popuphiding", onPopupHiding);
+ for (let event of ["popupshowing", "popuphiding", "popupshown", "popuphidden"])
+ panel.addEventListener(event, onPanelStateChange);
panel.addEventListener("click", onPanelClick, false);
// Panel content document can be either in panel `viewFrame` or in
// a `backgroundFrame` depending on panel state. Listeners are set
// on both to avoid setting and removing listeners on panel state changes.
panel.addEventListener("DOMContentLoaded", onContentReady, true);
backgroundFrame.addEventListener("DOMContentLoaded", onContentReady, true);
panel.addEventListener("load", onContentLoad, true);
backgroundFrame.addEventListener("load", onContentLoad, true);
events.on("document-element-inserted", onContentChange);
-
panel.backgroundFrame = backgroundFrame;
- panel.viewFrame = viewFrame;
+ panel.viewFrame = null;
// Store event listener on the panel instance so that it won't be GC-ed
// while panel is alive.
panel.onContentChange = onContentChange;
return panel;
}
exports.make = make;
@@ -362,19 +362,17 @@ exports.attach = attach;
function detach(panel) {
if (panel.parentNode) panel.parentNode.removeChild(panel);
}
exports.detach = detach;
function dispose(panel) {
panel.backgroundFrame.remove();
- panel.viewFrame.remove();
panel.backgroundFrame = null;
- panel.viewFrame = null;
events.off("document-element-inserted", panel.onContentChange);
panel.onContentChange = null;
detach(panel);
}
exports.dispose = dispose;
function style(panel) {
/**
@@ -386,21 +384,17 @@ function style(panel) {
chrome for example.
**/
try {
let document = panel.ownerDocument;
let contentDocument = getContentDocument(panel);
let window = document.defaultView;
let node = document.getAnonymousElementByAttribute(panel, "class",
- "panel-arrowcontent") ||
- // Before bug 764755, anonymous content was different:
- // TODO: Remove this when targeting FF16+
- document.getAnonymousElementByAttribute(panel, "class",
- "panel-inner-arrowcontent");
+ "panel-arrowcontent");
let { color, fontFamily, fontSize, fontWeight } = window.getComputedStyle(node);
let style = contentDocument.createElement("style");
style.id = "sdk-panel-style";
style.textContent = "body { " +
"color: " + color + ";" +
"font-family: " + fontFamily + ";" +
@@ -418,29 +412,29 @@ function style(panel) {
}
catch (error) {
console.error("Unable to apply panel style");
console.exception(error);
}
}
exports.style = style;
-var getContentFrame = panel =>
- (isOpen(panel) || isOpening(panel)) ?
- panel.firstChild :
- panel.backgroundFrame
+var getContentFrame = panel => panel.viewFrame || panel.backgroundFrame;
exports.getContentFrame = getContentFrame;
function getContentDocument(panel) {
return getContentFrame(panel).contentDocument;
}
exports.getContentDocument = getContentDocument;
function setURL(panel, url) {
- getContentFrame(panel).setAttribute("src", url ? data.url(url) : url);
+ let frame = getContentFrame(panel);
+ let webNav = getDocShell(frame).QueryInterface(Ci.nsIWebNavigation);
+
+ webNav.loadURI(url ? data.url(url) : "about:blank", 0, null, null, null);
}
exports.setURL = setURL;
function allowContextMenu(panel, allow) {
if (allow) {
panel.setAttribute("context", "contentAreaContextMenu");
}
--- a/addon-sdk/source/test/addons/private-browsing-supported/test-panel.js
+++ b/addon-sdk/source/test/addons/private-browsing-supported/test-panel.js
@@ -2,100 +2,98 @@
* 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/. */
'use strict';
const { open, focus, close } = require('sdk/window/helpers');
const { isPrivate } = require('sdk/private-browsing');
const { defer } = require('sdk/core/promise');
const { browserWindows: windows } = require('sdk/windows');
+const { getInnerId, getMostRecentBrowserWindow } = require('sdk/window/utils');
+const { getActiveView } = require('sdk/view/core');
const BROWSER = 'chrome://browser/content/browser.xul';
exports.testRequirePanel = function(assert) {
require('sdk/panel');
assert.ok('the panel module should not throw an error');
};
exports.testShowPanelInPrivateWindow = function(assert, done) {
let panel = require('sdk/panel').Panel({
- contentURL: "data:text/html;charset=utf-8,"
+ contentURL: "data:text/html;charset=utf-8,I'm a leaf on the wind"
});
assert.ok(windows.length > 0, 'there is at least one open window');
for (let window of windows) {
assert.equal(isPrivate(window), false, 'open window is private');
}
- testShowPanel(assert, panel).
+ let panelView = getActiveView(panel);
+ let expectedWindowId = getInnerId(panelView.backgroundFrame.contentWindow);
+
+ function checkPanelFrame() {
+ let iframe = panelView.firstChild;
+
+ assert.equal(panelView.viewFrame, iframe, 'panel has the correct viewFrame value');
+
+ let windowId = getInnerId(iframe.contentWindow);
+
+ assert.equal(windowId, expectedWindowId, 'panel has the correct window visible');
+
+ assert.equal(iframe.contentDocument.body.textContent,
+ "I'm a leaf on the wind",
+ 'the panel has the expected content');
+ }
+
+ function testPanel(window) {
+ let { promise, resolve } = defer();
+
+ assert.ok(!panel.isShowing, 'the panel is not showing [1]');
+
+ panel.once('show', function() {
+ assert.ok(panel.isShowing, 'the panel is showing');
+
+ checkPanelFrame();
+
+ panel.once('hide', function() {
+ assert.ok(!panel.isShowing, 'the panel is not showing [2]');
+
+ resolve(window);
+ });
+
+ panel.hide();
+ });
+
+ panel.show();
+
+ return promise;
+ };
+
+ let initialWindow = getMostRecentBrowserWindow();
+
+ testPanel(initialWindow).
then(makeEmptyPrivateBrowserWindow).
then(focus).
then(function(window) {
assert.equal(isPrivate(window), true, 'opened window is private');
assert.pass('private window was focused');
return window;
}).
- then(function(window) {
- let { promise, resolve } = defer();
-
- assert.ok(!panel.isShowing, 'the panel is not showing [1]');
-
- panel.once('show', function() {
- assert.ok(panel.isShowing, 'the panel is showing');
-
- panel.once('hide', function() {
- assert.ok(!panel.isShowing, 'the panel is not showing [2]');
-
- resolve(window);
- });
-
- panel.hide();
- });
-
- panel.show();
-
- return promise;
- }).
+ then(testPanel).
then(close).
+ then(() => focus(initialWindow)).
+ then(testPanel).
then(done).
then(null, assert.fail);
};
function makeEmptyPrivateBrowserWindow(options) {
options = options || {};
return open(BROWSER, {
features: {
chrome: true,
toolbar: true,
private: true
}
});
}
-
-function testShowPanel(assert, panel) {
- let { promise, resolve } = defer();
- let shown = false;
-
- assert.ok(!panel.isShowing, 'the panel is not showing [1]');
-
- panel.once('hide', function() {
- assert.ok(!panel.isShowing, 'the panel is not showing [2]');
- assert.ok(shown, 'the panel was shown')
-
- resolve(null);
- });
-
- panel.once('show', function() {
- shown = true;
-
- assert.ok(panel.isShowing, 'the panel is showing');
-
- panel.hide();
- });
-
- panel.show();
-
- return promise;
-}
-
-//Test disabled because of bug 911071
-module.exports = {}