diff --git a/ext/js/core/utilities.js b/ext/js/core/utilities.js index d40ec40ee..62f48793d 100644 --- a/ext/js/core/utilities.js +++ b/ext/js/core/utilities.js @@ -282,3 +282,36 @@ export function sanitizeCSS(css) { export function addScopeToCss(css, scopeSelector) { return scopeSelector + ' {' + css + '\n}'; } + +/** + * Older browser versions do not support nested css and cannot use the normal `addScopeToCss`. + * All major web browsers should be fine but Anki is still distributing Chromium 112 on some platforms as of Anki version 24.11. + * Chromium 120+ is required for full support. + * @param {string} css + * @param {string} scopeSelector + * @returns {string} + */ +export function addScopeToCssLegacy(css, scopeSelector) { + const stylesheet = new CSSStyleSheet(); + // nodejs must fall back to the normal version of the function + if (typeof stylesheet.replaceSync === 'undefined') { + return addScopeToCss(css, scopeSelector); + } + stylesheet.replaceSync(css); + const newCSSRules = []; + for (const cssRule of stylesheet.cssRules) { + // ignore non-style rules + if (!(cssRule instanceof CSSStyleRule)) { + continue; + } + + const newSelectors = []; + for (const selector of cssRule.selectorText.split(',')) { + newSelectors.push(scopeSelector + ' ' + selector); + } + const newRule = cssRule.cssText.replace(cssRule.selectorText, newSelectors.join(', ')); + newCSSRules.push(newRule); + } + stylesheet.replaceSync(newCSSRules.join('\n')); + return [...stylesheet.cssRules].map((rule) => rule.cssText || '').join('\n'); +} diff --git a/ext/js/data/anki-note-data-creator.js b/ext/js/data/anki-note-data-creator.js index 8c9c9c4f6..fae679b4c 100644 --- a/ext/js/data/anki-note-data-creator.js +++ b/ext/js/data/anki-note-data-creator.js @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -import {addScopeToCss} from '../core/utilities.js'; +import {addScopeToCssLegacy} from '../core/utilities.js'; import {getDisambiguations, getGroupedPronunciations, getPronunciationsOfType, getTermFrequency, groupTermTags} from '../dictionary/dictionary-data-util.js'; import {distributeFurigana, distributeFuriganaInflected} from '../language/ja/japanese.js'; @@ -584,7 +584,7 @@ function getTermDictionaryEntryCommonInfo(dictionaryEntry, type, dictionaryStyle * @returns {string} */ function addGlossaryScopeToCss(css) { - return addScopeToCss(css, '.yomitan-glossary'); + return addScopeToCssLegacy(css, '.yomitan-glossary'); } /** @@ -597,7 +597,7 @@ function addDictionaryScopeToCss(css, dictionaryTitle) { .replace(/\\/g, '\\\\') .replace(/"/g, '\\"'); - return addScopeToCss(css, `[data-dictionary="${escapedTitle}"]`); + return addScopeToCssLegacy(css, `[data-dictionary="${escapedTitle}"]`); } /**