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": {
"message": "Custom included sites"
},
"styleIncludeNewLabel": {
"message": "Add new inclusion"
},
"styleIncludeDeleteLabel": {
"message": "Delete"
},
"styleExcludeLabel": {
"message": "Custom excluded sites"
},
"styleExcludeNewLabel": {
"message": "Add new exclusion"
},
"syncDropboxDeprecated": {
"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');
}
style[type] = list.concat([rule]);
return saveStyle(style, {reason: 'styleSettings'});
return saveStyle(style, {reason: 'config'});
}
async function removeIncludeExclude(type, id, rule) {
@ -393,7 +393,7 @@ const styleMan = (() => {
return;
}
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) {

View File

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

View File

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

View File

@ -84,16 +84,13 @@ function SectionsEditor() {
: null;
},
async replaceStyle(newStyle, codeIsUpdated) {
dirty.clear('name');
async replaceStyle(newStyle) {
dirty.clear();
// FIXME: avoid recreating all editors?
if (codeIsUpdated !== false) {
await initSections(newStyle.sections, {replace: true});
}
await initSections(newStyle.sections, {replace: true});
Object.assign(style, newStyle);
editor.onStyleUpdated();
updateHeader();
dirty.clear();
// Go from new style URL to edit style URL
if (style.id && !/[&?]id=/.test(location.search)) {
history.replaceState({}, document.title, `${location.pathname}?id=${style.id}`);
@ -131,6 +128,28 @@ function SectionsEditor() {
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 */
function fitToContent(section) {
const {cm, cm: {display: {wrapper, sizer}}} = section;

View File

@ -17,20 +17,12 @@
}
.form-group input[type=text],
.form-group input[type=number],
.form-group select {
.form-group select,
.form-group textarea {
display: block;
width: 100%;
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 {
display: block;
}
@ -47,3 +39,7 @@
[disabled] .radio-label {
opacity: 0.4;
}
.style-include textarea,
.style-exclude textarea {
height: 12em;
}

View File

@ -1,4 +1,4 @@
/* global API t */
/* global API */
/* exported StyleSettings */
'use strict';
@ -10,14 +10,21 @@ function StyleSettings(editor) {
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)),
createRuleTable(document.querySelector('.style-include'), 'inclusions'),
createRuleTable(document.querySelector('.style-exclude'), 'exclusions'),
createInput('.style-include textarea', () => (style.inclusions || []).join('\n'),
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);
editor.on('styleChange', update);
function textToList(text) {
const list = text.split(/\s*\r?\n\s*/g);
return list.filter(Boolean);
}
function update(newStyle, reason) {
if (!newStyle.id) 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)) {
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) {
const res = await API.usercss.build({
@ -211,14 +233,12 @@ function SourceEditor() {
cm.setPreprocessor((style.usercssData || {}).preprocessor);
}
function replaceStyle(newStyle, codeIsUpdated) {
function replaceStyle(newStyle) {
dirty.clear('name');
const sameCode = newStyle.sourceCode === cm.getValue();
if (sameCode) {
savedGeneration = cm.changeGeneration();
dirty.clear('sourceGeneration');
}
if (codeIsUpdated === false || sameCode) {
updateEnvironment();
dirty.clear('enabled');
updateLivePreview();