Backed out 3 changesets (bug 1434883) for frequent leaks in AbstractThread, AnimationTimeline, Annotators, Array, AsyncFreeSnowWhite, ... on a CLOSED TREE

Backed out changeset c8115e90ffa8 (bug 1434883)
Backed out changeset 22c83b1d417d (bug 1434883)
Backed out changeset 085796417462 (bug 1434883)
This commit is contained in:
Cosmin Sabou 2018-02-06 16:30:56 +02:00
Родитель c88a7c210e
Коммит 793dad7903
12 изменённых файлов: 91 добавлений и 307 удалений

Просмотреть файл

@ -187,25 +187,22 @@ var BrowserPageActions = {
togglePanelForAction(action, panelNode = null) {
let aaPanelNode = this.activatedActionPanelNode;
if (panelNode) {
// Note that this particular code path will not prevent the panel from
// opening later if PanelMultiView.showPopup was called but the panel has
// not been opened yet.
if (panelNode.state != "closed") {
PanelMultiView.hidePopup(panelNode);
panelNode.hidePopup();
return;
}
if (aaPanelNode) {
PanelMultiView.hidePopup(aaPanelNode);
aaPanelNode.hidePopup();
}
} else if (aaPanelNode) {
PanelMultiView.hidePopup(aaPanelNode);
aaPanelNode.hidePopup();
return;
} else {
panelNode = this._makeActivatedActionPanelForAction(action);
}
// Hide the main panel before showing the action's panel.
PanelMultiView.hidePopup(this.panelNode);
this.panelNode.hidePopup();
let anchorNode = this.panelAnchorNodeForAction(action);
anchorNode.setAttribute("open", "true");
@ -213,8 +210,7 @@ var BrowserPageActions = {
anchorNode.removeAttribute("open");
}, { once: true });
PanelMultiView.openPopup(panelNode, anchorNode, "bottomcenter topright")
.catch(Cu.reportError);
panelNode.openPopup(anchorNode, "bottomcenter topright");
},
_makeActivatedActionPanelForAction(action) {
@ -558,7 +554,7 @@ var BrowserPageActions = {
return;
}
// Otherwise, hide the main popup in case it was open:
PanelMultiView.hidePopup(this.panelNode);
this.panelNode.hidePopup();
// Toggle the activated action's panel if necessary
if (action.subview || action.wantsIframe) {
@ -698,12 +694,12 @@ var BrowserPageActions = {
// close it.
let panelNode = this.activatedActionPanelNode;
if (panelNode && panelNode.anchorNode.id == this.mainButtonNode.id) {
PanelMultiView.hidePopup(panelNode);
panelNode.hidePopup();
return;
}
if (this.panelNode.state == "open") {
PanelMultiView.hidePopup(this.panelNode);
this.panelNode.hidePopup();
} else if (this.panelNode.state == "closed") {
this.showPanel(event);
}
@ -727,10 +723,10 @@ var BrowserPageActions = {
this.mainButtonNode.removeAttribute("open");
}, {once: true});
this.mainButtonNode.setAttribute("open", "true");
PanelMultiView.openPopup(this.panelNode, this.mainButtonNode, {
this.panelNode.openPopup(this.mainButtonNode, {
position: "bottomcenter topright",
triggerEvent: event,
}).catch(Cu.reportError);
});
},
/**
@ -885,10 +881,10 @@ var BrowserPageActionFeedback = {
this.panelNode.hidden = false;
let anchor = BrowserPageActions.panelAnchorNodeForAction(action, event);
PanelMultiView.openPopup(this.panelNode, anchor, {
this.panelNode.openPopup(anchor, {
position: "bottomcenter topright",
triggerEvent: event,
}).catch(Cu.reportError);
});
this.panelNode.addEventListener("popupshown", () => {
this.feedbackAnimationBox.setAttribute("animate", "true");
@ -916,7 +912,7 @@ BrowserPageActions.bookmark = {
},
onCommand(event, buttonNode) {
PanelMultiView.hidePopup(BrowserPageActions.panelNode);
BrowserPageActions.panelNode.hidePopup();
BookmarkingUI.onStarCommand(event);
},
};
@ -929,7 +925,7 @@ BrowserPageActions.copyURL = {
},
onCommand(event, buttonNode) {
PanelMultiView.hidePopup(BrowserPageActions.panelNode);
BrowserPageActions.panelNode.hidePopup();
Cc["@mozilla.org/widget/clipboardhelper;1"]
.getService(Ci.nsIClipboardHelper)
.copyString(gURLBar.makeURIReadable(gBrowser.selectedBrowser.currentURI).displaySpec);
@ -946,7 +942,7 @@ BrowserPageActions.emailLink = {
},
onCommand(event, buttonNode) {
PanelMultiView.hidePopup(BrowserPageActions.panelNode);
BrowserPageActions.panelNode.hidePopup();
MailIntegration.sendLinkForBrowser(gBrowser.selectedBrowser);
},
};
@ -996,7 +992,7 @@ BrowserPageActions.sendToDevice = {
item.addEventListener("command", event => {
if (panelNode) {
PanelMultiView.hidePopup(panelNode);
panelNode.hidePopup();
}
// There are items in the subview that don't represent devices: "Sign
// in", "Learn about Sync", etc. Device items will be .sendtab-target.

Просмотреть файл

@ -41,7 +41,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
NewTabUtils: "resource://gre/modules/NewTabUtils.jsm",
PageActions: "resource:///modules/PageActions.jsm",
PageThumbs: "resource://gre/modules/PageThumbs.jsm",
PanelMultiView: "resource:///modules/PanelMultiView.jsm",
PanelView: "resource:///modules/PanelMultiView.jsm",
PluralForm: "resource://gre/modules/PluralForm.jsm",
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
@ -7260,7 +7259,7 @@ var gIdentityHandler = {
handleMoreInfoClick(event) {
displaySecurityInfo();
event.stopPropagation();
PanelMultiView.hidePopup(this._identityPopup);
this._identityPopup.hidePopup();
},
showSecuritySubView() {
@ -7282,14 +7281,14 @@ var gIdentityHandler = {
// Reload the page with the content unblocked
BrowserReloadWithFlags(
Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_MIXED_CONTENT);
PanelMultiView.hidePopup(this._identityPopup);
this._identityPopup.hidePopup();
},
enableMixedContentProtection() {
gBrowser.selectedBrowser.messageManager.sendAsyncMessage(
"MixedContent:ReenableProtection", {});
BrowserReload();
PanelMultiView.hidePopup(this._identityPopup);
this._identityPopup.hidePopup();
},
removeCertException() {
@ -7301,7 +7300,7 @@ var gIdentityHandler = {
let port = this._uri.port > 0 ? this._uri.port : 443;
this._overrideService.clearValidityOverride(host, port);
BrowserReloadSkipCache();
PanelMultiView.hidePopup(this._identityPopup);
this._identityPopup.hidePopup();
},
/**
@ -7367,7 +7366,7 @@ var gIdentityHandler = {
// Handle a location change while the Control Center is focused
// by closing the popup (bug 1207542)
if (shouldHidePopup) {
PanelMultiView.hidePopup(this._identityPopup);
this._identityPopup.hidePopup();
}
// NOTE: We do NOT update the identity popup (the control center) when
@ -7831,8 +7830,7 @@ var gIdentityHandler = {
this._identityBox.setAttribute("open", "true");
// Now open the popup, anchored off the primary chrome element
PanelMultiView.openPopup(this._identityPopup, this._identityIcon,
"bottomcenter topleft").catch(Cu.reportError);
this._identityPopup.openPopup(this._identityIcon, "bottomcenter topleft");
},
onPopupShown(event) {
@ -7865,7 +7863,7 @@ var gIdentityHandler = {
// Hide the panel when focusing an element that is
// neither an ancestor nor descendant unless the panel has
// @noautohide (e.g. for a tour).
PanelMultiView.hidePopup(this._identityPopup);
this._identityPopup.hidePopup();
}
},

Просмотреть файл

@ -14,10 +14,7 @@ add_task(async function() {
await loadBadCertPage("https://expired.example.com");
let { gIdentityHandler } = gBrowser.ownerGlobal;
let promisePanelOpen = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popupshown");
gIdentityHandler._identityBox.click();
await promisePanelOpen;
let promiseViewShown = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "ViewShown");
document.getElementById("identity-popup-security-expander").click();
await promiseViewShown;

Просмотреть файл

@ -14,7 +14,7 @@ const EXPECTED_APPMENU_OPEN_REFLOWS = [
{
stack: [
"openPopup@chrome://global/content/bindings/popup.xml",
"openPopup/this._openPopupPromise<@resource:///modules/PanelMultiView.jsm",
"show/</<@chrome://browser/content/customizableui/panelUI.js",
],
},

Просмотреть файл

@ -204,9 +204,7 @@ async function assertMixedContentBlockingState(tabbrowser, states = {}) {
}
// Make sure the identity popup has the correct mixedcontent states
let promisePanelOpen = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popupshown");
gIdentityHandler._identityBox.click();
await promisePanelOpen;
let popupAttr = doc.getElementById("identity-popup").getAttribute("mixedcontent");
let bodyAttr = doc.getElementById("identity-popup-securityView-body").getAttribute("mixedcontent");

Просмотреть файл

@ -560,10 +560,10 @@ add_task(async function sendToDevice_inUrlbar() {
Assert.notEqual(urlbarButton, null, "The urlbar button should exist");
Assert.ok(!urlbarButton.disabled,
"The urlbar button should not be disabled");
let panelPromise =
promisePanelShown(BrowserPageActions._activatedActionPanelID);
EventUtils.synthesizeMouseAtCenter(urlbarButton, {});
// The panel element for _activatedActionPanelID is created synchronously
// only after the associated button has been clicked.
await promisePanelShown(BrowserPageActions._activatedActionPanelID);
await panelPromise;
Assert.equal(urlbarButton.getAttribute("open"), "true",
"Button has open attribute");

Просмотреть файл

@ -266,14 +266,10 @@ function promisePanelHidden(panelIDOrNode) {
function promisePanelEvent(panelIDOrNode, eventType) {
return new Promise(resolve => {
let panel = panelIDOrNode;
if (typeof panel == "string") {
panel = document.getElementById(panelIDOrNode);
if (!panel) {
throw new Error(`Panel with ID "${panelIDOrNode}" does not exist.`);
}
}
if ((eventType == "popupshown" && panel.state == "open") ||
let panel = typeof(panelIDOrNode) != "string" ? panelIDOrNode :
document.getElementById(panelIDOrNode);
if (!panel ||
(eventType == "popupshown" && panel.state == "open") ||
(eventType == "popuphidden" && panel.state == "closed")) {
executeSoon(resolve);
return;

Просмотреть файл

@ -16,7 +16,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
SearchWidgetTracker: "resource:///modules/SearchWidgetTracker.jsm",
CustomizableWidgets: "resource:///modules/CustomizableWidgets.jsm",
DeferredTask: "resource://gre/modules/DeferredTask.jsm",
PanelMultiView: "resource:///modules/PanelMultiView.jsm",
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
ShortcutUtils: "resource://gre/modules/ShortcutUtils.jsm",
LightweightThemeManager: "resource://gre/modules/LightweightThemeManager.jsm",
@ -1779,7 +1778,7 @@ var CustomizableUIInternal = {
hidePanelForNode(aNode) {
let panel = this._getPanelForNode(aNode);
if (panel) {
PanelMultiView.hidePopup(panel);
panel.hidePopup();
}
},
@ -4265,7 +4264,7 @@ OverflowableToolbar.prototype = {
if (aEvent.target == this._chevron) {
this._onClickChevron(aEvent);
} else {
PanelMultiView.hidePopup(this._panel);
this._panel.hidePopup();
}
break;
case "customizationstarting":
@ -4277,7 +4276,7 @@ OverflowableToolbar.prototype = {
}
break;
case "dragend":
PanelMultiView.hidePopup(this._panel);
this._panel.hidePopup();
break;
case "popuphiding":
this._onPanelHiding(aEvent);
@ -4303,9 +4302,7 @@ OverflowableToolbar.prototype = {
// Ensure we update the gEditUIVisible flag when opening the popup, in
// case the edit controls are in it.
this._panel.addEventListener("popupshowing", () => doc.defaultView.updateEditUIVisibility(), {once: true});
PanelMultiView.openPopup(this._panel, anchor || this._chevron, {
triggerEvent: aEvent,
}).catch(Cu.reportError);
this._panel.openPopup(anchor || this._chevron, { triggerEvent: aEvent });
this._chevron.open = true;
this._panel.addEventListener("popupshown", () => {
@ -4318,8 +4315,8 @@ OverflowableToolbar.prototype = {
_onClickChevron(aEvent) {
if (this._chevron.open) {
this._panel.hidePopup();
this._chevron.open = false;
PanelMultiView.hidePopup(this._panel);
} else if (this._panel.state != "hiding" && !this._chevron.disabled) {
this.show(aEvent);
}
@ -4611,7 +4608,7 @@ OverflowableToolbar.prototype = {
}
this._hideTimeoutId = window.setTimeout(() => {
if (!this._panel.firstChild.matches(":hover")) {
PanelMultiView.hidePopup(this._panel);
this._panel.hidePopup();
}
}, OVERFLOW_PANEL_HIDE_DELAY_MS);
});

Просмотреть файл

@ -12,13 +12,9 @@
* <panelmultiview> element, although they don't need to be, as views can also
* be imported into the panel from other panels or popup sets.
*
* The panel should be opened asynchronously using the openPopup static method
* on the PanelMultiView object. This will display the view specified using the
* mainViewId attribute on the contained <panelmultiview> element.
*
* Specific subviews can slide in using the showSubView method, and backwards
* navigation can be done using the goBack method or through a button in the
* subview headers.
* The main view can be declared using the mainViewId attribute, and specific
* subviews can slide in using the showSubView method. Backwards navigation can
* be done using the goBack method or through a button in the subview headers.
*
* This diagram shows how <panelview> nodes move during navigation:
*
@ -53,7 +49,6 @@ this.EXPORTED_SYMBOLS = [
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.defineModuleGetter(this, "AppConstants",
"resource://gre/modules/AppConstants.jsm");
ChromeUtils.defineModuleGetter(this, "BrowserUtils",
@ -141,41 +136,6 @@ this.AssociatedToNode = class {
* This is associated to <panelmultiview> elements by the panelUI.xml binding.
*/
this.PanelMultiView = class extends this.AssociatedToNode {
/**
* Tries to open the specified <panel> and displays the main view specified
* with the "mainViewId" attribute on the <panelmultiview> node it contains.
*
* If the panel does not contain a <panelmultiview>, it is opened directly.
* This allows consumers like page actions to accept different panel types.
*
* @see The non-static openPopup method for details.
*/
static async openPopup(panelNode, ...args) {
let panelMultiViewNode = panelNode.querySelector("panelmultiview");
if (panelMultiViewNode) {
return this.forNode(panelMultiViewNode).openPopup(...args);
}
panelNode.openPopup(...args);
return true;
}
/**
* Closes the specified <panel> which contains a <panelmultiview> node.
*
* If the panel does not contain a <panelmultiview>, it is closed directly.
* This allows consumers like page actions to accept different panel types.
*
* @see The non-static hidePopup method for details.
*/
static hidePopup(panelNode) {
let panelMultiViewNode = panelNode.querySelector("panelmultiview");
if (panelMultiViewNode) {
this.forNode(panelMultiViewNode).hidePopup();
} else {
panelNode.hidePopup();
}
}
get _panel() {
return this.node.parentNode;
}
@ -228,15 +188,15 @@ this.PanelMultiView = class extends this.AssociatedToNode {
let panelView = this.openViews[this.openViews.length - 1];
return (panelView && panelView.node) || this._mainView;
}
constructor(node) {
super(node);
this._openPopupPromise = Promise.resolve(false);
this._openPopupCancelCallback = () => {};
/**
* @return {Promise} showSubView() returns a promise, which is kept here for
* random access.
*/
get currentShowPromise() {
return this._currentShowPromise || Promise.resolve();
}
connect() {
this.connected = true;
this.knownViews = new Set(Array.from(
this.node.getElementsByTagName("panelview"),
node => PanelView.forNode(node)));
@ -266,6 +226,7 @@ this.PanelMultiView = class extends this.AssociatedToNode {
// Set CSS-determined attributes now to prevent a layout flush when we do
// it when transitioning between panels.
this._dir = cs.direction;
this.showMainView();
// Proxy these public properties and methods, as used elsewhere by various
// parts of the browser, to this instance.
@ -275,7 +236,7 @@ this.PanelMultiView = class extends this.AssociatedToNode {
value: (...args) => this[method](...args)
});
});
["current", "showingSubView"].forEach(property => {
["current", "currentShowPromise", "showingSubView"].forEach(property => {
Object.defineProperty(this.node, property, {
enumerable: true,
get: () => this[property]
@ -305,154 +266,10 @@ this.PanelMultiView = class extends this.AssociatedToNode {
this._panel.removeEventListener("popupshown", this);
this._panel.removeEventListener("popuphidden", this);
this.window.removeEventListener("keydown", this);
this.node = this._openPopupPromise = this._openPopupCancelCallback =
this._viewContainer = this._viewStack = this.__dwu =
this.node = this._viewContainer = this._viewStack = this.__dwu =
this._panelViewCache = this._transitionDetails = null;
}
/**
* Tries to open the panel associated with this PanelMultiView, and displays
* the main view specified with the "mainViewId" attribute.
*
* The hidePopup method can be called while the operation is in progress to
* prevent the panel from being displayed. View events may also cancel the
* operation, so there is no guarantee that the panel will become visible.
*
* The "popuphidden" event will be fired either when the operation is canceled
* or when the popup is closed later. This event can be used for example to
* reset the "open" state of the anchor or tear down temporary panels.
*
* If this method is called again before the panel is shown, the result
* depends on the operation currently in progress. If the operation was not
* canceled, the panel is opened using the arguments from the previous call,
* and this call is ignored. If the operation was canceled, it will be
* retried again using the arguments from this call.
*
* It's not necessary for the <panelmultiview> binding to be connected when
* this method is called, but the containing panel must have its display
* turned on, for example it shouldn't have the "hidden" attribute.
*
* @param args
* Arguments to be forwarded to the openPopup method of the panel.
*
* @resolves With true as soon as the request to display the panel has been
* sent, or with false if the operation was canceled. The state of
* the panel at this point is not guaranteed. It may be still
* showing, completely shown, or completely hidden.
* @rejects If an exception is thrown at any point in the process before the
* request to display the panel is sent.
*/
async openPopup(...args) {
// Set up the function that allows hidePopup or a second call to showPopup
// to cancel the specific panel opening operation that we're starting below.
// This function must be synchronous, meaning we can't use Promise.race,
// because hidePopup wants to dispatch the "popuphidden" event synchronously
// even if the panel has not been opened yet.
let canCancel = true;
let cancelCallback = this._openPopupCancelCallback = () => {
// If the cancel callback is called and the panel hasn't been prepared
// yet, cancel showing it. Setting canCancel to false will prevent the
// popup from opening. If the panel has opened by the time the cancel
// callback is called, canCancel will be false already, and we will not
// fire the "popuphidden" event.
if (canCancel && this.node) {
canCancel = false;
this.dispatchCustomEvent("popuphidden");
}
};
// Create a promise that is resolved with the result of the last call to
// this method, where errors indicate that the panel was not opened.
let openPopupPromise = this._openPopupPromise.catch(() => {
return false;
});
// Make the preparation done before showing the panel non-reentrant. The
// promise created here will be resolved only after the panel preparation is
// completed, even if a cancellation request is received in the meantime.
return this._openPopupPromise = openPopupPromise.then(async wasShown => {
// The panel may have been destroyed in the meantime.
if (!this.node) {
return false;
}
// If the panel has been already opened there is nothing more to do. We
// check the actual state of the panel rather than setting some state in
// our handler of the "popuphidden" event because this has a lower chance
// of locking indefinitely if events aren't raised in the expected order.
if (wasShown && ["open", "showing"].includes(this._panel.state)) {
return true;
}
try {
// Most of the panel elements in the browser window have their display
// turned off for performance reasons, typically by setting the "hidden"
// attribute. If the caller has just turned on the display, the XBL
// binding for the <panelmultiview> element may still be disconnected.
// In this case, give the layout code a chance to run.
if (!this.connected) {
await BrowserUtils.promiseLayoutFlushed(this.document, "layout",
() => {});
// The XBL binding must be connected at this point. If this is not the
// case, the calling code should be updated to unhide the panel.
if (!this.connected) {
throw new Error("The binding for the panelmultiview element isn't" +
" connected. The containing panel may still have" +
" its display turned off by the hidden attribute.");
}
}
// Allow any of the ViewShowing handlers to prevent showing the main view.
if (!(await this.showMainView())) {
cancelCallback();
}
} catch (ex) {
cancelCallback();
throw ex;
}
// If a cancellation request was received there is nothing more to do.
if (!canCancel || !this.node) {
return false;
}
// We have to set canCancel to false before opening the popup because the
// hidePopup method of PanelMultiView can be re-entered by event handlers.
// If the openPopup call fails, however, we still have to dispatch the
// "popuphidden" event even if canCancel was set to false.
try {
canCancel = false;
this._panel.openPopup(...args);
return true;
} catch (ex) {
this.dispatchCustomEvent("popuphidden");
throw ex;
}
});
}
/**
* Closes the panel associated with this PanelMultiView.
*
* If the openPopup method was called but the panel has not been displayed
* yet, the operation is canceled and the panel will not be displayed, but the
* "popuphidden" event is fired synchronously anyways.
*
* This means that by the time this method returns all the operations handled
* by the "popuphidden" event are completed, for example resetting the "open"
* state of the anchor, and the panel is already invisible.
*/
hidePopup() {
if (!this.node) {
return;
}
// If we have already reached the _panel.openPopup call in the openPopup
// method, we can call hidePopup. Otherwise, we have to cancel the latest
// request to open the panel, which will have no effect if the request has
// been canceled already.
if (["open", "showing"].includes(this._panel.state)) {
this._panel.hidePopup();
} else {
this._openPopupCancelCallback();
}
}
/**
* Remove any child subviews into the panelViewCache, to ensure
* they remain usable even if this panelmultiview instance is removed
@ -487,7 +304,7 @@ this.PanelMultiView = class extends this.AssociatedToNode {
showMainView() {
if (!this.node || !this._mainViewId)
return Promise.resolve(false);
return Promise.resolve();
return this.showSubView(this._mainView);
}
@ -519,8 +336,8 @@ this.PanelMultiView = class extends this.AssociatedToNode {
this.showingSubView = nextPanelView.node.id != this._mainViewId;
}
async showSubView(aViewId, aAnchor, aPreviousView) {
try {
showSubView(aViewId, aAnchor, aPreviousView) {
this._currentShowPromise = (async () => {
// Support passing in the node directly.
let viewNode = typeof aViewId == "string" ? this.node.querySelector("#" + aViewId) : aViewId;
if (!viewNode) {
@ -591,7 +408,7 @@ this.PanelMultiView = class extends this.AssociatedToNode {
if (cancel) {
this._viewShowing = null;
return false;
return;
}
}
@ -604,12 +421,8 @@ this.PanelMultiView = class extends this.AssociatedToNode {
} else {
this.hideAllViewsExcept(nextPanelView);
}
return true;
} catch (ex) {
Cu.reportError(ex);
return false;
}
})().catch(e => Cu.reportError(e));
return this._currentShowPromise;
}
/**
@ -932,14 +745,10 @@ this.PanelMultiView = class extends this.AssociatedToNode {
case "popuphidden": {
// WebExtensions consumers can hide the popup from viewshowing, or
// mid-transition, which disrupts our state:
if (this._viewShowing) {
PanelView.forNode(this._viewShowing).dispatchCustomEvent("ViewHiding");
}
this._viewShowing = null;
this._transitioning = false;
this.node.removeAttribute("panelopen");
// Raise the ViewHiding event for the current view.
this.hideAllViewsExcept(null);
this.showMainView();
this.window.removeEventListener("keydown", this);
this._panel.removeEventListener("mousemove", this);
this.openViews.forEach(panelView => panelView.clearNavigation());

Просмотреть файл

@ -6,8 +6,6 @@ ChromeUtils.defineModuleGetter(this, "AppMenuNotifications",
"resource://gre/modules/AppMenuNotifications.jsm");
ChromeUtils.defineModuleGetter(this, "NewTabUtils",
"resource://gre/modules/NewTabUtils.jsm");
ChromeUtils.defineModuleGetter(this, "PanelMultiView",
"resource:///modules/PanelMultiView.jsm");
ChromeUtils.defineModuleGetter(this, "ScrollbarSampler",
"resource:///modules/ScrollbarSampler.jsm");
@ -217,9 +215,7 @@ const PanelUI = {
}, {once: true});
anchor = this._getPanelAnchor(anchor);
PanelMultiView.openPopup(this.panel, anchor, {
triggerEvent: domEvent,
}).catch(Cu.reportError);
this.panel.openPopup(anchor, { triggerEvent: domEvent });
}, (reason) => {
console.error("Error showing the PanelUI menu", reason);
});
@ -234,7 +230,7 @@ const PanelUI = {
return;
}
PanelMultiView.hidePopup(this.panel);
this.panel.hidePopup();
},
observe(subject, topic, status) {
@ -422,6 +418,10 @@ const PanelUI = {
await oldMultiView.showMainView();
}
let viewShown = false;
let listener = () => viewShown = true;
viewNode.addEventListener("ViewShown", listener, {once: true});
let multiView = document.createElement("panelmultiview");
multiView.setAttribute("id", "customizationui-widget-multiview");
multiView.setAttribute("viewCacheId", "appMenu-viewCache");
@ -431,7 +431,6 @@ const PanelUI = {
tempPanel.appendChild(multiView);
viewNode.classList.add("cui-widget-panelview");
let viewShown = false;
let panelRemover = () => {
viewNode.classList.remove("cui-widget-panelview");
if (viewShown) {
@ -446,6 +445,18 @@ const PanelUI = {
tempPanel.remove();
};
// Wait until all the tasks needed to show a view are done.
await multiView.currentShowPromise;
if (!viewShown) {
viewNode.removeEventListener("ViewShown", listener);
panelRemover();
return;
}
CustomizableUI.addPanelCloseListeners(tempPanel);
tempPanel.addEventListener("popuphidden", panelRemover);
if (aAnchor.parentNode.id == "PersonalToolbar") {
tempPanel.classList.add("bookmarks-toolbar");
}
@ -456,21 +467,10 @@ const PanelUI = {
anchor.setAttribute("consumeanchor", aAnchor.id);
}
try {
viewShown = await PanelMultiView.openPopup(tempPanel, anchor, {
position: "bottomcenter topright",
triggerEvent: domEvent,
});
} catch (ex) {
Cu.reportError(ex);
}
if (viewShown) {
CustomizableUI.addPanelCloseListeners(tempPanel);
tempPanel.addEventListener("popuphidden", panelRemover);
} else {
panelRemover();
}
tempPanel.openPopup(anchor, {
position: "bottomcenter topright",
triggerEvent: domEvent,
});
}
},
@ -620,7 +620,9 @@ const PanelUI = {
this.navbar.setAttribute("nonemptyoverflow", "true");
this.overflowPanel.setAttribute("hasfixeditems", "true");
} else if (!hasKids && this.navbar.hasAttribute("nonemptyoverflow")) {
PanelMultiView.hidePopup(this.overflowPanel);
if (this.overflowPanel.state != "closed") {
this.overflowPanel.hidePopup();
}
this.overflowPanel.removeAttribute("hasfixeditems");
this.navbar.removeAttribute("nonemptyoverflow");
}

Просмотреть файл

@ -250,7 +250,7 @@ var DownloadsPanel = {
return;
}
PanelMultiView.hidePopup(this.panel);
this.panel.hidePopup();
// Ensure that we allow the panel to be reopened. Note that, if the popup
// was open, then the onPopupHidden event handler has already updated the
@ -570,8 +570,7 @@ var DownloadsPanel = {
}
DownloadsCommon.log("Opening downloads panel popup.");
PanelMultiView.openPopup(this.panel, anchor, "bottomcenter topright",
0, 0, false, null).catch(Cu.reportError);
this.panel.openPopup(anchor, "bottomcenter topright", 0, 0, false, null);
});
},
};

Просмотреть файл

@ -431,7 +431,7 @@ add_task(async function withSubview() {
Assert.notEqual(panelViewButtonNodeUrlbar, null, "panelViewButtonNodeUrlbar");
onButtonCommandExpectedButtonID = panelViewButtonIDUrlbar;
EventUtils.synthesizeMouseAtCenter(panelViewButtonNodeUrlbar, {});
assertActivatedPageActionPanelHidden();
await promisePanelHidden(BrowserPageActions._activatedActionPanelID);
Assert.equal(onButtonCommandCallCount, 2,
"onButtonCommandCallCount should be inc'ed");
@ -532,7 +532,7 @@ add_task(async function withIframe() {
Assert.notEqual(aaPanel, null, "activated-action panel");
Assert.equal(aaPanel.anchorNode.id, urlbarButtonID, "aaPanel.anchorNode.id");
EventUtils.synthesizeMouseAtCenter(urlbarButtonNode, {});
assertActivatedPageActionPanelHidden();
await promisePanelHidden(BrowserPageActions._activatedActionPanelID);
// Click the action's urlbar button.
EventUtils.synthesizeMouseAtCenter(urlbarButtonNode, {});
@ -546,7 +546,7 @@ add_task(async function withIframe() {
Assert.notEqual(aaPanel, null, "aaPanel");
Assert.equal(aaPanel.anchorNode.id, urlbarButtonID, "aaPanel.anchorNode.id");
EventUtils.synthesizeMouseAtCenter(urlbarButtonNode, {});
assertActivatedPageActionPanelHidden();
await promisePanelHidden(BrowserPageActions._activatedActionPanelID);
// Hide the action's button in the urlbar.
action.pinnedToUrlbar = false;
@ -567,7 +567,7 @@ add_task(async function withIframe() {
Assert.equal(aaPanel.anchorNode.id, BrowserPageActions.mainButtonNode.id,
"aaPanel.anchorNode.id");
EventUtils.synthesizeMouseAtCenter(BrowserPageActions.mainButtonNode, {});
assertActivatedPageActionPanelHidden();
await promisePanelHidden(BrowserPageActions._activatedActionPanelID);
// Remove the action.
action.remove();
@ -1416,10 +1416,6 @@ add_task(async function contextMenu() {
});
function assertActivatedPageActionPanelHidden() {
Assert.ok(!document.getElementById(BrowserPageActions._activatedActionPanelID));
}
function promisePageActionPanelOpen() {
let dwu = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
@ -1463,14 +1459,10 @@ function promisePanelHidden(panelIDOrNode) {
function promisePanelEvent(panelIDOrNode, eventType) {
return new Promise(resolve => {
let panel = panelIDOrNode;
if (typeof panel == "string") {
panel = document.getElementById(panelIDOrNode);
if (!panel) {
throw new Error(`Panel with ID "${panelIDOrNode}" does not exist.`);
}
}
if ((eventType == "popupshown" && panel.state == "open") ||
let panel = typeof(panelIDOrNode) != "string" ? panelIDOrNode :
document.getElementById(panelIDOrNode);
if (!panel ||
(eventType == "popupshown" && panel.state == "open") ||
(eventType == "popuphidden" && panel.state == "closed")) {
executeSoon(resolve);
return;