From d2c930a94d6e445053bcb5e5bb629851165425fc Mon Sep 17 00:00:00 2001 From: StefanVukovic99 Date: Thu, 20 Jun 2024 19:27:02 +0200 Subject: support css file in dictionaries (#1080) * get styles in db * get styles in settings * use styles * fix test * scope * fix comma separated * escape dict name in css selector * g regex * get styles in anki * fix tests * more specificity * whitespace * test importing * test handlebars * add styles to glossary-first --- ext/js/display/display-anki.js | 21 +++++++++++++++++++++ ext/js/display/display.js | 38 +++++++++++++++++++++++++++++++++++--- 2 files changed, 56 insertions(+), 3 deletions(-) (limited to 'ext/js/display') diff --git a/ext/js/display/display-anki.js b/ext/js/display/display-anki.js index fa82a7b6..68a6654c 100644 --- a/ext/js/display/display-anki.js +++ b/ext/js/display/display-anki.js @@ -91,6 +91,8 @@ export class DisplayAnki { this._noteTags = []; /** @type {Map} */ this._modeOptions = new Map(); + /** @type {import('settings').DictionariesOptions} */ + this._dictionaries = []; /** @type {Map} */ this._dictionaryEntryTypeModeMap = new Map([ ['kanji', ['kanji']], @@ -147,6 +149,7 @@ export class DisplayAnki { glossaryLayoutMode: this._glossaryLayoutMode, compactTags: this._compactTags, marker: 'test', + dictionaryStylesMap: this._getDictionaryStylesMap(), }); } catch (e) { ankiNoteDataException = e; @@ -191,6 +194,7 @@ export class DisplayAnki { _onOptionsUpdated({options}) { const { general: {resultOutputMode, glossaryLayoutMode, compactTags}, + dictionaries, anki: { tags, duplicateScope, @@ -227,6 +231,7 @@ export class DisplayAnki { this._modeOptions.set('kanji', kanji); this._modeOptions.set('term-kanji', terms); this._modeOptions.set('term-kana', terms); + this._dictionaries = dictionaries; void this._updateAnkiFieldTemplates(options); } @@ -808,6 +813,7 @@ export class DisplayAnki { const details = this._ankiNoteBuilder.getDictionaryEntryDetailsForNote(dictionaryEntry); const audioDetails = this._getAnkiNoteMediaAudioDetails(details); const optionsContext = this._display.getOptionsContext(); + const dictionaryStylesMap = this._getDictionaryStylesMap(); const {note, errors, requirements: outputRequirements} = await this._ankiNoteBuilder.createNote({ dictionaryEntry, @@ -836,10 +842,25 @@ export class DisplayAnki { }, }, requirements, + dictionaryStylesMap, }); return {note, errors, requirements: outputRequirements}; } + /** + * @returns {Map} + */ + _getDictionaryStylesMap() { + const styleMap = new Map(); + for (const dictionary of this._dictionaries) { + const {name, styles} = dictionary; + if (typeof styles === 'string') { + styleMap.set(name, styles); + } + } + return styleMap; + } + /** * @param {boolean} isTerms * @returns {import('display-anki').CreateMode[]} diff --git a/ext/js/display/display.js b/ext/js/display/display.js index 6b3838e5..ebd11e0a 100644 --- a/ext/js/display/display.js +++ b/ext/js/display/display.js @@ -1152,7 +1152,7 @@ export class Display extends EventDispatcher { */ _setTheme(options) { const {general} = options; - const {popupTheme} = general; + const {popupTheme, popupOuterTheme} = general; /** @type {string} */ let pageType = this._pageType; try { @@ -1169,10 +1169,42 @@ export class Display extends EventDispatcher { log.error(e); } this._themeController.theme = popupTheme; - this._themeController.outerTheme = general.popupOuterTheme; + this._themeController.outerTheme = popupOuterTheme; this._themeController.siteOverride = pageType === 'search' || pageType === 'popupPreview'; this._themeController.updateTheme(); - this.setCustomCss(general.customPopupCss); + const customCss = this._getCustomCss(options); + this.setCustomCss(customCss); + } + + /** + * @param {import('settings').ProfileOptions} options + * @returns {string} + */ + _getCustomCss(options) { + const {general: {customPopupCss}, dictionaries} = options; + let customCss = customPopupCss; + for (const {name, enabled, styles = ''} of dictionaries) { + if (enabled) { + customCss += '\n' + this._addScopeToCss(styles, name); + } + } + this.setCustomCss(customCss); + return customCss; + } + + /** + * @param {string} css + * @param {string} dictionaryTitle + * @returns {string} + */ + _addScopeToCss(css, dictionaryTitle) { + const escapedTitle = dictionaryTitle + .replace(/\\/g, '\\\\') + .replace(/"/g, '\\"'); + + const regex = /([^\r\n,{}]+)(\s*[,{])/g; + const replacement = `[data-dictionary="${escapedTitle}"] $1$2`; + return css.replace(regex, replacement); } /** -- cgit v1.2.3