aboutsummaryrefslogtreecommitdiffstats
path: root/js/vapi-contextmenu.js
diff options
context:
space:
mode:
authorAlessio Vanni <vannilla@firemail.cc>2019-07-19 16:11:45 +0200
committerAlessio Vanni <vannilla@firemail.cc>2019-07-19 16:11:45 +0200
commit1ec6e70fc1df5f804f8ec254055fce3775123785 (patch)
tree03910671df22785ea18be4415eb6c14d8553d329 /js/vapi-contextmenu.js
parenta835d88e7fb3b5f01614985958bc68dd7f9e78cc (diff)
parentacd097e4733c106a15815c90e21c00d0c545e042 (diff)
downloadematrix-1ec6e70fc1df5f804f8ec254055fce3775123785.tar.lz
ematrix-1ec6e70fc1df5f804f8ec254055fce3775123785.tar.xz
ematrix-1ec6e70fc1df5f804f8ec254055fce3775123785.zip
Merge branch 'rewrite-vapi'
Diffstat (limited to 'js/vapi-contextmenu.js')
-rw-r--r--js/vapi-contextmenu.js212
1 files changed, 212 insertions, 0 deletions
diff --git a/js/vapi-contextmenu.js b/js/vapi-contextmenu.js
new file mode 100644
index 0000000..b0f8694
--- /dev/null
+++ b/js/vapi-contextmenu.js
@@ -0,0 +1,212 @@
+/*******************************************************************************
+
+ ηMatrix - a browser extension to black/white list requests.
+ Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors
+ Copyright (C) 2019 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://gitlab.com/vannilla/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;
+ };
+})();