single-file-core 1.5.25 → 1.5.27

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/core/helper.js CHANGED
@@ -233,7 +233,7 @@ function preProcessDoc(doc, win, options) {
233
233
  };
234
234
  }
235
235
 
236
- function getElementsInfo(win, doc, element, options, data = { usedFonts: new Map(), canvases: [], images: [], posters: [], videos: [], shadowRoots: [], markedElements: [] }, ascendantHidden) {
236
+ function getElementsInfo(win, doc, element, options, data = { usedFonts: new Map(), canvases: [], images: [], posters: [], videos: [], shadowRoots: [], markedElements: [] }, adoptedStyleSheetsCache = new Map(), ascendantHidden) {
237
237
  if (element.childNodes) {
238
238
  const elements = Array.from(element.childNodes).filter(node => (node instanceof win.HTMLElement) || (node instanceof win.SVGElement) || (node instanceof globalThis.HTMLElement) || (node instanceof globalThis.SVGElement));
239
239
  elements.forEach(element => {
@@ -278,7 +278,7 @@ function getElementsInfo(win, doc, element, options, data = { usedFonts: new Map
278
278
  try {
279
279
  if (shadowRoot.adoptedStyleSheets) {
280
280
  if (shadowRoot.adoptedStyleSheets.length) {
281
- shadowRootInfo.adoptedStyleSheets = getStylesheetsContent(shadowRoot.adoptedStyleSheets);
281
+ shadowRootInfo.adoptedStyleSheets = getStylesheetsContent(shadowRoot.adoptedStyleSheets, adoptedStyleSheetsCache);
282
282
  } else if (shadowRoot.adoptedStyleSheets.length === undefined) {
283
283
  const listener = event => shadowRootInfo.adoptedStyleSheets = event.detail.adoptedStyleSheets;
284
284
  shadowRoot.addEventListener(GET_ADOPTED_STYLESHEETS_RESPONSE_EVENT, listener);
@@ -292,7 +292,7 @@ function getElementsInfo(win, doc, element, options, data = { usedFonts: new Map
292
292
  } catch (error) {
293
293
  // ignored
294
294
  }
295
- getElementsInfo(win, doc, shadowRoot, options, data, elementHidden);
295
+ getElementsInfo(win, doc, shadowRoot, options, data, adoptedStyleSheetsCache, elementHidden);
296
296
  shadowRootInfo.content = shadowRoot.innerHTML;
297
297
  shadowRootInfo.mode = shadowRoot.mode;
298
298
  shadowRootInfo.delegateFocus = shadowRoot.delegatesFocus;
@@ -306,7 +306,7 @@ function getElementsInfo(win, doc, element, options, data = { usedFonts: new Map
306
306
  // ignored
307
307
  }
308
308
  }
309
- getElementsInfo(win, doc, element, options, data, elementHidden);
309
+ getElementsInfo(win, doc, element, options, data, adoptedStyleSheetsCache, elementHidden);
310
310
  if (!options.autoSaveExternalSave && options.removeHiddenElements && ascendantHidden) {
311
311
  if (elementKept || element.getAttribute(KEPT_CONTENT_ATTRIBUTE_NAME) == "") {
312
312
  if (element.parentElement) {
@@ -323,8 +323,27 @@ function getElementsInfo(win, doc, element, options, data = { usedFonts: new Map
323
323
  return data;
324
324
  }
325
325
 
326
- function getStylesheetsContent(styleSheets) {
327
- return styleSheets ? Array.from(styleSheets).map(stylesheet => Array.from(stylesheet.cssRules).map(cssRule => cssRule.cssText).join("\n")) : [];
326
+ function getStylesheetsContent(styleSheets, adoptedStyleSheetsCache = new Map()) {
327
+ if (styleSheets) {
328
+ const result = [];
329
+ for (const styleSheet of Array.from(styleSheets)) {
330
+ if (adoptedStyleSheetsCache.has(styleSheet)) {
331
+ result.push(adoptedStyleSheetsCache.get(styleSheet));
332
+ } else {
333
+ let cssText = "";
334
+ if (styleSheet && styleSheet.cssRules) {
335
+ for (const cssRule of styleSheet.cssRules) {
336
+ cssText += cssRule.cssText + "\n";
337
+ }
338
+ }
339
+ adoptedStyleSheetsCache.set(styleSheet, cssText);
340
+ result.push(cssText);
341
+ }
342
+ }
343
+ return result;
344
+ } else {
345
+ return [];
346
+ }
328
347
  }
329
348
 
330
349
  function getResourcesInfo(win, doc, element, options, data, elementHidden, computedStyle) {
@@ -113,21 +113,21 @@ function getProcessorHelperClass(utilInstance) {
113
113
  const stylesheetInfo = stylesheets.get(styleElement);
114
114
  if (stylesheetInfo) {
115
115
  stylesheets.delete(styleElement);
116
- const styleSheetRefIndex = options.inlineStylesheetsRefs.get(styleElement);
117
- if (styleSheetRefIndex === undefined) {
116
+ const stylesheetRefIndex = options.inlineStylesheetsRefs.get(styleElement);
117
+ if (stylesheetRefIndex === undefined) {
118
118
  styleElement.textContent = this.generateStylesheetContent(stylesheetInfo.stylesheet, options);
119
119
  } else if (options.groupDuplicateStylesheets) {
120
- if (!doc.querySelector("style[" + DUPLICATE_STYLESHEET_ATTRIBUTE_NAME + "=\"" + styleSheetRefIndex + "\"]")) {
120
+ if (!doc.querySelector("style[" + DUPLICATE_STYLESHEET_ATTRIBUTE_NAME + "=\"" + stylesheetRefIndex + "\"]")) {
121
121
  const styleElement = doc.createElement("style");
122
- styleElement.textContent = options.inlineStylesheets.get(styleSheetRefIndex);
122
+ styleElement.textContent = options.inlineStylesheets.get(stylesheetRefIndex);
123
123
  styleElement.setAttribute("media", "not all");
124
- styleElement.setAttribute(DUPLICATE_STYLESHEET_ATTRIBUTE_NAME, styleSheetRefIndex);
124
+ styleElement.setAttribute(DUPLICATE_STYLESHEET_ATTRIBUTE_NAME, stylesheetRefIndex);
125
125
  doc.head.appendChild(styleElement);
126
126
  }
127
127
  styleElement.textContent = "/* */";
128
- styleElement.setAttribute("onload", "this.textContent=document.querySelector('style[" + DUPLICATE_STYLESHEET_ATTRIBUTE_NAME + "=\"" + styleSheetRefIndex + "\"]').textContent;this.removeAttribute(\"onload\")");
128
+ styleElement.setAttribute("onload", "this.textContent=document.querySelector('style[" + DUPLICATE_STYLESHEET_ATTRIBUTE_NAME + "=\"" + stylesheetRefIndex + "\"]').textContent;this.removeAttribute(\"onload\")");
129
129
  } else {
130
- styleElement.textContent = options.inlineStylesheets.get(styleSheetRefIndex);
130
+ styleElement.textContent = options.inlineStylesheets.get(stylesheetRefIndex);
131
131
  }
132
132
  if (stylesheetInfo.mediaText) {
133
133
  styleElement.media = stylesheetInfo.mediaText;
@@ -76,27 +76,38 @@ function getProcessorHelperClass(utilInstance) {
76
76
  }
77
77
 
78
78
  async resolveStylesheetElement(element, stylesheetInfo, stylesheets, baseURI, options, workStyleElement, resources) {
79
- if (!options.inlineStylesheetsRefs.has(element)) {
80
- if (!options.blockStylesheets) {
81
- stylesheets.set({ element }, stylesheetInfo);
79
+ if (!options.blockStylesheets) {
80
+ stylesheets.set({ element }, stylesheetInfo);
81
+ if (!options.inlineStylesheetsRefs.has(element)) {
82
82
  if (element.tagName.toUpperCase() == "LINK") {
83
83
  await this.resolveLinkStylesheetURLs(stylesheetInfo, element, element.href, baseURI, options, workStyleElement, resources, stylesheets);
84
84
  } else {
85
85
  stylesheetInfo.stylesheet = cssTree.parse(element.textContent, { context: "stylesheet", parseCustomProperty: true });
86
86
  await this.resolveImportURLs(stylesheetInfo, baseURI, options, workStyleElement, resources, stylesheets);
87
87
  }
88
+ }
89
+ } else {
90
+ if (element.tagName.toUpperCase() == "LINK") {
91
+ element.href = util.EMPTY_RESOURCE;
88
92
  } else {
89
- if (element.tagName.toUpperCase() == "LINK") {
90
- element.href = util.EMPTY_RESOURCE;
91
- } else {
92
- element.textContent = "";
93
- }
93
+ element.textContent = "";
94
94
  }
95
95
  }
96
96
  }
97
97
 
98
98
  replaceStylesheets(doc, stylesheets, options, resources) {
99
99
  const entries = Array.from(stylesheets).reverse();
100
+ const linkElements = new Map();
101
+ Array.from(new Set(options.inlineStylesheetsRefs.values())).forEach(stylesheetRefIndex => {
102
+ const linkElement = doc.createElement("link");
103
+ linkElement.setAttribute("rel", "stylesheet");
104
+ linkElement.setAttribute("type", "text/css");
105
+ const name = "stylesheet_" + resources.stylesheets.size + ".css";
106
+ linkElement.setAttribute("href", name);
107
+ const content = options.inlineStylesheets.get(stylesheetRefIndex);
108
+ resources.stylesheets.set(resources.stylesheets.size, { name, content });
109
+ linkElements.set(stylesheetRefIndex, linkElement);
110
+ });
100
111
  for (const [key, stylesheetInfo] of entries) {
101
112
  if (key.urlNode) {
102
113
  const name = "stylesheet_" + resources.stylesheets.size + ".css";
@@ -105,27 +116,29 @@ function getProcessorHelperClass(utilInstance) {
105
116
  } else {
106
117
  key.urlNode.value = name;
107
118
  }
108
- resources.stylesheets.set(resources.stylesheets.size, { name, stylesheet: stylesheetInfo.stylesheet });
119
+ resources.stylesheets.set(resources.stylesheets.size, { name, stylesheet: stylesheetInfo.stylesheet, url: stylesheetInfo.url });
120
+ } else if (key.element.tagName.toUpperCase() == "LINK") {
121
+ const linkElement = key.element;
122
+ const name = "stylesheet_" + resources.stylesheets.size + ".css";
123
+ linkElement.setAttribute("href", name);
124
+ resources.stylesheets.set(resources.stylesheets.size, { name, stylesheet: stylesheetInfo.stylesheet, url: stylesheetInfo.url });
109
125
  } else {
110
- if (key.element.tagName.toUpperCase() == "LINK") {
111
- const linkElement = key.element;
112
- const name = "stylesheet_" + resources.stylesheets.size + ".css";
113
- linkElement.setAttribute("href", name);
114
- resources.stylesheets.set(resources.stylesheets.size, { name, stylesheet: stylesheetInfo.stylesheet });
126
+ const styleElement = key.element;
127
+ const stylesheetRefIndex = options.inlineStylesheetsRefs.get(styleElement);
128
+ if (stylesheetRefIndex === undefined) {
129
+ styleElement.textContent = this.generateStylesheetContent(stylesheetInfo.stylesheet, options);
115
130
  } else {
116
- const styleElement = key.element;
117
- const styleSheetRefIndex = options.inlineStylesheetsRefs.get(styleElement);
118
- if (styleSheetRefIndex === undefined) {
119
- styleElement.textContent = this.generateStylesheetContent(stylesheetInfo.stylesheet, options);
120
- } else {
121
- styleElement.textContent = options.inlineStylesheets.get(styleSheetRefIndex);
122
- }
131
+ const linkElement = linkElements.get(stylesheetRefIndex).cloneNode(true);
132
+ styleElement.replaceWith(linkElement);
133
+ key.element = linkElement;
123
134
  }
124
135
  }
125
136
  }
126
137
  for (const [, stylesheetResource] of resources.stylesheets) {
127
- stylesheetResource.content = this.generateStylesheetContent(stylesheetResource.stylesheet, options);
128
- stylesheetResource.stylesheet = null;
138
+ if (stylesheetResource.stylesheet) {
139
+ stylesheetResource.content = this.generateStylesheetContent(stylesheetResource.stylesheet, options);
140
+ stylesheetResource.stylesheet = null;
141
+ }
129
142
  }
130
143
  }
131
144
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "single-file-core",
3
- "version": "1.5.25",
3
+ "version": "1.5.27",
4
4
  "description": "SingleFile Core",
5
5
  "author": "Gildas Lormeau",
6
6
  "license": "AGPL-3.0-or-later",
@@ -51,6 +51,7 @@
51
51
  const DELETE_FONT_EVENT = "single-file-delete-font";
52
52
  const CLEAR_FONTS_EVENT = "single-file-clear-fonts";
53
53
  const NEW_WORKLET_EVENT = "single-file-new-worklet";
54
+ const BOOTSTRAP_EVENT = "single-file-bootstrap";
54
55
  const FONT_STYLE_PROPERTIES = {
55
56
  family: "font-family",
56
57
  style: "font-style",
@@ -149,6 +150,11 @@
149
150
  document.dispatchEvent(new CustomEvent(FETCH_RESPONSE_EVENT, { detail }));
150
151
  });
151
152
  document.addEventListener(GET_ADOPTED_STYLESHEETS_REQUEST_EVENT, getAdoptedStylesheetsListener);
153
+ document.addEventListener(BOOTSTRAP_EVENT, event => {
154
+ if (globalThis.bootstrap && event.detail.data) {
155
+ globalThis.bootstrap(event.detail.data);
156
+ }
157
+ });
152
158
  }
153
159
 
154
160
  function loadDeferredImagesStart(keepZoomLevel) {