From 30e6bf178ce79867c2a43674541f139239bef6dd Mon Sep 17 00:00:00 2001 From: Peter Barnum Date: Wed, 28 Aug 2024 10:40:01 -0600 Subject: [PATCH] attach `injectStyles` object to window --- README.md | 8 +++++ injectStyles.js | 89 ++++++++++++++++++++++++++++++++++------------ test.html | 2 +- test/index.test.js | 5 +++ 4 files changed, 81 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 8fa8331..4f06668 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,14 @@ To include this package in your project, simply add the following to the ` defer > + ... + + ... ... diff --git a/injectStyles.js b/injectStyles.js index c50d37b..1ed8824 100644 --- a/injectStyles.js +++ b/injectStyles.js @@ -60,8 +60,14 @@ const cdn = { prism: 'https://cdnjs.cloudflare.com/ajax/libs/prism/9000.0.1/prism.min.js' }; +const scriptExists = src => { + const scripts = Array.from(document.querySelectorAll('script')); + return scripts.some(el => el.src === src); +}; + const appendScript = async src => { if (!src) return console.error('No script provided'); + if (scriptExists(src)) return; try { await new Promise((resolve, reject) => { const script = document.createElement('script'); @@ -113,6 +119,11 @@ const highlightBlocks = () => { preBlocks.forEach(preBlock => { const $code = preBlock.querySelector('code'); + + const classList = [...preBlock.classList, ...($code?.classList ?? [])]; + // Already highlighted + if (classList.includes('language-javascript')) return; + if (!$code?.textContent) return; $code.className = 'language-javascript'; @@ -235,39 +246,73 @@ const appendCopyButton = el => { const init = async () => { const darkMode = window.matchMedia('(prefers-color-scheme: dark)'); - darkMode.addEventListener('change', async e => { - await replaceStyles(e.matches); - }); + darkMode.addEventListener('change', e => replaceStyles(e.matches)); - await replaceStyles(darkMode.matches); + replaceStyles(darkMode.matches); highlightDescriptions(); - highlightBlocks(); + setTimeout(highlightBlocks, 0); document.querySelectorAll('li h2').forEach(appendCopyButton); }; -(async () => { - await appendScript(cdn.prism); - await appendScript(cdn.javascript); - await appendScript(cdn.markdown); - - const existingWinLoad = window.onload; - - window.onload = async () => { +const load = cb => { + return () => { updateFavicon(); - // @ts-expect-error - existingWinLoad?.(); + + cb?.(); var afterTest = window['after'] || window['afterAll'] || (fn => setTimeout(fn, 0)); - afterTest(() => { - init(); - }); - - if (scriptConfig.runMocha && typeof mocha !== 'undefined') { - // mocha.setup('bdd'); - mocha.run(updateFavicon); + afterTest(init); + + if ( + scriptConfig.runMocha && + typeof mocha !== 'undefined' && + // @ts-expect-error - _state exists on mocha if defined + mocha._state !== 'running' + ) { + try { + mocha.setup('bdd'); + mocha.run(updateFavicon); + } catch (err) { + console.error( + 'Mocha instance already running. If you did not intend to have mocha run automatically [mocha.run()] and instead are running manually in the app, remove the `runMocha` attribute from the script tag.' + ); + } } }; +}; + +/** + * @typedef {{ + * init: () => void; + * load: (cb?: () => void) => () => void; + * updateFavicon: (failures?: number) => void; + * appendCopyButton: (el: HTMLElement) => void; + * highlightDescriptions: () => void; + * highlightBlocks: () => void; + * start: (failures?: number) => void; + * }} InjectStyles + */ + +/** @type {InjectStyles} */ +var injectStyles = { + init, + load, + updateFavicon, + appendCopyButton, + highlightDescriptions, + highlightBlocks, + start: failures => load(() => updateFavicon(failures))() +}; + +(async () => { + await appendScript(cdn.prism); + await appendScript(cdn.javascript); + await appendScript(cdn.markdown); + + window.onload = load(window.onload); + + window['injectStyles'] = injectStyles; })(); diff --git a/test.html b/test.html index 43d6b45..1b2d3eb 100644 --- a/test.html +++ b/test.html @@ -11,7 +11,7 @@ - + diff --git a/test/index.test.js b/test/index.test.js index 69941df..8d6f5ab 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -1,7 +1,12 @@ /** @typedef {import('chai')} */ + + const expect = (window['expect'] = chai.expect); +mocha.setup('bdd'); +window.onload = () => mocha.run(injectStyles.start); + describe('Mocha CSS', function () { it('should have **correct** _color_ and background when in `light` and `dark` modes', () => { const media = window.matchMedia('(prefers-color-scheme: dark)');