From 669fb443a9ad3343d1a63000b8cb910a33c015cc Mon Sep 17 00:00:00 2001 From: tophf Date: Sat, 25 Dec 2021 21:43:07 +0300 Subject: [PATCH] show style settings in a dialog --- edit.html | 97 +++++++++++++++++++---------------------- edit/base.js | 46 ++++++++++++++----- edit/edit.css | 19 +------- edit/edit.js | 14 +++--- edit/sections-editor.js | 16 +------ edit/settings.css | 7 +++ edit/settings.js | 28 +++++++----- edit/source-editor.js | 15 +------ js/event-emitter.js | 37 ---------------- 9 files changed, 118 insertions(+), 161 deletions(-) delete mode 100644 js/event-emitter.js diff --git a/edit.html b/edit.html index dfc741cc..aaff56d3 100644 --- a/edit.html +++ b/edit.html @@ -17,7 +17,6 @@ - @@ -62,7 +61,6 @@ - + + @@ -241,8 +280,6 @@ - - @@ -278,7 +315,8 @@
- + +
@@ -437,53 +475,7 @@ target="_blank">
-
-
-
-
-
-
-
-
- - -
- - - - - -
- - - -
-
-
+
@@ -528,6 +520,5 @@ - diff --git a/edit/base.js b/edit/base.js index f3d4261e..ec13a50a 100644 --- a/edit/base.js +++ b/edit/base.js @@ -11,19 +11,20 @@ debounce getOwnTab sessionStore + tryCatch tryJSONparse tryURL */// toolbox.js -/* global EventEmitter */ 'use strict'; /** * @type Editor * @namespace Editor */ -const editor = Object.assign(EventEmitter(), { +const editor = { style: null, dirty: DirtyReporter(), + events: {}, isUsercss: false, isWindowed: false, lazyKeymaps: { @@ -36,7 +37,21 @@ const editor = Object.assign(EventEmitter(), { previewDelay: 200, // Chrome devtools uses 200 scrollInfo: null, - onStyleUpdated() { + cancel: () => location.assign('/manage.html'), + + emit(name, ...args) { + for (const fn of editor.events[name] || []) { + tryCatch(fn, ...args); + } + }, + + on(name, fn) { + (editor.events[name] || ( + editor.events[name] = new Set() + )).add(fn); + }, + + updateClass() { document.documentElement.classList.toggle('is-new-style', !editor.style.id); }, @@ -48,6 +63,19 @@ const editor = Object.assign(EventEmitter(), { customName || name || t('styleMissingName') } - Stylus`; // the suffix enables external utilities to process our windows e.g. pin on top }, +}; + +editor.on('styleUpdated', (newStyle, reason) => { + if (reason === 'config') { + delete newStyle.sourceCode; + delete newStyle.sections; + delete newStyle.name; + delete newStyle.enabled; + Object.assign(editor.style, newStyle); + editor.updateLivePreview(); + } else if (reason !== 'new') { + editor.replaceStyle(newStyle); + } }); //#region pre-init @@ -90,7 +118,7 @@ const baseInit = (() => { // switching the mode here to show the correct page ASAP, usually before DOMContentLoaded editor.isUsercss = Boolean(style.usercssData || !style.id && prefs.get('newStyleAsUsercss')); editor.style = style; - editor.onStyleUpdated(); + editor.updateClass(); editor.updateTitle(false); document.documentElement.classList.toggle('usercss', editor.isUsercss); sessionStore.justEditedStyleId = style.id || ''; @@ -292,16 +320,10 @@ baseInit.ready.then(() => { } } - getOwnTab().then(async tab => { + getOwnTab().then(tab => { ownTabId = tab.id; - // use browser history back when 'back to manage' is clicked if (sessionStore['manageStylesHistory' + ownTabId] === location.href) { - await baseInit.domReady; - $('#cancel-button').onclick = event => { - event.stopPropagation(); - event.preventDefault(); - history.back(); - }; + editor.cancel = () => history.back(); } }); diff --git a/edit/edit.css b/edit/edit.css index 157056ba..0055a7c3 100644 --- a/edit/edit.css +++ b/edit/edit.css @@ -105,11 +105,8 @@ label { #header h1 { margin-top: 0; } -.main { - padding-left: 280px; - height: 100%; -} #sections { + padding-left: 280px; min-height: 0; height: 100%; } @@ -284,10 +281,6 @@ input:invalid { margin: 0 .2rem .5rem 0; } -#actions #cancel-button { - margin: 0; -} - #options:not([open]) + #lint h2 { margin-top: 0; } @@ -768,11 +761,6 @@ body:not(.find-open) [data-match-highlight-count="1"] .CodeMirror-selection-high max-height: calc(100vh - 8rem); overflow-y: auto; } -#help-popup .settings { - min-width: 500px; - min-height: 200px; - max-width: 48vw; -} #help-popup .dismiss { position: absolute; right: 4px; @@ -1180,16 +1168,13 @@ body.linter-disabled .hidden-unless-compact { #lint:not([open]) + #footer { margin: .25em 0 -1em .25em; } - .main { + #sections { height: unset !important; padding-left: 0; display: flex; flex-direction: column; flex: 1; } - .tab-bar { - margin-top: var(--fixed-height); - } #sections > :not(.single-editor) { margin: 0 .5rem; padding: .5rem 0; diff --git a/edit/edit.js b/edit/edit.js index 2e171735..33fe1f43 100644 --- a/edit/edit.js +++ b/edit/edit.js @@ -1,5 +1,5 @@ /* global $ $create messageBoxProxy waitForSheet */// dom.js -/* global msg API */// msg.js +/* global API msg */// msg.js /* global CodeMirror */ /* global SectionsEditor */ /* global SourceEditor */ @@ -11,7 +11,6 @@ /* global linterMan */ /* global prefs */ /* global t */// localization.js -/* global StyleSettings */// settings.js 'use strict'; //#region init @@ -19,7 +18,6 @@ baseInit.ready.then(async () => { await waitForSheet(); (editor.isUsercss ? SourceEditor : SectionsEditor)(); - StyleSettings(editor); await editor.ready; editor.ready = true; editor.dirty.onChange(editor.updateDirty); @@ -32,6 +30,7 @@ baseInit.ready.then(async () => { // enabling after init to prevent flash of validation failure on an empty name $('#name').required = !editor.isUsercss; $('#save-button').onclick = editor.save; + $('#cancel-button').onclick = editor.cancel; const elSec = $('#sections-list'); // editor.toc.expanded pref isn't saved in compact-layout so prefs.subscribe won't work @@ -48,6 +47,11 @@ baseInit.ready.then(async () => { require(['/edit/linter-dialogs'], () => linterMan.showLintConfig()); $('#lint-help').onclick = () => require(['/edit/linter-dialogs'], () => linterMan.showLintHelp()); + $('#style-cfg-btn').onclick = () => require([ + '/edit/settings.css', + '/edit/settings', /* global StyleSettings */ + ], () => StyleSettings()); + require([ '/edit/autocomplete', '/edit/global-search', @@ -75,7 +79,7 @@ msg.onExtension(request => { } else { API.styles.get(request.style.id) .then(style => { - editor.emit('styleChange', style, request.reason); + editor.emit('styleUpdated', style, request.reason); }); } } @@ -168,7 +172,7 @@ window.on('beforeunload', e => { } }, - toggleStyle(enabled = style.enabled) { + toggleStyle(enabled = !style.enabled) { $('#enabled').checked = enabled; editor.updateEnabledness(enabled); }, diff --git a/edit/sections-editor.js b/edit/sections-editor.js index 306babb5..6530f35e 100644 --- a/edit/sections-editor.js +++ b/edit/sections-editor.js @@ -89,7 +89,7 @@ function SectionsEditor() { // FIXME: avoid recreating all editors? await initSections(newStyle.sections, {replace: true}); Object.assign(style, newStyle); - editor.onStyleUpdated(); + editor.updateClass(); updateHeader(); // Go from new style URL to edit style URL if (style.id && !/[&?]id=/.test(location.search)) { @@ -109,7 +109,7 @@ function SectionsEditor() { newStyle = await API.styles.editSave(newStyle); destroyRemovedSections(); if (!style.id) { - editor.emit('styleChange', newStyle, 'new'); + editor.emit('styleUpdated', newStyle, 'new'); } sessionStore.justEditedStyleId = newStyle.id; editor.replaceStyle(newStyle, false); @@ -137,18 +137,6 @@ function SectionsEditor() { updateHeader(); updateLivePreview(); }); - editor.on('styleChange', (newStyle, reason) => { - if (reason === 'new') return; // nothing is new for us - if (reason === 'config') { - delete newStyle.sections; - delete newStyle.name; - delete newStyle.enabled; - Object.assign(style, newStyle); - updateLivePreview(); - return; - } - editor.replaceStyle(newStyle); - }); /** @param {EditorSection} section */ function fitToContent(section) { diff --git a/edit/settings.css b/edit/settings.css index 3b33eba8..ef42c05a 100644 --- a/edit/settings.css +++ b/edit/settings.css @@ -1,3 +1,6 @@ +.compact-layout #help-popup[data-type="styleSettings"] { + width: 90%; +} .style-settings { padding: 0.7rem 1.7rem; border: 0; @@ -41,6 +44,10 @@ } .style-settings textarea { resize: vertical; + min-width: 33vw; min-height: 2.5em; max-height: 50vh; } +.style-settings textarea:not(:placeholder-shown) { + min-width: 50vw; +} diff --git a/edit/settings.js b/edit/settings.js index b54d28fe..c8cd5852 100644 --- a/edit/settings.js +++ b/edit/settings.js @@ -1,11 +1,14 @@ -/* global $ $$ */// dom.js +/* global $ $$ $create moveFocus */// dom.js /* global API */// msg.js +/* global editor */ +/* global helpPopup */// util.js +/* global t */// localization.js /* exported StyleSettings */ 'use strict'; -function StyleSettings(editor) { +function StyleSettings() { let {style} = editor; - + 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)), @@ -16,10 +19,16 @@ function StyleSettings(editor) { ['.style-exclude', 'exclusions'], ].map(createArea), ]; - update(style); - - editor.on('styleChange', update); + editor.on('styleUpdated', update); + helpPopup.show(t('editorSettingLabel'), $create([ + ui, + $create('.buttons', [ + $create('button', {onclick: helpPopup.close}, t('confirmClose')), + ]), + ])); + $('#help-popup').dataset.type = 'styleSettings'; + moveFocus(ui, 0); function textToList(text) { const list = text.split(/\s*\r?\n\s*/g); @@ -30,13 +39,12 @@ function StyleSettings(editor) { if (!newStyle.id) return; if (reason === 'editSave') return; style = newStyle; - $('.style-settings').disabled = false; inputs.forEach(i => i.update()); } function createArea([parentSel, type]) { const sel = parentSel + ' textarea'; - const el = $(sel); + const el = $(sel, ui); el.on('input', () => { const val = el.value; el.rows = val.match(/^/gm).length + !val.endsWith('\n'); @@ -53,7 +61,7 @@ function StyleSettings(editor) { } function createRadio(selector, getter, setter) { - const els = $$(selector); + const els = $$(selector, ui); for (const el of els) { el.addEventListener('change', e => { if (el.checked) { @@ -73,7 +81,7 @@ function StyleSettings(editor) { } function createInput(selector, getter, setter) { - const el = $(selector); + const el = $(selector, ui); el.addEventListener('change', setter); return { update() { diff --git a/edit/source-editor.js b/edit/source-editor.js index ead9e378..198887f0 100644 --- a/edit/source-editor.js +++ b/edit/source-editor.js @@ -71,7 +71,7 @@ function SourceEditor() { } else { res = await API.usercss.editSave({customName, enabled, id, sourceCode}); if (!id) { - editor.emit('styleChange', res.style, 'new'); + editor.emit('styleUpdated', res.style, 'new'); } // Awaiting inside `try` so that exceptions go to our `catch` await replaceStyle(res.style); @@ -125,17 +125,6 @@ function SourceEditor() { updateMeta(); updateLivePreview(); }); - editor.on('styleChange', (newStyle, reason) => { - if (reason === 'new') return; - if (reason === 'config') { - delete newStyle.sourceCode; - delete newStyle.name; - Object.assign(style, newStyle); - updateLivePreview(); - return; - } - replaceStyle(newStyle); - }); async function preprocess(style) { const res = await API.usercss.build({ @@ -265,7 +254,7 @@ function SourceEditor() { } sessionStore.justEditedStyleId = newStyle.id; Object.assign(style, newStyle); - editor.onStyleUpdated(); + editor.updateClass(); updateMeta(); } } diff --git a/js/event-emitter.js b/js/event-emitter.js deleted file mode 100644 index df4b6916..00000000 --- a/js/event-emitter.js +++ /dev/null @@ -1,37 +0,0 @@ -/* exported EventEmitter */ -'use strict'; - -function EventEmitter() { - const listeners = new Map(); - return { - on(ev, cb, opt) { - if (!listeners.has(ev)) { - listeners.set(ev, new Map()); - } - listeners.get(ev).set(cb, opt); - if (opt && opt.runNow) { - cb(); - } - }, - off(ev, cb) { - const cbs = listeners.get(ev); - if (cbs) { - cbs.delete(cb); - } - }, - emit(ev, ...args) { - const cbs = listeners.get(ev); - if (!cbs) return; - for (const [cb, opt] of cbs.entries()) { - try { - cb(...args); - } catch (err) { - console.error(err); - } - if (opt && opt.once) { - cbs.delete(cb); - } - } - }, - }; -}