--- a/browser/components/uitour/UITour.jsm
+++ b/browser/components/uitour/UITour.jsm
@@ -79,17 +79,18 @@ this.UITour = {
url: null,
seenPageIDs: null,
// This map is not persisted and is used for
// building the content source of a potential tour.
pageIDsForSession: new Map(),
pageIDSourceBrowsers: new WeakMap(),
/* Map from browser chrome windows to a Set of <browser>s in which a tour is open (both visible and hidden) */
tourBrowsersByWindow: new WeakMap(),
- appMenuOpenForAnnotation: new Set(),
+ // Menus opened by api users explictly through `Mozilla.UITour.showMenu` call
+ noautohideMenus: new Set(),
availableTargetsCache: new WeakMap(),
clearAvailableTargetsCache() {
this.availableTargetsCache = new WeakMap();
},
_annotationPanelMutationObservers: new WeakMap(),
highlightEffects: ["random", "wobble", "zoom", "color"],
@@ -199,16 +200,34 @@ this.UITour = {
}],
["trackingProtection", {
query: "#tracking-protection-icon",
}],
["urlbar", {
query: "#urlbar",
widgetName: "urlbar-container",
}],
+ ["pageActionButton", {
+ query: "#pageActionButton"
+ }],
+ ["pageAction-panel-bookmark", {
+ query: "#pageAction-panel-bookmark"
+ }],
+ ["pageAction-panel-copyURL", {
+ query: "#pageAction-panel-copyURL"
+ }],
+ ["pageAction-panel-emailLink", {
+ query: "#pageAction-panel-emailLink"
+ }],
+ ["pageAction-panel-sendToDevice", {
+ query: "#pageAction-panel-sendToDevice"
+ }],
+ ["bookmark-star-button", {
+ query: "#star-button"
+ }]
]),
init() {
log.debug("Initializing UITour");
// Lazy getter is initialized here so it can be replicated any time
// in a test.
delete this.seenPageIDs;
Object.defineProperty(this, "seenPageIDs", {
@@ -449,24 +468,26 @@ this.UITour = {
}
case "resetTheme": {
this.resetTheme();
break;
}
case "showMenu": {
+ this.noautohideMenus.add(data.name);
this.showMenu(window, data.name, () => {
if (typeof data.showCallbackID == "string")
this.sendPageCallback(messageManager, data.showCallbackID);
});
break;
}
case "hideMenu": {
+ this.noautohideMenus.delete(data.name);
this.hideMenu(window, data.name);
break;
}
case "showNewTab": {
this.showNewTab(window, browser);
break;
}
@@ -787,43 +808,74 @@ this.UITour = {
return {
seenPageIDs: [...this.seenPageIDs.keys()],
};
},
/**
* Tear down a tour from a tab e.g. upon switching/closing tabs.
*/
- teardownTourForBrowser(aWindow, aBrowser, aTourPageClosing = false) {
+ async teardownTourForBrowser(aWindow, aBrowser, aTourPageClosing = false) {
log.debug("teardownTourForBrowser: aBrowser = ", aBrowser, aTourPageClosing);
if (this.pageIDSourceBrowsers.has(aBrowser)) {
let pageID = this.pageIDSourceBrowsers.get(aBrowser);
this.setExpiringTelemetryBucket(pageID, aTourPageClosing ? "closed" : "inactive");
}
let openTourBrowsers = this.tourBrowsersByWindow.get(aWindow);
if (aTourPageClosing && openTourBrowsers) {
openTourBrowsers.delete(aBrowser);
}
this.hideHighlight(aWindow);
this.hideInfo(aWindow);
- // Ensure the menu panel is hidden before calling recreatePopup so popup events occur.
- this.hideMenu(aWindow, "appMenu");
- this.hideMenu(aWindow, "controlCenter");
- // Clean up panel listeners after calling hideMenu above.
- aWindow.PanelUI.panel.removeEventListener("popuphiding", this.hideAppMenuAnnotations);
- aWindow.PanelUI.panel.removeEventListener("ViewShowing", this.hideAppMenuAnnotations);
- aWindow.PanelUI.panel.removeEventListener("popuphidden", this.onPanelHidden);
- let controlCenterPanel = aWindow.gIdentityHandler._identityPopup;
- controlCenterPanel.removeEventListener("popuphidden", this.onPanelHidden);
- controlCenterPanel.removeEventListener("popuphiding", this.hideControlCenterAnnotations);
+ let panels = [
+ {
+ name: "appMenu",
+ node: aWindow.PanelUI.panel,
+ events: [
+ [ "popuphidden", this.onPanelHidden ],
+ [ "popuphiding", this.hideAppMenuAnnotations ],
+ [ "ViewShowing", this.hideAppMenuAnnotations ]
+ ]
+ },
+ {
+ name: "pageActionPanel",
+ node: aWindow.BrowserPageActions.panelNode,
+ events: [
+ [ "popuphidden", this.onPanelHidden ],
+ [ "popuphiding", this.hidePageActionPanelAnnotations ],
+ [ "ViewShowing", this.hidePageActionPanelAnnotations ]
+ ]
+ },
+ {
+ name: "controlCenter",
+ node: aWindow.gIdentityHandler._identityPopup,
+ events: [
+ [ "popuphidden", this.onPanelHidden ],
+ [ "popuphiding", this.hideControlCenterAnnotations ]
+ ]
+ },
+ ];
+ for (let panel of panels) {
+ // Ensure the menu panel is hidden and clean up panel listeners after calling hideMenu.
+ if (panel.node.state != "closed") {
+ await new Promise(resolve => {
+ panel.node.addEventListener("popuphidden", resolve, { once: true });
+ this.hideMenu(aWindow, panel.name);
+ });
+ }
+ for (let [ name, listener ] of panel.events) {
+ panel.node.removeEventListener(name, listener);
+ }
+ }
+ this.noautohideMenus.clear();
this.resetTheme();
// If there are no more tour tabs left in the window, teardown the tour for the whole window.
if (!openTourBrowsers || openTourBrowsers.size == 0) {
this.teardownTourForWindow(aWindow);
}
},
@@ -936,68 +988,103 @@ this.UITour = {
// Use the widget for filtering if it exists since the target may be the icon inside.
if (aTarget.widgetName) {
targetElement = aTarget.node.ownerDocument.getElementById(aTarget.widgetName);
}
return targetElement.id.startsWith("appMenu-");
},
+ targetIsInPageActionPanel(aTarget) {
+ return aTarget.node.id.startsWith("pageAction-panel-");
+ },
+
/**
- * Called before opening or after closing a highlight or info panel to see if
- * we need to open or close the appMenu to see the annotation's anchor.
+ * Called before opening or after closing a highlight or an info tooltip to see if
+ * we need to open or close the menu to see the annotation's anchor.
+ *
+ * @param {ChromeWindow} aWindow the chrome window
+ * @param {bool} aShouldOpen true means we should open the menu, otherwise false
+ * @param {String} aMenuName "appMenu" or "pageActionPanel"
*/
- _setAppMenuStateForAnnotation(aWindow, aAnnotationType, aShouldOpenForHighlight, aTarget = null,
- aCallback = null) {
- log.debug("_setAppMenuStateForAnnotation:", aAnnotationType);
- log.debug("_setAppMenuStateForAnnotation: Menu is expected to be:", aShouldOpenForHighlight ? "open" : "closed");
+ _setMenuStateForAnnotation(aWindow, aShouldOpen, aMenuName) {
+ log.debug("_setMenuStateForAnnotation: Menu is ", aMenuName);
+ log.debug("_setMenuStateForAnnotation: Menu is expected to be:", aShouldOpen ? "open" : "closed");
+ let menu = aMenuName == "appMenu" ? aWindow.PanelUI.panel : aWindow.BrowserPageActions.panelNode;
// If the panel is in the desired state, we're done.
- let panelIsOpen = aWindow.PanelUI.panel.state != "closed";
- if (aShouldOpenForHighlight == panelIsOpen) {
- log.debug("_setAppMenuStateForAnnotation: Panel already in expected state");
- if (aCallback)
- aCallback();
- return;
- }
-
- // Don't close the menu if it wasn't opened by us (e.g. via showmenu instead).
- if (!aShouldOpenForHighlight && !this.appMenuOpenForAnnotation.has(aAnnotationType)) {
- log.debug("_setAppMenuStateForAnnotation: Menu not opened by us, not closing");
- if (aCallback)
- aCallback();
- return;
- }
-
- if (aShouldOpenForHighlight) {
- this.appMenuOpenForAnnotation.add(aAnnotationType);
- } else {
- this.appMenuOpenForAnnotation.delete(aAnnotationType);
+ let panelIsOpen = menu.state != "closed";
+ if (aShouldOpen == panelIsOpen) {
+ log.debug("_setMenuStateForAnnotation: Menu already in expected state");
+ return Promise.resolve();
}
// Actually show or hide the menu
- if (this.appMenuOpenForAnnotation.size) {
- log.debug("_setAppMenuStateForAnnotation: Opening the menu");
- this.showMenu(aWindow, "appMenu", async () => {
- // PanelMultiView's like the AppMenu might shuffle the DOM, which might result
- // in our target being invalidated if it was anonymous content (since the XBL
- // binding it belonged to got destroyed). We work around this by re-querying for
- // the node and stuffing it into the old target structure.
- log.debug("_setAppMenuStateForAnnotation: Refreshing target");
- let refreshedTarget = await this.getTarget(aWindow, aTarget.targetName);
- aTarget.node = refreshedTarget.node;
- aCallback();
+ let promise = null;
+ if (aShouldOpen) {
+ log.debug("_setMenuStateForAnnotation: Opening the menu");
+ promise = new Promise(resolve => {
+ this.showMenu(aWindow, aMenuName, resolve);
+ });
+ } else if (!this.noautohideMenus.has(aMenuName)) {
+ // If the menu was opened explictly by api user through `Mozilla.UITour.showMenu`,
+ // it should be closed explictly by api user through `Mozilla.UITour.hideMenu`.
+ // So we shouldn't get to here to close it for the highlight/info annotation.
+ log.debug("_setMenuStateForAnnotation: Closing the menu");
+ promise = new Promise(resolve => {
+ menu.addEventListener("popuphidden", resolve, { once: true });
+ this.hideMenu(aWindow, aMenuName);
});
- } else {
- log.debug("_setAppMenuStateForAnnotation: Closing the menu");
- this.hideMenu(aWindow, "appMenu");
- if (aCallback)
- aCallback();
+ }
+ return promise;
+ },
+
+ /**
+ * Ensure the target's visibility and the open/close states of menus for the target.
+ *
+ * @param {ChromeWindow} aChromeWindow The chrome window
+ * @param {Object} aTarget The target on which we show highlight or show info.
+ */
+ async _ensureTarget(aChromeWindow, aTarget) {
+ let shouldOpenAppMenu = false;
+ let shouldOpenPageActionPanel = false;
+ if (this.targetIsInAppMenu(aTarget)) {
+ shouldOpenAppMenu = true;
+ } else if (this.targetIsInPageActionPanel(aTarget)) {
+ shouldOpenPageActionPanel = true;
+ // Ensure the panel visibility so as to ensure the visibility of
+ // the target element inside the panel otherwise
+ // we would be rejected in the below `isElementVisible` checking.
+ aChromeWindow.BrowserPageActions.panelNode.hidden = false;
}
+ // Prevent showing a panel at an undefined position.
+ if (!this.isElementVisible(aTarget.node)) {
+ return Promise.reject(`_ensureTarget: Reject the ${aTarget.name} target since it isn't visible.`);
+ }
+
+ let menuToOpen = null;
+ let menuClosePromises = [];
+ if (shouldOpenAppMenu) {
+ menuToOpen = "appMenu";
+ menuClosePromises.push(this._setMenuStateForAnnotation(aChromeWindow, false, "pageActionPanel"));
+ } else if (shouldOpenPageActionPanel) {
+ menuToOpen = "pageActionPanel";
+ menuClosePromises.push(this._setMenuStateForAnnotation(aChromeWindow, false, "appMenu"));
+ } else {
+ menuClosePromises.push(this._setMenuStateForAnnotation(aChromeWindow, false, "appMenu"));
+ menuClosePromises.push(this._setMenuStateForAnnotation(aChromeWindow, false, "pageActionPanel"));
+ }
+
+ let promise = Promise.all(menuClosePromises);
+ await promise;
+ if (menuToOpen) {
+ promise = this._setMenuStateForAnnotation(aChromeWindow, true, menuToOpen);
+ }
+ return promise;
},
previewTheme(aTheme) {
let origin = Services.prefs.getCharPref("browser.uitour.themeOrigin");
let data = LightweightThemeManager.parseTheme(aTheme, origin);
if (data)
LightweightThemeManager.previewTheme(data);
},
@@ -1006,41 +1093,44 @@ this.UITour = {
LightweightThemeManager.resetPreview();
},
/**
* The node to which a highlight or notification(-popup) is anchored is sometimes
* obscured because it may be inside an overflow menu. This function should figure
* that out and offer the overflow chevron as an alternative.
*
- * @param {Node} aAnchor The element that's supposed to be the anchor
+ * @param {ChromeWindow} aChromeWindow The chrome window
+ * @param {Object} aTarget The target object whose node is supposed to be the anchor
* @type {Node}
*/
- _correctAnchor(aAnchor) {
+ async _correctAnchor(aChromeWindow, aTarget) {
+ // PanelMultiView's like the AppMenu might shuffle the DOM, which might result
+ // in our anchor being invalidated if it was anonymous content (since the XBL
+ // binding it belonged to got destroyed). We work around this by re-querying for
+ // the node and stuffing it into the old anchor structure.
+ let refreshedTarget = await this.getTarget(aChromeWindow, aTarget.targetName);
+ let node = aTarget.node = refreshedTarget.node;
// If the target is in the overflow panel, just return the overflow button.
- if (aAnchor.getAttribute("overflowedItem")) {
- let doc = aAnchor.ownerDocument;
- let placement = CustomizableUI.getPlacementOfWidget(aAnchor.id);
- let areaNode = doc.getElementById(placement.area);
- return areaNode.overflowable._chevron;
+ if (node.closest("#widget-overflow-scroller")) {
+ return CustomizableUI.getWidget(node.id).forWindow(aChromeWindow).anchor;
}
-
- return aAnchor;
+ return node;
},
/**
* @param aChromeWindow The chrome window that the highlight is in. Necessary since some targets
* are in a sub-frame so the defaultView is not the same as the chrome
* window.
* @param aTarget The element to highlight.
* @param aEffect (optional) The effect to use from UITour.highlightEffects or "none".
* @see UITour.highlightEffects
*/
- showHighlight(aChromeWindow, aTarget, aEffect = "none") {
- function showHighlightPanel() {
+ async showHighlight(aChromeWindow, aTarget, aEffect = "none") {
+ let showHighlightPanel = (aAnchorEl) => {
let highlighter = aChromeWindow.document.getElementById("UITourHighlight");
let effect = aEffect;
if (effect == "random") {
// Exclude "random" from the randomly selected effects.
let randomEffect = 1 + Math.floor(Math.random() * (this.highlightEffects.length - 1));
if (randomEffect == this.highlightEffects.length)
randomEffect--; // On the order of 1 in 2^62 chance of this happening.
@@ -1048,17 +1138,17 @@ this.UITour = {
}
// Toggle the effect attribute to "none" and flush layout before setting it so the effect plays.
highlighter.setAttribute("active", "none");
aChromeWindow.getComputedStyle(highlighter).animationName;
highlighter.setAttribute("active", effect);
highlighter.parentElement.setAttribute("targetName", aTarget.targetName);
highlighter.parentElement.hidden = false;
- let highlightAnchor = this._correctAnchor(aTarget.node);
+ let highlightAnchor = aAnchorEl;
let targetRect = highlightAnchor.getBoundingClientRect();
let highlightHeight = targetRect.height;
let highlightWidth = targetRect.width;
let minDimension = Math.min(highlightHeight, highlightWidth);
let maxDimension = Math.max(highlightHeight, highlightWidth);
// If the dimensions are within 200% of each other (to include the bookmarks button),
// make the highlight a circle with the largest dimension as the diameter.
@@ -1082,55 +1172,52 @@ this.UITour = {
let highlightWindow = aChromeWindow;
let highlightStyle = highlightWindow.getComputedStyle(highlighter);
let highlightHeightWithMin = Math.max(highlightHeight, parseFloat(highlightStyle.minHeight));
let highlightWidthWithMin = Math.max(highlightWidth, parseFloat(highlightStyle.minWidth));
let offsetX = -(Math.max(0, highlightWidthWithMin - targetRect.width) / 2);
let offsetY = -(Math.max(0, highlightHeightWithMin - targetRect.height) / 2);
this._addAnnotationPanelMutationObserver(highlighter.parentElement);
highlighter.parentElement.openPopup(highlightAnchor, "overlap", offsetX, offsetY);
- }
+ };
- // Prevent showing a panel at an undefined position.
- if (!this.isElementVisible(aTarget.node)) {
- log.warn("showHighlight: Not showing a highlight since the target isn't visible", aTarget);
- return;
+ try {
+ await this._ensureTarget(aChromeWindow, aTarget);
+ let anchorEl = await this._correctAnchor(aChromeWindow, aTarget);
+ showHighlightPanel(anchorEl);
+ } catch (e) {
+ log.warn(e);
}
-
- this._setAppMenuStateForAnnotation(aChromeWindow, "highlight",
- this.targetIsInAppMenu(aTarget),
- aTarget,
- showHighlightPanel.bind(this));
},
hideHighlight(aWindow) {
let highlighter = aWindow.document.getElementById("UITourHighlight");
this._removeAnnotationPanelMutationObserver(highlighter.parentElement);
highlighter.parentElement.hidePopup();
highlighter.removeAttribute("active");
-
- this._setAppMenuStateForAnnotation(aWindow, "highlight", false);
+ this._setMenuStateForAnnotation(aWindow, false, "appMenu");
+ this._setMenuStateForAnnotation(aWindow, false, "pageActionPanel");
},
/**
* Show an info panel.
*
* @param {ChromeWindow} aChromeWindow
* @param {Node} aAnchor
* @param {String} [aTitle=""]
* @param {String} [aDescription=""]
* @param {String} [aIconURL=""]
* @param {Object[]} [aButtons=[]]
* @param {Object} [aOptions={}]
* @param {String} [aOptions.closeButtonCallback]
* @param {String} [aOptions.targetCallback]
*/
- showInfo(aChromeWindow, aAnchor, aTitle = "", aDescription = "",
+ async showInfo(aChromeWindow, aAnchor, aTitle = "", aDescription = "",
aIconURL = "", aButtons = [], aOptions = {}) {
- function showInfoPanel(aAnchorEl) {
+ let showInfoPanel = (aAnchorEl) => {
aAnchorEl.focus();
let document = aChromeWindow.document;
let tooltip = document.getElementById("UITourTooltip");
let tooltipTitle = document.getElementById("UITourTooltipTitle");
let tooltipDesc = document.getElementById("UITourTooltipDescription");
let tooltipIcon = document.getElementById("UITourTooltipIcon");
let tooltipButtons = document.getElementById("UITourTooltipButtons");
@@ -1214,112 +1301,111 @@ this.UITour = {
this._addAnnotationPanelMutationObserver(tooltip);
tooltip.openPopup(aAnchorEl, alignment, xOffset || 0, yOffset || 0);
if (tooltip.state == "closed") {
document.defaultView.addEventListener("endmodalstate", function() {
tooltip.openPopup(aAnchorEl, alignment);
}, {once: true});
}
- }
-
- // Prevent showing a panel at an undefined position.
- if (!this.isElementVisible(aAnchor.node)) {
- log.warn("showInfo: Not showing since the target isn't visible", aAnchor);
- return;
- }
-
- // We need to bind the anchor argument to the showInfoPanel function call
- // after _setAppMenuStateForAnnotation has finished, since
- // _setAppMenuStateForAnnotation might have refreshed the anchor node.
- let callShowInfoPanel = () => {
- showInfoPanel.call(this, this._correctAnchor(aAnchor.node));
};
- this._setAppMenuStateForAnnotation(aChromeWindow, "info",
- this.targetIsInAppMenu(aAnchor),
- aAnchor,
- callShowInfoPanel);
+ try {
+ await this._ensureTarget(aChromeWindow, aAnchor);
+ let anchorEl = await this._correctAnchor(aChromeWindow, aAnchor);
+ showInfoPanel(anchorEl);
+ } catch (e) {
+ log.warn(e);
+ }
},
isInfoOnTarget(aChromeWindow, aTargetName) {
let document = aChromeWindow.document;
let tooltip = document.getElementById("UITourTooltip");
return tooltip.getAttribute("targetName") == aTargetName && tooltip.state != "closed";
},
hideInfo(aWindow) {
let document = aWindow.document;
-
let tooltip = document.getElementById("UITourTooltip");
this._removeAnnotationPanelMutationObserver(tooltip);
tooltip.hidePopup();
- this._setAppMenuStateForAnnotation(aWindow, "info", false);
+ this._setMenuStateForAnnotation(aWindow, false, "appMenu");
+ this._setMenuStateForAnnotation(aWindow, false, "pageActionPanel");
let tooltipButtons = document.getElementById("UITourTooltipButtons");
while (tooltipButtons.firstChild)
tooltipButtons.firstChild.remove();
},
showMenu(aWindow, aMenuName, aOpenCallback = null) {
log.debug("showMenu:", aMenuName);
function openMenuButton(aMenuBtn) {
if (!aMenuBtn || !aMenuBtn.boxObject || aMenuBtn.open) {
if (aOpenCallback)
aOpenCallback();
return;
}
if (aOpenCallback)
- aMenuBtn.addEventListener("popupshown", onPopupShown);
+ aMenuBtn.addEventListener("popupshown", aOpenCallback, { once: true });
aMenuBtn.boxObject.openMenu(true);
}
- function onPopupShown(event) {
- this.removeEventListener("popupshown", onPopupShown);
- aOpenCallback(event);
- }
- if (aMenuName == "appMenu") {
- aWindow.PanelUI.panel.setAttribute("noautohide", "true");
- // If the popup is already opened, don't recreate the widget as it may cause a flicker.
- if (aWindow.PanelUI.panel.state != "open") {
- this.recreatePopup(aWindow.PanelUI.panel);
+ if (aMenuName == "appMenu" || aMenuName == "pageActionPanel") {
+ let menu = {
+ onPanelHidden: this.onPanelHidden
+ };
+ if (aMenuName == "appMenu") {
+ menu.node = aWindow.PanelUI.panel;
+ menu.hideMenuAnnotations = this.hideAppMenuAnnotations;
+ menu.show = () => aWindow.PanelUI.show();
+ } else {
+ menu.node = aWindow.BrowserPageActions.panelNode;
+ menu.hideMenuAnnotations = this.hidePageActionPanelAnnotations;
+ menu.show = () => aWindow.BrowserPageActions.showPanel();
}
- aWindow.PanelUI.panel.addEventListener("popuphiding", this.hideAppMenuAnnotations);
- aWindow.PanelUI.panel.addEventListener("ViewShowing", this.hideAppMenuAnnotations);
- aWindow.PanelUI.panel.addEventListener("popuphidden", this.onPanelHidden);
+
+ menu.node.setAttribute("noautohide", "true");
+ // If the popup is already opened, don't recreate the widget as it may cause a flicker.
+ if (menu.node.state != "open") {
+ this.recreatePopup(menu.node);
+ }
if (aOpenCallback) {
- aWindow.PanelUI.panel.addEventListener("popupshown", onPopupShown);
+ menu.node.addEventListener("popupshown", aOpenCallback, { once: true });
}
- aWindow.PanelUI.show();
+ menu.node.addEventListener("popuphidden", menu.onPanelHidden);
+ menu.node.addEventListener("popuphiding", menu.hideMenuAnnotations);
+ menu.node.addEventListener("ViewShowing", menu.hideMenuAnnotations);
+ menu.show();
} else if (aMenuName == "bookmarks") {
let menuBtn = aWindow.document.getElementById("bookmarks-menu-button");
openMenuButton(menuBtn);
} else if (aMenuName == "controlCenter") {
let popup = aWindow.gIdentityHandler._identityPopup;
// Add the listener even if the panel is already open since it will still
// only get registered once even if it was UITour that opened it.
popup.addEventListener("popuphiding", this.hideControlCenterAnnotations);
popup.addEventListener("popuphidden", this.onPanelHidden);
- popup.setAttribute("noautohide", true);
+ popup.setAttribute("noautohide", "true");
this.clearAvailableTargetsCache();
if (popup.state == "open") {
if (aOpenCallback) {
aOpenCallback();
}
return;
}
this.recreatePopup(popup);
// Open the control center
if (aOpenCallback) {
- popup.addEventListener("popupshown", onPopupShown);
+ popup.addEventListener("popupshown", aOpenCallback, { once: true });
}
aWindow.document.getElementById("identity-box").click();
} else if (aMenuName == "pocket") {
this.getTarget(aWindow, "pocket").then(async function onPocketTarget(target) {
let widgetGroupWrapper = CustomizableUI.getWidget(target.widgetName);
if (widgetGroupWrapper.type != "view" || !widgetGroupWrapper.viewId) {
log.error("Can't open the pocket menu without a view");
return;
@@ -1354,19 +1440,19 @@ this.UITour = {
let widgetWrapper = widgetGroupWrapper.forWindow(aWindow);
aWindow.PanelUI.showSubView(widgetGroupWrapper.viewId,
widgetWrapper.anchor,
placement.area);
}).catch(log.error);
} else if (aMenuName == "urlbar") {
this.getTarget(aWindow, "urlbar").then(target => {
let urlbar = target.node;
- urlbar.popup.addEventListener("popupshown", evt => {
- aOpenCallback && aOpenCallback(evt);
- }, {once: true});
+ if (aOpenCallback) {
+ urlbar.popup.addEventListener("popupshown", aOpenCallback, { once: true });
+ }
urlbar.focus();
// To demonstrate the ability of searching, we type "Firefox" in advance
// for URLBar's dropdown. To limit the search results on browser-related
// items, we use "Firefox" hard-coded rather than l10n brandShortName
// entity to avoid unrelated or unpredicted results for, like, Nightly
// or translated entites.
const SEARCH_STRING = "Firefox";
urlbar.value = SEARCH_STRING;
@@ -1386,24 +1472,28 @@ this.UITour = {
if (aMenuName == "appMenu") {
aWindow.PanelUI.hide();
} else if (aMenuName == "bookmarks") {
let menuBtn = aWindow.document.getElementById("bookmarks-menu-button");
closeMenuButton(menuBtn);
} else if (aMenuName == "controlCenter") {
let panel = aWindow.gIdentityHandler._identityPopup;
panel.hidePopup();
+ } else if (aMenuName == "urlbar") {
+ aWindow.gURLBar.closePopup();
+ } else if (aMenuName == "pageActionPanel") {
+ aWindow.BrowserPageActions.panelNode.hidePopup();
}
},
showNewTab(aWindow, aBrowser) {
aWindow.openLinkIn("about:newtab", "current", {targetBrowser: aBrowser});
},
- hideAnnotationsForPanel(aEvent, aTargetPositionCallback) {
+ _hideAnnotationsForPanel(aEvent, aTargetPositionCallback) {
let win = aEvent.target.ownerGlobal;
let annotationElements = new Map([
// [annotationElement (panel), method to hide the annotation]
[win.document.getElementById("UITourHighlightContainer"), UITour.hideHighlight.bind(UITour)],
[win.document.getElementById("UITourTooltip"), UITour.hideInfo.bind(UITour)],
]);
annotationElements.forEach((hideMethod, annotationElement) => {
if (annotationElement.state != "closed") {
@@ -1415,25 +1505,28 @@ this.UITour = {
annotationElement.state == "closed" ||
!aTargetPositionCallback(aTarget)) {
return;
}
hideMethod(win);
}).catch(log.error);
}
});
- UITour.appMenuOpenForAnnotation.clear();
},
hideAppMenuAnnotations(aEvent) {
- UITour.hideAnnotationsForPanel(aEvent, UITour.targetIsInAppMenu);
+ UITour._hideAnnotationsForPanel(aEvent, UITour.targetIsInAppMenu);
+ },
+
+ hidePageActionPanelAnnotations(aEvent) {
+ UITour._hideAnnotationsForPanel(aEvent, UITour.targetIsInPageActionPanel);
},
hideControlCenterAnnotations(aEvent) {
- UITour.hideAnnotationsForPanel(aEvent, (aTarget) => {
+ UITour._hideAnnotationsForPanel(aEvent, (aTarget) => {
return aTarget.targetName.startsWith("controlCenter-");
});
},
onPanelHidden(aEvent) {
aEvent.target.removeAttribute("noautohide");
UITour.recreatePopup(aEvent.target);
UITour.clearAvailableTargetsCache();