add per-style setting for autoupdate checks

This commit is contained in:
tophf 2022-01-19 22:21:54 +03:00
parent f041f2265a
commit ce9e74e2a0
4 changed files with 71 additions and 43 deletions

View File

@ -63,7 +63,7 @@ const updateMan = (() => {
checkingAll = true; checkingAll = true;
const port = observe && chrome.runtime.connect({name: 'updater'}); const port = observe && chrome.runtime.connect({name: 'updater'});
const styles = (await API.styles.getAll()) const styles = (await API.styles.getAll())
.filter(style => style.updateUrl); .filter(style => style.updateUrl && style.updatable !== false);
if (port) port.postMessage({count: styles.length}); if (port) port.postMessage({count: styles.length});
log(''); log('');
log(`${save ? 'Scheduled' : 'Manual'} update check for ${styles.length} styles`); log(`${save ? 'Scheduled' : 'Manual'} update check for ${styles.length} styles`);

View File

@ -23,10 +23,13 @@
.style-settings input[type=radio] { .style-settings input[type=radio] {
margin-left: -.5em; /* compensate for label's 16px margin in edit.css */ margin-left: -.5em; /* compensate for label's 16px margin in edit.css */
} }
.style-settings input[type=text], .style-settings input:disabled ~ label {
.style-settings input[type=number], opacity: .5;
.style-settings select, }
.style-settings textarea { .style-settings .rel {
position: relative;
}
.style-settings .w100 {
display: block; display: block;
width: 100%; width: 100%;
margin-top: .25em; margin-top: .25em;

View File

@ -1,8 +1,11 @@
<div> <div>
<fieldset class="style-settings can-close-on-esc"> <fieldset class="style-settings can-close-on-esc">
<label i18n-text="styleUpdateUrlLabel"> <div class="rel">
<input id="ss-update-url" type="text"> <input id="ss-updatable" type="checkbox">
</label> <svg class="svg-icon checked"><use xlink:href="#svg-icon-checked"/></svg>
<label i18n-text="installUpdateFromLabel" for="ss-updatable"></label>
<input id="ss-update-url" type="url" class="w100" i18n-placeholder="styleUpdateUrlLabel">
</div>
<div id="ss-scheme"> <div id="ss-scheme">
<div i18n-text="installPreferSchemeLabel"></div> <div i18n-text="installPreferSchemeLabel"></div>
<label i18n-text-append="installPreferSchemeNone"> <label i18n-text-append="installPreferSchemeNone">
@ -16,11 +19,11 @@
</label> </label>
</div> </div>
<label i18n-text="styleIncludeLabel"> <label i18n-text="styleIncludeLabel">
<textarea id="ss-inclusions" spellcheck="false" <textarea id="ss-inclusions" spellcheck="false" class="w100"
placeholder="*://site1.com/*&#10;*://site2.com/*"></textarea> placeholder="*://site1.com/*&#10;*://site2.com/*"></textarea>
</label> </label>
<label i18n-text="styleExcludeLabel"> <label i18n-text="styleExcludeLabel">
<textarea id="ss-exclusions" spellcheck="false" <textarea id="ss-exclusions" spellcheck="false" class="w100"
placeholder="*://site1.com/*&#10;*://site2.com/*"></textarea> placeholder="*://site1.com/*&#10;*://site2.com/*"></textarea>
</label> </label>
</fieldset> </fieldset>

View File

@ -1,26 +1,32 @@
/* global $ $$ moveFocus setupLivePrefs */// dom.js /* global $ moveFocus setupLivePrefs */// dom.js
/* global API */// msg.js /* global API */// msg.js
/* global editor */ /* global editor */
/* global helpPopup */// util.js /* global helpPopup */// util.js
/* global t */// localization.js /* global t */// localization.js
/* global debounce */// toolbox.js /* global debounce tryURL */// toolbox.js
/* exported StyleSettings */ /* exported StyleSettings */
'use strict'; 'use strict';
async function StyleSettings() { async function StyleSettings() {
const AUTOSAVE_DELAY = 500; // same as config-dialog.js const AUTOSAVE_DELAY = 500; // same as config-dialog.js
const SS_ID = 'styleSettings'; const SS_ID = 'styleSettings';
const PASS = val => val;
await t.fetchTemplate('/edit/settings.html', SS_ID); await t.fetchTemplate('/edit/settings.html', SS_ID);
const {style} = editor; const {style} = editor;
const ui = t.template[SS_ID].cloneNode(true); const ui = t.template[SS_ID].cloneNode(true);
const elAuto = $('#config\\.autosave', ui); const elAuto = $('#config\\.autosave', ui);
const elSave = $('#ss-save', ui); const elSave = $('#ss-save', ui);
const elUpd = $('#ss-updatable', ui);
const pendingSetters = new Map(); const pendingSetters = new Map();
const updaters = [ const updaters = [
initInput('#ss-update-url', () => style.updateUrl || '', initCheckbox(elUpd, 'updatable', tryURL(style.updateUrl).href),
val => API.styles.config(style.id, 'updateUrl', val)), initInput('#ss-update-url', 'updateUrl', '', {
initRadio('ss-scheme', () => style.preferScheme || 'none', validate(el) {
val => API.styles.config(style.id, 'preferScheme', val)), elUpd.disabled = !el.value || !el.validity.valid;
return el.validity.valid;
},
}),
initRadio('ss-scheme', 'preferScheme', 'none'),
initArea('inclusions'), initArea('inclusions'),
initArea('exclusions'), initArea('exclusions'),
]; ];
@ -43,51 +49,67 @@ async function StyleSettings() {
} }
function initArea(type) { function initArea(type) {
const selector = `#ss-${type}`; return initInput(`#ss-${type}`, type, [], {
const el = $(selector, ui); get: textToList,
el.oninput = () => { set: list => list.join('\n'),
validate(el) {
const val = el.value; const val = el.value;
el.rows = val.match(/^/gm).length + !val.endsWith('\n'); el.rows = val.match(/^/gm).length + !val.endsWith('\n');
};
return initInput(selector,
() => {
const list = style[type] || [];
const text = list.join('\n');
el.rows = (list.length || 1) + 1;
return text;
}, },
val => API.styles.config(style.id, type, textToList(val)) });
);
} }
function initInput(selector, getter, setter) { function initCheckbox(el, key, defVal) {
const el = $(selector, ui); return initInput(el, key, Boolean(defVal), {dom: 'checked'});
el.oninput = () => autosave(el, setter); }
function initInput(el, key, defVal, {
dom = 'value', // DOM property name
get = PASS, // transformer function(val) after getting DOM value
set = PASS, // transformer function(val) before setting DOM value
validate = PASS, // function(el) - return `false` to prevent saving
} = {}) {
if (typeof el === 'string') {
el = $(el, ui);
}
el.oninput = () => {
if (validate(el) !== false) {
autosave(el, {dom, get, key});
}
};
return () => { return () => {
const val = getter(); let val = style[key];
val = set(val != null ? val : defVal);
// Skipping if unchanged to preserve the Undo history of the input // Skipping if unchanged to preserve the Undo history of the input
if (el.value !== val) el.value = val; if (el[dom] !== val) el[dom] = val;
validate(el);
}; };
} }
function initRadio(name, getter, setter) { function initRadio(name, key, defVal) {
for (const el of $$(`[name="${name}"]`, ui)) { $(`#${name}`, ui).oninput = e => {
el.onchange = () => { if (e.target.checked) {
if (el.checked) autosave(el, setter); autosave(e.target, {key});
};
} }
};
return () => { return () => {
$(`[name="${name}"][value="${getter()}"]`, ui).checked = true; const val = style[key] || defVal;
const el = $(`[name="${name}"][value="${val}"]`, ui);
el.checked = true;
}; };
} }
function save() { function save() {
pendingSetters.forEach((fn, el) => fn(el.value)); pendingSetters.forEach(saveValue);
pendingSetters.clear(); pendingSetters.clear();
helpPopup.div.classList.remove('dirty'); helpPopup.div.classList.remove('dirty');
elSave.disabled = true; elSave.disabled = true;
} }
function saveValue({dom = 'value', get = PASS, key}, el) {
return API.styles.config(style.id, key, get(el[dom]));
}
function textToList(text) { function textToList(text) {
return text.split(/\n/).map(s => s.trim()).filter(Boolean); return text.split(/\n/).map(s => s.trim()).filter(Boolean);
} }