seemore 1.12.5 → 1.12.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/app/export/exportPage.ts +29 -5
package/package.json
CHANGED
|
@@ -57,7 +57,23 @@ function waitFor(predicate: () => boolean, timeoutMs: number): Promise<void> {
|
|
|
57
57
|
* reloads); the build ships a single hashed stylesheet link. Same-origin sheets are inlined
|
|
58
58
|
* — a `file://` page cannot fetch them — and a sheet that is genuinely remote stays linked,
|
|
59
59
|
* the same treaty as remote images.
|
|
60
|
+
*
|
|
61
|
+
* Every `<style>` is taken, not just the framework's: diagram libraries (Mermaid, D2) and
|
|
62
|
+
* Radix inject their own rules at runtime with no marker to select them by, and the export
|
|
63
|
+
* needs those. The two exceptions are the highlight rule (installed per-navigation, and
|
|
64
|
+
* meaningless in a static file) and any sheet a browser extension injected into the page —
|
|
65
|
+
* the latter is not the page's, would not load from a file anyway, and can run to hundreds
|
|
66
|
+
* of kilobytes; it is spotted by the `chrome-extension:`/`moz-extension:` URLs it carries.
|
|
67
|
+
*/
|
|
68
|
+
/**
|
|
69
|
+
* A stylesheet a browser extension put on the page, told apart by the extension-only URL
|
|
70
|
+
* scheme it loads its own assets from. Deliberately narrow: it must never match a rule the
|
|
71
|
+
* site or a library authored, since a false positive silently drops real styling.
|
|
60
72
|
*/
|
|
73
|
+
function isExtensionCss(text: string): boolean {
|
|
74
|
+
return /\b(?:chrome-extension|moz-extension):\/\//i.test(text);
|
|
75
|
+
}
|
|
76
|
+
|
|
61
77
|
async function collectCss(): Promise<{ css: string; remoteLinks: string }> {
|
|
62
78
|
const seen = new Set<string>();
|
|
63
79
|
const parts: string[] = [];
|
|
@@ -67,7 +83,7 @@ async function collectCss(): Promise<{ css: string; remoteLinks: string }> {
|
|
|
67
83
|
// The highlight rule is installed per-navigation and means nothing in a static file.
|
|
68
84
|
if (style.id === 'seemore-highlight-style') continue;
|
|
69
85
|
const text = style.textContent ?? '';
|
|
70
|
-
if (text.trim() === '' || seen.has(text)) continue;
|
|
86
|
+
if (text.trim() === '' || seen.has(text) || isExtensionCss(text)) continue;
|
|
71
87
|
seen.add(text);
|
|
72
88
|
parts.push(text);
|
|
73
89
|
}
|
|
@@ -80,7 +96,9 @@ async function collectCss(): Promise<{ css: string; remoteLinks: string }> {
|
|
|
80
96
|
continue;
|
|
81
97
|
}
|
|
82
98
|
if (url.origin !== location.origin) {
|
|
83
|
-
|
|
99
|
+
// An extension's own sheet (`chrome-extension://…`) is not the page's and would not
|
|
100
|
+
// load in the file anyway; only a genuinely remote http(s) sheet stays linked.
|
|
101
|
+
if (url.protocol === 'http:' || url.protocol === 'https:') remote.push(link.outerHTML);
|
|
84
102
|
continue;
|
|
85
103
|
}
|
|
86
104
|
const text = await fetch(url.href)
|
|
@@ -384,11 +402,17 @@ const RUNTIME = `(function () {
|
|
|
384
402
|
});
|
|
385
403
|
})();`;
|
|
386
404
|
|
|
405
|
+
/** The root attributes that still mean something once the page is a standalone file. */
|
|
406
|
+
const KEPT_ROOT_ATTRIBUTES = new Set(['lang', 'dir', 'class']);
|
|
407
|
+
|
|
387
408
|
function buildExportHtml(article: Element, css: string, remoteLinks: string, favicons: string): string {
|
|
388
|
-
//
|
|
389
|
-
// class next-themes resolved for *this* screen
|
|
390
|
-
// own OS when the file is opened.
|
|
409
|
+
// Only the root attributes that mean something in a standalone file ride along: lang,
|
|
410
|
+
// dir, and class minus the theme class next-themes resolved for *this* screen — THEME_INIT
|
|
411
|
+
// sets that from the reader's own OS when the file is opened. The rest of the live root is
|
|
412
|
+
// state for this screen (next-themes' `style="color-scheme: …"`, the sidebar's collapse
|
|
413
|
+
// flag) or was put there by a browser extension. An emptied class attribute is dropped.
|
|
391
414
|
const attrs = Array.from(document.documentElement.attributes)
|
|
415
|
+
.filter((attr) => KEPT_ROOT_ATTRIBUTES.has(attr.name))
|
|
392
416
|
.map((attr) => {
|
|
393
417
|
if (attr.name !== 'class') return { name: attr.name, value: attr.value };
|
|
394
418
|
const kept = attr.value
|