зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1705440 - remove old modal prompt implementation, r=mconley,webdriver-reviewers,extension-reviewers,desktop-theme-reviewers,tabbrowser-reviewers,whimboo,rpl
Differential Revision: https://phabricator.services.mozilla.com/D204759
This commit is contained in:
Родитель
5d1af6669c
Коммит
a3568826b0
|
@ -18,6 +18,4 @@ skip-if = [
|
|||
|
||||
["test_tree.xhtml"]
|
||||
|
||||
["test_ui_modalprompt.html"]
|
||||
|
||||
["test_update.html"]
|
||||
|
|
|
@ -1,111 +0,0 @@
|
|||
<html>
|
||||
|
||||
<head>
|
||||
<title>Modal prompts</title>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
|
||||
<script type="application/javascript"
|
||||
src="../common.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../relations.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../role.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../events.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../browser.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
SpecialPowers.pushPrefEnv({
|
||||
set: [["prompts.contentPromptSubDialog", false]],
|
||||
});
|
||||
function showAlert() {
|
||||
this.eventSeq = [
|
||||
{
|
||||
type: EVENT_SHOW,
|
||||
match(aEvent) {
|
||||
return aEvent.accessible.role == ROLE_DIALOG;
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
this.invoke = function showAlert_invoke() {
|
||||
window.setTimeout(
|
||||
function() {
|
||||
currentTabDocument().defaultView.alert("hello");
|
||||
}, 0);
|
||||
};
|
||||
|
||||
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);
|
||||
testRelation(dialog, RELATION_DESCRIBED_BY, info);
|
||||
};
|
||||
|
||||
this.getID = function showAlert_getID() {
|
||||
return "show alert";
|
||||
};
|
||||
}
|
||||
|
||||
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() {
|
||||
closeBrowserWindow();
|
||||
};
|
||||
gQueue.invoke(); // will call SimpleTest.finish()
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
openBrowserWindow(doTests);
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body id="body">
|
||||
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=661293"
|
||||
title="The tabmodalprompt dialog's prompt label doesn't get the text properly associated for accessibility">
|
||||
Mozilla Bug 661293
|
||||
</a>
|
||||
<br>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -9,21 +9,6 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
|||
PromptUtils: "resource://gre/modules/PromptUtils.sys.mjs",
|
||||
BrowserUtils: "resource://gre/modules/BrowserUtils.sys.mjs",
|
||||
});
|
||||
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
lazy,
|
||||
"tabChromePromptSubDialog",
|
||||
"prompts.tabChromePromptSubDialog",
|
||||
false
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
lazy,
|
||||
"contentPromptSubDialog",
|
||||
"prompts.contentPromptSubDialog",
|
||||
false
|
||||
);
|
||||
|
||||
ChromeUtils.defineLazyGetter(lazy, "gTabBrowserLocalization", function () {
|
||||
return new Localization(["browser/tabbrowser.ftl"], true);
|
||||
|
@ -109,116 +94,18 @@ export class PromptParent extends JSWindowActorParent {
|
|||
}
|
||||
|
||||
receiveMessage(message) {
|
||||
let args = message.data;
|
||||
let id = args._remoteId;
|
||||
|
||||
switch (message.name) {
|
||||
case "Prompt:Open":
|
||||
if (!this.windowContext.isActiveInTab) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (
|
||||
(args.modalType === Ci.nsIPrompt.MODAL_TYPE_CONTENT &&
|
||||
!lazy.contentPromptSubDialog) ||
|
||||
(args.modalType === Ci.nsIPrompt.MODAL_TYPE_TAB &&
|
||||
!lazy.tabChromePromptSubDialog)
|
||||
) {
|
||||
return this.openContentPrompt(args, id);
|
||||
}
|
||||
return this.openPromptWithTabDialogBox(args);
|
||||
return this.openPromptWithTabDialogBox(message.data);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a TabModalPrompt for a BrowsingContext, and puts the associated browser
|
||||
* in the modal state until the TabModalPrompt is closed.
|
||||
*
|
||||
* @param {Object} args
|
||||
* The arguments passed up from the BrowsingContext to be passed directly
|
||||
* to the TabModalPrompt.
|
||||
* @param {string} id
|
||||
* 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.
|
||||
*/
|
||||
openContentPrompt(args, id) {
|
||||
let browser = this.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;
|
||||
let needRemove = false;
|
||||
|
||||
// If the page which called the prompt is different from the the top context
|
||||
// where we show the prompt, ask the prompt implementation to display the origin.
|
||||
// For example, this can happen if a cross origin subframe shows a prompt.
|
||||
args.showCallerOrigin =
|
||||
args.promptPrincipal &&
|
||||
!browser.contentPrincipal.equals(args.promptPrincipal);
|
||||
|
||||
let onPromptClose = () => {
|
||||
// NOTE: this code is totally bust now, as `gBrowserDialogs` won't produce
|
||||
// the right objects for it. It's also unused though, and removed in the
|
||||
// next commit.
|
||||
let promptData = gBrowserDialogs.get(this.browsingContext);
|
||||
if (!promptData || !promptData.has(id)) {
|
||||
throw new Error(
|
||||
"Failed to close a prompt since it wasn't registered for some reason."
|
||||
);
|
||||
}
|
||||
|
||||
let { resolver, tabModalPrompt } = promptData.get(id);
|
||||
// It's possible that we removed the prompt during the
|
||||
// appendPrompt call below. In that case, newPrompt will be
|
||||
// undefined. We set the needRemove flag to remember to remove
|
||||
// it right after we've finished adding it.
|
||||
if (tabModalPrompt) {
|
||||
tabPrompt.removePrompt(tabModalPrompt);
|
||||
} else {
|
||||
needRemove = true;
|
||||
}
|
||||
|
||||
lazy.PromptUtils.fireDialogEvent(
|
||||
window,
|
||||
"DOMModalDialogClosed",
|
||||
browser,
|
||||
this.getClosingEventDetail(args)
|
||||
);
|
||||
resolver(args);
|
||||
browser.maybeLeaveModalState();
|
||||
};
|
||||
|
||||
try {
|
||||
browser.enterModalState();
|
||||
lazy.PromptUtils.fireDialogEvent(
|
||||
window,
|
||||
"DOMWillOpenModalDialog",
|
||||
browser,
|
||||
this.getOpenEventDetail(args)
|
||||
);
|
||||
|
||||
args.promptActive = true;
|
||||
|
||||
newPrompt = tabPrompt.appendPrompt(args, onPromptClose);
|
||||
if (needRemove) {
|
||||
tabPrompt.removePrompt(newPrompt);
|
||||
}
|
||||
} catch (ex) {
|
||||
console.error(ex);
|
||||
onPromptClose(true);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens either a window prompt or TabDialogBox at the content or tab level
|
||||
* for a BrowsingContext, and puts the associated browser in the modal state
|
||||
|
|
|
@ -1680,15 +1680,6 @@ pref("browser.topsites.contile.sov.enabled", true);
|
|||
pref("browser.partnerlink.attributionURL", "https://topsites.services.mozilla.com/cid/");
|
||||
pref("browser.partnerlink.campaign.topsites", "amzn_2020_a1");
|
||||
|
||||
// Whether to show tab level system prompts opened via nsIPrompt(Service) as
|
||||
// SubDialogs in the TabDialogBox (true) or as TabModalPrompt in the
|
||||
// TabModalPromptBox (false).
|
||||
pref("prompts.tabChromePromptSubDialog", true);
|
||||
|
||||
// Whether to show the dialogs opened at the content level, such as
|
||||
// alert() or prompt(), using a SubDialogManager in the TabDialogBox.
|
||||
pref("prompts.contentPromptSubDialog", true);
|
||||
|
||||
// Whether to show window-modal dialogs opened for browser windows
|
||||
// in a SubDialog inside their parent, instead of an OS level window.
|
||||
pref("prompts.windowPromptSubDialog", true);
|
||||
|
|
|
@ -916,7 +916,7 @@ menupopup[emptyplacesresult="true"] > .hide-if-empty-places-result {
|
|||
position: absolute;
|
||||
}
|
||||
|
||||
browser[tabmodalPromptShowing], browser[tabDialogShowing] {
|
||||
browser[tabDialogShowing] {
|
||||
-moz-user-focus: none !important;
|
||||
}
|
||||
|
||||
|
|
|
@ -79,7 +79,6 @@ ChromeUtils.defineESModuleGetters(this, {
|
|||
SubDialog: "resource://gre/modules/SubDialog.sys.mjs",
|
||||
SubDialogManager: "resource://gre/modules/SubDialog.sys.mjs",
|
||||
TabCrashHandler: "resource:///modules/ContentCrashHandlers.sys.mjs",
|
||||
TabModalPrompt: "chrome://global/content/tabprompts.sys.mjs",
|
||||
TabsSetupFlowManager:
|
||||
"resource:///modules/firefox-view-tabs-setup-manager.sys.mjs",
|
||||
TelemetryEnvironment: "resource://gre/modules/TelemetryEnvironment.sys.mjs",
|
||||
|
@ -691,7 +690,6 @@ function shouldSuppressPopupNotifications() {
|
|||
// don't cover up the prompt.
|
||||
return (
|
||||
window.windowState == window.STATE_MINIMIZED ||
|
||||
gBrowser?.selectedBrowser.hasAttribute("tabmodalChromePromptShowing") ||
|
||||
gBrowser?.selectedBrowser.hasAttribute("tabDialogShowing") ||
|
||||
gDialogBox?.isOpen
|
||||
);
|
||||
|
@ -9440,221 +9438,6 @@ TabDialogBox.prototype.QueryInterface = ChromeUtils.generateQI([
|
|||
"nsISupportsWeakReference",
|
||||
]);
|
||||
|
||||
function TabModalPromptBox(browser) {
|
||||
this._weakBrowserRef = Cu.getWeakReference(browser);
|
||||
/*
|
||||
* These WeakMaps 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();
|
||||
}
|
||||
|
||||
TabModalPromptBox.prototype = {
|
||||
_promptCloseCallback(
|
||||
onCloseCallback,
|
||||
principalToAllowFocusFor,
|
||||
allowFocusCheckbox,
|
||||
...args
|
||||
) {
|
||||
if (
|
||||
principalToAllowFocusFor &&
|
||||
allowFocusCheckbox &&
|
||||
allowFocusCheckbox.checked
|
||||
) {
|
||||
Services.perms.addFromPrincipal(
|
||||
principalToAllowFocusFor,
|
||||
"focus-tab-by-prompt",
|
||||
Services.perms.ALLOW_ACTION
|
||||
);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
browser.parentNode.insertBefore(
|
||||
newPrompt.element,
|
||||
browser.nextElementSibling
|
||||
);
|
||||
browser.setAttribute("tabmodalPromptShowing", true);
|
||||
|
||||
// Indicate if a tab modal chrome prompt is being shown so that
|
||||
// PopupNotifications are suppressed.
|
||||
if (
|
||||
args.modalType === Ci.nsIPrompt.MODAL_TYPE_TAB &&
|
||||
!browser.hasAttribute("tabmodalChromePromptShowing")
|
||||
) {
|
||||
browser.setAttribute("tabmodalChromePromptShowing", true);
|
||||
// Notify popup notifications of the UI change so they hide their
|
||||
// notification panels.
|
||||
UpdatePopupNotificationsVisibility();
|
||||
}
|
||||
|
||||
let prompts = this.listPrompts(args.modalType);
|
||||
if (prompts.length > 1) {
|
||||
// Let's hide ourself behind the current prompt.
|
||||
newPrompt.element.hidden = true;
|
||||
}
|
||||
|
||||
let principalToAllowFocusFor = this._allowTabFocusByPromptPrincipal;
|
||||
delete this._allowTabFocusByPromptPrincipal;
|
||||
|
||||
let allowFocusCheckbox; // Define outside the if block so we can bind it into the callback.
|
||||
let hostForAllowFocusCheckbox = "";
|
||||
try {
|
||||
hostForAllowFocusCheckbox = principalToAllowFocusFor.URI.host;
|
||||
} catch (ex) {
|
||||
/* Ignore exceptions for host-less URIs */
|
||||
}
|
||||
if (hostForAllowFocusCheckbox) {
|
||||
let allowFocusRow = document.createElement("div");
|
||||
|
||||
let spacer = document.createElement("div");
|
||||
allowFocusRow.appendChild(spacer);
|
||||
|
||||
allowFocusCheckbox = document.createXULElement("checkbox");
|
||||
document.l10n.setAttributes(
|
||||
allowFocusCheckbox,
|
||||
"tabbrowser-allow-dialogs-to-get-focus",
|
||||
{ domain: hostForAllowFocusCheckbox }
|
||||
);
|
||||
allowFocusRow.appendChild(allowFocusCheckbox);
|
||||
|
||||
newPrompt.ui.rows.append(allowFocusRow);
|
||||
}
|
||||
|
||||
let tab = gBrowser.getTabForBrowser(browser);
|
||||
let closeCB = this._promptCloseCallback.bind(
|
||||
null,
|
||||
onCloseCallback,
|
||||
principalToAllowFocusFor,
|
||||
allowFocusCheckbox
|
||||
);
|
||||
newPrompt.init(args, tab, closeCB);
|
||||
return newPrompt;
|
||||
},
|
||||
|
||||
removePrompt(aPrompt) {
|
||||
let { modalType } = aPrompt.args;
|
||||
if (modalType === Ci.nsIPrompt.MODAL_TYPE_TAB) {
|
||||
this._tabPrompts.delete(aPrompt.element);
|
||||
} else {
|
||||
this._contentPrompts.delete(aPrompt.element);
|
||||
}
|
||||
|
||||
let browser = this.browser;
|
||||
aPrompt.element.remove();
|
||||
|
||||
let prompts = this.listPrompts(modalType);
|
||||
if (prompts.length) {
|
||||
let prompt = prompts[prompts.length - 1];
|
||||
prompt.element.hidden = false;
|
||||
// Because we were hidden before, this won't have been possible, so do it now:
|
||||
prompt.Dialog.setDefaultFocus();
|
||||
} else if (modalType === Ci.nsIPrompt.MODAL_TYPE_TAB) {
|
||||
// If we remove the last tab chrome prompt, also remove the browser
|
||||
// attribute.
|
||||
browser.removeAttribute("tabmodalChromePromptShowing");
|
||||
// Notify popup notifications of the UI change so they show notification
|
||||
// panels again.
|
||||
UpdatePopupNotificationsVisibility();
|
||||
}
|
||||
// Check if all prompts are closed
|
||||
if (!this._hasPrompts()) {
|
||||
browser.removeAttribute("tabmodalPromptShowing");
|
||||
browser.focus();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if the prompt box has prompt elements.
|
||||
* @returns {Boolean} - true if there are prompt elements.
|
||||
*/
|
||||
_hasPrompts() {
|
||||
return !!this._getPromptElements().length;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get list of current prompt elements.
|
||||
* @param {Number} [aModalType] - Optionally filter by
|
||||
* Ci.nsIPrompt.MODAL_TYPE_.
|
||||
* @returns {NodeList} - A list of tabmodalprompt elements.
|
||||
*/
|
||||
_getPromptElements(aModalType = null) {
|
||||
let selector = "tabmodalprompt";
|
||||
|
||||
if (aModalType != null) {
|
||||
if (aModalType === Ci.nsIPrompt.MODAL_TYPE_TAB) {
|
||||
selector += ".tab-prompt";
|
||||
} else {
|
||||
selector += ".content-prompt";
|
||||
}
|
||||
}
|
||||
return this.browser.parentNode.querySelectorAll(selector);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get a list of all TabModalPrompt objects associated with the prompt box.
|
||||
* @param {Number} [aModalType] - Optionally filter by
|
||||
* Ci.nsIPrompt.MODAL_TYPE_.
|
||||
* @returns {TabModalPrompt[]} - An array of TabModalPrompt objects.
|
||||
*/
|
||||
listPrompts(aModalType = null) {
|
||||
// Get the nodelist, then return the TabModalPrompt instances as an array
|
||||
let promptMap;
|
||||
|
||||
if (aModalType) {
|
||||
if (aModalType === Ci.nsIPrompt.MODAL_TYPE_TAB) {
|
||||
promptMap = this._tabPrompts;
|
||||
} else {
|
||||
promptMap = this._contentPrompts;
|
||||
}
|
||||
}
|
||||
|
||||
let elements = this._getPromptElements(aModalType);
|
||||
|
||||
if (promptMap) {
|
||||
return [...elements].map(el => promptMap.get(el));
|
||||
}
|
||||
return [...elements].map(
|
||||
el => this._contentPrompts.get(el) || this._tabPrompts.get(el)
|
||||
);
|
||||
},
|
||||
|
||||
onNextPromptShowAllowFocusCheckboxFor(principal) {
|
||||
this._allowTabFocusByPromptPrincipal = principal;
|
||||
},
|
||||
|
||||
get browser() {
|
||||
let browser = this._weakBrowserRef.get();
|
||||
if (!browser) {
|
||||
throw new Error("Stale promptbox! The associated browser is gone.");
|
||||
}
|
||||
return browser;
|
||||
},
|
||||
};
|
||||
|
||||
// Handle window-modal prompts that we want to display with the same style as
|
||||
// tab-modal prompts.
|
||||
var gDialogBox = {
|
||||
|
|
|
@ -131,7 +131,6 @@
|
|||
"PanicButtonNotifier",
|
||||
"SafeBrowsingNotificationBox",
|
||||
"TabDialogBox",
|
||||
"TabModalPromptBox",
|
||||
"gDialogBox",
|
||||
"ConfirmationHint",
|
||||
"FirefoxViewHandler",
|
||||
|
@ -196,7 +195,6 @@
|
|||
"SubDialog",
|
||||
"SubDialogManager",
|
||||
"TabCrashHandler",
|
||||
"TabModalPrompt",
|
||||
"TabsSetupFlowManager",
|
||||
"TelemetryEnvironment",
|
||||
"TranslationsParent",
|
||||
|
|
|
@ -38,9 +38,6 @@
|
|||
both "content" and "skin" packages, which bug 1385444 will unify later. -->
|
||||
<link rel="stylesheet" href="chrome://global/skin/global.css" />
|
||||
|
||||
<link rel="stylesheet" href="chrome://global/content/tabprompts.css" />
|
||||
<link rel="stylesheet" href="chrome://global/skin/tabprompts.css" />
|
||||
|
||||
<link rel="stylesheet" href="chrome://browser/content/browser.css" />
|
||||
<link rel="stylesheet" href="chrome://browser/content/tabbrowser.css" />
|
||||
<link
|
||||
|
|
|
@ -893,14 +893,6 @@
|
|||
: "";
|
||||
},
|
||||
|
||||
getTabModalPromptBox(aBrowser) {
|
||||
let browser = aBrowser || this.selectedBrowser;
|
||||
if (!browser.tabModalPromptBox) {
|
||||
browser.tabModalPromptBox = new TabModalPromptBox(browser);
|
||||
}
|
||||
return browser.tabModalPromptBox;
|
||||
},
|
||||
|
||||
getTabDialogBox(aBrowser) {
|
||||
if (!aBrowser) {
|
||||
throw new Error("aBrowser is required");
|
||||
|
@ -1320,31 +1312,6 @@
|
|||
this.addToMultiSelectedTabs(oldTab);
|
||||
}
|
||||
|
||||
if (oldBrowser != newBrowser && oldBrowser.getInPermitUnload) {
|
||||
oldBrowser.getInPermitUnload(inPermitUnload => {
|
||||
if (!inPermitUnload) {
|
||||
return;
|
||||
}
|
||||
// Since the user is switching away from a tab that has
|
||||
// a beforeunload prompt active, we remove the prompt.
|
||||
// This prevents confusing user flows like the following:
|
||||
// 1. User attempts to close Firefox
|
||||
// 2. User switches tabs (ingoring a beforeunload prompt)
|
||||
// 3. User returns to tab, presses "Leave page"
|
||||
let promptBox = this.getTabModalPromptBox(oldBrowser);
|
||||
let prompts = promptBox.listPrompts();
|
||||
// There might not be any prompts here if the tab was closed
|
||||
// while in an onbeforeunload prompt, which will have
|
||||
// destroyed aforementioned prompt already, so check there's
|
||||
// something to remove, first:
|
||||
if (prompts.length) {
|
||||
// NB: This code assumes that the beforeunload prompt
|
||||
// is the top-most prompt on the tab.
|
||||
prompts[prompts.length - 1].abortPrompt();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!gMultiProcessBrowser) {
|
||||
this._adjustFocusBeforeTabSwitch(oldTab, newTab);
|
||||
this._adjustFocusAfterTabSwitch(newTab);
|
||||
|
@ -1439,19 +1406,6 @@
|
|||
newBrowser.tabDialogBox.focus();
|
||||
return;
|
||||
}
|
||||
if (newBrowser.hasAttribute("tabmodalPromptShowing")) {
|
||||
// If there's a tabmodal prompt showing, focus it.
|
||||
let prompts = newBrowser.tabModalPromptBox.listPrompts();
|
||||
let prompt = prompts[prompts.length - 1];
|
||||
// @tabmodalPromptShowing is also set for other tab modal prompts
|
||||
// (e.g. the Payment Request dialog) so there may not be a <tabmodalprompt>.
|
||||
// Bug 1492814 will implement this for the Payment Request dialog.
|
||||
if (prompt) {
|
||||
prompt.Dialog.setDefaultFocus();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Focus the location bar if it was previously focused for that tab.
|
||||
// In full screen mode, only bother making the location bar visible
|
||||
// if the tab is a blank one.
|
||||
|
@ -6103,12 +6057,7 @@
|
|||
);
|
||||
if (permission != Services.perms.ALLOW_ACTION) {
|
||||
// Tell the prompt box we want to show the user a checkbox:
|
||||
let tabPrompt = Services.prefs.getBoolPref(
|
||||
"prompts.contentPromptSubDialog"
|
||||
)
|
||||
? this.getTabDialogBox(tabForEvent.linkedBrowser)
|
||||
: this.getTabModalPromptBox(tabForEvent.linkedBrowser);
|
||||
|
||||
let tabPrompt = this.getTabDialogBox(tabForEvent.linkedBrowser);
|
||||
tabPrompt.onNextPromptShowAllowFocusCheckboxFor(
|
||||
promptPrincipal
|
||||
);
|
||||
|
|
|
@ -125,22 +125,12 @@ function getBrowser(panel) {
|
|||
return readyPromise.then(initBrowser);
|
||||
}
|
||||
|
||||
// Stub tabbrowser implementation for use by the tab-modal alert code.
|
||||
// Stub tabbrowser implementation to make sure that links from inside
|
||||
// extension sidebar panels open in new tabs, see bug 1488055.
|
||||
var gBrowser = {
|
||||
get selectedBrowser() {
|
||||
return document.getElementById("webext-panels-browser");
|
||||
},
|
||||
|
||||
getTabForBrowser() {
|
||||
return null;
|
||||
},
|
||||
|
||||
getTabModalPromptBox(browser) {
|
||||
if (!browser.tabModalPromptBox) {
|
||||
browser.tabModalPromptBox = new TabModalPromptBox(browser);
|
||||
}
|
||||
return browser.tabModalPromptBox;
|
||||
},
|
||||
};
|
||||
|
||||
function updatePosition() {
|
||||
|
|
|
@ -157,16 +157,10 @@ function promiseAlertDialogObserved() {
|
|||
async function observer(subject) {
|
||||
info("alert dialog observed as expected");
|
||||
Services.obs.removeObserver(observer, "common-dialog-loaded");
|
||||
Services.obs.removeObserver(observer, "tabmodal-dialog-loaded");
|
||||
|
||||
if (subject.Dialog) {
|
||||
subject.Dialog.ui.button0.click();
|
||||
} else {
|
||||
subject.querySelector(".tabmodalprompt-button0").click();
|
||||
}
|
||||
subject.Dialog.ui.button0.click();
|
||||
resolve();
|
||||
}
|
||||
Services.obs.addObserver(observer, "common-dialog-loaded");
|
||||
Services.obs.addObserver(observer, "tabmodal-dialog-loaded");
|
||||
});
|
||||
}
|
||||
|
|
|
@ -8,12 +8,6 @@ const kTestPage = "https://example.org/browser/dom/html/test/bug436200.html";
|
|||
async function run_test(shouldShowPrompt, msg) {
|
||||
let promptShown = false;
|
||||
|
||||
function tabModalObserver(subject) {
|
||||
promptShown = true;
|
||||
subject.querySelector(".tabmodalprompt-button0").click();
|
||||
}
|
||||
Services.obs.addObserver(tabModalObserver, "tabmodal-dialog-loaded");
|
||||
|
||||
function commonDialogObserver(subject) {
|
||||
let dialog = subject.Dialog;
|
||||
promptShown = true;
|
||||
|
@ -27,7 +21,6 @@ async function run_test(shouldShowPrompt, msg) {
|
|||
let form = content.document.getElementById("test_form");
|
||||
form.submit();
|
||||
});
|
||||
Services.obs.removeObserver(tabModalObserver, "tabmodal-dialog-loaded");
|
||||
Services.obs.removeObserver(commonDialogObserver, "common-dialog-loaded");
|
||||
|
||||
is(promptShown, shouldShowPrompt, msg);
|
||||
|
|
|
@ -31,17 +31,9 @@ function runTest() {
|
|||
var os = Services.obs;
|
||||
|
||||
os.addObserver(onPromptLoad, "common-dialog-loaded");
|
||||
os.addObserver(onPromptLoad, "tabmodal-dialog-loaded");
|
||||
|
||||
function onPromptLoad(subject) {
|
||||
let ui = subject.Dialog ? subject.Dialog.ui : undefined;
|
||||
if (!ui) {
|
||||
// subject is an tab prompt, find the elements ourselves
|
||||
ui = {
|
||||
loginTextbox: subject.querySelector(".tabmodalprompt-loginTextbox"),
|
||||
button0: subject.querySelector(".tabmodalprompt-button0"),
|
||||
};
|
||||
}
|
||||
let ui = subject.Dialog.ui;
|
||||
sendAsyncMessage("ok", [true, "onPromptLoad is called"]);
|
||||
gPromptInput = ui.loginTextbox;
|
||||
gPromptInput.addEventListener("focus", onPromptFocus);
|
||||
|
@ -77,7 +69,6 @@ function runTest() {
|
|||
}
|
||||
|
||||
addMessageListener("destroy", function() {
|
||||
os.removeObserver(onPromptLoad, "tabmodal-dialog-loaded");
|
||||
os.removeObserver(onPromptLoad, "common-dialog-loaded");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -144,23 +144,6 @@ browser.Context = class {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the current tabmodal UI object. According to the browser
|
||||
* associated with the currently selected tab.
|
||||
*/
|
||||
getTabModal() {
|
||||
let br = this.contentBrowser;
|
||||
if (!br.hasAttribute("tabmodalPromptShowing")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// The modal is a direct sibling of the browser element.
|
||||
// See tabbrowser.xml's getTabModalPromptBox.
|
||||
let modalElements = br.parentNode.getElementsByTagName("tabmodalprompt");
|
||||
|
||||
return br.tabModalPromptBox.getPrompt(modalElements[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the current window.
|
||||
*
|
||||
|
|
|
@ -77,18 +77,6 @@ modal.findPrompt = function (context) {
|
|||
return new modal.Dialog(() => context, dialogs[0].frameContentWindow);
|
||||
}
|
||||
}
|
||||
|
||||
// If no modal dialog has been found yet, check for old non SubDialog based
|
||||
// content modal dialogs. Even with those deprecated in Firefox 89 we should
|
||||
// keep supporting applications that don't have them implemented yet.
|
||||
if (contentBrowser?.tabModalPromptBox) {
|
||||
const prompts = contentBrowser.tabModalPromptBox.listPrompts();
|
||||
if (prompts.length) {
|
||||
lazy.logger.trace("Found open old-style content prompt");
|
||||
return new modal.Dialog(() => context, null);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
|
@ -136,11 +124,7 @@ modal.Dialog = class {
|
|||
}
|
||||
|
||||
get tabModal() {
|
||||
let win = this.window;
|
||||
if (win) {
|
||||
return win.Dialog;
|
||||
}
|
||||
return this.curBrowser_.getTabModal();
|
||||
return this.window?.Dialog;
|
||||
}
|
||||
|
||||
get promptType() {
|
||||
|
|
|
@ -1,119 +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/. */
|
||||
|
||||
/* Tab Modal Prompt boxes */
|
||||
|
||||
.tabModalBackground {
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.tabModalBackground,
|
||||
tabmodalprompt {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
tabmodalprompt {
|
||||
--tabmodalprompt-padding: 20px;
|
||||
overflow: hidden;
|
||||
text-shadow: none; /* remove lightweight theme text-shadow */
|
||||
}
|
||||
|
||||
tabmodalprompt:not([hidden]) {
|
||||
display: grid;
|
||||
grid-template-rows: 1fr [dialog-start] auto [dialog-end] 2fr;
|
||||
justify-items: center;
|
||||
}
|
||||
|
||||
/*
|
||||
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;
|
||||
grid-template-rows: [dialog-start] auto [dialog-end] 1fr;
|
||||
}
|
||||
|
||||
tabmodalprompt.tab-prompt .tabmodalprompt-mainContainer {
|
||||
margin-top: -5px;
|
||||
}
|
||||
|
||||
.tabmodalprompt-mainContainer {
|
||||
min-width: 20em;
|
||||
min-height: 12em;
|
||||
max-width: calc(60% + calc(var(--tabmodalprompt-padding) * 2));
|
||||
-moz-user-focus: normal;
|
||||
grid-row: dialog;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.tabmodalprompt-topContainer {
|
||||
flex-grow: 1;
|
||||
padding: var(--tabmodalprompt-padding);
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
align-items: baseline;
|
||||
align-content: center; /* center content vertically */
|
||||
max-width: 100%;
|
||||
min-height: 0;
|
||||
max-height: 60vh;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.tabmodalprompt-topContainer > div:not(.tabmodalprompt-infoContainer, [hidden]) {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
.tabmodalprompt-infoContainer {
|
||||
grid-column: span 2;
|
||||
|
||||
display: block;
|
||||
margin-block: auto;
|
||||
max-width: 100%;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
justify-self: center; /* center text, but only when it fits in one line */
|
||||
}
|
||||
|
||||
/* When all elements in the first column are hidden, prevent the second column
|
||||
from becoming the first one because it won't have the right fraction */
|
||||
.tabmodalprompt-topContainer > div > *:nth-child(2) {
|
||||
grid-column: 2;
|
||||
}
|
||||
|
||||
.infoTitle {
|
||||
margin-bottom: 1em !important;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.infoBody {
|
||||
margin: 0 !important;
|
||||
-moz-user-focus: normal;
|
||||
user-select: text;
|
||||
cursor: text !important;
|
||||
white-space: pre-wrap;
|
||||
unicode-bidi: plaintext;
|
||||
outline: none; /* remove focus outline */
|
||||
overflow: auto;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
tabmodalprompt label[value=""] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tabmodalprompt-buttonContainer {
|
||||
display: flex;
|
||||
padding: 12px var(--tabmodalprompt-padding) 15px;
|
||||
}
|
||||
|
||||
.tabmodalprompt-buttonSpacer {
|
||||
flex-grow: 1;
|
||||
}
|
|
@ -1,298 +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/. */
|
||||
|
||||
import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
|
||||
|
||||
export var TabModalPrompt = class {
|
||||
constructor(win) {
|
||||
this.win = win;
|
||||
let newPrompt = (this.element =
|
||||
win.document.createElement("tabmodalprompt"));
|
||||
win.MozXULElement.insertFTLIfNeeded("toolkit/global/tabprompts.ftl");
|
||||
newPrompt.setAttribute("role", "dialog");
|
||||
let randomIdSuffix = Math.random().toString(32).substring(2);
|
||||
newPrompt.setAttribute("aria-describedby", `infoBody-${randomIdSuffix}`);
|
||||
newPrompt.appendChild(
|
||||
win.MozXULElement.parseXULToFragment(
|
||||
`
|
||||
<div class="tabmodalprompt-mainContainer" xmlns="http://www.w3.org/1999/xhtml" xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<div class="tabmodalprompt-topContainer">
|
||||
<div class="tabmodalprompt-infoContainer">
|
||||
<div class="tabmodalprompt-infoTitle infoTitle" hidden="hidden"/>
|
||||
<div class="tabmodalprompt-infoBody infoBody" id="infoBody-${randomIdSuffix}" tabindex="-1"/>
|
||||
</div>
|
||||
|
||||
<div class="tabmodalprompt-loginContainer" hidden="hidden">
|
||||
<xul:label class="tabmodalprompt-loginLabel" data-l10n-id="tabmodalprompt-username" control="loginTextbox-${randomIdSuffix}"/>
|
||||
<input class="tabmodalprompt-loginTextbox" id="loginTextbox-${randomIdSuffix}"/>
|
||||
</div>
|
||||
|
||||
<div class="tabmodalprompt-password1Container" hidden="hidden">
|
||||
<xul:label class="tabmodalprompt-password1Label" data-l10n-id="tabmodalprompt-password" control="password1Textbox-${randomIdSuffix}"/>
|
||||
<input class="tabmodalprompt-password1Textbox" type="password" id="password1Textbox-${randomIdSuffix}"/>
|
||||
</div>
|
||||
|
||||
<div class="tabmodalprompt-checkboxContainer" hidden="hidden">
|
||||
<div/>
|
||||
<xul:checkbox class="tabmodalprompt-checkbox"/>
|
||||
</div>
|
||||
|
||||
<!-- content goes here -->
|
||||
</div>
|
||||
<div class="tabmodalprompt-buttonContainer">
|
||||
<xul:button class="tabmodalprompt-button3" hidden="true"/>
|
||||
<div class="tabmodalprompt-buttonSpacer"/>
|
||||
<xul:button class="tabmodalprompt-button0" data-l10n-id="tabmodalprompt-ok-button"/>
|
||||
<xul:button class="tabmodalprompt-button2" hidden="true"/>
|
||||
<xul:button class="tabmodalprompt-button1" data-l10n-id="tabmodalprompt-cancel-button"/>
|
||||
</div>
|
||||
</div>`
|
||||
)
|
||||
);
|
||||
|
||||
this.ui = {
|
||||
prompt: this,
|
||||
promptContainer: this.element,
|
||||
mainContainer: newPrompt.querySelector(".tabmodalprompt-mainContainer"),
|
||||
loginContainer: newPrompt.querySelector(".tabmodalprompt-loginContainer"),
|
||||
loginTextbox: newPrompt.querySelector(".tabmodalprompt-loginTextbox"),
|
||||
loginLabel: newPrompt.querySelector(".tabmodalprompt-loginLabel"),
|
||||
password1Container: newPrompt.querySelector(
|
||||
".tabmodalprompt-password1Container"
|
||||
),
|
||||
password1Textbox: newPrompt.querySelector(
|
||||
".tabmodalprompt-password1Textbox"
|
||||
),
|
||||
password1Label: newPrompt.querySelector(".tabmodalprompt-password1Label"),
|
||||
infoContainer: newPrompt.querySelector(".tabmodalprompt-infoContainer"),
|
||||
infoBody: newPrompt.querySelector(".tabmodalprompt-infoBody"),
|
||||
infoTitle: newPrompt.querySelector(".tabmodalprompt-infoTitle"),
|
||||
infoIcon: null,
|
||||
rows: newPrompt.querySelector(".tabmodalprompt-topContainer"),
|
||||
checkbox: newPrompt.querySelector(".tabmodalprompt-checkbox"),
|
||||
checkboxContainer: newPrompt.querySelector(
|
||||
".tabmodalprompt-checkboxContainer"
|
||||
),
|
||||
button3: newPrompt.querySelector(".tabmodalprompt-button3"),
|
||||
button2: newPrompt.querySelector(".tabmodalprompt-button2"),
|
||||
button1: newPrompt.querySelector(".tabmodalprompt-button1"),
|
||||
button0: newPrompt.querySelector(".tabmodalprompt-button0"),
|
||||
// focusTarget (for BUTTON_DELAY_ENABLE) not yet supported
|
||||
};
|
||||
|
||||
if (AppConstants.XP_UNIX) {
|
||||
// Reorder buttons on Linux
|
||||
let buttonContainer = newPrompt.querySelector(
|
||||
".tabmodalprompt-buttonContainer"
|
||||
);
|
||||
buttonContainer.appendChild(this.ui.button3);
|
||||
buttonContainer.appendChild(this.ui.button2);
|
||||
buttonContainer.appendChild(
|
||||
newPrompt.querySelector(".tabmodalprompt-buttonSpacer")
|
||||
);
|
||||
buttonContainer.appendChild(this.ui.button1);
|
||||
buttonContainer.appendChild(this.ui.button0);
|
||||
}
|
||||
|
||||
this.ui.button0.addEventListener(
|
||||
"command",
|
||||
this.onButtonClick.bind(this, 0)
|
||||
);
|
||||
this.ui.button1.addEventListener(
|
||||
"command",
|
||||
this.onButtonClick.bind(this, 1)
|
||||
);
|
||||
this.ui.button2.addEventListener(
|
||||
"command",
|
||||
this.onButtonClick.bind(this, 2)
|
||||
);
|
||||
this.ui.button3.addEventListener(
|
||||
"command",
|
||||
this.onButtonClick.bind(this, 3)
|
||||
);
|
||||
// Anonymous wrapper used here because |Dialog| doesn't exist until init() is called!
|
||||
this.ui.checkbox.addEventListener("command", () => {
|
||||
this.Dialog.onCheckbox();
|
||||
});
|
||||
|
||||
/**
|
||||
* Based on dialog.xml handlers
|
||||
*/
|
||||
this.element.addEventListener(
|
||||
"keypress",
|
||||
event => {
|
||||
switch (event.keyCode) {
|
||||
case KeyEvent.DOM_VK_RETURN:
|
||||
this.onKeyAction("default", event);
|
||||
break;
|
||||
|
||||
case KeyEvent.DOM_VK_ESCAPE:
|
||||
this.onKeyAction("cancel", event);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (
|
||||
AppConstants.platform == "macosx" &&
|
||||
event.key == "." &&
|
||||
event.metaKey
|
||||
) {
|
||||
this.onKeyAction("cancel", event);
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
{ mozSystemGroup: true }
|
||||
);
|
||||
|
||||
this.element.addEventListener(
|
||||
"focus",
|
||||
event => {
|
||||
let bnum = this.args.defaultButtonNum || 0;
|
||||
let defaultButton = this.ui["button" + bnum];
|
||||
|
||||
if (AppConstants.platform == "macosx") {
|
||||
// On OS X, the default button always stays marked as such (until
|
||||
// the entire prompt blurs).
|
||||
defaultButton.setAttribute("default", "true");
|
||||
} else {
|
||||
// On other platforms, the default button is only marked as such
|
||||
// when no other button has focus. XUL buttons on not-OSX will
|
||||
// react to pressing enter as a command, so you can't trigger the
|
||||
// default without tabbing to it or something that isn't a button.
|
||||
let focusedDefault = event.originalTarget == defaultButton;
|
||||
let someButtonFocused =
|
||||
event.originalTarget.localName == "button" ||
|
||||
event.originalTarget.localName == "toolbarbutton";
|
||||
if (focusedDefault || !someButtonFocused) {
|
||||
defaultButton.setAttribute("default", "true");
|
||||
}
|
||||
}
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
this.element.addEventListener("blur", () => {
|
||||
// If focus shifted to somewhere else in the browser, don't make
|
||||
// the default button look active.
|
||||
let bnum = this.args.defaultButtonNum || 0;
|
||||
let button = this.ui["button" + bnum];
|
||||
button.removeAttribute("default");
|
||||
});
|
||||
}
|
||||
|
||||
init(args, linkedTab, onCloseCallback) {
|
||||
this.args = args;
|
||||
this.linkedTab = linkedTab;
|
||||
this.onCloseCallback = onCloseCallback;
|
||||
|
||||
if (args.enableDelay) {
|
||||
throw new Error(
|
||||
"BUTTON_DELAY_ENABLE not yet supported for tab-modal prompts"
|
||||
);
|
||||
}
|
||||
|
||||
// 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()!
|
||||
this.win.addEventListener("resize", this);
|
||||
this.win.addEventListener("unload", this);
|
||||
if (linkedTab) {
|
||||
linkedTab.addEventListener("TabClose", this);
|
||||
}
|
||||
// Note:
|
||||
// nsPrompter.js or in e10s mode browser-parent.js call abortPrompt,
|
||||
// when the domWindow, for which the prompt was created, generates
|
||||
// a "pagehide" event.
|
||||
|
||||
let { CommonDialog } = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/CommonDialog.sys.mjs"
|
||||
);
|
||||
this.Dialog = new CommonDialog(args, this.ui);
|
||||
this.Dialog.onLoad(null);
|
||||
|
||||
// For content prompts display the tabprompt title that shows the prompt origin when
|
||||
// the prompt origin is not the same as that of the top window.
|
||||
if (
|
||||
args.modalType == Ci.nsIPrompt.MODAL_TYPE_CONTENT &&
|
||||
args.showCallerOrigin
|
||||
) {
|
||||
this.ui.infoTitle.removeAttribute("hidden");
|
||||
}
|
||||
|
||||
// TODO: should unhide buttonSpacer on Windows when there are 4 buttons.
|
||||
// Better yet, just drop support for 4-button dialogs. (bug 609510)
|
||||
}
|
||||
|
||||
shutdownPrompt() {
|
||||
// remove our event listeners
|
||||
try {
|
||||
this.win.removeEventListener("resize", this);
|
||||
this.win.removeEventListener("unload", this);
|
||||
if (this.linkedTab) {
|
||||
this.linkedTab.removeEventListener("TabClose", this);
|
||||
}
|
||||
} catch (e) {}
|
||||
// invoke callback
|
||||
this.onCloseCallback();
|
||||
this.win = null;
|
||||
this.ui = null;
|
||||
// Intentionally not cleaning up |this.element| here --
|
||||
// TabModalPromptBox.removePrompt() would need it and it might not
|
||||
// be called yet -- see browser_double_close_tabs.js.
|
||||
}
|
||||
|
||||
abortPrompt() {
|
||||
// Called from other code when the page changes.
|
||||
this.Dialog.abortPrompt();
|
||||
this.shutdownPrompt();
|
||||
}
|
||||
|
||||
handleEvent(aEvent) {
|
||||
switch (aEvent.type) {
|
||||
case "unload":
|
||||
case "TabClose":
|
||||
this.abortPrompt();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
onButtonClick(buttonNum) {
|
||||
// We want to do all the work her asynchronously off a Gecko
|
||||
// runnable, because of situations like the one described in
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1167575#c35 : we
|
||||
// get here off processing of an OS event and will also process
|
||||
// one more Gecko runnable before we break out of the event loop
|
||||
// spin whoever posted the prompt is doing. If we do all our
|
||||
// work sync, we will exit modal state _before_ processing that
|
||||
// runnable, and if exiting moral state posts a runnable we will
|
||||
// incorrectly process that runnable before leaving our event
|
||||
// loop spin.
|
||||
Services.tm.dispatchToMainThread(() => {
|
||||
this.Dialog["onButton" + buttonNum]();
|
||||
this.shutdownPrompt();
|
||||
});
|
||||
}
|
||||
|
||||
onKeyAction(action, event) {
|
||||
if (event.defaultPrevented) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.stopPropagation();
|
||||
if (action == "default") {
|
||||
let bnum = this.args.defaultButtonNum || 0;
|
||||
this.onButtonClick(bnum);
|
||||
} else {
|
||||
// action == "cancel"
|
||||
this.onButtonClick(1); // Cancel button
|
||||
}
|
||||
}
|
||||
};
|
|
@ -9,5 +9,3 @@ toolkit.jar:
|
|||
content/global/commonDialog.css (content/commonDialog.css)
|
||||
content/global/selectDialog.js (content/selectDialog.js)
|
||||
content/global/selectDialog.xhtml (content/selectDialog.xhtml)
|
||||
content/global/tabprompts.css (content/tabprompts.css)
|
||||
content/global/tabprompts.sys.mjs (content/tabprompts.sys.mjs)
|
||||
|
|
|
@ -30,11 +30,10 @@ CommonDialog.prototype = {
|
|||
initialFocusResolver: null,
|
||||
|
||||
/**
|
||||
* @param [commonDialogEl] - Dialog element from commonDialog.xhtml,
|
||||
* null for TabModalPrompts.
|
||||
* @param [commonDialogEl] - Dialog element from commonDialog.xhtml.
|
||||
*/
|
||||
async onLoad(commonDialogEl = null) {
|
||||
let isEmbedded = !!commonDialogEl?.ownerGlobal.docShell.chromeEventHandler;
|
||||
async onLoad(commonDialogEl) {
|
||||
let isEmbedded = !!commonDialogEl.ownerGlobal.docShell.chromeEventHandler;
|
||||
|
||||
switch (this.args.promptType) {
|
||||
case "alert":
|
||||
|
@ -106,36 +105,19 @@ CommonDialog.prototype = {
|
|||
throw new Error("unknown dialog type");
|
||||
}
|
||||
|
||||
if (commonDialogEl) {
|
||||
commonDialogEl.setAttribute(
|
||||
"windowtype",
|
||||
"prompt:" + this.args.promptType
|
||||
);
|
||||
}
|
||||
commonDialogEl.setAttribute("windowtype", "prompt:" + this.args.promptType);
|
||||
|
||||
// set the document title
|
||||
let title = this.args.title;
|
||||
let infoTitle = this.ui.infoTitle;
|
||||
infoTitle.appendChild(infoTitle.ownerDocument.createTextNode(title));
|
||||
|
||||
// Specific check to prevent showing the title on the old content prompts for macOS.
|
||||
// This should be removed when the old content prompts are removed.
|
||||
let contentSubDialogPromptEnabled = Services.prefs.getBoolPref(
|
||||
"prompts.contentPromptSubDialog"
|
||||
);
|
||||
let isOldContentPrompt =
|
||||
!contentSubDialogPromptEnabled &&
|
||||
this.args.modalType == Ci.nsIPrompt.MODAL_TYPE_CONTENT;
|
||||
|
||||
// After making these preventative checks, we can determine to show it if we're on
|
||||
// macOS (where there is no titlebar) or if the prompt is a common dialog document
|
||||
// and has been embedded (has a chromeEventHandler).
|
||||
infoTitle.hidden =
|
||||
isOldContentPrompt || !(AppConstants.platform === "macosx" || isEmbedded);
|
||||
infoTitle.hidden = !(AppConstants.platform === "macosx" || isEmbedded);
|
||||
|
||||
if (commonDialogEl) {
|
||||
commonDialogEl.ownerDocument.title = title;
|
||||
}
|
||||
commonDialogEl.ownerDocument.title = title;
|
||||
|
||||
// Set button labels and visibility
|
||||
//
|
||||
|
@ -202,15 +184,7 @@ CommonDialog.prototype = {
|
|||
|
||||
// Set the default button
|
||||
let b = this.args.defaultButtonNum || 0;
|
||||
let button = this.ui["button" + b];
|
||||
|
||||
if (commonDialogEl) {
|
||||
commonDialogEl.defaultButton = ["accept", "cancel", "extra1", "extra2"][
|
||||
b
|
||||
];
|
||||
} else {
|
||||
button.setAttribute("default", "true");
|
||||
}
|
||||
commonDialogEl.defaultButton = ["accept", "cancel", "extra1", "extra2"][b];
|
||||
|
||||
if (!isEmbedded && !this.ui.promptContainer?.hidden) {
|
||||
// Set default focus and select textbox contents if applicable. If we're
|
||||
|
@ -229,7 +203,7 @@ CommonDialog.prototype = {
|
|||
// Play a sound (unless we're showing a content prompt -- don't want those
|
||||
// to feel like OS prompts).
|
||||
try {
|
||||
if (commonDialogEl && this.soundID && !this.args.openedWithTabDialog) {
|
||||
if (this.soundID && !this.args.openedWithTabDialog) {
|
||||
Cc["@mozilla.org/sound;1"]
|
||||
.getService(Ci.nsISound)
|
||||
.playEventSound(this.soundID);
|
||||
|
@ -238,20 +212,12 @@ CommonDialog.prototype = {
|
|||
console.error("Couldn't play common dialog event sound: ", e);
|
||||
}
|
||||
|
||||
if (commonDialogEl) {
|
||||
if (isEmbedded) {
|
||||
// If we delayed default focus above, wait for it to be ready before
|
||||
// sending the notification.
|
||||
await this.initialFocusPromise;
|
||||
}
|
||||
Services.obs.notifyObservers(this.ui.prompt, "common-dialog-loaded");
|
||||
} else {
|
||||
// ui.promptContainer is the <tabmodalprompt> element.
|
||||
Services.obs.notifyObservers(
|
||||
this.ui.promptContainer,
|
||||
"tabmodal-dialog-loaded"
|
||||
);
|
||||
if (isEmbedded) {
|
||||
// If we delayed default focus above, wait for it to be ready before
|
||||
// sending the notification.
|
||||
await this.initialFocusPromise;
|
||||
}
|
||||
Services.obs.notifyObservers(this.ui.prompt, "common-dialog-loaded");
|
||||
},
|
||||
|
||||
setLabelForNode(aNode, aLabel) {
|
||||
|
|
|
@ -31,52 +31,6 @@ async function handlePromptWhenItAppears(action, modalType, isSelect) {
|
|||
}
|
||||
}
|
||||
|
||||
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),
|
||||
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"
|
||||
);
|
||||
}
|
||||
|
||||
async function handlePrompt(action, modalType, isSelect) {
|
||||
let ui;
|
||||
let browserWin = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
|
@ -142,8 +96,7 @@ function getPromptState(ui) {
|
|||
state.checkHidden = ui.checkboxContainer.hidden;
|
||||
state.checkMsg = state.checkHidden ? "" : ui.checkbox.label;
|
||||
state.checked = state.checkHidden ? false : ui.checkbox.checked;
|
||||
// TabModalPrompts don't have an infoIcon
|
||||
state.iconClass = ui.infoIcon ? ui.infoIcon.className : null;
|
||||
state.iconClass = ui.infoIcon.className;
|
||||
state.textValue = ui.loginTextbox.value;
|
||||
state.passValue = ui.password1Textbox.value;
|
||||
|
||||
|
|
|
@ -17,10 +17,6 @@ function propBagToObject(bag) {
|
|||
}
|
||||
|
||||
var modalType;
|
||||
var tabSubDialogsEnabled = SpecialPowers.Services.prefs.getBoolPref(
|
||||
"prompts.tabChromePromptSubDialog",
|
||||
false
|
||||
);
|
||||
var isSelectDialog = false;
|
||||
var isOSX = "nsILocalFileMac" in SpecialPowers.Ci;
|
||||
var isE10S = SpecialPowers.Services.appinfo.processType == 2;
|
||||
|
@ -227,7 +223,7 @@ function checkPromptState(promptState, expectedState) {
|
|||
is(promptState.checked, expectedState.checked, "Checking checkbox checked");
|
||||
if (
|
||||
modalType === Ci.nsIPrompt.MODAL_TYPE_WINDOW ||
|
||||
(modalType === Ci.nsIPrompt.MODAL_TYPE_TAB && tabSubDialogsEnabled)
|
||||
modalType === Ci.nsIPrompt.MODAL_TYPE_TAB
|
||||
) {
|
||||
is(
|
||||
promptState.iconClass,
|
||||
|
|
|
@ -1,13 +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/.
|
||||
|
||||
tabmodalprompt-username =
|
||||
.value = User Name:
|
||||
tabmodalprompt-password =
|
||||
.value = Password:
|
||||
|
||||
tabmodalprompt-ok-button =
|
||||
.label = OK
|
||||
tabmodalprompt-cancel-button =
|
||||
.label = Cancel
|
|
@ -13,9 +13,6 @@
|
|||
content="default-src chrome:; style-src chrome: 'unsafe-inline'; img-src chrome: file: jar: https: http:; connect-src chrome: data: https: http:; object-src 'none'"
|
||||
/>
|
||||
<meta name="color-scheme" content="light dark" />
|
||||
<link rel="stylesheet" href="chrome://global/content/tabprompts.css" />
|
||||
<link rel="stylesheet" href="chrome://global/skin/tabprompts.css" />
|
||||
|
||||
<link rel="stylesheet" href="chrome://global/skin/in-content/common.css" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
/* exported attachUpdateHandler, detachUpdateHandler, gBrowser,
|
||||
/* exported attachUpdateHandler, detachUpdateHandler,
|
||||
* getBrowserElement, installAddonsFromFilePicker,
|
||||
* isCorrectlySigned, isDisabledUnsigned, isDiscoverEnabled,
|
||||
* isPending, loadReleaseNotes, openOptionsInTab, promiseEvent,
|
||||
|
@ -196,21 +196,6 @@ function showPermissionsPrompt(addon) {
|
|||
});
|
||||
}
|
||||
|
||||
// Stub tabbrowser implementation for use by the tab-modal alert code
|
||||
// when an alert/prompt/confirm method is called in a WebExtensions options_ui
|
||||
// page (See Bug 1385548 for rationale).
|
||||
var gBrowser = {
|
||||
getTabModalPromptBox(browser) {
|
||||
const parentWindow = window.docShell.chromeEventHandler.ownerGlobal;
|
||||
|
||||
if (parentWindow.gBrowser) {
|
||||
return parentWindow.gBrowser.getTabModalPromptBox(browser);
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
};
|
||||
|
||||
function isCorrectlySigned(addon) {
|
||||
// Add-ons without an "isCorrectlySigned" property are correctly signed as
|
||||
// they aren't the correct type for signing.
|
||||
|
|
|
@ -133,7 +133,6 @@ var Harness = {
|
|||
Services.obs.addObserver(this, "addon-install-failed");
|
||||
|
||||
// For browser_auth tests which trigger auth dialogs.
|
||||
Services.obs.addObserver(this, "tabmodal-dialog-loaded");
|
||||
Services.obs.addObserver(this, "common-dialog-loaded");
|
||||
|
||||
this._boundWin = Cu.getWeakReference(win); // need this so our addon manager listener knows which window to use.
|
||||
|
@ -157,7 +156,6 @@ var Harness = {
|
|||
Services.obs.removeObserver(self, "addon-install-blocked");
|
||||
Services.obs.removeObserver(self, "addon-install-failed");
|
||||
|
||||
Services.obs.removeObserver(self, "tabmodal-dialog-loaded");
|
||||
Services.obs.removeObserver(self, "common-dialog-loaded");
|
||||
|
||||
AddonManager.removeInstallListener(self);
|
||||
|
@ -553,11 +551,6 @@ var Harness = {
|
|||
);
|
||||
}, this);
|
||||
break;
|
||||
case "tabmodal-dialog-loaded":
|
||||
let browser = subject.ownerGlobal.gBrowser.selectedBrowser;
|
||||
let prompt = browser.tabModalPromptBox.getPrompt(subject);
|
||||
this.promptReady(prompt.Dialog);
|
||||
break;
|
||||
case "common-dialog-loaded":
|
||||
this.promptReady(subject.Dialog);
|
||||
break;
|
||||
|
|
|
@ -12,7 +12,6 @@ toolkit.jar:
|
|||
skin/classic/global/menu.css
|
||||
skin/classic/global/menulist.css
|
||||
skin/classic/global/richlistbox.css
|
||||
skin/classic/global/tabprompts.css
|
||||
skin/classic/global/tabbox.css
|
||||
skin/classic/global/toolbar.css
|
||||
skin/classic/global/wizard.css
|
||||
|
|
|
@ -1,62 +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/. */
|
||||
|
||||
/* Tab Modal Prompt boxes */
|
||||
.tabModalBackground,
|
||||
tabmodalprompt {
|
||||
background-color: hsla(0,0%,10%,.5);
|
||||
}
|
||||
|
||||
tabmodalprompt {
|
||||
font-family: sans-serif; /* use content font not system UI font */
|
||||
font-size: 110%;
|
||||
}
|
||||
|
||||
.tabmodalprompt-mainContainer {
|
||||
color: black;
|
||||
background-color: hsla(0,0%,100%,.95);
|
||||
background-clip: padding-box;
|
||||
border-radius: 2px;
|
||||
border: 1px solid hsla(0,0%,0%,.5);
|
||||
}
|
||||
|
||||
.tabmodalprompt-buttonContainer {
|
||||
background-color: hsla(0,0%,0%,.05);
|
||||
border-top: 1px solid hsla(0,0%,0%,.05);
|
||||
}
|
||||
|
||||
.tabmodalprompt-buttonContainer > button {
|
||||
appearance: none;
|
||||
padding: 2px 0;
|
||||
margin: 0;
|
||||
margin-inline-start: 8px;
|
||||
border-radius: 2px;
|
||||
color: black !important;
|
||||
background-color: hsl(0,0%,90%);
|
||||
background-image: linear-gradient(hsla(0,0%,100%,.7), transparent);
|
||||
background-clip: padding-box;
|
||||
border: 1px solid;
|
||||
border-color: hsl(0,0%,65%) hsl(0,0%,60%) hsl(0,0%,50%);
|
||||
box-shadow: 0 1px 0 hsla(0,0%,100%,.9) inset,
|
||||
0 1px 2px hsla(0,0%,0%,.1);
|
||||
}
|
||||
|
||||
.tabmodalprompt-buttonContainer > button[default=true] {
|
||||
background-color: hsl(0,0%,79%);
|
||||
}
|
||||
|
||||
.tabmodalprompt-buttonContainer > button:hover {
|
||||
background-color: hsl(0,0%,96%);
|
||||
}
|
||||
|
||||
.tabmodalprompt-buttonContainer > button:hover:active {
|
||||
background-image: linear-gradient(hsla(0,0%,100%,.2), transparent);
|
||||
background-color: hsl(0,0%,70%);
|
||||
box-shadow: 0 1px 0 hsla(0,0%,100%,.2) inset,
|
||||
0 1px 3px hsla(0,0%,0%,.2);
|
||||
}
|
||||
|
||||
.tabmodalprompt-buttonContainer > button:focus-visible {
|
||||
outline: var(--focus-outline);
|
||||
}
|
|
@ -11,7 +11,6 @@
|
|||
#include desktop-jar.inc.mn
|
||||
|
||||
skin/classic/global/dialog.css (../../windows/global/dialog.css)
|
||||
skin/classic/global/tabprompts.css (../../windows/global/tabprompts.css)
|
||||
skin/classic/global/wizard.css (../../windows/global/wizard.css)
|
||||
|
||||
skin/classic/global/arrow/panelarrow-vertical.svg (../../windows/global/arrow/panelarrow-vertical.svg)
|
||||
|
|
|
@ -1,25 +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/. */
|
||||
|
||||
/* Tab Modal Prompt boxes */
|
||||
.tabModalBackground,
|
||||
tabmodalprompt {
|
||||
background-color: hsla(0,0%,10%,.5);
|
||||
}
|
||||
|
||||
tabmodalprompt {
|
||||
font-family: sans-serif; /* use content font not system UI font */
|
||||
}
|
||||
|
||||
.tabmodalprompt-mainContainer {
|
||||
color: FieldText;
|
||||
background-color: Field;
|
||||
border-radius: 2px;
|
||||
border: 1px solid threeDDarkShadow;
|
||||
}
|
||||
|
||||
.tabmodalprompt-buttonContainer {
|
||||
background-color: hsla(0,0%,0%,.05);
|
||||
border-top: 1px solid hsla(0,0%,0%,.05);
|
||||
}
|
Загрузка…
Ссылка в новой задаче