├── .gitignore ├── firefox-only ├── _locales │ └── en │ │ └── messages.json ├── background.js ├── data │ ├── icons │ │ ├── 128.png │ │ ├── 16.png │ │ ├── 18.png │ │ ├── 19.png │ │ ├── 256.png │ │ ├── 32.png │ │ ├── 36.png │ │ ├── 38.png │ │ ├── 48.png │ │ ├── 64.png │ │ └── n │ │ │ ├── 128.png │ │ │ ├── 16.png │ │ │ ├── 18.png │ │ │ ├── 19.png │ │ │ ├── 32.png │ │ │ ├── 36.png │ │ │ ├── 38.png │ │ │ ├── 48.png │ │ │ └── 64.png │ └── options │ │ ├── index.html │ │ ├── index.js │ │ ├── matched.js │ │ └── matched.json └── manifest.json ├── v1 ├── builds │ ├── packed │ │ ├── chrome.zip │ │ ├── firefox.xpi │ │ ├── icon.png │ │ └── icon64.png │ └── unpacked │ │ └── chrome │ │ ├── data │ │ └── icons │ │ │ ├── 128.png │ │ │ ├── 16.png │ │ │ ├── 18.png │ │ │ ├── 19.png │ │ │ ├── 256.png │ │ │ ├── 32.png │ │ │ ├── 36.png │ │ │ ├── 38.png │ │ │ ├── 48.png │ │ │ ├── 64.png │ │ │ └── n │ │ │ ├── 128.png │ │ │ ├── 16.png │ │ │ ├── 18.png │ │ │ ├── 19.png │ │ │ ├── 32.png │ │ │ ├── 36.png │ │ │ ├── 38.png │ │ │ ├── 48.png │ │ │ └── 64.png │ │ ├── lib │ │ ├── background.js │ │ ├── chrome │ │ │ └── chrome.js │ │ └── config.js │ │ └── manifest.json ├── gulpfile.js └── src │ ├── data │ └── icons │ │ ├── 128.png │ │ ├── 16.png │ │ ├── 18.png │ │ ├── 19.png │ │ ├── 256.png │ │ ├── 32.png │ │ ├── 36.png │ │ ├── 38.png │ │ ├── 48.png │ │ ├── 64.png │ │ └── n │ │ ├── 128.png │ │ ├── 16.png │ │ ├── 18.png │ │ ├── 19.png │ │ ├── 32.png │ │ ├── 36.png │ │ ├── 38.png │ │ ├── 48.png │ │ └── 64.png │ ├── lib │ ├── background.js │ ├── chrome │ │ └── chrome.js │ ├── config.js │ └── firefox │ │ └── firefox.js │ ├── manifest.json │ └── package.json ├── v2 ├── _locales ├── background.js ├── data └── manifest.json └── v3 ├── _locales ├── bg │ └── messages.json ├── cs │ └── messages.json ├── da │ └── messages.json ├── de │ └── messages.json ├── el │ └── messages.json ├── en │ └── messages.json ├── et │ └── messages.json ├── fi │ └── messages.json ├── fr │ └── messages.json ├── hu │ └── messages.json ├── nl │ └── messages.json └── zh_CN │ └── messages.json ├── data ├── icons │ ├── 128.png │ ├── 16.png │ ├── 256.png │ ├── 32.png │ ├── 48.png │ ├── 64.png │ ├── a │ │ ├── 128.png │ │ ├── 16.png │ │ └── 32.png │ ├── d │ │ ├── 128.png │ │ ├── 16.png │ │ └── 32.png │ └── n │ │ ├── 16.png │ │ └── 32.png └── options │ ├── index.css │ ├── index.html │ └── index.js ├── manifest.json └── worker.js /.gitignore: -------------------------------------------------------------------------------- 1 | addon-sdk* 2 | node_modules 3 | builds/unpacked 4 | test/ 5 | .DS_Store 6 | Thumbs.db 7 | -------------------------------------------------------------------------------- /firefox-only/_locales/en/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "app_description": { 3 | "message": "Toggle JavaScript engines (inline, data URL, remote, and external) on and off the easy way" 4 | }, 5 | "options_title": { 6 | "message": "Options :: JavaScript Toggle On and Off" 7 | }, 8 | "options_refresh_enabled": { 9 | "message": "Refresh current webpage when JavaScript engine is toggled to \"Enabled\"" 10 | }, 11 | "options_refresh_disabled": { 12 | "message": "Refresh current webpage when JavaScript engine is toggled to \"Disabled\"" 13 | }, 14 | "options_badge": { 15 | "message": "Add badge \"d\" to the toolbar button when JavaScript is disabled (to better distinguish between two states)" 16 | }, 17 | "options_whitelist": { 18 | "message": "White-list (Comma separated list of domains to allow JS when it is globally disallowed):" 19 | }, 20 | "options_blacklist": { 21 | "message": "Black-list (Comma separated list of domains to disallow JS when it is globally allowed):" 22 | }, 23 | "options_reset": { 24 | "message": "Factory Reset" 25 | }, 26 | "options_support": { 27 | "message": "Support Development" 28 | }, 29 | "options_save": { 30 | "message": "Save" 31 | }, 32 | "bg_disable": { 33 | "message": "Click to disable JavaScript" 34 | }, 35 | "bg_enable": { 36 | "message": "Click to enable JavaScript" 37 | }, 38 | "bg_warning": { 39 | "message": "This extension only works on HTTP and HTTPS schemes" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /firefox-only/background.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let badge = false; 4 | let tab; 5 | 6 | const app = { 7 | title: title => { 8 | chrome.browserAction.setTitle({ 9 | title 10 | }); 11 | }, 12 | icon: (path = '') => { 13 | if (chrome.browserAction.setIcon) { 14 | chrome.browserAction.setIcon({ 15 | path: { 16 | '19': 'data/icons' + path + '/19.png', 17 | '38': 'data/icons' + path + '/38.png' 18 | } 19 | }); 20 | } 21 | if (badge && chrome.browserAction.setBadgeText) { 22 | chrome.browserAction.setBadgeText({ 23 | text: path ? 'd' : '' 24 | }); 25 | } 26 | } 27 | }; 28 | 29 | const refresh = () => chrome.storage.local.get({ 30 | 'refresh-enabled': true, 31 | 'refresh-disabled': true, 32 | 'state': true 33 | }, prefs => { 34 | if (tab && tab.url && tab.url.startsWith('http')) { 35 | if ((prefs.state && prefs['refresh-enabled']) || (prefs.state === false && prefs['refresh-disabled'])) { 36 | chrome.tabs.reload(tab.id, { 37 | bypassCache: true 38 | }); 39 | } 40 | } 41 | tab = null; 42 | }); 43 | 44 | const getHost = tab => tab.url.split('://')[1].split('/')[0]; 45 | 46 | const js = { 47 | whitelist: [], 48 | blacklist: [], 49 | whiteListen: d => { 50 | const hostname = getHost(d); 51 | for (const h of js.whitelist) { 52 | if (hostname.endsWith(h)) { 53 | return; 54 | } 55 | } 56 | const responseHeaders = d.responseHeaders; 57 | responseHeaders.push({ 58 | 'name': 'Content-Security-Policy', 59 | 'value': 'script-src \'none\'' 60 | }); 61 | return {responseHeaders}; 62 | }, 63 | blackListen: d => { 64 | const hostname = getHost(d); 65 | for (const h of js.blacklist) { 66 | if (hostname.endsWith(h)) { 67 | const responseHeaders = d.responseHeaders; 68 | responseHeaders.push({ 69 | 'name': 'Content-Security-Policy', 70 | 'value': 'script-src \'none\'' 71 | }); 72 | return {responseHeaders}; 73 | } 74 | } 75 | return; 76 | }, 77 | enable: () => { 78 | chrome.webRequest.onHeadersReceived.removeListener(js.whiteListen); 79 | chrome.webRequest.onHeadersReceived.addListener( 80 | js.blackListen, 81 | { 82 | 'urls': ['*://*/*'], 83 | 'types': [ 84 | 'main_frame', 85 | 'sub_frame' 86 | ] 87 | }, 88 | ['blocking', 'responseHeaders'] 89 | ); 90 | window.setTimeout(refresh, 10); 91 | app.icon(); 92 | app.title(chrome.i18n.getMessage('bg_disable')); 93 | }, 94 | disable: () => { 95 | chrome.webRequest.onHeadersReceived.removeListener(js.blackListen); 96 | chrome.webRequest.onHeadersReceived.addListener( 97 | js.whiteListen, 98 | { 99 | 'urls': ['*://*/*'], 100 | 'types': [ 101 | 'main_frame', 102 | 'sub_frame' 103 | ] 104 | }, 105 | ['blocking', 'responseHeaders'] 106 | ); 107 | window.setTimeout(refresh, 10); 108 | app.icon('/n'); 109 | app.title(chrome.i18n.getMessage('bg_enable')); 110 | } 111 | }; 112 | 113 | chrome.storage.local.get({ 114 | state: true, 115 | badge: false, 116 | whitelist: [], 117 | blacklist: [] 118 | }, prefs => { 119 | badge = prefs.badge; 120 | js.whitelist = prefs.whitelist; 121 | js.blacklist = prefs.blacklist; 122 | js[prefs.state ? 'enable' : 'disable'](); 123 | }); 124 | 125 | chrome.storage.onChanged.addListener(prefs => { 126 | if (prefs.state) { 127 | js[prefs.state.newValue ? 'enable' : 'disable'](); 128 | } 129 | if (prefs.whitelist) { 130 | js.whitelist = prefs.whitelist.newValue; 131 | } 132 | if (prefs.blacklist) { 133 | js.blacklist = prefs.blacklist.newValue; 134 | } 135 | if (prefs.badge) { 136 | badge = prefs.badge.newValue; 137 | } 138 | }); 139 | // 140 | const onClicked = t => { 141 | tab = t; 142 | chrome.storage.local.get({ 143 | state: true 144 | }, prefs => { 145 | prefs.state = !prefs.state; 146 | chrome.storage.local.set(prefs); 147 | }); 148 | }; 149 | chrome.browserAction.onClicked.addListener(onClicked); 150 | chrome.commands.onCommand.addListener(() => { 151 | chrome.tabs.query({ 152 | active: true, 153 | currentWindow: true 154 | }, tabs => { 155 | if (tabs && tabs.length) { 156 | onClicked(tabs[0]); 157 | } 158 | }); 159 | }); 160 | // 161 | if (chrome.contextMenus) { 162 | chrome.contextMenus.create({ 163 | id: 'open-test-page', 164 | title: 'Check JavaScript execution', 165 | contexts: ['browser_action'] 166 | }); 167 | chrome.contextMenus.create({ 168 | id: 'open-settings', 169 | title: 'Open settings', 170 | contexts: ['browser_action'] 171 | }); 172 | chrome.contextMenus.create({ 173 | id: 'separator', 174 | type: 'separator', 175 | documentUrlPatterns: ['http://*/*', 'https://*/*'] 176 | }); 177 | chrome.contextMenus.create({ 178 | id: 'whitelist-toggle', 179 | title: 'Add to or remove from whitelist', 180 | contexts: ['browser_action'], 181 | documentUrlPatterns: ['http://*/*', 'https://*/*'] 182 | }); 183 | chrome.contextMenus.create({ 184 | id: 'blacklist-toggle', 185 | title: 'Add to or remove from blacklist', 186 | contexts: ['browser_action'], 187 | documentUrlPatterns: ['http://*/*', 'https://*/*'] 188 | }); 189 | 190 | chrome.contextMenus.onClicked.addListener((info, t) => { 191 | if (info.menuItemId === 'open-test-page') { 192 | chrome.tabs.create({ 193 | url: 'https://webbrowsertools.com/javascript/?rand=' + Math.random() 194 | }); 195 | } 196 | else if (info.menuItemId === 'open-settings') { 197 | chrome.runtime.openOptionsPage(); 198 | } 199 | else if (info.menuItemId === 'whitelist-toggle' || info.menuItemId === 'blacklist-toggle') { 200 | const hostname = getHost(t); 201 | const type = info.menuItemId.replace('-toggle', ''); 202 | const index = js[type].indexOf(hostname); 203 | if (index > -1) { 204 | js[type].splice(index, 1); 205 | } 206 | else { 207 | js[type].push(hostname); 208 | } 209 | chrome.notifications.create({ 210 | title: chrome.runtime.getManifest().name, 211 | type: 'basic', 212 | iconUrl: 'data/icons/48.png', 213 | message: index > -1 ? `"${hostname}" is removed from the ${type}` : `"${hostname}" is added to the ${type}` 214 | }); 215 | chrome.storage.local.set({ 216 | [type]: js[type] 217 | }, () => { 218 | tab = t; 219 | refresh(); 220 | }); 221 | } 222 | }); 223 | } 224 | // FAQs & Feedback 225 | { 226 | const {onInstalled, setUninstallURL, getManifest} = chrome.runtime; 227 | const {name, version} = getManifest(); 228 | const page = getManifest().homepage_url; 229 | onInstalled.addListener(({reason, previousVersion}) => { 230 | chrome.storage.local.get({ 231 | 'faqs': true, 232 | 'last-update': 0 233 | }, prefs => { 234 | if (reason === 'install' || (prefs.faqs && reason === 'update')) { 235 | const doUpdate = (Date.now() - prefs['last-update']) / 1000 / 60 / 60 / 24 > 45; 236 | if (doUpdate && previousVersion !== version) { 237 | chrome.tabs.create({ 238 | url: page + '?version=' + version + 239 | (previousVersion ? '&p=' + previousVersion : '') + 240 | '&type=' + reason, 241 | active: reason === 'install' 242 | }); 243 | chrome.storage.local.set({'last-update': Date.now()}); 244 | } 245 | } 246 | }); 247 | }); 248 | setUninstallURL(page + '?rd=feedback&name=' + encodeURIComponent(name) + '&version=' + version); 249 | } 250 | -------------------------------------------------------------------------------- /firefox-only/data/icons/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/firefox-only/data/icons/128.png -------------------------------------------------------------------------------- /firefox-only/data/icons/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/firefox-only/data/icons/16.png -------------------------------------------------------------------------------- /firefox-only/data/icons/18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/firefox-only/data/icons/18.png -------------------------------------------------------------------------------- /firefox-only/data/icons/19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/firefox-only/data/icons/19.png -------------------------------------------------------------------------------- /firefox-only/data/icons/256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/firefox-only/data/icons/256.png -------------------------------------------------------------------------------- /firefox-only/data/icons/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/firefox-only/data/icons/32.png -------------------------------------------------------------------------------- /firefox-only/data/icons/36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/firefox-only/data/icons/36.png -------------------------------------------------------------------------------- /firefox-only/data/icons/38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/firefox-only/data/icons/38.png -------------------------------------------------------------------------------- /firefox-only/data/icons/48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/firefox-only/data/icons/48.png -------------------------------------------------------------------------------- /firefox-only/data/icons/64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/firefox-only/data/icons/64.png -------------------------------------------------------------------------------- /firefox-only/data/icons/n/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/firefox-only/data/icons/n/128.png -------------------------------------------------------------------------------- /firefox-only/data/icons/n/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/firefox-only/data/icons/n/16.png -------------------------------------------------------------------------------- /firefox-only/data/icons/n/18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/firefox-only/data/icons/n/18.png -------------------------------------------------------------------------------- /firefox-only/data/icons/n/19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/firefox-only/data/icons/n/19.png -------------------------------------------------------------------------------- /firefox-only/data/icons/n/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/firefox-only/data/icons/n/32.png -------------------------------------------------------------------------------- /firefox-only/data/icons/n/36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/firefox-only/data/icons/n/36.png -------------------------------------------------------------------------------- /firefox-only/data/icons/n/38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/firefox-only/data/icons/n/38.png -------------------------------------------------------------------------------- /firefox-only/data/icons/n/48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/firefox-only/data/icons/n/48.png -------------------------------------------------------------------------------- /firefox-only/data/icons/n/64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/firefox-only/data/icons/n/64.png -------------------------------------------------------------------------------- /firefox-only/data/options/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 |
33 | 34 |

35 | 39 |

40 | 41 |

42 | 46 |

47 | 48 |
49 | 50 |
51 | 52 | - 53 | 54 |
55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /firefox-only/data/options/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // localization 4 | [...document.querySelectorAll('[data-i18n]')].forEach(e => { 5 | e.textContent = chrome.i18n.getMessage(e.dataset.i18n); 6 | }); 7 | 8 | const toast = document.getElementById('toast'); 9 | 10 | function restore() { 11 | chrome.storage.local.get({ 12 | 'whitelist': [], 13 | 'blacklist': [], 14 | 'refresh-enabled': true, 15 | 'refresh-disabled': true, 16 | 'badge': false 17 | }, prefs => { 18 | document.getElementById('whitelist').value = prefs.whitelist.join(', '); 19 | document.getElementById('blacklist').value = prefs.blacklist.join(', '); 20 | document.getElementById('refresh-enabled').checked = prefs['refresh-enabled']; 21 | document.getElementById('refresh-disabled').checked = prefs['refresh-disabled']; 22 | document.getElementById('badge').checked = prefs.badge; 23 | }); 24 | } 25 | function save() { 26 | let whitelist = document.getElementById('whitelist').value; 27 | whitelist = whitelist.split(/\s*,\s*/).map(s => { 28 | return s.replace('http://', '').replace('https://', '').split('/')[0].trim(); 29 | }).filter((h, i, l) => h && l.indexOf(h) === i); 30 | 31 | let blacklist = document.getElementById('blacklist').value; 32 | blacklist = blacklist.split(/\s*,\s*/).map(s => { 33 | return s.replace('http://', '').replace('https://', '').split('/')[0].trim(); 34 | }).filter((h, i, l) => h && l.indexOf(h) === i); 35 | 36 | chrome.storage.local.set({ 37 | whitelist, 38 | blacklist, 39 | 'refresh-enabled': document.getElementById('refresh-enabled').checked, 40 | 'refresh-disabled': document.getElementById('refresh-disabled').checked, 41 | 'badge': document.getElementById('badge').checked 42 | }, () => { 43 | restore(); 44 | toast.textContent = 'Options saved.'; 45 | setTimeout(() => toast.textContent = '', 750); 46 | chrome.storage.local.get({ 47 | 'badge': false, 48 | 'state': false 49 | }, prefs => chrome.browserAction.setBadgeText({ 50 | text: prefs.badge && prefs.state === false ? 'd' : '' 51 | })); 52 | }); 53 | } 54 | 55 | document.addEventListener('DOMContentLoaded', restore); 56 | document.getElementById('save').addEventListener('click', save); 57 | 58 | // reset 59 | document.getElementById('reset').addEventListener('click', e => { 60 | if (e.detail === 1) { 61 | toast.textContent = 'Double-click to reset!'; 62 | window.setTimeout(() => toast.textContent = '', 750); 63 | } 64 | else { 65 | localStorage.clear(); 66 | chrome.storage.local.clear(() => { 67 | chrome.runtime.reload(); 68 | window.close(); 69 | }); 70 | } 71 | }); 72 | // support 73 | document.getElementById('support').addEventListener('click', () => chrome.tabs.create({ 74 | url: chrome.runtime.getManifest().homepage_url + '?rd=donate' 75 | })); 76 | -------------------------------------------------------------------------------- /firefox-only/data/options/matched.js: -------------------------------------------------------------------------------- 1 | ../../../../_/matched/matched.js -------------------------------------------------------------------------------- /firefox-only/data/options/matched.json: -------------------------------------------------------------------------------- 1 | ../../../../_/matched/matched.json -------------------------------------------------------------------------------- /firefox-only/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "JavaScript Toggle On and Off", 3 | "description": "__MSG_app_description__", 4 | "version": "0.2.4", 5 | "manifest_version": 2, 6 | "default_locale": "en", 7 | "permissions": [ 8 | "storage", 9 | "tabs", 10 | "contextMenus", 11 | "", 12 | "webRequest", 13 | "webRequestBlocking", 14 | "notifications" 15 | ], 16 | "browser_action": {}, 17 | "background": { 18 | "scripts": [ 19 | "background.js" 20 | ] 21 | }, 22 | "homepage_url": "https://add0n.com/javascript-toggler.html", 23 | "icons": { 24 | "16": "data/icons/16.png", 25 | "18": "data/icons/18.png", 26 | "19": "data/icons/19.png", 27 | "32": "data/icons/32.png", 28 | "36": "data/icons/36.png", 29 | "38": "data/icons/38.png", 30 | "48": "data/icons/48.png", 31 | "64": "data/icons/64.png", 32 | "128": "data/icons/128.png", 33 | "256": "data/icons/256.png" 34 | }, 35 | "options_ui": { 36 | "page": "data/options/index.html", 37 | "chrome_style": true 38 | }, 39 | "commands": { 40 | "toggle-javascript-engine": { 41 | "suggested_key": { 42 | "default": "Alt+Shift+L" 43 | }, 44 | "description": "Toggle JavaScript Engine" 45 | } 46 | }, 47 | "applications": { 48 | "gecko": { 49 | "id": "{479f0278-2c34-4365-b9f0-1d328d0f0a40}", 50 | "strict_min_version": "57.0" 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /v1/builds/packed/chrome.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/builds/packed/chrome.zip -------------------------------------------------------------------------------- /v1/builds/packed/firefox.xpi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/builds/packed/firefox.xpi -------------------------------------------------------------------------------- /v1/builds/packed/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/builds/packed/icon.png -------------------------------------------------------------------------------- /v1/builds/packed/icon64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/builds/packed/icon64.png -------------------------------------------------------------------------------- /v1/builds/unpacked/chrome/data/icons/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/builds/unpacked/chrome/data/icons/128.png -------------------------------------------------------------------------------- /v1/builds/unpacked/chrome/data/icons/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/builds/unpacked/chrome/data/icons/16.png -------------------------------------------------------------------------------- /v1/builds/unpacked/chrome/data/icons/18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/builds/unpacked/chrome/data/icons/18.png -------------------------------------------------------------------------------- /v1/builds/unpacked/chrome/data/icons/19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/builds/unpacked/chrome/data/icons/19.png -------------------------------------------------------------------------------- /v1/builds/unpacked/chrome/data/icons/256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/builds/unpacked/chrome/data/icons/256.png -------------------------------------------------------------------------------- /v1/builds/unpacked/chrome/data/icons/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/builds/unpacked/chrome/data/icons/32.png -------------------------------------------------------------------------------- /v1/builds/unpacked/chrome/data/icons/36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/builds/unpacked/chrome/data/icons/36.png -------------------------------------------------------------------------------- /v1/builds/unpacked/chrome/data/icons/38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/builds/unpacked/chrome/data/icons/38.png -------------------------------------------------------------------------------- /v1/builds/unpacked/chrome/data/icons/48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/builds/unpacked/chrome/data/icons/48.png -------------------------------------------------------------------------------- /v1/builds/unpacked/chrome/data/icons/64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/builds/unpacked/chrome/data/icons/64.png -------------------------------------------------------------------------------- /v1/builds/unpacked/chrome/data/icons/n/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/builds/unpacked/chrome/data/icons/n/128.png -------------------------------------------------------------------------------- /v1/builds/unpacked/chrome/data/icons/n/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/builds/unpacked/chrome/data/icons/n/16.png -------------------------------------------------------------------------------- /v1/builds/unpacked/chrome/data/icons/n/18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/builds/unpacked/chrome/data/icons/n/18.png -------------------------------------------------------------------------------- /v1/builds/unpacked/chrome/data/icons/n/19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/builds/unpacked/chrome/data/icons/n/19.png -------------------------------------------------------------------------------- /v1/builds/unpacked/chrome/data/icons/n/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/builds/unpacked/chrome/data/icons/n/32.png -------------------------------------------------------------------------------- /v1/builds/unpacked/chrome/data/icons/n/36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/builds/unpacked/chrome/data/icons/n/36.png -------------------------------------------------------------------------------- /v1/builds/unpacked/chrome/data/icons/n/38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/builds/unpacked/chrome/data/icons/n/38.png -------------------------------------------------------------------------------- /v1/builds/unpacked/chrome/data/icons/n/48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/builds/unpacked/chrome/data/icons/n/48.png -------------------------------------------------------------------------------- /v1/builds/unpacked/chrome/data/icons/n/64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/builds/unpacked/chrome/data/icons/n/64.png -------------------------------------------------------------------------------- /v1/builds/unpacked/chrome/lib/background.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var app = app || require('./firefox/firefox'); 4 | var config = config || require('./config'); 5 | 6 | function checkState () { 7 | app.button.icon = config.js.state ? 'icons' : 'icons/n'; 8 | app.button.label = 'JavaScript Toggle On and Off\n\n' + 9 | `JavaScript is "${config.js.state ? 'Enabled' : 'Disabled'}"`; 10 | } 11 | 12 | var blocker = (function () { 13 | let listener = function (details) { 14 | let headers = details.responseHeaders; 15 | headers.push({ 16 | 'name': 'Content-Security-Policy', 17 | 'value': "script-src 'none'" // jshint ignore:line 18 | }); 19 | return { 20 | responseHeaders: headers 21 | }; 22 | }; 23 | return { 24 | install: function () { 25 | app.webRequest.onHeadersReceived.addListener(listener, 26 | { 27 | 'urls': new app.MatchPattern(['']), 28 | 'types': [ 29 | 'main_frame', 30 | 'sub_frame' 31 | ] 32 | }, 33 | ['blocking', 'responseHeaders'] 34 | ); 35 | app.contentSettings.javascript.set({ 36 | primaryPattern: '', 37 | setting: 'block' 38 | }); 39 | }, 40 | remove: function () { 41 | app.webRequest.onHeadersReceived.removeListener(listener); 42 | app.contentSettings.javascript.set({ 43 | primaryPattern: '', 44 | setting: 'allow' 45 | }); 46 | } 47 | }; 48 | })(); 49 | app.unload(blocker.remove); 50 | 51 | app.button.onCommand(() => { 52 | config.js.state = !config.js.state; 53 | blocker[config.js.state ? 'remove' : 'install'](); 54 | checkState(); 55 | }); 56 | blocker[config.js.state ? 'remove' : 'install'](); 57 | checkState(); 58 | 59 | // 60 | app.contextMenus.create({ 61 | title: 'Check JavaScript execution', 62 | contexts: ['browser_action'], 63 | onclick: () => app.tab.open('http://tools.add0n.com/check-javascript.html?rand=' + Math.random()) 64 | }); 65 | 66 | // 67 | app.startup(function () { 68 | let version = config.welcome.version; 69 | if (app.version() !== version) { 70 | app.timers.setTimeout(function () { 71 | app.tab.open( 72 | 'http://add0n.com/javascript-toggler.html?v=' + app.version() + 73 | (version ? '&p=' + version + '&type=upgrade' : '&type=install') 74 | ); 75 | config.welcome.version = app.version(); 76 | }, config.welcome.timeout); 77 | } 78 | }); 79 | -------------------------------------------------------------------------------- /v1/builds/unpacked/chrome/lib/chrome/chrome.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var app = {}; 4 | 5 | app.storage = (function () { 6 | let objs = {}; 7 | chrome.storage.local.get(null, function (o) { 8 | objs = o; 9 | let script = document.createElement('script'); 10 | document.body.appendChild(script); 11 | script.src = 'lib/background.js'; 12 | }); 13 | return { 14 | read: (id) => objs[id], 15 | write: (id, data) => { 16 | objs[id] = data; 17 | let tmp = {}; 18 | tmp[id] = data; 19 | chrome.storage.local.set(tmp, function () {}); 20 | } 21 | }; 22 | })(); 23 | 24 | app.button = (function () { 25 | let onCommand; 26 | chrome.browserAction.onClicked.addListener(function () { 27 | if (onCommand) { 28 | onCommand(); 29 | } 30 | }); 31 | return { 32 | onCommand: (c) => onCommand = c, 33 | set icon (root) { // jshint ignore: line 34 | chrome.browserAction.setIcon({ 35 | path: { 36 | '19': '../../data/' + root + '/19.png', 37 | '38': '../../data/' + root + '/38.png' 38 | } 39 | }); 40 | }, 41 | set label (label) { // jshint ignore: line 42 | chrome.browserAction.setTitle({ 43 | title: label 44 | }); 45 | } 46 | }; 47 | })(); 48 | 49 | app.tab = { 50 | open: (url) => chrome.tabs.create({url}) 51 | }; 52 | 53 | app.version = () => chrome[chrome.runtime && chrome.runtime.getManifest ? 'runtime' : 'extension'].getManifest().version; 54 | 55 | app.timers = window; 56 | 57 | app.startup = (function () { 58 | let loadReason, callback; 59 | function check () { 60 | if (loadReason === 'startup' || loadReason === 'install') { 61 | if (callback) { 62 | callback(); 63 | } 64 | } 65 | } 66 | if (chrome.runtime.onInstalled && chrome.runtime.onStartup) { 67 | chrome.runtime.onInstalled.addListener(function (details) { 68 | loadReason = details.reason; 69 | check(); 70 | }); 71 | chrome.runtime.onStartup.addListener(function () { 72 | loadReason = 'startup'; 73 | check(); 74 | }); 75 | } 76 | else { 77 | loadReason = 'startup'; 78 | check(); 79 | } 80 | return (c) => { 81 | callback = c; 82 | check(); 83 | }; 84 | })(); 85 | 86 | app.unload = function () {}; 87 | 88 | app.MatchPattern = function (arr) { 89 | return arr; 90 | }; 91 | app.webRequest = chrome.webRequest; 92 | app.contentSettings = chrome.contentSettings; 93 | app.contextMenus = chrome.contextMenus; 94 | -------------------------------------------------------------------------------- /v1/builds/unpacked/chrome/lib/config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var config = typeof require === 'undefined' ? {} : exports; 4 | var app = app || require('./firefox/firefox'); 5 | 6 | config.js = { 7 | get state () { 8 | let state = app.storage.read('state'); 9 | return (state === undefined) ? true : state; 10 | }, 11 | set state (val) { 12 | app.storage.write('state', val); 13 | } 14 | }; 15 | 16 | config.welcome = { 17 | get version () { 18 | return app.storage.read('version'); 19 | }, 20 | set version (val) { 21 | app.storage.write('version', val); 22 | }, 23 | timeout: 3, 24 | get show () { 25 | let state = app.storage.read('show'); 26 | return (state === undefined) ? true : state; 27 | }, 28 | set show (val) { 29 | app.storage.write('show', val); 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /v1/builds/unpacked/chrome/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "JavaScript Toggle On and Off", 3 | "short_name": "ijtoaoff", 4 | "description": "Toggle JavaScript engine on and off the easy way", 5 | "author": "Richard Neomy", 6 | "version": "0.1.4", 7 | "manifest_version": 2, 8 | "permissions": [ 9 | "storage", 10 | "contentSettings", 11 | "contextMenus", 12 | "webRequest", 13 | "webRequestBlocking", 14 | "" 15 | ], 16 | "browser_action": { 17 | "default_icon": { 18 | "19": "data/icons/19.png", 19 | "38": "data/icons/38.png" 20 | } 21 | }, 22 | "background": { 23 | "scripts": [ 24 | "lib/chrome/chrome.js", 25 | "lib/config.js" 26 | ] 27 | }, 28 | "homepage_url": "http://add0n.com/javascript-toggler.html", 29 | "icons": { 30 | "16": "data/icons/16.png", 31 | "48": "data/icons/48.png", 32 | "128": "data/icons/128.png" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /v1/gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | var change = require('gulp-change'); 5 | var babel = require('gulp-babel'); 6 | var gulpif = require('gulp-if'); 7 | var gulpFilter = require('gulp-filter'); 8 | var shell = require('gulp-shell'); 9 | var wait = require('gulp-wait'); 10 | var clean = require('gulp-clean'); 11 | var zip = require('gulp-zip'); 12 | var rename = require('gulp-rename'); 13 | var util = require('gulp-util'); 14 | var runSequence = require('run-sequence'); 15 | 16 | /* clean */ 17 | gulp.task('clean', function () { 18 | return gulp.src([ 19 | 'builds/unpacked/chrome/*', 20 | 'builds/unpacked/firefox/*', 21 | ], {read: false}) 22 | .pipe(clean()); 23 | }); 24 | /* chrome build */ 25 | gulp.task('chrome-build', function () { 26 | gulp.src([ 27 | 'src/**/*' 28 | ]) 29 | .pipe(gulpFilter(function (f) { 30 | if (f.relative.indexOf('.DS_Store') !== -1 || f.relative.indexOf('Thumbs.db') !== -1) { 31 | return false; 32 | } 33 | if (f.relative.indexOf('firefox') !== -1 && f.relative.indexOf('firefox.png') === -1) { 34 | return false; 35 | } 36 | if (f.path.indexOf('/locale') !== -1) { 37 | return false; 38 | } 39 | if (f.relative.indexOf('safari') !== -1) { 40 | return false; 41 | } 42 | if (f.relative.split('/').length === 1) { 43 | return f.relative === 'manifest.json' ? true : false; 44 | } 45 | return true; 46 | })) 47 | .pipe(gulpif(function (f) { 48 | return f.path.indexOf('.js') !== -1 && f.path.indexOf('.json') === -1; 49 | }, change(function (content) { 50 | return content.replace(/\/\*\* wrapper[\s\S]*\\*\*\*\//m, ''); 51 | }))) 52 | .pipe(gulpif(function (f) { 53 | return f.path.indexOf('.html') !== -1; 54 | }, change(function (content) { 55 | return content.replace(/.*shadow_index\.js.*/, ' \n '); 56 | }))) 57 | .pipe(gulp.dest('builds/unpacked/chrome')) 58 | .pipe(zip('chrome.zip')) 59 | .pipe(gulp.dest('builds/packed')); 60 | }); 61 | gulp.task('chrome-install', function () { 62 | gulp.src('') 63 | .pipe(wait(1000)) 64 | .pipe(shell([ 65 | '"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --load-and-launch-app=`pwd` &' 66 | ], { 67 | cwd: './builds/unpacked/chrome' 68 | })); 69 | }); 70 | 71 | /* firefox build */ 72 | gulp.task('firefox-build', function () { 73 | gulp.src([ 74 | 'src/**/*' 75 | ]) 76 | .pipe(gulpFilter(function (f) { 77 | if (f.relative.indexOf('.DS_Store') !== -1 || f.relative.indexOf('Thumbs.db') !== -1) { 78 | return false; 79 | } 80 | if (f.path.indexOf('_locales') !== -1) { 81 | return false; 82 | } 83 | if (f.relative.indexOf('chrome') !== -1 && 84 | f.relative !== 'chrome.manifest' && 85 | f.relative.indexOf('chrome.png') === -1 && 86 | f.relative.indexOf('firefox/chrome') === -1 87 | ) { 88 | return false; 89 | } 90 | if (f.relative.indexOf('shadow_index.js') !== -1) { 91 | return false; 92 | } 93 | if (f.relative.indexOf('safari') !== -1) { 94 | return false; 95 | } 96 | if (f.relative.split('/').length === 1) { 97 | return ['package.json', 'chrome.manifest'].indexOf(f.relative) !== -1; 98 | } 99 | return true; 100 | })) 101 | .pipe(gulpif(function (f) { 102 | return f.path.indexOf('.html') !== -1; 103 | }, change(function (content) { 104 | return content.replace(/\n.*shadow_index\.js.*/, ''); 105 | }))) 106 | .pipe(gulp.dest('builds/unpacked/firefox')); 107 | }); 108 | /* firefox pack */ 109 | gulp.task('firefox-pack', function () { 110 | gulp.src('') 111 | .pipe(wait(1000)) 112 | .pipe(shell([ 113 | 'jpm xpi', 114 | 'mv *.xpi ../../packed/firefox.xpi', 115 | 'jpm post --post-url http://localhost:8888/' 116 | ], { 117 | cwd: './builds/unpacked/firefox' 118 | })) 119 | .pipe(shell([ 120 | 'zip firefox.xpi icon.png icon64.png', 121 | ], { 122 | cwd: './builds/packed' 123 | })); 124 | }); 125 | /* */ 126 | gulp.task('chrome', function (callback) { 127 | runSequence('clean', 'chrome-build', 'chrome-install', callback); 128 | }); 129 | gulp.task('firefox', function (callback) { 130 | runSequence('clean', 'firefox-build', 'firefox-pack', callback); 131 | }); 132 | -------------------------------------------------------------------------------- /v1/src/data/icons/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/src/data/icons/128.png -------------------------------------------------------------------------------- /v1/src/data/icons/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/src/data/icons/16.png -------------------------------------------------------------------------------- /v1/src/data/icons/18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/src/data/icons/18.png -------------------------------------------------------------------------------- /v1/src/data/icons/19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/src/data/icons/19.png -------------------------------------------------------------------------------- /v1/src/data/icons/256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/src/data/icons/256.png -------------------------------------------------------------------------------- /v1/src/data/icons/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/src/data/icons/32.png -------------------------------------------------------------------------------- /v1/src/data/icons/36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/src/data/icons/36.png -------------------------------------------------------------------------------- /v1/src/data/icons/38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/src/data/icons/38.png -------------------------------------------------------------------------------- /v1/src/data/icons/48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/src/data/icons/48.png -------------------------------------------------------------------------------- /v1/src/data/icons/64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/src/data/icons/64.png -------------------------------------------------------------------------------- /v1/src/data/icons/n/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/src/data/icons/n/128.png -------------------------------------------------------------------------------- /v1/src/data/icons/n/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/src/data/icons/n/16.png -------------------------------------------------------------------------------- /v1/src/data/icons/n/18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/src/data/icons/n/18.png -------------------------------------------------------------------------------- /v1/src/data/icons/n/19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/src/data/icons/n/19.png -------------------------------------------------------------------------------- /v1/src/data/icons/n/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/src/data/icons/n/32.png -------------------------------------------------------------------------------- /v1/src/data/icons/n/36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/src/data/icons/n/36.png -------------------------------------------------------------------------------- /v1/src/data/icons/n/38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/src/data/icons/n/38.png -------------------------------------------------------------------------------- /v1/src/data/icons/n/48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/src/data/icons/n/48.png -------------------------------------------------------------------------------- /v1/src/data/icons/n/64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v1/src/data/icons/n/64.png -------------------------------------------------------------------------------- /v1/src/lib/background.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var app = app || require('./firefox/firefox'); 4 | var config = config || require('./config'); 5 | 6 | function checkState () { 7 | app.button.icon = config.js.state ? 'icons' : 'icons/n'; 8 | app.button.label = 'JavaScript Toggle On and Off\n\n' + 9 | `JavaScript is "${config.js.state ? 'Enabled' : 'Disabled'}"`; 10 | } 11 | 12 | var blocker = (function () { 13 | let listener = function (details) { 14 | let headers = details.responseHeaders; 15 | headers.push({ 16 | 'name': 'Content-Security-Policy', 17 | 'value': "script-src 'none'" // jshint ignore:line 18 | }); 19 | return { 20 | responseHeaders: headers 21 | }; 22 | }; 23 | return { 24 | install: function () { 25 | app.webRequest.onHeadersReceived.addListener(listener, 26 | { 27 | 'urls': new app.MatchPattern(['']), 28 | 'types': [ 29 | 'main_frame', 30 | 'sub_frame' 31 | ] 32 | }, 33 | ['blocking', 'responseHeaders'] 34 | ); 35 | app.contentSettings.javascript.set({ 36 | primaryPattern: '', 37 | setting: 'block' 38 | }); 39 | }, 40 | remove: function () { 41 | app.webRequest.onHeadersReceived.removeListener(listener); 42 | app.contentSettings.javascript.set({ 43 | primaryPattern: '', 44 | setting: 'allow' 45 | }); 46 | } 47 | }; 48 | })(); 49 | app.unload(blocker.remove); 50 | 51 | app.button.onCommand(() => { 52 | config.js.state = !config.js.state; 53 | blocker[config.js.state ? 'remove' : 'install'](); 54 | checkState(); 55 | }); 56 | blocker[config.js.state ? 'remove' : 'install'](); 57 | checkState(); 58 | 59 | // 60 | app.contextMenus.create({ 61 | title: 'Check JavaScript execution', 62 | contexts: ['browser_action'], 63 | onclick: () => app.tab.open('http://tools.add0n.com/check-javascript.html?rand=' + Math.random()) 64 | }); 65 | 66 | // 67 | app.startup(function () { 68 | let version = config.welcome.version; 69 | if (app.version() !== version) { 70 | app.timers.setTimeout(function () { 71 | app.tab.open( 72 | 'http://add0n.com/javascript-toggler.html?v=' + app.version() + 73 | (version ? '&p=' + version + '&type=upgrade' : '&type=install') 74 | ); 75 | config.welcome.version = app.version(); 76 | }, config.welcome.timeout); 77 | } 78 | }); 79 | -------------------------------------------------------------------------------- /v1/src/lib/chrome/chrome.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var app = {}; 4 | 5 | app.storage = (function () { 6 | let objs = {}; 7 | chrome.storage.local.get(null, function (o) { 8 | objs = o; 9 | let script = document.createElement('script'); 10 | document.body.appendChild(script); 11 | script.src = 'lib/background.js'; 12 | }); 13 | return { 14 | read: (id) => objs[id], 15 | write: (id, data) => { 16 | objs[id] = data; 17 | let tmp = {}; 18 | tmp[id] = data; 19 | chrome.storage.local.set(tmp, function () {}); 20 | } 21 | }; 22 | })(); 23 | 24 | app.button = (function () { 25 | let onCommand; 26 | chrome.browserAction.onClicked.addListener(function () { 27 | if (onCommand) { 28 | onCommand(); 29 | } 30 | }); 31 | return { 32 | onCommand: (c) => onCommand = c, 33 | set icon (root) { // jshint ignore: line 34 | chrome.browserAction.setIcon({ 35 | path: { 36 | '19': '../../data/' + root + '/19.png', 37 | '38': '../../data/' + root + '/38.png' 38 | } 39 | }); 40 | }, 41 | set label (label) { // jshint ignore: line 42 | chrome.browserAction.setTitle({ 43 | title: label 44 | }); 45 | } 46 | }; 47 | })(); 48 | 49 | app.tab = { 50 | open: (url) => chrome.tabs.create({url}) 51 | }; 52 | 53 | app.version = () => chrome[chrome.runtime && chrome.runtime.getManifest ? 'runtime' : 'extension'].getManifest().version; 54 | 55 | app.timers = window; 56 | 57 | app.startup = (function () { 58 | let loadReason, callback; 59 | function check () { 60 | if (loadReason === 'startup' || loadReason === 'install') { 61 | if (callback) { 62 | callback(); 63 | } 64 | } 65 | } 66 | if (chrome.runtime.onInstalled && chrome.runtime.onStartup) { 67 | chrome.runtime.onInstalled.addListener(function (details) { 68 | loadReason = details.reason; 69 | check(); 70 | }); 71 | chrome.runtime.onStartup.addListener(function () { 72 | loadReason = 'startup'; 73 | check(); 74 | }); 75 | } 76 | else { 77 | loadReason = 'startup'; 78 | check(); 79 | } 80 | return (c) => { 81 | callback = c; 82 | check(); 83 | }; 84 | })(); 85 | 86 | app.unload = function () {}; 87 | 88 | app.MatchPattern = function (arr) { 89 | return arr; 90 | }; 91 | app.webRequest = chrome.webRequest; 92 | app.contentSettings = chrome.contentSettings; 93 | app.contextMenus = chrome.contextMenus; 94 | -------------------------------------------------------------------------------- /v1/src/lib/config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var config = typeof require === 'undefined' ? {} : exports; 4 | var app = app || require('./firefox/firefox'); 5 | 6 | config.js = { 7 | get state () { 8 | let state = app.storage.read('state'); 9 | return (state === undefined) ? true : state; 10 | }, 11 | set state (val) { 12 | app.storage.write('state', val); 13 | } 14 | }; 15 | 16 | config.welcome = { 17 | get version () { 18 | return app.storage.read('version'); 19 | }, 20 | set version (val) { 21 | app.storage.write('version', val); 22 | }, 23 | timeout: 3, 24 | get show () { 25 | let state = app.storage.read('show'); 26 | return (state === undefined) ? true : state; 27 | }, 28 | set show (val) { 29 | app.storage.write('show', val); 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /v1/src/lib/firefox/firefox.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Load Firefox based resources 4 | var self = require('sdk/self'), 5 | sp = require('sdk/simple-prefs'), 6 | prefs = sp.prefs, 7 | tabs = require('sdk/tabs'), 8 | timers = require('sdk/timers'), 9 | unload = require('sdk/system/unload'), 10 | buttons = require('sdk/ui/button/action'), 11 | pService = require('sdk/preferences/service'), 12 | {Ci, Cc, Cu} = require('chrome'); 13 | 14 | //var {WebRequest} = Cu.import('resource://gre/modules/WebRequest.jsm'); 15 | var {MatchPattern} = Cu.import('resource://gre/modules/MatchPattern.jsm'); 16 | var {Services} = Cu.import('resource://gre/modules/Services.jsm'); 17 | 18 | //toolbar button 19 | exports.button = (function () { 20 | let callback = function () {}; 21 | let button = buttons.ActionButton({ 22 | id: self.name, 23 | label: 'toolbar label', 24 | icon: { 25 | '18': './icons/16.png', 26 | '36': './icons/32.png', 27 | '64': './icons/64.png' 28 | }, 29 | onClick: () => callback() 30 | }); 31 | return { 32 | set icon (root) { // jshint ignore: line 33 | button.icon = { 34 | '18': './' + root + '/18.png', 35 | '36': './' + root + '/36.png', 36 | '64': './' + root + '/64.png' 37 | }; 38 | }, 39 | set label (val) { // jshint ignore:line 40 | button.label = val; 41 | }, 42 | onCommand: (c) => callback = c 43 | }; 44 | })(); 45 | 46 | exports.storage = { 47 | read: (id) => prefs[id], 48 | write: (id, data) => prefs[id] = data 49 | }; 50 | 51 | exports.tab = { 52 | open: (url) => tabs.open({url}) 53 | }; 54 | 55 | exports.version = () => self.version; 56 | 57 | exports.timers = timers; 58 | 59 | exports.startup = function (callback) { 60 | if (self.loadReason === 'install' || self.loadReason === 'startup') { 61 | callback(); 62 | } 63 | }; 64 | 65 | exports.unload = function (c) { 66 | unload.when(function (e) { 67 | if (e === 'shutdown') { 68 | return; 69 | } 70 | c(); 71 | }); 72 | }; 73 | 74 | exports.MatchPattern = MatchPattern; 75 | // exports.webRequest = WebRequest; 76 | // exports.webRequest is temporary solution until WebRequest.JSM's setResponseHeader is landed 77 | exports.webRequest = (function () { 78 | let observerService = Cc['@mozilla.org/observer-service;1'].getService(Ci.nsIObserverService); 79 | let listener; 80 | function observe (subject) { 81 | let channel = subject.QueryInterface(Ci.nsIHttpChannel); 82 | let loadInfo = channel.loadInfo; 83 | if (loadInfo) { 84 | let rawtype = loadInfo.externalContentPolicyType !== undefined ? 85 | loadInfo.externalContentPolicyType : loadInfo.contentPolicyType; 86 | 87 | if ((rawtype === 6 || rawtype === 7) && listener) { 88 | listener({responseHeaders: []}).responseHeaders.forEach( function(header) { 89 | channel.setResponseHeader(header.name, header.value, false); 90 | }); 91 | } 92 | } 93 | } 94 | return { 95 | onHeadersReceived: { 96 | addListener: function (l) { 97 | listener = l; 98 | observerService.addObserver(observe, 'http-on-examine-response', false); 99 | }, 100 | removeListener: function () { 101 | if (listener) { 102 | observerService.removeObserver(observe, 'http-on-examine-response'); 103 | listener = null; 104 | } 105 | } 106 | } 107 | }; 108 | })(); 109 | 110 | exports.contentSettings = { 111 | javascript: { 112 | set: (obj) => pService.set('javascript.enabled', obj.setting === 'allow') 113 | } 114 | }; 115 | 116 | exports.contextMenus = (function () { 117 | let cache = new WeakMap(); 118 | let NS_XUL = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'; 119 | let properties = {}; 120 | 121 | function attach (window) { 122 | function load () { 123 | window.removeEventListener('load', load); 124 | let menupopup = window.document.getElementById('toolbar-context-menu'); 125 | if (!menupopup) { 126 | return; 127 | } 128 | let menuseparator = window.document.createElementNS(NS_XUL, 'menuseparator'); 129 | menuseparator.setAttribute('id', self.name + 'menuseparator'); 130 | menuseparator.setAttribute('hidden', true); 131 | menupopup.appendChild(menuseparator); 132 | let menuitem = window.document.createElementNS(NS_XUL, 'menuitem'); 133 | menuitem.setAttribute('id', self.name + 'menuitem'); 134 | menuitem.setAttribute('label', properties.title); 135 | menuitem.addEventListener('command', properties.onclick); 136 | menuitem.setAttribute('hidden', true); 137 | menupopup.appendChild(menuitem); 138 | 139 | function onContext (e) { 140 | let target = e.target; 141 | let doc = target.ownerDocument.defaultView.document; 142 | let menuitem = doc.getElementById(self.name + 'menuitem'); 143 | let menuseparator = doc.getElementById(self.name + 'menuseparator'); 144 | if (menuitem) { 145 | menuitem.setAttribute('hidden', target.id.indexOf(self.name) === -1); 146 | } 147 | if (menuseparator) { 148 | menuseparator.setAttribute('hidden', target.id.indexOf(self.name) === -1); 149 | } 150 | } 151 | window.addEventListener('contextmenu', onContext, true); 152 | cache.set(window, onContext); 153 | } 154 | if (window.document.readyState === 'complete') { 155 | load(); 156 | } 157 | else { 158 | window.addEventListener('load', load); 159 | } 160 | } 161 | 162 | let WindowListener = { 163 | onOpenWindow: function(xulWindow) { 164 | let window = xulWindow.QueryInterface(Ci.nsIInterfaceRequestor) 165 | .getInterface(Ci.nsIDOMWindow); 166 | attach(window); 167 | } 168 | }; 169 | 170 | unload.when(function (e) { 171 | if (e === 'shutdown') { 172 | return; 173 | } 174 | Services.wm.removeListener(WindowListener); 175 | let windows = Services.wm.getEnumerator('navigator:browser'); 176 | while (windows.hasMoreElements()) { 177 | let win = windows.getNext().QueryInterface(Ci.nsIDOMWindow); 178 | if (cache.has(win)) { 179 | win.removeEventListener('contextmenu', cache.get(win), true); 180 | let menuitem = win.document.getElementById(self.name + 'menuitem'); 181 | let menuseparator = win.document.getElementById(self.name + 'menuseparator'); 182 | if (menuitem) { 183 | menuitem.parentNode.removeChild(menuitem); 184 | } 185 | if (menuseparator) { 186 | menuseparator.parentNode.removeChild(menuseparator); 187 | } 188 | } 189 | } 190 | }); 191 | 192 | return { 193 | create: function (obj) { 194 | properties = obj; 195 | Services.wm.addListener(WindowListener); 196 | let windows = Services.wm.getEnumerator('navigator:browser'); 197 | while (windows.hasMoreElements()) { 198 | attach(windows.getNext().QueryInterface(Ci.nsIDOMWindow)); 199 | } 200 | } 201 | }; 202 | })(); 203 | 204 | -------------------------------------------------------------------------------- /v1/src/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "JavaScript Toggle On and Off", 3 | "short_name": "ijtoaoff", 4 | "description": "Toggle JavaScript engine on and off the easy way", 5 | "author": "Richard Neomy", 6 | "version": "0.1.4", 7 | "manifest_version": 2, 8 | "permissions": [ 9 | "storage", 10 | "contentSettings", 11 | "contextMenus", 12 | "webRequest", 13 | "webRequestBlocking", 14 | "" 15 | ], 16 | "browser_action": { 17 | "default_icon": { 18 | "19": "data/icons/19.png", 19 | "38": "data/icons/38.png" 20 | } 21 | }, 22 | "background": { 23 | "scripts": [ 24 | "lib/chrome/chrome.js", 25 | "lib/config.js" 26 | ] 27 | }, 28 | "homepage_url": "http://add0n.com/javascript-toggler.html", 29 | "icons": { 30 | "16": "data/icons/16.png", 31 | "48": "data/icons/48.png", 32 | "128": "data/icons/128.png" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /v1/src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "JavaScript Toggle On and Off", 3 | "name": "ijtoaoff", 4 | "description": "Toggle JavaScript engine on and off the easy way", 5 | "id": "jid1-EbhJmw1yu6Juy@jetpack", 6 | "license": "Mozilla Public License, version 2.0", 7 | "version": "0.1.4", 8 | "author": "Richard Neomy", 9 | "main": "./lib/background.js", 10 | "url": "http://add0n.com/javascript-toggler.html", 11 | "permissions": { 12 | "private-browsing": true, 13 | "multiprocess": true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /v2/_locales: -------------------------------------------------------------------------------- 1 | ../firefox-only/_locales/ -------------------------------------------------------------------------------- /v2/background.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let tab; 4 | 5 | const notify = message => chrome.notifications.create({ 6 | title: chrome.runtime.getManifest().name, 7 | type: 'basic', 8 | iconUrl: 'data/icons/48.png', 9 | message 10 | }); 11 | 12 | const app = { 13 | title: title => chrome.browserAction.setTitle({ 14 | title 15 | }), 16 | icon: (path = '', badge) => { 17 | chrome.browserAction.setIcon({ 18 | path: { 19 | '16': 'data/icons' + path + '/16.png', 20 | '19': 'data/icons' + path + '/19.png', 21 | '32': 'data/icons' + path + '/32.png', 22 | '38': 'data/icons' + path + '/38.png', 23 | '48': 'data/icons' + path + '/48.png', 24 | '64': 'data/icons' + path + '/64.png' 25 | } 26 | }); 27 | if (badge) { 28 | chrome.browserAction.setBadgeText({ 29 | text: path ? 'd' : '' 30 | }); 31 | } 32 | } 33 | }; 34 | 35 | const refresh = () => chrome.storage.local.get({ 36 | 'refresh-enabled': true, 37 | 'refresh-disabled': true, 38 | 'state': true 39 | }, prefs => { 40 | if (tab && tab.url && tab.url.startsWith('http')) { 41 | if ((prefs.state && prefs['refresh-enabled']) || (prefs.state === false && prefs['refresh-disabled'])) { 42 | chrome.tabs.reload(tab.id, { 43 | bypassCache: true 44 | }); 45 | } 46 | } 47 | tab = null; 48 | }); 49 | 50 | const js = { 51 | wildcard: host => `*://*.${host}/*`.replace(/\*\.\*/g, '*'), 52 | enable: badge => { 53 | chrome.contentSettings.javascript.clear({}, () => chrome.storage.local.get({ 54 | blacklist: [] 55 | }, prefs => { 56 | prefs.blacklist.forEach(host => chrome.contentSettings.javascript.set({ 57 | primaryPattern: js.wildcard(host), 58 | setting: 'block' 59 | })); 60 | window.setTimeout(refresh, 10); 61 | })); 62 | app.icon('', badge); 63 | app.title(chrome.i18n.getMessage('bg_disable')); 64 | }, 65 | disable: badge => { 66 | chrome.contentSettings.javascript.clear({}, () => { 67 | chrome.contentSettings.javascript.set({ 68 | primaryPattern: '', 69 | setting: 'block' 70 | }); 71 | chrome.storage.local.get({ 72 | whitelist: [] 73 | }, prefs => { 74 | prefs.whitelist.forEach(host => chrome.contentSettings.javascript.set({ 75 | primaryPattern: js.wildcard(host), 76 | setting: 'allow' 77 | })); 78 | window.setTimeout(refresh, 10); 79 | }); 80 | }); 81 | app.icon('/n', badge); 82 | app.title(chrome.i18n.getMessage('bg_enable')); 83 | } 84 | }; 85 | 86 | function init() { 87 | chrome.storage.local.get({ 88 | state: true, 89 | badge: false 90 | }, prefs => { 91 | js[prefs.state ? 'enable' : 'disable'](prefs.badge); 92 | }); 93 | } 94 | init(); 95 | 96 | chrome.storage.onChanged.addListener(prefs => { 97 | if (prefs.state) { 98 | init(); 99 | } 100 | if (prefs.whitelist && !prefs.state) { 101 | init(); 102 | } 103 | if (prefs.blacklist && !prefs.state) { 104 | init(); 105 | } 106 | }); 107 | // 108 | chrome.browserAction.onClicked.addListener(t => { 109 | tab = t; 110 | chrome.storage.local.get({ 111 | state: true 112 | }, prefs => { 113 | prefs.state = !prefs.state; 114 | chrome.storage.local.set(prefs); 115 | }); 116 | }); 117 | // 118 | { 119 | const onStartup = () => { 120 | chrome.contextMenus.create({ 121 | id: 'open-test-page', 122 | title: 'Check JavaScript execution', 123 | contexts: ['browser_action'] 124 | }); 125 | chrome.contextMenus.create({ 126 | id: 'whitelist-toggle', 127 | title: 'Add to or remove from whitelist', 128 | contexts: ['browser_action'], 129 | documentUrlPatterns: ['http://*/*', 'https://*/*'] 130 | }); 131 | chrome.contextMenus.create({ 132 | id: 'blacklist-toggle', 133 | title: 'Add to or remove from blacklist', 134 | contexts: ['browser_action'], 135 | documentUrlPatterns: ['http://*/*', 'https://*/*'] 136 | }); 137 | }; 138 | chrome.runtime.onInstalled.addListener(onStartup); 139 | chrome.runtime.onStartup.addListener(onStartup); 140 | } 141 | 142 | chrome.contextMenus.onClicked.addListener((info, t) => { 143 | if (info.menuItemId === 'open-test-page') { 144 | chrome.tabs.create({ 145 | url: 'https://webbrowsertools.com/javascript/' 146 | }); 147 | } 148 | else if (info.menuItemId === 'whitelist-toggle' || info.menuItemId === 'blacklist-toggle') { 149 | if (t.url.startsWith('http')) { 150 | const {hostname} = new URL(t.url); 151 | const type = info.menuItemId.replace('-toggle', ''); 152 | chrome.storage.local.get({ 153 | [type]: [] 154 | }, prefs => { 155 | const index = prefs[type].indexOf(hostname); 156 | if (index > -1) { 157 | prefs[type].splice(index, 1); 158 | } 159 | else { 160 | prefs[type].push(hostname); 161 | } 162 | notify(index > -1 ? `"${hostname}" is removed from the ${type}` : `"${hostname}" is added to the ${type}`); 163 | tab = t; 164 | chrome.storage.local.set(prefs); 165 | }); 166 | } 167 | else { 168 | notify(chrome.i18n.getMessage('bg_warning')); 169 | } 170 | } 171 | }); 172 | 173 | /* FAQs & Feedback */ 174 | { 175 | const {management, runtime: {onInstalled, setUninstallURL, getManifest}, storage, tabs} = chrome; 176 | if (navigator.webdriver !== true) { 177 | const page = getManifest().homepage_url; 178 | const {name, version} = getManifest(); 179 | onInstalled.addListener(({reason, previousVersion}) => { 180 | management.getSelf(({installType}) => installType === 'normal' && storage.local.get({ 181 | 'faqs': true, 182 | 'last-update': 0 183 | }, prefs => { 184 | if (reason === 'install' || (prefs.faqs && reason === 'update')) { 185 | const doUpdate = (Date.now() - prefs['last-update']) / 1000 / 60 / 60 / 24 > 45; 186 | if (doUpdate && previousVersion !== version) { 187 | tabs.create({ 188 | url: page + '?version=' + version + (previousVersion ? '&p=' + previousVersion : '') + '&type=' + reason, 189 | active: reason === 'install' 190 | }); 191 | storage.local.set({'last-update': Date.now()}); 192 | } 193 | } 194 | })); 195 | }); 196 | setUninstallURL(page + '?rd=feedback&name=' + encodeURIComponent(name) + '&version=' + version); 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /v2/data: -------------------------------------------------------------------------------- 1 | ../firefox-only/data/ -------------------------------------------------------------------------------- /v2/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "JavaScript Toggle On and Off", 3 | "description": "__MSG_app_description__", 4 | "author": "Richard Neomy", 5 | "version": "0.2.4", 6 | "manifest_version": 2, 7 | "default_locale": "en", 8 | "permissions": [ 9 | "storage", 10 | "contentSettings", 11 | "contextMenus", 12 | "activeTab", 13 | "notifications" 14 | ], 15 | "browser_action": {}, 16 | "background": { 17 | "persistent": false, 18 | "scripts": [ 19 | "background.js" 20 | ] 21 | }, 22 | "homepage_url": "https://add0n.com/javascript-toggler.html", 23 | "icons": { 24 | "16": "data/icons/16.png", 25 | "19": "data/icons/19.png", 26 | "32": "data/icons/32.png", 27 | "38": "data/icons/38.png", 28 | "48": "data/icons/48.png", 29 | "64": "data/icons/64.png", 30 | "128": "data/icons/128.png", 31 | "256": "data/icons/256.png" 32 | }, 33 | "options_ui": { 34 | "page": "data/options/index.html", 35 | "chrome_style": true 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /v3/_locales/bg/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "app_description": { 3 | "message": "Лесно включване и изключване на двигателите на JavaScript (вградени, URL за данни, отдалечени и външни)" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /v3/_locales/cs/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "app_description": { 3 | "message": "Snadné zapínání a vypínání motorů JavaScriptu (inline, data URL, vzdálené a externí)" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /v3/_locales/da/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "app_description": { 3 | "message": "Slå JavaScript-motorer (inline, data-URL, eksternt og eksternt) til og fra på en nem måde" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /v3/_locales/de/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "app_description": { 3 | "message": "Ein- und Ausschalten von JavaScript-Engines (Inline, Daten-URL, Remote und extern) auf einfache Art und Weise" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /v3/_locales/el/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "app_description": { 3 | "message": "Ενεργοποίηση και απενεργοποίηση μηχανών JavaScript (inline, URL δεδομένων, απομακρυσμένες και εξωτερικές) με εύκολο τρόπο" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /v3/_locales/en/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "app_description": { 3 | "message": "Toggle JavaScript engines (inline, data URL, remote, and external) on and off the easy way" 4 | }, 5 | "options_title": { 6 | "message": "Options :: JavaScript Toggle On and Off" 7 | }, 8 | "options_refresh_enabled": { 9 | "message": "Refresh the current page when JavaScript is toggled to enabled" 10 | }, 11 | "options_refresh_disabled": { 12 | "message": "Refresh the current page when JavaScript is toggled to disabled" 13 | }, 14 | "options_exception_list": { 15 | "message": "Exception List" 16 | }, 17 | "options_whitelist": { 18 | "message": "(when JS is blocked) (Comma-separated list of domains to allow JS execution when it is globally blocked)" 19 | }, 20 | "options_blacklist": { 21 | "message": "(when JS is allowed) (Comma-separated list of domains to block JS execution when it is globally permitted)" 22 | }, 23 | "options_reset": { 24 | "message": "Factory Reset" 25 | }, 26 | "options_support": { 27 | "message": "Support Development" 28 | }, 29 | "options_save": { 30 | "message": "Save Options" 31 | }, 32 | "options_private": { 33 | "message": "Enable on Incognito" 34 | }, 35 | "options_badge_color": { 36 | "message": "Color of the badge icon when JS is disabled" 37 | }, 38 | "bg_disable": { 39 | "message": "Click to disable JavaScript" 40 | }, 41 | "bg_enable": { 42 | "message": "Click to enable JavaScript" 43 | }, 44 | "bg_warning": { 45 | "message": "This extension only works on HTTP and HTTPS schemes" 46 | }, 47 | "bg_add_to_whitelist": { 48 | "message": "Exception List (when JS is blocked)" 49 | }, 50 | "bg_add_to_blacklist": { 51 | "message": "Exception List (when JS is allowed)" 52 | }, 53 | "bg_test": { 54 | "message": "Check JavaScript Execution" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /v3/_locales/et/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "app_description": { 3 | "message": "JavaScript-mootorite (inline, andme-URL, remote ja external) sisse- ja väljalülitamine lihtsal viisil" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /v3/_locales/fi/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "app_description": { 3 | "message": "JavaScript-moottoreiden (inline, data-URL, remote ja ulkoinen) kytkeminen päälle ja pois päältä helpolla tavalla" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /v3/_locales/fr/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "app_description": { 3 | "message": "Activez et désactivez les moteurs JavaScript (en ligne, URL de données, distant et externe) en toute simplicité." 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /v3/_locales/hu/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "app_description": { 3 | "message": "JavaScript motorok (inline, adat URL, távoli és külső) be- és kikapcsolása egyszerű módon" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /v3/_locales/nl/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "app_description": { 3 | "message": "Schakel JavaScript engines (inline, data URL, remote en extern) op een eenvoudige manier aan en uit" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /v3/_locales/zh_CN/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "app_description": { 3 | "message": "以简单的方式切换JavaScript引擎(内联、数据URL、远程和外部)的开启和关闭" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /v3/data/icons/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v3/data/icons/128.png -------------------------------------------------------------------------------- /v3/data/icons/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v3/data/icons/16.png -------------------------------------------------------------------------------- /v3/data/icons/256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v3/data/icons/256.png -------------------------------------------------------------------------------- /v3/data/icons/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v3/data/icons/32.png -------------------------------------------------------------------------------- /v3/data/icons/48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v3/data/icons/48.png -------------------------------------------------------------------------------- /v3/data/icons/64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v3/data/icons/64.png -------------------------------------------------------------------------------- /v3/data/icons/a/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v3/data/icons/a/128.png -------------------------------------------------------------------------------- /v3/data/icons/a/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v3/data/icons/a/16.png -------------------------------------------------------------------------------- /v3/data/icons/a/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v3/data/icons/a/32.png -------------------------------------------------------------------------------- /v3/data/icons/d/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v3/data/icons/d/128.png -------------------------------------------------------------------------------- /v3/data/icons/d/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v3/data/icons/d/16.png -------------------------------------------------------------------------------- /v3/data/icons/d/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v3/data/icons/d/32.png -------------------------------------------------------------------------------- /v3/data/icons/n/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v3/data/icons/n/16.png -------------------------------------------------------------------------------- /v3/data/icons/n/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rNeomy/javascript-toggle-on-and-off/9134c62939fad9b69c15bb5c23614a1f21cba00b/v3/data/icons/n/32.png -------------------------------------------------------------------------------- /v3/data/options/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-size: 13px; 3 | font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; 4 | background-color: #fff; 5 | color: #4d5156; 6 | } 7 | button, 8 | input[type=submit], 9 | input[type=button] { 10 | height: 24px; 11 | color: #444; 12 | background-image: linear-gradient(rgb(237, 237, 237), rgb(237, 237, 237) 38%, rgb(222, 222, 222)); 13 | box-shadow: rgba(0, 0, 0, 0.08) 0 1px 0, rgba(255, 255, 255, 0.75) 0 1px 2px inset; 14 | text-shadow: rgb(240, 240, 240) 0 1px 0; 15 | } 16 | button, 17 | textarea, 18 | input[type=submit], 19 | input[type=button] { 20 | border: solid 1px rgba(0, 0, 0, 0.25); 21 | } 22 | input[type=button]:disabled { 23 | opacity: 0.5; 24 | } 25 | textarea { 26 | width: 100%; 27 | box-sizing: border-box; 28 | display: block; 29 | padding: 5px; 30 | margin-top: 5px; 31 | } 32 | a, 33 | a:visited { 34 | color: #0077cc; 35 | text-decoration: none; 36 | } 37 | .tbl { 38 | display: grid; 39 | grid-template-columns: 1fr min-content; 40 | grid-gap: 10px 5px; 41 | align-items: center; 42 | } 43 | .tbl input { 44 | justify-self: end; 45 | align-self: start; 46 | } 47 | -------------------------------------------------------------------------------- /v3/data/options/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 |

20 | 23 | 24 |

25 | 26 |

27 | 30 | 31 |

32 | 33 |

34 | 35 | 36 |

37 |

38 | 39 | 40 | 41 |

42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /v3/data/options/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // localization 4 | [...document.querySelectorAll('[data-i18n]')].forEach(e => { 5 | e.textContent = chrome.i18n.getMessage(e.dataset.i18n); 6 | }); 7 | 8 | const toast = document.getElementById('toast'); 9 | 10 | function restore() { 11 | chrome.storage.local.get({ 12 | 'whitelist': [], 13 | 'blacklist': [], 14 | 'refresh-enabled': true, 15 | 'refresh-disabled': true, 16 | 'badge-color': '#da4537' 17 | }, prefs => { 18 | document.getElementById('whitelist').value = prefs.whitelist.join(', '); 19 | document.getElementById('blacklist').value = prefs.blacklist.join(', '); 20 | document.getElementById('refresh-enabled').checked = prefs['refresh-enabled']; 21 | document.getElementById('refresh-disabled').checked = prefs['refresh-disabled']; 22 | document.getElementById('badge-color').value = prefs['badge-color']; 23 | }); 24 | } 25 | function save() { 26 | let whitelist = document.getElementById('whitelist').value; 27 | whitelist = whitelist.split(/\s*,\s*/).map(s => { 28 | return s.replace('http://', '').replace('https://', '').split('/')[0].trim(); 29 | }).filter((h, i, l) => h && l.indexOf(h) === i); 30 | 31 | let blacklist = document.getElementById('blacklist').value; 32 | blacklist = blacklist.split(/\s*,\s*/).map(s => { 33 | return s.replace('http://', '').replace('https://', '').split('/')[0].trim(); 34 | }).filter((h, i, l) => h && l.indexOf(h) === i); 35 | 36 | chrome.storage.local.set({ 37 | whitelist, 38 | blacklist, 39 | 'refresh-enabled': document.getElementById('refresh-enabled').checked, 40 | 'refresh-disabled': document.getElementById('refresh-disabled').checked, 41 | 'badge-color': document.getElementById('badge-color').value 42 | }, () => { 43 | restore(); 44 | toast.textContent = 'Options saved.'; 45 | setTimeout(() => toast.textContent = '', 750); 46 | }); 47 | } 48 | 49 | document.addEventListener('DOMContentLoaded', restore); 50 | document.getElementById('save').addEventListener('click', save); 51 | 52 | // reset 53 | document.getElementById('reset').addEventListener('click', e => { 54 | if (e.detail === 1) { 55 | toast.textContent = 'Double-click to reset!'; 56 | window.setTimeout(() => toast.textContent = '', 750); 57 | } 58 | else { 59 | localStorage.clear(); 60 | chrome.storage.local.clear(() => { 61 | chrome.runtime.reload(); 62 | window.close(); 63 | }); 64 | } 65 | }); 66 | // support 67 | document.getElementById('support').addEventListener('click', () => chrome.tabs.create({ 68 | url: chrome.runtime.getManifest().homepage_url + '?rd=donate' 69 | })); 70 | // incognito 71 | document.getElementById('private').addEventListener('click', () => chrome.tabs.create({ 72 | url: chrome.runtime.getManifest().homepage_url + '#faq3' 73 | })); 74 | // Links 75 | const links = window.links = (d = document) => { 76 | for (const a of [...d.querySelectorAll('[data-href]')]) { 77 | if (a.hasAttribute('href') === false) { 78 | a.href = chrome.runtime.getManifest().homepage_url + '#' + a.dataset.href; 79 | } 80 | } 81 | }; 82 | document.addEventListener('DOMContentLoaded', () => links()); 83 | -------------------------------------------------------------------------------- /v3/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "JavaScript Toggle On and Off", 3 | "description": "__MSG_app_description__", 4 | "version": "0.3.3", 5 | "manifest_version": 3, 6 | "default_locale": "en", 7 | "permissions": [ 8 | "storage", 9 | "contentSettings", 10 | "contextMenus", 11 | "activeTab", 12 | "notifications", 13 | "declarativeContent" 14 | ], 15 | "action": {}, 16 | "background": { 17 | "service_worker": "worker.js" 18 | }, 19 | "homepage_url": "https://add0n.com/javascript-toggler.html", 20 | "icons": { 21 | "16": "data/icons/16.png", 22 | "32": "data/icons/32.png", 23 | "48": "data/icons/48.png", 24 | "64": "data/icons/64.png", 25 | "128": "data/icons/128.png", 26 | "256": "data/icons/256.png" 27 | }, 28 | "options_ui": { 29 | "page": "data/options/index.html" 30 | }, 31 | "commands": { 32 | "_execute_action": {} 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /v3/worker.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let tab; 4 | 5 | const translate = id => chrome.i18n.getMessage(id) || id; 6 | 7 | const notify = message => chrome.notifications.create({ 8 | title: chrome.runtime.getManifest().name, 9 | type: 'basic', 10 | iconUrl: 'data/icons/48.png', 11 | message 12 | }); 13 | 14 | const icon = (state, title) => { 15 | chrome.action.setTitle({ 16 | title: translate(title) 17 | }); 18 | chrome.action.setBadgeText({ 19 | text: state ? '' : 'd' 20 | }); 21 | }; 22 | 23 | { 24 | const run = () => chrome.storage.local.get({ 25 | 'badge-color': '#da4537' 26 | }, prefs => chrome.action.setBadgeBackgroundColor({ 27 | color: prefs['badge-color'] 28 | })); 29 | chrome.runtime.onStartup.addListener(run); 30 | chrome.runtime.onInstalled.addListener(run); 31 | } 32 | 33 | const refresh = () => chrome.storage.local.get({ 34 | 'refresh-enabled': true, 35 | 'refresh-disabled': true, 36 | 'state': true 37 | }, prefs => { 38 | if (tab && tab.url && tab.url.startsWith('http')) { 39 | if ((prefs.state && prefs['refresh-enabled']) || (prefs.state === false && prefs['refresh-disabled'])) { 40 | chrome.tabs.reload(tab.id, { 41 | bypassCache: true 42 | }); 43 | } 44 | } 45 | tab = null; 46 | }); 47 | 48 | async function image(url) { 49 | const img = await createImageBitmap(await (await fetch(url)).blob()); 50 | const {width: w, height: h} = img; 51 | const canvas = new OffscreenCanvas(w, h); 52 | const ctx = canvas.getContext('2d'); 53 | ctx.drawImage(img, 0, 0, w, h); 54 | 55 | return ctx.getImageData(0, 0, w, h); 56 | } 57 | 58 | const js = { 59 | wildcard: host => `*://*.${host}/*`.replace(/\*\.\*/g, '*'), 60 | enable() { 61 | icon(true, 'bg_disable'); 62 | 63 | chrome.contentSettings.javascript.clear({}, () => chrome.storage.local.get({ 64 | blacklist: [] 65 | }, prefs => { 66 | prefs.blacklist.forEach(host => chrome.contentSettings.javascript.set({ 67 | primaryPattern: js.wildcard(host), 68 | setting: 'block' 69 | })); 70 | chrome.declarativeContent.onPageChanged.removeRules(undefined, async () => { 71 | const action = new chrome.declarativeContent.SetIcon({ 72 | imageData: { 73 | 16: await image('/data/icons/d/16.png'), 74 | 32: await image('/data/icons/d/32.png') 75 | } 76 | }); 77 | chrome.declarativeContent.onPageChanged.addRules([{ 78 | conditions: prefs.blacklist.map(host => new chrome.declarativeContent.PageStateMatcher({ 79 | pageUrl: { 80 | hostSuffix: host 81 | } 82 | })), 83 | actions: [action] 84 | }]); 85 | }); 86 | setTimeout(refresh, 10); 87 | })); 88 | }, 89 | disable() { 90 | icon(false, 'bg_enable'); 91 | chrome.contentSettings.javascript.clear({}, () => { 92 | chrome.contentSettings.javascript.set({ 93 | primaryPattern: '', 94 | setting: 'block' 95 | }); 96 | chrome.storage.local.get({ 97 | whitelist: [] 98 | }, prefs => { 99 | prefs.whitelist.forEach(host => chrome.contentSettings.javascript.set({ 100 | primaryPattern: js.wildcard(host), 101 | setting: 'allow' 102 | })); 103 | chrome.declarativeContent.onPageChanged.removeRules(undefined, async () => { 104 | const action = new chrome.declarativeContent.SetIcon({ 105 | imageData: { 106 | 16: await image('/data/icons/a/16.png'), 107 | 32: await image('/data/icons/a/32.png') 108 | } 109 | }); 110 | chrome.declarativeContent.onPageChanged.addRules([{ 111 | conditions: prefs.whitelist.map(host => new chrome.declarativeContent.PageStateMatcher({ 112 | pageUrl: { 113 | hostSuffix: host 114 | } 115 | })), 116 | actions: [action] 117 | }]); 118 | }); 119 | 120 | setTimeout(refresh, 10); 121 | }); 122 | }); 123 | } 124 | }; 125 | 126 | function init() { 127 | chrome.storage.local.get({ 128 | state: true 129 | }, prefs => { 130 | js[prefs.state ? 'enable' : 'disable'](); 131 | }); 132 | } 133 | init(); 134 | 135 | chrome.storage.onChanged.addListener(prefs => { 136 | if (prefs.state) { 137 | init(); 138 | } 139 | if (prefs.whitelist && !prefs.state) { 140 | init(); 141 | } 142 | if (prefs.blacklist && !prefs.state) { 143 | init(); 144 | } 145 | if (prefs['badge-color']) { 146 | chrome.action.setBadgeBackgroundColor({ 147 | color: prefs['badge-color'].newValue 148 | }); 149 | } 150 | }); 151 | // 152 | chrome.action.onClicked.addListener(t => { 153 | tab = t; 154 | chrome.storage.local.get({ 155 | state: true 156 | }, prefs => { 157 | prefs.state = !prefs.state; 158 | chrome.storage.local.set(prefs); 159 | }); 160 | }); 161 | // 162 | { 163 | const onStartup = () => { 164 | chrome.contextMenus.create({ 165 | id: 'open-test-page', 166 | title: translate('bg_test'), 167 | contexts: ['action'] 168 | }); 169 | chrome.contextMenus.create({ 170 | id: 'whitelist-toggle', 171 | title: translate('bg_add_to_whitelist'), 172 | contexts: ['action'], 173 | documentUrlPatterns: ['http://*/*', 'https://*/*'] 174 | }); 175 | chrome.contextMenus.create({ 176 | id: 'blacklist-toggle', 177 | title: translate('bg_add_to_blacklist'), 178 | contexts: ['action'], 179 | documentUrlPatterns: ['http://*/*', 'https://*/*'] 180 | }); 181 | }; 182 | chrome.runtime.onInstalled.addListener(onStartup); 183 | chrome.runtime.onStartup.addListener(onStartup); 184 | } 185 | 186 | chrome.contextMenus.onClicked.addListener((info, t) => { 187 | if (info.menuItemId === 'open-test-page') { 188 | chrome.tabs.create({ 189 | url: 'https://webbrowsertools.com/javascript/' 190 | }); 191 | } 192 | else if (info.menuItemId === 'whitelist-toggle' || info.menuItemId === 'blacklist-toggle') { 193 | if (t.url.startsWith('http')) { 194 | const {hostname} = new URL(t.url); 195 | const type = info.menuItemId.replace('-toggle', ''); 196 | chrome.storage.local.get({ 197 | [type]: [] 198 | }, prefs => { 199 | const index = prefs[type].indexOf(hostname); 200 | if (index > -1) { 201 | prefs[type].splice(index, 1); 202 | } 203 | else { 204 | prefs[type].push(hostname); 205 | } 206 | notify(index > -1 ? `"${hostname}" is removed from the ${type}` : `"${hostname}" is added to the ${type}`); 207 | tab = t; 208 | chrome.storage.local.set(prefs); 209 | }); 210 | } 211 | else { 212 | notify(translate('bg_warning')); 213 | } 214 | } 215 | }); 216 | 217 | /* FAQs & Feedback */ 218 | { 219 | const {management, runtime: {onInstalled, setUninstallURL, getManifest}, storage, tabs} = chrome; 220 | if (navigator.webdriver !== true) { 221 | const page = getManifest().homepage_url; 222 | const {name, version} = getManifest(); 223 | onInstalled.addListener(({reason, previousVersion}) => { 224 | management.getSelf(({installType}) => installType === 'normal' && storage.local.get({ 225 | 'faqs': true, 226 | 'last-update': 0 227 | }, prefs => { 228 | if (reason === 'install' || (prefs.faqs && reason === 'update')) { 229 | const doUpdate = (Date.now() - prefs['last-update']) / 1000 / 60 / 60 / 24 > 45; 230 | if (doUpdate && previousVersion !== version) { 231 | tabs.query({active: true, currentWindow: true}, tbs => tabs.create({ 232 | url: page + '?version=' + version + (previousVersion ? '&p=' + previousVersion : '') + '&type=' + reason, 233 | active: reason === 'install', 234 | ...(tbs && tbs.length && {index: tbs[0].index + 1}) 235 | })); 236 | storage.local.set({'last-update': Date.now()}); 237 | } 238 | } 239 | })); 240 | }); 241 | setUninstallURL(page + '?rd=feedback&name=' + encodeURIComponent(name) + '&version=' + version); 242 | } 243 | } 244 | --------------------------------------------------------------------------------