1 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 // This file is loaded into the browser window scope.
7 /* eslint-env mozilla/browser-window */
9 ChromeUtils.defineESModuleGetters(this, {
10 OriginControls: "resource://gre/modules/ExtensionPermissions.sys.mjs",
14 * The `unified-extensions-item` custom element is used to manage an extension
15 * in the list of extensions, which is displayed when users click the unified
16 * extensions (toolbar) button.
18 * This custom element must be initialized with `setExtension()`:
21 * let item = document.createElement("unified-extensions-item");
22 * item.setExtension(extension);
23 * document.body.appendChild(item);
26 customElements.define(
27 "unified-extensions-item",
28 class extends HTMLElement {
30 * Set the extension for this item. The item will be populated based on the
31 * extension when it is rendered into the DOM.
33 * @param {Extension} extension The extension to use.
35 setExtension(extension) {
36 this.extension = extension;
40 if (this._menuButton) {
44 const template = document.getElementById(
45 "unified-extensions-item-template"
47 this.appendChild(template.content.cloneNode(true));
49 this._actionButton = this.querySelector(
50 ".unified-extensions-item-action-button"
52 this._menuButton = this.querySelector(
53 ".unified-extensions-item-menu-button"
55 this._messageDeck = this.querySelector(
56 ".unified-extensions-item-message-deck"
59 // Focus/blur events are fired on specific elements only.
60 this._actionButton.addEventListener("blur", this);
61 this._actionButton.addEventListener("focus", this);
62 this._menuButton.addEventListener("blur", this);
63 this._menuButton.addEventListener("focus", this);
65 this.addEventListener("command", this);
66 this.addEventListener("mouseout", this);
67 this.addEventListener("mouseover", this);
73 const { target } = event;
77 if (target === this._menuButton) {
78 const popup = target.ownerDocument.getElementById(
79 "unified-extensions-context-menu"
81 // Anchor to the visible part of the button.
82 const anchor = target.firstElementChild;
88 true /* isContextMenu */,
89 false /* attributesOverride */,
92 } else if (target === this._actionButton) {
93 const win = event.target.ownerGlobal;
94 const tab = win.gBrowser.selectedTab;
96 this.extension.tabManager.addActiveTabPermission(tab);
97 this.extension.tabManager.activateScripts(tab);
103 this._messageDeck.selectedIndex =
104 gUnifiedExtensions.MESSAGE_DECK_INDEX_DEFAULT;
109 if (target === this._menuButton) {
110 this._messageDeck.selectedIndex =
111 gUnifiedExtensions.MESSAGE_DECK_INDEX_MENU_HOVER;
112 } else if (target === this._actionButton) {
113 this._messageDeck.selectedIndex =
114 gUnifiedExtensions.MESSAGE_DECK_INDEX_HOVER;
121 const messages = OriginControls.getStateMessageIDs({
122 policy: this.extension.policy,
123 tab: this.ownerGlobal.gBrowser.selectedTab,
130 const messageDefaultElement = this.querySelector(
131 ".unified-extensions-item-message-default"
133 this.ownerDocument.l10n.setAttributes(
134 messageDefaultElement,
138 const messageHoverElement = this.querySelector(
139 ".unified-extensions-item-message-hover"
141 this.ownerDocument.l10n.setAttributes(
143 messages.onHover || messages.default
148 const state = OriginControls.getState(
149 this.extension.policy,
150 this.ownerGlobal.gBrowser.selectedTab
153 return state && state.whenClicked && !state.hasAccess;
157 if (!this.extension) {
159 "unified-extensions-item requires an extension, forgot to call setExtension()?"
163 this.setAttribute("extension-id", this.extension.id);
165 "toolbaritem-combined-buttons",
166 "unified-extensions-item"
169 // The data-extensionid attribute is used by context menu handlers
170 // to identify the extension being manipulated by the context menu.
171 this._actionButton.dataset.extensionid = this.extension.id;
173 const { attention } = OriginControls.getAttentionState(
174 this.extension.policy,
177 this.toggleAttribute("attention", attention);
179 this.querySelector(".unified-extensions-item-name").textContent =
182 AddonManager.getAddonByID(this.extension.id).then(addon => {
183 const iconURL = AddonManager.getPreferredIconURL(addon, 32, window);
185 this.querySelector(".unified-extensions-item-icon").setAttribute(
192 this._actionButton.disabled = !this.#hasAction();
194 // The data-extensionid attribute is used by context menu handlers
195 // to identify the extension being manipulated by the context menu.
196 this._menuButton.dataset.extensionid = this.extension.id;
197 this.ownerDocument.l10n.setAttributes(
199 "unified-extensions-item-open-menu",
200 { extensionName: this.extension.name }
203 this.#setStateMessage();