diff --git a/omega-i18n/en/messages.json b/omega-i18n/en/messages.json index 243d6ed..87df7ba 100644 --- a/omega-i18n/en/messages.json +++ b/omega-i18n/en/messages.json @@ -91,7 +91,8 @@ "message": "Switchy" }, "ruleListFormat_AutoProxy": { - "message": "AutoProxy" + "message": "AutoProxy", + "description": "The rule list format name of the AutoProxy project. This has nothing to do with SwitchProfile." }, "dialog_close": { @@ -333,6 +334,15 @@ "options_group_pacScript": { "message": "PAC Script" }, + "options_group_virtualProfile": { + "message": "Virtual Profile" + }, + "options_virtualProfileTarget": { + "message": "Target" + }, + "options_virtualProfileTargetHelp": { + "message": "When this profile is applied, it acts exactly the same as the profile selected below." + }, "options_group_ruleListConfig": { "message": "Rule List Config" }, @@ -532,6 +542,12 @@ "options_profileDescRuleListProfile" : { "message": "Reusing an online collection of conditions published by others." }, + "options_profileTypeVirtualProfile" : { + "message": "Virtual Profile" + }, + "options_profileDescVirtualProfile" : { + "message": "A virtual profile can act as any of the other profiles on demand. It works well with SwitchProfile, allowing you to change the result of multiple conditions by one click." + }, "options_createProfile" : { "message": "Create" }, diff --git a/omega-i18n/zh_CN/messages.json b/omega-i18n/zh_CN/messages.json index e6d63b1..753f914 100644 --- a/omega-i18n/zh_CN/messages.json +++ b/omega-i18n/zh_CN/messages.json @@ -91,7 +91,8 @@ "message": "Switchy" }, "ruleListFormat_AutoProxy": { - "message": "AutoProxy" + "message": "AutoProxy", + "description": "AutoProxy 项目规则列表格式的名称,和此程序的自动切换等无关。" }, "dialog_close": { @@ -339,6 +340,9 @@ "options_ruleListFormat": { "message": "规则列表格式" }, + "options_virtualProfileTargetHelp": { + "message": "当使用此情景模式时,相当于使用了以下情景模式:" + }, "options_group_ruleListResult": { "message": "规则列表结果情景模式" }, @@ -532,6 +536,12 @@ "options_profileDescRuleListProfile" : { "message": "使用他人发布的在线规则列表来切换情景模式。" }, + "options_profileTypeVirtualProfile" : { + "message": "虚情景模式" + }, + "options_profileDescVirtualProfile" : { + "message": "虚情景模式可以作为某个其他情景模式使用,并可以根据需要更改对象。一般用在自动切换中,这样就可以一次性更改多个条件对应的代理。" + }, "options_createProfile" : { "message": "创建" }, diff --git a/omega-i18n/zh_HK/messages.json b/omega-i18n/zh_HK/messages.json index 527b47b..22b9976 100644 --- a/omega-i18n/zh_HK/messages.json +++ b/omega-i18n/zh_HK/messages.json @@ -340,6 +340,9 @@ "options_ruleListFormat": { "message": "規則列表格式" }, + "options_virtualProfileTargetHelp": { + "message": "當使用此情景模式時,相當於使用了以下情景模式:" + }, "options_group_ruleListResult": { "message": "規則列表結果情景模式" }, @@ -533,6 +536,12 @@ "options_profileDescRuleListProfile" : { "message": "使用他人發佈的在線規則列表來切換情景模式。" }, + "options_profileTypeVirtualProfile" : { + "message": "虛擬情景模式" + }, + "options_profileDescVirtualProfile" : { + "message": "虛擬情景模式可以作為某個其他情景模式使用,並可以根據需要更改目標。一般用在自動切換中,這樣就可以一次性更改多個條件對應的代理。" + }, "options_createProfile" : { "message": "創建" }, diff --git a/omega-i18n/zh_TW/messages.json b/omega-i18n/zh_TW/messages.json index 2f0dbb9..f4f3dcb 100644 --- a/omega-i18n/zh_TW/messages.json +++ b/omega-i18n/zh_TW/messages.json @@ -91,7 +91,8 @@ "message": "Switchy" }, "ruleListFormat_AutoProxy": { - "message": "AutoProxy" + "message": "AutoProxy", + "description": "AutoProxy 項目規則列表格式的名稱,和本程式的自動切換等無關。" }, "dialog_close": { @@ -339,6 +340,9 @@ "options_ruleListFormat": { "message": "規則列表格式" }, + "options_virtualProfileTargetHelp": { + "message": "當使用此情景模式時,相當於使用了以下情景模式:" + }, "options_group_ruleListResult": { "message": "規則列表結果情景模式" }, @@ -532,6 +536,12 @@ "options_profileDescRuleListProfile" : { "message": "使用他人釋出的線上規則列表來切換情景模式。" }, + "options_profileTypeVirtualProfile" : { + "message": "虛擬情景模式" + }, + "options_profileDescVirtualProfile" : { + "message": "虛擬情景模式可以作為某個其他情景模式使用,並可以根據需要更改目標。一般用在自動切換中,這樣就可以一次性更改多個條件對應的代理。" + }, "options_createProfile" : { "message": "創建" }, diff --git a/omega-pac/src/profiles.coffee b/omega-pac/src/profiles.coffee index 6262290..7eddc59 100644 --- a/omega-pac/src/profiles.coffee +++ b/omega-pac/src/profiles.coffee @@ -299,6 +299,11 @@ module.exports = exports = create: (profile) -> profile.defaultProfileName ?= 'direct' profile.rules ?= [] + if profile.profileType == 'VirtualProfile' and not profile.virtualType? + target = exports.byName(profile.defaultProfileName, {}) + if target + profile.virtualType = target.profileType + profile.color = target.color directReferenceSet: (profile) -> refs = {} refs[exports.nameAsKey(profile.defaultProfileName)] = @@ -323,10 +328,12 @@ module.exports = exports = return rule return [exports.nameAsKey(profile.defaultProfileName), null] compile: (profile, cache) -> + rules = cache.analyzed + if rules.length == 0 + return @profileResult profile.defaultProfileName body = [ new U2.AST_Directive value: 'use strict' ] - rules = cache.analyzed for rule in rules body.push new U2.AST_If condition: Conditions.compile rule.condition @@ -342,6 +349,7 @@ module.exports = exports = ] body: body ) + 'VirtualProfile': 'SwitchProfile' 'RuleListProfile': includable: true inclusive: true diff --git a/omega-pac/test/profiles.coffee b/omega-pac/test/profiles.coffee index 204628c..444e2c3 100644 --- a/omega-pac/test/profiles.coffee +++ b/omega-pac/test/profiles.coffee @@ -167,6 +167,12 @@ describe 'Profiles', -> '+example': 'example' '+abc': 'abc' ) + describe 'VirtualProfile', -> + profile = Profiles.create('test', 'VirtualProfile') + profile.defaultProfileName = 'default' + it 'should always return defaultProfileName', -> + testProfile(profile, 'http://www.example.com/abc', + ['+default', null]) describe 'RulelistProfile', -> profile = Profiles.create('test', 'AutoProxyRuleListProfile') profile.defaultProfileName = 'default' diff --git a/omega-target-chromium-extension/background.coffee b/omega-target-chromium-extension/background.coffee index fcc89f1..360cc6e 100644 --- a/omega-target-chromium-extension/background.coffee +++ b/omega-target-chromium-extension/background.coffee @@ -51,6 +51,11 @@ actionForUrl = (url) -> options.matchProfile(request) ).then ({profile, results}) -> current = options.currentProfile() + currentName = dispName(current.name) + if current.profileType == 'VirtualProfile' + realCurrentName = current.defaultProfileName + currentName += " [#{dispName(realCurrentName)}]" + current = options.profile(realCurrentName) details = '' direct = false attached = false @@ -63,7 +68,7 @@ actionForUrl = (url) -> name = name.substr(1) if isHidden(name) attached = true - else + else if name != realCurrentName details += chrome.i18n.getMessage 'browserAction_defaultRuleDetails' details += " => #{dispName(name)}\n" else if result[1].length == 0 @@ -103,7 +108,7 @@ actionForUrl = (url) -> drawIcon(profile.color, current.color) return { title: chrome.i18n.getMessage('browserAction_titleWithResult', [ - dispName(current.name) + currentName dispName(profile.name) details ]) @@ -163,14 +168,20 @@ options.currentProfileChanged = (reason) -> else if reason != 'clearBadge' external = false + current = options.currentProfile() + currentName = '' + if current + currentName = dispName(current.name) + if current.profileType == 'VirtualProfile' + realCurrentName = current.defaultProfileName + currentName += " [#{dispName(realCurrentName)}]" + current = options.profile(realCurrentName) title = if profile.name == '' details = profile.pacUrl ? options.printFixedProfile(profile) details = details ? profile.profileType else - chrome.i18n.getMessage('browserAction_titleNormal', [ - options._currentProfileName - ]) + chrome.i18n.getMessage('browserAction_titleNormal', [currentName]) if external and profile.profileType != 'SystemProfile' message = chrome.i18n.getMessage('browserAction_titleExternalProxy') title = message + '\n' + title diff --git a/omega-target-chromium-extension/omega_target_web.coffee b/omega-target-chromium-extension/omega_target_web.coffee index 1c6dc7b..f6ec12d 100644 --- a/omega-target-chromium-extension/omega_target_web.coffee +++ b/omega-target-chromium-extension/omega_target_web.coffee @@ -96,6 +96,8 @@ angular.module('omegaTarget', []).factory 'omegaTarget', ($q) -> callBackground('addCondition', condition, profileName) addProfile: (profile) -> callBackground('addProfile', profile).then omegaTarget.refresh + setDefaultProfile: (profileName, defaultProfileName) -> + callBackground('setDefaultProfile', profileName, defaultProfileName) getActivePageInfo: -> # First, try to clear badges on opening the popup. callBackground('clearBadge') diff --git a/omega-target/src/options.coffee b/omega-target/src/options.coffee index 55d01bd..952bdfa 100644 --- a/omega-target/src/options.coffee +++ b/omega-target/src/options.coffee @@ -280,16 +280,25 @@ class Options profile = if @_currentProfileName then @currentProfile() else null profiles = {} currentIncludable = profile && OmegaPac.Profiles.isIncludable(profile) + allReferenceSet = null if not profile or not OmegaPac.Profiles.isInclusive(profile) results = [] - OmegaPac.Profiles.each @_options, (key, profile) -> + OmegaPac.Profiles.each @_options, (key, p) => profiles[key] = - name: profile.name - profileType: profile.profileType - color: profile.color - builtin: !!profile.builtin - if currentIncludable and OmegaPac.Profiles.isIncludable(profile) - results?.push(profile.name) + name: p.name + profileType: p.profileType + color: p.color + builtin: if p.builtin then true + if p.virtualType + profiles[key].virtualType = p.virtualType + profiles[key].defaultProfileName = p.defaultProfileName + if not allReferenceSet? + allReferenceSet = OmegaPac.Profiles.allReferenceSet profile, @_options + if allReferenceSet[key] + profiles[key].validResultProfiles = + OmegaPac.Profiles.validResultProfilesFor(p, @_options) + if currentIncludable and OmegaPac.Profiles.isIncludable(p) + results?.push(p.name) if profile and OmegaPac.Profiles.isInclusive(profile) results = OmegaPac.Profiles.validResultProfilesFor(profile, @_options) results = results.map (profile) -> profile.name @@ -505,7 +514,7 @@ class Options ### addTempRule: (domain, profileName) -> @log.method('Options#addTempRule', this, arguments) - return Profile.resolve() if not @_currentProfileName + return Promise.resolve() if not @_currentProfileName profile = OmegaPac.Profiles.byName(profileName, @_options) if not profile return Promise.reject new ProfileNotExistError(profileName) @@ -566,16 +575,19 @@ class Options ###* # Add a condition to the current active switch profile. # @param {Object.} cond The condition to add - # @param {string>} profileName The name of the profile to add the rule to. + # @param {string>} profileName The name of the result profile of the rule. # @returns {Promise} A promise which is fulfilled when the condition is saved. ### addCondition: (condition, profileName) -> @log.method('Options#addCondition', this, arguments) - return Profile.resolve() if not @_currentProfileName + return Promise.resolve() if not @_currentProfileName profile = OmegaPac.Profiles.byName(@_currentProfileName, @_options) if not profile?.rules? return Promise.reject new Error( "Cannot add condition to Profile #{@profile.name} (@{profile.type})") + 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] @@ -593,6 +605,33 @@ class Options changes[OmegaPac.Profiles.nameAsKey(profile)] = profile @_setOptions(changes) + ###* + # Set the defaultProfileName of the profile. + # @param {string>} profileName The name of the profile to modify. + # @param {string>} defaultProfileName The defaultProfileName to set. + # @returns {Promise} A promise which is fulfilled when the profile is saved. + ### + setDefaultProfile: (profileName, defaultProfileName) -> + @log.method('Options#setDefaultProfile', this, arguments) + profile = OmegaPac.Profiles.byName(profileName, @_options) + if not profile? + return Promise.reject new ProfileNotExistError(profileName) + else if not profile.defaultProfileName? + return Promise.reject new Error("Profile #{@profile.name} " + + "(@{profile.type}) does not have defaultProfileName!") + target = OmegaPac.Profiles.byName(defaultProfileName, @_options) + if not target? + return Promise.reject new ProfileNotExistError(defaultProfileName) + + profile.defaultProfileName = defaultProfileName + if profile.virtualType + profile.color = target.color + profile.virtualType = target.profileType + OmegaPac.Profiles.updateRevision(profile) + changes = {} + changes[OmegaPac.Profiles.nameAsKey(profile)] = profile + @_setOptions(changes) + ###* # Add a profile to the options # @param {{}} profile The profile to create @@ -616,7 +655,7 @@ class Options ### matchProfile: (request) -> if not @_currentProfileName - return Profile.resolve({profile: @_externalProfile, results: []}) + return Promise.resolve({profile: @_externalProfile, results: []}) results = [] profile = @_tempProfile profile ?= OmegaPac.Profiles.byName(@_currentProfileName, @_options) diff --git a/omega-web/src/coffee/omega_decoration.coffee b/omega-web/src/coffee/omega_decoration.coffee index adcaf3e..c2bcc16 100644 --- a/omega-web/src/coffee/omega_decoration.coffee +++ b/omega-web/src/coffee/omega_decoration.coffee @@ -1,6 +1,7 @@ orderForType = 'FixedProfile': -2000 'PacProfile': -1000 + 'VirtualProfile': 1000 'SwitchProfile': 2000 'RuleListProfile': 3000 @@ -10,6 +11,7 @@ angular.module('omegaDecoration', []).value('profileIcons', { 'AutoDetectProfile': 'glyphicon-file' 'FixedProfile': 'glyphicon-globe' 'PacProfile': 'glyphicon-file' + 'VirtualProfile': 'glyphicon-question-sign' 'RuleListProfile': 'glyphicon-list' 'SwitchProfile': 'glyphicon-retweet' }).constant('profileOrder', (a, b) -> @@ -21,12 +23,15 @@ angular.module('omegaDecoration', []).value('profileIcons', { -1 else 1 -).directive('omegaRepeatDone', ($parse) -> +).directive('omegaProfileIcon', (profileIcons) -> restrict: 'A' - link: (scope, element, attrs) -> - callback = $parse(attrs.omegaRepeatDone) - if scope.$last - scope.$evalAsync callback + templateUrl: 'partials/omega_profile_icon.html' + scope: + 'profile': '=?omegaProfileIcon' + 'icon': '=?icon' + 'color': '=?color' + link: (scope, element, attrs, ngModel) -> + scope.profileIcons = profileIcons ).directive('omegaProfileSelect', ($timeout, profileIcons) -> restrict: 'A' templateUrl: 'partials/omega_profile_select.html' diff --git a/omega-web/src/coffee/popup.coffee b/omega-web/src/coffee/popup.coffee index 976e260..b1a80d9 100644 --- a/omega-web/src/coffee/popup.coffee +++ b/omega-web/src/coffee/popup.coffee @@ -28,7 +28,7 @@ module.controller 'PopupCtrl', ($scope, $window, $q, omegaTarget, if not normal and $scope.isEffective(profile.name) 'glyphicon-ok' else - profileIcons[profile.profileType] + undefined $scope.openOptions = (hash) -> omegaTarget.openOptions(hash).then -> $window.close() @@ -45,6 +45,10 @@ module.controller 'PopupCtrl', ($scope, $window, $q, omegaTarget, $scope.tempRuleMenu.open = false omegaTarget.addTempRule(domain, profileName).then -> refresh() + + $scope.setDefaultProfile = (profileName, defaultProfileName) -> + omegaTarget.setDefaultProfile(profileName, defaultProfileName).then -> + refresh() $scope.addCondition = (condition, profileName) -> omegaTarget.addCondition(condition, profileName).then -> diff --git a/omega-web/src/less/options.less b/omega-web/src/less/options.less index 9736e08..b4776a9 100644 --- a/omega-web/src/less/options.less +++ b/omega-web/src/less/options.less @@ -243,6 +243,11 @@ main { visibility: hidden; } +.virtual-profile-icon { + border: dotted 1px; + margin: -1px; +} + .profile-actions { float: right; } diff --git a/omega-web/src/less/popup.less b/omega-web/src/less/popup.less index cd5b54c..f32c691 100644 --- a/omega-web/src/less/popup.less +++ b/omega-web/src/less/popup.less @@ -28,6 +28,11 @@ body.with-condition-form { padding: 0 5px; } +.virtual-profile-icon { + border: dotted 1px; + margin: -1px; +} + .nav { margin-bottom: 0; } @@ -47,6 +52,28 @@ li > a { .glyphicon { margin-right: 6px; } + + &.profile-with-default-edit { + padding-right: 0; + .dropdown-toggle { + margin: -5px 0; + color: inherit; + padding: 5px 8px; + min-width: 20px; + float: right; + + .glyphicon { + margin-right: 0; + } + } + } + } + + > li.active .dropdown-toggle { + border: none !important; + border-left: solid 1px !important; + background: none !important; + border-radius: 0 !important; } } diff --git a/omega-web/src/omega/controllers/profile.coffee b/omega-web/src/omega/controllers/profile.coffee index 5d6b9f8..d3fe9f7 100644 --- a/omega-web/src/omega/controllers/profile.coffee +++ b/omega-web/src/omega/controllers/profile.coffee @@ -5,6 +5,7 @@ angular.module('omega').controller 'ProfileCtrl', ($scope, $stateParams, profileTemplates = 'FixedProfile': 'profile_fixed.html' 'PacProfile': 'profile_pac.html' + 'VirtualProfile': 'profile_virtual.html' 'SwitchProfile': 'profile_switch.html' 'RuleListProfile': 'profile_rule_list.html' $scope.spectrumOptions = diff --git a/omega-web/src/omega/controllers/virtual_profile.coffee b/omega-web/src/omega/controllers/virtual_profile.coffee new file mode 100644 index 0000000..7709ac3 --- /dev/null +++ b/omega-web/src/omega/controllers/virtual_profile.coffee @@ -0,0 +1,9 @@ +angular.module('omega').controller 'VirtualProfileCtrl', ($scope, $location, + $modal, profileIcons, getAttachedName) -> + + onProfileChange = (profile, oldProfile) -> + return if profile == oldProfile or not profile or not oldProfile + target = $scope.profileByName(profile.defaultProfileName) + profile.color = target.color + profile.virtualType = target.profileType + $scope.$watch 'profile', onProfileChange, true diff --git a/omega-web/src/options.jade b/omega-web/src/options.jade index 1f3686d..f512383 100644 --- a/omega-web/src/options.jade +++ b/omega-web/src/options.jade @@ -30,8 +30,7 @@ html(lang='en' ng-controller='MasterCtrl' ng-csp) li.nav-header {{'options_navHeader_profiles' | tr}} li(ng-repeat='profile in options | profiles:"sorted"' ui-sref-active='active') a(ui-sref='profile({name: profile.name})') - span.glyphicon(class='{{profileIcons[profile.profileType]}}' - ng-style='{color: profile.color}') + span(omega-profile-icon='profile') = ' ' | {{profile.name}} li diff --git a/omega-web/src/partials/cannot_delete_profile.jade b/omega-web/src/partials/cannot_delete_profile.jade index 83645d2..6b0f5a3 100644 --- a/omega-web/src/partials/cannot_delete_profile.jade +++ b/omega-web/src/partials/cannot_delete_profile.jade @@ -8,8 +8,7 @@ .well ul.list-style-none li(ng-repeat='p in refs') - span.glyphicon(class='{{profileIcons[p.profileType]}}' - ng-style='{color: p.color}') + span(omega-profile-icon='p') = ' ' | {{p.name | dispName}} p {{'options_modifyReferringProfiles' | tr}} diff --git a/omega-web/src/partials/delete_attached.jade b/omega-web/src/partials/delete_attached.jade index cbd91e9..78da597 100644 --- a/omega-web/src/partials/delete_attached.jade +++ b/omega-web/src/partials/delete_attached.jade @@ -6,7 +6,7 @@ .modal-body p {{'options_deleteAttachedConfirm' | tr}} .well - span.glyphicon(class='{{profileIcons[attached.profileType]}}') + span(omega-profile-icon='attached') = ' ' | {{attached.sourceUrl || ('options_ruleListLineCount' | tr:[attached.ruleList.split('\n').length])}} .modal-footer diff --git a/omega-web/src/partials/delete_profile.jade b/omega-web/src/partials/delete_profile.jade index cf0467d..b0cbc3e 100644 --- a/omega-web/src/partials/delete_profile.jade +++ b/omega-web/src/partials/delete_profile.jade @@ -6,8 +6,7 @@ .modal-body p {{'options_deleteProfileConfirm' | tr}} .well - span.glyphicon(class='{{profileIcons[profile.profileType]}}' - ng-style='{color: profile.color}') + span(omega-profile-icon='profile') = ' ' | {{profile.name}} .modal-footer diff --git a/omega-web/src/partials/new_profile.jade b/omega-web/src/partials/new_profile.jade index 2b1d7d3..27a3fb2 100644 --- a/omega-web/src/partials/new_profile.jade +++ b/omega-web/src/partials/new_profile.jade @@ -8,7 +8,7 @@ form(ng-submit='newProfile.$valid && $close(profile)' name='newProfile') .form-group(ng-class='{"has-error": !newProfile.profileNewName.$valid}') label(for='profile-new-name') {{'options_newProfileName' | tr}} input#profile-new-name.form-control(type='text' name='profileNewName' required ng-model='profile.name' - ui-validate='validateProfileName') + ui-validate='validateProfileName' autofocus) .help-block(ng-show='newProfile.profileNewName.$error.required') {{'options_profileNameEmpty' | tr}} .help-block(ng-show='newProfile.profileNewName.$error.reserved') {{'options_profileNameReserved' | tr}} .help-block(ng-show='!newProfile.profileNewName.$error.reserved && newProfile.profileNewName.$error.conflict') @@ -23,7 +23,7 @@ form(ng-submit='newProfile.$valid && $close(profile)' name='newProfile') label input(type='radio' name='profile-new-type' value='FixedProfile' ng-model='profile.profileType' ng-init='profile.profileType = "FixedProfile"') span.profile-type - span.glyphicon.glyphicon-globe + span.glyphicon(ng-class='profileIcons["FixedProfile"]') = ' ' span {{'options_profileTypeFixedProfile' | tr}} .help-block {{'options_profileDescFixedProfile' | tr}} @@ -31,7 +31,7 @@ form(ng-submit='newProfile.$valid && $close(profile)' name='newProfile') label input(type='radio', name='profile-new-type', value='SwitchProfile' ng-model='profile.profileType') span.profile-type - span.glyphicon.glyphicon-retweet + span.glyphicon(ng-class='profileIcons["SwitchProfile"]') = ' ' span {{'options_profileTypeSwitchProfile' | tr}} .help-block {{'options_profileDescSwitchProfile' | tr}} @@ -39,11 +39,19 @@ form(ng-submit='newProfile.$valid && $close(profile)' name='newProfile') label input(type='radio', name='profile-new-type', value='PacProfile' ng-model='profile.profileType') span.profile-type - span.glyphicon.glyphicon-file + span.glyphicon(ng-class='profileIcons["PacProfile"]') = ' ' span {{'options_profileTypePacProfile' | tr}} .help-block {{'options_profileDescPacProfile' | tr}} .help-block {{'options_profileDescMorePacProfile' | tr}} + .radio + label + input(type='radio', name='profile-new-type', value='VirtualProfile' ng-model='profile.profileType') + span.profile-type + span.glyphicon.virtual-profile-icon(ng-class='profileIcons["VirtualProfile"]') + = ' ' + span {{'options_profileTypeVirtualProfile' | tr}} + .help-block {{'options_profileDescVirtualProfile' | tr}} .modal-footer button.btn.btn-default(type='button' ng-click='$dismiss()') {{'dialog_cancel' | tr}} button.btn.btn-primary(type='submit' ng-disabled='!newProfile.$valid') {{'options_createProfile' | tr}} diff --git a/omega-web/src/partials/omega_profile_icon.jade b/omega-web/src/partials/omega_profile_icon.jade new file mode 100644 index 0000000..6a6f658 --- /dev/null +++ b/omega-web/src/partials/omega_profile_icon.jade @@ -0,0 +1,2 @@ +span.glyphicon(class='{{icon || profileIcons[profile.virtualType] || profileIcons[profile.profileType]}}' + ng-style='{color: color || profile.color}' ng-class='{"virtual-profile-icon": profile.profileType == "VirtualProfile"}') diff --git a/omega-web/src/partials/omega_profile_select.jade b/omega-web/src/partials/omega_profile_select.jade index 7f38099..124642f 100644 --- a/omega-web/src/partials/omega_profile_select.jade +++ b/omega-web/src/partials/omega_profile_select.jade @@ -1,7 +1,7 @@ .btn-group.omega-profile-select(dropdown on-toggle="toggled(open)") button.btn.btn-default.dropdown-toggle(type='button' aria-expanded='false' role='listbox' aria-haspopup='true') - span.glyphicon(class='{{profileIcon || "glyphicon-time"}}' ng-style='{color: selectedProfile.color}') + span(omega-profile-icon='selectedProfile' icon='selectedProfile ? undefined : "glyphicon-time"') = ' ' span(ng-show='!!profileName') {{getName(selectedProfile)}} span(ng-show='!profileName') {{defaultText}} @@ -14,5 +14,5 @@ = ' {{defaultText}}' li(role='option' ng-repeat='profile in dispProfiles' ng-class='{active: profileName == profile.name}') a(ng-click='setProfileName(profile.name)') - span.glyphicon(class='{{profileIcons[profile.profileType]}}' ng-style='{color: profile.color}') + span(omega-profile-icon='profile') = ' {{getName(profile)}}' diff --git a/omega-web/src/partials/profile_virtual.jade b/omega-web/src/partials/profile_virtual.jade new file mode 100644 index 0000000..a5b38c4 --- /dev/null +++ b/omega-web/src/partials/profile_virtual.jade @@ -0,0 +1,10 @@ +div(ng-controller='VirtualProfileCtrl') + section.settings-group + h3 {{'options_group_virtualProfile' | tr}} + p.help-block + | {{'options_virtualProfileTargetHelp' | tr}} + .form-group + label {{'options_virtualProfileTarget' | tr}} + = ' ' + div(omega-profile-select='options | profiles:profile' ng-model='profile.defaultProfileName' + disp-name='$profile.name | dispName' style='display: inline-block;') diff --git a/omega-web/src/partials/rule_remove_confirm.jade b/omega-web/src/partials/rule_remove_confirm.jade index 23f5afc..6242b5a 100644 --- a/omega-web/src/partials/rule_remove_confirm.jade +++ b/omega-web/src/partials/rule_remove_confirm.jade @@ -10,8 +10,7 @@ = ' ' | {{rule.condition.pattern}} span.pull-right - span.glyphicon(class='{{profileIcons[ruleProfile.profileType]}}' - ng-style='{color: ruleProfile.color}') + span(omega-profile-icon='ruleProfile') = ' ' | {{ruleProfile.name | dispName}} .modal-footer diff --git a/omega-web/src/partials/rule_reset_confirm.jade b/omega-web/src/partials/rule_reset_confirm.jade index edcbcbb..bb11c43 100644 --- a/omega-web/src/partials/rule_reset_confirm.jade +++ b/omega-web/src/partials/rule_reset_confirm.jade @@ -6,8 +6,7 @@ .modal-body p {{'options_resetRulesConfirm' | tr}} .well - span.glyphicon(class='{{profileIcons[ruleProfile.profileType]}}' - ng-style='{color: ruleProfile.color}') + span(omega-profile-icon='ruleProfile') = ' ' | {{ruleProfile.name | dispName}} .modal-footer diff --git a/omega-web/src/partials/ui.jade b/omega-web/src/partials/ui.jade index c6ad9f0..873a5ba 100644 --- a/omega-web/src/partials/ui.jade +++ b/omega-web/src/partials/ui.jade @@ -36,14 +36,12 @@ section.settings-group ul.cycle-profile-container.cycle-enabled(ui-sortable="sortableOptions" ng-model='options["-quickSwitchProfiles"]') li(ng-repeat='name in options["-quickSwitchProfiles"]') - span.glyphicon(class='{{profileIcons[profileByName(name).profileType]}}' - ng-style='{color: profileByName(name).color}') + span(omega-profile-icon='profileByName(name)') = ' ' | {{name | dispName}} h4 {{'options_notCycledProfiles' | tr}} ul.cycle-profile-container(ui-sortable="sortableOptions" ng-model='notCycledProfiles') li.bg-success(ng-repeat='name in notCycledProfiles') - span.glyphicon(class='{{profileIcons[profileByName(name).profileType]}}' - ng-style='{color: profileByName(name).color}') + span(omega-profile-icon='profileByName(name)') = ' ' | {{name | dispName}} diff --git a/omega-web/src/popup.jade b/omega-web/src/popup.jade index a2c055f..0d8a46b 100644 --- a/omega-web/src/popup.jade +++ b/omega-web/src/popup.jade @@ -27,30 +27,36 @@ html(lang='en' ng-app='omegaPopup' ng-controller='PopupCtrl' ng-csp) ul.nav.nav-pills.nav-stacked(ng-hide='showConditionForm || proxyNotControllable') li.profile(ng-repeat='profile in builtinProfiles' ng-class='{active: isActive(profile.name), "bg-info": isEffective(profile.name)}') a(ng-click='applyProfile(profile)') - span.glyphicon(ng-style='{color: profile.color}' class='{{getIcon(profile)}}') + span(omega-profile-icon='profile' icon='getIcon(profile)') = ' ' | {{profile.name | dispName}} li.profile.external-profile(ng-show='!!externalProfile' ng-class='{active: isActive(""), "bg-info": isEffective("")}') a(ng-click='nameExternal.open = true') form(name='nameExternalForm' ng-submit='nameExternalForm.$valid && saveExternal()') - span.glyphicon(ng-style='{color: externalProfile.color}' class='{{getIcon(externalProfile, "normal")}}') + span(omega-profile-icon='externalProfile' icon='getIcon(externalProfile, "normal")') = ' ' 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.divider - li.profile(ng-repeat='profile in customProfiles' ng-class='{active: isActive(profile.name), "bg-info": isEffective(profile.name)}') - a(ng-click='applyProfile(profile)') - span.glyphicon(ng-style='{color: profile.color}' class='{{getIcon(profile)}}') + li.profile(ng-repeat='profile in customProfiles' ng-class='{active: isActive(profile.name), "bg-info": isEffective(profile.name)}' + dropdown) + a(ng-click='applyProfile(profile)' ng-if='!profile.validResultProfiles') + span(omega-profile-icon='profile' icon='getIcon(profile)') = ' ' | {{profile.name | dispName}} - li.external-profile(style='display: none') - a.form-group - span.glyphicon.glyphicon-question-sign - = ' ' - span {{'popup_externalProfile' | tr}} - input.external-profile-name.input-small(type='text' style='display: none' - placeholder='{{"popup_externalProfileName" | tr}}') + a.profile-with-default-edit(ng-click='applyProfile(profile)' ng-if='!!profile.validResultProfiles') + span(omega-profile-icon='profile' icon='getIcon(profile)') + = ' {{profile.name | dispName}} ' + | [{{profile.defaultProfileName}}] + button.dropdown-toggle.btn.btn-default(ng-click='$event.stopPropagation()') + span.glyphicon.glyphicon-chevron-down + ul.dropdown-menu(ng-if='!!profile.validResultProfiles') + li(ng-repeat='p in profile.validResultProfiles' ng-class='{active: p.name == profile.defaultProfileName}') + a(ng-click='setDefaultProfile(profile.name, p.name)') + span(omega-profile-icon='p') + = ' ' + | {{p.name | dispName}} li.divider(ng-show='!!currentDomain && validResultProfiles.length') li(ng-show='!!currentProfileCanAddRule') a(ng-click='showConditionForm = true') @@ -67,8 +73,7 @@ html(lang='en' ng-app='omegaPopup' ng-controller='PopupCtrl' ng-csp) li(ng-repeat='profile in validResultProfiles' ng-class='{active: profile.name == currentTempRuleProfile}' ng-show='!!currentTempRuleProfile || validResultProfiles.length == 1 || profile.name != currentProfileName') a(ng-click='addTempRule(currentDomain, profile.name)') - span.glyphicon(ng-style='{color: profile.color}' - class='{{profileIcons[profile.profileType]}}') + span(omega-profile-icon='profile') = ' ' | {{profile.name | dispName}} li.divider @@ -95,8 +100,7 @@ html(lang='en' ng-app='omegaPopup' ng-controller='PopupCtrl' ng-csp) | {{'popup_addConditionTo' | tr}} = ' ' span.profile-inline - span.glyphicon(ng-style='{color: currentProfile.color}' - class='{{profileIcons[currentProfile.profileType]}}') + span(omega-profile-icon='currentProfile') = ' ' | {{currentProfileName | dispName}} div.form-group