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