forked from mirrors/gecko-dev
		
	 9691ab4a5f
			
		
	
	
		9691ab4a5f
		
	
	
	
	
		
			
			Depends on D175553 Differential Revision: https://phabricator.services.mozilla.com/D176005
		
			
				
	
	
		
			204 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			204 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
 | |
|  * 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/. */
 | |
| 
 | |
| // This file is loaded into the browser window scope.
 | |
| /* eslint-env mozilla/browser-window */
 | |
| 
 | |
| ChromeUtils.defineESModuleGetters(this, {
 | |
|   OriginControls: "resource://gre/modules/ExtensionPermissions.sys.mjs",
 | |
| });
 | |
| 
 | |
| /**
 | |
|  * The `unified-extensions-item` custom element is used to manage an extension
 | |
|  * in the list of extensions, which is displayed when users click the unified
 | |
|  * extensions (toolbar) button.
 | |
|  *
 | |
|  * This custom element must be initialized with `setExtension()`:
 | |
|  *
 | |
|  * ```
 | |
|  * let item = document.createElement("unified-extensions-item");
 | |
|  * item.setExtension(extension);
 | |
|  * document.body.appendChild(item);
 | |
|  * ```
 | |
|  */
 | |
| customElements.define(
 | |
|   "unified-extensions-item",
 | |
|   class extends HTMLElement {
 | |
|     /**
 | |
|      * Set the extension for this item. The item will be populated based on the
 | |
|      * extension when it is rendered into the DOM.
 | |
|      *
 | |
|      * @param {Extension} extension The extension to use.
 | |
|      */
 | |
|     setExtension(extension) {
 | |
|       this.extension = extension;
 | |
|     }
 | |
| 
 | |
|     connectedCallback() {
 | |
|       if (this._menuButton) {
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|       const template = document.getElementById(
 | |
|         "unified-extensions-item-template"
 | |
|       );
 | |
|       this.appendChild(template.content.cloneNode(true));
 | |
| 
 | |
|       this._actionButton = this.querySelector(
 | |
|         ".unified-extensions-item-action-button"
 | |
|       );
 | |
|       this._menuButton = this.querySelector(
 | |
|         ".unified-extensions-item-menu-button"
 | |
|       );
 | |
|       this._messageDeck = this.querySelector(
 | |
|         ".unified-extensions-item-message-deck"
 | |
|       );
 | |
| 
 | |
|       // Focus/blur events are fired on specific elements only.
 | |
|       this._actionButton.addEventListener("blur", this);
 | |
|       this._actionButton.addEventListener("focus", this);
 | |
|       this._menuButton.addEventListener("blur", this);
 | |
|       this._menuButton.addEventListener("focus", this);
 | |
| 
 | |
|       this.addEventListener("command", this);
 | |
|       this.addEventListener("mouseout", this);
 | |
|       this.addEventListener("mouseover", this);
 | |
| 
 | |
|       this.render();
 | |
|     }
 | |
| 
 | |
|     handleEvent(event) {
 | |
|       const { target } = event;
 | |
| 
 | |
|       switch (event.type) {
 | |
|         case "command":
 | |
|           if (target === this._menuButton) {
 | |
|             const popup = target.ownerDocument.getElementById(
 | |
|               "unified-extensions-context-menu"
 | |
|             );
 | |
|             // Anchor to the visible part of the button.
 | |
|             const anchor = target.firstElementChild;
 | |
|             popup.openPopup(
 | |
|               anchor,
 | |
|               "after_end",
 | |
|               0,
 | |
|               0,
 | |
|               true /* isContextMenu */,
 | |
|               false /* attributesOverride */,
 | |
|               event
 | |
|             );
 | |
|           } else if (target === this._actionButton) {
 | |
|             const win = event.target.ownerGlobal;
 | |
|             const tab = win.gBrowser.selectedTab;
 | |
| 
 | |
|             this.extension.tabManager.addActiveTabPermission(tab);
 | |
|             this.extension.tabManager.activateScripts(tab);
 | |
|           }
 | |
|           break;
 | |
| 
 | |
|         case "blur":
 | |
|         case "mouseout":
 | |
|           this._messageDeck.selectedIndex =
 | |
|             gUnifiedExtensions.MESSAGE_DECK_INDEX_DEFAULT;
 | |
|           break;
 | |
| 
 | |
|         case "focus":
 | |
|         case "mouseover":
 | |
|           if (target === this._menuButton) {
 | |
|             this._messageDeck.selectedIndex =
 | |
|               gUnifiedExtensions.MESSAGE_DECK_INDEX_MENU_HOVER;
 | |
|           } else if (target === this._actionButton) {
 | |
|             this._messageDeck.selectedIndex =
 | |
|               gUnifiedExtensions.MESSAGE_DECK_INDEX_HOVER;
 | |
|           }
 | |
|           break;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     #setStateMessage() {
 | |
|       const messages = OriginControls.getStateMessageIDs({
 | |
|         policy: this.extension.policy,
 | |
|         tab: this.ownerGlobal.gBrowser.selectedTab,
 | |
|       });
 | |
| 
 | |
|       if (!messages) {
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|       const messageDefaultElement = this.querySelector(
 | |
|         ".unified-extensions-item-message-default"
 | |
|       );
 | |
|       this.ownerDocument.l10n.setAttributes(
 | |
|         messageDefaultElement,
 | |
|         messages.default
 | |
|       );
 | |
| 
 | |
|       const messageHoverElement = this.querySelector(
 | |
|         ".unified-extensions-item-message-hover"
 | |
|       );
 | |
|       this.ownerDocument.l10n.setAttributes(
 | |
|         messageHoverElement,
 | |
|         messages.onHover || messages.default
 | |
|       );
 | |
|     }
 | |
| 
 | |
|     #hasAction() {
 | |
|       const state = OriginControls.getState(
 | |
|         this.extension.policy,
 | |
|         this.ownerGlobal.gBrowser.selectedTab
 | |
|       );
 | |
| 
 | |
|       return state && state.whenClicked && !state.hasAccess;
 | |
|     }
 | |
| 
 | |
|     render() {
 | |
|       if (!this.extension) {
 | |
|         throw new Error(
 | |
|           "unified-extensions-item requires an extension, forgot to call setExtension()?"
 | |
|         );
 | |
|       }
 | |
| 
 | |
|       this.setAttribute("extension-id", this.extension.id);
 | |
|       this.classList.add(
 | |
|         "toolbaritem-combined-buttons",
 | |
|         "unified-extensions-item"
 | |
|       );
 | |
| 
 | |
|       // The data-extensionid attribute is used by context menu handlers
 | |
|       // to identify the extension being manipulated by the context menu.
 | |
|       this._actionButton.dataset.extensionid = this.extension.id;
 | |
| 
 | |
|       this.toggleAttribute(
 | |
|         "attention",
 | |
|         OriginControls.getAttention(this.extension.policy, this.ownerGlobal)
 | |
|       );
 | |
| 
 | |
|       this.querySelector(".unified-extensions-item-name").textContent =
 | |
|         this.extension.name;
 | |
| 
 | |
|       AddonManager.getAddonByID(this.extension.id).then(addon => {
 | |
|         const iconURL = AddonManager.getPreferredIconURL(addon, 32, window);
 | |
|         if (iconURL) {
 | |
|           this.querySelector(".unified-extensions-item-icon").setAttribute(
 | |
|             "src",
 | |
|             iconURL
 | |
|           );
 | |
|         }
 | |
|       });
 | |
| 
 | |
|       this._actionButton.disabled = !this.#hasAction();
 | |
| 
 | |
|       // The data-extensionid attribute is used by context menu handlers
 | |
|       // to identify the extension being manipulated by the context menu.
 | |
|       this._menuButton.dataset.extensionid = this.extension.id;
 | |
|       this._menuButton.setAttribute(
 | |
|         "data-l10n-args",
 | |
|         JSON.stringify({ extensionName: this.extension.name })
 | |
|       );
 | |
| 
 | |
|       this.#setStateMessage();
 | |
|     }
 | |
|   }
 | |
| );
 |