From 3d0bbb72f99eb5771b2f84eb0bef8fdb48e6ffce Mon Sep 17 00:00:00 2001 From: tophf Date: Tue, 18 Jan 2022 17:22:49 +0300 Subject: [PATCH] save-as-template button in editor + keep i18n attributes and use them as CSS selectors + reduce flicker when creating a new style --- _locales/en/messages.json | 7 +++---- edit.html | 3 +++ edit/edit.css | 4 ++-- edit/edit.js | 6 +++++- edit/source-editor.js | 36 +++++++++++------------------------- js/localization.js | 1 - 6 files changed, 24 insertions(+), 33 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 84649365..4a88c107 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1352,6 +1352,9 @@ "retrieveDropboxSync": { "message": "Dropbox Import" }, + "saveAsTemplate": { + "message": "Save as template" + }, "search": { "message": "Search", "description": "Label before the search input field in the editor shown on Ctrl-F" @@ -1812,10 +1815,6 @@ "usercssReplaceTemplateConfirmation": { "message": "Replace the default template for new Usercss styles with the current code?" }, - "usercssReplaceTemplateName": { - "message": "Empty @name replaces the default template", - "description": "The text shown after @name when creating a new Usercss style" - }, "usercssReplaceTemplateSectionBody": { "message": "Insert code here...", "description": "The code placeholder comment in a new style created by clicking 'Write style' in the popup" diff --git a/edit.html b/edit.html index c74a4b66..b162045a 100644 --- a/edit.html +++ b/edit.html @@ -392,6 +392,9 @@ +
+ +
diff --git a/edit/edit.css b/edit/edit.css index 11697142..0553f5bf 100644 --- a/edit/edit.css +++ b/edit/edit.css @@ -977,7 +977,7 @@ body.linter-disabled .hidden-unless-compact { margin-top: 0; } -#options-wrapper .options-column:nth-child(2) { +#options-wrapper .options-column:nth-child(n + 2) { margin-top: .75rem; } @@ -1126,7 +1126,7 @@ body.linter-disabled .hidden-unless-compact { .options-column > .usercss-only { margin-bottom: 0; } - #options-wrapper .options-column:nth-child(2) { + #options-wrapper .options-column:nth-child(n + 2) { margin-top: 0; } #options:not([open]), diff --git a/edit/edit.js b/edit/edit.js index 19a94ac7..eda76e9b 100644 --- a/edit/edit.js +++ b/edit/edit.js @@ -4,6 +4,7 @@ /* global SectionsEditor */ /* global SourceEditor */ /* global baseInit */ +/* global chromeSync */// storage-util.js /* global clipString createHotkeyInput helpPopup */// util.js /* global closeCurrentTab deepEqual sessionStore tryJSONparse */// toolbox.js /* global cmFactory */ @@ -16,7 +17,10 @@ //#region init baseInit.ready.then(async () => { - await waitForSheet(); + [editor.template] = await Promise.all([ + editor.isUsercss && !editor.style.id && chromeSync.getLZValue(chromeSync.LZ_KEY.usercssTemplate), + waitForSheet(), + ]); (editor.isUsercss ? SourceEditor : SectionsEditor)(); await editor.ready; editor.ready = true; diff --git a/edit/source-editor.js b/edit/source-editor.js index 5683c519..b9ce6c66 100644 --- a/edit/source-editor.js +++ b/edit/source-editor.js @@ -17,20 +17,19 @@ function SourceEditor() { const {style, /** @type DirtyReporter */dirty} = editor; let savedGeneration; - let placeholderName = ''; let prevMode = NaN; $$remove('.sectioned-only'); $('#header').on('wheel', headerOnScroll); $('#sections').textContent = ''; $('#sections').appendChild($create('.single-editor')); - - if (!style.id) setupNewStyle(style); + $('[i18n-text="saveAsTemplate"]').onclick = saveTemplate; const cm = cmFactory.create($('.single-editor')); const sectionFinder = MozSectionFinder(cm); const sectionWidget = MozSectionWidget(cm, sectionFinder); editor.livePreview.init(preprocess); + if (!style.id) setupNewStyle(); createMetaCompiler(meta => { style.usercssData = meta; style.name = meta.name; @@ -75,13 +74,7 @@ function SourceEditor() { } showLog(res); } catch (err) { - const i = err.index; - const isNameEmpty = i > 0 && - err.code === 'missingValue' && - sourceCode.slice(sourceCode.lastIndexOf('\n', i - 1), i).trim().endsWith('@name'); - return isNameEmpty - ? saveTemplate(sourceCode) - : showSaveError(err); + showSaveError(err); } }, scrollToEditor: () => {}, @@ -160,7 +153,7 @@ function SourceEditor() { return name; } - async function setupNewStyle(style) { + function setupNewStyle() { style.sections[0].code = ' '.repeat(prefs.get('editor.tabSize')) + `/* ${t('usercssReplaceTemplateSectionBody')} */`; let section = MozDocMapper.styleToCss(style); @@ -177,17 +170,11 @@ function SourceEditor() { @author Me ==/UserStyle== */ `.replace(/^\s+/gm, ''); - - dirty.clear('sourceGeneration'); - style.sourceCode = ''; - - placeholderName = `${style.name || t('usercssReplaceTemplateName')} - ${new Date().toLocaleString()}`; - let code = await chromeSync.getLZValue(chromeSync.LZ_KEY.usercssTemplate); - code = code || DEFAULT_CODE; - code = code.replace(/@name(\s*)(?=[\r\n])/, (str, space) => - `${str}${space ? '' : ' '}${placeholderName}`); + style.name = [style.name, new Date().toLocaleString()].filter(Boolean).join(' - '); // strip the last dummy section if any, add an empty line followed by the section - style.sourceCode = code.replace(/\s*@-moz-document[^{]*{[^}]*}\s*$|\s+$/g, '') + '\n\n' + section; + style.sourceCode = (editor.template || DEFAULT_CODE) + .replace(/(@name)(?:([\t\x20]+).*|\n)/, (_, k, space) => `${k}${space || ' '}${style.name}`) + .replace(/\s*@-moz-document[^{]*{[^}]*}\s*$|\s+$/g, '') + '\n\n' + section; cm.startOperation(); cm.setValue(style.sourceCode); cm.clearHistory(); @@ -199,9 +186,7 @@ function SourceEditor() { function updateMeta() { const name = style.customName || style.name; - if (name !== placeholderName) { - $('#name').value = name; - } + $('#name').value = name; $('#enabled').checked = style.enabled; $('#url').href = style.url; editor.updateName(); @@ -236,9 +221,10 @@ function SourceEditor() { } } - async function saveTemplate(code) { + async function saveTemplate() { if (await messageBoxProxy.confirm(t('usercssReplaceTemplateConfirmation'))) { const key = chromeSync.LZ_KEY.usercssTemplate; + const code = cm.getValue(); await chromeSync.setLZValue(key, code); if (await chromeSync.getLZValue(key) !== code) { messageBoxProxy.alert(t('syncStorageErrorSaving')); diff --git a/js/localization.js b/js/localization.js index b413e255..b34497eb 100644 --- a/js/localization.js +++ b/js/localization.js @@ -73,7 +73,6 @@ Object.assign(t, { if (toInsert) { node.insertBefore(toInsert, before || null); } - node.removeAttribute(name); } } },