simplify css + save + autosave
This commit is contained in:
parent
bbb3585f2f
commit
b553325d7c
|
@ -88,9 +88,6 @@
|
|||
"message": "Author",
|
||||
"description": "Label for the style author"
|
||||
},
|
||||
"autosaveNotice": {
|
||||
"message": "Changes are saved automatically"
|
||||
},
|
||||
"backupButtons": {
|
||||
"message": "Backup",
|
||||
"description": "Heading for backup"
|
||||
|
|
65
edit.html
65
edit.html
|
@ -231,44 +231,41 @@
|
|||
</template>
|
||||
|
||||
<template data-id="styleSettings">
|
||||
<fieldset class="style-settings can-close-on-esc">
|
||||
<!-- <label class="style-origin">
|
||||
<span class="form-label" i18n-text="styleOriginLabel"></span>
|
||||
<input id="styleOrigin" type="text">
|
||||
</label> -->
|
||||
<label class="form-group style-update-url">
|
||||
<span class="form-label" i18n-text="styleUpdateUrlLabel"></span>
|
||||
<input type="text">
|
||||
</label>
|
||||
<div class="form-group style-prefer-scheme radio-group">
|
||||
<!-- FIXME: should we use a different message from install page? -->
|
||||
<span class="form-label" i18n-text="installPreferSchemeLabel"></span>
|
||||
<label class="radio-item">
|
||||
<input type="radio" name="preferScheme" value="none">
|
||||
<span class="radio-label" i18n-text="installPreferSchemeNone"></span>
|
||||
<div>
|
||||
<fieldset class="style-settings can-close-on-esc">
|
||||
<label i18n-text="styleUpdateUrlLabel">
|
||||
<input id="ss-update-url" type="text">
|
||||
</label>
|
||||
<label class="radio-item">
|
||||
<input type="radio" name="preferScheme" value="dark">
|
||||
<span class="radio-label" i18n-text="installPreferSchemeDark"></span>
|
||||
<div>
|
||||
<div i18n-text="installPreferSchemeLabel"></div>
|
||||
<label i18n-text-append="installPreferSchemeNone">
|
||||
<input name="ss-scheme" type="radio" value="none">
|
||||
</label>
|
||||
<label i18n-text-append="installPreferSchemeDark">
|
||||
<input name="ss-scheme" type="radio" value="dark">
|
||||
</label>
|
||||
<label i18n-text-append="installPreferSchemeLight">
|
||||
<input name="ss-scheme" type="radio" value="light">
|
||||
</label>
|
||||
</div>
|
||||
<label i18n-text="styleIncludeLabel">
|
||||
<textarea id="ss-inclusions" spellcheck="false"
|
||||
placeholder="*://site1.com/* *://site2.com/*"></textarea>
|
||||
</label>
|
||||
<label class="radio-item">
|
||||
<input type="radio" name="preferScheme" value="light">
|
||||
<span class="radio-label" i18n-text="installPreferSchemeLight"></span>
|
||||
<label i18n-text="styleExcludeLabel">
|
||||
<textarea id="ss-exclusions" spellcheck="false"
|
||||
placeholder="*://site1.com/* *://site2.com/*"></textarea>
|
||||
</label>
|
||||
</fieldset>
|
||||
<div class="buttons">
|
||||
<button id="ss-save" i18n-text="confirmSave" disabled></button>
|
||||
<label i18n-title="configOnChangeTooltip" i18n-text-append="configOnChange">
|
||||
<input id="config.autosave" type="checkbox">
|
||||
<svg class="svg-icon checked"><use xlink:href="#svg-icon-checked"/></svg>
|
||||
</label>
|
||||
<button id="ss-close" i18n-text="confirmClose"></button>
|
||||
</div>
|
||||
<label class="form-group style-include">
|
||||
<span class="form-label" i18n-text="styleIncludeLabel"></span>
|
||||
<textarea spellcheck="false" placeholder="*://site1.com/* *://site2.com/*"></textarea>
|
||||
</label>
|
||||
<label class="form-group style-exclude">
|
||||
<span class="form-label" i18n-text="styleExcludeLabel"></span>
|
||||
<textarea spellcheck="false" placeholder="*://site1.com/* *://site2.com/*"></textarea>
|
||||
</label>
|
||||
<!-- <label class="style-always-important">
|
||||
<input type="checkbox">
|
||||
<span class="form-label" i18n-text="styleAlwaysImportantLabel"></span>
|
||||
</label> -->
|
||||
</fieldset>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<link href="vendor/codemirror/lib/codemirror.css" rel="stylesheet">
|
||||
|
|
|
@ -411,10 +411,6 @@ input:invalid {
|
|||
.edit-actions button {
|
||||
margin-right: .2rem;
|
||||
}
|
||||
.dirty > label::before {
|
||||
content: "*";
|
||||
font-weight: bold;
|
||||
}
|
||||
#sections {
|
||||
counter-reset: codebox;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
#help-popup.style-settings-popup.dirty .title::after {
|
||||
content: ' *';
|
||||
}
|
||||
.compact-layout #help-popup.style-settings-popup {
|
||||
width: 90%;
|
||||
}
|
||||
|
@ -6,48 +9,29 @@
|
|||
border: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.style-settings > * {
|
||||
display: block;
|
||||
margin: 1rem 0;
|
||||
padding: 0;
|
||||
}
|
||||
.style-settings > :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.style-settings > :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.form-group {
|
||||
display: block;
|
||||
margin: .6em 0;
|
||||
padding: 0;
|
||||
.style-settings input[type=radio] {
|
||||
margin-left: -.5em; /* compensate for label's 16px margin in edit.css */
|
||||
}
|
||||
.form-label {
|
||||
display: inline-block;
|
||||
margin: .3em 0;
|
||||
}
|
||||
[disabled] .form-label {
|
||||
opacity: 0.4;
|
||||
}
|
||||
.form-group input[type=text],
|
||||
.form-group input[type=number],
|
||||
.form-group select,
|
||||
.form-group textarea {
|
||||
.style-settings input[type=text],
|
||||
.style-settings input[type=number],
|
||||
.style-settings select,
|
||||
.style-settings textarea {
|
||||
display: block;
|
||||
width: 100%;
|
||||
margin-top: .25em;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.radio-group .form-label {
|
||||
display: block;
|
||||
}
|
||||
.radio-item {
|
||||
display: flex;
|
||||
margin: 0.3em 0 .3em;
|
||||
padding: 0;
|
||||
align-items: center;
|
||||
width: max-content;
|
||||
}
|
||||
.radio-item input {
|
||||
margin: 0 0.6em 0 0;
|
||||
}
|
||||
[disabled] .radio-label {
|
||||
opacity: 0.4;
|
||||
}
|
||||
.style-settings textarea {
|
||||
resize: vertical;
|
||||
min-width: 33vw;
|
||||
|
|
111
edit/settings.js
111
edit/settings.js
|
@ -1,90 +1,91 @@
|
|||
/* global $ $$ $create moveFocus */// dom.js
|
||||
/* global $ $$ moveFocus setupLivePrefs */// dom.js
|
||||
/* global API */// msg.js
|
||||
/* global editor */
|
||||
/* global helpPopup */// util.js
|
||||
/* global t */// localization.js
|
||||
/* global debounce */// toolbox.js
|
||||
/* exported StyleSettings */
|
||||
'use strict';
|
||||
|
||||
function StyleSettings() {
|
||||
const {style} = editor;
|
||||
const AUTOSAVE_DELAY = 500; // same as config-dialog.js
|
||||
const ui = t.template.styleSettings.cloneNode(true);
|
||||
const inputs = [
|
||||
createInput('.style-update-url input', () => style.updateUrl || '',
|
||||
e => API.styles.config(style.id, 'updateUrl', e.target.value)),
|
||||
createRadio('.style-prefer-scheme input', () => style.preferScheme || 'none',
|
||||
e => API.styles.config(style.id, 'preferScheme', e.target.value)),
|
||||
...[
|
||||
['.style-include', 'inclusions'],
|
||||
['.style-exclude', 'exclusions'],
|
||||
].map(createArea),
|
||||
const elAuto = $('[id="config.autosave"]', ui);
|
||||
const elSave = $('#ss-save', ui);
|
||||
const pendingSetters = new Map();
|
||||
const {style} = editor;
|
||||
const updaters = [
|
||||
initInput('#ss-update-url', () => style.updateUrl || '',
|
||||
val => API.styles.config(style.id, 'updateUrl', val)),
|
||||
initRadio('ss-scheme', () => style.preferScheme || 'none',
|
||||
val => API.styles.config(style.id, 'preferScheme', val)),
|
||||
initArea('inclusions'),
|
||||
initArea('exclusions'),
|
||||
];
|
||||
(editor.updateSettings = () => {
|
||||
inputs.forEach(i => i.update());
|
||||
updaters.forEach(fn => fn());
|
||||
})();
|
||||
helpPopup.show(t('styleSettings'), $create([
|
||||
ui,
|
||||
$create('.buttons', [
|
||||
$create('button', {
|
||||
onclick: helpPopup.close,
|
||||
title: t('autosaveNotice'),
|
||||
}, t('confirmClose')),
|
||||
]),
|
||||
]), {
|
||||
helpPopup.show(t('styleSettings'), ui, {
|
||||
className: 'style-settings-popup',
|
||||
});
|
||||
elSave.onclick = save;
|
||||
$('#ss-close', ui).onclick = helpPopup.close;
|
||||
setupLivePrefs([elAuto.id]);
|
||||
moveFocus(ui, 0);
|
||||
|
||||
function textToList(text) {
|
||||
const list = text.split(/\s*\r?\n\s*/g);
|
||||
return list.filter(Boolean);
|
||||
function autosave(el, setter) {
|
||||
pendingSetters.set(el, setter);
|
||||
helpPopup.div.classList.add('dirty');
|
||||
elSave.disabled = false;
|
||||
if (elAuto.checked) debounce(save, AUTOSAVE_DELAY);
|
||||
}
|
||||
|
||||
function createArea([parentSel, type]) {
|
||||
const sel = parentSel + ' textarea';
|
||||
const el = $(sel, ui);
|
||||
el.on('input', () => {
|
||||
function initArea(type) {
|
||||
const selector = `#ss-${type}`;
|
||||
const el = $(selector, ui);
|
||||
el.oninput = () => {
|
||||
const val = el.value;
|
||||
el.rows = val.match(/^/gm).length + !val.endsWith('\n');
|
||||
});
|
||||
return createInput(sel,
|
||||
};
|
||||
return initInput(selector,
|
||||
() => {
|
||||
const list = style[type] || [];
|
||||
const text = list.join('\n');
|
||||
el.rows = (list.length || 1) + 1;
|
||||
return text;
|
||||
},
|
||||
() => API.styles.config(style.id, type, textToList(el.value))
|
||||
val => API.styles.config(style.id, type, textToList(val))
|
||||
);
|
||||
}
|
||||
|
||||
function createRadio(selector, getter, setter) {
|
||||
const els = $$(selector, ui);
|
||||
for (const el of els) {
|
||||
el.addEventListener('change', e => {
|
||||
if (el.checked) {
|
||||
setter(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
return {
|
||||
update() {
|
||||
for (const el of els) {
|
||||
if (el.value === getter()) {
|
||||
el.checked = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
function initInput(selector, getter, setter) {
|
||||
const el = $(selector, ui);
|
||||
el.oninput = () => autosave(el, setter);
|
||||
return () => {
|
||||
const val = getter();
|
||||
// Skipping if unchanged to preserve the Undo history of the input
|
||||
if (el.value !== val) el.value = val;
|
||||
};
|
||||
}
|
||||
|
||||
function createInput(selector, getter, setter) {
|
||||
const el = $(selector, ui);
|
||||
el.addEventListener('change', setter);
|
||||
return {
|
||||
update() {
|
||||
el.value = getter();
|
||||
},
|
||||
function initRadio(name, getter, setter) {
|
||||
for (const el of $$(`[name="${name}"]`, ui)) {
|
||||
el.onchange = () => {
|
||||
if (el.checked) autosave(el, setter);
|
||||
};
|
||||
}
|
||||
return () => {
|
||||
$(`[name="${name}"][value="${getter()}"]`, ui).checked = true;
|
||||
};
|
||||
}
|
||||
|
||||
function save() {
|
||||
pendingSetters.forEach((fn, el) => fn(el.value));
|
||||
helpPopup.div.classList.remove('dirty');
|
||||
elSave.disabled = true;
|
||||
}
|
||||
|
||||
function textToList(text) {
|
||||
return text.split(/\n/).map(s => s.trim()).filter(Boolean);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user