mirror of
https://github.com/zero-peak/ZeroOmega.git
synced 2025-01-22 15:08:12 -05:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
6f2763bff3
@ -274,6 +274,16 @@ msgstr "Proxy Změny"
|
||||
msgid "options_revertProxyChanges"
|
||||
msgstr "Reverzní proxy změněna jinou aplikací."
|
||||
|
||||
msgid "options_group_networkRequests"
|
||||
msgstr "Network Requests"
|
||||
|
||||
msgid "options_monitorWebRequests"
|
||||
msgstr "Show count of failed web requests for resources in the current tab."
|
||||
|
||||
msgid "options_monitorWebRequestsHelp"
|
||||
msgstr "A yellow badge will be displayed on the icon if some resources fail to load,<br>"
|
||||
"and you can set the profile for such resources conveniently via the popup menu."
|
||||
|
||||
msgid "options_downloadOptions"
|
||||
msgstr "Nastavení stahování"
|
||||
|
||||
@ -992,6 +1002,18 @@ msgstr "Report problémů"
|
||||
msgid "popup_errorLog"
|
||||
msgstr "Protokol chyb"
|
||||
|
||||
msgid "popup_requestErrorCount"
|
||||
msgstr "$COUNT$ failed resources"
|
||||
|
||||
msgid "popup_requestErrorWarning"
|
||||
msgstr "A few resources failed to load due to network issues."
|
||||
|
||||
msgid "popup_requestErrorAddCondition"
|
||||
msgstr "You can review the following domains and use proxy for them when appropriate."
|
||||
|
||||
msgid "options_resultProfileForSelectedDomains"
|
||||
msgstr "Use this profile for all selected domains"
|
||||
|
||||
msgid "popup_issueTemplate"
|
||||
msgstr ""
|
||||
"\n"
|
||||
|
@ -274,6 +274,16 @@ msgstr "Proxy Changes"
|
||||
msgid "options_revertProxyChanges"
|
||||
msgstr "Revert proxy changes done by other apps."
|
||||
|
||||
msgid "options_group_networkRequests"
|
||||
msgstr "Network Requests"
|
||||
|
||||
msgid "options_monitorWebRequests"
|
||||
msgstr "Show count of failed web requests for resources in the current tab."
|
||||
|
||||
msgid "options_monitorWebRequestsHelp"
|
||||
msgstr "A yellow badge will be displayed on the icon if some resources fail to load,<br>"
|
||||
"and you can set the profile for such resources conveniently via the popup menu."
|
||||
|
||||
msgid "options_downloadOptions"
|
||||
msgstr "Download Options"
|
||||
|
||||
@ -989,6 +999,18 @@ msgstr "Report issues"
|
||||
msgid "popup_errorLog"
|
||||
msgstr "Error log"
|
||||
|
||||
msgid "popup_requestErrorCount"
|
||||
msgstr "$COUNT$ failed resources"
|
||||
|
||||
msgid "popup_requestErrorWarning"
|
||||
msgstr "A few resources failed to load due to network issues."
|
||||
|
||||
msgid "popup_requestErrorAddCondition"
|
||||
msgstr "You can review the following domains and use proxy for them when appropriate."
|
||||
|
||||
msgid "options_resultProfileForSelectedDomains"
|
||||
msgstr "Use this profile for all selected domains"
|
||||
|
||||
msgid "popup_issueTemplate"
|
||||
msgstr ""
|
||||
"\n"
|
||||
|
@ -277,6 +277,16 @@ msgstr "Proxy Changes"
|
||||
msgid "options_revertProxyChanges"
|
||||
msgstr "Revert proxy changes done by other apps."
|
||||
|
||||
msgid "options_group_networkRequests"
|
||||
msgstr "Network Requests"
|
||||
|
||||
msgid "options_monitorWebRequests"
|
||||
msgstr "Show count of failed web requests for resources in the current tab."
|
||||
|
||||
msgid "options_monitorWebRequestsHelp"
|
||||
msgstr "A yellow badge will be displayed on the icon if some resources fail to load,<br>"
|
||||
"and you can set the profile for such resources conveniently via the popup menu."
|
||||
|
||||
msgid "options_downloadOptions"
|
||||
msgstr "Download Options"
|
||||
|
||||
@ -1003,6 +1013,18 @@ msgstr "Report issues"
|
||||
msgid "popup_errorLog"
|
||||
msgstr "Error log"
|
||||
|
||||
msgid "popup_requestErrorCount"
|
||||
msgstr "$COUNT$ failed resources"
|
||||
|
||||
msgid "popup_requestErrorWarning"
|
||||
msgstr "A few resources failed to load due to network issues."
|
||||
|
||||
msgid "popup_requestErrorAddCondition"
|
||||
msgstr "You can review the following domains and use proxy for them when appropriate."
|
||||
|
||||
msgid "options_resultProfileForSelectedDomains"
|
||||
msgstr "Use this profile for all selected domains"
|
||||
|
||||
msgid "popup_issueTemplate"
|
||||
msgstr ""
|
||||
"\n"
|
||||
|
@ -247,6 +247,16 @@ msgstr "代理设置变化"
|
||||
msgid "options_revertProxyChanges"
|
||||
msgstr "撤消其他扩展对代理的更改。"
|
||||
|
||||
msgid "options_group_networkRequests"
|
||||
msgstr "网络请求"
|
||||
|
||||
msgid "options_monitorWebRequests"
|
||||
msgstr "在图标上显示当前页面中由于网络原因而未加载的资源数量。"
|
||||
|
||||
msgid "options_monitorWebRequestsHelp"
|
||||
msgstr "启用此选项后,如有资源加载失败,则图标上会显示数字提示。<br>"
|
||||
"此时,您可以通过弹出菜单一次设置这些资源使用的情景模式,操作十分便捷。"
|
||||
|
||||
msgid "options_downloadOptions"
|
||||
msgstr "下载选项"
|
||||
|
||||
@ -868,6 +878,18 @@ msgstr "反馈问题"
|
||||
msgid "popup_errorLog"
|
||||
msgstr "错误日志"
|
||||
|
||||
msgid "popup_requestErrorCount"
|
||||
msgstr "$COUNT$个资源未加载"
|
||||
|
||||
msgid "popup_requestErrorWarning"
|
||||
msgstr "由于网络原因,此页面部分资源加载失败。"
|
||||
|
||||
msgid "popup_requestErrorAddCondition"
|
||||
msgstr "您可以查看以下域名,并根据实际情况确定是否对其使用代理。"
|
||||
|
||||
msgid "options_resultProfileForSelectedDomains"
|
||||
msgstr "对所有选中域名使用此情景模式:"
|
||||
|
||||
msgid "popup_issueTemplate"
|
||||
msgstr ""
|
||||
"\n"
|
||||
|
@ -247,6 +247,16 @@ msgstr "代理設定變化"
|
||||
msgid "options_revertProxyChanges"
|
||||
msgstr "撤消其他擴展對代理的更改。"
|
||||
|
||||
msgid "options_group_networkRequests"
|
||||
msgstr "網路請求"
|
||||
|
||||
msgid "options_monitorWebRequests"
|
||||
msgstr "在圖示上顯示當前頁面中由於網路原因而未載入的資源數量。"
|
||||
|
||||
msgid "options_monitorWebRequestsHelp"
|
||||
msgstr "啟用此選項後,如有資源載入失敗,則圖示上會顯示數字提示。<br>"
|
||||
"此時,您可以通過彈出選單一次設定這些資源使用的情景模式,操作十分便捷。"
|
||||
|
||||
msgid "options_downloadOptions"
|
||||
msgstr "下載選項"
|
||||
|
||||
@ -868,6 +878,18 @@ msgstr "反饋問題"
|
||||
msgid "popup_errorLog"
|
||||
msgstr "錯誤日誌"
|
||||
|
||||
msgid "popup_requestErrorCount"
|
||||
msgstr "$COUNT$個資源未載入"
|
||||
|
||||
msgid "popup_requestErrorWarning"
|
||||
msgstr "由於網路原因,此頁面部分資源載入失敗。"
|
||||
|
||||
msgid "popup_requestErrorAddCondition"
|
||||
msgstr "您可以檢視以下域名,並根據實際情況確定是否對其使用代理。"
|
||||
|
||||
msgid "options_resultProfileForSelectedDomains"
|
||||
msgstr "對所有選中域名使用此情景模式:"
|
||||
|
||||
msgid "popup_issueTemplate"
|
||||
msgstr ""
|
||||
"\n"
|
||||
|
@ -38,3 +38,20 @@ class AttachedCache
|
||||
obj[@prop] = value
|
||||
|
||||
exports.AttachedCache = AttachedCache
|
||||
|
||||
exports.getBaseDomain = (domain) ->
|
||||
return domain if domain.indexOf(':') > 0 # IPv6
|
||||
lastCharCode = domain.charCodeAt(domain.length - 1)
|
||||
return domain if 48 <= lastCharCode <= 57 # IP address ending with number.
|
||||
segments = domain.split('.')
|
||||
if segments.length <= 2
|
||||
return domain
|
||||
if segments[0] == 'www'
|
||||
segments.shift()
|
||||
len = segments.length
|
||||
if len <= 2
|
||||
return segments.join('.')
|
||||
if segments[len - 2].length <= 2
|
||||
return segments[len - 3] + '.' + segments[len - 2] + '.' + segments[len - 1]
|
||||
else
|
||||
return segments[len - 2] + '.' + segments[len - 1]
|
||||
|
29
omega-pac/test/utils.coffee
Normal file
29
omega-pac/test/utils.coffee
Normal file
@ -0,0 +1,29 @@
|
||||
chai = require 'chai'
|
||||
should = chai.should()
|
||||
Utils = require '../src/utils'
|
||||
|
||||
describe 'getBaseDomain', ->
|
||||
{getBaseDomain} = Utils
|
||||
it 'should return domains with zero level unchanged', ->
|
||||
getBaseDomain('someinternaldomain').should.equal('someinternaldomain')
|
||||
it 'should return domains with one level unchanged', ->
|
||||
getBaseDomain('example.com').should.equal('example.com')
|
||||
getBaseDomain('e.test').should.equal('e.test')
|
||||
getBaseDomain('a.b').should.equal('a.b')
|
||||
it 'should ignore the leading www with domains with two or more levels', ->
|
||||
getBaseDomain('www.example.com').should.equal('example.com')
|
||||
getBaseDomain('www.e.test').should.equal('e.test')
|
||||
getBaseDomain('www.a.b').should.equal('a.b')
|
||||
it 'should assume two-segment TLD if len(second segment from last) <= 2', ->
|
||||
getBaseDomain('images.google.co.uk').should.equal('google.co.uk')
|
||||
getBaseDomain('images.google.co.jp').should.equal('google.co.jp')
|
||||
getBaseDomain('ab.de.ef.test').should.equal('de.ef.test')
|
||||
it 'should assume one-segment TLD and keep two segments as base otherwise', ->
|
||||
getBaseDomain('subdomain.example.com').should.equal('example.com')
|
||||
getBaseDomain('some.site.example.net').should.equal('example.net')
|
||||
getBaseDomain('some.site.abc.test').should.equal('abc.test')
|
||||
getBaseDomain('ab.de.efg.test').should.equal('efg.test')
|
||||
it 'should not try to modify IP address literals', ->
|
||||
getBaseDomain('127.0.0.1').should.equal('127.0.0.1')
|
||||
getBaseDomain('[::1]').should.equal('[::1]')
|
||||
getBaseDomain('::f').should.equal('::f')
|
@ -32,6 +32,8 @@ module.exports = (grunt) ->
|
||||
for i in [0...refs.length]
|
||||
placeholder = refs[i] ? ('_unused_' + i)
|
||||
placeholders[placeholder] = {content: '$' + i}
|
||||
if message == ' '
|
||||
message = ''
|
||||
result[key] =
|
||||
message: message
|
||||
placeholders: placeholders
|
||||
|
@ -4,6 +4,7 @@ module.exports =
|
||||
ChromeTabs: require('./src/tabs')
|
||||
SwitchySharp: require('./src/switchysharp')
|
||||
ExternalApi: require('./src/external_api.coffee')
|
||||
WebRequestMonitor: require('./src/web_request_monitor')
|
||||
Inspect: require('./src/inspect')
|
||||
Url: require('url')
|
||||
|
||||
|
@ -29,10 +29,16 @@ angular.module('omegaTarget', []).factory 'omegaTarget', ($q) ->
|
||||
d.resolve(response.result)
|
||||
)
|
||||
return d.promise
|
||||
connectBackground = (name, message, callback) ->
|
||||
port = chrome.runtime.connect({name: name})
|
||||
port.postMessage(message)
|
||||
port.onMessage.addListener(callback)
|
||||
return
|
||||
|
||||
isChromeUrl = (url) -> url.substr(0, 6) == 'chrome'
|
||||
|
||||
optionsChangeCallback = []
|
||||
requestInfoCallback = null
|
||||
prefix = 'omega.local.'
|
||||
urlParser = document.createElement('a')
|
||||
omegaTarget =
|
||||
@ -113,33 +119,19 @@ angular.module('omegaTarget', []).factory 'omegaTarget', ($q) ->
|
||||
d = $q['defer']()
|
||||
chrome.tabs.query {active: true, lastFocusedWindow: true}, (tabs) ->
|
||||
if not tabs[0]?.url
|
||||
d.resolve(undefined)
|
||||
d.resolve(null)
|
||||
return
|
||||
getBadge = $q['defer']()
|
||||
chrome.browserAction.getBadgeText {tabId: tabs[0]?.id}, (result) ->
|
||||
getBadge.resolve(result)
|
||||
$q.all([getBadge.promise, omegaTarget.state('inspectUrl')
|
||||
]).then ([badge, url]) ->
|
||||
if badge != '#' || not url
|
||||
d.resolve(tabs[0]?.url)
|
||||
else
|
||||
clearBadge = false
|
||||
d.resolve(url)
|
||||
return d.promise.then (url) ->
|
||||
# First, try to clear badges on opening the popup.
|
||||
callBackground('clearBadge') if clearBadge
|
||||
return null if not url or isChromeUrl(url)
|
||||
urlParser.href = url
|
||||
domain = urlParser.hostname
|
||||
callBackground('queryTempRule', domain).then (profileName) ->
|
||||
url: url
|
||||
domain: domain
|
||||
tempRuleProfileName: profileName
|
||||
args = {tabId: tabs[0].id, url: tabs[0].url}
|
||||
if tabs[0].id and requestInfoCallback
|
||||
connectBackground('tabRequestInfo', args,
|
||||
requestInfoCallback)
|
||||
d.resolve(callBackground('getPageInfo', args))
|
||||
return d.promise
|
||||
refreshActivePage: ->
|
||||
d = $q['defer']()
|
||||
chrome.tabs.query {active: true, lastFocusedWindow: true}, (tabs) ->
|
||||
if tabs[0].url and not isChromeUrl(tabs[0].url)
|
||||
chrome.tabs.reload(tabs[0].id)
|
||||
chrome.tabs.reload(tabs[0].id, {bypassCache: true})
|
||||
d.resolve()
|
||||
return d.promise
|
||||
openManage: ->
|
||||
@ -148,5 +140,7 @@ angular.module('omegaTarget', []).factory 'omegaTarget', ($q) ->
|
||||
chrome.tabs.create url: 'chrome://extensions/configureCommands'
|
||||
setOptionsSync: (enabled, args) ->
|
||||
callBackground('setOptionsSync', enabled, args)
|
||||
setRequestInfoCallback: (callback) ->
|
||||
requestInfoCallback = callback
|
||||
|
||||
return omegaTarget
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 2,
|
||||
"name": "__MSG_manifest_app_name__",
|
||||
"version": "2.3.5",
|
||||
"version": "2.3.7",
|
||||
"description": "__MSG_manifest_app_description__",
|
||||
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkhwZJT76btQ04EEMOFtZPLESD1TmSVjbLjs0OyesD9Ht8YllFPfJ3qmtbSQGVuvmxH1GK/jUO2QcEWb8bHuOjoRlq20fi5j5Aq90O8FKET+y5D8PxCyi3WmnquiEwaE5cNmaCsw/G2JlO+bZOtdQ/QKOvMxBAegABYimEGfSvCMVUEvpymys0gBhLoch72zPAiJUBkf0z8BtjYTueMRcRXkrSeRPLygUDQnZ1TkQWMYYBp/zqpD5ggxytAklEMQzR9Hn0lqu5s7iuUAgihbysPn/8Wh00Zj5FySpK//KcpG3JS7UWxC28oSt8z5ZR3YimnX+HX3P36V0mC1pgM4o7wIDAQAB",
|
||||
"icons": {
|
||||
|
@ -20,6 +20,7 @@
|
||||
"po2json": "^0.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"heap": "^0.2.6",
|
||||
"omega-target": "../omega-target",
|
||||
"omega-web": "../omega-web",
|
||||
"xhr": "^1.16.0"
|
||||
|
@ -2,11 +2,12 @@ OmegaTarget = require('omega-target')
|
||||
OmegaPac = OmegaTarget.OmegaPac
|
||||
Promise = OmegaTarget.Promise
|
||||
xhr = Promise.promisify(require('xhr'))
|
||||
url = require('url')
|
||||
Url = require('url')
|
||||
chromeApiPromisifyAll = require('./chrome_api')
|
||||
proxySettings = chromeApiPromisifyAll(chrome.proxy.settings)
|
||||
parseExternalProfile = require('./parse_external_profile')
|
||||
ProxyAuth = require('./proxy_auth')
|
||||
WebRequestMonitor = require('./web_request_monitor')
|
||||
|
||||
class ChromeOptions extends OmegaTarget.Options
|
||||
_inspect: null
|
||||
@ -15,10 +16,10 @@ class ChromeOptions extends OmegaTarget.Options
|
||||
|
||||
fetchUrl: (dest_url, opt_bypass_cache) ->
|
||||
if opt_bypass_cache
|
||||
parsed = url.parse(dest_url, true)
|
||||
parsed = Url.parse(dest_url, true)
|
||||
parsed.search = undefined
|
||||
parsed.query['_'] = Date.now()
|
||||
dest_url = url.format(parsed)
|
||||
dest_url = Url.format(parsed)
|
||||
xhr(dest_url).get(1)
|
||||
|
||||
updateProfile: (args...) ->
|
||||
@ -188,6 +189,44 @@ class ChromeOptions extends OmegaTarget.Options
|
||||
@_inspect.disable()
|
||||
return Promise.resolve()
|
||||
|
||||
_requestMonitor: null
|
||||
_monitorWebRequests: false
|
||||
_tabRequestInfoPorts: null
|
||||
setMonitorWebRequests: (enabled) ->
|
||||
@_monitorWebRequests = enabled
|
||||
if enabled and not @_requestMonitor?
|
||||
@_tabRequestInfoPorts = {}
|
||||
@_requestMonitor = new WebRequestMonitor()
|
||||
@_requestMonitor.watchTabs (tabId, info) =>
|
||||
return unless @_monitorWebRequests
|
||||
if info.errorCount > 0
|
||||
info.badgeSet = true
|
||||
badge = {text: info.errorCount.toString(), color: '#f0ad4e'}
|
||||
chrome.browserAction.setBadgeText(text: badge.text, tabId: tabId)
|
||||
chrome.browserAction.setBadgeBackgroundColor(
|
||||
color: badge.color
|
||||
tabId: tabId
|
||||
)
|
||||
else if info.badgeSet
|
||||
info.badgeSet = false
|
||||
chrome.browserAction.setBadgeText(text: '', tabId: tabId)
|
||||
@_tabRequestInfoPorts[tabId]?.postMessage(
|
||||
@_requestMonitor.summarizeErrors(info, OmegaPac.getBaseDomain))
|
||||
|
||||
chrome.runtime.onConnect.addListener (port) =>
|
||||
return unless port.name == 'tabRequestInfo'
|
||||
return unless @_monitorWebRequests
|
||||
tabId = null
|
||||
port.onMessage.addListener (msg) =>
|
||||
tabId = msg.tabId
|
||||
@_tabRequestInfoPorts[tabId] = port
|
||||
info = @_requestMonitor.tabInfo[tabId]
|
||||
if info
|
||||
summ = @_requestMonitor.summarizeErrors info, OmegaPac.getBaseDomain
|
||||
port.postMessage(summ)
|
||||
port.onDisconnect.addListener =>
|
||||
delete @_tabRequestInfoPorts[tabId] if tabId?
|
||||
|
||||
_alarms: null
|
||||
schedule: (name, periodInMinutes, callback) ->
|
||||
name = 'omega.' + name
|
||||
@ -264,5 +303,24 @@ class ChromeOptions extends OmegaTarget.Options
|
||||
onFirstRun: (reason) ->
|
||||
chrome.tabs.create url: chrome.extension.getURL('options.html')
|
||||
|
||||
getPageInfo: ({tabId, url}) ->
|
||||
getBadge = new Promise (resolve, reject) ->
|
||||
chrome.browserAction.getBadgeText {tabId: tabId}, (result) ->
|
||||
resolve(result)
|
||||
|
||||
getInspectUrl = @_state.get({inspectUrl: ''})
|
||||
Promise.join getBadge, getInspectUrl, (badge, {inspectUrl}) =>
|
||||
if badge == '#' and inspectUrl
|
||||
url = inspectUrl
|
||||
else
|
||||
@clearBadge()
|
||||
return null if not url or url.substr(0, 6) == 'chrome'
|
||||
domain = OmegaPac.getBaseDomain(Url.parse(url).hostname)
|
||||
return {
|
||||
url: url
|
||||
domain: domain
|
||||
tempRuleProfileName: @queryTempRule(domain)
|
||||
}
|
||||
|
||||
module.exports = ChromeOptions
|
||||
|
||||
|
183
omega-target-chromium-extension/src/web_request_monitor.coffee
Normal file
183
omega-target-chromium-extension/src/web_request_monitor.coffee
Normal file
@ -0,0 +1,183 @@
|
||||
Heap = require('heap')
|
||||
Url = require('url')
|
||||
|
||||
module.exports = class WebRequestMonitor
|
||||
constructor: ->
|
||||
@_requests = {}
|
||||
@_recentRequests = new Heap((a, b) -> a._startTime - b._startTime)
|
||||
@_callbacks = []
|
||||
@_tabCallbacks = []
|
||||
@tabInfo = {}
|
||||
|
||||
_callbacks: null
|
||||
watching: false
|
||||
timer: null
|
||||
watch: (callback) ->
|
||||
@_callbacks.push(callback)
|
||||
return if @watching
|
||||
if not chrome.webRequest
|
||||
console.log('Request monitor disabled! No webRequest permission.')
|
||||
return
|
||||
chrome.webRequest.onBeforeRequest.addListener(
|
||||
@_requestStart.bind(this)
|
||||
{urls: ['<all_urls>']}
|
||||
)
|
||||
chrome.webRequest.onHeadersReceived.addListener(
|
||||
@_requestHeadersReceived.bind(this)
|
||||
{urls: ['<all_urls>']}
|
||||
)
|
||||
chrome.webRequest.onBeforeRedirect.addListener(
|
||||
@_requestRedirected.bind(this)
|
||||
{urls: ['<all_urls>']}
|
||||
)
|
||||
chrome.webRequest.onCompleted.addListener(
|
||||
@_requestDone.bind(this)
|
||||
{urls: ['<all_urls>']}
|
||||
)
|
||||
chrome.webRequest.onErrorOccurred.addListener(
|
||||
@_requestError.bind(this)
|
||||
{urls: ['<all_urls>']}
|
||||
)
|
||||
@watching = true
|
||||
|
||||
_requests: null
|
||||
_recentRequests: null
|
||||
|
||||
_requestStart: (req) ->
|
||||
return if req.tabId < 0
|
||||
req._startTime = Date.now()
|
||||
@_requests[req.requestId] = req
|
||||
@_recentRequests.push(req)
|
||||
@timer ?= setInterval(@_tick.bind(this), 1000)
|
||||
for callback in @_callbacks
|
||||
callback('start', req)
|
||||
|
||||
_tick: ->
|
||||
now = Date.now()
|
||||
while (req = @_recentRequests.peek())
|
||||
reqInfo = @_requests[req.requestId]
|
||||
if reqInfo and not reqInfo.noTimeout
|
||||
if now - req._startTime < 5000
|
||||
break
|
||||
else
|
||||
reqInfo.timeoutCalled = true
|
||||
for callback in @_callbacks
|
||||
callback('timeout', reqInfo)
|
||||
@_recentRequests.pop()
|
||||
|
||||
_requestHeadersReceived: (req) ->
|
||||
reqInfo = @_requests[req.requestId]
|
||||
return unless reqInfo
|
||||
reqInfo.noTimeout = true
|
||||
if reqInfo.timeoutCalled
|
||||
for callback in @_callbacks
|
||||
callback('ongoing', req)
|
||||
|
||||
_requestRedirected: (req) ->
|
||||
if req.url.indexOf('data:') == 0
|
||||
@_requestDone(req)
|
||||
|
||||
_requestError: (req) ->
|
||||
reqInfo = @_requests[req.requestId]
|
||||
delete @_requests[req.requestId]
|
||||
|
||||
return if req.tabId < 0
|
||||
return if req.error.indexOf('BLOCKED') >= 0
|
||||
return if req.error.indexOf('net::ERR_FILE_') == 0
|
||||
return if req.url.indexOf('file:') == 0
|
||||
return if req.url.indexOf('chrome') == 0
|
||||
return unless reqInfo
|
||||
if req.error == 'net::ERR_ABORTED'
|
||||
if reqInfo.timeoutCalled and not reqInfo.noTimeout
|
||||
for callback in @_callbacks
|
||||
callback('timeoutAbort', req)
|
||||
return
|
||||
for callback in @_callbacks
|
||||
callback('error', req)
|
||||
|
||||
_requestDone: (req) ->
|
||||
for callback in @_callbacks
|
||||
callback('done', req)
|
||||
delete @_requests[req.requestId]
|
||||
|
||||
eventCategory:
|
||||
start: 'ongoing'
|
||||
ongoing: 'ongoing'
|
||||
timeout: 'error'
|
||||
error: 'error'
|
||||
timeoutAbort: 'error'
|
||||
done: 'done'
|
||||
|
||||
tabsWatching: false
|
||||
_tabCallbacks: null
|
||||
|
||||
watchTabs: (callback) ->
|
||||
@_tabCallbacks.push(callback)
|
||||
return if @tabsWatching
|
||||
@watch(@setTabRequestInfo.bind(this))
|
||||
@tabsWatching = true
|
||||
chrome.tabs.onCreated.addListener (tab) =>
|
||||
return unless tab.id
|
||||
@tabInfo[tab.id] = @_newTabInfo()
|
||||
chrome.tabs.onRemoved.addListener (tab) =>
|
||||
delete @tabInfo[tab.id]
|
||||
chrome.tabs.onReplaced?.addListener (added, removed) =>
|
||||
@tabInfo[added] ?= @_newTabInfo()
|
||||
delete @tabInfo[removed]
|
||||
chrome.tabs.onUpdated.addListener (tab) =>
|
||||
info = @tabInfo[tab.id] ?= @_newTabInfo()
|
||||
return unless info
|
||||
for callback in @_tabCallbacks
|
||||
callback(tab.id, info, null, 'updated')
|
||||
chrome.tabs.query {}, (tabs) =>
|
||||
for tab in tabs
|
||||
@tabInfo[tab.id] ?= @_newTabInfo()
|
||||
|
||||
_newTabInfo: -> {
|
||||
requests: {}
|
||||
requestCount: 0
|
||||
requestStatus: {}
|
||||
|
||||
ongoingCount: 0
|
||||
errorCount: 0
|
||||
doneCount: 0
|
||||
}
|
||||
|
||||
setTabRequestInfo: (status, req) ->
|
||||
info = @tabInfo[req.tabId]
|
||||
if info
|
||||
if status == 'start' and req.type == 'main_frame'
|
||||
for own key, value of @_newTabInfo()
|
||||
info[key] = value
|
||||
info.requests[req.requestId] = req
|
||||
if (oldStatus = info.requestStatus[req.requestId])
|
||||
info[@eventCategory[oldStatus] + 'Count']--
|
||||
else
|
||||
info.requestCount++
|
||||
info.requestStatus[req.requestId] = status
|
||||
info[@eventCategory[status] + 'Count']++
|
||||
for callback in @_tabCallbacks
|
||||
callback(req.tabId, info, req, status)
|
||||
|
||||
summarizeErrors: (info, domainOfHost) ->
|
||||
domains = []
|
||||
domainInfoByName = {}
|
||||
for reqId, req of info.requests
|
||||
if @eventCategory[info.requestStatus[reqId]] == 'error'
|
||||
domain = Url.parse(req.url).hostname
|
||||
domain = domainOfHost(domain) if domainOfHost
|
||||
domainInfo = domainInfoByName[domain]
|
||||
if not domainInfo
|
||||
domainInfo = domainInfoByName[domain] = {
|
||||
domain: domain
|
||||
errorCount: 0
|
||||
type: 'other'
|
||||
}
|
||||
domains.push(domainInfo)
|
||||
domainInfo.errorCount++
|
||||
domainInfo.type = req.type
|
||||
domains.sort (a, b) -> b.errorCount - a.errorCount
|
||||
return {
|
||||
errorCount: info.errorCount
|
||||
domains: domains
|
||||
}
|
@ -368,6 +368,12 @@ class Options
|
||||
showMenu = true
|
||||
@_setOptions({'-showInspectMenu': true}, {persist: true})
|
||||
@setInspect(showMenu: showMenu)
|
||||
if changes['-monitorWebRequests']? or changes == @_options
|
||||
monitorWebRequests = @_options['-monitorWebRequests']
|
||||
if not monitorWebRequests?
|
||||
monitorWebRequests = true
|
||||
@_setOptions({'-monitorWebRequests': true}, {persist: true})
|
||||
@setMonitorWebRequests(monitorWebRequests)
|
||||
|
||||
handler()
|
||||
@_storage.watch null, handler
|
||||
@ -395,6 +401,14 @@ class Options
|
||||
###
|
||||
setInspect: -> Promise.resolve()
|
||||
|
||||
###*
|
||||
# Apply the settings related to web request monitoring.
|
||||
# In base class, this method is not implemented and will not do anything.
|
||||
# @param {boolean} enabled Whether network shall be monitored or not
|
||||
# @returns {Promise} A promise which is fulfilled when the settings apply
|
||||
###
|
||||
setMonitorWebRequests: -> Promise.resolve()
|
||||
|
||||
###*
|
||||
# @callback watchCallback
|
||||
# @param {Object.<string, {}>} changes A map from keys to values.
|
||||
@ -806,18 +820,23 @@ class Options
|
||||
target = OmegaPac.Profiles.byName(profileName, @_options)
|
||||
if not target?
|
||||
return Promise.reject new ProfileNotExistError(profileName)
|
||||
# Try to remove rules with the same condition first.
|
||||
tag = OmegaPac.Conditions.tag(condition)
|
||||
for i in [0...profile.rules.length]
|
||||
if OmegaPac.Conditions.tag(profile.rules[i].condition) == tag
|
||||
profile.rules.splice(i, 1)
|
||||
break
|
||||
if not Array.isArray(condition)
|
||||
condition = [condition]
|
||||
|
||||
for cond in condition
|
||||
# Try to remove rules with the same condition first.
|
||||
tag = OmegaPac.Conditions.tag(cond)
|
||||
for i in [0...profile.rules.length]
|
||||
if OmegaPac.Conditions.tag(profile.rules[i].condition) == tag
|
||||
profile.rules.splice(i, 1)
|
||||
break
|
||||
|
||||
# Add the new rule to the start so that it won't be shadowed by others.
|
||||
profile.rules.unshift({
|
||||
condition: cond
|
||||
profileName: profileName
|
||||
})
|
||||
|
||||
# Add the new rule to the beginning so that it won't be shadowed by others.
|
||||
profile.rules.unshift({
|
||||
condition: condition
|
||||
profileName: profileName
|
||||
})
|
||||
OmegaPac.Profiles.updateRevision(profile)
|
||||
changes = {}
|
||||
changes[OmegaPac.Profiles.nameAsKey(profile)] = profile
|
||||
|
@ -8,13 +8,16 @@ module.filter 'dispName', (omegaTarget) ->
|
||||
name = name.name
|
||||
omegaTarget.getMessage('profile_' + name) || name
|
||||
|
||||
moveUp = (activeIndex, items) ->
|
||||
i = activeIndex - 1
|
||||
if i >= 0
|
||||
items.eq(i)[0]?.focus()
|
||||
moveDown = (activeIndex, items) -> items.eq(activeIndex + 1)[0]?.focus()
|
||||
shortcutKeys =
|
||||
38: (activeIndex, items) -> # Up
|
||||
i = activeIndex - 1
|
||||
if i >= 0
|
||||
items.eq(i)[0]?.focus()
|
||||
40: (activeIndex, items) -> # Down
|
||||
items.eq(activeIndex + 1)[0]?.focus()
|
||||
38: moveUp # Up
|
||||
40: moveDown # Down
|
||||
74: moveDown # j
|
||||
75: moveUp # k
|
||||
48: '+direct' # 0
|
||||
83: '+system' # s
|
||||
191: 'help' # /
|
||||
@ -27,6 +30,7 @@ shortcutKeys =
|
||||
79: 'option' # o
|
||||
73: 'issue' # i
|
||||
76: 'log' # l
|
||||
82: 'requestInfo' # r
|
||||
|
||||
for i in [1..9]
|
||||
shortcutKeys[48 + i] = i
|
||||
@ -61,6 +65,7 @@ jQuery(document).on 'keydown', (e) ->
|
||||
'option': 'O'
|
||||
'issue': 'I'
|
||||
'log': 'L'
|
||||
'requestInfo': 'R'
|
||||
for shortcut, key of keys
|
||||
showHelp(shortcut, key)
|
||||
customProfiles().each (i, el) ->
|
||||
@ -148,6 +153,7 @@ module.controller 'PopupCtrl', ($scope, $window, $q, omegaTarget,
|
||||
$scope.addTempRule = (domain, profileName) ->
|
||||
$scope.tempRuleMenu.open = false
|
||||
omegaTarget.addTempRule(domain, profileName).then ->
|
||||
omegaTarget.state('lastProfileNameForCondition', profileName)
|
||||
refresh()
|
||||
|
||||
$scope.setDefaultProfile = (profileName, defaultProfileName) ->
|
||||
@ -156,6 +162,16 @@ module.controller 'PopupCtrl', ($scope, $window, $q, omegaTarget,
|
||||
|
||||
$scope.addCondition = (condition, profileName) ->
|
||||
omegaTarget.addCondition(condition, profileName).then ->
|
||||
omegaTarget.state('lastProfileNameForCondition', profileName)
|
||||
refresh()
|
||||
|
||||
$scope.addConditionForDomains = (domains, profileName) ->
|
||||
conditions = Object.keys(domains).map (domain) -> {
|
||||
conditionType: 'HostWildcardCondition'
|
||||
pattern: '*.' + domain
|
||||
}
|
||||
omegaTarget.addCondition(conditions, profileName).then ->
|
||||
omegaTarget.state('lastProfileNameForCondition', profileName)
|
||||
refresh()
|
||||
|
||||
$scope.validateProfileName =
|
||||
@ -170,13 +186,15 @@ module.controller 'PopupCtrl', ($scope, $window, $q, omegaTarget,
|
||||
omegaTarget.applyProfile(name).then ->
|
||||
refresh()
|
||||
|
||||
preselectedProfileNameForCondition = 'direct'
|
||||
|
||||
omegaTarget.state([
|
||||
'availableProfiles', 'currentProfileName', 'isSystemProfile',
|
||||
'validResultProfiles', 'refreshOnProfileChange', 'externalProfile',
|
||||
'proxyNotControllable'
|
||||
'proxyNotControllable', 'lastProfileNameForCondition'
|
||||
]).then ([availableProfiles, currentProfileName, isSystemProfile,
|
||||
validResultProfiles, refresh, externalProfile,
|
||||
proxyNotControllable]) ->
|
||||
proxyNotControllable, lastProfileNameForCondition]) ->
|
||||
$scope.proxyNotControllable = proxyNotControllable
|
||||
return if proxyNotControllable
|
||||
$scope.availableProfiles = availableProfiles
|
||||
@ -198,6 +216,11 @@ module.controller 'PopupCtrl', ($scope, $window, $q, omegaTarget,
|
||||
|
||||
$scope.validResultProfiles = profilesByNames(validResultProfiles)
|
||||
|
||||
if lastProfileNameForCondition
|
||||
for profile in $scope.validResultProfiles
|
||||
if profile.name == lastProfileNameForCondition
|
||||
preselectedProfileNameForCondition = lastProfileNameForCondition
|
||||
|
||||
$scope.builtinProfiles = []
|
||||
$scope.customProfiles = []
|
||||
for own key, profile of availableProfiles
|
||||
@ -211,9 +234,21 @@ module.controller 'PopupCtrl', ($scope, $window, $q, omegaTarget,
|
||||
|
||||
$scope.customProfiles.sort(profileOrder)
|
||||
|
||||
$scope.domainsForCondition = {}
|
||||
$scope.requestInfoProvided = null
|
||||
omegaTarget.setRequestInfoCallback (info) ->
|
||||
$scope.$apply ->
|
||||
$scope.requestInfo = info
|
||||
$scope.requestInfoProvided ?= (info?.domains.length > 0)
|
||||
for domain in info.domains
|
||||
$scope.domainsForCondition[domain.domain] ?= true
|
||||
$scope.profileForDomains ?= preselectedProfileNameForCondition
|
||||
|
||||
omegaTarget.getActivePageInfo().then((info) ->
|
||||
if info
|
||||
$scope.currentTempRuleProfile = info.tempRuleProfileName
|
||||
if $scope.currentTempRuleProfile
|
||||
preselectedProfileNameForCondition = $scope.currentTempRuleProfile
|
||||
$scope.currentDomain = info.domain
|
||||
else
|
||||
$q.reject()
|
||||
@ -234,6 +269,8 @@ module.controller 'PopupCtrl', ($scope, $window, $q, omegaTarget,
|
||||
condition:
|
||||
conditionType: 'HostWildcardCondition'
|
||||
pattern: conditionSuggestion['HostWildcardCondition']
|
||||
profileName: $scope.currentTempRuleProfile ? 'direct'
|
||||
profileName: preselectedProfileNameForCondition
|
||||
$scope.$watch 'rule.condition.conditionType', (type) ->
|
||||
$scope.rule.condition.pattern = conditionSuggestion[type]
|
||||
else
|
||||
$scope.requestInfoProvided = false
|
||||
|
@ -152,3 +152,7 @@ legend,
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.request-info-details {
|
||||
min-width: 360px;
|
||||
}
|
||||
|
@ -30,7 +30,9 @@ angular.module('omega').constant 'isProfileNameReserved', (name) ->
|
||||
name.charCodeAt(1) == charCodeUnderscore)
|
||||
|
||||
angular.module('omega').config ($stateProvider, $urlRouterProvider,
|
||||
$httpProvider, $animateProvider) ->
|
||||
$httpProvider, $animateProvider, $compileProvider) ->
|
||||
$compileProvider.aHrefSanitizationWhitelist(
|
||||
/^\s*(https?|ftp|mailto|chrome-extension):/)
|
||||
$animateProvider.classNameFilter(/angular-animate/)
|
||||
|
||||
$urlRouterProvider.otherwise '/ui'
|
||||
|
@ -6,6 +6,13 @@ section.settings-group
|
||||
label
|
||||
input#revert-proxy-changes(type='checkbox' ng-model='options["-revertProxyChanges"]')
|
||||
span {{'options_revertProxyChanges' | tr}}
|
||||
section.settings-group
|
||||
h3 {{'options_group_networkRequests' | tr}}
|
||||
div.checkbox
|
||||
label
|
||||
input#revert-proxy-changes(type='checkbox' ng-model='options["-monitorWebRequests"]')
|
||||
span {{'options_monitorWebRequests' | tr}}
|
||||
p.help-block(omega-html="'options_monitorWebRequestsHelp' | tr")
|
||||
section.settings-group
|
||||
h3 {{'options_downloadOptions' | tr}}
|
||||
p.help-block {{'options_downloadOptionsHelp' | tr}}
|
||||
|
@ -24,12 +24,12 @@ html(lang='en' ng-app='omegaPopup' ng-controller='PopupCtrl' ng-csp)
|
||||
link(rel='stylesheet' href='lib/bootstrap/css/bootstrap.min.css')
|
||||
link(rel='stylesheet' href='css/popup.css')
|
||||
body(ng-class='{"with-condition-form": showConditionForm}')
|
||||
ul.popup-menu-nav.nav.nav-pills.nav-stacked(ng-hide='showConditionForm || proxyNotControllable')
|
||||
ul.popup-menu-nav.nav.nav-pills.nav-stacked(ng-hide='showConditionForm || proxyNotControllable || showRequestInfo')
|
||||
li.profile(ng-repeat='profile in builtinProfiles' ng-class='{active: isActive(profile.name), "bg-info": isEffective(profile.name)}')
|
||||
a(href='#' role='button' ng-attr-tabindex='{{100 + $index}}' ng-click='applyProfile(profile)' title='{{getProfileTitle(profile)}}'
|
||||
data-shortcut='+{{profile.name}}')
|
||||
span(omega-profile-inline='profile' icon='getIcon(profile)' options='availableProfiles' disp-name='dispNameFilter')
|
||||
li.profile.external-profile(ng-show='!!externalProfile' ng-class='{active: isActive(""), "bg-info": isEffective("")}')
|
||||
li.profile.external-profile(ng-show='!requestInfoProvided && !!externalProfile' ng-class='{active: isActive(""), "bg-info": isEffective("")}')
|
||||
a(href='#' role='button' ng-click='nameExternal.open = true' title='{{getProfileTitle(externalProfile)}}' data-shortcut='external')
|
||||
form(name='nameExternalForm' ng-submit='nameExternalForm.$valid && saveExternal()')
|
||||
span(omega-profile-icon='externalProfile' icon='getIcon(externalProfile, "normal")' options='availableProfiles' disp-name='dispNameFilter')
|
||||
@ -37,6 +37,11 @@ html(lang='en' ng-app='omegaPopup' ng-controller='PopupCtrl' ng-csp)
|
||||
span(ng-show='!nameExternal.open') {{'popup_externalProfile' | tr}}
|
||||
input.form-control(ng-show='!!nameExternal.open' ng-model='externalProfile.name' ng-blur='nameExternalForm.submit()'
|
||||
placeholder='{{"popup_externalProfileName" | tr}}' ui-validate='validateProfileName')
|
||||
li.request-info(ng-show='!!requestInfoProvided' class='bg-warning')
|
||||
a(href='#' role='button' ng-click='showRequestInfo = true' data-shortcut='requestInfo')
|
||||
span.glyphicon.glyphicon-warning-sign.text-warning
|
||||
= ' '
|
||||
| {{'popup_requestErrorCount' | tr:[requestInfo.errorCount]}}
|
||||
li.divider
|
||||
li.profile.custom-profile(ng-repeat='profile in customProfiles' ng-class='{active: isActive(profile.name), "bg-info": isEffective(profile.name)}'
|
||||
dropdown)
|
||||
@ -126,6 +131,31 @@ html(lang='en' ng-app='omegaPopup' ng-controller='PopupCtrl' ng-csp)
|
||||
p.proxy-not-controllable-controls
|
||||
button.btn.btn-default(ng-click='closePopup()') {{'dialog_cancel' | tr}}
|
||||
button.btn.btn-primary(ng-click='openManage()') {{'popup_proxyNotControllableManage' | tr}}
|
||||
div.request-info-details(ng-show='showRequestInfo')
|
||||
form.request-info-details(style='display: none;'
|
||||
ng-style='{display: showRequestInfo ? "block" : "none"}'
|
||||
ng-submit='addConditionForDomains(domainsForCondition, profileForDomains)')
|
||||
fieldset
|
||||
legend
|
||||
| {{'popup_addConditionTo' | tr}}
|
||||
= ' '
|
||||
span.profile-inline
|
||||
span(omega-profile-inline='currentProfile' options='availableProfiles' disp-name='dispNameFilter')
|
||||
p.text-warning {{'popup_requestErrorWarning' | tr}}
|
||||
p.help-block {{'popup_requestErrorAddCondition' | tr}}
|
||||
.checkbox(ng-repeat='domain in requestInfo.domains')
|
||||
label
|
||||
input(type='checkbox' ng-model='domainsForCondition[domain.domain]')
|
||||
span.label.label-warning {{domain.errorCount}}
|
||||
=' *.{{domain.domain}}'
|
||||
div.form-group
|
||||
label {{'options_resultProfileForSelectedDomains' | tr}}
|
||||
div(omega-profile-select='validResultProfiles' ng-model='profileForDomains'
|
||||
disp-name='dispNameFilter' options='availableProfiles')
|
||||
div.condition-controls
|
||||
button.btn.btn-default(type='button' ng-click='showRequestInfo = false')
|
||||
| {{'dialog_cancel' | tr}}
|
||||
button.btn.btn-primary(type='submit') {{'popup_addCondition' | tr}}
|
||||
|
||||
script(src='js/log_error.js')
|
||||
script(src='lib/FileSaver/FileSaver.js')
|
||||
|
Loading…
Reference in New Issue
Block a user