Change: use textarea for include/exclude, remove isCodeUpdated

This commit is contained in:
eight04 2021-12-07 02:17:41 +08:00
parent a7a58c9037
commit 7e61ea9691
8 changed files with 79 additions and 94 deletions

View File

@ -1652,18 +1652,9 @@
"styleIncludeLabel": { "styleIncludeLabel": {
"message": "Custom included sites" "message": "Custom included sites"
}, },
"styleIncludeNewLabel": {
"message": "Add new inclusion"
},
"styleIncludeDeleteLabel": {
"message": "Delete"
},
"styleExcludeLabel": { "styleExcludeLabel": {
"message": "Custom excluded sites" "message": "Custom excluded sites"
}, },
"styleExcludeNewLabel": {
"message": "Add new exclusion"
},
"syncDropboxDeprecated": { "syncDropboxDeprecated": {
"message": "Dropbox import/export is replaced by a more advanced style sync in the options page." "message": "Dropbox import/export is replaced by a more advanced style sync in the options page."
}, },

View File

@ -382,7 +382,7 @@ const styleMan = (() => {
throw new Error('The rule already exists'); throw new Error('The rule already exists');
} }
style[type] = list.concat([rule]); style[type] = list.concat([rule]);
return saveStyle(style, {reason: 'styleSettings'}); return saveStyle(style, {reason: 'config'});
} }
async function removeIncludeExclude(type, id, rule) { async function removeIncludeExclude(type, id, rule) {
@ -393,7 +393,7 @@ const styleMan = (() => {
return; return;
} }
style[type] = list.filter(r => r !== rule); style[type] = list.filter(r => r !== rule);
return saveStyle(style, {reason: 'styleSettings'}); return saveStyle(style, {reason: 'config'});
} }
function broadcastStyleUpdated(style, reason, method = 'styleUpdated', codeIsUpdated = true) { function broadcastStyleUpdated(style, reason, method = 'styleUpdated', codeIsUpdated = true) {

View File

@ -469,16 +469,14 @@
<span class="radio-label" i18n-text="installPreferSchemeLight"></span> <span class="radio-label" i18n-text="installPreferSchemeLight"></span>
</label> </label>
</div> </div>
<div class="form-group style-include"> <label class="form-group style-include">
<div class="form-label" i18n-text="styleIncludeLabel"></div> <span class="form-label" i18n-text="styleIncludeLabel"></span>
<div class="rule-table"></div> <textarea></textarea>
<button i18n-text="styleIncludeNewLabel" class="add-rule"></button> </label>
</div> <label class="form-group style-exclude">
<div class="form-group style-exclude"> <span class="form-label" i18n-text="styleExcludeLabel"></span>
<div class="form-label" i18n-text="styleExcludeLabel"></div> <textarea></textarea>
<div class="rule-table"></div> </label>
<button i18n-text="styleExcludeNewLabel" class="add-rule"></button>
</div>
<!-- <label class="style-always-important"> <!-- <label class="style-always-important">
<input type="checkbox"> <input type="checkbox">
<span class="form-label" i18n-text="styleAlwaysImportantLabel"></span> <span class="form-label" i18n-text="styleAlwaysImportantLabel"></span>

View File

@ -1,5 +1,5 @@
/* global $ $create messageBoxProxy waitForSheet */// dom.js /* global $ $create messageBoxProxy waitForSheet */// dom.js
/* global API msg */// msg.js /* global msg */// msg.js
/* global CodeMirror */ /* global CodeMirror */
/* global SectionsEditor */ /* global SectionsEditor */
/* global SourceEditor */ /* global SourceEditor */
@ -70,11 +70,7 @@ msg.onExtension(request => {
switch (request.method) { switch (request.method) {
case 'styleUpdated': case 'styleUpdated':
if (editor.style.id === style.id && !IGNORE_UPDATE_REASONS.includes(request.reason)) { if (editor.style.id === style.id && !IGNORE_UPDATE_REASONS.includes(request.reason)) {
Promise.resolve(request.codeIsUpdated === false ? style : API.styles.get(style.id)) editor.emit('styleChange', request.style, request.reason, request.codeIsUpdated);
.then(newStyle => {
editor.replaceStyle(newStyle, request.codeIsUpdated);
editor.emit('styleChange', newStyle, request.reason);
});
} }
break; break;
case 'styleDeleted': case 'styleDeleted':
@ -165,9 +161,9 @@ window.on('beforeunload', e => {
} }
}, },
toggleStyle() { toggleStyle(enabled = style.enabled) {
$('#enabled').checked = !style.enabled; $('#enabled').checked = enabled;
editor.updateEnabledness(!style.enabled); editor.updateEnabledness(enabled);
}, },
updateDirty() { updateDirty() {

View File

@ -84,16 +84,13 @@ function SectionsEditor() {
: null; : null;
}, },
async replaceStyle(newStyle, codeIsUpdated) { async replaceStyle(newStyle) {
dirty.clear('name'); dirty.clear();
// FIXME: avoid recreating all editors? // FIXME: avoid recreating all editors?
if (codeIsUpdated !== false) {
await initSections(newStyle.sections, {replace: true}); await initSections(newStyle.sections, {replace: true});
}
Object.assign(style, newStyle); Object.assign(style, newStyle);
editor.onStyleUpdated(); editor.onStyleUpdated();
updateHeader(); updateHeader();
dirty.clear();
// Go from new style URL to edit style URL // Go from new style URL to edit style URL
if (style.id && !/[&?]id=/.test(location.search)) { if (style.id && !/[&?]id=/.test(location.search)) {
history.replaceState({}, document.title, `${location.pathname}?id=${style.id}`); history.replaceState({}, document.title, `${location.pathname}?id=${style.id}`);
@ -131,6 +128,28 @@ function SectionsEditor() {
editor.ready = initSections(style.sections); editor.ready = initSections(style.sections);
editor.on('styleChange', async (newStyle, reason) => {
if (reason === 'new') return; // nothing is new for us
if (reason === 'toggle') {
if (!dirty.isDirty()) {
Object.assign(style, newStyle);
updateHeader();
}
updateLivePreview();
return;
}
if (reason === 'config') {
newStyle = await API.styles.get(newStyle.id);
delete newStyle.sections;
delete newStyle.name;
delete newStyle.enabled;
Object.assign(style, newStyle);
updateLivePreview();
return;
}
editor.replaceStyle(await API.styles.get(newStyle.id));
});
/** @param {EditorSection} section */ /** @param {EditorSection} section */
function fitToContent(section) { function fitToContent(section) {
const {cm, cm: {display: {wrapper, sizer}}} = section; const {cm, cm: {display: {wrapper, sizer}}} = section;

View File

@ -17,20 +17,12 @@
} }
.form-group input[type=text], .form-group input[type=text],
.form-group input[type=number], .form-group input[type=number],
.form-group select { .form-group select,
.form-group textarea {
display: block; display: block;
width: 100%; width: 100%;
box-sizing: border-box; box-sizing: border-box;
} }
.rule-table {
display: grid;
grid-template-columns: minmax(min-content, 1fr) min-content;
grid-gap: .3em;
margin: 0 0 .3em 0;
}
[data-length="0"] .rule-table {
margin: 0;
}
.radio-group .form-label { .radio-group .form-label {
display: block; display: block;
} }
@ -47,3 +39,7 @@
[disabled] .radio-label { [disabled] .radio-label {
opacity: 0.4; opacity: 0.4;
} }
.style-include textarea,
.style-exclude textarea {
height: 12em;
}

View File

@ -1,4 +1,4 @@
/* global API t */ /* global API */
/* exported StyleSettings */ /* exported StyleSettings */
'use strict'; 'use strict';
@ -10,14 +10,21 @@ function StyleSettings(editor) {
e => API.styles.config(style.id, 'updateUrl', e.target.value)), e => API.styles.config(style.id, 'updateUrl', e.target.value)),
createRadio('.style-prefer-scheme input', () => style.preferScheme || 'none', createRadio('.style-prefer-scheme input', () => style.preferScheme || 'none',
e => API.styles.config(style.id, 'preferScheme', e.target.value)), e => API.styles.config(style.id, 'preferScheme', e.target.value)),
createRuleTable(document.querySelector('.style-include'), 'inclusions'), createInput('.style-include textarea', () => (style.inclusions || []).join('\n'),
createRuleTable(document.querySelector('.style-exclude'), 'exclusions'), e => API.styles.config(style.id, 'inclusions', textToList(e.target.value))),
createInput('.style-exclude textarea', () => (style.exclusions || []).join('\n'),
e => API.styles.config(style.id, 'exclusions', textToList(e.target.value))),
]; ];
update(style); update(style);
editor.on('styleChange', update); editor.on('styleChange', update);
function textToList(text) {
const list = text.split(/\s*\r?\n\s*/g);
return list.filter(Boolean);
}
function update(newStyle, reason) { function update(newStyle, reason) {
if (!newStyle.id) return; if (!newStyle.id) return;
if (reason === 'editSave' || reason === 'config') return; if (reason === 'editSave' || reason === 'config') return;
@ -55,46 +62,4 @@ function StyleSettings(editor) {
}, },
}; };
} }
function createRuleTable(container, type) {
const table = container.querySelector('.rule-table');
container.querySelector('.add-rule').addEventListener('click', addRule);
return {update};
function update() {
// TODO: don't recreate everything
table.innerHTML = '';
if (!style[type]) {
style[type] = [];
}
container.dataset.length = style[type].length;
style[type].forEach((rule, i) => {
const input = document.createElement('input');
input.value = rule;
input.addEventListener('change', () => {
style[type][i] = input.value;
API.styles.config(style.id, type, style[type]);
});
table.append(input);
const delButton = document.createElement('button');
delButton.textContent = t('styleIncludeDeleteLabel');
delButton.addEventListener('click', () => {
style[type].splice(i, 1);
API.styles.config(style.id, type, style[type]);
update();
});
table.append(delButton);
});
}
function addRule() {
if (!style[type]) {
style[type] = [];
}
style[type].push('');
API.styles.config(style.id, type, style[type]);
update();
}
}
} }

View File

@ -116,6 +116,28 @@ function SourceEditor() {
if (!$isTextInput(document.activeElement)) { if (!$isTextInput(document.activeElement)) {
cm.focus(); cm.focus();
} }
editor.on('styleChange', async (newStyle, reason) => {
if (reason === 'new') return;
if (reason === 'config') {
newStyle = await API.styles.get(newStyle.id);
delete newStyle.sourceCode;
delete newStyle.name;
Object.assign(style, newStyle);
updateLivePreview();
return;
}
if (reason === 'toggle') {
if (dirty.isDirty()) {
editor.toggleStyle(newStyle.enabled);
} else {
style.enabled = newStyle.enabled;
}
updateMeta();
updateLivePreview();
return;
}
replaceStyle(await API.styles.get(newStyle.id));
});
async function preprocess(style) { async function preprocess(style) {
const res = await API.usercss.build({ const res = await API.usercss.build({
@ -211,14 +233,12 @@ function SourceEditor() {
cm.setPreprocessor((style.usercssData || {}).preprocessor); cm.setPreprocessor((style.usercssData || {}).preprocessor);
} }
function replaceStyle(newStyle, codeIsUpdated) { function replaceStyle(newStyle) {
dirty.clear('name'); dirty.clear('name');
const sameCode = newStyle.sourceCode === cm.getValue(); const sameCode = newStyle.sourceCode === cm.getValue();
if (sameCode) { if (sameCode) {
savedGeneration = cm.changeGeneration(); savedGeneration = cm.changeGeneration();
dirty.clear('sourceGeneration'); dirty.clear('sourceGeneration');
}
if (codeIsUpdated === false || sameCode) {
updateEnvironment(); updateEnvironment();
dirty.clear('enabled'); dirty.clear('enabled');
updateLivePreview(); updateLivePreview();