single-file-core 1.0.45 → 1.0.47
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/modules/index.js +3 -1
- package/modules/template-formatter.js +2104 -0
- package/package.json +1 -1
- package/processors/hooks/content/content-hooks-frames-web.js +0 -12
- package/single-file-core.js +2 -155
- package/single-file-helper.js +56 -54
- package/single-file-util.js +6 -14
package/package.json
CHANGED
|
@@ -67,9 +67,7 @@
|
|
|
67
67
|
const Event = globalThis.Event;
|
|
68
68
|
const FileReader = globalThis.FileReader;
|
|
69
69
|
const Blob = globalThis.Blob;
|
|
70
|
-
const console = globalThis.console;
|
|
71
70
|
const JSON = globalThis.JSON;
|
|
72
|
-
const warn = (console && console.warn && ((...args) => console.warn(...args))) || (() => { });
|
|
73
71
|
|
|
74
72
|
const observers = new Map();
|
|
75
73
|
const observedElements = new Map();
|
|
@@ -314,12 +312,7 @@
|
|
|
314
312
|
|
|
315
313
|
if (globalThis.FontFace) {
|
|
316
314
|
const FontFace = globalThis.FontFace;
|
|
317
|
-
let warningFontFaceDisplayed;
|
|
318
315
|
globalThis.FontFace = function () {
|
|
319
|
-
if (!warningFontFaceDisplayed) {
|
|
320
|
-
warn("SingleFile is hooking the FontFace constructor, document.fonts.delete and document.fonts.clear to handle dynamically loaded fonts.");
|
|
321
|
-
warningFontFaceDisplayed = true;
|
|
322
|
-
}
|
|
323
316
|
getDetailObject(...arguments).then(detail => dispatchEvent(new CustomEvent(NEW_FONT_FACE_EVENT, { detail })));
|
|
324
317
|
return new FontFace(...arguments);
|
|
325
318
|
};
|
|
@@ -340,12 +333,7 @@
|
|
|
340
333
|
|
|
341
334
|
if (globalThis.IntersectionObserver) {
|
|
342
335
|
const IntersectionObserver = globalThis.IntersectionObserver;
|
|
343
|
-
let warningIntersectionObserverDisplayed;
|
|
344
336
|
globalThis.IntersectionObserver = function () {
|
|
345
|
-
if (!warningIntersectionObserverDisplayed) {
|
|
346
|
-
warn("SingleFile is hooking the IntersectionObserver API to detect and load deferred images.");
|
|
347
|
-
warningIntersectionObserverDisplayed = true;
|
|
348
|
-
}
|
|
349
337
|
const intersectionObserver = new IntersectionObserver(...arguments);
|
|
350
338
|
const observeIntersection = IntersectionObserver.prototype.observe || intersectionObserver.observe;
|
|
351
339
|
const unobserveIntersection = IntersectionObserver.prototype.unobserve || intersectionObserver.unobserve;
|
package/single-file-core.js
CHANGED
|
@@ -517,21 +517,7 @@ class Processor {
|
|
|
517
517
|
this.stats.set("processed", "HTML bytes", contentSize);
|
|
518
518
|
this.stats.add("discarded", "HTML bytes", size - contentSize);
|
|
519
519
|
}
|
|
520
|
-
|
|
521
|
-
const replacementCharacter = this.options.filenameReplacementCharacter;
|
|
522
|
-
filename = util.getValidFilename(filename, this.options.filenameReplacedCharacters, replacementCharacter);
|
|
523
|
-
if (!this.options.backgroundSave) {
|
|
524
|
-
filename = filename.replace(/\//g, replacementCharacter);
|
|
525
|
-
}
|
|
526
|
-
if (!this.options.keepFilename && ((this.options.filenameMaxLengthUnit == "bytes" && util.getContentSize(filename) > this.options.filenameMaxLength) || filename.length > this.options.filenameMaxLength)) {
|
|
527
|
-
const extensionMatch = filename.match(/(\.[^.]{3,4})$/);
|
|
528
|
-
const extension = extensionMatch && extensionMatch[0] && extensionMatch[0].length > 1 ? extensionMatch[0] : "";
|
|
529
|
-
filename = this.options.filenameMaxLengthUnit == "bytes" ? await util.truncateText(filename, this.options.filenameMaxLength - extension.length) : filename.substring(0, this.options.filenameMaxLength - extension.length);
|
|
530
|
-
filename = filename + "…" + extension;
|
|
531
|
-
}
|
|
532
|
-
if (!filename) {
|
|
533
|
-
filename = "Unnamed page";
|
|
534
|
-
}
|
|
520
|
+
const filename = await util.formatFilename(content, this.options);
|
|
535
521
|
const matchTitle = this.baseURI.match(/([^/]*)\/?(\.html?.*)$/) || this.baseURI.match(/\/\/([^/]*)\/?$/);
|
|
536
522
|
const pageData = {
|
|
537
523
|
stats: this.stats.data,
|
|
@@ -1479,7 +1465,7 @@ class Processor {
|
|
|
1479
1465
|
publisher: publisherElement && publisherElement.content ? publisherElement.content.trim() : "",
|
|
1480
1466
|
heading: headingElement && headingElement.textContent ? headingElement.textContent.trim() : ""
|
|
1481
1467
|
};
|
|
1482
|
-
this.options.infobarContent = await
|
|
1468
|
+
this.options.infobarContent = await util.evalTemplate(this.options.infobarTemplate, this.options, null, true);
|
|
1483
1469
|
}
|
|
1484
1470
|
}
|
|
1485
1471
|
|
|
@@ -1493,86 +1479,6 @@ const SINGLE_FILE_VARIABLE_NAME_PREFIX = "--sf-img-";
|
|
|
1493
1479
|
const SINGLE_FILE_VARIABLE_MAX_SIZE = 512 * 1024;
|
|
1494
1480
|
|
|
1495
1481
|
class ProcessorHelper {
|
|
1496
|
-
static async evalTemplate(template = "", options, content, dontReplaceSlash) {
|
|
1497
|
-
const url = util.parseURL(options.saveUrl);
|
|
1498
|
-
template = await evalTemplateVariable(template, "page-title", () => options.title || "No title", dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1499
|
-
template = await evalTemplateVariable(template, "page-heading", () => options.info.heading || "No heading", dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1500
|
-
template = await evalTemplateVariable(template, "page-language", () => options.info.lang || "No language", dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1501
|
-
template = await evalTemplateVariable(template, "page-description", () => options.info.description || "No description", dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1502
|
-
template = await evalTemplateVariable(template, "page-author", () => options.info.author || "No author", dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1503
|
-
template = await evalTemplateVariable(template, "page-creator", () => options.info.creator || "No creator", dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1504
|
-
template = await evalTemplateVariable(template, "page-publisher", () => options.info.publisher || "No publisher", dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1505
|
-
await evalDate(options.saveDate);
|
|
1506
|
-
await evalDate(options.visitDate, "visit-");
|
|
1507
|
-
template = await evalTemplateVariable(template, "url-hash", () => url.hash.substring(1) || "No hash", dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1508
|
-
template = await evalTemplateVariable(template, "url-host", () => url.host.replace(/\/$/, "") || "No host", dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1509
|
-
template = await evalTemplateVariable(template, "url-hostname", () => url.hostname.replace(/\/$/, "") || "No hostname", dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1510
|
-
const urlHref = decode(url.href);
|
|
1511
|
-
template = await evalTemplateVariable(template, "url-href", () => urlHref || "No href", dontReplaceSlash === undefined ? true : dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1512
|
-
template = await evalTemplateVariable(template, "url-href-digest-sha-1", urlHref ? async () => util.digest("SHA-1", urlHref) : "No href", dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1513
|
-
template = await evalTemplateVariable(template, "url-href-flat", () => decode(url.href) || "No href", false, options.filenameReplacementCharacter);
|
|
1514
|
-
template = await evalTemplateVariable(template, "url-referrer", () => decode(options.referrer) || "No referrer", dontReplaceSlash === undefined ? true : dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1515
|
-
template = await evalTemplateVariable(template, "url-referrer-flat", () => decode(options.referrer) || "No referrer", false, options.filenameReplacementCharacter);
|
|
1516
|
-
template = await evalTemplateVariable(template, "url-password", () => url.password || "No password", dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1517
|
-
template = await evalTemplateVariable(template, "url-pathname", () => decode(url.pathname).replace(/^\//, "").replace(/\/$/, "") || "No pathname", dontReplaceSlash === undefined ? true : dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1518
|
-
template = await evalTemplateVariable(template, "url-pathname-flat", () => decode(url.pathname) || "No pathname", false, options.filenameReplacementCharacter);
|
|
1519
|
-
template = await evalTemplateVariable(template, "url-port", () => url.port || "No port", dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1520
|
-
template = await evalTemplateVariable(template, "url-protocol", () => url.protocol || "No protocol", dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1521
|
-
template = await evalTemplateVariable(template, "url-search", () => url.search.substring(1) || "No search", dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1522
|
-
const params = util.getSearchParams(url.search);
|
|
1523
|
-
for (const [name, value] of params) {
|
|
1524
|
-
template = await evalTemplateVariable(template, "url-search-" + name, () => value || "", dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1525
|
-
}
|
|
1526
|
-
template = template.replace(/{\s*url-search-[^}\s]*\s*}/gi, "");
|
|
1527
|
-
template = await evalTemplateVariable(template, "url-username", () => url.username || "No username", dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1528
|
-
template = await evalTemplateVariable(template, "tab-id", () => String(options.tabId || "No tab id"), dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1529
|
-
template = await evalTemplateVariable(template, "tab-index", () => String(options.tabIndex || "No tab index"), dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1530
|
-
template = await evalTemplateVariable(template, "url-last-segment", () => decode(getLastSegment(url, options.filenameReplacementCharacter)) || "No last segment", dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1531
|
-
if (content) {
|
|
1532
|
-
template = await evalTemplateVariable(template, "digest-sha-256", async () => util.digest("SHA-256", content), dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1533
|
-
template = await evalTemplateVariable(template, "digest-sha-384", async () => util.digest("SHA-384", content), dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1534
|
-
template = await evalTemplateVariable(template, "digest-sha-512", async () => util.digest("SHA-512", content), dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1535
|
-
}
|
|
1536
|
-
const bookmarkFolder = (options.bookmarkFolders && options.bookmarkFolders.join("/")) || "";
|
|
1537
|
-
template = await evalTemplateVariable(template, "bookmark-pathname", () => bookmarkFolder, dontReplaceSlash === undefined ? true : dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1538
|
-
template = await evalTemplateVariable(template, "bookmark-pathname-flat", () => bookmarkFolder, false, options.filenameReplacementCharacter);
|
|
1539
|
-
template = await evalTemplateVariable(template, "profile-name", () => options.profileName, dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1540
|
-
return template.trim();
|
|
1541
|
-
|
|
1542
|
-
function decode(value) {
|
|
1543
|
-
try {
|
|
1544
|
-
return decodeURI(value);
|
|
1545
|
-
} catch (error) {
|
|
1546
|
-
return value;
|
|
1547
|
-
}
|
|
1548
|
-
}
|
|
1549
|
-
|
|
1550
|
-
async function evalDate(date, prefix = "") {
|
|
1551
|
-
if (date) {
|
|
1552
|
-
template = await evalTemplateVariable(template, prefix + "datetime-iso", () => date.toISOString(), dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1553
|
-
template = await evalTemplateVariable(template, prefix + "date-iso", () => date.toISOString().split("T")[0], dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1554
|
-
template = await evalTemplateVariable(template, prefix + "time-iso", () => date.toISOString().split("T")[1].split("Z")[0], dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1555
|
-
template = await evalTemplateVariable(template, prefix + "date-locale", () => date.toLocaleDateString(), dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1556
|
-
template = await evalTemplateVariable(template, prefix + "time-locale", () => date.toLocaleTimeString(), dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1557
|
-
template = await evalTemplateVariable(template, prefix + "day-locale", () => String(date.getDate()).padStart(2, "0"), dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1558
|
-
template = await evalTemplateVariable(template, prefix + "month-locale", () => String(date.getMonth() + 1).padStart(2, "0"), dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1559
|
-
template = await evalTemplateVariable(template, prefix + "year-locale", () => String(date.getFullYear()), dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1560
|
-
template = await evalTemplateVariable(template, prefix + "datetime-locale", () => date.toLocaleString(), dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1561
|
-
template = await evalTemplateVariable(template, prefix + "datetime-utc", () => date.toUTCString(), dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1562
|
-
template = await evalTemplateVariable(template, prefix + "day-utc", () => String(date.getUTCDate()).padStart(2, "0"), dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1563
|
-
template = await evalTemplateVariable(template, prefix + "month-utc", () => String(date.getUTCMonth() + 1).padStart(2, "0"), dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1564
|
-
template = await evalTemplateVariable(template, prefix + "year-utc", () => String(date.getUTCFullYear()), dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1565
|
-
template = await evalTemplateVariable(template, prefix + "hours-locale", () => String(date.getHours()).padStart(2, "0"), dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1566
|
-
template = await evalTemplateVariable(template, prefix + "minutes-locale", () => String(date.getMinutes()).padStart(2, "0"), dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1567
|
-
template = await evalTemplateVariable(template, prefix + "seconds-locale", () => String(date.getSeconds()).padStart(2, "0"), dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1568
|
-
template = await evalTemplateVariable(template, prefix + "hours-utc", () => String(date.getUTCHours()).padStart(2, "0"), dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1569
|
-
template = await evalTemplateVariable(template, prefix + "minutes-utc", () => String(date.getUTCMinutes()).padStart(2, "0"), dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1570
|
-
template = await evalTemplateVariable(template, prefix + "seconds-utc", () => String(date.getUTCSeconds()).padStart(2, "0"), dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1571
|
-
template = await evalTemplateVariable(template, prefix + "time-ms", () => String(date.getTime()), dontReplaceSlash, options.filenameReplacementCharacter);
|
|
1572
|
-
}
|
|
1573
|
-
}
|
|
1574
|
-
}
|
|
1575
|
-
|
|
1576
1482
|
static setBackgroundImage(element, url, style) {
|
|
1577
1483
|
element.style.setProperty("background-blend-mode", "normal", "important");
|
|
1578
1484
|
element.style.setProperty("background-clip", "content-box", "important");
|
|
@@ -2102,65 +2008,6 @@ function getOnEventAttributeNames(doc) {
|
|
|
2102
2008
|
return attributeNames;
|
|
2103
2009
|
}
|
|
2104
2010
|
|
|
2105
|
-
async function evalTemplateVariable(template, variableName, valueGetter, dontReplaceSlash, replacementCharacter) {
|
|
2106
|
-
let maxLength, maxCharLength;
|
|
2107
|
-
if (template) {
|
|
2108
|
-
const regExpVariable = "{\\s*" + variableName.replace(/\W|_/g, "[$&]") + "\\s*}";
|
|
2109
|
-
let replaceRegExp = new RegExp(regExpVariable + "\\[\\d+(ch)?\\]", "g");
|
|
2110
|
-
if (template.match(replaceRegExp)) {
|
|
2111
|
-
const matchedLength = template.match(replaceRegExp)[0];
|
|
2112
|
-
if (matchedLength.match(/\[(\d+)\]$/)) {
|
|
2113
|
-
maxLength = Number(matchedLength.match(/\[(\d+)\]$/)[1]);
|
|
2114
|
-
if (isNaN(maxLength) || maxLength <= 0) {
|
|
2115
|
-
maxLength = null;
|
|
2116
|
-
}
|
|
2117
|
-
} else {
|
|
2118
|
-
maxCharLength = Number(matchedLength.match(/\[(\d+)ch\]$/)[1]);
|
|
2119
|
-
if (isNaN(maxCharLength) || maxCharLength <= 0) {
|
|
2120
|
-
maxCharLength = null;
|
|
2121
|
-
}
|
|
2122
|
-
}
|
|
2123
|
-
} else {
|
|
2124
|
-
replaceRegExp = new RegExp(regExpVariable, "g");
|
|
2125
|
-
}
|
|
2126
|
-
if (template.match(replaceRegExp)) {
|
|
2127
|
-
let value = await valueGetter();
|
|
2128
|
-
if (!dontReplaceSlash) {
|
|
2129
|
-
value = value.replace(/\/+/g, replacementCharacter);
|
|
2130
|
-
}
|
|
2131
|
-
if (maxLength) {
|
|
2132
|
-
value = await util.truncateText(value, maxLength);
|
|
2133
|
-
} else if (maxCharLength) {
|
|
2134
|
-
value = value.substring(0, maxCharLength);
|
|
2135
|
-
}
|
|
2136
|
-
return template.replace(replaceRegExp, value);
|
|
2137
|
-
}
|
|
2138
|
-
}
|
|
2139
|
-
return template;
|
|
2140
|
-
}
|
|
2141
|
-
|
|
2142
|
-
function getLastSegment(url, replacementCharacter) {
|
|
2143
|
-
let lastSegmentMatch = url.pathname.match(/\/([^/]+)$/),
|
|
2144
|
-
lastSegment = lastSegmentMatch && lastSegmentMatch[0];
|
|
2145
|
-
if (!lastSegment) {
|
|
2146
|
-
lastSegmentMatch = url.href.match(/([^/]+)\/?$/);
|
|
2147
|
-
lastSegment = lastSegmentMatch && lastSegmentMatch[0];
|
|
2148
|
-
}
|
|
2149
|
-
if (!lastSegment) {
|
|
2150
|
-
lastSegmentMatch = lastSegment.match(/(.*)\.[^.]+$/);
|
|
2151
|
-
lastSegment = lastSegmentMatch && lastSegmentMatch[0];
|
|
2152
|
-
}
|
|
2153
|
-
if (!lastSegment) {
|
|
2154
|
-
lastSegment = url.hostname.replace(/\/+/g, replacementCharacter).replace(/\/$/, "");
|
|
2155
|
-
}
|
|
2156
|
-
lastSegmentMatch = lastSegment.match(/(.*)\.[^.]+$/);
|
|
2157
|
-
if (lastSegmentMatch && lastSegmentMatch[1]) {
|
|
2158
|
-
lastSegment = lastSegmentMatch[1];
|
|
2159
|
-
}
|
|
2160
|
-
lastSegment = lastSegment.replace(/\/$/, "").replace(/^\//, "");
|
|
2161
|
-
return lastSegment;
|
|
2162
|
-
}
|
|
2163
|
-
|
|
2164
2011
|
function getUrlFunctions(declarationList) {
|
|
2165
2012
|
return cssTree.findAll(declarationList, node => node.type == "Url");
|
|
2166
2013
|
}
|
package/single-file-helper.js
CHANGED
|
@@ -183,70 +183,72 @@ function preProcessDoc(doc, win, options) {
|
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
function getElementsInfo(win, doc, element, options, data = { usedFonts: new Map(), canvases: [], images: [], posters: [], videos: [], shadowRoots: [], markedElements: [] }, ascendantHidden) {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
if (
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
186
|
+
if (element.childNodes) {
|
|
187
|
+
const elements = Array.from(element.childNodes).filter(node => (node instanceof win.HTMLElement) || (node instanceof win.SVGElement));
|
|
188
|
+
elements.forEach(element => {
|
|
189
|
+
let elementHidden, elementKept, computedStyle;
|
|
190
|
+
if (!options.autoSaveExternalSave && (options.removeHiddenElements || options.removeUnusedFonts || options.compressHTML)) {
|
|
191
|
+
computedStyle = getComputedStyle(win, element);
|
|
192
|
+
if (element instanceof win.HTMLElement) {
|
|
193
|
+
if (options.removeHiddenElements) {
|
|
194
|
+
elementKept = ((ascendantHidden || element.closest("html > head")) && KEPT_TAG_NAMES.includes(element.tagName)) || element.closest("details");
|
|
195
|
+
if (!elementKept) {
|
|
196
|
+
elementHidden = ascendantHidden || testHiddenElement(element, computedStyle);
|
|
197
|
+
if (elementHidden) {
|
|
198
|
+
element.setAttribute(HIDDEN_CONTENT_ATTRIBUTE_NAME, "");
|
|
199
|
+
data.markedElements.push(element);
|
|
200
|
+
}
|
|
199
201
|
}
|
|
200
202
|
}
|
|
201
203
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
204
|
+
if (!elementHidden) {
|
|
205
|
+
if (options.compressHTML && computedStyle) {
|
|
206
|
+
const whiteSpace = computedStyle.getPropertyValue("white-space");
|
|
207
|
+
if (whiteSpace && whiteSpace.startsWith("pre")) {
|
|
208
|
+
element.setAttribute(PRESERVED_SPACE_ELEMENT_ATTRIBUTE_NAME, "");
|
|
209
|
+
data.markedElements.push(element);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (options.removeUnusedFonts) {
|
|
213
|
+
getUsedFont(computedStyle, options, data.usedFonts);
|
|
214
|
+
getUsedFont(getComputedStyle(win, element, ":first-letter"), options, data.usedFonts);
|
|
215
|
+
getUsedFont(getComputedStyle(win, element, ":before"), options, data.usedFonts);
|
|
216
|
+
getUsedFont(getComputedStyle(win, element, ":after"), options, data.usedFonts);
|
|
209
217
|
}
|
|
210
|
-
}
|
|
211
|
-
if (options.removeUnusedFonts) {
|
|
212
|
-
getUsedFont(computedStyle, options, data.usedFonts);
|
|
213
|
-
getUsedFont(getComputedStyle(win, element, ":first-letter"), options, data.usedFonts);
|
|
214
|
-
getUsedFont(getComputedStyle(win, element, ":before"), options, data.usedFonts);
|
|
215
|
-
getUsedFont(getComputedStyle(win, element, ":after"), options, data.usedFonts);
|
|
216
218
|
}
|
|
217
219
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
220
|
+
getResourcesInfo(win, doc, element, options, data, elementHidden, computedStyle);
|
|
221
|
+
const shadowRoot = !(element instanceof win.SVGElement) && getShadowRoot(element);
|
|
222
|
+
if (shadowRoot && !element.classList.contains(SINGLE_FILE_UI_ELEMENT_CLASS)) {
|
|
223
|
+
const shadowRootInfo = {};
|
|
224
|
+
element.setAttribute(SHADOW_ROOT_ATTRIBUTE_NAME, data.shadowRoots.length);
|
|
225
|
+
data.markedElements.push(element);
|
|
226
|
+
data.shadowRoots.push(shadowRootInfo);
|
|
227
|
+
getElementsInfo(win, doc, shadowRoot, options, data, elementHidden);
|
|
228
|
+
shadowRootInfo.content = shadowRoot.innerHTML;
|
|
229
|
+
shadowRootInfo.mode = shadowRoot.mode;
|
|
230
|
+
try {
|
|
231
|
+
if (shadowRoot.adoptedStyleSheets && shadowRoot.adoptedStyleSheets.length) {
|
|
232
|
+
shadowRootInfo.adoptedStyleSheets = Array.from(shadowRoot.adoptedStyleSheets).map(stylesheet => Array.from(stylesheet.cssRules).map(cssRule => cssRule.cssText).join("\n"));
|
|
233
|
+
}
|
|
234
|
+
} catch (error) {
|
|
235
|
+
// ignored
|
|
232
236
|
}
|
|
233
|
-
} catch (error) {
|
|
234
|
-
// ignored
|
|
235
237
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
238
|
+
getElementsInfo(win, doc, element, options, data, elementHidden);
|
|
239
|
+
if (!options.autoSaveExternalSave && options.removeHiddenElements && ascendantHidden) {
|
|
240
|
+
if (elementKept || element.getAttribute(KEPT_CONTENT_ATTRIBUTE_NAME) == "") {
|
|
241
|
+
if (element.parentElement) {
|
|
242
|
+
element.parentElement.setAttribute(KEPT_CONTENT_ATTRIBUTE_NAME, "");
|
|
243
|
+
data.markedElements.push(element.parentElement);
|
|
244
|
+
}
|
|
245
|
+
} else if (elementHidden) {
|
|
246
|
+
element.setAttribute(REMOVED_CONTENT_ATTRIBUTE_NAME, "");
|
|
247
|
+
data.markedElements.push(element);
|
|
243
248
|
}
|
|
244
|
-
} else if (elementHidden) {
|
|
245
|
-
element.setAttribute(REMOVED_CONTENT_ATTRIBUTE_NAME, "");
|
|
246
|
-
data.markedElements.push(element);
|
|
247
249
|
}
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
+
});
|
|
251
|
+
}
|
|
250
252
|
return data;
|
|
251
253
|
}
|
|
252
254
|
|
package/single-file-util.js
CHANGED
|
@@ -115,20 +115,11 @@ function getInstance(utilOptions) {
|
|
|
115
115
|
getContentSize(content) {
|
|
116
116
|
return new Blob([content]).size;
|
|
117
117
|
},
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
return
|
|
123
|
-
reader.addEventListener("load", () => {
|
|
124
|
-
if (content.startsWith(reader.result)) {
|
|
125
|
-
resolve(reader.result);
|
|
126
|
-
} else {
|
|
127
|
-
this.truncateText(content, maxSize - 1).then(resolve).catch(reject);
|
|
128
|
-
}
|
|
129
|
-
}, false);
|
|
130
|
-
reader.addEventListener("error", reject, false);
|
|
131
|
-
});
|
|
118
|
+
formatFilename(content, options) {
|
|
119
|
+
return modules.templateFormatter.formatFilename(content, options, this);
|
|
120
|
+
},
|
|
121
|
+
evalTemplate(template, options, content, dontReplaceSlash) {
|
|
122
|
+
return modules.templateFormatter.evalTemplate(template, options, this, content, dontReplaceSlash);
|
|
132
123
|
},
|
|
133
124
|
minifyHTML(doc, options) {
|
|
134
125
|
return modules.htmlMinifier.process(doc, options);
|
|
@@ -325,6 +316,7 @@ async function getFetchResponse(resourceURL, options, data, charset, contentType
|
|
|
325
316
|
charset = "utf-8";
|
|
326
317
|
data = new TextDecoder(charset).decode(data);
|
|
327
318
|
}
|
|
319
|
+
data = data.replace(/\ufeff/gi, "");
|
|
328
320
|
}
|
|
329
321
|
} else {
|
|
330
322
|
data = options.asBinary ? helper.EMPTY_RESOURCE : "";
|