diff --git a/lib/sdk/panel/utils.js b/lib/sdk/panel/utils.js
index c502b1795..2afbab40e 100644
--- a/lib/sdk/panel/utils.js
+++ b/lib/sdk/panel/utils.js
@@ -236,7 +236,12 @@ function make(document) {
let viewFrame = createFrame(panel, frameOptions);
setupPanelFrame(viewFrame);
- function onDisplayChange({type}) {
+ function onDisplayChange({type, target}) {
+ // Events from child element like may propagate (dropdowns are
+ // popups too), in which case frame loader shouldn't be swapped.
+ // See Bug 886329
+ if (target !== this) return;
+
try { swapFrameLoaders(backgroundFrame, viewFrame); }
catch(error) { console.exception(error); }
events.emit(type, { subject: panel });
diff --git a/lib/sdk/window/helpers.js b/lib/sdk/window/helpers.js
index 43a11b14b..b69ffeba9 100644
--- a/lib/sdk/window/helpers.js
+++ b/lib/sdk/window/helpers.js
@@ -5,7 +5,8 @@
const { defer } = require('../core/promise');
const events = require('../system/events');
-const { open: openWindow, onFocus, getToplevelWindow } = require('./utils');
+const { open: openWindow, onFocus, getToplevelWindow,
+ isInteractive } = require('./utils');
function open(uri, options) {
return promise(openWindow.apply(null, arguments), 'load');
@@ -36,6 +37,18 @@ function focus(window) {
}
exports.focus = focus;
+function ready(window) {
+ let { promise: result, resolve } = defer();
+
+ if (isInteractive(window))
+ resolve(window);
+ else
+ resolve(promise(window, 'DOMContentLoaded'));
+
+ return result;
+}
+exports.ready = ready;
+
function promise(target, evt, capture) {
let deferred = defer();
capture = !!capture;
@@ -47,4 +60,4 @@ function promise(target, evt, capture) {
return deferred.promise;
}
-exports.promise = promise;
\ No newline at end of file
+exports.promise = promise;
diff --git a/test/test-panel.js b/test/test-panel.js
index 5d4bd4754..eab3720b7 100644
--- a/test/test-panel.js
+++ b/test/test-panel.js
@@ -14,7 +14,7 @@ const { Loader } = require('sdk/test/loader');
const { LoaderWithHookedConsole } = require("sdk/test/loader");
const timer = require("sdk/timers");
const self = require('sdk/self');
-const { open, close, focus } = require('sdk/window/helpers');
+const { open, close, focus, ready } = require('sdk/window/helpers');
const { isPrivate } = require('sdk/private-browsing');
const { isWindowPBSupported, isGlobalPBSupported } = require('sdk/private-browsing/utils');
const { defer, all } = require('sdk/core/promise');
@@ -896,6 +896,43 @@ exports['test passing DOM node as first argument'] = function (assert, done) {
panel.show(widgetNode);
};
+// This test is checking that `onpupshowing` events emitted by panel's children
+// are not considered.
+// See Bug 886329
+exports['test nested popups'] = function (assert, done) {
+ let loader = Loader(module);
+ let { Panel } = loader.require('sdk/panel');
+ let { getActiveView } = loader.require('sdk/view/core');
+ let url = '';
+
+ let getContentWindow = panel => {
+ return getActiveView(panel).querySelector('iframe').contentWindow;
+ }
+
+ let panel = Panel({
+ contentURL: 'data:text/html;charset=utf-8,' + encodeURIComponent(url),
+ onShow: () => {
+ ready(getContentWindow(panel)).then(({ window, document }) => {
+ let select = document.querySelector('select');
+ let event = document.createEvent('UIEvent');
+
+ event.initUIEvent('popupshowing', true, true, window, null);
+ select.dispatchEvent(event);
+
+ assert.equal(
+ select,
+ getContentWindow(panel).document.querySelector('select'),
+ 'select is still loaded in panel'
+ );
+
+ done();
+ });
+ }
+ });
+
+ panel.show();
+};
+
if (isWindowPBSupported) {
exports.testGetWindow = function(assert, done) {
let activeWindow = getMostRecentBrowserWindow();