diff --git a/dom/browser-element/BrowserElementChildPreload.js b/dom/browser-element/BrowserElementChildPreload.js index 75f62604e603..e6bbf89733ee 100644 --- a/dom/browser-element/BrowserElementChildPreload.js +++ b/dom/browser-element/BrowserElementChildPreload.js @@ -379,6 +379,10 @@ BrowserElementChild.prototype = { } debug("Nested event loop - finish"); + if (win.modalDepth == 0) { + delete this._windowIDDict[outerWindowID]; + } + // If we exited the loop because the inner window changed, then bail on the // modal prompt. if (innerWindowID !== this._tryGetInnerWindowID(win)) { @@ -411,7 +415,6 @@ BrowserElementChild.prototype = { } let win = this._windowIDDict[outerID].get(); - delete this._windowIDDict[outerID]; if (!win) { debug("recvStopWaiting, but window is gone\n"); diff --git a/dom/browser-element/mochitest/browserElement_Alert.js b/dom/browser-element/mochitest/browserElement_Alert.js index 0c63ab39661f..269996bb5174 100644 --- a/dom/browser-element/mochitest/browserElement_Alert.js +++ b/dom/browser-element/mochitest/browserElement_Alert.js @@ -124,7 +124,7 @@ function test4() { // test4 is a mozbrowsershowmodalprompt listener. function test5(e) { - iframe.removeEventListener('mozbrowsershowmodalprompt', test4); + iframe.removeEventListener('mozbrowsershowmodalprompt', test5); is(e.detail.message, 'test4'); e.preventDefault(); // cause the page to block. @@ -139,6 +139,140 @@ function test5a() { function test5b() { iframe.removeEventListener('mozbrowserloadend', test5b); + SimpleTest.executeSoon(test6); +} + +// Test nested alerts +var promptBlockers = []; +function test6() { + iframe.addEventListener("mozbrowsershowmodalprompt", test6a); + + var script = 'data:,\ + this.testState = 0; \ + content.alert(1); \ + this.testState = 3; \ + '; + mm.loadFrameScript(script, /* allowDelayedLoad = */ false); +} + +function test6a(e) { + iframe.removeEventListener("mozbrowsershowmodalprompt", test6a); + + is(e.detail.message, '1'); + e.preventDefault(); // cause the alert to block. + promptBlockers.push(e); + + SimpleTest.executeSoon(test6b); +} + +function test6b() { + var script = 'data:,\ + if (this.testState === 0) { \ + sendAsyncMessage("test-success", "1: Correct testState"); \ + } \ + else { \ + sendAsyncMessage("test-fail", "1: Wrong testState: " + this.testState); \ + }'; + mm.loadFrameScript(script, /* allowDelayedLoad = */ false); + numPendingChildTests++; + + waitForPendingTests(test6c); +} + +function test6c() { + iframe.addEventListener("mozbrowsershowmodalprompt", test6d); + + var script = 'data:,\ + this.testState = 1; \ + content.alert(2); \ + this.testState = 2; \ + '; + mm.loadFrameScript(script, /* allowDelayedLoad = */ false); +} + +function test6d(e) { + iframe.removeEventListener("mozbrowsershowmodalprompt", test6d); + + is(e.detail.message, '2'); + e.preventDefault(); // cause the alert to block. + promptBlockers.push(e); + + SimpleTest.executeSoon(test6e); +} + +function test6e() { + var script = 'data:,\ + if (this.testState === 1) { \ + sendAsyncMessage("test-success", "2: Correct testState"); \ + } \ + else { \ + sendAsyncMessage("test-fail", "2: Wrong testState: " + this.testState); \ + }'; + mm.loadFrameScript(script, /* allowDelayedLoad = */ false); + numPendingChildTests++; + + waitForPendingTests(test6f); +} + +function test6f() { + var e = promptBlockers.pop(); + // Now unblock the iframe and check that the script completed. + e.detail.unblock(); + + var script2 = 'data:,\ + if (this.testState === 2) { \ + sendAsyncMessage("test-success", "3: Correct testState"); \ + } \ + else { \ + sendAsyncMessage("test-try-again", "3: Wrong testState (for now): " + this.testState); \ + }'; + + // Urgh. e.unblock() didn't necessarily unblock us immediately, so we have + // to spin and wait. + function onTryAgain() { + SimpleTest.executeSoon(function() { + //dump('onTryAgain\n'); + mm.loadFrameScript(script2, /* allowDelayedLoad = */ false); + }); + } + + mm.addMessageListener('test-try-again', onTryAgain); + numPendingChildTests++; + + onTryAgain(); + waitForPendingTests(test6g); +} + +function test6g() { + var e = promptBlockers.pop(); + // Now unblock the iframe and check that the script completed. + e.detail.unblock(); + + var script2 = 'data:,\ + if (this.testState === 3) { \ + sendAsyncMessage("test-success", "4: Correct testState"); \ + } \ + else { \ + sendAsyncMessage("test-try-again", "4: Wrong testState (for now): " + this.testState); \ + }'; + + // Urgh. e.unblock() didn't necessarily unblock us immediately, so we have + // to spin and wait. + function onTryAgain() { + SimpleTest.executeSoon(function() { + //dump('onTryAgain\n'); + mm.loadFrameScript(script2, /* allowDelayedLoad = */ false); + }); + } + + mm.addMessageListener('test-try-again', onTryAgain); + numPendingChildTests++; + + onTryAgain(); + waitForPendingTests(test6h); +} + +function test6h() { SimpleTest.finish(); }