Add a mini-popup page with the menu only.

This allows the popup to load faster for most cases. If advanced
features are used, the user will be redirected to the full popup page.
This commit is contained in:
FelisCatus 2017-03-14 00:25:46 -04:00
parent bdb24d9c88
commit 9d71c91634
23 changed files with 1068 additions and 11 deletions

View File

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

View File

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

View File

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

View File

@ -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),
};

View File

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

View File

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

View File

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

View File

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

View File

@ -12,3 +12,8 @@ module.exports =
cwd: 'img'
src: ['**/*']
dest: 'build/img/'
popup:
expand: true
cwd: 'src/popup'
src: ['**/*']
dest: 'build/popup/'

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,56 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>SwitchyOmega Popup</title>
<link rel="stylesheet" href="css/index.css">
</head>
<body>
<ul class="om-nav">
<li class="om-nav-item" id="js-profile-tpl">
<a href="#" id="js-direct" role="button">
<span class="glyphicon glyphicon-transfer" style="color: #aaa;"></span>
<span class="om-profile-name"></span>
</a>
</li>
<li class="om-nav-item">
<a href="#" id="js-system" role="button">
<span class="glyphicon glyphicon-off" style="color: #000;"></span>
<span class="om-profile-name"></span>
</a>
</li>
<li class="om-nav-item om-reqinfo om-hidden">
<a href="../popup.html#!requestInfo" id="js-reqinfo" role="button">
<span class="glyphicon glyphicon-warning-sign"></span>
<span class="om-reqinfo-text"></span>
</a>
</li>
<li class="om-divider"></li>
<li class="om-divider" id="js-profiles-end"></li>
<li class="om-nav-item om-nav-addrule">
<a href="../popup.html#!addRule" id="js-addrule" role="button">
<span class="glyphicon glyphicon-plus"></span>
<span id="js-addrule-label"></span>
</a>
</li>
<li class="om-nav-item om-nav-temprule om-has-dropdown">
<a href="#" id="js-temprule" role="button">
<span class="glyphicon glyphicon-filter"></span>
<span>
<span class="om-page-domain"></span>
<span class="om-caret"></span>
</span>
</a>
</li>
<li class="om-divider"></li>
<li class="om-nav-item">
<a href="#" id="js-option" role="button">
<span class="glyphicon glyphicon-wrench"></span>
<span id="js-option-label"></span>
</a>
</li>
</ul>
<script src="../../lib/script.js/script.min.js"></script>
<script src="js/loader.js"></script>
</body>
</html>

View File

@ -0,0 +1,10 @@
$script.ready('om-page-info', function() {
document.querySelector('#js-direct .om-profile-name').textContent =
OmegaTargetPopup.getMessage('profile_direct');
document.querySelector('#js-system .om-profile-name').textContent =
OmegaTargetPopup.getMessage('profile_system');
document.querySelector('#js-addrule-label').textContent =
OmegaTargetPopup.getMessage('popup_addCondition');
document.querySelector('#js-option-label').textContent =
OmegaTargetPopup.getMessage('popup_showOptions');
});

View File

@ -0,0 +1,49 @@
(function() {
handleClick('js-option', showOptions);
handleClick('js-temprule', showTempRuleDropdown);
handleClick('js-direct', applyProfile.bind(this, 'direct'));
handleClick('js-system', applyProfile.bind(this, 'system'));
OmegaPopup.addTempRule = addTempRule;
OmegaPopup.setDefaultProfile = setDefaultProfile;
OmegaPopup.applyProfile = applyProfile;
return;
function handleClick(id, handler) {
document.getElementById(id).addEventListener('click', handler, false);
}
function closePopup() {
window.close();
}
function showOptions() {
$script.ready('om-target', function() {
OmegaTargetPopup.openOptions(null, closePopup);
});
}
function applyProfile(profileName) {
$script.ready('om-target', function() {
OmegaTargetPopup.applyProfile(profileName, closePopup);
});
}
function setDefaultProfile(profileName, defaultProfileName) {
$script.ready('om-target', function() {
OmegaTargetPopup.setDefaultProfile(profileName, defaultProfileName,
closePopup);
});
}
function addTempRule(domain, profileName) {
$script.ready('om-target', function() {
OmegaTargetPopup.addTempRule(domain, profileName, closePopup);
});
}
function showTempRuleDropdown() {
$script.ready('om-dropdowns', function() {
OmegaPopup.showTempRuleDropdown();
});
}
})();

