/******************************************************************************* ηMatrix - a browser extension to black/white list requests. Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors Copyright (C) 2019-2020 Alessio Vanni This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see {http://www.gnu.org/licenses/}. Home: https://libregit.spks.xyz/heckyel/ematrix uMatrix Home: https://github.com/gorhill/uMatrix */ 'use strict'; /******************************************************************************/ (function () { vAPI.contextMenu = { contextMap: { frame: 'inFrame', link: 'onLink', image: 'onImage', audio: 'onAudio', video: 'onVideo', editable: 'onEditableArea' } }; vAPI.contextMenu.displayMenuItem = function ({target}) { let doc = target.ownerDocument; let gContextMenu = doc.defaultView.gContextMenu; if (!gContextMenu.browser) { return; } let menuitem = doc.getElementById(vAPI.contextMenu.menuItemId); let currentURI = gContextMenu.browser.currentURI; // https://github.com/chrisaljoudi/uBlock/issues/105 // TODO: Should the element picker works on any kind of pages? if (!currentURI.schemeIs('http') && !currentURI.schemeIs('https')) { menuitem.setAttribute('hidden', true); return; } let ctx = vAPI.contextMenu.contexts; if (!ctx) { menuitem.setAttribute('hidden', false); return; } let ctxMap = vAPI.contextMenu.contextMap; for (let context of ctx) { if (context === 'page' && !gContextMenu.onLink && !gContextMenu.onImage && !gContextMenu.onEditableArea && !gContextMenu.inFrame && !gContextMenu.onVideo && !gContextMenu.onAudio) { menuitem.setAttribute('hidden', false); return; } if (ctxMap.hasOwnProperty(context) && gContextMenu[ctxMap[context]]) { menuitem.setAttribute('hidden', false); return; } } menuitem.setAttribute('hidden', true); }; vAPI.contextMenu.register = (function () { let register = function (doc) { if (!this.menuItemId) { return; } // Already installed? if (doc.getElementById(this.menuItemId) !== null) { return; } let contextMenu = doc.getElementById('contentAreaContextMenu'); let menuitem = doc.createElement('menuitem'); menuitem.setAttribute('id', this.menuItemId); menuitem.setAttribute('label', this.menuLabel); menuitem.setAttribute('image', vAPI.getURL('img/browsericons/icon19-19.png')); menuitem.setAttribute('class', 'menuitem-iconic'); menuitem.addEventListener('command', this.onCommand); contextMenu.addEventListener('popupshowing', this.displayMenuItem); contextMenu.insertBefore(menuitem, doc.getElementById('inspect-separator')); }; let registerSafely = function (doc, tryCount) { // https://github.com/gorhill/uBlock/issues/906 // Be sure document.readyState is 'complete': it could happen // at launch time that we are called by // vAPI.contextMenu.create() directly before the environment // is properly initialized. if (doc.readyState === 'complete') { register.call(this, doc); return; } if (typeof tryCount !== 'number') { tryCount = 0; } tryCount += 1; if (tryCount < 8) { vAPI.setTimeout(registerSafely.bind(this, doc, tryCount), 200); } }; return registerSafely; })(); vAPI.contextMenu.unregister = function (doc) { if (!this.menuItemId) { return; } let menuitem = doc.getElementById(this.menuItemId); if (menuitem === null) { return; } let contextMenu = menuitem.parentNode; menuitem.removeEventListener('command', this.onCommand); contextMenu.removeEventListener('popupshowing', this.displayMenuItem); contextMenu.removeChild(menuitem); }; vAPI.contextMenu.create = function (details, callback) { this.menuItemId = details.id; this.menuLabel = details.title; this.contexts = details.contexts; if (Array.isArray(this.contexts) && this.contexts.length) { this.contexts = this.contexts.indexOf('all') === -1 ? this.contexts : null; } else { // default in Chrome this.contexts = ['page']; } this.onCommand = function () { let gContextMenu = vAPI.browser.getOwnerWindow(this).gContextMenu; let details = { menuItemId: this.id }; if (gContextMenu.inFrame) { details.tagName = 'iframe'; // Probably won't work with e10s // eMatrix: doesn't matter ;) details.frameUrl = gContextMenu.focusedWindow.location.href; } else if (gContextMenu.onImage) { details.tagName = 'img'; details.srcUrl = gContextMenu.mediaURL; } else if (gContextMenu.onAudio) { details.tagName = 'audio'; details.srcUrl = gContextMenu.mediaURL; } else if (gContextMenu.onVideo) { details.tagName = 'video'; details.srcUrl = gContextMenu.mediaURL; } else if (gContextMenu.onLink) { details.tagName = 'a'; details.linkUrl = gContextMenu.linkURL; } callback(details, { id: vAPI.tabs.manager.tabIdFromTarget(gContextMenu.browser), url: gContextMenu.browser.currentURI.asciiSpec }); }; for (let win of vAPI.window.getWindows()) { this.register(win.document); } }; vAPI.contextMenu.remove = function () { for (let win of vAPI.window.getWindows()) { this.unregister(win.document); } this.menuItemId = null; this.menuLabel = null; this.contexts = null; this.onCommand = null; }; })();