Compatible with Firefox mv3

This commit is contained in:
suziwen 2024-03-23 12:58:16 +08:00
parent 9dbf5fe955
commit 85114c1045
14 changed files with 207 additions and 101 deletions

View File

@ -5,6 +5,8 @@ ZeroOmega, forked from SwitchyOmega compatible with manifest v3
[Microsoft Edge Addons](https://microsoftedge.microsoft.com/addons/detail/zeroomegaproxy-switchy-/dmaldhchmoafliphkijbfhaomcgglmgd) [Microsoft Edge Addons](https://microsoftedge.microsoft.com/addons/detail/zeroomegaproxy-switchy-/dmaldhchmoafliphkijbfhaomcgglmgd)
[ZeroOmega--Proxy Switchy](https://addons.mozilla.org/en-US/firefox/addon/zeroomega/)
Manage and switch between multiple proxies quickly & easily. Manage and switch between multiple proxies quickly & easily.
[![Translation status](https://hosted.weblate.org/widgets/switchyomega/-/svg-badge.svg)](https://hosted.weblate.org/engage/switchyomega/?utm_source=widget) [![Translation status](https://hosted.weblate.org/widgets/switchyomega/-/svg-badge.svg)](https://hosted.weblate.org/engage/switchyomega/?utm_source=widget)

View File

@ -0,0 +1,11 @@
#!/bin/bash
. ~/.nvm/nvm.sh
nvm use 11.9.0
rm -f ./release.zip
#minify-all-js ./build -j
cd build
rm -f manifest-chrome.json
mv manifest.json manifest-chrome.json
mv manifest-firefox.json manifest.json
zip -r ../release.zip ./*
mv manifest-chrome.json manifest.json

View File

@ -42,21 +42,23 @@ class LocalStorage {
} }
const instance = new LocalStorage() const instance = new LocalStorage()
globalThis.localStorage = new Proxy(instance, { if (!globalThis.localStorage) {
set: function (obj, prop, value) { globalThis.localStorage = new Proxy(instance, {
if (LocalStorage.prototype.hasOwnProperty(prop)) { set: function (obj, prop, value) {
instance[prop] = value if (LocalStorage.prototype.hasOwnProperty(prop)) {
} else { instance[prop] = value
instance.setItem(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)
}
} }
return true })
}, }
get: function (target, name) {
if (LocalStorage.prototype.hasOwnProperty(name)) {
return instance[name]
}
if (valuesMap.has(name)) {
return instance.getItem(name)
}
}
})

View File

@ -0,0 +1,54 @@
{
"manifest_version": 3,
"name": "ZeroOmega--Proxy Switchy manifest v3 version",
"version": "3.1.0",
"description": "__MSG_manifest_app_description__",
"icons": {
"16": "img/icons/omega-action-16.png",
"24": "img/icons/omega-action-24.png",
"32": "img/icons/omega-action-32.png",
"48": "img/icons/omega-48.png",
"64": "img/icons/omega-64.png",
"128": "img/icons/omega-128.png"
},
"default_locale": "en",
"action": {
"default_icon": {
"16": "img/icons/omega-action-16.png",
"19": "img/icons/omega-action-19.png",
"24": "img/icons/omega-action-24.png",
"32": "img/icons/omega-action-32.png"
},
"default_title": "__MSG_manifest_icon_default_title__",
"default_popup": "popup/index.html"
},
"background": {
"scripts": ["x-background.js"],
"type": "module"
},
"minimum_chrome_version": "111",
"options_ui": {
"page": "options.html",
"browser_style": false,
"open_in_tab": true
},
"commands": {
"_execute_action": { "suggested_key": { "default": "Alt+Shift+O" } }
},
"permissions": [
"proxy",
"tabs",
"alarms",
"storage",
"webRequest",
"webRequestBlocking",
"contextMenus"
],
"host_permissions": ["<all_urls>"],
"browser_specific_settings": {
"gecko": {
"id": "suziwen1@gmail.com",
"strict_min_version": "111.0"
}
}
}

View File

@ -1,7 +1,7 @@
{ {
"manifest_version": 3, "manifest_version": 3,
"name": "ZeroOmega--Proxy Switchy manifest v3 version", "name": "ZeroOmega--Proxy Switchy manifest v3 version",
"version": "3.0.0", "version": "3.1.0",
"description": "__MSG_manifest_app_description__", "description": "__MSG_manifest_app_description__",
"icons": { "icons": {
"16": "img/icons/omega-action-16.png", "16": "img/icons/omega-action-16.png",

View File

@ -184,6 +184,7 @@ proxyImpl = OmegaTargetCurrent.proxy.getProxyImpl(Log)
state.set({proxyImplFeatures: proxyImpl.features}) state.set({proxyImplFeatures: proxyImpl.features})
options = new OmegaTargetCurrent.Options(null, storage, state, Log, sync, options = new OmegaTargetCurrent.Options(null, storage, state, Log, sync,
proxyImpl) proxyImpl)
options.externalApi = new OmegaTargetCurrent.ExternalApi(options) options.externalApi = new OmegaTargetCurrent.ExternalApi(options)
options.externalApi.listen() options.externalApi.listen()

View File

@ -1,25 +1,18 @@
globalThis.window = globalThis if not globalThis.window
globalThis.global = globalThis globalThis.window = globalThis
globalThis.global = globalThis
window.UglifyJS_NoUnsafeEval = true window.UglifyJS_NoUnsafeEval = true
window.OmegaContextMenuQuickSwitchHandler = -> null
chrome.runtime.onInstalled.addListener( -> chrome.runtime.onInstalled.addListener( ->
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? 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: ["action"]
contexts: ["action"] })
})
chrome.contextMenus.onClicked.addListener((info, tab) ->
switch info.menuItemId
when 'enableQuickSwitch'
globalThis.OmegaContextMenuQuickSwitchHandler(info)
)
) )

View File

@ -12,6 +12,50 @@ class ChromeOptions extends OmegaTarget.Options
fetchUrl: fetchUrl fetchUrl: fetchUrl
constructor: (args...) ->
super(args...)
chrome.contextMenus.onClicked.addListener((info, tab) =>
@ready.then( =>
switch info.menuItemId
when 'enableQuickSwitch'
changes = {}
changes['-enableQuickSwitch'] = info.checked
setOptions = @_setOptions(changes)
if info.checked and not @_quickSwitchCanEnable
setOptions.then ->
chrome.tabs.create(
url: chrome.runtime.getURL('options.html#/ui')
)
)
)
chrome.action.onClicked.addListener (tab) =>
if browser?.proxy?.onRequest?
browser.permissions.request({origins: ["<all_urls>"]})
@ready.then( =>
@clearBadge()
if not @_options['-enableQuickSwitch']
# If we reach here, then the browser does not support popup.
# Let's open the popup page in a tab.
chrome.tabs.create(url: 'popup/index.html')
return
profiles = @_options['-quickSwitchProfiles']
index = profiles.indexOf(@_currentProfileName)
index = (index + 1) % profiles.length
@applyProfile(profiles[index]).then =>
if @_options['-refreshOnProfileChange']
url = tab.pendingUrl or tab.url
return if not url
return if url.substr(0, 6) == 'chrome'
return if url.substr(0, 6) == 'about:'
return if url.substr(0, 4) == 'moz-'
if tab.pendingUrl
chrome.tabs.update(tab.id, {url: url})
else
chrome.tabs.reload(tab.id)
)
updateProfile: (args...) -> updateProfile: (args...) ->
super(args...).then (results) -> super(args...).then (results) ->
error = false error = false
@ -68,48 +112,11 @@ class ChromeOptions extends OmegaTarget.Options
chrome.action.setBadgeText?(text: '') chrome.action.setBadgeText?(text: '')
return return
_quickSwitchInit: false
_quickSwitchHandlerReady: false
_quickSwitchCanEnable: false _quickSwitchCanEnable: false
setQuickSwitch: (quickSwitch, canEnable) -> setQuickSwitch: (quickSwitch, canEnable) ->
@_quickSwitchCanEnable = canEnable @_quickSwitchCanEnable = canEnable
if not @_quickSwitchHandlerReady if quickSwitch
@_quickSwitchHandlerReady = true chrome.action.setPopup({popup: ''})
window.OmegaContextMenuQuickSwitchHandler = (info) =>
changes = {}
changes['-enableQuickSwitch'] = info.checked
setOptions = @_setOptions(changes)
if info.checked and not @_quickSwitchCanEnable
setOptions.then ->
chrome.tabs.create(
url: chrome.runtime.getURL('options.html#/ui')
)
if quickSwitch or not chrome.action.setPopup?
chrome.action.setPopup?({popup: ''})
if not @_quickSwitchInit
@_quickSwitchInit = true
chrome.action.onClicked.addListener (tab) =>
@clearBadge()
if not @_options['-enableQuickSwitch']
# If we reach here, then the browser does not support popup.
# Let's open the popup page in a tab.
chrome.tabs.create(url: 'popup/index.html')
return
profiles = @_options['-quickSwitchProfiles']
index = profiles.indexOf(@_currentProfileName)
index = (index + 1) % profiles.length
@applyProfile(profiles[index]).then =>
if @_options['-refreshOnProfileChange']
url = tab.pendingUrl or tab.url
return if not url
return if url.substr(0, 6) == 'chrome'
return if url.substr(0, 6) == 'about:'
return if url.substr(0, 4) == 'moz-'
if tab.pendingUrl
chrome.tabs.update(tab.id, {url: url})
else
chrome.tabs.reload(tab.id)
else else
chrome.action.setPopup({popup: 'popup/index.html'}) chrome.action.setPopup({popup: 'popup/index.html'})

View File

@ -10,7 +10,7 @@ class BrowserStorage extends Storage
get: (keys) -> get: (keys) ->
promiseResult = idbKeyval.get('localStorage').then((initValuesMap) => promiseResult = idbKeyval.get('localStorage').then((initValuesMap) =>
if !_globalLocalStorageCache if !_globalLocalStorageCache
@proto.initValuesMap(initValuesMap) @proto.initValuesMap?(initValuesMap)
_globalLocalStorageCache = true _globalLocalStorageCache = true
map = {} map = {}
if typeof keys == 'string' if typeof keys == 'string'
@ -33,13 +33,14 @@ class BrowserStorage extends Storage
set: (items) -> set: (items) ->
promiseResult = idbKeyval.get('localStorage').then((initValuesMap) => promiseResult = idbKeyval.get('localStorage').then((initValuesMap) =>
if !_globalLocalStorageCache if !_globalLocalStorageCache
@proto.initValuesMap(initValuesMap) @proto.initValuesMap?(initValuesMap)
_globalLocalStorageCache = true _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)
return items return items
).then((items) => ).then((items) =>
return items unless @proto.getValuesMap
initValuesMap = @proto.getValuesMap() initValuesMap = @proto.getValuesMap()
idbKeyval.set('localStorage', initValuesMap).then( -> idbKeyval.set('localStorage', initValuesMap).then( ->
return items return items
@ -50,7 +51,7 @@ class BrowserStorage extends Storage
remove: (keys) -> remove: (keys) ->
promiseResult = idbKeyval.get('localStorage').then((initValuesMap) => promiseResult = idbKeyval.get('localStorage').then((initValuesMap) =>
if !_globalLocalStorageCache if !_globalLocalStorageCache
@proto.initValuesMap(initValuesMap) @proto.initValuesMap?(initValuesMap)
_globalLocalStorageCache = true _globalLocalStorageCache = true
if not keys? if not keys?
if not @prefix if not @prefix
@ -70,6 +71,7 @@ class BrowserStorage extends Storage
@proto.removeItem.call(@storage, @prefix + key) @proto.removeItem.call(@storage, @prefix + key)
).then( => ).then( =>
return unless @proto.getValuesMap
initValuesMap = @proto.getValuesMap() initValuesMap = @proto.getValuesMap()
idbKeyval.set('localStorage', initValuesMap).then( -> idbKeyval.set('localStorage', initValuesMap).then( ->
return return

View File

@ -21,7 +21,7 @@
"tests" "tests"
], ],
"dependencies": { "dependencies": {
"angular": "~1.7.2", "angular": "~1.8.2",
"angular-animate": "~1.7.2", "angular-animate": "~1.7.2",
"angular-loader": "~1.7.2", "angular-loader": "~1.7.2",
"angular-i18n": "~1.7.2", "angular-i18n": "~1.7.2",
@ -127,6 +127,6 @@
} }
}, },
"resolutions": { "resolutions": {
"angular": "~1.7.2" "angular": "~1.8.2"
} }
} }

View File

@ -178,7 +178,7 @@ module.controller 'PopupCtrl', ($scope, $window, $q, omegaTarget,
$scope.saveExternal = -> $scope.saveExternal = ->
$scope.nameExternal.open = false $scope.nameExternal.open = false
name = $scope.externalProfile.name name = $scope.externalProfile?.name
if name if name
omegaTarget.addProfile($scope.externalProfile).then -> omegaTarget.addProfile($scope.externalProfile).then ->
omegaTarget.applyProfile(name).then -> omegaTarget.applyProfile(name).then ->

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<button id="grant-permissions-btn">grant site permissions</button>
<script src="js/grant_permissions.js"></script>
</body>
</html>

View File

@ -0,0 +1,9 @@
const btn = document.querySelector('#grant-permissions-btn')
btn.onclick = async ()=>{
const permissionValue = {origins: ["<all_urls>"]}
const hasPermission = await browser.permissions.request(permissionValue);
if (hasPermission) {
location.href = 'index.html'
}
}

View File

@ -2,21 +2,35 @@ window.OmegaPopup = {};
$script(['js/index.js', 'js/profiles.js', 'js/keyboard.js'], 'om-main'); $script(['js/index.js', 'js/profiles.js', 'js/keyboard.js'], 'om-main');
$script(['js/i18n.js']); $script(['js/i18n.js']);
$script('../js/omega_target_popup.js', 'om-target', function() { $script('../js/omega_target_popup.js', 'om-target', function() {
OmegaTargetPopup.getActivePageInfo(function(err, info) { function init(){
window.OmegaPopup.pageInfo = info; OmegaTargetPopup.getActivePageInfo(function(err, info) {
$script.done('om-page-info'); window.OmegaPopup.pageInfo = info;
}); $script.done('om-page-info');
OmegaTargetPopup.getState([ });
'availableProfiles', OmegaTargetPopup.getState([
'currentProfileName', 'availableProfiles',
'validResultProfiles', 'currentProfileName',
'isSystemProfile', 'validResultProfiles',
'currentProfileCanAddRule', 'isSystemProfile',
'proxyNotControllable', 'currentProfileCanAddRule',
'externalProfile', 'proxyNotControllable',
'showExternalProfile', 'externalProfile',
], function(err, state) { 'showExternalProfile',
window.OmegaPopup.state = state; ], function(err, state) {
$script.done('om-state'); window.OmegaPopup.state = state;
}); $script.done('om-state');
});
}
const permissionValue = {origins: ["<all_urls>"]}
if (globalThis.browser && browser.proxy && browser.proxy.onRequest){
chrome.permissions.contains(permissionValue).then((hasPermission)=>{
if (!hasPermission) {
location.href = 'grant_permissions.html'
} else {
init();
}
})
} else {
init();
}
}); });