View File

@ -0,0 +1,129 @@
(function() {
var keyHandler = {
38: moveUp, // Up
40: moveDown, // Down
37: closeDropdown, // Left
39: openDropdown, // Right
72: closeDropdown, // h
74: moveUp, // j
75: moveDown, // k
76: openDropdown, // l
191: showKeyboardHelp, // /
63: showKeyboardHelp, // ?
48: 'js-direct', // 0
83: 'js-system', // s
69: 'js-external', // e
65: 'js-addrule', // a
187: 'js-addrule', // +, =
84: 'js-temprule', // t
79: 'js-option', // o
82: 'js-reqinfo', // r
};
for (i = 1; i <= 9; i++) {
keyHandler[48 + i] = 'js-profile-' + i;
}
var walker;
return init();
function init() {
walker = document.createTreeWalker(
document.querySelector('.om-nav'),
NodeFilter.SHOW_ELEMENT,
{acceptNode: tabbableElementsOnly}
);
window.addEventListener('keydown', function(e) {
var handler = keyHandler[e.keyCode];
if (!handler) console.log(e.keyCode);
if (handler == null) return;
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
if (typeof handler === 'string') {
clickById(handler);
} else {
handler();
}
});
}
function tabbableElementsOnly(node) {
if (node.classList.contains('om-hidden')) {
return NodeFilter.FILTER_REJECT;
} else if (node.classList.contains('om-dropdown') &&
!node.parentElement.classList.contains('om-open')) {
return NodeFilter.FILTER_REJECT;
} else if (node.tabIndex >= 0) {
return NodeFilter.FILTER_ACCEPT;
} else {
return NodeFilter.FILTER_SKIP;
}
}
function moveUp() {
walker.currentNode = document.activeElement;
var result = null;
if (walker.currentNode) {
result = walker.previousNode();
}
if (!result) {
walker.currentNode = walker.root.lastElementChild;
walker.previousNode();
walker.nextNode();
}
walker.currentNode.focus();
}
function moveDown() {
walker.currentNode = document.activeElement;
var result = null;
if (walker.currentNode) {
result = walker.nextNode();
}
if (!result) {
walker.currentNode = walker.root;
walker.nextNode();
}
walker.currentNode.focus();
}
function openDropdown() {
var container = document.querySelector('.om-open');
if (container) {
// Existing dropdown. Just move to it.
container.querySelector('a').focus();
return;
}
var selectedItem = document.activeElement;
if (!selectedItem || !selectedItem.parentElement) return;
if (selectedItem.parentElement.classList.contains('om-has-dropdown')) {
var toggle = selectedItem.querySelector('.om-edit-toggle');
if (toggle) {
toggle.click();
} else {
selectedItem.click();
}
}
}
function closeDropdown() {
var container = document.querySelector('.om-open');
if (container) {
container.classList.remove('om-open');
container.querySelector('a').focus();
}
}
function showKeyboardHelp() {
$script('js/keyboard_help.js');
}
function clickById(id) {
var element = document.getElementById(id);
if (element) element.click();
}
})();

View File

