├── .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 |
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 |
--------------------------------------------------------------------------------