From fb7de8d7b04339abcd537751d655893cc1764cbc Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 26 Jan 2022 14:08:37 +0000 Subject: [PATCH 1/3] Load light theme prior to HTML export to ensure it is present --- src/utils/exportUtils/exportCSS.ts | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/utils/exportUtils/exportCSS.ts b/src/utils/exportUtils/exportCSS.ts index ceafed174b4..39268fe2e8f 100644 --- a/src/utils/exportUtils/exportCSS.ts +++ b/src/utils/exportUtils/exportCSS.ts @@ -16,6 +16,8 @@ limitations under the License. /* eslint-disable max-len, camelcase */ +import { defer } from "matrix-js-sdk/src/utils"; + import customCSS from "!!raw-loader!./exportCustomCSS.css"; const cssSelectorTextClassesRegex = /\.[\w-]+/g; @@ -34,15 +36,35 @@ function mutateCssText(css: string): string { ); } +function isLightTheme(sheet: CSSStyleSheet): boolean { + return (sheet.ownerNode).dataset.mxTheme?.toLowerCase() === "light"; +} + // naively culls unused css rules based on which classes are present in the html, // doesn't cull rules which won't apply due to the full selector not matching but gets rid of a LOT of cruft anyway. const getExportCSS = async (usedClasses: Set): Promise => { + const lightTheme = document.querySelector('link[rel=stylesheet][data-mx-theme="light" i]'); + let mustDisableLightTheme = false; + // if the light theme isn't currently enabled then we need to have the browser download it before we can proceed. + if (lightTheme?.disabled) { + lightTheme.disabled = false; + if (!Array.from(document.styleSheets).some(isLightTheme)) { + const deferred = defer(); + lightTheme.onload = deferred.resolve.bind(deferred.promise); + await deferred.promise; + } + mustDisableLightTheme = true; + } + // only include bundle.css and the data-mx-theme=light styling const stylesheets = Array.from(document.styleSheets).filter(s => { - return s.href?.endsWith("bundle.css") || - (s.ownerNode as HTMLStyleElement).dataset.mxTheme?.toLowerCase() === "light"; + return s.href?.endsWith("bundle.css") || isLightTheme(s); }); + if (mustDisableLightTheme) { + lightTheme.disabled = true; + } + let css = ""; for (const stylesheet of stylesheets) { for (const rule of stylesheet.cssRules) { From 7c1704e35fc9d56d750467a5402b80167bcde93f Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 26 Jan 2022 14:23:29 +0000 Subject: [PATCH 2/3] Save a variable --- src/utils/exportUtils/exportCSS.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/utils/exportUtils/exportCSS.ts b/src/utils/exportUtils/exportCSS.ts index 39268fe2e8f..ac1a75e14fe 100644 --- a/src/utils/exportUtils/exportCSS.ts +++ b/src/utils/exportUtils/exportCSS.ts @@ -44,16 +44,15 @@ function isLightTheme(sheet: CSSStyleSheet): boolean { // doesn't cull rules which won't apply due to the full selector not matching but gets rid of a LOT of cruft anyway. const getExportCSS = async (usedClasses: Set): Promise => { const lightTheme = document.querySelector('link[rel=stylesheet][data-mx-theme="light" i]'); - let mustDisableLightTheme = false; + const isLightDisabled = lightTheme?.disabled; // if the light theme isn't currently enabled then we need to have the browser download it before we can proceed. - if (lightTheme?.disabled) { + if (isLightDisabled) { lightTheme.disabled = false; if (!Array.from(document.styleSheets).some(isLightTheme)) { const deferred = defer(); lightTheme.onload = deferred.resolve.bind(deferred.promise); await deferred.promise; } - mustDisableLightTheme = true; } // only include bundle.css and the data-mx-theme=light styling @@ -61,7 +60,7 @@ const getExportCSS = async (usedClasses: Set): Promise => { return s.href?.endsWith("bundle.css") || isLightTheme(s); }); - if (mustDisableLightTheme) { + if (isLightDisabled) { lightTheme.disabled = true; } From 73342c1cc1273fe21b0b6c90451a0520e56c717b Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 26 Jan 2022 15:56:38 +0000 Subject: [PATCH 3/3] Slightly less grotesque solution to the missing theme data issue --- src/utils/exportUtils/exportCSS.ts | 34 ++++++++++++++---------------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/utils/exportUtils/exportCSS.ts b/src/utils/exportUtils/exportCSS.ts index ac1a75e14fe..b85c2a9431a 100644 --- a/src/utils/exportUtils/exportCSS.ts +++ b/src/utils/exportUtils/exportCSS.ts @@ -14,10 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -/* eslint-disable max-len, camelcase */ - -import { defer } from "matrix-js-sdk/src/utils"; - import customCSS from "!!raw-loader!./exportCustomCSS.css"; const cssSelectorTextClassesRegex = /\.[\w-]+/g; @@ -40,28 +36,30 @@ function isLightTheme(sheet: CSSStyleSheet): boolean { return (sheet.ownerNode).dataset.mxTheme?.toLowerCase() === "light"; } +async function getRulesFromCssFile(path: string): Promise { + const doc = document.implementation.createHTMLDocument(""); + const styleElement = document.createElement("style"); + + const res = await fetch(path); + styleElement.textContent = await res.text(); + // the style will only be parsed once it is added to a document + doc.body.appendChild(styleElement); + + return styleElement.sheet; +} + // naively culls unused css rules based on which classes are present in the html, // doesn't cull rules which won't apply due to the full selector not matching but gets rid of a LOT of cruft anyway. const getExportCSS = async (usedClasses: Set): Promise => { - const lightTheme = document.querySelector('link[rel=stylesheet][data-mx-theme="light" i]'); - const isLightDisabled = lightTheme?.disabled; - // if the light theme isn't currently enabled then we need to have the browser download it before we can proceed. - if (isLightDisabled) { - lightTheme.disabled = false; - if (!Array.from(document.styleSheets).some(isLightTheme)) { - const deferred = defer(); - lightTheme.onload = deferred.resolve.bind(deferred.promise); - await deferred.promise; - } - } - // only include bundle.css and the data-mx-theme=light styling const stylesheets = Array.from(document.styleSheets).filter(s => { return s.href?.endsWith("bundle.css") || isLightTheme(s); }); - if (isLightDisabled) { - lightTheme.disabled = true; + // If the light theme isn't loaded we will have to fetch & parse it manually + if (!stylesheets.some(isLightTheme)) { + const href = document.querySelector('link[rel="stylesheet"][href$="theme-light.css"]').href; + stylesheets.push(await getRulesFromCssFile(href)); } let css = "";