Allow editing switch profiles as omega rule list. Fix #80.

This commit is contained in:
FelisCatus 2015-02-09 21:14:23 +08:00
parent a54e02b503
commit 75ecb9aa46
9 changed files with 428 additions and 79 deletions

View File

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

View File

@ -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": "代理服务器"
}, },

View File

@ -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": "代理服務器"
}, },

View File

@ -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": "代理伺服器"
}, },

View File

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

View File

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

View File

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

View File

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

View File

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