@ -0,0 +1,32 @@
(function() {
var keyForId = {
'js-direct': '0',
'js-system': 'S',
'js-external': 'E',
'js-addrule': 'A',
'js-temprule': 'T',
'js-option': 'O',
'js-reqinfo': 'R'
}
Object.keys(keyForId).forEach(function (id) {
showHelp(id, keyForId[id]);
});
for (var i = 1; i <= 9; i++) {
showHelp('js-profile-' + i, '' + i);
}
return;
function showHelp(id, key) {
var element = document.getElementById(id);
if (!element) return;
if (!element.querySelector('.om-keyboard-help')) {
var span = document.createElement('span');
span.classList.add('om-keyboard-help');
span.textContent = key;
var reference = element.querySelector('.glyphicon');
reference.parentNode.insertBefore(span, reference.nextSibling);
}
}
})();

View File

@ -0,0 +1,21 @@
window.OmegaPopup = {};
$script(['js/index.js', 'js/profiles.js', 'js/keyboard.js'], 'om-main');
$script(['js/i18n.js']);
$script('../js/omega_target_popup.js', 'om-target', function() {
OmegaTargetPopup.getActivePageInfo(function(err, info) {
window.OmegaPopup.pageInfo = info;
$script.done('om-page-info');
});
OmegaTargetPopup.getState([
'availableProfiles',
'currentProfileName',
'validResultProfiles',
'isSystemProfile',
'currentProfileCanAddRule',
'proxyNotControllable',
'externalProfile',
], function(err, state) {
window.OmegaPopup.state = state;
$script.done('om-state');
});
});

View File

