diff --git a/docs/metrics.md b/docs/metrics.md index aefe38e..317ff4e 100644 --- a/docs/metrics.md +++ b/docs/metrics.md @@ -68,6 +68,16 @@ Containers will use Test Pilot Telemetry with no batching of data. Details of when pings are sent are below, along with examples of the `payload` portion of a `testpilottest` telemetry ping for each scenario. +* The user shows the new tab menu + +```js + { + "uuid": , + "event": "show-plus-button-menu", + "eventSource": ["plus-button"] + } +``` + * The user clicks on a container name to open a tab in that container ```js @@ -76,7 +86,7 @@ of a `testpilottest` telemetry ping for each scenario. "userContextId": , "clickedContainerTabCount": , "event": "open-tab", - "eventSource": ["tab-bar"|"pop-up"|"file-menu"|"alltabs-menu"] + "eventSource": ["tab-bar"|"pop-up"|"file-menu"|"alltabs-menu"|"plus-button"] } ``` @@ -269,7 +279,7 @@ local schema = { ### Valid data should be enforced on the server side: -* `eventSource` should be one of `tab-bar`, `pop-up`, or `file-menu`. +* `eventSource` should be one of `tab-bar`, `pop-up`, `file-menu`, "alltabs-nmenu" or "plus-button". All Mozilla data is kept by default for 180 days and in accordance with our privacy policies. diff --git a/index.js b/index.js index 4ebce44..aefc544 100644 --- a/index.js +++ b/index.js @@ -6,9 +6,6 @@ const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; const DEFAULT_TAB = "about:newtab"; const LOOKUP_KEY = "$ref"; -const SHOW_MENU_TIMEOUT = 100; -const HIDE_MENU_TIMEOUT = 300; - const INCOMPATIBLE_ADDON_IDS = [ "pulse@mozilla.com", "snoozetabs@mozilla.com", @@ -246,18 +243,15 @@ const ContainerService = { } tabs.on("open", tab => { - this._hideAllPanels(); this._restyleTab(tab); this._remapTab(tab); }); tabs.on("close", tab => { - this._hideAllPanels(); this._remapTab(tab); }); tabs.on("activate", tab => { - this._hideAllPanels(); this._restyleActiveTab(tab).catch(() => {}); this._configureActiveWindows(); this._remapTab(tab); @@ -941,12 +935,6 @@ const ContainerService = { return this._configureWindows(); }, - _hideAllPanels() { - for (let windowObject of this._windowMap.values()) { // eslint-disable-line prefer-const - windowObject.hidePanel(); - } - }, - _restyleActiveTab(tab) { if (!tab) { return Promise.resolve(null); @@ -1105,22 +1093,50 @@ ContainerWindow.prototype = { _timeoutStore: new Map(), _elementCache: new Map(), _tooltipCache: new Map(), - _plusButton: null, - _overflowPlusButton: null, _tabsElement: null, _init(window) { this._window = window; this._tabsElement = this._window.document.getElementById("tabbrowser-tabs"); + this._style = Style({ uri: self.data.url("usercontext.css") }); this._plusButton = this._window.document.getAnonymousElementByAttribute(this._tabsElement, "anonid", "tabs-newtab-button"); this._overflowPlusButton = this._window.document.getElementById("new-tab-button"); - this._style = Style({ uri: self.data.url("usercontext.css") }); + + // Only hack the normal plus button as the alltabs is done elsewhere + this.attachMenuEvent("plus-button", this._plusButton); + attachTo(this._style, this._window); }, + attachMenuEvent(source, button) { + const popup = button.querySelector(".new-tab-popup"); + popup.addEventListener("popupshown", () => { + ContainerService.sendTelemetryPayload({ + "event": "show-plus-button-menu", + "eventSource": source + }); + popup.querySelector("menuseparator").remove(); + const popupMenuItems = [...popup.querySelectorAll("menuitem")]; + popupMenuItems.forEach((item) => { + const userContextId = item.getAttribute("data-usercontextid"); + if (!userContextId) { + item.remove(); + } + item.setAttribute("command", ""); + item.addEventListener("command", (e) => { + e.stopPropagation(); + e.preventDefault(); + ContainerService.openTab({ + userContextId: userContextId, + source: source + }); + }); + }); + }); + }, + configure() { return Promise.all([ - this._configurePlusButtonMenu(), this._configureActiveTab(), this._configureFileMenu(), this._configureAllTabsMenu(), @@ -1133,113 +1149,6 @@ ContainerWindow.prototype = { return this._configureContextMenu(); }, - handleEvent(e) { - let el = e.target; - switch (e.type) { - case "mouseover": - this._createTimeout("show", () => { - this.showPopup(el); - }, SHOW_MENU_TIMEOUT); - break; - case "click": - this.hidePanel(); - break; - case "mouseout": - while(el) { - if (el === this._panelElement || - el === this._plusButton || - el === this._overflowPlusButton) { - // Clear show timeout so we don't hide and reshow - this._cleanTimeout("show"); - this._createTimeout("hidden", () => { - this.hidePanel(); - }, HIDE_MENU_TIMEOUT); - return; - } - el = el.parentElement; - } - break; - } - }, - - showPopup(buttonElement) { - this._cleanAllTimeouts(); - this._panelElement.openPopup(buttonElement); - }, - - _configurePlusButtonMenuElement(buttonElement) { - if (buttonElement) { - // Let's remove the tooltip because it can go over our panel. - this._tooltipCache.set(buttonElement, buttonElement.getAttribute("tooltip")); - buttonElement.setAttribute("tooltip", ""); - this._disableElement(buttonElement); - - buttonElement.addEventListener("mouseover", this); - buttonElement.addEventListener("click", this); - buttonElement.addEventListener("mouseout", this); - } - }, - - async _configurePlusButtonMenu() { - const mainPopupSetElement = this._window.document.getElementById("mainPopupSet"); - - // Let's remove all the previous panels. - if (this._panelElement) { - this._panelElement.remove(); - } - - this._panelElement = this._window.document.createElementNS(XUL_NS, "panel"); - this._panelElement.setAttribute("id", "new-tab-overlay"); - this._panelElement.setAttribute("position", "bottomcenter topleft"); - this._panelElement.setAttribute("side", "top"); - this._panelElement.setAttribute("flip", "side"); - this._panelElement.setAttribute("type", "arrow"); - this._panelElement.setAttribute("animate", "open"); - this._panelElement.setAttribute("consumeoutsideclicks", "never"); - mainPopupSetElement.appendChild(this._panelElement); - - this._configurePlusButtonMenuElement(this._plusButton); - this._configurePlusButtonMenuElement(this._overflowPlusButton); - - this._panelElement.addEventListener("mouseout", this); - - this._panelElement.addEventListener("mouseover", () => { - this._cleanAllTimeouts(); - }); - - try { - const identities = await ContainerService.queryIdentities(); - identities.forEach(identity => { - const menuItemElement = this._window.document.createElementNS(XUL_NS, "menuitem"); - this._panelElement.appendChild(menuItemElement); - menuItemElement.className = "menuitem-iconic"; - menuItemElement.setAttribute("tooltiptext", identity.name); - menuItemElement.setAttribute("label", identity.name); - menuItemElement.setAttribute("data-usercontextid", identity.userContextId); - menuItemElement.setAttribute("data-identity-icon", identity.icon); - menuItemElement.setAttribute("data-identity-color", identity.color); - - menuItemElement.addEventListener("command", (e) => { - ContainerService.openTab({ - userContextId: identity.userContextId, - source: "tab-bar" - }); - e.stopPropagation(); - }); - - menuItemElement.addEventListener("mouseover", () => { - this._cleanAllTimeouts(); - }); - - menuItemElement.addEventListener("mouseout", this); - - this._panelElement.appendChild(menuItemElement); - }); - } catch (e) { - this.hidePanel(); - } - }, - _configureTabStyle() { const promises = []; for (let tab of modelFor(this._window).tabs) { // eslint-disable-line prefer-const @@ -1409,11 +1318,6 @@ ContainerWindow.prototype = { } }, - hidePanel() { - this._cleanAllTimeouts(); - this._panelElement.hidePopup(); - }, - shutdown() { // CSS must be removed. detachFrom(this._style, this._window); @@ -1437,11 +1341,6 @@ ContainerWindow.prototype = { } }, - _shutdownPlusButtonMenu() { - this._shutDownPlusButtonMenuElement(this._plusButton); - this._shutDownPlusButtonMenuElement(this._overflowPlusButton); - }, - _shutdownFileMenu() { this._shutdownMenu("menu_newUserContext"); }, diff --git a/webextension/css/content.css b/webextension/css/content.css index 6fb2681..5681887 100644 --- a/webextension/css/content.css +++ b/webextension/css/content.css @@ -1,6 +1,6 @@ .container-notification { align-items: center; - background: #33f70c; + background: #efefef; color: #003f07; display: flex; font: 12px sans-serif; diff --git a/webextension/js/content-script.js b/webextension/js/content-script.js index bd3aa43..8485d30 100644 --- a/webextension/js/content-script.js +++ b/webextension/js/content-script.js @@ -31,7 +31,7 @@ async function addMessage(message) { await delayAnimation(100); await doAnimation(divElement, "transform", "translateY(0)"); - await delayAnimation(2000); + await delayAnimation(3000); await doAnimation(divElement, "transform", "translateY(-100%)"); divElement.remove();