|
|
@@ -99,13 +99,13 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
{ option: "insertFaviconLink", action: "insertFaviconLink" },
|
|
|
{ action: "replaceCanvasElements" },
|
|
|
{ action: "insertFonts" },
|
|
|
+ { action: "insertShadowRootContents" },
|
|
|
{ option: "removeHiddenElements", action: "removeHiddenElements" },
|
|
|
{ action: "resolveHrefs" },
|
|
|
{ action: "resolveStyleAttributeURLs" }
|
|
|
],
|
|
|
parallel: [
|
|
|
{ action: "resolveStylesheetURLs" },
|
|
|
- { action: "resolveShadowRootURLs" },
|
|
|
{ option: "!removeFrames", action: "resolveFrameURLs" },
|
|
|
{ option: "!removeImports", action: "resolveHtmlImportURLs" }
|
|
|
]
|
|
|
@@ -128,7 +128,6 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
],
|
|
|
parallel: [
|
|
|
{ option: "!removeFrames", action: "processFrames" },
|
|
|
- { action: "processShadowRoots" },
|
|
|
{ option: "!removeImports", action: "processHtmlImports" },
|
|
|
]
|
|
|
}, {
|
|
|
@@ -804,7 +803,11 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
if (element.media) {
|
|
|
mediaText = element.media.toLowerCase();
|
|
|
}
|
|
|
- this.stylesheets.set(element, { mediaText });
|
|
|
+ const stylesheetInfo = { mediaText };
|
|
|
+ this.stylesheets.set(element, stylesheetInfo);
|
|
|
+ if (element.closest("[" + WC_ATTRIBUTE_NAME + "]")) {
|
|
|
+ stylesheetInfo.scoped = true;
|
|
|
+ }
|
|
|
const options = { maxResourceSize: this.options.maxResourceSize, maxResourceSizeEnabled: this.options.maxResourceSizeEnabled, url: this.options.url, charset: this.charset, compressCSS: this.options.compressCSS };
|
|
|
let stylesheetContent;
|
|
|
if (element.tagName.toLowerCase() == "link") {
|
|
|
@@ -825,7 +828,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
if (this.options.compressCSS) {
|
|
|
ProcessorHelper.removeSingleLineCssComments(stylesheet);
|
|
|
}
|
|
|
- this.stylesheets.get(element).stylesheet = stylesheet;
|
|
|
+ stylesheetInfo.stylesheet = stylesheet;
|
|
|
} else {
|
|
|
this.stylesheets.delete(element);
|
|
|
}
|
|
|
@@ -877,44 +880,44 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- async resolveShadowRootURLs() {
|
|
|
- const rootOptions = this.options;
|
|
|
- const batchRequest = this.batchRequest;
|
|
|
+ insertShadowRootContents() {
|
|
|
+ const doc = this.doc;
|
|
|
+ const options = this.options;
|
|
|
if (this.options.shadowRootsData && this.options.shadowRootsData.length) {
|
|
|
- await resolveURLs(this.doc);
|
|
|
+ processElement(this.doc);
|
|
|
+ const scriptElement = doc.createElement("script");
|
|
|
+ scriptElement.setAttribute(WC_ATTRIBUTE_NAME, "");
|
|
|
+ scriptElement.textContent = `(()=>{processNode(document);function processNode(node){node.querySelectorAll("template[${WC_ATTRIBUTE_NAME}]").forEach(element=>{const shadowRoot=element.parentElement.attachShadow({mode:"open"});shadowRoot.innerHTML=element.innerHTML;element.remove();processNode(shadowRoot)})}})()`;
|
|
|
+ doc.body.appendChild(scriptElement);
|
|
|
}
|
|
|
|
|
|
- async function resolveURLs(rootElement) {
|
|
|
- const shadowRootElements = Array.from((rootElement.querySelectorAll("[" + docUtil.SHADOW_ROOT_ATTRIBUTE_NAME + "]")));
|
|
|
- await Promise.all(shadowRootElements.map(async element => {
|
|
|
+ function processElement(element) {
|
|
|
+ const shadowRootElements = Array.from((element.querySelectorAll("[" + docUtil.SHADOW_ROOT_ATTRIBUTE_NAME + "]")));
|
|
|
+ shadowRootElements.forEach(element => {
|
|
|
const id = element.getAttribute(docUtil.SHADOW_ROOT_ATTRIBUTE_NAME);
|
|
|
- const shadowRootData = rootOptions.shadowRootsData[Number(id)];
|
|
|
- const options = Object.create(rootOptions);
|
|
|
- options.insertSingleFileComment = false;
|
|
|
- options.insertFaviconLink = false;
|
|
|
- options.doc = null;
|
|
|
- options.win = null;
|
|
|
- options.url = options.baseURI = rootOptions.url;
|
|
|
- if (shadowRootData.content) {
|
|
|
- const doc = docUtil.parseDocContent(shadowRootData.content);
|
|
|
- const docData = docUtil.preProcessDoc(doc, options.win, options);
|
|
|
- options.content = docUtil.serialize(doc);
|
|
|
- docUtil.postProcessDoc(doc, options);
|
|
|
- options.postersData = docData.postersData;
|
|
|
- options.canvasData = docData.canvasData;
|
|
|
- options.stylesheetsData = docData.stylesheetsData;
|
|
|
- options.fontsData = docData.fontsData;
|
|
|
- options.imageData = docData.imageData;
|
|
|
- options.usedFonts = docData.usedFonts;
|
|
|
- options.shadowRootsData = docData.shadowRootsData;
|
|
|
- shadowRootData.processor = new Runner(options);
|
|
|
- shadowRootData.element = element;
|
|
|
- await shadowRootData.processor.loadPage();
|
|
|
- await shadowRootData.processor.initialize();
|
|
|
- shadowRootData.maxResources = batchRequest.getMaxResources();
|
|
|
- await resolveURLs(shadowRootData.processor.getDocument());
|
|
|
+ const shadowRootData = options.shadowRootsData[Number(id)];
|
|
|
+ if (shadowRootData) {
|
|
|
+ const templateElement = doc.createElement("template");
|
|
|
+ templateElement.setAttribute(WC_ATTRIBUTE_NAME, "");
|
|
|
+ const shadowDoc = docUtil.parseDocContent(shadowRootData.content);
|
|
|
+ if (shadowDoc.head) {
|
|
|
+ const metaCharset = shadowDoc.head.querySelector("meta[charset]");
|
|
|
+ if (metaCharset) {
|
|
|
+ metaCharset.remove();
|
|
|
+ }
|
|
|
+ shadowDoc.head.childNodes.forEach(node => templateElement.appendChild(shadowDoc.importNode(node, true)));
|
|
|
+ }
|
|
|
+ if (shadowDoc.body) {
|
|
|
+ shadowDoc.body.childNodes.forEach(node => templateElement.appendChild(shadowDoc.importNode(node, true)));
|
|
|
+ }
|
|
|
+ processElement(templateElement);
|
|
|
+ if (element.firstChild) {
|
|
|
+ element.insertBefore(templateElement, element.firstChild);
|
|
|
+ } else {
|
|
|
+ element.appendChild(templateElement);
|
|
|
+ }
|
|
|
}
|
|
|
- }));
|
|
|
+ });
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -1065,56 +1068,6 @@ this.SingleFileCore = this.SingleFileCore || (() => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- async processShadowRoots() {
|
|
|
- const rootDoc = this.doc;
|
|
|
- const options = this.options;
|
|
|
- const stats = this.stats;
|
|
|
- if (this.options.shadowRootsData && this.options.shadowRootsData.length) {
|
|
|
- await processRootElement(this.doc);
|
|
|
- const scriptElement = rootDoc.createElement("script");
|
|
|
- scriptElement.textContent = `(()=>{processNode(document);function processNode(node){node.querySelectorAll("[${WC_ATTRIBUTE_NAME}]").forEach(element=>{const shadowRoot=element.parentElement.attachShadow({mode:"open"});shadowRoot.innerHTML=element.innerHTML;element.remove();processNode(shadowRoot)})}})()`;
|
|
|
- this.doc.body.appendChild(scriptElement);
|
|
|
- }
|
|
|
-
|
|
|
- async function processRootElement(rootElement) {
|
|
|
- const shadowRootElements = Array.from(rootElement.querySelectorAll("[" + docUtil.SHADOW_ROOT_ATTRIBUTE_NAME + "]"));
|
|
|
- await Promise.all(shadowRootElements.map(async element => {
|
|
|
- const id = element.getAttribute(docUtil.SHADOW_ROOT_ATTRIBUTE_NAME);
|
|
|
- if (id) {
|
|
|
- const shadowRootData = options.shadowRootsData[Number(id)];
|
|
|
- if (shadowRootData) {
|
|
|
- options.shadowRootsData = options.shadowRootsData.filter(shadowRootData => shadowRootData.id != id);
|
|
|
- if (shadowRootData.processor) {
|
|
|
- stats.add("processed", "shadow root elements", 1);
|
|
|
- await shadowRootData.processor.run();
|
|
|
- const doc = shadowRootData.processor.getDocument();
|
|
|
- const templateElement = rootDoc.createElement("template");
|
|
|
- templateElement.setAttribute(WC_ATTRIBUTE_NAME, "");
|
|
|
- if (doc.head) {
|
|
|
- const metaCharset = doc.head.querySelector("meta[charset]");
|
|
|
- if (metaCharset) {
|
|
|
- metaCharset.remove();
|
|
|
- }
|
|
|
- doc.head.childNodes.forEach(node => templateElement.appendChild(doc.importNode(node, true)));
|
|
|
- }
|
|
|
- if (doc.body) {
|
|
|
- doc.body.childNodes.forEach(node => templateElement.appendChild(doc.importNode(node, true)));
|
|
|
- }
|
|
|
- await processRootElement(templateElement);
|
|
|
- if (element.firstChild) {
|
|
|
- element.insertBefore(templateElement, element.firstChild);
|
|
|
- } else {
|
|
|
- element.appendChild(templateElement);
|
|
|
- }
|
|
|
- } else {
|
|
|
- stats.add("discarded", "shadow root elements", 1);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }));
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
async processHtmlImports() {
|
|
|
const linkElements = Array.from(this.doc.querySelectorAll("link[rel=import][href]"));
|
|
|
await Promise.all(linkElements.map(async linkElement => {
|