diff --git a/omega-target-chromium-extension/background.coffee b/omega-target-chromium-extension/background.coffee index 26b5e06..f13a112 100644 --- a/omega-target-chromium-extension/background.coffee +++ b/omega-target-chromium-extension/background.coffee @@ -285,6 +285,12 @@ encodeError = (obj) -> else obj +refreshActivePageIfEnabled = -> + return unless localStorage['omega.local.refreshOnProfileChange'] + chrome.tabs.query {active: true, lastFocusedWindow: true}, (tabs) -> + if tabs[0].url and tabs[0].url.substr(0, 6) != 'chrome' + chrome.tabs.reload(tabs[0].id, {bypassCache: true}) + chrome.runtime.onMessage.addListener (request, sender, respond) -> options.ready.then -> target = options @@ -298,6 +304,8 @@ chrome.runtime.onMessage.addListener (request, sender, respond) -> return promise = Promise.resolve().then -> method.apply(target, request.args) + if request.refreshActivePage + promise.then refreshActivePageIfEnabled return if request.noReply promise.then (result) -> diff --git a/omega-target-chromium-extension/grunt/copy.coffee b/omega-target-chromium-extension/grunt/copy.coffee index f816ed9..cd4afff 100644 --- a/omega-target-chromium-extension/grunt/copy.coffee +++ b/omega-target-chromium-extension/grunt/copy.coffee @@ -11,6 +11,9 @@ module.exports = target_self: src: 'omega_target_chromium_extension.min.js' dest: 'build/js/' + target_popup: + src: 'omega_target_popup.js' + dest: 'build/js/' overlay: expand: true cwd: 'overlay' diff --git a/omega-target-chromium-extension/grunt/watch.coffee b/omega-target-chromium-extension/grunt/watch.coffee index 06a73dc..cafeb37 100644 --- a/omega-target-chromium-extension/grunt/watch.coffee +++ b/omega-target-chromium-extension/grunt/watch.coffee @@ -17,6 +17,9 @@ module.exports = copy_overlay: files: ['overlay/**/*'] tasks: ['copy:overlay'] + copy_target_popup: + files: ['omega_target_popup.js'] + tasks: ['copy:target_popup'] src: files: ['src/**/*.coffee'] tasks: ['coffeelint:src', 'browserify', 'copy:target_self'] diff --git a/omega-target-chromium-extension/omega_target_popup.js b/omega-target-chromium-extension/omega_target_popup.js new file mode 100644 index 0000000..79b3d31 --- /dev/null +++ b/omega-target-chromium-extension/omega_target_popup.js @@ -0,0 +1,81 @@ +function callBackgroundNoReply(method, args, cb) { + chrome.runtime.sendMessage({ + method: method, + args: args, + noReply: true, + refreshActivePage: true, + }); + if (cb) return cb(); +} + +function callBackground(method, args, cb) { + chrome.runtime.sendMessage({ + method: method, + args: args, + }, function(response) { + if (chrome.runtime.lastError != null) + return cb && cb(chrome.runtime.lastError) + if (response.error) return cb && cb(response.error) + return cb && cb(null, response.result) + }); +} + +var requestInfoCallback = null; + +OmegaTargetPopup = { + getState: function (keys, cb) { + var results = {}; + keys.forEach(function(key) { + try { + results[key] = JSON.parse(localStorage['omega.local.' + key]); + } catch (_) { + return null; + } + }); + if (cb) cb(null, results); + }, + applyProfile: function (name, cb) { + callBackgroundNoReply('applyProfile', [name], cb); + }, + openOptions: function (hash, cb) { + var options_url = chrome.extension.getURL('options.html'); + + chrome.tabs.query({ + url: options_url + }, function(tabs) { + if (tabs.length > 0) { + var props = { + active: true + }; + if (hash) { + var url = options_url + hash; + props.url = url; + } + chrome.tabs.update(tabs[0].id, props); + } else { + chrome.tabs.create({ + url: options_url + }); + } + if (cb) return cb(); + }); + }, + getActivePageInfo: function(cb) { + chrome.tabs.query({active: true, lastFocusedWindow: true}, function (tabs) { + if (tabs.length === 0 || !tabs[0].url) return cb(); + var args = {tabId: tabs[0].id, url: tabs[0].url}; + callBackground('getPageInfo', [args], cb) + }); + }, + setDefaultProfile: function(profileName, defaultProfileName, cb) { + callBackgroundNoReply('setDefaultProfile', + [profileName, defaultProfileName], cb); + }, + addTempRule: function(domain, profileName, cb) { + callBackgroundNoReply('addTempRule', [domain, profileName], cb); + }, + openManage: function(domain, profileName, cb) { + chrome.tabs.create({url: 'chrome://extensions/?id=' + chrome.runtime.id}); + }, + getMessage: chrome.i18n.getMessage.bind(chrome.i18n), +}; diff --git a/omega-target-chromium-extension/omega_target_web.coffee b/omega-target-chromium-extension/omega_target_web.coffee index 4a6cf7a..0b88bf0 100644 --- a/omega-target-chromium-extension/omega_target_web.coffee +++ b/omega-target-chromium-extension/omega_target_web.coffee @@ -131,7 +131,7 @@ angular.module('omegaTarget', []).factory 'omegaTarget', ($q) -> connectBackground('tabRequestInfo', args, requestInfoCallback) d.resolve(callBackground('getPageInfo', args)) - return d.promise + return d.promise.then (info) -> if info?.url then info else null refreshActivePage: -> d = $q['defer']() chrome.tabs.query {active: true, lastFocusedWindow: true}, (tabs) -> diff --git a/omega-target-chromium-extension/overlay/manifest.json b/omega-target-chromium-extension/overlay/manifest.json index b4400cc..19d3180 100644 --- a/omega-target-chromium-extension/overlay/manifest.json +++ b/omega-target-chromium-extension/overlay/manifest.json @@ -21,7 +21,7 @@ "32": "img/icons/omega-action-32.png" }, "default_title": "__MSG_manifest_icon_default_title__", - "default_popup": "popup.html" + "default_popup": "popup/index.html" }, "background": { "page": "background.html" diff --git a/omega-target-chromium-extension/src/external_api.coffee b/omega-target-chromium-extension/src/external_api.coffee index 3c7a92e..a080718 100644 --- a/omega-target-chromium-extension/src/external_api.coffee +++ b/omega-target-chromium-extension/src/external_api.coffee @@ -21,7 +21,7 @@ module.exports = class ExternalApi return unless @disabled @options.setProxyNotControllable(null) - chrome.browserAction.setPopup({popup: 'popup.html'}) + chrome.browserAction.setPopup({popup: 'popup/index.html'}) @options.reloadQuickSwitch() @disabled = false @options.clearBadge() @@ -48,7 +48,7 @@ module.exports = class ExternalApi if @knownExts[port.sender.id] >= 32 reason = 'upgrade' @options.setProxyNotControllable reason, {text: 'X', color: '#5ab432'} - chrome.browserAction.setPopup({popup: 'popup.html'}) + chrome.browserAction.setPopup({popup: 'popup/index.html'}) port.postMessage({action: 'state', state: 'disabled'}) when 'enable' @reenable() diff --git a/omega-target-chromium-extension/src/options.coffee b/omega-target-chromium-extension/src/options.coffee index 1375e1a..d34651c 100644 --- a/omega-target-chromium-extension/src/options.coffee +++ b/omega-target-chromium-extension/src/options.coffee @@ -197,7 +197,7 @@ class ChromeOptions extends OmegaTarget.Options if tab.url and tab.url.indexOf('chrome') != 0 chrome.tabs.reload(tab.id) else - chrome.browserAction.setPopup({popup: 'popup.html'}) + chrome.browserAction.setPopup({popup: 'popup/index.html'}) Promise.resolve() setInspect: (settings) -> @@ -329,6 +329,8 @@ class ChromeOptions extends OmegaTarget.Options chrome.tabs.create url: chrome.extension.getURL('options.html') getPageInfo: ({tabId, url}) -> + errorCount = @_requestMonitor.tabInfo[tabId]?.errorCount + result = if errorCount then {errorCount: errorCount} else null getBadge = new Promise (resolve, reject) -> chrome.browserAction.getBadgeText {tabId: tabId}, (result) -> resolve(result) @@ -339,19 +341,21 @@ class ChromeOptions extends OmegaTarget.Options url = inspectUrl else @clearBadge() - return null if not url + return result if not url if url.substr(0, 6) == 'chrome' errorPagePrefix = 'chrome://errorpage/' if url.substr(0, errorPagePrefix.length) == errorPagePrefix url = querystring.parse(url.substr(url.indexOf('?') + 1)).lasturl - return null if not url + return result if not url else - return null + return result domain = OmegaPac.getBaseDomain(Url.parse(url).hostname) + return { url: url domain: domain tempRuleProfileName: @queryTempRule(domain) + errorCount: errorCount } module.exports = ChromeOptions diff --git a/omega-web/grunt/copy.coffee b/omega-web/grunt/copy.coffee index ba0cd18..64f74bc 100644 --- a/omega-web/grunt/copy.coffee +++ b/omega-web/grunt/copy.coffee @@ -12,3 +12,8 @@ module.exports = cwd: 'img' src: ['**/*'] dest: 'build/img/' + popup: + expand: true + cwd: 'src/popup' + src: ['**/*'] + dest: 'build/popup/' diff --git a/omega-web/grunt/watch.coffee b/omega-web/grunt/watch.coffee index 532f26f..f37edaa 100644 --- a/omega-web/grunt/watch.coffee +++ b/omega-web/grunt/watch.coffee @@ -17,6 +17,10 @@ module.exports = files: 'img/**/*' tasks: 'copy:img' + copy_popup: + files: + 'src/popup/**/*' + tasks: 'copy:popup' jade: files: ['src/**/*.jade'] tasks: 'jade' diff --git a/omega-web/src/coffee/popup.coffee b/omega-web/src/coffee/popup.coffee index 40ec0e3..d4a0dd8 100644 --- a/omega-web/src/coffee/popup.coffee +++ b/omega-web/src/coffee/popup.coffee @@ -184,8 +184,20 @@ module.controller 'PopupCtrl', ($scope, $window, $q, omegaTarget, omegaTarget.applyProfile(name).then -> refresh() + $scope.returnToMenu = -> + if location.hash.indexOf('!') >= 0 + location.href = 'popup/index.html' + return + $scope.showConditionForm = false + $scope.showRequestInfo = false + preselectedProfileNameForCondition = 'direct' + if $window.location.hash == '#!requestInfo' + $scope.showRequestInfo = true + else if $window.location.hash == '#!external' + $scope.nameExternal = {open: true} + omegaTarget.state([ 'availableProfiles', 'currentProfileName', 'isSystemProfile', 'validResultProfiles', 'refreshOnProfileChange', 'externalProfile', @@ -257,6 +269,8 @@ module.controller 'PopupCtrl', ($scope, $window, $q, omegaTarget, if $scope.currentTempRuleProfile preselectedProfileNameForCondition = $scope.currentTempRuleProfile $scope.currentDomain = info.domain + if $window.location.hash == '#!addRule' + $scope.prepareConditionForm() $scope.prepareConditionForm = -> currentDomain = $scope.currentDomain diff --git a/omega-web/src/popup.jade b/omega-web/src/popup.jade index 25a0861..5d9807f 100644 --- a/omega-web/src/popup.jade +++ b/omega-web/src/popup.jade @@ -1,6 +1,6 @@ doctype html // - Copyright (C) 2012-2013, The SwitchyOmega Authors. Please see the AUTHORS file + Copyright 2017 The SwitchyOmega Authors. Please see the AUTHORS file for details. This file is part of SwitchyOmega. @@ -111,7 +111,7 @@ html(lang='en' ng-app='omegaPopup' ng-controller='PopupCtrl' ng-csp) div(omega-profile-select='validResultProfiles' ng-model='rule.profileName' disp-name='dispNameFilter' options='availableProfiles') div.condition-controls - button.btn.btn-default(type='button' ng-click='showConditionForm = false') + button.btn.btn-default(type='button' ng-click='returnToMenu()') | {{'dialog_cancel' | tr}} button.btn.btn-primary(type='submit' ng-disabled='conditionForm.$invalid') {{'popup_addCondition' | tr}} div.proxy-not-controllable(ng-show='proxyNotControllable') @@ -148,7 +148,7 @@ html(lang='en' ng-app='omegaPopup' ng-controller='PopupCtrl' ng-csp) p.help-block(ng-show='!currentProfileCanAddRule') | {{'popup_requestErrorCannotAddCondition' | tr}} div.condition-controls - button.btn.btn-default(type='button' ng-click='showRequestInfo = false') + button.btn.btn-default(type='button' ng-click='returnToMenu()') | {{'dialog_cancel' | tr}} button.btn.btn-primary(type='submit' ng-show='!!currentProfileCanAddRule') {{'popup_addCondition' | tr}} button.btn.btn-default.pull-right(type='button' ng-show='!currentProfileCanAddRule' diff --git a/omega-web/src/popup/css/dialog.css b/omega-web/src/popup/css/dialog.css new file mode 100644 index 0000000..1d634f2 --- /dev/null +++ b/omega-web/src/popup/css/dialog.css @@ -0,0 +1,97 @@ +/*! + * Copyright 2017 The SwitchyOmega Authors. Please see the AUTHORS file + * for details. + * Based on Bootstrap v3.3.2 (http://getbootstrap.com) + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) +*/ + +/* Dialog */ + +body, html { + margin: 0; + padding: 0; +} + +p { + margin: 0 0 1em 0; +} + +.om-dialog { + min-width: 400px; + padding: 10px 10px; + font-size: 14px; +} + + .om-text-danger { + color: #a94442; + } + + .om-dialog-help { + display: block; + margin-top: 5px; + margin-bottom: 10px; + color: #737373; + } + + .om-dialog-controls { + margin-bottom: 0; + } + + .om-dialog-controls .om-btn-primary { + float: right; + } + +/* Button */ + +.om-btn { + display: inline-block; + padding: 6px 12px; + margin-bottom: 0; + font-size: 14px; + font-weight: 400; + line-height: 1.42857143; + text-align: center; + white-space: nowrap; + vertical-align: middle; + -ms-touch-action: manipulation; + touch-action: manipulation; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + background-image: none; + border: 1px solid transparent; + border-radius: 4px +} + +.om-btn.active, .om-btn:active { + background-image: none; + outline: 0; + -webkit-box-shadow: inset 0 3px 5px rgba(0,0,0,.125); + box-shadow: inset 0 3px 5px rgba(0,0,0,.125); +} + +.om-btn-default { + color: #333; + background-color: #fff; + border-color: #ccc; +} + +.om-btn-default:hover { + background-color: #e6e6e6; + border-color: #adadad; +} + +.om-btn-primary { + color: #fff; + background-color: #337ab7; + border-color: #2e6da4; +} + +.om-btn-primary:hover { + color: #fff; + background-color: #286090; + border-color: #204d74; +} diff --git a/omega-web/src/popup/css/index.css b/omega-web/src/popup/css/index.css new file mode 100644 index 0000000..ca63909 --- /dev/null +++ b/omega-web/src/popup/css/index.css @@ -0,0 +1,220 @@ +/*! + * Copyright 2017 The SwitchyOmega Authors. Please see the AUTHORS file + * for details. + * Based on Bootstrap v3.3.2 (http://getbootstrap.com) + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) +*/ + +/* Layout */ + +html, body { + font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; + font-size: 14px; + padding: 0; + margin: 0; +} + +body { + min-width: 12em; +} + +.om-hidden { + display: none !important; +} + +/* Menu */ + +.om-nav { + list-style: none; + padding: 0; + margin: 0; +} + + .om-nav-item { + display: block; + margin: 2px 0; + } + + .om-nav-item > a > .glyphicon { + margin-right: 8px; + } + + .om-nav-item > a { + display: block; + padding: 5px 25px 5px 8px; + border-radius: 4px; + line-height: 1.5em; + font-size: 1em; + color: #337ab7; + text-decoration: none; + white-space: nowrap; + cursor: pointer; + } + .om-nav-item > a:hover { + text-decoration: none; + background-color: #eee; + } + .om-nav-item > a:hover { + color: #23527c; + } + .om-nav-item.om-effective > a { + background-color: #d9edf7; + } + .om-nav-item.om-active > a { + color: #fff; + background-color: #337ab7; + } + + .om-divider { + height: 1px; + overflow: hidden; + background-color: #E5E5E5; + } + + .om-reqinfo { + background-color: #fcf8e3; + } + + .glyphicon-warning-sign { + color: #8a6d3b; + } + +/* Dropdown */ + +.om-dropdown { + display: none; + list-style: none; + padding: 5px 0; + margin: 0 5px !important; + border: 1px solid rgba(0,0,0,.15); + border-radius: 4px; + box-shadow: 0 6px 12px rgba(0,0,0,.175); +} + +.om-open .om-dropdown { + display: block; +} + +.om-dropdown .om-nav-item { + margin: 0; +} + +.om-dropdown .om-nav-item > a { + padding: 3px 20px; + line-height: 1.3em; + margin: 0; +} + +.om-caret { + display: inline-block; + width: 0; + height: 0; + margin-left: 2px; + vertical-align: middle; + border-top: 4px solid; + border-right: 4px solid transparent; + border-left: 4px solid transparent; +} + +.om-virtual-profile-icon { + border: dotted 1px; + margin: -1px; +} + +/* Default Edit */ + +.om-has-edit { + padding-right: 32px; + position: relative; +} + + .om-edit-toggle { + background-color: #fff; + border: 1px solid #ccc; + color: #337ab7; + display: inline-block; + margin: -5px 0; + text-align: center; + padding: 5px 8px 3px; + position: absolute; + right: 0; + } + + .om-edit-toggle:hover { + background-color: #e6e6e6; + border-color: #adadad; + } + +/* Keyboard */ + +.om-keyboard-help { + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; + border: solid 1px #000; + border-radius: 2px; + display: inline-block; + color: #000; + box-shadow: 1px 1px; + width: 1em; + height: 1em; + line-height: 1em; + text-align: center; + margin-top: -3px; +} + +/* Glyphicons */ + +@font-face { + font-family: 'Glyphicons Halflings'; + src: url(../../../lib/bootstrap/fonts/glyphicons-halflings-regular.eot); + src: url(../../../lib/bootstrap/fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../../../lib/bootstrap/fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../../../lib/bootstrap/fonts/glyphicons-halflings-regular.woff) format('woff'),url(../../../lib/bootstrap/fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../../../lib/bootstrap/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg') +} + +.glyphicon { + position: relative; + top: 1px; + display: inline-block; + font-family: 'Glyphicons Halflings'; + font-style: normal; + font-weight: 400; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.glyphicon-transfer:before { + content: "\e178"; +} +.glyphicon-off:before { + content: "\e017"; +} +.glyphicon-warning-sign:before { + content: "\e107"; +} +.glyphicon-file:before { + content: "\e022" +} +.glyphicon-globe:before { + content: "\e135" +} +.glyphicon-question-sign:before { + content: "\e085" +} +.glyphicon-list:before { + content: "\e056" +} +.glyphicon-retweet:before { + content: "\e115" +} +.glyphicon-plus:before { + content: "\2b" +} +.glyphicon-filter:before { + content: "\e138" +} +.glyphicon-wrench:before { + content: "\e136" +} +.glyphicon-chevron-down:before { + content: "\e114"; +} diff --git a/omega-web/src/popup/index.html b/omega-web/src/popup/index.html new file mode 100644 index 0000000..9182af8 --- /dev/null +++ b/omega-web/src/popup/index.html @@ -0,0 +1,56 @@ + + +
+ ++ + +
+