Merge remote-tracking branch 'origin/master'

This commit is contained in:
Weblate 2015-02-18 06:59:26 +01:00
commit 6f2763bff3
20 changed files with 543 additions and 49 deletions

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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]

View 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')

View File

@ -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

View File

@ -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')

View File

@ -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

View File

@ -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": {

View File

@ -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"

View File

@ -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

View 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
}

View File

@ -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

View File

@ -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

View File

@ -152,3 +152,7 @@ legend,
margin-bottom: 0;
}
}
.request-info-details {
min-width: 360px;
}

View File

@ -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'

View File

@ -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}}

View File

@ -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')