@ -0,0 +1,272 @@
(function() {
$script.ready('om-state', updateMenuByState);
$script.ready('om-page-info', updateMenuByPageInfo);
$script.ready(['om-state', 'om-page-info'], updateMenuByStateAndPageInfo);
var profileTemplate = document.getElementById('js-profile-tpl')
.cloneNode(true);
profileTemplate.classList.remove('om-profile-tpl');
var iconForProfileType = {
'DirectProfile': 'glyphicon-transfer',
'SystemProfile': 'glyphicon-off',
'AutoDetectProfile': 'glyphicon-file',
'FixedProfile': 'glyphicon-globe',
'PacProfile': 'glyphicon-file',
'VirtualProfile': 'glyphicon-question-sign',
'RuleListProfile': 'glyphicon-list',
'SwitchProfile': 'glyphicon-retweet',
};
var orderForType = {
'FixedProfile': -2000,
'PacProfile': -1000,
'VirtualProfile': 1000,
'SwitchProfile': 2000,
'RuleListProfile': 3000,
};
return;
function updateMenuByState() {
var state = OmegaPopup.state;
if (state.proxyNotControllable) {
location.href = 'proxy_not_controllable.html';
return;
}
addProfilesItems(state);
updateOtherItems(state);
}
function compareProfile(a, b) {
var diff;
diff = (orderForType[a.profileType] | 0) - (orderForType[b.profileType] | 0);
if (diff !== 0) {
return diff;
}
if (a.name === b.name) {
return 0;
} else if (a.name < b.name) {
return -1;
} else {
return 1;
}
}
function updateMenuByPageInfo() {
var info = OmegaPopup.pageInfo;
if (info && info.errorCount > 0) {
document.querySelector('.om-reqinfo').classList.remove('om-hidden');
var text = OmegaTargetPopup.getMessage('popup_requestErrorCount',
[info.errorCount]);
document.querySelector('.om-reqinfo-text').textContent = text;
}
}
function updateMenuByStateAndPageInfo() {
var state = OmegaPopup.state;
var info = OmegaPopup.pageInfo;
if (state.externalProfile && (!info || !info.errorCount)) {
showMenuForExternalProfile(state);
}
if (!info || !info.url) return updateOtherItems(null);
document.querySelector('.om-page-domain').textContent = info.domain;
OmegaPopup.showTempRuleDropdown = showTempRuleDropdown;
$script.done('om-dropdowns');
}
function showMenuForExternalProfile(state) {
var profile = state.externalProfile;
profile.name = OmegaTargetPopup.getMessage('popup_externalProfile')
var profileDisp = createMenuItemForProfile(profile);
var link = profileDisp.querySelector('a');
link.id = 'js-external';
link.addEventListener('click', function() {
location.href = '../popup.html#!external';
});
if (state.currentProfileName === '') {
profileDisp.classList.add('om-effective');
}
var reqInfo = document.querySelector('.om-reqinfo');
reqInfo.parentElement.insertBefore(profileDisp, reqInfo);
}
function showTempRuleDropdown() {
var tempRuleItem = document.querySelector('.om-nav-temprule');
toggleDropdown(tempRuleItem, createTempRuleDropdown);
document.getElementById('js-temprule').focus();
}
function updateOtherItems(state) {
var hasValidResults = state && state.validResultProfiles &&
state.validResultProfiles.length;
if (!hasValidResults || !state.currentProfileCanAddRule) {
document.querySelector('.om-nav-addrule').classList.add('om-hidden');
document.getElementById('js-addrule').href = '#';
}
if (!hasValidResults) {
document.querySelector('.om-nav-temprule').classList.add('om-hidden');
document.getElementById('js-temprule').href = '#';
}
}
var isValidResultProfile = {};
validResultProfiles.forEach(function(name) {
isValidResultProfile['+' + name] = true;
});
function addProfilesItems(state) {
var currentProfileClass = 'om-active';
if (state.isSystemProfile) {
document.getElementById('js-system').parentElement
.classList.add('om-active');
currentProfileClass = 'om-effective';
}
if (state.currentProfileName === 'direct') {
document.getElementById('js-direct').parentElement
.classList.add(currentProfileClass);
}
var profilesEnd = document.getElementById('js-profiles-end');
var profilesContainer = profilesEnd.parentElement;
var profileCount = 0;
var charCodeUnderscore = '_'.charCodeAt(0)
var profiles = Object.keys(state.availableProfiles).map(function(key) {
return state.availableProfiles[key];
}).sort(compareProfile);
profiles.forEach(function(profile) {
if (profile.builtin) return;
if (profile.name.charCodeAt(0) === charCodeUnderscore) return;
profileCount++;
var profileDisp = createMenuItemForProfile(profile,
state.availableProfiles);
var link = profileDisp.querySelector('a');
link.id = 'js-profile-' + profileCount;
link.addEventListener('click', function() {
$script.ready('om-main', function() {
OmegaPopup.applyProfile(profile.name);
});
});
if (profile.name === state.currentProfileName) {
profileDisp.classList.add(currentProfileClass);
}
if (profile.validResultProfiles) {
profileDisp.classList.add('om-has-dropdown');
link.classList.add('om-has-edit');
var toggle = document.createElement('div');
toggle.classList.add('om-edit-toggle');
var icon = document.createElement('span');
icon.setAttribute('class', 'glyphicon glyphicon-chevron-down');
toggle.appendChild(icon);
toggle.addEventListener('click', function(e) {
e.stopPropagation();
e.preventDefault();
toggleDropdown(profileDisp,
createDefaultProfileDropdown.bind(profileDisp, profile));
});
link.appendChild(toggle);
}
profilesContainer.insertBefore(profileDisp, profilesEnd);
});
}
function createMenuItemForProfile(profile, profiles) {
var profileDisp = profileTemplate.cloneNode(true);
var text = profile.name;
if (profile.defaultProfileName) {
text += ' [' + profile.defaultProfileName + ']';
}
profileDisp.querySelector('.om-profile-name').textContent = text;
var targetProfile = profile;
if (profile.profileType === 'VirtualProfile') {
targetProfile = profiles['+' + profile.defaultProfileName];
}
var iconClass = iconForProfileType[targetProfile.profileType];
var icon = profileDisp.querySelector('.glyphicon');
icon.setAttribute('class', 'glyphicon ' + iconClass)
icon.style.color = targetProfile.color;
if (targetProfile !== profile) {
icon.classList.add('om-virtual-profile-icon');
}
return profileDisp;
}
function toggleDropdown(container, createDropdown) {
if (!container.classList.contains('om-dropdown-loaded')) {
var dropdown = createDropdown();
dropdown.classList.add('om-dropdown');
container.appendChild(dropdown);
container.classList.add('om-dropdown-loaded');
}
if (container.classList.contains('om-open')) {
container.classList.remove('om-open');
} else {
container.classList.add('om-open');
}
}
function createTempRuleDropdown() {
var ul = document.createElement('ul');
var state = OmegaPopup.state;
var pageInfo = OmegaPopup.pageInfo;
var profiles = state.validResultProfiles.map(function(name) {
return state.availableProfiles['+' + name];
}).sort(compareProfile);
profiles.forEach(function(profile) {
if (profile.name.indexOf('__') === 0) return;
if ((profile.name === OmegaPopup.state.currentProfileName) &&
(!pageInfo.tempRuleProfileName) &&
(state.validResultProfiles.length > 1)
) return;
var li = createMenuItemForProfile(profile, state.availableProfiles);
var link = li.querySelector('a');
link.addEventListener('click', function() {
$script.ready('om-main', function() {
OmegaPopup.addTempRule(pageInfo.domain, profile.name);
});
});
if (profile.name === pageInfo.tempRuleProfileName) {
li.classList.add('om-active');
}
ul.appendChild(li);
});
return ul;
}
function createDefaultProfileDropdown(profile) {
var ul = document.createElement('ul');
var state = OmegaPopup.state;
var profiles = profile.validResultProfiles.map(function(name) {
return state.availableProfiles['+' + name];
}).sort(compareProfile);
profiles.forEach(function(resultProfile) {
if (resultProfile.name.indexOf('__') === 0) return;
if ((resultProfile === profile.currentProfileName) &&
(profile.validResultProfiles.length > 1)
) return;
var li = createMenuItemForProfile(resultProfile, state.availableProfiles);
var link = li.querySelector('a');
link.addEventListener('click', function() {
$script.ready('om-main', function() {
OmegaPopup.setDefaultProfile(profile.name, resultProfile.name);
});
});
if (resultProfile.name === profile.currentProfileName) {
li.classList.add('om-active');
}
ul.appendChild(li);
});
return ul;
}
})();

