소스 검색

moved code from content.js into single-file-core.js

Gildas 7 년 전
부모
커밋
894872a4bf
3개의 변경된 파일100개의 추가작업 그리고 115개의 파일을 삭제
  1. 4 101
      extension/core/content/content.js
  2. 3 1
      lib/single-file/single-file-browser.js
  3. 93 13
      lib/single-file/single-file-core.js

+ 4 - 101
extension/core/content/content.js

@@ -18,7 +18,7 @@
  *   along with SingleFile.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-/* global browser, SingleFile, singlefile, FrameTree, document, Blob, MouseEvent, getSelection, getComputedStyle, prompt, addEventListener, Node, HTMLElement */
+/* global browser, SingleFile, singlefile, FrameTree, document, Blob, MouseEvent, getSelection, prompt, addEventListener, Node, window */
 
 this.singlefile.top = this.singlefile.top || (() => {
 
@@ -53,35 +53,13 @@ this.singlefile.top = this.singlefile.top || (() => {
 	async function processPage(options) {
 		options = await getOptions(options);
 		const processor = new (SingleFile.getClass())(options);
-		fixInlineScripts();
-		disableNoscriptTags();
-		hideNonMetadataContents();
 		if (options.selected) {
 			markSelectedContent(processor.SELECTED_CONTENT_ATTRIBUTE_NAME, processor.SELECTED_CONTENT_ROOT_ATTRIBUTE_NAME);
 		}
-		if (options.removeHiddenElements) {
-			markRemovedElements(processor.REMOVED_CONTENT_ATTRIBUTE_NAME);
-		}
-		if (options.compressHTML) {
-			markPreserveElements(processor.PRESERVED_SPACE_ELEMENT_ATTRIBUTE_NAME);
-		}
-		options.url = options.url || document.location.href;
-		options.content = options.content || getDoctype(document) + document.documentElement.outerHTML;
 		await processor.initialize();
 		if (options.shadowEnabled) {
 			singlefile.ui.init();
 		}
-		enableDisabledNoscriptTags();
-		displayHiddenNonMetadataContents();
-		if (options.removeHiddenElements) {
-			unmarkRemovedElements(processor.REMOVED_CONTENT_ATTRIBUTE_NAME);
-		}
-		if (options.compressHTML) {
-			unmarkPreserveElements(processor.PRESERVED_SPACE_ELEMENT_ATTRIBUTE_NAME);
-		}
-		if (!options.removeFrames) {
-			removeWindowIdFrames(processor.WIN_ID_ATTRIBUTE_NAME);
-		}
 		await processor.preparePageData();
 		const page = processor.getPageData();
 		if (options.selected) {
@@ -104,61 +82,6 @@ this.singlefile.top = this.singlefile.top || (() => {
 		URL.revokeObjectURL(page.url);
 	}
 
-	function disableNoscriptTags() {
-		document.head.querySelectorAll("noscript").forEach(element => {
-			const disabledNoscriptElement = document.createElement("disabled-noscript");
-			Array.from(element.childNodes).forEach(node => disabledNoscriptElement.appendChild(node));
-			disabledNoscriptElement.hidden = true;
-			element.parentElement.replaceChild(disabledNoscriptElement, element);
-		});
-	}
-
-	function enableDisabledNoscriptTags() {
-		document.head.querySelectorAll("disabled-noscript").forEach(element => {
-			const noscriptElement = document.createElement("noscript");
-			Array.from(element.childNodes).forEach(node => noscriptElement.appendChild(node));
-			element.parentElement.replaceChild(noscriptElement, element);
-		});
-	}
-
-	function hideNonMetadataContents() {
-		document.head.querySelectorAll("*:not(base):not(link):not(meta):not(noscript):not(script):not(style):not(template):not(title)").forEach(element => element.hidden = true);
-	}
-
-	function displayHiddenNonMetadataContents() {
-		document.head.querySelectorAll("*:not(base):not(link):not(meta):not(noscript):not(script):not(style):not(template):not(title)").forEach(element => element.removeAttribute("hidden"));
-	}
-
-	function fixInlineScripts() {
-		document.querySelectorAll("script").forEach(element => element.textContent = element.textContent.replace(/<\/script>/gi, "<\\/script>"));
-	}
-
-	function markPreserveElements(PRESERVED_SPACE_ELEMENT_ATTRIBUTE_NAME) {
-		document.querySelectorAll("*").forEach(element => {
-			const style = getComputedStyle(element);
-			if (style.whiteSpace.startsWith("pre")) {
-				element.setAttribute(PRESERVED_SPACE_ELEMENT_ATTRIBUTE_NAME, "");
-			}
-		});
-	}
-
-	function unmarkPreserveElements(PRESERVED_SPACE_ELEMENT_ATTRIBUTE_NAME) {
-		document.querySelectorAll("[" + PRESERVED_SPACE_ELEMENT_ATTRIBUTE_NAME + "]").forEach(element => element.removeAttribute(PRESERVED_SPACE_ELEMENT_ATTRIBUTE_NAME));
-	}
-
-	function markRemovedElements(REMOVED_CONTENT_ATTRIBUTE_NAME) {
-		document.querySelectorAll("html > body *:not(style):not(script):not(link):not(frame):not(iframe):not(object)").forEach(element => {
-			const style = getComputedStyle(element);
-			if (element instanceof HTMLElement && (element.hidden || style.display == "none" || ((style.opacity === 0 || style.visibility == "hidden") && !element.clientWidth && !element.clientHeight)) && !element.querySelector("iframe, frame, object[type=\"text/html\"][data]")) {
-				element.setAttribute(REMOVED_CONTENT_ATTRIBUTE_NAME, "");
-			}
-		});
-	}
-
-	function unmarkRemovedElements(REMOVED_CONTENT_ATTRIBUTE_NAME) {
-		document.querySelectorAll("[" + REMOVED_CONTENT_ATTRIBUTE_NAME + "]").forEach(element => element.removeAttribute(REMOVED_CONTENT_ATTRIBUTE_NAME));
-	}
-
 	function markSelectedContent(SELECTED_CONTENT_ATTRIBUTE_NAME, SELECTED_CONTENT_ROOT_ATTRIBUTE_NAME) {
 		const selection = getSelection();
 		const range = selection.rangeCount ? selection.getRangeAt(0) : null;
@@ -182,11 +105,9 @@ this.singlefile.top = this.singlefile.top || (() => {
 		document.querySelectorAll("[" + SELECTED_CONTENT_ROOT_ATTRIBUTE_NAME + "]").forEach(selectedContent => selectedContent.removeAttribute(SELECTED_CONTENT_ROOT_ATTRIBUTE_NAME));
 	}
 
-	function removeWindowIdFrames(WIN_ID_ATTRIBUTE_NAME) {
-		document.querySelectorAll("[" + WIN_ID_ATTRIBUTE_NAME + "]").forEach(element => element.removeAttribute(WIN_ID_ATTRIBUTE_NAME));
-	}
-
 	async function getOptions(options) {
+		options.doc = document;
+		options.win = window;
 		options.canvasData = getCanvasData();
 		options.emptyStyleRulesText = getEmptyStyleRulesText();
 		if (!options.removeFrames) {
@@ -236,24 +157,6 @@ this.singlefile.top = this.singlefile.top || (() => {
 		return canvasData;
 	}
 
-	function getDoctype(doc) {
-		const docType = doc.doctype;
-		let docTypeString;
-		if (docType) {
-			docTypeString = "<!DOCTYPE " + docType.nodeName;
-			if (docType.publicId) {
-				docTypeString += " PUBLIC \"" + docType.publicId + "\"";
-				if (docType.systemId)
-					docTypeString += " \"" + docType.systemId + "\"";
-			} else if (docType.systemId)
-				docTypeString += " SYSTEM \"" + docType.systemId + "\"";
-			if (docType.internalSubset)
-				docTypeString += " [" + docType.internalSubset + "]";
-			return docTypeString + ">\n";
-		}
-		return "";
-	}
-
 	async function downloadPage(page, options) {
 		const response = await browser.runtime.sendMessage({ download: true, url: page.url, saveAs: options.confirmFilename, filename: page.filename });
 		if (response.notSupported) {
@@ -271,4 +174,4 @@ this.singlefile.top = this.singlefile.top || (() => {
 		}
 	}
 
-})();
+})();

+ 3 - 1
lib/single-file/single-file-browser.js

@@ -98,7 +98,6 @@ this.SingleFile = this.SingleFile || (() => {
 			return {
 				DOMParser,
 				document: doc,
-				serialize: options => serializer.process(doc, options.compressHTML),
 				parseSrcset: srcset => parseSrcset.process(srcset),
 				uglifycss: (content, options) => uglifycss.processString(content, options),
 				lazyLoader: {
@@ -112,6 +111,9 @@ this.SingleFile = this.SingleFile || (() => {
 				rulesMinifier: doc => rulesMinifier.process(doc)
 			};
 		}
+		static serialize(doc, compressHTML) {
+			return serializer.process(doc, compressHTML);
+		}
 	}
 
 	return { getClass: () => SingleFileCore.getClass(Download, DOM, URL) };

+ 93 - 13
lib/single-file/single-file-core.js

@@ -36,10 +36,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 			constructor(options) {
 				this.options = options;
 				this.SELECTED_CONTENT_ATTRIBUTE_NAME = SELECTED_CONTENT_ATTRIBUTE_NAME;
-				this.REMOVED_CONTENT_ATTRIBUTE_NAME = REMOVED_CONTENT_ATTRIBUTE_NAME;
 				this.SELECTED_CONTENT_ROOT_ATTRIBUTE_NAME = SELECTED_CONTENT_ROOT_ATTRIBUTE_NAME;
-				this.PRESERVED_SPACE_ELEMENT_ATTRIBUTE_NAME = PRESERVED_SPACE_ELEMENT_ATTRIBUTE_NAME;
-				this.WIN_ID_ATTRIBUTE_NAME = WIN_ID_ATTRIBUTE_NAME;
 			}
 			async initialize() {
 				this.processor = new PageProcessor(this.options);
@@ -77,7 +74,20 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 	class PageProcessor {
 		constructor(options) {
 			this.options = options;
+			this.options.content = this.options.content || (this.options.doc ? DOMProcessor.serialize(this.options.doc, false) : null);
+			this.options.url = this.options.url || this.options.doc.location.href;
 			this.processor = new DOMProcessor(options);
+			if (this.options.doc) {
+				this.processor.fixInlineScripts();
+				this.processor.disableNoscriptElements();
+				this.processor.hideNonMetadataContents();
+				if (this.options.removeHiddenElements) {
+					this.processor.markRemovedElements();
+				}
+				if (this.options.compressHTML) {
+					this.processor.markPreservedElements();
+				}
+			}
 			this.onprogress = options.onprogress || (() => { });
 		}
 
@@ -90,7 +100,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 		async initialize() {
 			this.onprogress(new ProgressEvent(RESOURCES_INITIALIZING, { pageURL: this.options.url }));
 			this.processor.removeInfoToolbar();
-			this.processor.enableDisabledNoscriptTags();
+			this.processor.enableDisabledNoscriptTags(this.processor.doc.head.querySelectorAll("disabled-noscript"));
 			this.processor.replaceEmptyStyles();
 			if (!this.options.jsEnabled || (this.options.saveRawPage && this.options.removeScripts)) {
 				this.processor.insertNoscriptContents();
@@ -135,6 +145,21 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 			if (!this.options.removeScripts) {
 				this.pendingPromises.push(this.processor.scripts());
 			}
+			if (this.options.doc) {
+				this.processor.enableDisabledNoscriptTags(this.options.doc.querySelectorAll("disabled-noscript"));
+				this.processor.displayHiddenNonMetadataContents();
+				if (this.options.removeHiddenElements) {
+					this.processor.unmarkRemovedElements();
+				}
+				if (this.options.compressHTML) {
+					this.processor.unmarkPreservedElements();
+				}
+				if (!this.options.removeFrames) {
+					this.processor.removeWindowIdFrames();
+				}
+				this.options.doc = null;
+				this.options.win = null;
+			}
 			this.onprogress(new ProgressEvent(RESOURCES_INITIALIZED, { pageURL: this.options.url, index: 0, max: batchRequest.getMaxResources() }));
 		}
 
@@ -256,6 +281,10 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 			this.baseURI = options.url;
 		}
 
+		static serialize(doc, compressHTML) {
+			return DOM.serialize(doc, compressHTML);
+		}
+
 		async loadPage(pageContent) {
 			if (!pageContent || this.options.saveRawPage) {
 				pageContent = await Download.getContent(this.baseURI, { asDataURI: false, maxResourceSize: this.options.maxResourceSize, maxResourceSizeEnabled: this.options.maxResourceSizeEnabled });
@@ -304,7 +333,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 			if (this.options.displayStats) {
 				size = new Blob([this.doc.documentElement.outerHTML]).size;
 			}
-			const content = this.dom.serialize(this.options);
+			const content = DOMProcessor.serialize(this.doc, this.options.compressHTML);
 			if (this.options.displayStats) {
 				this.stats.processed.htmlBytes = new Blob([content]).size;
 				this.stats.discarded.htmlBytes += size - this.stats.processed.htmlBytes;
@@ -316,6 +345,65 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 			};
 		}
 
+		fixInlineScripts() {
+			this.options.doc.querySelectorAll("script").forEach(element => element.textContent = element.textContent.replace(/<\/script>/gi, "<\\/script>"));
+		}
+
+		disableNoscriptElements() {
+			this.options.doc.head.querySelectorAll("noscript").forEach(element => {
+				const disabledNoscriptElement = this.options.doc.createElement("disabled-noscript");
+				Array.from(element.childNodes).forEach(node => disabledNoscriptElement.appendChild(node));
+				disabledNoscriptElement.hidden = true;
+				element.parentElement.replaceChild(disabledNoscriptElement, element);
+			});
+		}
+
+		hideNonMetadataContents() {
+			this.options.doc.head.querySelectorAll("*:not(base):not(link):not(meta):not(noscript):not(script):not(style):not(template):not(title)").forEach(element => element.hidden = true);
+		}
+
+		markRemovedElements() {
+			this.options.doc.querySelectorAll("html > body *:not(style):not(script):not(link):not(frame):not(iframe):not(object)").forEach(element => {
+				const style = this.options.win.getComputedStyle(element);
+				if (element instanceof this.options.win.HTMLElement && (element.hidden || style.display == "none" || ((style.opacity === 0 || style.visibility == "hidden") && !element.clientWidth && !element.clientHeight)) && !element.querySelector("iframe, frame, object[type=\"text/html\"][data]")) {
+					element.setAttribute(REMOVED_CONTENT_ATTRIBUTE_NAME, "");
+				}
+			});
+		}
+
+		markPreservedElements() {
+			this.options.doc.querySelectorAll("*").forEach(element => {
+				const style = this.options.win.getComputedStyle(element);
+				if (style.whiteSpace.startsWith("pre")) {
+					element.setAttribute(PRESERVED_SPACE_ELEMENT_ATTRIBUTE_NAME, "");
+				}
+			});
+		}
+
+		displayHiddenNonMetadataContents() {
+			this.options.doc.head.querySelectorAll("*:not(base):not(link):not(meta):not(noscript):not(script):not(style):not(template):not(title)").forEach(element => element.removeAttribute("hidden"));
+		}
+
+		unmarkPreservedElements() {
+			this.options.doc.querySelectorAll("[" + PRESERVED_SPACE_ELEMENT_ATTRIBUTE_NAME + "]").forEach(element => element.removeAttribute(PRESERVED_SPACE_ELEMENT_ATTRIBUTE_NAME));
+		}
+
+		unmarkRemovedElements() {
+			this.options.doc.querySelectorAll("[" + REMOVED_CONTENT_ATTRIBUTE_NAME + "]").forEach(element => element.removeAttribute(REMOVED_CONTENT_ATTRIBUTE_NAME));
+		}
+
+		removeWindowIdFrames() {
+			this.options.doc.querySelectorAll("[" + WIN_ID_ATTRIBUTE_NAME + "]").forEach(element => element.removeAttribute(WIN_ID_ATTRIBUTE_NAME));
+		}
+
+		enableDisabledNoscriptTags(noscriptTags) {
+			noscriptTags.forEach(element => {
+				const noscriptElement = this.options.doc.createElement("noscript");
+				Array.from(element.childNodes).forEach(node => noscriptElement.appendChild(node));
+				element.parentElement.replaceChild(noscriptElement, element);
+			});
+		}
+
 		insertNoscriptContents() {
 			if (this.DOMParser) {
 				this.doc.querySelectorAll("noscript").forEach(element => {
@@ -463,14 +551,6 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 			this.doc.documentElement.insertBefore(commentNode, this.doc.documentElement.firstChild);
 		}
 
-		enableDisabledNoscriptTags() {
-			this.doc.querySelectorAll("disabled-noscript").forEach(element => {
-				const noscriptElement = this.doc.createElement("noscript");
-				Array.from(element.childNodes).forEach(node => noscriptElement.appendChild(node));
-				element.parentElement.replaceChild(noscriptElement, element);
-			});
-		}
-
 		replaceCanvasElements() {
 			if (this.options.canvasData) {
 				this.doc.querySelectorAll("canvas").forEach((canvasElement, indexCanvasElement) => {