migrate from mv2 to mv3

This commit is contained in:
suziwen 2024-02-29 22:14:04 +08:00
parent b93171da95
commit 6c56da0360
35 changed files with 296 additions and 216 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
node_modules node_modules
bower_components bower_components
package-lock.json

View File

@ -111,7 +111,7 @@ To build the project:
grunt grunt
# After building, a folder will be generated: # After building, a folder will be generated:
cd .. # Return to project root. cd .. # Return to project root.
ls omega-chromium-extension/build/ ls omega-target-chromium-extension/build/
# The folder above can be loaded as an unpacked extension in Chromium now. # The folder above can be loaded as an unpacked extension in Chromium now.
To enable `grunt watch`, run `grunt watch` once in the `omega-build` directory. To enable `grunt watch`, run `grunt watch` once in the `omega-build` directory.

View File

@ -1,5 +1,5 @@
(function(exports, global) { (function(exports, global) {
global["UglifyJS"] = exports; globalThis["UglifyJS"] = exports;
"use strict"; "use strict";
function array_to_hash(a) { function array_to_hash(a) {
var ret = Object.create(null); var ret = Object.create(null);

View File

@ -3,5 +3,6 @@
/tmp /tmp
/build /build
/build*
/release.zip /release.zip
/web-ext-artifacts /web-ext-artifacts

View File

@ -0,0 +1,5 @@
#!/bin/bash
. ~/.nvm/nvm.sh
nvm use 11.9.0
minify-all-js ./build -j
cd build && zip -r ../release.zip ./*

View File

@ -0,0 +1 @@
function _slicedToArray(t,n){return _arrayWithHoles(t)||_iterableToArrayLimit(t,n)||_unsupportedIterableToArray(t,n)||_nonIterableRest()}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _unsupportedIterableToArray(t,n){if(t){if("string"==typeof t)return _arrayLikeToArray(t,n);var r=Object.prototype.toString.call(t).slice(8,-1);return"Object"===r&&t.constructor&&(r=t.constructor.name),"Map"===r||"Set"===r?Array.from(t):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?_arrayLikeToArray(t,n):void 0}}function _arrayLikeToArray(t,n){(null==n||n>t.length)&&(n=t.length);for(var r=0,e=new Array(n);r<n;r++)e[r]=t[r];return e}function _iterableToArrayLimit(t,n){var r=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=r){var e,o,u=[],i=!0,a=!1;try{for(r=r.call(t);!(i=(e=r.next()).done)&&(u.push(e.value),!n||u.length!==n);i=!0);}catch(t){a=!0,o=t}finally{try{i||null==r.return||r.return()}finally{if(a)throw o}}return u}}function _arrayWithHoles(t){if(Array.isArray(t))return t}function _typeof(t){return _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},_typeof(t)}!function(t,n){"object"===("undefined"==typeof exports?"undefined":_typeof(exports))&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((t="undefined"!=typeof globalThis?globalThis:t||self).idbKeyval={})}(this,(function(t){"use strict";function n(t){return new Promise((function(n,r){t.oncomplete=t.onsuccess=function(){return n(t.result)},t.onabort=t.onerror=function(){return r(t.error)}}))}function r(t,r){var e=indexedDB.open(t);e.onupgradeneeded=function(){return e.result.createObjectStore(r)};var o=n(e);return function(t,n){return o.then((function(e){return n(e.transaction(r,t).objectStore(r))}))}}var e;function o(){return e||(e=r("keyval-store","keyval")),e}function u(t,r){return t.openCursor().onsuccess=function(){this.result&&(r(this.result),this.result.continue())},n(t.transaction)}t.clear=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:o();return t("readwrite",(function(t){return t.clear(),n(t.transaction)}))},t.createStore=r,t.del=function(t){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:o();return r("readwrite",(function(r){return r.delete(t),n(r.transaction)}))},t.delMany=function(t){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:o();return r("readwrite",(function(r){return t.forEach((function(t){return r.delete(t)})),n(r.transaction)}))},t.entries=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:o();return t("readonly",(function(r){if(r.getAll&&r.getAllKeys)return Promise.all([n(r.getAllKeys()),n(r.getAll())]).then((function(t){var n=_slicedToArray(t,2),r=n[0],e=n[1];return r.map((function(t,n){return[t,e[n]]}))}));var e=[];return t("readonly",(function(t){return u(t,(function(t){return e.push([t.key,t.value])})).then((function(){return e}))}))}))},t.get=function(t){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:o();return r("readonly",(function(r){return n(r.get(t))}))},t.getMany=function(t){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:o();return r("readonly",(function(r){return Promise.all(t.map((function(t){return n(r.get(t))})))}))},t.keys=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:o();return t("readonly",(function(t){if(t.getAllKeys)return n(t.getAllKeys());var r=[];return u(t,(function(t){return r.push(t.key)})).then((function(){return r}))}))},t.promisifyRequest=n,t.set=function(t,r){var e=arguments.length>2&&void 0!==arguments[2]?arguments[2]:o();return e("readwrite",(function(e){return e.put(r,t),n(e.transaction)}))},t.setMany=function(t){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:o();return r("readwrite",(function(r){return t.forEach((function(t){return r.put(t[1],t[0])})),n(r.transaction)}))},t.update=function(t,r){var e=arguments.length>2&&void 0!==arguments[2]?arguments[2]:o();return e("readwrite",(function(e){return new Promise((function(o,u){e.get(t).onsuccess=function(){try{e.put(r(this.result),t),o(n(e.transaction))}catch(t){u(t)}}}))}))},t.values=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:o();return t("readonly",(function(t){if(t.getAll)return n(t.getAll());var r=[];return u(t,(function(t){return r.push(t.value)})).then((function(){return r}))}))},Object.defineProperty(t,"__esModule",{value:!0})}));

View File

@ -0,0 +1,62 @@
'use strict'
let valuesMap = new Map()
class LocalStorage {
getItem (key) {
const stringKey = String(key)
if (valuesMap.has(key)) {
return String(valuesMap.get(stringKey))
}
return null
}
setItem (key, val) {
valuesMap.set(String(key), String(val))
}
removeItem (key) {
valuesMap.delete(key)
}
clear () {
valuesMap.clear()
}
key (i) {
if (arguments.length === 0) {
throw new TypeError("Failed to execute 'key' on 'Storage': 1 argument required, but only 0 present.") // this is a TypeError implemented on Chrome, Firefox throws Not enough arguments to Storage.key.
}
var arr = Array.from(valuesMap.keys())
return arr[i]
}
get length () {
return valuesMap.size
}
initValuesMap (_valuesMap){
valuesMap = new Map(Object.entries(_valuesMap || {}))
}
getValuesMap (){
return Object.fromEntries(valuesMap);
}
}
const instance = new LocalStorage()
globalThis.localStorage = new Proxy(instance, {
set: function (obj, prop, value) {
if (LocalStorage.prototype.hasOwnProperty(prop)) {
instance[prop] = value
} else {
instance.setItem(prop, value)
}
return true
},
get: function (target, name) {
if (LocalStorage.prototype.hasOwnProperty(name)) {
return instance[name]
}
if (valuesMap.has(name)) {
return instance.getItem(name)
}
}
})

View File

@ -1,9 +1,8 @@
{ {
"manifest_version": 2, "manifest_version": 3,
"name": "__MSG_manifest_app_name__", "name": "ZeroOmega--Proxy Switchy manifest v3 version",
"version": "2.5.21", "version": "3.0.0",
"description": "__MSG_manifest_app_description__", "description": "__MSG_manifest_app_description__",
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkhwZJT76btQ04EEMOFtZPLESD1TmSVjbLjs0OyesD9Ht8YllFPfJ3qmtbSQGVuvmxH1GK/jUO2QcEWb8bHuOjoRlq20fi5j5Aq90O8FKET+y5D8PxCyi3WmnquiEwaE5cNmaCsw/G2JlO+bZOtdQ/QKOvMxBAegABYimEGfSvCMVUEvpymys0gBhLoch72zPAiJUBkf0z8BtjYTueMRcRXkrSeRPLygUDQnZ1TkQWMYYBp/zqpD5ggxytAklEMQzR9Hn0lqu5s7iuUAgihbysPn/8Wh00Zj5FySpK//KcpG3JS7UWxC28oSt8z5ZR3YimnX+HX3P36V0mC1pgM4o7wIDAQAB",
"icons": { "icons": {
"16": "img/icons/omega-action-16.png", "16": "img/icons/omega-action-16.png",
"24": "img/icons/omega-action-24.png", "24": "img/icons/omega-action-24.png",
@ -13,8 +12,7 @@
"128": "img/icons/omega-128.png" "128": "img/icons/omega-128.png"
}, },
"default_locale": "en", "default_locale": "en",
"browser_action": { "action": {
"browser_style": false,
"default_icon": { "default_icon": {
"16": "img/icons/omega-action-16.png", "16": "img/icons/omega-action-16.png",
"19": "img/icons/omega-action-19.png", "19": "img/icons/omega-action-19.png",
@ -25,40 +23,27 @@
"default_popup": "popup/index.html" "default_popup": "popup/index.html"
}, },
"background": { "background": {
"page": "background.html" "service_worker": "x-background.js",
"type": "module"
}, },
"minimum_chrome_version": "22.0.0", "minimum_chrome_version": "111",
"options_page": "options.html", "options_page": "options.html",
"options_ui": { "options_ui": {
"page": "options.html", "page": "options.html",
"browser_style": false, "browser_style": false,
"open_in_tab": true "open_in_tab": true
}, },
"commands": {
"_execute_action": { "suggested_key": { "default": "Alt+Shift+O" } }
},
"permissions": [ "permissions": [
"proxy", "proxy",
"tabs", "tabs",
"alarms", "alarms",
"storage", "storage",
"webRequest", "webRequest",
"downloads", "webRequestAuthProvider",
"webRequestBlocking", "contextMenus"
"contextMenus",
"http://*/*",
"https://*/*",
"<all_urls>"
], ],
"commands": { "host_permissions": ["<all_urls>"]
"_execute_browser_action": {
"suggested_key": {
"default": "Alt+Shift+O"
}
}
},
"applications": {
"gecko": {
"id": "switchyomega@feliscatus.addons.mozilla.org",
"strict_min_version": "55.0a1"
}
}
} }

View File

@ -0,0 +1,11 @@
import "./js/background_preload.js"
import "./idb-keyval.js"
import "./localstorage-polyfill.js"
import "./js/log_error.js"
//import "./lib/FileSaver/FileSaver.min.js"
import "./js/omega_debug.js"
import "./js/omega_pac.min.js"
import "./js/omega_target.min.js"
import "./js/omega_target_chromium_extension.min.js"
import "./img/icons/draw_omega.js"
import "./js/background.js"

View File

@ -45,7 +45,8 @@ drawIcon = (resultColor, profileColor) ->
return icon if icon return icon if icon
try try
if not drawContext? if not drawContext?
drawContext = document.getElementById('canvas-icon').getContext('2d') canvas = new OffscreenCanvas(300, 300)
drawContext = canvas.getContext('2d', { willReadFrequently: true })
icon = {} icon = {}
for size in [16, 19, 24, 32, 38] for size in [16, 19, 24, 32, 38]
@ -186,7 +187,7 @@ options = new OmegaTargetCurrent.Options(null, storage, state, Log, sync,
options.externalApi = new OmegaTargetCurrent.ExternalApi(options) options.externalApi = new OmegaTargetCurrent.ExternalApi(options)
options.externalApi.listen() options.externalApi.listen()
if chrome.runtime.id != OmegaTargetCurrent.SwitchySharp.extId if chrome.runtime.id != OmegaTargetCurrent.SwitchySharp.extId and false
options.switchySharp = new OmegaTargetCurrent.SwitchySharp() options.switchySharp = new OmegaTargetCurrent.SwitchySharp()
options.switchySharp.monitor() options.switchySharp.monitor()
@ -212,7 +213,7 @@ options._inspect = new OmegaTargetCurrent.Inspect (url, tab) ->
title = chrome.i18n.getMessage('browserAction_titleInspect', urlDisp) + '\n' title = chrome.i18n.getMessage('browserAction_titleInspect', urlDisp) + '\n'
title += action.title title += action.title
chrome.browserAction.setTitle(title: title, tabId: tab.id) chrome.action.setTitle(title: title, tabId: tab.id)
tabs.setTabBadge(tab, { tabs.setTabBadge(tab, {
text: '#' text: '#'
color: action.resultColor color: action.resultColor
@ -320,11 +321,14 @@ encodeError = (obj) ->
refreshActivePageIfEnabled = -> refreshActivePageIfEnabled = ->
return if localStorage['omega.local.refreshOnProfileChange'] == 'false' return if localStorage['omega.local.refreshOnProfileChange'] == 'false'
chrome.tabs.query {active: true, lastFocusedWindow: true}, (tabs) -> chrome.tabs.query {active: true, lastFocusedWindow: true}, (tabs) ->
url = tabs[0].url url = tabs[0].url or tabs[0].url
return if not url return if not url
return if url.substr(0, 6) == 'chrome' return if url.substr(0, 6) == 'chrome'
return if url.substr(0, 6) == 'about:' return if url.substr(0, 6) == 'about:'
return if url.substr(0, 4) == 'moz-' return if url.substr(0, 4) == 'moz-'
if tabs[0].pendingUrl
chrome.tabs.update(tabs[0].id, {url: url})
else
chrome.tabs.reload(tabs[0].id, {bypassCache: true}) chrome.tabs.reload(tabs[0].id, {bypassCache: true})
chrome.runtime.onMessage.addListener (request, sender, respond) -> chrome.runtime.onMessage.addListener (request, sender, respond) ->
@ -333,6 +337,9 @@ chrome.runtime.onMessage.addListener (request, sender, respond) ->
if request.method == 'getState' if request.method == 'getState'
target = state target = state
method = state.get method = state.get
else if request.method == 'setState'
target = state
method = state.set
else else
target = options target = options
method = target[request.method] method = target[request.method]

View File

@ -1,32 +1,25 @@
globalThis.window = globalThis
globalThis.global = globalThis
window.UglifyJS_NoUnsafeEval = true window.UglifyJS_NoUnsafeEval = true
localStorage['log'] = ''
localStorage['logLastError'] = ''
window.OmegaContextMenuQuickSwitchHandler = -> null window.OmegaContextMenuQuickSwitchHandler = -> null
chrome.runtime.onInstalled.addListener( ->
if chrome.contextMenus? if chrome.contextMenus?
# We don't need this API. However its presence indicates that Chrome >= 35 # We don't need this API. However its presence indicates that Chrome >= 35
# which provides info.checked we need in contextMenu callback. # which provides info.checked we need in contextMenu callback.
# https://developer.chrome.com/extensions/contextMenus # https://developer.chrome.com/extensions/contextMenus
if chrome.i18n.getUILanguage? if chrome.i18n.getUILanguage?
# We must create the menu item here before others to make it first in menu.
chrome.contextMenus.create({ chrome.contextMenus.create({
id: 'enableQuickSwitch' id: 'enableQuickSwitch'
title: chrome.i18n.getMessage('contextMenu_enableQuickSwitch') title: chrome.i18n.getMessage('contextMenu_enableQuickSwitch')
type: 'checkbox' type: 'checkbox'
checked: false checked: false
contexts: ["browser_action"] contexts: ["action"]
onclick: (info) -> window.OmegaContextMenuQuickSwitchHandler(info)
})
chrome.contextMenus.create({
title: chrome.i18n.getMessage('popup_reportIssues')
contexts: ["browser_action"]
onclick: OmegaDebug.reportIssue
})
chrome.contextMenus.create({
title: chrome.i18n.getMessage('popup_errorLog')
contexts: ["browser_action"]
onclick: OmegaDebug.downloadLog
}) })
chrome.contextMenus.onClicked.addListener((info, tab) ->
switch info.menuItemId
when 'enableQuickSwitch'
globalThis.OmegaContextMenuQuickSwitchHandler(info)
)
)

View File

@ -6,11 +6,6 @@ window.OmegaDebug =
downloadLog: -> downloadLog: ->
blob = new Blob [localStorage['log']], {type: "text/plain;charset=utf-8"} blob = new Blob [localStorage['log']], {type: "text/plain;charset=utf-8"}
filename = "OmegaLog_#{Date.now()}.txt" filename = "OmegaLog_#{Date.now()}.txt"
if browser?.downloads?.download?
url = URL.createObjectURL(blob)
browser.downloads.download({url: url, filename: filename})
else
saveAs(blob, filename) saveAs(blob, filename)
resetOptions: -> resetOptions: ->
localStorage.clear() localStorage.clear()

View File

@ -50,19 +50,27 @@ angular.module('omegaTarget', []).factory 'omegaTarget', ($q) ->
omegaTarget = omegaTarget =
options: null options: null
state: (name, value) -> state: (name, value) ->
d = $q.defer()
if arguments.length == 1 if arguments.length == 1
getValue = (key) -> try JSON.parse(localStorage[prefix + key])
if Array.isArray(name) if Array.isArray(name)
return $q.when(name.map(getValue)) callBackground('getState', name).then((values) ->
d.resolve(name.map((key) -> values[key]))
)
else else
value = getValue(name) callBackground('getState', [name]).then( (values) ->
d.resolve(values[name])
)
else else
localStorage[prefix + name] = JSON.stringify(value) newItem = {}
return $q.when(value) newItem[name] = value
callBackground('setState', newItem).then( ->
d.resolve(value)
)
return d.promise
lastUrl: (url) -> lastUrl: (url) ->
name = 'web.last_url' name = 'web.last_url'
if url if url
omegaTarget.state(name, url) localStorage[prefix + name] = url
url url
else else
try JSON.parse(localStorage[prefix + name]) try JSON.parse(localStorage[prefix + name])
@ -91,7 +99,7 @@ angular.module('omegaTarget', []).factory 'omegaTarget', ($q) ->
getMessage: chrome.i18n.getMessage.bind(chrome.i18n) getMessage: chrome.i18n.getMessage.bind(chrome.i18n)
openOptions: (hash) -> openOptions: (hash) ->
d = $q['defer']() d = $q['defer']()
options_url = chrome.extension.getURL('options.html') options_url = chrome.runtime.getURL('options.html')
chrome.tabs.query url: options_url, (tabs) -> chrome.tabs.query url: options_url, (tabs) ->
url = if hash url = if hash
urlParser.href = tabs[0]?.url || options_url urlParser.href = tabs[0]?.url || options_url
@ -124,10 +132,10 @@ angular.module('omegaTarget', []).factory 'omegaTarget', ($q) ->
clearBadge = true clearBadge = true
d = $q['defer']() d = $q['defer']()
chrome.tabs.query {active: true, lastFocusedWindow: true}, (tabs) -> chrome.tabs.query {active: true, lastFocusedWindow: true}, (tabs) ->
if not tabs[0]?.url if tabs.length == 0 or not (tabs[0].pendingUrl || tabs[0].url)
d.resolve(null) d.resolve(null)
return return
args = {tabId: tabs[0].id, url: tabs[0].url} args = {tabId: tabs[0].id, url: tabs[0].pendingUrl || tabs[0].url}
if tabs[0].id and requestInfoCallback if tabs[0].id and requestInfoCallback
connectBackground('tabRequestInfo', args, connectBackground('tabRequestInfo', args,
requestInfoCallback) requestInfoCallback)
@ -136,7 +144,11 @@ angular.module('omegaTarget', []).factory 'omegaTarget', ($q) ->
refreshActivePage: -> refreshActivePage: ->
d = $q['defer']() d = $q['defer']()
chrome.tabs.query {active: true, lastFocusedWindow: true}, (tabs) -> chrome.tabs.query {active: true, lastFocusedWindow: true}, (tabs) ->
if tabs[0].url and not isChromeUrl(tabs[0].url) url = tabs[0].pendingUrl || tabs[0].url
if url and not isChromeUrl(url)
if tabs[0].pendingUrl
chrome.tabs.update(tabs[0].id, {url})
else
chrome.tabs.reload(tabs[0].id, {bypassCache: true}) chrome.tabs.reload(tabs[0].id, {bypassCache: true})
d.resolve() d.resolve()
return d.promise return d.promise

View File

@ -24,25 +24,15 @@ var requestInfoCallback = null;
OmegaTargetPopup = { OmegaTargetPopup = {
getState: function (keys, cb) { getState: function (keys, cb) {
if (typeof localStorage === 'undefined' || !localStorage.length) {
callBackground('getState', [keys], cb); callBackground('getState', [keys], cb);
return; return;
}
var results = {};
keys.forEach(function(key) {
try {
results[key] = JSON.parse(localStorage['omega.local.' + key]);
} catch (_) {
return null;
}
});
if (cb) cb(null, results);
}, },
applyProfile: function (name, cb) { applyProfile: function (name, cb) {
callBackgroundNoReply('applyProfile', [name], cb); callBackgroundNoReply('applyProfile', [name], cb);
}, },
openOptions: function (hash, cb) { openOptions: function (hash, cb) {
var options_url = chrome.extension.getURL('options.html'); var options_url = chrome.runtime.getURL('options.html');
console.log('open options.....')
chrome.tabs.query({ chrome.tabs.query({
url: options_url url: options_url
@ -66,8 +56,8 @@ OmegaTargetPopup = {
}, },
getActivePageInfo: function(cb) { getActivePageInfo: function(cb) {
chrome.tabs.query({active: true, lastFocusedWindow: true}, function (tabs) { chrome.tabs.query({active: true, lastFocusedWindow: true}, function (tabs) {
if (tabs.length === 0 || !tabs[0].url) return cb(); if (tabs.length === 0 || !(tabs[0].pendingUrl || tabs[0].url)) return cb();
var args = {tabId: tabs[0].id, url: tabs[0].url}; var args = {tabId: tabs[0].id, url: tabs[0].pendingUrl || tabs[0].url};
callBackground('getPageInfo', [args], cb) callBackground('getPageInfo', [args], cb)
}); });
}, },

View File

@ -22,7 +22,7 @@ module.exports = class ExternalApi
return unless @disabled return unless @disabled
@options.setProxyNotControllable(null) @options.setProxyNotControllable(null)
chrome.browserAction.setPopup?({popup: 'popup/index.html'}) chrome.action.setPopup?({popup: 'popup/index.html'})
@options.reloadQuickSwitch() @options.reloadQuickSwitch()
@disabled = false @disabled = false
@options.clearBadge() @options.clearBadge()
@ -49,7 +49,7 @@ module.exports = class ExternalApi
if @knownExts[port.sender.id] >= 32 if @knownExts[port.sender.id] >= 32
reason = 'upgrade' reason = 'upgrade'
@options.setProxyNotControllable reason, {text: 'X', color: '#5ab432'} @options.setProxyNotControllable reason, {text: 'X', color: '#5ab432'}
chrome.browserAction.setPopup?({popup: 'popup/index.html'}) chrome.action.setPopup?({popup: 'popup/index.html'})
port.postMessage({action: 'state', state: 'disabled'}) port.postMessage({action: 'state', state: 'disabled'})
when 'enable' when 'enable'
@reenable() @reenable()

View File

@ -1,10 +1,14 @@
Promise = OmegaTarget.Promise Promise = OmegaTarget.Promise
xhr = Promise.promisify(require('xhr')) #xhr = Promise.promisify(require('xhr'))
Url = require('url') Url = require('url')
ContentTypeRejectedError = OmegaTarget.ContentTypeRejectedError ContentTypeRejectedError = OmegaTarget.ContentTypeRejectedError
xhrWrapper = (args...) -> xhrWrapper = (args...) ->
xhr(args...).catch (err) -> fetch(args...).then((response) ->
response.text().then((body) ->
return [response, body]
)
).catch (err) ->
throw err unless err.isOperational throw err unless err.isOperational
if not err.statusCode if not err.statusCode
throw new OmegaTarget.NetworkError(err) throw new OmegaTarget.NetworkError(err)

View File

@ -15,6 +15,7 @@ module.exports = class Inspect
return unless chrome.i18n.getUILanguage? return unless chrome.i18n.getUILanguage?
return if @_enabled return if @_enabled
return
webResource = [ webResource = [
"http://*/*" "http://*/*"

View File

@ -51,11 +51,11 @@ class ChromeOptions extends OmegaTarget.Options
else else
text: '?' text: '?'
color: '#49afcd' color: '#49afcd'
chrome.browserAction.setBadgeText(text: options.text) chrome.action.setBadgeText(text: options.text)
chrome.browserAction.setBadgeBackgroundColor(color: options.color) chrome.action.setBadgeBackgroundColor(color: options.color)
if options.title if options.title
@_badgeTitle = options.title @_badgeTitle = options.title
chrome.browserAction.setTitle(title: options.title) chrome.action.setTitle(title: options.title)
else else
@_badgeTitle = null @_badgeTitle = null
clearBadge: -> clearBadge: ->
@ -65,7 +65,7 @@ class ChromeOptions extends OmegaTarget.Options
if @_proxyNotControllable if @_proxyNotControllable
@setBadge() @setBadge()
else else
chrome.browserAction.setBadgeText?(text: '') chrome.action.setBadgeText?(text: '')
return return
_quickSwitchInit: false _quickSwitchInit: false
@ -82,14 +82,14 @@ class ChromeOptions extends OmegaTarget.Options
if info.checked and not @_quickSwitchCanEnable if info.checked and not @_quickSwitchCanEnable
setOptions.then -> setOptions.then ->
chrome.tabs.create( chrome.tabs.create(
url: chrome.extension.getURL('options.html#/ui') url: chrome.runtime.getURL('options.html#/ui')
) )
if quickSwitch or not chrome.browserAction.setPopup? if quickSwitch or not chrome.action.setPopup?
chrome.browserAction.setPopup?({popup: ''}) chrome.action.setPopup?({popup: ''})
if not @_quickSwitchInit if not @_quickSwitchInit
@_quickSwitchInit = true @_quickSwitchInit = true
chrome.browserAction.onClicked.addListener (tab) => chrome.action.onClicked.addListener (tab) =>
@clearBadge() @clearBadge()
if not @_options['-enableQuickSwitch'] if not @_options['-enableQuickSwitch']
# If we reach here, then the browser does not support popup. # If we reach here, then the browser does not support popup.
@ -101,14 +101,17 @@ class ChromeOptions extends OmegaTarget.Options
index = (index + 1) % profiles.length index = (index + 1) % profiles.length
@applyProfile(profiles[index]).then => @applyProfile(profiles[index]).then =>
if @_options['-refreshOnProfileChange'] if @_options['-refreshOnProfileChange']
url = tab.url url = tab.pendingUrl or tab.url
return if not url return if not url
return if url.substr(0, 6) == 'chrome' return if url.substr(0, 6) == 'chrome'
return if url.substr(0, 6) == 'about:' return if url.substr(0, 6) == 'about:'
return if url.substr(0, 4) == 'moz-' return if url.substr(0, 4) == 'moz-'
if tab.pendingUrl
chrome.tabs.update(tab.id, {url: url})
else
chrome.tabs.reload(tab.id) chrome.tabs.reload(tab.id)
else else
chrome.browserAction.setPopup({popup: 'popup/index.html'}) chrome.action.setPopup({popup: 'popup/index.html'})
chrome.contextMenus?.update('enableQuickSwitch', {checked: !!quickSwitch}) chrome.contextMenus?.update('enableQuickSwitch', {checked: !!quickSwitch})
Promise.resolve() Promise.resolve()
@ -135,14 +138,22 @@ class ChromeOptions extends OmegaTarget.Options
if info.errorCount > 0 if info.errorCount > 0
info.badgeSet = true info.badgeSet = true
badge = {text: info.errorCount.toString(), color: '#f0ad4e'} badge = {text: info.errorCount.toString(), color: '#f0ad4e'}
chrome.browserAction.setBadgeText(text: badge.text, tabId: tabId) chrome.action.setBadgeText(text: badge.text, tabId: tabId)
chrome.browserAction.setBadgeBackgroundColor( .catch((e) ->
console.log('error:',e)
)
chrome.action.setBadgeBackgroundColor(
color: badge.color color: badge.color
tabId: tabId tabId: tabId
).catch((e) ->
console.log('error:',e)
) )
else if info.badgeSet else if info.badgeSet
info.badgeSet = false info.badgeSet = false
chrome.browserAction.setBadgeText(text: '', tabId: tabId) chrome.action.setBadgeText(text: '', tabId: tabId)
.catch((e) ->
console.log('error:',e)
)
@_tabRequestInfoPorts[tabId]?.postMessage({ @_tabRequestInfoPorts[tabId]?.postMessage({
errorCount: info.errorCount errorCount: info.errorCount
summary: info.summary summary: info.summary
@ -210,10 +221,7 @@ class ChromeOptions extends OmegaTarget.Options
upgrade: (options, changes) -> upgrade: (options, changes) ->
super(options).catch (err) => super(options).catch (err) =>
return Promise.reject err if options?['schemaVersion'] return Promise.reject err if options?['schemaVersion']
getOldOptions = if @switchySharp getOldOptions = Promise.reject()
@switchySharp.getOptions().timeout(1000)
else
Promise.reject()
getOldOptions = getOldOptions.catch -> getOldOptions = getOldOptions.catch ->
if options?['config'] if options?['config']
@ -239,16 +247,17 @@ class ChromeOptions extends OmegaTarget.Options
return this && super(upgraded, upgraded) return this && super(upgraded, upgraded)
onFirstRun: (reason) -> onFirstRun: (reason) ->
chrome.tabs.create url: chrome.extension.getURL('options.html') console.log('first run ....')
chrome.tabs.create url: chrome.runtime.getURL('options.html')
getPageInfo: ({tabId, url}) -> getPageInfo: ({tabId, url}) ->
errorCount = @_requestMonitor?.tabInfo[tabId]?.errorCount errorCount = @_requestMonitor?.tabInfo[tabId]?.errorCount
result = if errorCount then {errorCount: errorCount} else null result = if errorCount then {errorCount: errorCount} else null
getBadge = new Promise (resolve, reject) -> getBadge = new Promise (resolve, reject) ->
if not chrome.browserAction.getBadgeText? if not chrome.action.getBadgeText?
resolve('') resolve('')
return return
chrome.browserAction.getBadgeText {tabId: tabId}, (result) -> chrome.action.getBadgeText {tabId: tabId}, (result) ->
resolve(result) resolve(result)
getInspectUrl = @_state.get({inspectUrl: ''}) getInspectUrl = @_state.get({inspectUrl: ''})

View File

@ -25,10 +25,10 @@ class ChromeTabs
tabs.forEach (tab) => tabs.forEach (tab) =>
@_dirtyTabs[tab.id] = tab.id @_dirtyTabs[tab.id] = tab.id
@onUpdated tab.id, {}, tab if tab.active @onUpdated tab.id, {}, tab if tab.active
if chrome.browserAction.setPopup? if chrome.action.setPopup?
chrome.browserAction.setTitle({title: action.title}) chrome.action.setTitle({title: action.title})
else else
chrome.browserAction.setTitle({title: action.shortTitle}) chrome.action.setTitle({title: action.shortTitle})
@setIcon(action.icon) @setIcon(action.icon)
onUpdated: (tabId, changeInfo, tab) -> onUpdated: (tabId, changeInfo, tab) ->
@ -42,32 +42,35 @@ class ChromeTabs
processTab: (tab, changeInfo) -> processTab: (tab, changeInfo) ->
if @_badgeTab if @_badgeTab
for own id of @_badgeTab for own id of @_badgeTab
try chrome.browserAction.setBadgeText?(text: '', tabId: id) try chrome.action.setBadgeText?(text: '', tabId: id)
@_badgeTab = null @_badgeTab = null
if not tab.url? or tab.url.indexOf("chrome") == 0 if not tab.url? or tab.url.indexOf("chrome") == 0
if @_defaultAction if @_defaultAction
chrome.browserAction.setTitle({ chrome.action.setTitle({
title: @_defaultAction.title title: @_defaultAction.title
tabId: tab.id tabId: tab.id
}) })
@clearIcon tab.id @clearIcon tab.id
return return
@actionForUrl(tab.url).then (action) => @actionForUrl(tab.url).then((action) =>
if not action if not action
@clearIcon tab.id @clearIcon tab.id
return return
@setIcon(action.icon, tab.id) @setIcon(action.icon, tab.id)
if chrome.browserAction.setPopup? if chrome.action.setPopup?
chrome.browserAction.setTitle({title: action.title, tabId: tab.id}) chrome.action.setTitle({title: action.title, tabId: tab.id})
else else
chrome.browserAction.setTitle({title: action.shortTitle, tabId: tab.id}) chrome.action.setTitle({title: action.shortTitle, tabId: tab.id})
).catch((e) ->
console.log('error:', e)
)
setTabBadge: (tab, badge) -> setTabBadge: (tab, badge) ->
@_badgeTab ?= {} @_badgeTab ?= {}
@_badgeTab[tab.id] = true @_badgeTab[tab.id] = true
chrome.browserAction.setBadgeText?(text: badge.text, tabId: tab.id) chrome.action.setBadgeText?(text: badge.text, tabId: tab.id)
chrome.browserAction.setBadgeBackgroundColor?( chrome.action.setBadgeBackgroundColor?(
color: badge.color color: badge.color
tabId: tab.id tabId: tab.id
) )
@ -87,11 +90,11 @@ class ChromeTabs
_chromeSetIcon: (params) -> _chromeSetIcon: (params) ->
try try
chrome.browserAction.setIcon?(params, @ignoreError) chrome.action.setIcon?(params, @ignoreError)
catch _ catch _
# Some legacy Chrome versions will panic if there are other icon sizes. # Some legacy Chrome versions will panic if there are other icon sizes.
params.imageData = {19: params.imageData[19], 38: params.imageData[38]} params.imageData = {19: params.imageData[19], 38: params.imageData[38]}
chrome.browserAction.setIcon?(params, @ignoreError) chrome.action.setIcon?(params, @ignoreError)
clearIcon: (tabId) -> clearIcon: (tabId) ->
return unless @_defaultAction?.icon? return unless @_defaultAction?.icon?

View File

@ -128,8 +128,8 @@ module.exports = class WebRequestMonitor
chrome.tabs.onCreated.addListener (tab) => chrome.tabs.onCreated.addListener (tab) =>
return unless tab.id return unless tab.id
@tabInfo[tab.id] = @_newTabInfo() @tabInfo[tab.id] = @_newTabInfo()
chrome.tabs.onRemoved.addListener (tab) => chrome.tabs.onRemoved.addListener (tabId) =>
delete @tabInfo[tab.id] delete @tabInfo[tabId]
chrome.tabs.onReplaced?.addListener (added, removed) => chrome.tabs.onReplaced?.addListener (added, removed) =>
@tabInfo[added] ?= @_newTabInfo() @tabInfo[added] ?= @_newTabInfo()
delete @tabInfo[removed] delete @tabInfo[removed]

View File

@ -1,11 +1,17 @@
Storage = require('./storage') Storage = require('./storage')
Promise = require('bluebird') Promise = require('bluebird')
_globalLocalStorageCache = null
class BrowserStorage extends Storage class BrowserStorage extends Storage
constructor: (@storage, @prefix = '') -> constructor: (@storage, @prefix = '') ->
@proto = Object.getPrototypeOf(@storage) @proto = Object.getPrototypeOf(@storage)
get: (keys) -> get: (keys) ->
promiseResult = idbKeyval.get('localStorage').then((initValuesMap) =>
if !_globalLocalStorageCache
@proto.initValuesMap(initValuesMap)
_globalLocalStorageCache = true
map = {} map = {}
if typeof keys == 'string' if typeof keys == 'string'
map[keys] = undefined map[keys] = undefined
@ -20,15 +26,32 @@ class BrowserStorage extends Storage
map[key] = value if value? map[key] = value if value?
if typeof map[key] == 'undefined' if typeof map[key] == 'undefined'
delete map[key] delete map[key]
Promise.resolve map return map
)
Promise.resolve promiseResult
set: (items) -> set: (items) ->
promiseResult = idbKeyval.get('localStorage').then((initValuesMap) =>
if !_globalLocalStorageCache
@proto.initValuesMap(initValuesMap)
_globalLocalStorageCache = true
for own key, value of items for own key, value of items
value = JSON.stringify(value) value = JSON.stringify(value)
@proto.setItem.call(@storage, @prefix + key, value) @proto.setItem.call(@storage, @prefix + key, value)
Promise.resolve items return items
).then((items) =>
initValuesMap = @proto.getValuesMap()
idbKeyval.set('localStorage', initValuesMap).then( ->
return items
)
)
Promise.resolve promiseResult
remove: (keys) -> remove: (keys) ->
promiseResult = idbKeyval.get('localStorage').then((initValuesMap) =>
if !_globalLocalStorageCache
@proto.initValuesMap(initValuesMap)
_globalLocalStorageCache = true
if not keys? if not keys?
if not @prefix if not @prefix
@proto.clear.call(@storage) @proto.clear.call(@storage)
@ -46,6 +69,12 @@ class BrowserStorage extends Storage
for key in keys for key in keys
@proto.removeItem.call(@storage, @prefix + key) @proto.removeItem.call(@storage, @prefix + key)
Promise.resolve() ).then( =>
initValuesMap = @proto.getValuesMap()
idbKeyval.set('localStorage', initValuesMap).then( ->
return
)
)
Promise.resolve promiseResult
module.exports = BrowserStorage module.exports = BrowserStorage

View File

@ -34,7 +34,7 @@
"ngprogress": "~1.0.4", "ngprogress": "~1.0.4",
"angular-ui-sortable": "~0.13.3", "angular-ui-sortable": "~0.13.3",
"jsondiffpatch": "~0.1.7", "jsondiffpatch": "~0.1.7",
"angular-spectrum-colorpicker": "~1.3.5", "angular-spectrum-colorpicker": "git://github.com/suziwen/angular-spectrum-colorpicker.git#main",
"blob": "*", "blob": "*",
"FileSaver": "=1.3.3", "FileSaver": "=1.3.3",
"angular-ui-utils": "bower-validate", "angular-ui-utils": "bower-validate",

View File

@ -1,4 +1,4 @@
var drawOmega = function (ctx, outerCircleColor, innerCircleColor) { globalThis.drawOmega = function (ctx, outerCircleColor, innerCircleColor) {
ctx.globalCompositeOperation = "source-over"; ctx.globalCompositeOperation = "source-over";
ctx.fillStyle = outerCircleColor; ctx.fillStyle = outerCircleColor;
ctx.beginPath(); ctx.beginPath();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -1,12 +1 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1708946463856" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10155" width="128" height="128" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M704 896h256L1024 768v256H640V809.7792c131.106133-56.490667 224-197.154133 224-361.7792 0-214.4256-157.5936-382.2592-352-382.2592S160 233.5744 160 448c0 164.625067 92.893867 305.3056 224 361.7792V1024H0V768l64 128h256v-32.597333C132.369067 796.945067 0 636.0064 0 448 0 200.567467 229.2224 0 512 0s512 200.567467 512 448c0 188.0064-132.369067 348.945067-320 415.402667v32.597333z" p-id="10156" fill="#31afec"></path></svg>
<svg
xmlns="http://www.w3.org/2000/svg"
width="128"
height="128"
version="1.1">
<path
d="M 64 64 m -56 0 a 56 56 0 1 0 112 0 a 56 56 0 1 0 -112 0 M 64 64 m -28 0 a 28 28 0 1 0 56 0 a 28 28 0 1 0 -56 0"
fill-rule="evenodd"
fill="#31afec"
stroke="none" />
</svg>

Before

Width:  |  Height:  |  Size: 334 B

After

Width:  |  Height:  |  Size: 756 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 870 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 568 B

After

Width:  |  Height:  |  Size: 373 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 692 B

After

Width:  |  Height:  |  Size: 426 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 737 B

After

Width:  |  Height:  |  Size: 489 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 613 B

View File

@ -1,12 +1 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1708946463856" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10155" width="32" height="32" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M704 896h256L1024 768v256H640V809.7792c131.106133-56.490667 224-197.154133 224-361.7792 0-214.4256-157.5936-382.2592-352-382.2592S160 233.5744 160 448c0 164.625067 92.893867 305.3056 224 361.7792V1024H0V768l64 128h256v-32.597333C132.369067 796.945067 0 636.0064 0 448 0 200.567467 229.2224 0 512 0s512 200.567467 512 448c0 188.0064-132.369067 348.945067-320 415.402667v32.597333z" p-id="10156" fill="#31afec"></path></svg>
<svg
xmlns="http://www.w3.org/2000/svg"
width="32"
height="32"
version="1.1">
<path
d="M 16 16 m -16 0 a 16 16 0 1 0 32 0 a 16 16 0 1 0 -32 0 M 16 16 m -8 0 a 8 8 0 1 0 16 0 a 8 8 0 1 0 -16 0"
fill-rule="evenodd"
fill="#31afec"
stroke="none" />
</svg>

Before

Width:  |  Height:  |  Size: 325 B

After

Width:  |  Height:  |  Size: 754 B

View File

@ -96,14 +96,6 @@ angular.module('omega').factory 'omegaDebug', ($window, $rootScope,
omegaDebug omegaDebug
angular.module('omega').factory 'downloadFile', -> angular.module('omega').factory 'downloadFile', ->
if browser?.downloads?.download?
return (blob, filename) ->
url = URL.createObjectURL(blob)
if filename
browser.downloads.download({url: url, filename: filename})
else
browser.downloads.download({url: url})
else
return (blob, filename) -> return (blob, filename) ->
noAutoBom = true noAutoBom = true
saveAs(blob, filename, noAutoBom) saveAs(blob, filename, noAutoBom)

View File

@ -13,7 +13,7 @@ html(lang='en' ng-controller='MasterCtrl' ng-csp)
.container-fluid .container-fluid
header.col-lg-2.col-sm-3.side-nav header.col-lg-2.col-sm-3.side-nav
h1 h1
a(ui-sref='about' title='{{"about_title" | tr}}') {{'appNameShort' | tr}} a(ui-sref='about' title='{{"about_title" | tr}}') Zero Omega
sup.om-experimental.text-danger(ng-show='isExperimental') sup.om-experimental.text-danger(ng-show='isExperimental')
| {{'options_experimental_badge' | tr}} | {{'options_experimental_badge' | tr}}
nav.nav.nav-pills.nav-stacked nav.nav.nav-pills.nav-stacked

View File

@ -1,7 +1,4 @@
(function() { (function() {
$script.ready('om-state', updateMenuByState);
$script.ready('om-page-info', updateMenuByPageInfo);
$script.ready(['om-state', 'om-page-info'], updateMenuByStateAndPageInfo);
var profileTemplate = document.getElementById('js-profile-tpl') var profileTemplate = document.getElementById('js-profile-tpl')
.cloneNode(true); .cloneNode(true);
@ -25,6 +22,10 @@
'RuleListProfile': 3000, 'RuleListProfile': 3000,
}; };
$script.ready('om-state', updateMenuByState);
$script.ready('om-page-info', updateMenuByPageInfo);
$script.ready(['om-state', 'om-page-info'], updateMenuByStateAndPageInfo);
return; return;
function updateMenuByState() { function updateMenuByState() {