View File

@ -0,0 +1,29 @@
(function() {
var closeButton = document.getElementById('js-close');
closeButton.addEventListener('click', window.close.bind(window), false);
var manageButton = document.getElementById('js-manage-ext');
manageButton.addEventListener('click',
OmegaTargetPopup.openManage.bind(OmegaTargetPopup), false);
closeButton.textContent = OmegaTargetPopup.getMessage('dialog_cancel');
manageButton.textContent = OmegaTargetPopup.getMessage(
'popup_proxyNotControllableManage');
OmegaTargetPopup.getState([
'proxyNotControllable',
], function(err, state) {
var reason = state.proxyNotControllable;
var messageElement = document.getElementById('js-nc-text');
var detailsElement = document.getElementById('js-nc-details');
messageElement.textContent = OmegaTargetPopup.getMessage(
'popup_proxyNotControllable_' + reason);
var detailsMessage = OmegaTargetPopup.getMessage(
'popup_proxyNotControllableDetails_' + reason);
if (!detailsMessage) detailsMessage = OmegaTargetPopup.getMessage(
'popup_proxyNotControllableDetails');
detailsElement.textContent = detailsMessage;
});
})();

View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>SwitchyOmega Popup</title>
<link rel="stylesheet" href="css/dialog.css">
</head>
<body>
<div class="om-dialog">
<p class="om-text-danger" id="js-nc-text"></p>
<p class="om-dialog-help" id="js-nc-details"></p>
<p class="om-dialog-controls">
<button id="js-close" class="om-btn om-btn-default"></button>
<button id="js-manage-ext" class="om-btn om-btn-primary"></button>
</p>
</div>
<script src="../js/omega_target_popup.js"></script>
<script src="js/proxy_not_controllable.js"></script>
</body>
</html>