зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 5 changesets (bug 1615588) for browser-chrome failures e.g. browser_beforeunload_duplicate_dialogs.js. CLOSED TREE
Backed out changeset 751cca7566a8 (bug 1615588) Backed out changeset 474aca043834 (bug 1615588) Backed out changeset 7839b95ef76c (bug 1615588) Backed out changeset 32bb87f48b13 (bug 1615588) Backed out changeset 264e642042b1 (bug 1615588) --HG-- extra : rebase_source : 41ed149c97382bc1cf823abc56811b382cae0207
This commit is contained in:
Родитель
2e7598ddac
Коммит
954b969608
|
@ -46,9 +46,6 @@
|
|||
};
|
||||
|
||||
this.check = function showAlert_finalCheck(aEvent) {
|
||||
if(aEvent.type === EVENT_HIDE) {
|
||||
return;
|
||||
}
|
||||
var dialog = aEvent.accessible.DOMNode;
|
||||
var info = dialog.querySelector(".tabmodalprompt-infoBody");
|
||||
testRelation(info, RELATION_DESCRIPTION_FOR, dialog);
|
||||
|
@ -60,34 +57,14 @@
|
|||
};
|
||||
}
|
||||
|
||||
function closeAlert() {
|
||||
this.eventSeq = [
|
||||
{
|
||||
type: EVENT_HIDE,
|
||||
match(aEvent) {
|
||||
return aEvent.accessible.role == ROLE_DIALOG;
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
this.invoke = function showAlert_invoke() {
|
||||
synthesizeKey("VK_RETURN", {}, browserWindow());
|
||||
};
|
||||
|
||||
this.getID = function showAlert_getID() {
|
||||
return "cleanup alert";
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// gA11yEventDumpToConsole = true; // debug
|
||||
|
||||
var gQueue = null;
|
||||
function doTests() {
|
||||
gQueue = new eventQueue();
|
||||
gQueue.push(new showAlert());
|
||||
gQueue.push(new closeAlert());
|
||||
gQueue.onFinish = function() {
|
||||
synthesizeKey("VK_RETURN", {}, browserWindow());
|
||||
closeBrowserWindow();
|
||||
};
|
||||
gQueue.invoke(); // will call SimpleTest.finish()
|
||||
|
|
|
@ -1,20 +0,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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["PromptChild"];
|
||||
|
||||
class PromptChild extends JSWindowActorChild {
|
||||
constructor(dispatcher) {
|
||||
super(dispatcher);
|
||||
}
|
||||
|
||||
handleEvent(aEvent) {
|
||||
if (aEvent.type !== "pagehide") {
|
||||
return;
|
||||
}
|
||||
this.sendAsyncMessage("Prompt:OnPageHide", {});
|
||||
}
|
||||
}
|
|
@ -120,35 +120,40 @@ class PromptParent extends JSWindowActorParent {
|
|||
forceClosePrompts(browsingContext) {
|
||||
let prompts = gBrowserPrompts.get(browsingContext) || [];
|
||||
|
||||
for (let [, prompt] of prompts) {
|
||||
prompt.tabModalPrompt && prompt.tabModalPrompt.abortPrompt();
|
||||
for (let prompt of prompts) {
|
||||
if (prompt.tabModalPrompt) {
|
||||
prompt.tabModalPrompt.abortPrompt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
receiveMessage(message) {
|
||||
let browsingContext = this.browsingContext;
|
||||
let args = message.data;
|
||||
let browsingContext = args.browsingContext || this.browsingContext;
|
||||
let id = args._remoteId;
|
||||
|
||||
switch (message.name) {
|
||||
case "Prompt:Open": {
|
||||
const COMMON_DIALOG = "chrome://global/content/commonDialog.xhtml";
|
||||
const SELECT_DIALOG = "chrome://global/content/selectDialog.xhtml";
|
||||
|
||||
let topPrincipal =
|
||||
browsingContext.top.currentWindowGlobal.documentPrincipal;
|
||||
args.showAlertOrigin = topPrincipal.equals(args.promptPrincipal);
|
||||
if (args.modalType === Ci.nsIPrompt.MODAL_TYPE_WINDOW) {
|
||||
return this.openWindowPrompt(args, browsingContext);
|
||||
|
||||
if (message.data.tabPrompt) {
|
||||
return this.openTabPrompt(message.data, browsingContext, id);
|
||||
}
|
||||
return this.openTabPrompt(args, browsingContext, id);
|
||||
let uri =
|
||||
message.data.promptType == "select" ? SELECT_DIALOG : COMMON_DIALOG;
|
||||
|
||||
let browser = browsingContext.top.embedderElement;
|
||||
return this.openModalWindow(uri, message.data, browser);
|
||||
}
|
||||
case "Prompt:ForceClose": {
|
||||
this.forceClosePrompt(browsingContext, id);
|
||||
break;
|
||||
}
|
||||
case "Prompt:OnPageHide": {
|
||||
// User navigates away, close all non window prompts
|
||||
this.forceClosePrompts(browsingContext);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
@ -167,15 +172,12 @@ class PromptParent extends JSWindowActorParent {
|
|||
* A unique ID to differentiate multiple Prompts coming from the same
|
||||
* BrowsingContext.
|
||||
* @return {Promise}
|
||||
* Resolves when the TabModalPrompt is dismissed.
|
||||
* @resolves {Object}
|
||||
* The arguments returned from the TabModalPrompt.
|
||||
* Resolves with the arguments returned from the TabModalPrompt when it
|
||||
* is dismissed.
|
||||
*/
|
||||
openTabPrompt(args, browsingContext = this.browsingContext, id) {
|
||||
openTabPrompt(args, browsingContext, id) {
|
||||
let browser = browsingContext.top.embedderElement;
|
||||
if (!browser) {
|
||||
throw new Error("Cannot tab-prompt without a browser!");
|
||||
}
|
||||
let window = browser.ownerGlobal;
|
||||
let tabPrompt = window.gBrowser.getTabModalPromptBox(browser);
|
||||
let newPrompt;
|
||||
|
@ -204,7 +206,7 @@ class PromptParent extends JSWindowActorParent {
|
|||
|
||||
PromptUtils.fireDialogEvent(window, "DOMModalDialogClosed", browser);
|
||||
resolver(args);
|
||||
browser.maybeLeaveModalState();
|
||||
browser.leaveModalState();
|
||||
};
|
||||
|
||||
try {
|
||||
|
@ -240,49 +242,31 @@ class PromptParent extends JSWindowActorParent {
|
|||
}
|
||||
|
||||
/**
|
||||
* Opens a window prompt for a BrowsingContext, and puts the associated
|
||||
* Opens a window-modal prompt for a BrowsingContext, and puts the associated
|
||||
* browser in the modal state until the prompt is closed.
|
||||
*
|
||||
* @param {string} uri
|
||||
* The URI to a XUL document to be loaded in a modal window.
|
||||
* @param {Object} args
|
||||
* The arguments passed up from the BrowsingContext to be passed
|
||||
* directly to the modal window.
|
||||
* @param {BrowsingContext} browsingContext
|
||||
* The BrowsingContext from which the request to open the window-modal
|
||||
* @param {Element} browser
|
||||
* The <xul:browser> from which the request to open the window-modal
|
||||
* prompt came.
|
||||
* @return {Promise}
|
||||
* Resolves when the window prompt is dismissed.
|
||||
* @resolves {Object}
|
||||
* The arguments returned from the window prompt.
|
||||
* Resolves with the arguments returned from the window-modal
|
||||
* prompt when it is dismissed.
|
||||
*/
|
||||
openWindowPrompt(args, browsingContext = this.browsingContext) {
|
||||
const COMMON_DIALOG = "chrome://global/content/commonDialog.xhtml";
|
||||
const SELECT_DIALOG = "chrome://global/content/selectDialog.xhtml";
|
||||
let uri = args.promptType == "select" ? SELECT_DIALOG : COMMON_DIALOG;
|
||||
|
||||
let browser = browsingContext.top.embedderElement;
|
||||
// If can't get the browser, because the BC does not have an embedder element,
|
||||
// use window associated with the BC.
|
||||
// This happens if we are passed a browsingContext of a chrome window.
|
||||
let win = (browser && browser.ownerGlobal) || browsingContext.top.window;
|
||||
|
||||
// There's a requirement for prompts to be blocked if a window is
|
||||
// passed and that window is hidden (eg, auth prompts are suppressed if the
|
||||
// passed window is the hidden window).
|
||||
// See bug 875157 comment 30 for more..
|
||||
if (win && win.winUtils && !win.winUtils.isParentWindowMainWidgetVisible) {
|
||||
throw new Error("Cannot call openModalWindow on a hidden window");
|
||||
}
|
||||
|
||||
openModalWindow(uri, args, browser) {
|
||||
let window = browser.ownerGlobal;
|
||||
try {
|
||||
if (browser) {
|
||||
browser.enterModalState();
|
||||
PromptUtils.fireDialogEvent(win, "DOMWillOpenModalDialog", browser);
|
||||
}
|
||||
|
||||
browser.enterModalState();
|
||||
PromptUtils.fireDialogEvent(window, "DOMWillOpenModalDialog", browser);
|
||||
let bag = PromptUtils.objectToPropBag(args);
|
||||
|
||||
Services.ww.openWindow(
|
||||
win,
|
||||
window,
|
||||
uri,
|
||||
"_blank",
|
||||
"centerscreen,chrome,modal,titlebar",
|
||||
|
@ -291,10 +275,8 @@ class PromptParent extends JSWindowActorParent {
|
|||
|
||||
PromptUtils.propBagToObject(bag, args);
|
||||
} finally {
|
||||
if (browser) {
|
||||
browser.leaveModalState();
|
||||
PromptUtils.fireDialogEvent(win, "DOMModalDialogClosed", browser);
|
||||
}
|
||||
browser.leaveModalState();
|
||||
PromptUtils.fireDialogEvent(window, "DOMModalDialogClosed", browser);
|
||||
}
|
||||
return Promise.resolve(args);
|
||||
}
|
||||
|
|
|
@ -49,7 +49,6 @@ FINAL_TARGET_FILES.actors += [
|
|||
'PageStyleParent.jsm',
|
||||
'PluginChild.jsm',
|
||||
'PluginParent.jsm',
|
||||
'PromptChild.jsm',
|
||||
'PromptParent.jsm',
|
||||
'RFPHelperChild.jsm',
|
||||
'RFPHelperParent.jsm',
|
||||
|
|
|
@ -1256,10 +1256,6 @@ pref("browser.menu.showCharacterEncoding", "chrome://browser/locale/browser.prop
|
|||
// Allow using tab-modal prompts when possible.
|
||||
pref("prompts.tab_modal.enabled", true);
|
||||
|
||||
// Whether prompts should be content modal (1) tab modal (2) or window modal(3) by default
|
||||
// This is a fallback value for when prompt callers do not specify a modalType.
|
||||
pref("prompts.defaultModalType", 3);
|
||||
|
||||
// Activates preloading of the new tab url.
|
||||
pref("browser.newtab.preload", true);
|
||||
|
||||
|
|
|
@ -1338,12 +1338,14 @@ BrowserPageActions.addSearchEngine = {
|
|||
"error_duplicate_engine_msg",
|
||||
[brandName, uri]
|
||||
);
|
||||
Services.prompt.alertBC(
|
||||
gBrowser.selectedBrowser.browsingContext,
|
||||
Ci.nsIPrompt.MODAL_TYPE_CONTENT,
|
||||
title,
|
||||
text
|
||||
Services.prompt.QueryInterface(Ci.nsIPromptFactory);
|
||||
let prompt = Services.prompt.getPrompt(
|
||||
gBrowser.contentWindow,
|
||||
Ci.nsIPrompt
|
||||
);
|
||||
prompt.QueryInterface(Ci.nsIWritablePropertyBag2);
|
||||
prompt.setPropertyAsBool("allowTabModal", true);
|
||||
prompt.alert(title, text);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
|
|
@ -8874,14 +8874,13 @@ const SafeBrowsingNotificationBox = {
|
|||
function TabModalPromptBox(browser) {
|
||||
this._weakBrowserRef = Cu.getWeakReference(browser);
|
||||
/*
|
||||
* These WeakMaps holds the TabModalPrompt instances, key to the <tabmodalprompt> prompt
|
||||
* This WeakMap holds the TabModalPrompt instances, key to the <tabmodalprompt> prompt
|
||||
* in the DOM. We don't want to hold the instances directly to avoid leaking.
|
||||
*
|
||||
* WeakMap also prevents us from reading back its insertion order.
|
||||
* Order of the elements in the DOM should be the only order to consider.
|
||||
*/
|
||||
this._contentPrompts = new WeakMap();
|
||||
this._tabPrompts = new WeakMap();
|
||||
this.prompts = new WeakMap();
|
||||
}
|
||||
|
||||
TabModalPromptBox.prototype = {
|
||||
|
@ -8905,24 +8904,10 @@ TabModalPromptBox.prototype = {
|
|||
onCloseCallback.apply(this, args);
|
||||
},
|
||||
|
||||
getPrompt(promptEl) {
|
||||
if (promptEl.classList.contains("tab-prompt")) {
|
||||
return this._tabPrompts.get(promptEl);
|
||||
}
|
||||
return this._contentPrompts.get(promptEl);
|
||||
},
|
||||
|
||||
appendPrompt(args, onCloseCallback) {
|
||||
let browser = this.browser;
|
||||
let newPrompt = new TabModalPrompt(browser.ownerGlobal);
|
||||
|
||||
if (args.modalType === Ci.nsIPrompt.MODAL_TYPE_TAB) {
|
||||
newPrompt.element.classList.add("tab-prompt");
|
||||
this._tabPrompts.set(newPrompt.element, newPrompt);
|
||||
} else {
|
||||
newPrompt.element.classList.add("content-prompt");
|
||||
this._contentPrompts.set(newPrompt.element, newPrompt);
|
||||
}
|
||||
this.prompts.set(newPrompt.element, newPrompt);
|
||||
|
||||
browser.parentNode.insertBefore(
|
||||
newPrompt.element,
|
||||
|
@ -8930,7 +8915,7 @@ TabModalPromptBox.prototype = {
|
|||
);
|
||||
browser.setAttribute("tabmodalPromptShowing", true);
|
||||
|
||||
let prompts = this.listPrompts(args.modalType);
|
||||
let prompts = this.listPrompts();
|
||||
if (prompts.length > 1) {
|
||||
// Let's hide ourself behind the current prompt.
|
||||
newPrompt.element.hidden = true;
|
||||
|
@ -8972,16 +8957,11 @@ TabModalPromptBox.prototype = {
|
|||
},
|
||||
|
||||
removePrompt(aPrompt) {
|
||||
if (aPrompt.modalType === Ci.nsIPrompt.MODAL_TYPE_TAB) {
|
||||
this._tabPrompts.delete(aPrompt.element);
|
||||
} else {
|
||||
this._contentPrompts.delete(aPrompt.element);
|
||||
}
|
||||
|
||||
this.prompts.delete(aPrompt.element);
|
||||
let browser = this.browser;
|
||||
aPrompt.element.remove();
|
||||
|
||||
let prompts = this.listPrompts(aPrompt.modalType);
|
||||
let prompts = this.listPrompts();
|
||||
if (prompts.length) {
|
||||
let prompt = prompts[prompts.length - 1];
|
||||
prompt.element.hidden = false;
|
||||
|
@ -8993,29 +8973,15 @@ TabModalPromptBox.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
listPrompts(aModalType = null) {
|
||||
listPrompts(aPrompt) {
|
||||
// Get the nodelist, then return the TabModalPrompt instances as an array
|
||||
let selector = "tabmodalprompt";
|
||||
let promptMap;
|
||||
|
||||
if (aModalType != null) {
|
||||
if (aModalType === Ci.nsIPrompt.MODAL_TYPE_TAB) {
|
||||
selector += ".tab-prompt";
|
||||
promptMap = this._tabPrompts;
|
||||
} else {
|
||||
selector += ".content-prompt";
|
||||
promptMap = this._contentPrompts;
|
||||
}
|
||||
}
|
||||
|
||||
let elements = this.browser.parentNode.querySelectorAll(selector);
|
||||
|
||||
if (promptMap) {
|
||||
return [...elements].map(el => promptMap.get(el));
|
||||
}
|
||||
return [...elements].map(
|
||||
el => this._contentPrompts.get(el) || this._tabPrompts.get(el)
|
||||
const XUL_NS =
|
||||
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
let els = this.browser.parentNode.getElementsByTagNameNS(
|
||||
XUL_NS,
|
||||
"tabmodalprompt"
|
||||
);
|
||||
return Array.from(els).map(el => this.prompts.get(el));
|
||||
},
|
||||
|
||||
onNextPromptShowAllowFocusCheckboxFor(principal) {
|
||||
|
|
|
@ -43,7 +43,6 @@ const whitelist = {
|
|||
"resource:///actors/BrowserTabChild.jsm",
|
||||
"resource:///actors/LinkHandlerChild.jsm",
|
||||
"resource:///actors/SearchTelemetryChild.jsm",
|
||||
"resource:///actors/PromptChild.jsm",
|
||||
"resource://gre/actors/AutoCompleteChild.jsm",
|
||||
"resource://gre/modules/ActorChild.jsm",
|
||||
"resource://gre/modules/ActorManagerChild.jsm",
|
||||
|
|
|
@ -59,7 +59,9 @@ add_task(async function() {
|
|||
// The oldest should be the first.
|
||||
let i = 0;
|
||||
for (let promptElement of promptElements) {
|
||||
let prompt = tab.linkedBrowser.tabModalPromptBox.getPrompt(promptElement);
|
||||
let prompt = tab.linkedBrowser.tabModalPromptBox.prompts.get(
|
||||
promptElement
|
||||
);
|
||||
let expectedType = ["alert", "prompt", "confirm"][i % 3];
|
||||
is(
|
||||
prompt.Dialog.args.text,
|
||||
|
|
|
@ -61,7 +61,7 @@ add_task(async function() {
|
|||
ok(!checkbox.checked, "Checkbox shouldn't be checked");
|
||||
// tick box and accept dialog
|
||||
checkbox.checked = true;
|
||||
let ourPrompt = openedTab.linkedBrowser.tabModalPromptBox.getPrompt(
|
||||
let ourPrompt = openedTab.linkedBrowser.tabModalPromptBox.prompts.get(
|
||||
ourPromptElement
|
||||
);
|
||||
ourPrompt.onButtonClick(0);
|
||||
|
|
|
@ -305,15 +305,7 @@ let ACTORS = {
|
|||
parent: {
|
||||
moduleURI: "resource:///actors/PromptParent.jsm",
|
||||
},
|
||||
child: {
|
||||
moduleURI: "resource:///actors/PromptChild.jsm",
|
||||
events: {
|
||||
pagehide: {
|
||||
capture: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
includeChrome: true,
|
||||
|
||||
allFrames: true,
|
||||
},
|
||||
|
||||
|
|
|
@ -1165,12 +1165,14 @@ class SearchOneOffs {
|
|||
"error_duplicate_engine_msg",
|
||||
[brandName, target.getAttribute("uri")]
|
||||
);
|
||||
Services.prompt.alertBC(
|
||||
gBrowser.selectedBrowser.browsingContext,
|
||||
Ci.nsIPrompt.MODAL_TYPE_CONTENT,
|
||||
title,
|
||||
text
|
||||
Services.prompt.QueryInterface(Ci.nsIPromptFactory);
|
||||
let prompt = Services.prompt.getPrompt(
|
||||
gBrowser.contentWindow,
|
||||
Ci.nsIPrompt
|
||||
);
|
||||
prompt.QueryInterface(Ci.nsIWritablePropertyBag2);
|
||||
prompt.setPropertyAsBool("allowTabModal", true);
|
||||
prompt.alert(title, text);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ function waitForOnBeforeUnloadDialog(browser, callback) {
|
|||
const stack = browser.parentNode;
|
||||
const dialogs = stack.getElementsByTagName("tabmodalprompt");
|
||||
await waitUntil(() => dialogs[0]);
|
||||
const { button0, button1 } = browser.tabModalPromptBox.getPrompt(
|
||||
const { button0, button1 } = browser.tabModalPromptBox.prompts.get(
|
||||
dialogs[0]
|
||||
).ui;
|
||||
callback(button0, button1);
|
||||
|
|
|
@ -11516,12 +11516,11 @@ nsresult nsDocShell::ConfirmRepost(bool* aRepost) {
|
|||
return rv;
|
||||
}
|
||||
|
||||
// Make the repost prompt content modal to prevent malicious pages from
|
||||
// locking up the browser, see bug 1412559 for an example.
|
||||
// Make the repost prompt tab modal to prevent malicious pages from locking
|
||||
// up the browser, see bug 1412559 for an example.
|
||||
if (nsCOMPtr<nsIWritablePropertyBag2> promptBag =
|
||||
do_QueryInterface(prompter)) {
|
||||
promptBag->SetPropertyAsUint32(NS_LITERAL_STRING("modalType"),
|
||||
nsIPrompt::MODAL_TYPE_CONTENT);
|
||||
promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), true);
|
||||
}
|
||||
|
||||
int32_t buttonPressed;
|
||||
|
|
|
@ -4923,10 +4923,9 @@ bool nsGlobalWindowOuter::AlertOrConfirm(bool aAlert, const nsAString& aMessage,
|
|||
return false;
|
||||
}
|
||||
|
||||
// Always allow content modal prompts for alert and confirm.
|
||||
// Always allow tab modal prompts for alert and confirm.
|
||||
if (nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt)) {
|
||||
promptBag->SetPropertyAsUint32(NS_LITERAL_STRING("modalType"),
|
||||
nsIPrompt::MODAL_TYPE_CONTENT);
|
||||
promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), true);
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
|
@ -5013,10 +5012,9 @@ void nsGlobalWindowOuter::PromptOuter(const nsAString& aMessage,
|
|||
return;
|
||||
}
|
||||
|
||||
// Always allow content modal prompts for prompt.
|
||||
// Always allow tab modal prompts for prompt.
|
||||
if (nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt)) {
|
||||
promptBag->SetPropertyAsUint32(NS_LITERAL_STRING("modalType"),
|
||||
nsIPrompt::MODAL_TYPE_CONTENT);
|
||||
promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), true);
|
||||
}
|
||||
|
||||
// Pass in the default value, if any.
|
||||
|
|
|
@ -1297,7 +1297,7 @@ interface nsIDOMWindowUtils : nsISupports {
|
|||
/**
|
||||
* Is the window is in a modal state? [See enterModalState()]
|
||||
*/
|
||||
boolean isInModalState();
|
||||
[noscript] boolean isInModalState();
|
||||
|
||||
/**
|
||||
* Request set internal desktopMode flag change.
|
||||
|
|
Двоичные данные
memory/replace/dmd/test/script-sort-by.json.gz
Двоичные данные
memory/replace/dmd/test/script-sort-by.json.gz
Двоичный файл не отображается.
|
@ -61,12 +61,6 @@ interface nsIPrompt : nsISupports
|
|||
const unsigned long STD_YES_NO_BUTTONS = (BUTTON_TITLE_YES * BUTTON_POS_0) +
|
||||
(BUTTON_TITLE_NO * BUTTON_POS_1);
|
||||
|
||||
|
||||
// Indicates whether a prompt should be shown in-content, on tab level or as a separate window
|
||||
const unsigned long MODAL_TYPE_CONTENT = 1;
|
||||
const unsigned long MODAL_TYPE_TAB = 2;
|
||||
const unsigned long MODAL_TYPE_WINDOW = 3;
|
||||
|
||||
int32_t confirmEx(in wstring dialogTitle,
|
||||
in wstring text,
|
||||
in unsigned long buttonFlags,
|
||||
|
|
|
@ -295,7 +295,7 @@ browser.Context = class {
|
|||
"tabmodalprompt"
|
||||
);
|
||||
|
||||
return br.tabModalPromptBox.getPrompt(modalElements[0]);
|
||||
return br.tabModalPromptBox.prompts.get(modalElements[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -41,12 +41,6 @@ class BrowserElementChild extends JSWindowActorChild {
|
|||
}
|
||||
|
||||
case "LeaveModalState": {
|
||||
if (
|
||||
!message.data.forceLeave &&
|
||||
!this.contentWindow.windowUtils.isInModalState()
|
||||
) {
|
||||
break;
|
||||
}
|
||||
this.contentWindow.windowUtils.leaveModalState();
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -17,24 +17,6 @@ tabmodalprompt {
|
|||
-moz-user-focus: normal;
|
||||
}
|
||||
|
||||
/*
|
||||
Adjustments for chrome level tab-prompts to make them
|
||||
overlap with the upper chrome UI and move them in
|
||||
front of content prompts.
|
||||
*/
|
||||
tabmodalprompt.tab-prompt {
|
||||
overflow: visible;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
tabmodalprompt.tab-prompt .spacer-top {
|
||||
display: none;
|
||||
}
|
||||
|
||||
tabmodalprompt.tab-prompt *.tabmodalprompt-mainContainer {
|
||||
margin-top: -5px;
|
||||
}
|
||||
|
||||
.infoTitle {
|
||||
margin-bottom: 1em !important;
|
||||
font-weight: bold;
|
||||
|
|
|
@ -25,7 +25,7 @@ var TabModalPrompt = class {
|
|||
newPrompt.appendChild(
|
||||
win.MozXULElement.parseXULToFragment(
|
||||
`
|
||||
<spacer class="spacer-top" flex="1"/>
|
||||
<spacer flex="1"/>
|
||||
<hbox pack="center">
|
||||
<vbox class="tabmodalprompt-mainContainer">
|
||||
<grid class="tabmodalprompt-topContainer" flex="1">
|
||||
|
@ -217,13 +217,6 @@ var TabModalPrompt = class {
|
|||
);
|
||||
}
|
||||
|
||||
// Apply styling depending on modalType (content or tab prompt)
|
||||
if (args.modalType === Ci.nsIPrompt.MODAL_TYPE_TAB) {
|
||||
this.element.classList.add("tab-prompt");
|
||||
} else {
|
||||
this.element.classList.add("content-prompt");
|
||||
}
|
||||
|
||||
// We need to remove the prompt when the tab or browser window is closed or
|
||||
// the page navigates, else we never unwind the event loop and that's sad times.
|
||||
// Remember to cleanup in shutdownPrompt()!
|
||||
|
|
|
@ -26,8 +26,8 @@ Prompter.prototype = {
|
|||
|
||||
/* ---------- private members ---------- */
|
||||
|
||||
pickPrompter(options) {
|
||||
return new ModalPrompter(options);
|
||||
pickPrompter(domWin) {
|
||||
return new ModalPrompter(domWin);
|
||||
},
|
||||
|
||||
/* ---------- nsIPromptFactory ---------- */
|
||||
|
@ -48,7 +48,7 @@ Prompter.prototype = {
|
|||
}
|
||||
}
|
||||
|
||||
let p = new ModalPrompter({ domWin });
|
||||
let p = new ModalPrompter(domWin);
|
||||
p.QueryInterface(iid);
|
||||
return p;
|
||||
},
|
||||
|
@ -56,45 +56,25 @@ Prompter.prototype = {
|
|||
/* ---------- nsIPromptService ---------- */
|
||||
|
||||
alert(domWin, title, text) {
|
||||
let p = this.pickPrompter({ domWin });
|
||||
let p = this.pickPrompter(domWin);
|
||||
p.alert(title, text);
|
||||
},
|
||||
|
||||
alertBC(browsingContext, modalType, ...promptArgs) {
|
||||
let p = this.pickPrompter({ browsingContext, modalType });
|
||||
p.alert(...promptArgs);
|
||||
},
|
||||
|
||||
alertCheck(domWin, title, text, checkLabel, checkValue) {
|
||||
let p = this.pickPrompter({ domWin });
|
||||
let p = this.pickPrompter(domWin);
|
||||
p.alertCheck(title, text, checkLabel, checkValue);
|
||||
},
|
||||
|
||||
alertCheckBC(browsingContext, modalType, ...promptArgs) {
|
||||
let p = this.pickPrompter({ browsingContext, modalType });
|
||||
p.alertCheck(...promptArgs);
|
||||
},
|
||||
|
||||
confirm(domWin, title, text) {
|
||||
let p = this.pickPrompter({ domWin });
|
||||
let p = this.pickPrompter(domWin);
|
||||
return p.confirm(title, text);
|
||||
},
|
||||
|
||||
confirmBC(browsingContext, modalType, ...promptArgs) {
|
||||
let p = this.pickPrompter({ browsingContext, modalType });
|
||||
return p.confirm(...promptArgs);
|
||||
},
|
||||
|
||||
confirmCheck(domWin, title, text, checkLabel, checkValue) {
|
||||
let p = this.pickPrompter({ domWin });
|
||||
let p = this.pickPrompter(domWin);
|
||||
return p.confirmCheck(title, text, checkLabel, checkValue);
|
||||
},
|
||||
|
||||
confirmCheckBC(browsingContext, modalType, ...promptArgs) {
|
||||
let p = this.pickPrompter({ browsingContext, modalType });
|
||||
return p.confirmCheck(...promptArgs);
|
||||
},
|
||||
|
||||
confirmEx(
|
||||
domWin,
|
||||
title,
|
||||
|
@ -106,32 +86,7 @@ Prompter.prototype = {
|
|||
checkLabel,
|
||||
checkValue
|
||||
) {
|
||||
let p = this.pickPrompter({ domWin });
|
||||
return p.confirmEx(
|
||||
title,
|
||||
text,
|
||||
flags,
|
||||
button0,
|
||||
button1,
|
||||
button2,
|
||||
checkLabel,
|
||||
checkValue
|
||||
);
|
||||
},
|
||||
|
||||
confirmExBC(
|
||||
browsingContext,
|
||||
modalType,
|
||||
title,
|
||||
text,
|
||||
flags,
|
||||
button0,
|
||||
button1,
|
||||
button2,
|
||||
checkLabel,
|
||||
checkValue
|
||||
) {
|
||||
let p = this.pickPrompter({ browsingContext, modalType });
|
||||
let p = this.pickPrompter(domWin);
|
||||
return p.confirmEx(
|
||||
title,
|
||||
text,
|
||||
|
@ -145,15 +100,10 @@ Prompter.prototype = {
|
|||
},
|
||||
|
||||
prompt(domWin, title, text, value, checkLabel, checkValue) {
|
||||
let p = this.pickPrompter({ domWin });
|
||||
let p = this.pickPrompter(domWin);
|
||||
return p.nsIPrompt_prompt(title, text, value, checkLabel, checkValue);
|
||||
},
|
||||
|
||||
promptBC(browsingContext, modalType, ...promptArgs) {
|
||||
let p = this.pickPrompter({ browsingContext, modalType });
|
||||
return p.nsIPrompt_prompt(...promptArgs);
|
||||
},
|
||||
|
||||
promptUsernameAndPassword(
|
||||
domWin,
|
||||
title,
|
||||
|
@ -163,7 +113,7 @@ Prompter.prototype = {
|
|||
checkLabel,
|
||||
checkValue
|
||||
) {
|
||||
let p = this.pickPrompter({ domWin });
|
||||
let p = this.pickPrompter(domWin);
|
||||
return p.nsIPrompt_promptUsernameAndPassword(
|
||||
title,
|
||||
text,
|
||||
|
@ -174,13 +124,8 @@ Prompter.prototype = {
|
|||
);
|
||||
},
|
||||
|
||||
promptUsernameAndPasswordBC(browsingContext, modalType, ...promptArgs) {
|
||||
let p = this.pickPrompter({ browsingContext, modalType });
|
||||
return p.nsIPrompt_promptUsernameAndPassword(...promptArgs);
|
||||
},
|
||||
|
||||
promptPassword(domWin, title, text, pass, checkLabel, checkValue) {
|
||||
let p = this.pickPrompter({ domWin });
|
||||
let p = this.pickPrompter(domWin);
|
||||
return p.nsIPrompt_promptPassword(
|
||||
title,
|
||||
text,
|
||||
|
@ -190,31 +135,16 @@ Prompter.prototype = {
|
|||
);
|
||||
},
|
||||
|
||||
promptPasswordBC(browsingContext, modalType, ...promptArgs) {
|
||||
let p = this.pickPrompter({ browsingContext, modalType });
|
||||
return p.nsIPrompt_promptPassword(...promptArgs);
|
||||
},
|
||||
|
||||
select(domWin, title, text, list, selected) {
|
||||
let p = this.pickPrompter({ domWin });
|
||||
let p = this.pickPrompter(domWin);
|
||||
return p.select(title, text, list, selected);
|
||||
},
|
||||
|
||||
selectBC(browsingContext, modalType, ...promptArgs) {
|
||||
let p = this.pickPrompter({ browsingContext, modalType });
|
||||
return p.select(...promptArgs);
|
||||
},
|
||||
|
||||
promptAuth(domWin, channel, level, authInfo, checkLabel, checkValue) {
|
||||
let p = this.pickPrompter({ domWin });
|
||||
let p = this.pickPrompter(domWin);
|
||||
return p.promptAuth(channel, level, authInfo, checkLabel, checkValue);
|
||||
},
|
||||
|
||||
promptAuthBC(browsingContext, modalType, ...promptArgs) {
|
||||
let p = this.pickPrompter({ browsingContext, modalType });
|
||||
return p.promptAuth(...promptArgs);
|
||||
},
|
||||
|
||||
asyncPromptAuth(
|
||||
domWin,
|
||||
channel,
|
||||
|
@ -225,7 +155,7 @@ Prompter.prototype = {
|
|||
checkLabel,
|
||||
checkValue
|
||||
) {
|
||||
let p = this.pickPrompter({ domWin });
|
||||
let p = this.pickPrompter(domWin);
|
||||
return p.asyncPromptAuth(
|
||||
channel,
|
||||
callback,
|
||||
|
@ -236,11 +166,6 @@ Prompter.prototype = {
|
|||
checkValue
|
||||
);
|
||||
},
|
||||
|
||||
asyncPromptAuthBC(browsingContext, modalType, ...promptArgs) {
|
||||
let p = this.pickPrompter({ browsingContext, modalType });
|
||||
return p.asyncPromptAuth(...promptArgs);
|
||||
},
|
||||
};
|
||||
|
||||
// Common utils not specific to a particular prompter style.
|
||||
|
@ -444,6 +369,33 @@ var PromptUtilsTemp = {
|
|||
return text;
|
||||
},
|
||||
|
||||
getTabModalPrompt(domWin) {
|
||||
var promptBox = null;
|
||||
|
||||
try {
|
||||
// Get the topmost window, in case we're in a frame.
|
||||
var promptWin = domWin.top;
|
||||
|
||||
// Get the chrome window for the content window we're using.
|
||||
// (Unwrap because we need a non-IDL property below.)
|
||||
var chromeWin =
|
||||
promptWin.docShell.chromeEventHandler.ownerGlobal.wrappedJSObject;
|
||||
|
||||
if (chromeWin) {
|
||||
if (chromeWin.gBrowser && chromeWin.gBrowser.getTabModalPromptBox) {
|
||||
let browser = promptWin.docShell.chromeEventHandler;
|
||||
promptBox = chromeWin.gBrowser.getTabModalPromptBox(browser);
|
||||
} else if (chromeWin.getTabModalPromptBox) {
|
||||
chromeWin.getTabModalPromptBox(promptWin);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// If any errors happen, just assume no tabmodal prompter.
|
||||
}
|
||||
|
||||
return promptBox;
|
||||
},
|
||||
|
||||
getBrandFullName() {
|
||||
return this.brandBundle.GetStringFromName("brandFullName");
|
||||
},
|
||||
|
@ -482,169 +434,190 @@ XPCOMUtils.defineLazyGetter(PromptUtils, "ellipsis", function() {
|
|||
return ellipsis;
|
||||
});
|
||||
|
||||
class ModalPrompter {
|
||||
constructor({ browsingContext = null, domWin = null, modalType = null }) {
|
||||
if (browsingContext && domWin) {
|
||||
throw new Error("Pass either browsingContext or domWin");
|
||||
}
|
||||
this.browsingContext = browsingContext;
|
||||
this._domWin = domWin;
|
||||
function openModalWindow(domWin, uri, args) {
|
||||
// There's an implied contract that says modal prompts should still work
|
||||
// when no "parent" window is passed for the dialog (eg, the "Master
|
||||
// Password" dialog does this). These prompts must be shown even if there
|
||||
// are *no* visible windows at all.
|
||||
// There's also a requirement for prompts to be blocked if a window is
|
||||
// passed and that window is hidden (eg, auth prompts are supressed if the
|
||||
// passed window is the hidden window).
|
||||
// See bug 875157 comment 30 for more...
|
||||
if (domWin) {
|
||||
// a domWin was passed, so we can apply the check for it being hidden.
|
||||
let winUtils = domWin.windowUtils;
|
||||
|
||||
if (this._domWin) {
|
||||
// We have a domWin, get the associated browsing context
|
||||
this.browsingContext = BrowsingContext.getFromWindow(this._domWin);
|
||||
} else if (this.browsingContext) {
|
||||
// We have a browsingContext, get the associated dom window
|
||||
if (this.browsingContext.window) {
|
||||
this._domWin = this.browsingContext.window;
|
||||
} else {
|
||||
this._domWin =
|
||||
this.browsingContext.embedderElement &&
|
||||
this.browsingContext.embedderElement.ownerGlobal;
|
||||
}
|
||||
if (winUtils && !winUtils.isParentWindowMainWidgetVisible) {
|
||||
throw Components.Exception(
|
||||
"Cannot call openModalWindow on a hidden window",
|
||||
Cr.NS_ERROR_NOT_AVAILABLE
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// We try and find a window to use as the parent, but don't consider
|
||||
// if that is visible before showing the prompt.
|
||||
domWin = Services.ww.activeWindow;
|
||||
// domWin may still be null here if there are _no_ windows open.
|
||||
}
|
||||
// Note that we don't need to fire DOMWillOpenModalDialog and
|
||||
// DOMModalDialogClosed events here, wwatcher's OpenWindowInternal
|
||||
// will do that. Similarly for enterModalState / leaveModalState.
|
||||
|
||||
Services.ww.openWindow(
|
||||
domWin && domWin.docShell.rootTreeItem.domWindow,
|
||||
uri,
|
||||
"_blank",
|
||||
"centerscreen,chrome,modal,titlebar",
|
||||
args
|
||||
);
|
||||
}
|
||||
|
||||
function openTabPrompt(domWin, tabPrompt, args) {
|
||||
let docShell = domWin.docShell;
|
||||
let inPermitUnload =
|
||||
docShell.contentViewer && docShell.contentViewer.inPermitUnload;
|
||||
let eventDetail = Cu.cloneInto({ tabPrompt: true, inPermitUnload }, domWin);
|
||||
PromptUtils.fireDialogEvent(
|
||||
domWin,
|
||||
"DOMWillOpenModalDialog",
|
||||
null,
|
||||
eventDetail
|
||||
);
|
||||
|
||||
let winUtils = domWin.windowUtils;
|
||||
winUtils.enterModalState();
|
||||
|
||||
let frameMM = docShell.messageManager;
|
||||
|
||||
// We provide a callback so the prompt can close itself. We don't want to
|
||||
// wait for this event loop to return... Otherwise the presence of other
|
||||
// prompts on the call stack would in this dialog appearing unresponsive
|
||||
// until the other prompts had been closed.
|
||||
let callbackInvoked = false;
|
||||
let newPrompt;
|
||||
function onPromptClose(forceCleanup) {
|
||||
if (!newPrompt && !forceCleanup) {
|
||||
return;
|
||||
}
|
||||
callbackInvoked = true;
|
||||
if (newPrompt) {
|
||||
tabPrompt.removePrompt(newPrompt);
|
||||
}
|
||||
|
||||
// Use given modal type or fallback to default
|
||||
this.modalType = modalType || ModalPrompter.defaultModalType;
|
||||
frameMM.removeEventListener("pagehide", pagehide, true);
|
||||
|
||||
this.QueryInterface = ChromeUtils.generateQI([
|
||||
Ci.nsIPrompt,
|
||||
Ci.nsIAuthPrompt,
|
||||
Ci.nsIAuthPrompt2,
|
||||
Ci.nsIWritablePropertyBag2,
|
||||
]);
|
||||
winUtils.leaveModalState();
|
||||
|
||||
PromptUtils.fireDialogEvent(domWin, "DOMModalDialogClosed");
|
||||
}
|
||||
|
||||
set modalType(modalType) {
|
||||
// Setting modal type window is always allowed
|
||||
if (modalType == Ci.nsIPrompt.MODAL_TYPE_WINDOW) {
|
||||
this._modalType = modalType;
|
||||
frameMM.addEventListener("pagehide", pagehide, true);
|
||||
function pagehide(e) {
|
||||
// Check whether the event relates to our window or its ancestors
|
||||
let window = domWin;
|
||||
let eventWindow = e.target.defaultView;
|
||||
while (window != eventWindow && window.parent != window) {
|
||||
window = window.parent;
|
||||
}
|
||||
if (window != eventWindow) {
|
||||
return;
|
||||
}
|
||||
frameMM.removeEventListener("pagehide", pagehide, true);
|
||||
|
||||
if (newPrompt) {
|
||||
newPrompt.abortPrompt();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
let topPrincipal = domWin.top.document.nodePrincipal;
|
||||
let promptPrincipal = domWin.document.nodePrincipal;
|
||||
args.showAlertOrigin = topPrincipal.equals(promptPrincipal);
|
||||
args.promptActive = true;
|
||||
|
||||
newPrompt = tabPrompt.appendPrompt(args, onPromptClose);
|
||||
|
||||
// TODO since we don't actually open a window, need to check if
|
||||
// there's other stuff in nsWindowWatcher::OpenWindowInternal
|
||||
// that we might need to do here as well.
|
||||
|
||||
Services.tm.spinEventLoopUntil(() => !args.promptActive);
|
||||
delete args.promptActive;
|
||||
|
||||
if (args.promptAborted) {
|
||||
throw Components.Exception(
|
||||
"prompt aborted by user",
|
||||
Cr.NS_ERROR_NOT_AVAILABLE
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
// If the prompt unexpectedly failed to invoke the callback, do so here.
|
||||
if (!callbackInvoked) {
|
||||
onPromptClose(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function openRemotePrompt(domWin, args) {
|
||||
let actor = domWin.windowGlobalChild.getActor("Prompt");
|
||||
|
||||
let docShell = domWin.docShell;
|
||||
let inPermitUnload =
|
||||
docShell.contentViewer && docShell.contentViewer.inPermitUnload;
|
||||
let eventDetail = Cu.cloneInto(
|
||||
{ tabPrompt: args.tabPrompt, inPermitUnload },
|
||||
domWin
|
||||
);
|
||||
PromptUtils.fireDialogEvent(
|
||||
domWin,
|
||||
"DOMWillOpenModalDialog",
|
||||
null,
|
||||
eventDetail
|
||||
);
|
||||
|
||||
let windowUtils = domWin.windowUtils;
|
||||
windowUtils.enterModalState();
|
||||
|
||||
// It is technically possible for multiple prompts to be sent from a single
|
||||
// BrowsingContext. See bug 1266353. We use a randomly generated UUID to
|
||||
// differentiate between the different prompts.
|
||||
let id =
|
||||
"id" +
|
||||
Cc["@mozilla.org/uuid-generator;1"]
|
||||
.getService(Ci.nsIUUIDGenerator)
|
||||
.generateUUID()
|
||||
.toString();
|
||||
|
||||
let frameMM = docShell.messageManager;
|
||||
let closed = false;
|
||||
|
||||
let onPageHide = e => {
|
||||
let window = domWin;
|
||||
let eventWindow = e.target.defaultView;
|
||||
while (window != eventWindow && window.parent != window) {
|
||||
window = window.parent;
|
||||
}
|
||||
if (window != eventWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we have a chrome window and the browsing context isn't embedded
|
||||
// in a browser, we can't use tab/content prompts.
|
||||
// Or if we don't allow tab or content prompts, override modalType
|
||||
// argument to use window prompts
|
||||
if (
|
||||
!this.browsingContext ||
|
||||
!this._domWin ||
|
||||
(this._domWin.isChromeWindow &&
|
||||
!this.browsingContext.top.embedderElement) ||
|
||||
!ModalPrompter.tabModalEnabled
|
||||
) {
|
||||
modalType = Ci.nsIPrompt.MODAL_TYPE_WINDOW;
|
||||
actor.sendAsyncMessage("Prompt:ForceClose", { _remoteId: id });
|
||||
closed = true;
|
||||
};
|
||||
|
||||
Cu.reportError(
|
||||
"Prompter: Browser not available or tab modal prompts disabled. Falling back to window prompt."
|
||||
);
|
||||
}
|
||||
this._modalType = modalType;
|
||||
}
|
||||
frameMM.addEventListener("pagehide", onPageHide, true);
|
||||
|
||||
get modalType() {
|
||||
return this._modalType;
|
||||
}
|
||||
|
||||
/* ---------- internal methods ---------- */
|
||||
|
||||
openPrompt(args) {
|
||||
if (!this.browsingContext) {
|
||||
// We don't have a browsing context, fallback to a window prompt
|
||||
|
||||
// There's an implied contract that says modal prompts should still work
|
||||
// when no "parent" window is passed for the dialog (eg, the "Master
|
||||
// Password" dialog does this). These prompts must be shown even if there
|
||||
// are *no* visible windows at all.
|
||||
|
||||
// We try and find a window to use as the parent, but don't consider
|
||||
// if that is visible before showing the prompt.
|
||||
let parentWindow = Services.ww.activeWindow;
|
||||
// parentWindow may still be null here if there are _no_ windows open.
|
||||
|
||||
this.openWindowPrompt(parentWindow, args);
|
||||
return;
|
||||
}
|
||||
|
||||
// Select prompts are not part of CommonDialog
|
||||
// and thus not supported as tab or content prompts yet. See Bug 1622817.
|
||||
// Once they are integrated this override should be removed.
|
||||
if (
|
||||
args.promptType == "select" &&
|
||||
this.modalType !== Ci.nsIPrompt.MODAL_TYPE_WINDOW
|
||||
) {
|
||||
Cu.reportError(
|
||||
"Prompter: 'select' prompts do not support tab/content prompting. Falling back to window prompt."
|
||||
);
|
||||
args.modalType = Ci.nsIPrompt.MODAL_TYPE_WINDOW;
|
||||
} else {
|
||||
args.modalType = this.modalType;
|
||||
}
|
||||
|
||||
args.browsingContext = this.browsingContext;
|
||||
|
||||
let actor = this._domWin.windowGlobalChild.getActor("Prompt");
|
||||
|
||||
let docShell =
|
||||
(this.browsingContext && this.browsingContext.docShell) ||
|
||||
this._domWin.docShell;
|
||||
let inPermitUnload =
|
||||
docShell.contentViewer && docShell.contentViewer.inPermitUnload;
|
||||
let eventDetail = Cu.cloneInto(
|
||||
{
|
||||
tabPrompt: this.modalType != Ci.nsIPrompt.MODAL_TYPE_WINDOW,
|
||||
inPermitUnload,
|
||||
},
|
||||
this._domWin
|
||||
);
|
||||
PromptUtils.fireDialogEvent(
|
||||
this._domWin,
|
||||
"DOMWillOpenModalDialog",
|
||||
null,
|
||||
eventDetail
|
||||
);
|
||||
|
||||
let windowUtils =
|
||||
Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT &&
|
||||
this._domWin.windowUtils;
|
||||
|
||||
// Put content windows in the modal state while the prompt is open.
|
||||
if (windowUtils) {
|
||||
windowUtils.enterModalState();
|
||||
}
|
||||
|
||||
// It is technically possible for multiple prompts to be sent from a single
|
||||
// BrowsingContext. See bug 1266353. We use a randomly generated UUID to
|
||||
// differentiate between the different prompts.
|
||||
let id =
|
||||
"id" +
|
||||
Cc["@mozilla.org/uuid-generator;1"]
|
||||
.getService(Ci.nsIUUIDGenerator)
|
||||
.generateUUID()
|
||||
.toString();
|
||||
|
||||
let closed = false;
|
||||
|
||||
args.promptPrincipal = this._domWin.document.nodePrincipal;
|
||||
try {
|
||||
let promptPrincipal = domWin.document.nodePrincipal;
|
||||
args.promptPrincipal = promptPrincipal;
|
||||
args.inPermitUnload = inPermitUnload;
|
||||
args._remoteId = id;
|
||||
|
||||
actor
|
||||
.sendQuery("Prompt:Open", args)
|
||||
.then(returnedArgs => {
|
||||
// Copy the response from the closed prompt into our args, it will be
|
||||
// read by our caller.
|
||||
if (!returnedArgs) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (returnedArgs.promptAborted) {
|
||||
throw Components.Exception(
|
||||
"prompt aborted by user",
|
||||
Cr.NS_ERROR_NOT_AVAILABLE
|
||||
);
|
||||
}
|
||||
|
||||
let promise = actor.sendQuery("Prompt:Open", args);
|
||||
promise.then(returnedArgs => {
|
||||
// Copy the response from the closed prompt into our args, it will be
|
||||
// read by our caller.
|
||||
if (returnedArgs) {
|
||||
if (returnedArgs._remoteId !== id) {
|
||||
return;
|
||||
}
|
||||
|
@ -652,34 +625,82 @@ class ModalPrompter {
|
|||
for (let key in returnedArgs) {
|
||||
args[key] = returnedArgs[key];
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
closed = true;
|
||||
});
|
||||
}
|
||||
closed = true;
|
||||
});
|
||||
|
||||
Services.tm.spinEventLoopUntilOrShutdown(() => closed);
|
||||
|
||||
if (windowUtils) {
|
||||
windowUtils.leaveModalState();
|
||||
}
|
||||
PromptUtils.fireDialogEvent(this._domWin, "DOMModalDialogClosed");
|
||||
} finally {
|
||||
frameMM.removeEventListener("pagehide", onPageHide, true);
|
||||
windowUtils.leaveModalState();
|
||||
PromptUtils.fireDialogEvent(domWin, "DOMModalDialogClosed");
|
||||
}
|
||||
}
|
||||
|
||||
function ModalPrompter(domWin) {
|
||||
this.domWin = domWin;
|
||||
}
|
||||
ModalPrompter.prototype = {
|
||||
domWin: null,
|
||||
/*
|
||||
* Default to not using a tab-modal prompt, unless the caller opts in by
|
||||
* QIing to nsIWritablePropertyBag and setting the value of this property
|
||||
* to true.
|
||||
*/
|
||||
allowTabModal: false,
|
||||
|
||||
QueryInterface: ChromeUtils.generateQI([
|
||||
Ci.nsIPrompt,
|
||||
Ci.nsIAuthPrompt,
|
||||
Ci.nsIAuthPrompt2,
|
||||
Ci.nsIWritablePropertyBag2,
|
||||
]),
|
||||
|
||||
/* ---------- internal methods ---------- */
|
||||
|
||||
openPrompt(args) {
|
||||
// Check pref, if false/missing do not ever allow tab-modal prompts.
|
||||
const prefName = "prompts.tab_modal.enabled";
|
||||
let prefValue = false;
|
||||
if (Services.prefs.getPrefType(prefName) == Services.prefs.PREF_BOOL) {
|
||||
prefValue = Services.prefs.getBoolPref(prefName);
|
||||
}
|
||||
|
||||
let allowTabModal = this.allowTabModal && prefValue;
|
||||
|
||||
if (allowTabModal && this.domWin) {
|
||||
if (
|
||||
Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT
|
||||
) {
|
||||
args.tabPrompt = true;
|
||||
openRemotePrompt(this.domWin, args);
|
||||
return;
|
||||
}
|
||||
|
||||
let tabPrompt = PromptUtils.getTabModalPrompt(this.domWin);
|
||||
if (tabPrompt) {
|
||||
openTabPrompt(this.domWin, tabPrompt, args);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If we can't do a tab modal prompt, fallback to using a window-modal dialog.
|
||||
if (
|
||||
Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_CONTENT
|
||||
) {
|
||||
args.tabPrompt = false;
|
||||
openRemotePrompt(this.domWin, args);
|
||||
return;
|
||||
}
|
||||
|
||||
openWindowPrompt(parentWindow, args) {
|
||||
const COMMON_DIALOG = "chrome://global/content/commonDialog.xhtml";
|
||||
const SELECT_DIALOG = "chrome://global/content/selectDialog.xhtml";
|
||||
|
||||
let uri = args.promptType == "select" ? SELECT_DIALOG : COMMON_DIALOG;
|
||||
let propBag = PromptUtils.objectToPropBag(args);
|
||||
Services.ww.openWindow(
|
||||
parentWindow,
|
||||
uri,
|
||||
"_blank",
|
||||
"centerscreen,chrome,modal,titlebar",
|
||||
propBag
|
||||
);
|
||||
openModalWindow(this.domWin, uri, propBag);
|
||||
PromptUtils.propBagToObject(propBag, args);
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* ---------- interface disambiguation ----------
|
||||
|
@ -695,7 +716,7 @@ class ModalPrompter {
|
|||
return this.nsIPrompt_prompt.apply(this, arguments);
|
||||
}
|
||||
return this.nsIAuthPrompt_prompt.apply(this, arguments);
|
||||
}
|
||||
},
|
||||
|
||||
promptUsernameAndPassword() {
|
||||
// Both have 6 args, so use types.
|
||||
|
@ -703,7 +724,7 @@ class ModalPrompter {
|
|||
return this.nsIPrompt_promptUsernameAndPassword.apply(this, arguments);
|
||||
}
|
||||
return this.nsIAuthPrompt_promptUsernameAndPassword.apply(this, arguments);
|
||||
}
|
||||
},
|
||||
|
||||
promptPassword() {
|
||||
// Both have 5 args, so use types.
|
||||
|
@ -711,7 +732,7 @@ class ModalPrompter {
|
|||
return this.nsIPrompt_promptPassword.apply(this, arguments);
|
||||
}
|
||||
return this.nsIAuthPrompt_promptPassword.apply(this, arguments);
|
||||
}
|
||||
},
|
||||
|
||||
/* ---------- nsIPrompt ---------- */
|
||||
|
||||
|
@ -727,7 +748,7 @@ class ModalPrompter {
|
|||
};
|
||||
|
||||
this.openPrompt(args);
|
||||
}
|
||||
},
|
||||
|
||||
alertCheck(title, text, checkLabel, checkValue) {
|
||||
if (!title) {
|
||||
|
@ -746,7 +767,7 @@ class ModalPrompter {
|
|||
|
||||
// Checkbox state always returned, even if cancel clicked.
|
||||
checkValue.value = args.checked;
|
||||
}
|
||||
},
|
||||
|
||||
confirm(title, text) {
|
||||
if (!title) {
|
||||
|
@ -764,7 +785,7 @@ class ModalPrompter {
|
|||
|
||||
// Did user click Ok or Cancel?
|
||||
return args.ok;
|
||||
}
|
||||
},
|
||||
|
||||
confirmCheck(title, text, checkLabel, checkValue) {
|
||||
if (!title) {
|
||||
|
@ -787,7 +808,7 @@ class ModalPrompter {
|
|||
|
||||
// Did user click Ok or Cancel?
|
||||
return args.ok;
|
||||
}
|
||||
},
|
||||
|
||||
confirmEx(
|
||||
title,
|
||||
|
@ -841,7 +862,7 @@ class ModalPrompter {
|
|||
|
||||
// Get the number of the button the user clicked.
|
||||
return args.buttonNumClicked;
|
||||
}
|
||||
},
|
||||
|
||||
nsIPrompt_prompt(title, text, value, checkLabel, checkValue) {
|
||||
if (!title) {
|
||||
|
@ -868,7 +889,7 @@ class ModalPrompter {
|
|||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
},
|
||||
|
||||
nsIPrompt_promptUsernameAndPassword(
|
||||
title,
|
||||
|
@ -906,7 +927,7 @@ class ModalPrompter {
|
|||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
},
|
||||
|
||||
nsIPrompt_promptPassword(title, text, pass, checkLabel, checkValue) {
|
||||
if (!title) {
|
||||
|
@ -935,7 +956,7 @@ class ModalPrompter {
|
|||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
},
|
||||
|
||||
select(title, text, list, selected) {
|
||||
if (!title) {
|
||||
|
@ -960,7 +981,7 @@ class ModalPrompter {
|
|||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
},
|
||||
|
||||
/* ---------- nsIAuthPrompt ---------- */
|
||||
|
||||
|
@ -977,7 +998,7 @@ class ModalPrompter {
|
|||
result.value = defaultText;
|
||||
}
|
||||
return this.nsIPrompt_prompt(title, text, result, null, {});
|
||||
}
|
||||
},
|
||||
|
||||
nsIAuthPrompt_promptUsernameAndPassword(
|
||||
title,
|
||||
|
@ -996,12 +1017,12 @@ class ModalPrompter {
|
|||
null,
|
||||
{}
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
nsIAuthPrompt_promptPassword(title, text, passwordRealm, savePassword, pass) {
|
||||
// The passwordRealm and savePassword args were ignored by nsPrompt.cpp
|
||||
return this.nsIPrompt_promptPassword(title, text, pass, null, {});
|
||||
}
|
||||
},
|
||||
|
||||
/* ---------- nsIAuthPrompt2 ---------- */
|
||||
|
||||
|
@ -1037,7 +1058,7 @@ class ModalPrompter {
|
|||
PromptUtils.setAuthInfo(authInfo, userParam.value, passParam.value);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
},
|
||||
|
||||
asyncPromptAuth(
|
||||
channel,
|
||||
|
@ -1055,33 +1076,20 @@ class ModalPrompter {
|
|||
//
|
||||
// Bug 565582 will change this.
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
},
|
||||
|
||||
/* ---------- nsIWritablePropertyBag2 ---------- */
|
||||
// Legacy way to set modal type when prompting via nsIPrompt.
|
||||
// Please prompt via nsIPromptService. This will be removed in the future.
|
||||
setPropertyAsUint32(name, value) {
|
||||
if (name == "modalType") {
|
||||
this.modalType = value;
|
||||
|
||||
// Only a partial implementation, for one specific use case...
|
||||
|
||||
setPropertyAsBool(name, value) {
|
||||
if (name == "allowTabModal") {
|
||||
this.allowTabModal = value;
|
||||
} else {
|
||||
throw Cr.NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
ModalPrompter,
|
||||
"defaultModalType",
|
||||
"prompts.defaultModalType",
|
||||
Ci.nsIPrompt.MODAL_TYPE_WINDOW
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
ModalPrompter,
|
||||
"tabModalEnabled",
|
||||
"prompts.tab_modal.enabled",
|
||||
true
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
function AuthPromptAdapterFactory() {}
|
||||
AuthPromptAdapterFactory.prototype = {
|
||||
|
|
|
@ -27,52 +27,6 @@ function handlePromptWhenItAppears(action, isTabModal, isSelect) {
|
|||
}, 100);
|
||||
}
|
||||
|
||||
function checkTabModal(prompt, browser) {
|
||||
let doc = browser.ownerDocument;
|
||||
|
||||
let { bottom: toolboxBottom } = doc
|
||||
.getElementById("navigator-toolbox")
|
||||
.getBoundingClientRect();
|
||||
|
||||
let { mainContainer } = prompt.ui;
|
||||
|
||||
let { x, y } = mainContainer.getBoundingClientRect();
|
||||
ok(y > 0, "Container should have y > 0");
|
||||
// Inset by 1px since the corner point doesn't return the frame due to the
|
||||
// border-radius.
|
||||
is(
|
||||
doc.elementFromPoint(x + 1, y + 1).parentNode,
|
||||
mainContainer,
|
||||
"Check tabmodalprompt is visible"
|
||||
);
|
||||
|
||||
info("Click to the left of the dialog over the content area");
|
||||
isnot(
|
||||
doc.elementFromPoint(x - 10, y + 50),
|
||||
browser,
|
||||
"Check clicks on the content area don't go to the browser"
|
||||
);
|
||||
is(
|
||||
doc.elementFromPoint(x - 10, y + 50).parentNode,
|
||||
prompt.element,
|
||||
"Check clicks on the content area go to the prompt dialog background"
|
||||
);
|
||||
|
||||
if (prompt.args.modalType == Ci.nsIPrompt.MODAL_TYPE_TAB) {
|
||||
ok(
|
||||
y <= toolboxBottom - 5,
|
||||
"Dialog should overlap the toolbox by at least 5px"
|
||||
);
|
||||
} else {
|
||||
ok(y >= toolboxBottom, "Dialog must not overlap with toolbox.");
|
||||
}
|
||||
|
||||
ok(
|
||||
browser.hasAttribute("tabmodalPromptShowing"),
|
||||
"Check browser has @tabmodalPromptShowing"
|
||||
);
|
||||
}
|
||||
|
||||
function handlePrompt(action, isTabModal, isSelect) {
|
||||
let ui;
|
||||
|
||||
|
@ -86,7 +40,6 @@ function handlePrompt(action, isTabModal, isSelect) {
|
|||
}
|
||||
|
||||
ui = prompts[0].Dialog.ui;
|
||||
checkTabModal(prompts[0], gBrowser.selectedBrowser);
|
||||
} else {
|
||||
let doc = getDialogDoc();
|
||||
if (!doc) {
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -28,8 +28,11 @@ function waitForOnBeforeUnloadDialog(browser, callback) {
|
|||
SimpleTest.waitForCondition(
|
||||
() => Services.focus.activeWindow == browser.ownerGlobal,
|
||||
function() {
|
||||
let prompt = browser.tabModalPromptBox.listPrompts()[0];
|
||||
let { button0, button1 } = prompt.ui;
|
||||
let stack = browser.parentNode;
|
||||
let dialogs = stack.getElementsByTagNameNS(XUL_NS, "tabmodalprompt");
|
||||
let { button0, button1 } = browser.tabModalPromptBox.prompts.get(
|
||||
dialogs[0]
|
||||
).ui;
|
||||
callback(button0, button1);
|
||||
},
|
||||
"Waited too long for window with dialog to focus"
|
||||
|
|
|
@ -11,8 +11,6 @@ interface nsIAuthInformation;
|
|||
interface nsICancelable;
|
||||
interface nsIChannel;
|
||||
|
||||
webidl BrowsingContext;
|
||||
|
||||
/**
|
||||
* This is the interface to the embeddable prompt service; the service that
|
||||
* implements nsIPrompt. Its interface is designed to be just nsIPrompt, each
|
||||
|
@ -59,10 +57,6 @@ interface nsIPromptService : nsISupports
|
|||
void alert(in mozIDOMWindowProxy aParent,
|
||||
in wstring aDialogTitle,
|
||||
in wstring aText);
|
||||
void alertBC(in BrowsingContext aBrowsingContext,
|
||||
in unsigned long modalType,
|
||||
in wstring aDialogTitle,
|
||||
in wstring aText);
|
||||
|
||||
/**
|
||||
* Puts up an alert dialog with an OK button and a labeled checkbox.
|
||||
|
@ -84,12 +78,6 @@ interface nsIPromptService : nsISupports
|
|||
in wstring aText,
|
||||
in wstring aCheckMsg,
|
||||
inout boolean aCheckState);
|
||||
void alertCheckBC(in BrowsingContext aBrowsingContext,
|
||||
in unsigned long modalType,
|
||||
in wstring aDialogTitle,
|
||||
in wstring aText,
|
||||
in wstring aCheckMsg,
|
||||
inout boolean aCheckState);
|
||||
|
||||
/**
|
||||
* Puts up a dialog with OK and Cancel buttons.
|
||||
|
@ -106,10 +94,6 @@ interface nsIPromptService : nsISupports
|
|||
boolean confirm(in mozIDOMWindowProxy aParent,
|
||||
in wstring aDialogTitle,
|
||||
in wstring aText);
|
||||
boolean confirmBC(in BrowsingContext aBrowsingContext,
|
||||
in unsigned long modalType,
|
||||
in wstring aDialogTitle,
|
||||
in wstring aText);
|
||||
|
||||
/**
|
||||
* Puts up a dialog with OK and Cancel buttons and a labeled checkbox.
|
||||
|
@ -133,12 +117,6 @@ interface nsIPromptService : nsISupports
|
|||
in wstring aText,
|
||||
in wstring aCheckMsg,
|
||||
inout boolean aCheckState);
|
||||
boolean confirmCheckBC(in BrowsingContext aBrowsingContext,
|
||||
in unsigned long modalType,
|
||||
in wstring aDialogTitle,
|
||||
in wstring aText,
|
||||
in wstring aCheckMsg,
|
||||
inout boolean aCheckState);
|
||||
|
||||
/**
|
||||
* Button Flags
|
||||
|
@ -195,10 +173,6 @@ interface nsIPromptService : nsISupports
|
|||
const unsigned long STD_YES_NO_BUTTONS = (BUTTON_TITLE_YES * BUTTON_POS_0) +
|
||||
(BUTTON_TITLE_NO * BUTTON_POS_1);
|
||||
|
||||
// Indicates whether a prompt should be shown in-content, on tab level or as a separate window
|
||||
const unsigned long MODAL_TYPE_CONTENT = 1;
|
||||
const unsigned long MODAL_TYPE_TAB = 2;
|
||||
const unsigned long MODAL_TYPE_WINDOW = 3;
|
||||
|
||||
/**
|
||||
* Puts up a dialog with up to 3 buttons and an optional, labeled checkbox.
|
||||
|
@ -252,16 +226,6 @@ interface nsIPromptService : nsISupports
|
|||
in wstring aButton2Title,
|
||||
in wstring aCheckMsg,
|
||||
inout boolean aCheckState);
|
||||
int32_t confirmExBC(in BrowsingContext aBrowsingContext,
|
||||
in unsigned long modalType,
|
||||
in wstring aDialogTitle,
|
||||
in wstring aText,
|
||||
in unsigned long aButtonFlags,
|
||||
in wstring aButton0Title,
|
||||
in wstring aButton1Title,
|
||||
in wstring aButton2Title,
|
||||
in wstring aCheckMsg,
|
||||
inout boolean aCheckState);
|
||||
|
||||
/**
|
||||
* Puts up a dialog with an edit field and an optional, labeled checkbox.
|
||||
|
@ -291,13 +255,6 @@ interface nsIPromptService : nsISupports
|
|||
inout wstring aValue,
|
||||
in wstring aCheckMsg,
|
||||
inout boolean aCheckState);
|
||||
boolean promptBC(in BrowsingContext aBrowsingContext,
|
||||
in unsigned long modalType,
|
||||
in wstring aDialogTitle,
|
||||
in wstring aText,
|
||||
inout wstring aValue,
|
||||
in wstring aCheckMsg,
|
||||
inout boolean aCheckState);
|
||||
|
||||
/**
|
||||
* Puts up a dialog with an edit field, a password field, and an optional,
|
||||
|
@ -334,14 +291,6 @@ interface nsIPromptService : nsISupports
|
|||
inout wstring aPassword,
|
||||
in wstring aCheckMsg,
|
||||
inout boolean aCheckState);
|
||||
boolean promptUsernameAndPasswordBC(in BrowsingContext aBrowsingContext,
|
||||
in unsigned long modalType,
|
||||
in wstring aDialogTitle,
|
||||
in wstring aText,
|
||||
inout wstring aUsername,
|
||||
inout wstring aPassword,
|
||||
in wstring aCheckMsg,
|
||||
inout boolean aCheckState);
|
||||
|
||||
/**
|
||||
* Puts up a dialog with a password field and an optional, labeled checkbox.
|
||||
|
@ -371,13 +320,6 @@ interface nsIPromptService : nsISupports
|
|||
inout wstring aPassword,
|
||||
in wstring aCheckMsg,
|
||||
inout boolean aCheckState);
|
||||
boolean promptPasswordBC(in BrowsingContext aBrowsingContext,
|
||||
in unsigned long modalType,
|
||||
in wstring aDialogTitle,
|
||||
in wstring aText,
|
||||
inout wstring aPassword,
|
||||
in wstring aCheckMsg,
|
||||
inout boolean aCheckState);
|
||||
|
||||
/**
|
||||
* Puts up a dialog box which has a list box of strings from which the user
|
||||
|
@ -402,12 +344,6 @@ interface nsIPromptService : nsISupports
|
|||
in wstring aText,
|
||||
in Array<AString> aSelectList,
|
||||
out long aOutSelection);
|
||||
boolean selectBC(in BrowsingContext aBrowsingContext,
|
||||
in unsigned long modalType,
|
||||
in wstring aDialogTitle,
|
||||
in wstring aText,
|
||||
in Array<AString> aSelectList,
|
||||
out long aOutSelection);
|
||||
|
||||
// NOTE: These functions differ from their nsIAuthPrompt counterparts by
|
||||
// having additional checkbox parameters
|
||||
|
@ -423,13 +359,6 @@ interface nsIPromptService : nsISupports
|
|||
in nsIAuthInformation authInfo,
|
||||
in wstring checkboxLabel,
|
||||
inout boolean checkValue);
|
||||
boolean promptAuthBC(in BrowsingContext aBrowsingContext,
|
||||
in unsigned long modalType,
|
||||
in nsIChannel aChannel,
|
||||
in uint32_t level,
|
||||
in nsIAuthInformation authInfo,
|
||||
in wstring checkboxLabel,
|
||||
inout boolean checkValue);
|
||||
|
||||
nsICancelable asyncPromptAuth(in mozIDOMWindowProxy aParent,
|
||||
in nsIChannel aChannel,
|
||||
|
@ -439,13 +368,4 @@ interface nsIPromptService : nsISupports
|
|||
in nsIAuthInformation authInfo,
|
||||
in wstring checkboxLabel,
|
||||
inout boolean checkValue);
|
||||
nsICancelable asyncPromptAuthBC(in BrowsingContext aBrowsingContext,
|
||||
in unsigned long modalType,
|
||||
in nsIChannel aChannel,
|
||||
in nsIAuthPromptCallback aCallback,
|
||||
in nsISupports aContext,
|
||||
in uint32_t level,
|
||||
in nsIAuthInformation authInfo,
|
||||
in wstring checkboxLabel,
|
||||
inout boolean checkValue);
|
||||
};
|
||||
|
|
|
@ -2017,25 +2017,7 @@
|
|||
}
|
||||
|
||||
leaveModalState() {
|
||||
this.sendMessageToActor(
|
||||
"LeaveModalState",
|
||||
{ forceLeave: true },
|
||||
"BrowserElement",
|
||||
"roots"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be called for a window with or without modal state.
|
||||
* If the window is not in modal state, this is a no-op.
|
||||
*/
|
||||
maybeLeaveModalState() {
|
||||
this.sendMessageToActor(
|
||||
"LeaveModalState",
|
||||
{ forceLeave: false },
|
||||
"BrowserElement",
|
||||
"roots"
|
||||
);
|
||||
this.sendMessageToActor("LeaveModalState", {}, "BrowserElement", "roots");
|
||||
}
|
||||
|
||||
getDevicePermissionOrigins(key) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче