mirror of
https://github.com/zero-peak/ZeroOmega.git
synced 2025-01-22 15:08:12 -05:00
Allow editing switch profiles as omega rule list. Fix #80.
This commit is contained in:
parent
a54e02b503
commit
75ecb9aa46
@ -98,6 +98,47 @@
|
|||||||
"ruleList_usageUrl": {
|
"ruleList_usageUrl": {
|
||||||
"message": "https://github.com/FelisCatus/SwitchyOmega/wiki/RuleListUsage"
|
"message": "https://github.com/FelisCatus/SwitchyOmega/wiki/RuleListUsage"
|
||||||
},
|
},
|
||||||
|
"ruleList_error_resultNotEnabled": {
|
||||||
|
"message": "Missing '@with result' directive!"
|
||||||
|
},
|
||||||
|
"ruleList_error_unknownProfile": {
|
||||||
|
"message": "Unknown profile: $PROFILE$",
|
||||||
|
"placeholders": {
|
||||||
|
"profile": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "some profile"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ruleList_error_missingResultProfile": {
|
||||||
|
"message": "Missing result profile name at Line $LNO$: $SOURCE$",
|
||||||
|
"placeholders": {
|
||||||
|
"lno": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "11"
|
||||||
|
},
|
||||||
|
"source": {
|
||||||
|
"content": "$2",
|
||||||
|
"example": "*.example.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ruleList_error_invalidRule": {
|
||||||
|
"message": "Invalid rule at Line $LNO$: $SOURCE$",
|
||||||
|
"placeholders": {
|
||||||
|
"lno": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "11"
|
||||||
|
},
|
||||||
|
"source": {
|
||||||
|
"content": "$2",
|
||||||
|
"example": ":invalid rule"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ruleList_error_noDefaultRule": {
|
||||||
|
"message": "Missing default rule with catch-all '*' condition!"
|
||||||
|
},
|
||||||
|
|
||||||
"dialog_close": {
|
"dialog_close": {
|
||||||
"message": "Close"
|
"message": "Close"
|
||||||
@ -344,6 +385,15 @@
|
|||||||
"options_profileUnsupportedHelp": {
|
"options_profileUnsupportedHelp": {
|
||||||
"message": "The options could be broken, or from a newer version of this program."
|
"message": "The options could be broken, or from a newer version of this program."
|
||||||
},
|
},
|
||||||
|
"options_profileEditSource": {
|
||||||
|
"message": "Edit source code"
|
||||||
|
},
|
||||||
|
"options_profileEditSourceHelp": {
|
||||||
|
"message": "Show help about the source code format"
|
||||||
|
},
|
||||||
|
"options_profileEditSourceHelpUrl": {
|
||||||
|
"message": "https://github.com/FelisCatus/SwitchyOmega/wiki/SwitchyOmega-conditions-format#result-profile"
|
||||||
|
},
|
||||||
"options_group_proxyServers": {
|
"options_group_proxyServers": {
|
||||||
"message": "Proxy servers"
|
"message": "Proxy servers"
|
||||||
},
|
},
|
||||||
|
@ -98,6 +98,47 @@
|
|||||||
"ruleList_usageUrl": {
|
"ruleList_usageUrl": {
|
||||||
"message": "https://github.com/FelisCatus/SwitchyOmega/wiki/RuleListUsage"
|
"message": "https://github.com/FelisCatus/SwitchyOmega/wiki/RuleListUsage"
|
||||||
},
|
},
|
||||||
|
"ruleList_error_resultNotEnabled": {
|
||||||
|
"message": "语法错误:缺少 '@with result' 指令。"
|
||||||
|
},
|
||||||
|
"ruleList_error_unknownProfile": {
|
||||||
|
"message": "Unknown profile: $PROFILE$",
|
||||||
|
"placeholders": {
|
||||||
|
"profile": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "some profile"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ruleList_error_missingResultProfile": {
|
||||||
|
"message": "语法错误:缺少结果情景模式名称。 行号 $LNO$: $SOURCE$",
|
||||||
|
"placeholders": {
|
||||||
|
"lno": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "11"
|
||||||
|
},
|
||||||
|
"source": {
|
||||||
|
"content": "$2",
|
||||||
|
"example": "*.example.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ruleList_error_invalidRule": {
|
||||||
|
"message": "语法错误:非法规则。行号 $LNO$: $SOURCE$",
|
||||||
|
"placeholders": {
|
||||||
|
"lno": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "11"
|
||||||
|
},
|
||||||
|
"source": {
|
||||||
|
"content": "$2",
|
||||||
|
"example": ":invalid rule"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ruleList_error_noDefaultRule": {
|
||||||
|
"message": "语法错误:缺少匹配全部请求的默认规则。应在最后添加'*'规则和默认情景模式。"
|
||||||
|
},
|
||||||
|
|
||||||
"dialog_close": {
|
"dialog_close": {
|
||||||
"message": "关闭"
|
"message": "关闭"
|
||||||
@ -344,6 +385,15 @@
|
|||||||
"options_profileUnsupportedHelp": {
|
"options_profileUnsupportedHelp": {
|
||||||
"message": "选项文件已经损坏,或者当前版本过低无法处理选项。"
|
"message": "选项文件已经损坏,或者当前版本过低无法处理选项。"
|
||||||
},
|
},
|
||||||
|
"options_profileEditSource": {
|
||||||
|
"message": "编辑源代码"
|
||||||
|
},
|
||||||
|
"options_profileEditSourceHelp": {
|
||||||
|
"message": "显示源代码格式相关的帮助"
|
||||||
|
},
|
||||||
|
"options_profileEditSourceHelpUrl": {
|
||||||
|
"message": "https://github.com/FelisCatus/SwitchyOmega/wiki/SwitchyOmega-conditions-format#result-profile"
|
||||||
|
},
|
||||||
"options_group_proxyServers": {
|
"options_group_proxyServers": {
|
||||||
"message": "代理服务器"
|
"message": "代理服务器"
|
||||||
},
|
},
|
||||||
|
@ -98,6 +98,47 @@
|
|||||||
"ruleList_usageUrl": {
|
"ruleList_usageUrl": {
|
||||||
"message": "https://github.com/FelisCatus/SwitchyOmega/wiki/RuleListUsage"
|
"message": "https://github.com/FelisCatus/SwitchyOmega/wiki/RuleListUsage"
|
||||||
},
|
},
|
||||||
|
"ruleList_error_resultNotEnabled": {
|
||||||
|
"message": "語法錯誤:缺少 '@with result' 指令。"
|
||||||
|
},
|
||||||
|
"ruleList_error_unknownProfile": {
|
||||||
|
"message": "Unknown profile: $PROFILE$",
|
||||||
|
"placeholders": {
|
||||||
|
"profile": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "some profile"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ruleList_error_missingResultProfile": {
|
||||||
|
"message": "語法錯誤:缺少結果情景模式名稱。 行號 $LNO$: $SOURCE$",
|
||||||
|
"placeholders": {
|
||||||
|
"lno": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "11"
|
||||||
|
},
|
||||||
|
"source": {
|
||||||
|
"content": "$2",
|
||||||
|
"example": "*.example.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ruleList_error_invalidRule": {
|
||||||
|
"message": "語法錯誤:非法規則。行號 $LNO$: $SOURCE$",
|
||||||
|
"placeholders": {
|
||||||
|
"lno": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "11"
|
||||||
|
},
|
||||||
|
"source": {
|
||||||
|
"content": "$2",
|
||||||
|
"example": ":invalid rule"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ruleList_error_noDefaultRule": {
|
||||||
|
"message": "語法錯誤:缺少匹配全部請求的預設規則。應在最後新增'*'規則和預設情景模式。"
|
||||||
|
},
|
||||||
|
|
||||||
"dialog_close": {
|
"dialog_close": {
|
||||||
"message": "關閉"
|
"message": "關閉"
|
||||||
@ -344,6 +385,15 @@
|
|||||||
"options_profileUnsupportedHelp": {
|
"options_profileUnsupportedHelp": {
|
||||||
"message": "選項文件已經損壞,或者當前版本過低無法處理選項。"
|
"message": "選項文件已經損壞,或者當前版本過低無法處理選項。"
|
||||||
},
|
},
|
||||||
|
"options_profileEditSource": {
|
||||||
|
"message": "編輯原始碼"
|
||||||
|
},
|
||||||
|
"options_profileEditSourceHelp": {
|
||||||
|
"message": "顯示原始碼格式相關的幫助"
|
||||||
|
},
|
||||||
|
"options_profileEditSourceHelpUrl": {
|
||||||
|
"message": "https://github.com/FelisCatus/SwitchyOmega/wiki/SwitchyOmega-conditions-format#result-profile"
|
||||||
|
},
|
||||||
"options_group_proxyServers": {
|
"options_group_proxyServers": {
|
||||||
"message": "代理服務器"
|
"message": "代理服務器"
|
||||||
},
|
},
|
||||||
|
@ -98,6 +98,47 @@
|
|||||||
"ruleList_usageUrl": {
|
"ruleList_usageUrl": {
|
||||||
"message": "https://github.com/FelisCatus/SwitchyOmega/wiki/RuleListUsage"
|
"message": "https://github.com/FelisCatus/SwitchyOmega/wiki/RuleListUsage"
|
||||||
},
|
},
|
||||||
|
"ruleList_error_resultNotEnabled": {
|
||||||
|
"message": "語法錯誤:缺少 '@with result' 指令。"
|
||||||
|
},
|
||||||
|
"ruleList_error_unknownProfile": {
|
||||||
|
"message": "Unknown profile: $PROFILE$",
|
||||||
|
"placeholders": {
|
||||||
|
"profile": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "some profile"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ruleList_error_missingResultProfile": {
|
||||||
|
"message": "語法錯誤:缺少結果情景模式名稱。 行號 $LNO$: $SOURCE$",
|
||||||
|
"placeholders": {
|
||||||
|
"lno": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "11"
|
||||||
|
},
|
||||||
|
"source": {
|
||||||
|
"content": "$2",
|
||||||
|
"example": "*.example.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ruleList_error_invalidRule": {
|
||||||
|
"message": "語法錯誤:非法規則。行號 $LNO$: $SOURCE$",
|
||||||
|
"placeholders": {
|
||||||
|
"lno": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "11"
|
||||||
|
},
|
||||||
|
"source": {
|
||||||
|
"content": "$2",
|
||||||
|
"example": ":invalid rule"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ruleList_error_noDefaultRule": {
|
||||||
|
"message": "語法錯誤:缺少匹配全部請求的預設規則。應在最後新增'*'規則和預設情景模式。"
|
||||||
|
},
|
||||||
|
|
||||||
"dialog_close": {
|
"dialog_close": {
|
||||||
"message": "關閉"
|
"message": "關閉"
|
||||||
@ -344,6 +385,15 @@
|
|||||||
"options_profileUnsupportedHelp": {
|
"options_profileUnsupportedHelp": {
|
||||||
"message": "選項檔案已經損壞,或者當前版本過低無法處理選項。"
|
"message": "選項檔案已經損壞,或者當前版本過低無法處理選項。"
|
||||||
},
|
},
|
||||||
|
"options_profileEditSource": {
|
||||||
|
"message": "編輯原始碼"
|
||||||
|
},
|
||||||
|
"options_profileEditSourceHelp": {
|
||||||
|
"message": "顯示原始碼格式相關的幫助"
|
||||||
|
},
|
||||||
|
"options_profileEditSourceHelpUrl": {
|
||||||
|
"message": "https://github.com/FelisCatus/SwitchyOmega/wiki/SwitchyOmega-conditions-format#result-profile"
|
||||||
|
},
|
||||||
"options_group_proxyServers": {
|
"options_group_proxyServers": {
|
||||||
"message": "代理伺服器"
|
"message": "代理伺服器"
|
||||||
},
|
},
|
||||||
|
@ -70,7 +70,7 @@ module.exports = exports =
|
|||||||
switchy = exports['Switchy']
|
switchy = exports['Switchy']
|
||||||
parser = switchy.getParser(text)
|
parser = switchy.getParser(text)
|
||||||
return unless parser == 'parseOmega'
|
return unless parser == 'parseOmega'
|
||||||
return unless /(^|\n)@with\s+results?(\r|\n)/i.test(text)
|
return unless /(^|\n)@with\s+results?(\r|\n|$)/i.test(text)
|
||||||
refs = {}
|
refs = {}
|
||||||
for line in text.split(/\n|\r/)
|
for line in text.split(/\n|\r/)
|
||||||
line = line.trim()
|
line = line.trim()
|
||||||
@ -107,7 +107,7 @@ module.exports = exports =
|
|||||||
ruleList += line + eol
|
ruleList += line + eol
|
||||||
if withResult
|
if withResult
|
||||||
# TODO(catus): Also special chars and sequences in defaultProfileName.
|
# TODO(catus): Also special chars and sequences in defaultProfileName.
|
||||||
ruleList += '* +' + defaultProfileName + eol
|
ruleList += eol + '* +' + defaultProfileName + eol
|
||||||
return ruleList
|
return ruleList
|
||||||
|
|
||||||
getParser: (text) ->
|
getParser: (text) ->
|
||||||
@ -174,11 +174,20 @@ module.exports = exports =
|
|||||||
|
|
||||||
parseOmega: (text, matchProfileName, defaultProfileName, args = {}) ->
|
parseOmega: (text, matchProfileName, defaultProfileName, args = {}) ->
|
||||||
{strict} = args
|
{strict} = args
|
||||||
|
if strict
|
||||||
|
error = (fields) ->
|
||||||
|
err = new Error(fields.message)
|
||||||
|
for own key, value of fields
|
||||||
|
err[key] = value
|
||||||
|
throw err
|
||||||
|
includeSource = args.source ? true
|
||||||
rules = []
|
rules = []
|
||||||
rulesWithDefaultProfile = []
|
rulesWithDefaultProfile = []
|
||||||
withResult = false
|
withResult = false
|
||||||
exclusiveProfile = null
|
exclusiveProfile = null
|
||||||
|
lno = 0
|
||||||
for line in text.split(/\n|\r/)
|
for line in text.split(/\n|\r/)
|
||||||
|
lno++
|
||||||
line = line.trim()
|
line = line.trim()
|
||||||
continue if line.length == 0
|
continue if line.length == 0
|
||||||
switch line[0]
|
switch line[0]
|
||||||
@ -199,6 +208,7 @@ module.exports = exports =
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
source = null
|
source = null
|
||||||
|
exclusiveProfile = null if strict
|
||||||
if line[0] == '!'
|
if line[0] == '!'
|
||||||
profile = if withResult then null else defaultProfileName
|
profile = if withResult then null else defaultProfileName
|
||||||
source = line
|
source = line
|
||||||
@ -206,7 +216,12 @@ module.exports = exports =
|
|||||||
else if withResult
|
else if withResult
|
||||||
iSpace = line.lastIndexOf(' +')
|
iSpace = line.lastIndexOf(' +')
|
||||||
if iSpace < 0
|
if iSpace < 0
|
||||||
throw new Error("Missing result profile name: " + line) if strict
|
error?({
|
||||||
|
message: "Missing result profile name: " + line
|
||||||
|
reason: 'missingResultProfile'
|
||||||
|
source: line
|
||||||
|
sourceLineNo: lno
|
||||||
|
})
|
||||||
continue
|
continue
|
||||||
profile = line.substr(iSpace + 2).trim()
|
profile = line.substr(iSpace + 2).trim()
|
||||||
line = line.substr(0, iSpace).trim()
|
line = line.substr(0, iSpace).trim()
|
||||||
@ -216,10 +231,18 @@ module.exports = exports =
|
|||||||
|
|
||||||
cond = Conditions.fromStr(line)
|
cond = Conditions.fromStr(line)
|
||||||
if not cond
|
if not cond
|
||||||
throw new Error("Invalid rule: " + line) if strict
|
error?({
|
||||||
|
message: "Invalid rule: " + line
|
||||||
|
reason: 'invalidRule'
|
||||||
|
source: source ? line
|
||||||
|
sourceLineNo: lno
|
||||||
|
})
|
||||||
continue
|
continue
|
||||||
|
|
||||||
rule = {condition: cond, profileName: profile, source: source ? line}
|
rule =
|
||||||
|
condition: cond
|
||||||
|
profileName: profile
|
||||||
|
source: if includeSource then source ? line
|
||||||
rules.push(rule)
|
rules.push(rule)
|
||||||
if not profile
|
if not profile
|
||||||
rulesWithDefaultProfile.push(rule)
|
rulesWithDefaultProfile.push(rule)
|
||||||
@ -227,7 +250,10 @@ module.exports = exports =
|
|||||||
if withResult
|
if withResult
|
||||||
if not exclusiveProfile
|
if not exclusiveProfile
|
||||||
if strict
|
if strict
|
||||||
throw new Error("Missing default rule with catch-all '*' condition")
|
error?({
|
||||||
|
message: "Missing default rule with catch-all '*' condition"
|
||||||
|
reason: 'noDefaultRule'
|
||||||
|
})
|
||||||
exclusiveProfile = defaultProfileName || 'direct'
|
exclusiveProfile = defaultProfileName || 'direct'
|
||||||
for rule in rulesWithDefaultProfile
|
for rule in rulesWithDefaultProfile
|
||||||
rule.profileName = exclusiveProfile
|
rule.profileName = exclusiveProfile
|
||||||
|
@ -78,6 +78,7 @@ angular.module('omega').controller 'MasterCtrl', ($scope, $rootScope, $window,
|
|||||||
|
|
||||||
$rootScope.applyOptions = ->
|
$rootScope.applyOptions = ->
|
||||||
return unless checkFormValid()
|
return unless checkFormValid()
|
||||||
|
return if $rootScope.$broadcast('omegaApplyOptions').defaultPrevented
|
||||||
plainOptions = angular.fromJson(angular.toJson($rootScope.options))
|
plainOptions = angular.fromJson(angular.toJson($rootScope.options))
|
||||||
patch = diff.diff($rootScope.optionsOld, plainOptions)
|
patch = diff.diff($rootScope.optionsOld, plainOptions)
|
||||||
omegaTarget.optionsPatch(patch).then ->
|
omegaTarget.optionsPatch(patch).then ->
|
||||||
|
@ -1,6 +1,57 @@
|
|||||||
angular.module('omega').controller 'SwitchProfileCtrl', ($scope, $location,
|
angular.module('omega').controller 'SwitchProfileCtrl', ($scope, $rootScope,
|
||||||
$modal, profileIcons, getAttachedName, omegaTarget, $timeout, trFilter) ->
|
$location, $timeout, $q, $modal, profileIcons, getAttachedName, omegaTarget,
|
||||||
|
trFilter) ->
|
||||||
|
# == Rule list ==
|
||||||
|
$scope.ruleListFormats = OmegaPac.Profiles.ruleListFormats
|
||||||
|
|
||||||
|
exportRuleList = ->
|
||||||
|
text = OmegaPac.RuleList.Switchy.compose($scope.profile)
|
||||||
|
|
||||||
|
eol = '\r\n'
|
||||||
|
info = '\n'
|
||||||
|
info += '; Require: SwitchyOmega >= 2.3.2' + eol
|
||||||
|
info += "; Date: #{new Date().toLocaleDateString()}" + eol
|
||||||
|
info += "; Usage: #{trFilter('ruleList_usageUrl')}" + eol
|
||||||
|
|
||||||
|
text = text.replace('\n', info)
|
||||||
|
|
||||||
|
blob = new Blob [text], {type: "text/plain;charset=utf-8"}
|
||||||
|
fileName = $scope.profile.name.replace(/\W+/g, '_')
|
||||||
|
saveAs(blob, "OmegaRules_#{fileName}.sorl")
|
||||||
|
|
||||||
|
exportLegacyRuleList = ->
|
||||||
|
wildcardRules = ''
|
||||||
|
regexpRules = ''
|
||||||
|
for rule in $scope.profile.rules
|
||||||
|
i = ''
|
||||||
|
if rule.profileName == $scope.attachedOptions.defaultProfileName
|
||||||
|
i = '!'
|
||||||
|
switch rule.condition.conditionType
|
||||||
|
when 'HostWildcardCondition'
|
||||||
|
wildcardRules += i + '@*://' + rule.condition.pattern + '/*' + '\r\n'
|
||||||
|
when 'UrlWildcardCondition'
|
||||||
|
wildcardRules += i + '@' + rule.condition.pattern + '\r\n'
|
||||||
|
when 'UrlRegexCondition'
|
||||||
|
regexpRules += i + rule.condition.pattern + '\r\n'
|
||||||
|
|
||||||
|
text = """
|
||||||
|
; Summary: Proxy Switchy! Exported Rule List
|
||||||
|
; Date: #{new Date().toLocaleDateString()}
|
||||||
|
; Website: http://bit.ly/proxyswitchy
|
||||||
|
|
||||||
|
#BEGIN
|
||||||
|
|
||||||
|
[wildcard]
|
||||||
|
#{wildcardRules}
|
||||||
|
[regexp]
|
||||||
|
#{regexpRules}
|
||||||
|
#END
|
||||||
|
"""
|
||||||
|
blob = new Blob [text], {type: "text/plain;charset=utf-8"}
|
||||||
|
fileName = $scope.profile.name.replace(/\W+/g, '_')
|
||||||
|
saveAs(blob, "SwitchyRules_#{fileName}.ssrl")
|
||||||
|
|
||||||
|
# == Condition types ==
|
||||||
$scope.showConditionHelp = ($location.search().help == 'condition')
|
$scope.showConditionHelp = ($location.search().help == 'condition')
|
||||||
|
|
||||||
$scope.basicConditionTypes = [
|
$scope.basicConditionTypes = [
|
||||||
@ -40,53 +91,6 @@ angular.module('omega').controller 'SwitchProfileCtrl', ($scope, $location,
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
exportRuleList = ->
|
|
||||||
text = OmegaPac.RuleList.Switchy.compose($scope.profile)
|
|
||||||
|
|
||||||
eol = '\r\n'
|
|
||||||
info = '\n'
|
|
||||||
info += '; Require: SwitchyOmega >= 2.3.2' + eol
|
|
||||||
info += "; Date: #{new Date().toLocaleDateString()}" + eol
|
|
||||||
info += "; Usage: #{trFilter('ruleList_usageUrl')}" + eol
|
|
||||||
|
|
||||||
text = text.replace('\n', info)
|
|
||||||
|
|
||||||
blob = new Blob [text], {type: "text/plain;charset=utf-8"}
|
|
||||||
fileName = $scope.profile.name.replace(/\W+/g, '_')
|
|
||||||
saveAs(blob, "OmegaRules_#{fileName}.sorl")
|
|
||||||
|
|
||||||
exportLegacyRuleList = ->
|
|
||||||
wildcardRules = ''
|
|
||||||
regexpRules = ''
|
|
||||||
for rule in $scope.profile.rules
|
|
||||||
i = ''
|
|
||||||
if rule.profileName == $scope.defaultProfileName
|
|
||||||
i = '!'
|
|
||||||
switch rule.condition.conditionType
|
|
||||||
when 'HostWildcardCondition'
|
|
||||||
wildcardRules += i + '@*://' + rule.condition.pattern + '/*' + '\r\n'
|
|
||||||
when 'UrlWildcardCondition'
|
|
||||||
wildcardRules += i + '@' + rule.condition.pattern + '\r\n'
|
|
||||||
when 'UrlRegexCondition'
|
|
||||||
regexpRules += i + rule.condition.pattern + '\r\n'
|
|
||||||
|
|
||||||
text = """
|
|
||||||
; Summary: Proxy Switchy! Exported Rule List
|
|
||||||
; Date: #{new Date().toLocaleDateString()}
|
|
||||||
; Website: http://bit.ly/proxyswitchy
|
|
||||||
|
|
||||||
#BEGIN
|
|
||||||
|
|
||||||
[wildcard]
|
|
||||||
#{wildcardRules}
|
|
||||||
[regexp]
|
|
||||||
#{regexpRules}
|
|
||||||
#END
|
|
||||||
"""
|
|
||||||
blob = new Blob [text], {type: "text/plain;charset=utf-8"}
|
|
||||||
fileName = $scope.profile.name.replace(/\W+/g, '_')
|
|
||||||
saveAs(blob, "SwitchyRules_#{fileName}.ssrl")
|
|
||||||
|
|
||||||
expandGroups = (groups) ->
|
expandGroups = (groups) ->
|
||||||
result = []
|
result = []
|
||||||
for group in groups
|
for group in groups
|
||||||
@ -149,6 +153,14 @@ angular.module('omega').controller 'SwitchProfileCtrl', ($scope, $location,
|
|||||||
if $scope.hasConditionTypes == 0
|
if $scope.hasConditionTypes == 0
|
||||||
unwatchRules = $scope.$watch 'profile.rules', updateHasConditionTypes, true
|
unwatchRules = $scope.$watch 'profile.rules', updateHasConditionTypes, true
|
||||||
|
|
||||||
|
# == Rules ==
|
||||||
|
rulesReadyDefer = $q.defer()
|
||||||
|
rulesReady = rulesReadyDefer.promise
|
||||||
|
stopWatchingForRules = $scope.$watch 'profile.rules', (rules) ->
|
||||||
|
return unless rules
|
||||||
|
stopWatchingForRules()
|
||||||
|
rulesReadyDefer.resolve(rules)
|
||||||
|
|
||||||
$scope.addRule = ->
|
$scope.addRule = ->
|
||||||
rule =
|
rule =
|
||||||
if $scope.profile.rules.length > 0
|
if $scope.profile.rules.length > 0
|
||||||
@ -156,7 +168,7 @@ angular.module('omega').controller 'SwitchProfileCtrl', ($scope, $location,
|
|||||||
angular.copy(templ)
|
angular.copy(templ)
|
||||||
else
|
else
|
||||||
condition: {conditionType: 'HostWildcardCondition', pattern: ''}
|
condition: {conditionType: 'HostWildcardCondition', pattern: ''}
|
||||||
profileName: $scope.profile.defaultProfileName
|
profileName: $scope.attachedOptions.defaultProfileName
|
||||||
if rule.condition.pattern
|
if rule.condition.pattern
|
||||||
rule.condition.pattern = ''
|
rule.condition.pattern = ''
|
||||||
$scope.profile.rules.push rule
|
$scope.profile.rules.push rule
|
||||||
@ -201,7 +213,8 @@ angular.module('omega').controller 'SwitchProfileCtrl', ($scope, $location,
|
|||||||
|
|
||||||
$scope.resetRules = ->
|
$scope.resetRules = ->
|
||||||
scope = $scope.$new('isolate')
|
scope = $scope.$new('isolate')
|
||||||
scope.ruleProfile = $scope.profileByName($scope.defaultProfileName)
|
scope.ruleProfile =
|
||||||
|
$scope.profileByName($scope.attachedOptions.defaultProfileName)
|
||||||
scope.dispNameFilter = $scope.dispNameFilter
|
scope.dispNameFilter = $scope.dispNameFilter
|
||||||
scope.options = $scope.options
|
scope.options = $scope.options
|
||||||
$modal.open(
|
$modal.open(
|
||||||
@ -209,7 +222,7 @@ angular.module('omega').controller 'SwitchProfileCtrl', ($scope, $location,
|
|||||||
scope: scope
|
scope: scope
|
||||||
).result.then ->
|
).result.then ->
|
||||||
for rule in $scope.profile.rules
|
for rule in $scope.profile.rules
|
||||||
rule.profileName = $scope.defaultProfileName
|
rule.profileName = $scope.attachedOptions.defaultProfileName
|
||||||
|
|
||||||
$scope.sortableOptions =
|
$scope.sortableOptions =
|
||||||
handle: '.sort-bar'
|
handle: '.sort-bar'
|
||||||
@ -219,8 +232,9 @@ angular.module('omega').controller 'SwitchProfileCtrl', ($scope, $location,
|
|||||||
forcePlaceholderSize: true
|
forcePlaceholderSize: true
|
||||||
containment: 'parent'
|
containment: 'parent'
|
||||||
|
|
||||||
$scope.ruleListFormats = OmegaPac.Profiles.ruleListFormats
|
# == Attached ==
|
||||||
|
attachedReadyDefer = $q.defer()
|
||||||
|
attachedReady = attachedReadyDefer.promise
|
||||||
$scope.$watch 'profile.name', (name) ->
|
$scope.$watch 'profile.name', (name) ->
|
||||||
$scope.attachedName = getAttachedName(name)
|
$scope.attachedName = getAttachedName(name)
|
||||||
$scope.attachedKey = OmegaPac.Profiles.nameAsKey($scope.attachedName)
|
$scope.attachedKey = OmegaPac.Profiles.nameAsKey($scope.attachedName)
|
||||||
@ -250,7 +264,7 @@ angular.module('omega').controller 'SwitchProfileCtrl', ($scope, $location,
|
|||||||
$scope.$watch 'profile.defaultProfileName', (name) ->
|
$scope.$watch 'profile.defaultProfileName', (name) ->
|
||||||
$scope.attachedOptions.enabled = (name == $scope.attachedName)
|
$scope.attachedOptions.enabled = (name == $scope.attachedName)
|
||||||
if not $scope.attached or not $scope.attachedOptions.enabled
|
if not $scope.attached or not $scope.attachedOptions.enabled
|
||||||
$scope.defaultProfileName = name
|
$scope.attachedOptions.defaultProfileName = name
|
||||||
|
|
||||||
$scope.$watch 'attachedOptions.enabled', (enabled, oldValue) ->
|
$scope.$watch 'attachedOptions.enabled', (enabled, oldValue) ->
|
||||||
return if enabled == oldValue
|
return if enabled == oldValue
|
||||||
@ -261,16 +275,18 @@ angular.module('omega').controller 'SwitchProfileCtrl', ($scope, $location,
|
|||||||
if $scope.profile.defaultProfileName == $scope.attachedName
|
if $scope.profile.defaultProfileName == $scope.attachedName
|
||||||
if $scope.attached
|
if $scope.attached
|
||||||
$scope.profile.defaultProfileName = $scope.attached.defaultProfileName
|
$scope.profile.defaultProfileName = $scope.attached.defaultProfileName
|
||||||
$scope.defaultProfileName = $scope.attached.defaultProfileName
|
$scope.attachedOptions.defaultProfileName =
|
||||||
|
$scope.attached.defaultProfileName
|
||||||
else
|
else
|
||||||
$scope.profile.defaultProfileName = 'direct'
|
$scope.profile.defaultProfileName = 'direct'
|
||||||
$scope.defaultProfileName = 'direct'
|
$scope.attachedOptions.defaultProfileName = 'direct'
|
||||||
|
|
||||||
$scope.$watch 'attached.defaultProfileName', (name) ->
|
$scope.$watch 'attached.defaultProfileName', (name) ->
|
||||||
if name and $scope.attachedOptions.enabled
|
if name and $scope.attachedOptions.enabled
|
||||||
$scope.defaultProfileName = name
|
$scope.attachedOptions.defaultProfileName = name
|
||||||
|
|
||||||
$scope.$watch 'defaultProfileName', (name) ->
|
$scope.$watch 'attachedOptions.defaultProfileName', (name) ->
|
||||||
|
attachedReadyDefer.resolve()
|
||||||
if $scope.attached and $scope.attachedOptions.enabled
|
if $scope.attached and $scope.attachedOptions.enabled
|
||||||
$scope.attached.defaultProfileName = name
|
$scope.attached.defaultProfileName = name
|
||||||
else
|
else
|
||||||
@ -301,11 +317,95 @@ angular.module('omega').controller 'SwitchProfileCtrl', ($scope, $location,
|
|||||||
$scope.profile.defaultProfileName = $scope.attached.defaultProfileName
|
$scope.profile.defaultProfileName = $scope.attached.defaultProfileName
|
||||||
delete $scope.options[$scope.attachedKey]
|
delete $scope.options[$scope.attachedKey]
|
||||||
|
|
||||||
stopWatchingForGuide = $scope.$watch 'profile.rules', (rules) ->
|
# == Edit source ==
|
||||||
return unless rules
|
stateEditorKey = 'web._profileEditor.' + $scope.profile.name
|
||||||
stopWatchingForGuide()
|
$scope.loadRules = false
|
||||||
omegaTarget.state(['web.switchGuide', 'firstRun'
|
$scope.editSource = false
|
||||||
]).then ([switchGuide, firstRun]) ->
|
parseOmegaRules = (code, {detect, requireResult} = {}) ->
|
||||||
return if firstRun or switchGuide == 'shown'
|
setError = (error) ->
|
||||||
$script 'js/switch_profile_guide.js'
|
if error.reason
|
||||||
omegaTarget.state('web.switchGuide', 'shown')
|
args = error.args ? [
|
||||||
|
error.sourceLineNo
|
||||||
|
error.source
|
||||||
|
]
|
||||||
|
message = trFilter('ruleList_error_' + error.reason, args)
|
||||||
|
error.message = message if message
|
||||||
|
return {error: error}
|
||||||
|
if detect and not OmegaPac.RuleList.Switchy.detect(code)
|
||||||
|
return {error: {reason: 'notSwitchy'}}
|
||||||
|
refs = OmegaPac.RuleList.Switchy.directReferenceSet({
|
||||||
|
ruleList: code
|
||||||
|
})
|
||||||
|
if requireResult and not refs
|
||||||
|
return setError({reason: 'resultNotEnabled'})
|
||||||
|
for own key, name of refs
|
||||||
|
if not OmegaPac.Profiles.byKey(key, $scope.options)
|
||||||
|
return setError({reason: 'unknownProfile', args: [name]})
|
||||||
|
try
|
||||||
|
return rules: OmegaPac.RuleList.Switchy.parseOmega(code, null, null,
|
||||||
|
{strict: true, source: false})
|
||||||
|
catch err
|
||||||
|
return setError(err)
|
||||||
|
parseSource = ->
|
||||||
|
return true unless $scope.source
|
||||||
|
{rules, error} = parseOmegaRules($scope.source.code.trim(),
|
||||||
|
requireResult: true)
|
||||||
|
if error
|
||||||
|
$scope.source.error = error
|
||||||
|
$scope.editSource = true
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
$scope.source.error = undefined
|
||||||
|
$scope.attachedOptions.defaultProfileName = rules.pop().profileName
|
||||||
|
# Try to merge with existing rules if possible.
|
||||||
|
diff = jsondiffpatch.create(
|
||||||
|
objectHash: (obj) -> JSON.stringify(obj)
|
||||||
|
textDiff: minLength: 1 / 0
|
||||||
|
)
|
||||||
|
oldRules = angular.fromJson(angular.toJson($scope.profile.rules))
|
||||||
|
patch = diff.diff(oldRules, rules)
|
||||||
|
jsondiffpatch.patch($scope.profile.rules, patch)
|
||||||
|
return true
|
||||||
|
$scope.toggleSource = -> $q.all([attachedReady, rulesReady]).then ->
|
||||||
|
$scope.editSource = not $scope.editSource
|
||||||
|
if $scope.editSource
|
||||||
|
args =
|
||||||
|
rules: $scope.profile.rules
|
||||||
|
defaultProfileName: $scope.attachedOptions.defaultProfileName
|
||||||
|
code = OmegaPac.RuleList.Switchy.compose(args, withResult: true)
|
||||||
|
$scope.source = {code: code}
|
||||||
|
else
|
||||||
|
return unless parseSource()
|
||||||
|
$scope.source = null
|
||||||
|
$scope.loadRules = true
|
||||||
|
omegaTarget.state(stateEditorKey, {editSource: $scope.editSource})
|
||||||
|
|
||||||
|
$scope.$on 'omegaApplyOptions', (event) ->
|
||||||
|
if $scope.attached?.ruleList and not $scope.attached.sourceUrl
|
||||||
|
$scope.attachedRuleListError = undefined
|
||||||
|
{error} = parseOmegaRules($scope.attached.ruleList.trim(), detect: true)
|
||||||
|
if error
|
||||||
|
if error.reason != 'resultNotEnabled' and error.reason != 'notSwitchy'
|
||||||
|
$scope.attachedRuleListError = error
|
||||||
|
event.preventDefault()
|
||||||
|
angular.element('#attached-rulelist')[0].focus()
|
||||||
|
else
|
||||||
|
$scope.attached.format = 'Switchy'
|
||||||
|
|
||||||
|
if $scope.editSource and $scope.source.touched
|
||||||
|
event.preventDefault()
|
||||||
|
if parseSource()
|
||||||
|
$scope.source.touched = false
|
||||||
|
$timeout ->
|
||||||
|
$rootScope.applyOptions()
|
||||||
|
|
||||||
|
omegaTarget.state(stateEditorKey).then (opts) ->
|
||||||
|
if opts?.editSource
|
||||||
|
$scope.toggleSource()
|
||||||
|
else
|
||||||
|
$scope.loadRules = true
|
||||||
|
getState = omegaTarget.state(['web.switchGuide', 'firstRun'])
|
||||||
|
$q.all([rulesReady, getState]).then ([_, [switchGuide, firstRun]]) ->
|
||||||
|
return if firstRun or switchGuide == 'shown'
|
||||||
|
$script 'js/switch_profile_guide.js'
|
||||||
|
omegaTarget.state('web.switchGuide', 'shown')
|
||||||
|
@ -6,7 +6,7 @@ section.settings-group
|
|||||||
.text-info
|
.text-info
|
||||||
span.glyphicon.glyphicon-info-sign
|
span.glyphicon.glyphicon-info-sign
|
||||||
= ' '
|
= ' '
|
||||||
{{'options_exportProfileHelp' | tr}}
|
| {{'options_exportProfileHelp' | tr}}
|
||||||
div.checkbox(ng-show='!(options["-showConditionTypes"] > 0)')
|
div.checkbox(ng-show='!(options["-showConditionTypes"] > 0)')
|
||||||
label
|
label
|
||||||
input(type='checkbox' ng-model='options["-exportLegacyRuleList"]')
|
input(type='checkbox' ng-model='options["-exportLegacyRuleList"]')
|
||||||
|
@ -15,8 +15,26 @@ div(ng-controller='SwitchProfileCtrl')
|
|||||||
dt(ng-repeat-start='type in group.types') {{'condition_' + type | tr}}
|
dt(ng-repeat-start='type in group.types') {{'condition_' + type | tr}}
|
||||||
dd(ng-repeat-end ng-bind-html='"condition_help_" + type | tr')
|
dd(ng-repeat-end ng-bind-html='"condition_help_" + type | tr')
|
||||||
section.settings-group
|
section.settings-group
|
||||||
h3 {{'options_group_switchRules' | tr}}
|
h3
|
||||||
.table-responsive.switch-rules-wrapper
|
| {{'options_group_switchRules' | tr}}
|
||||||
|
= ' '
|
||||||
|
button.btn(ng-click='toggleSource()' ng-class='editSource ? "btn-primary active" : "btn-default"')
|
||||||
|
span.glyphicon.glyphicon-edit
|
||||||
|
= ' '
|
||||||
|
| {{'options_profileEditSource' | tr}}
|
||||||
|
= ' '
|
||||||
|
a.btn.btn-link.btn-sm.clear-padding.toggle-condition-help(
|
||||||
|
ng-show='editSource' target='_blank'
|
||||||
|
title='{{"options_profileEditSourceHelp" | tr}}'
|
||||||
|
href='{{"options_profileEditSourceHelpUrl" | tr}}')
|
||||||
|
span.glyphicon.glyphicon-question-sign
|
||||||
|
.alert.alert-danger.width-limit(ng-show='source.error')
|
||||||
|
span.glyphicon.glyphicon-remove
|
||||||
|
= ' '
|
||||||
|
| {{source.error.message}}
|
||||||
|
.rules-source(ng-show='editSource')
|
||||||
|
textarea.monospace.form-control.width-limit(ng-model='source.code' rows=20 ng-change='source.touched = true; $root.optionsDirty = true')
|
||||||
|
.table-responsive.switch-rules-wrapper(ng-if='loadRules' ng-show='!editSource')
|
||||||
table.switch-rules.table.table-bordered.table-condensed.width-limit-xl
|
table.switch-rules.table.table-bordered.table-condensed.width-limit-xl
|
||||||
thead
|
thead
|
||||||
tr
|
tr
|
||||||
@ -94,7 +112,7 @@ div(ng-controller='SwitchProfileCtrl')
|
|||||||
td
|
td
|
||||||
td(colspan='2') {{'options_switchDefaultProfile' | tr}}
|
td(colspan='2') {{'options_switchDefaultProfile' | tr}}
|
||||||
td
|
td
|
||||||
div(omega-profile-select='options | profiles:profile' ng-model='defaultProfileName'
|
div(omega-profile-select='options | profiles:profile' ng-model='attachedOptions.defaultProfileName'
|
||||||
disp-name='dispNameFilter' options='options')
|
disp-name='dispNameFilter' options='options')
|
||||||
td
|
td
|
||||||
button.btn.btn-info.btn-sm(title="{{'options_resetRules_help' | tr}}" ng-click='resetRules()')
|
button.btn.btn-info.btn-sm(title="{{'options_resetRules_help' | tr}}" ng-click='resetRules()')
|
||||||
@ -131,5 +149,9 @@ div(ng-controller='SwitchProfileCtrl')
|
|||||||
| {{'options_ruleListLastUpdate' | tr:[(attached.lastUpdate | date:'medium')]}}
|
| {{'options_ruleListLastUpdate' | tr:[(attached.lastUpdate | date:'medium')]}}
|
||||||
p.alert.alert-danger.width-limit(ng-show='attached.sourceUrl && !attached.lastUpdate')
|
p.alert.alert-danger.width-limit(ng-show='attached.sourceUrl && !attached.lastUpdate')
|
||||||
| {{'options_ruleListObsolete' | tr}}
|
| {{'options_ruleListObsolete' | tr}}
|
||||||
textarea.monospace.form-control.width-limit(ng-model='attached.ruleList' rows=20
|
p.alert.alert-danger.width-limit(ng-show='attachedRuleListError')
|
||||||
ng-disabled='!!attached.sourceUrl')
|
span.glyphicon.glyphicon-remove
|
||||||
|
= ' '
|
||||||
|
| {{attachedRuleListError.message}}
|
||||||
|
textarea#attached-rulelist.monospace.form-control.width-limit(rows=20
|
||||||
|
ng-model='attached.ruleList' ng-disabled='!!attached.sourceUrl')
|
||||||
|
Loading…
Reference in New Issue
Block a user