Change UI of exceptions to datalist

This commit is contained in:
Ilya Ig. Petrov 2017-01-30 12:04:07 +00:00
parent d022220303
commit 400771eff4
3 changed files with 195 additions and 177 deletions

View File

@ -0,0 +1,3 @@
https://chromereleases.googleblog.com/search/label/Stable%20updates
https://www.chromestatus.com
https://www.youtube.com/user/ChromeDevelopers/videos

View File

@ -41,6 +41,9 @@
padding-left: 1.4em; padding-left: 1.4em;
padding-right: 1.4em; padding-right: 1.4em;
} }
.horizontal-list li {
display: inline-block;
}
/* NOT CONTROLLED */ /* NOT CONTROLLED */
@ -67,7 +70,7 @@
display: none; display: none;
} }
.acc-padded { .acc-padded {
padding: 0.6em 0 1em 0.5em; padding: 0.6em 0.5em 1em;
} }
/* HIDE */ /* HIDE */
@ -96,10 +99,7 @@
} }
.nav-labels { .nav-labels {
text-align: center; text-align: center;
--blue-bg: DodgerBlue; --blue-bg: dodgerblue;
}
.nav-labels li {
display: inline-block;
} }
.nav-labels li label { .nav-labels li label {
display: inline-block; display: inline-block;
@ -259,49 +259,27 @@
/* TAB_3 EXCEPTIONS */ /* TAB_3 EXCEPTIONS */
#right-flexed-editor { #exc-editor {
flex-grow: 99;
max-height: 100%;
border: 1px solid var(--border-color);
width: 100%;
display: flex;
flex-direction: column;
}
#right-flexed-editor > * {
width: 100%;
}
#except-editor {
border-radius: 0 !important; border-radius: 0 !important;
border: none; border: none !important;
border-bottom: 1px solid var(--border-color); border-bottom: 1px solid var(--ribbon-color) !important;
// I don't understand this three, but they have effect.
max-height: 1.6em !important; max-height: 1.6em !important;
min-height: 1.6em !important; min-height: 1.6em !important;
height: 1em !important;
flex-grow: 99;
width: 100% !important;
} }
#bottom-flexed-editor { #exc-radio {
flex-grow: 99; display: flex;
position: relative; justify-content: space-around;
} }
[name="if-proxy-this-site"]:checked + label {
select#exceptions-select { font-weight: bold;
color: black; }
background: transparent; #exc-editor.if-yes {
border-radius: 0; background-color: lightgreen;
box-shadow: none; }
text-shadow: none; #exc-editor.if-no {
padding: 0; background-color: pink;
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 100%;
border: none !important;
} }
option.if-proxied { option.if-proxied {
@ -311,21 +289,6 @@
color: red; color: red;
} }
#exc-flex-container {
position: relative;
display: flex;
/* Fixes multi-select bug
when its border is rendered below
its scrollbar. */
--border-color: var(--default-grey);
}
#exc-flex-container > * {
flex-grow: 1;
padding: 0;
margin: 0;
}
/* CONTROL RAW = BUTTON + LINK */ /* CONTROL RAW = BUTTON + LINK */
.control-row { .control-row {
@ -357,7 +320,7 @@
<input type="radio" name="accordion" class="off" id="acc-mods"/> <input type="radio" name="accordion" class="off" id="acc-mods"/>
<input type="radio" name="accordion" class="off" id="acc-ntf"/> <input type="radio" name="accordion" class="off" id="acc-ntf"/>
<section class="nav-labels hidden-for-options-page"> <section class="nav-labels horizontal-list hidden-for-options-page">
<ul> <ul>
<li><label for="acc-pac" class="nav-label">PAC-скрипт</label></li> <li><label for="acc-pac" class="nav-label">PAC-скрипт</label></li>
<li><label for="acc-mods" class="nav-label">Модификаторы</label></li> <li><label for="acc-mods" class="nav-label">Модификаторы</label></li>
@ -384,22 +347,18 @@
<section data-for="acc-exc" class="hideable"> <section data-for="acc-exc" class="hideable">
<header>Проксировать этот сайт?</header>
<div class="acc-padded" id="exc-flex-container">
<ul style="padding-right: 1em" id="exc-radio"> <div style="display: flex; justify-content: space-around;">
<span>Проксировать</span>
<input placeholder="*.example.com" list="exc-list" name="browser" id="exc-editor"/>?
<datalist id="exc-list"></datalist>
</div>
<ol class="acc-padded horizontal-list" id="exc-radio">
<li><input id="this-auto" type="radio" checked name="if-proxy-this-site"/> <label for="this-auto">🔄&#xFE0E; авто</label></li> <li><input id="this-auto" type="radio" checked name="if-proxy-this-site"/> <label for="this-auto">🔄&#xFE0E; авто</label></li>
<li><input id="this-yes" type="radio" name="if-proxy-this-site"/> <label for="this-yes">&nbsp;да</label></li> <li><input id="this-yes" type="radio" name="if-proxy-this-site"/> <label for="this-yes">&nbsp;да</label></li>
<li><input id="this-no" type="radio" name="if-proxy-this-site"/> <label for="this-no">&nbsp;нет</label></li> <li><input id="this-no" type="radio" name="if-proxy-this-site"/> <label for="this-no">&nbsp;нет</label></li>
<li><a href>Весь список</a></li> </ol>
</ul>
<div id="right-flexed-editor">
<input type="text" placeholder="example.com" id="except-editor"/>
<div id="bottom-flexed-editor">
<select multiple id="exceptions-select"></select>
</div>
</div>
</div>
</section> </section>
<section data-for="acc-mods" class="hideable"> <section data-for="acc-mods" class="hideable">

View File

@ -256,79 +256,12 @@ chrome.runtime.getBackgroundPage( (backgroundPage) =>
{ {
const excEditor = document.getElementById('except-editor'); const excEditor = document.getElementById('exc-editor');
if (currentTab && !currentTab.url.startsWith('chrome')) { if (currentTab && !currentTab.url.startsWith('chrome')) {
excEditor.value = new URL(currentTab.url).hostname; excEditor.value = new URL(currentTab.url).hostname;
} }
const excSelect = document.getElementById('exceptions-select');
excEditor.onkeyup = function() {
this.value = this.value.trim();
for(const opt of excSelect.options) {
let commonChars = 0;
for( const i in this.value ) {
if (this.value.charAt(i) !== opt.value.charAt(i)) {
break;
}
++commonChars;
}
opt.style.order = commonChars;
}
return true;
};
const thisYes = document.getElementById('this-yes');
const thisNo = document.getElementById('this-no');
const ifProxiedClass = 'if-proxied';
excSelect.onclick = function(event) {
// Only one item may be selecte at a time.
// Spread op is used to fight weird bug with iterator.
for(const sopt of [...this.selectedOptions]) {
sopt.selected = false;
}
const opt = event.target;
opt.selected = true;
if (opt.classList.contains(ifProxiedClass)) {
thisYes.checked = true;
} else {
thisNo.checked = true;
}
excEditor.value = opt.value.trim();
};
const addOption = function addOption(host, ifProxy) {
const opt = document.createElement('option');
opt.text = host;
if(ifProxy) {
opt.classList.add(ifProxiedClass);
};
const editorHost = excEditor.value.trim();
if (host === editorHost) {
excSelect.insertBefore( opt, excSelect.firstChild );
opt.click();
} else {
excSelect.add(opt);
}
}
{ // Populate select box.
const pacMods = pacKitchen.getPacMods();
for(const host of Object.keys(pacMods.exceptions || {}).sort()) {
addOption(host, pacMods.exceptions[host]);
}
}
const validateHost = function validateHost(host) { const validateHost = function validateHost(host) {
const ValidHostnameRegex = /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/; const ValidHostnameRegex = /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/;
@ -340,30 +273,165 @@ chrome.runtime.getBackgroundPage( (backgroundPage) =>
}; };
const excPrefix = '*.';
const prefRe = new RegExp('^(\\s*\\*\\.?)?');
const ifProxyHtml = '✔';
const addOption = function addOption(host, ifProxy) {
const opt = document.createElement('option');
opt.value = excPrefix + host;
opt.dataset.host = host;
opt.innerHTML = ifProxy ? ifProxyHtml : '✘';
const editorHost = excEditor.value.trim();
if (host === editorHost) {
excList.insertBefore( opt, excList.firstChild );
} else {
excList.appendChild(opt);
}
};
const excList = document.getElementById('exc-list');
const getExactOpts = (_host) => {
const _nakedHost = _host.replace(prefRe, '');
return [].filter.call(
excList.childNodes,
(opt) => opt.dataset.host === _nakedHost
);
};
const thisYes = document.getElementById('this-yes');
const thisNo = document.getElementById('this-no');
const thisAuto = document.getElementById('this-auto');
const yesClass = 'if-yes';
const noClass = 'if-no';
function moveCursorIfNeeded() {
const nu = excEditor.dataset.moveCursorTo;
if(nu !== undefined) {
excEditor.setSelectionRange(nu, nu);
delete excEditor.dataset.moveCursorTo;
}
}
excEditor.onkeydown = function(event) {
console.log('DOWN', event);
moveCursorIfNeeded();
const start = this.selectionStart;
const end = this.selectionEnd;
if (start < 2 && event.key.length === 1) {
this.setSelectionRange(2, end < 2 ? 2 : end);
}
if(event.key === 'Enter') {
// Hide all non-exact matches.
alert(12);
}
return true;
};
excEditor.oninput = function(event) {
console.log('INPUT')
const _host = this.value;
const prefixedHost = this.value.replace(prefRe, excPrefix);
const setInputValue = (newValue) => {
const nu = this.selectionStart + newValue.length - this.value.length;
this.value = newValue;
excEditor.dataset.moveCursorTo = nu;
window.setTimeout(moveCursorIfNeeded, 0);
}
setInputValue(prefixedHost);
const _nakedHost = _host.trim().replace(prefRe, '');
thisAuto.checked = true;
const toDefault = (opt) => opt.value = excPrefix + opt.dataset.host;;
const delim = ' | ';
let exactOpt = false;
const ifLineSelected = _host.includes(delim);
excList.childNodes.forEach(
(opt) => {
const ifExactMatch = opt.dataset.host === _nakedHost || opt.value === _host;
if (ifExactMatch) {
exactOpt = opt;
return;
}
toDefault(opt);
const ifCommonPrefix = opt.dataset.host.startsWith(_nakedHost);
if (ifCommonPrefix) {
opt.value = prefixedHost + delim + '^' + opt.dataset.host;
return;
}
const ifCommonSuffix = opt.dataset.host.endsWith(_nakedHost);
if (ifCommonSuffix) {
opt.value = this.value + delim + opt.dataset.host + '$';
}
}
);
this.classList.remove(noClass, yesClass);
if (exactOpt) {
console.log('EXACT', exactOpt);
//excList.childNodes.forEach( (opt) => opt.value = false );
setInputValue(toDefault(exactOpt));
if (ifLineSelected) {
// Hide all.
excList.childNodes.forEach( (opt) => opt.value = false );
} else {
// Hide exact.
exactOpt.value = false;
}
if(exactOpt.innerHTML === ifProxyHtml) {
thisYes.checked = true;
this.classList.add(yesClass);
} else {
thisNo.checked = true;
this.classList.add(noClass);
}
}
return true;
};
{ // Populate selector.
const pacMods = pacKitchen.getPacMods();
for(const host of Object.keys(pacMods.exceptions || {}).sort()) {
addOption(host, pacMods.exceptions[host]);
}
}
excEditor.oninput();
document.getElementById('exc-radio').onclick = function(event) { document.getElementById('exc-radio').onclick = function(event) {
if( !['LABEL', 'INPUT'].includes( event.target.tagName ) ) { /* ON CLICK */
if(event.target.tagName !== 'INPUT') {
return true; return true;
} }
const _host = excEditor.value.trim(); const _host = excEditor.value.trim().replace(prefRe, '');
const pacMods = pacKitchen.getPacMods(); const pacMods = pacKitchen.getPacMods();
pacMods.exceptions = pacMods.exceptions || {}; pacMods.exceptions = pacMods.exceptions || {};
let fixSelectBox; let fixUi = () => {};
if (document.getElementById('this-auto').checked) { if (thisAuto.checked) {
delete pacMods.exceptions[_host]; delete pacMods.exceptions[_host];
fixSelectBox = () => { fixUi = () => excEditor.value = '';
for(const sopt of [...excSelect.selectedOptions]) {
const shost = sopt.value.trim();
delete pacMods.exceptions[shost];
sopt.remove();
}
excEditor.value = '';
}
} else { } else {
// YES or NO. // YES or NO.
if (!validateHost(_host)) { if (!validateHost(_host)) {
@ -376,33 +444,20 @@ chrome.runtime.getBackgroundPage( (backgroundPage) =>
return false; return false;
} }
pacMods.exceptions[_host] = thisYes.checked; pacMods.exceptions[_host] = thisYes.checked;
fixUi = () => addOption(_host, thisYes.checked);
if (excSelect.selectedIndex === -1) {
// Add new.
fixSelectBox = () => addOption(_host, thisYes.checked);
} else {
// Edit selected.
fixSelectBox = () => {
for(const sopt of [...excSelect.selectedOptions]) {
sopt.value = _host;
if (thisYes.checked) {
sopt.classList.add(ifProxiedClass);
} else {
sopt.classList.remove(ifProxiedClass);
}
}
}
}
} }
conduct( conduct(
'Применяем исключения...', 'Применяем исключения...',
(cb) => pacKitchen.keepCookedNowAsync(pacMods, cb), (cb) => pacKitchen.keepCookedNowAsync(pacMods, cb),
'Исключения применены.', 'Исключения применены.',
fixSelectBox () => {
getExactOpts(_host).forEach( (opt) => opt.remove() );
fixUi();
excEditor.oninput();
}
); );
return true; return true;
@ -550,6 +605,7 @@ HTTPS 11.22.33.44:8080;">${conf.value || localStorage.getItem(uiRaw) || ''}</tex
document.querySelector('#update-' + id).click(); document.querySelector('#update-' + id).click();
} }
document.documentElement.style.display = ''; document.documentElement.style.display = '';
console.log(Date.now() - START); console.log(Date.now() - START);
}) })