Răsfoiți Sursa

improved srcset removing

Gildas 7 ani în urmă
părinte
comite
53df6e66bd

+ 1 - 1
extension/core/bg/core.js

@@ -138,7 +138,7 @@ singlefile.core = (() => {
 		options.framesData = message.framesData;
 		options.canvasData = message.canvasData;
 		options.stylesheetContents = message.stylesheetContents;
-		options.currentSrcImages = message.currentSrcImages;
+		options.imageData = message.imageData;
 		options.insertSingleFileComment = true;
 		options.insertFaviconLink = true;
 		options.backgroundTab = true;

+ 2 - 2
extension/core/content/content-autosave.js

@@ -47,7 +47,7 @@ this.singlefile.autosave = this.singlefile.autosave || (async () => {
 				if (!options.removeFrames && this.frameTree) {
 					framesData = await frameTree.getAsync(options);
 				}
-				browser.runtime.sendMessage({ processContent: true, content: docHelper.serialize(document, false), canvasData: docData.canvasData, stylesheetContents: docData.stylesheetContents, currentSrcImages: docData.currentSrcImages, framesData, url: location.href });
+				browser.runtime.sendMessage({ processContent: true, content: docHelper.serialize(document, false), canvasData: docData.canvasData, stylesheetContents: docData.stylesheetContents, imageData: docData.imageData, framesData, url: location.href });
 				docHelper.postProcessDoc(document, window);
 				singlefile.pageAutoSaved = true;
 			}
@@ -75,7 +75,7 @@ this.singlefile.autosave = this.singlefile.autosave || (async () => {
 	function onUnload() {
 		if (!singlefile.pageAutoSaved) {
 			const docData = docHelper.preProcessDoc(document, window, options);
-			browser.runtime.sendMessage({ processContent: true, content: docHelper.serialize(document), canvasData: docData.canvasData, stylesheetContents: docData.stylesheetContents, currentSrcImages: docData.currentSrcImages, framesData: this.frameTree && !options.removeFrames && frameTree.getSync(options), url: location.href });
+			browser.runtime.sendMessage({ processContent: true, content: docHelper.serialize(document), canvasData: docData.canvasData, stylesheetContents: docData.stylesheetContents, imageData: docData.imageData, framesData: this.frameTree && !options.removeFrames && frameTree.getSync(options), url: location.href });
 		}
 	}
 

+ 31 - 16
lib/single-file/doc-helper.js

@@ -23,6 +23,7 @@ this.docHelper = this.docHelper || (() => {
 	const REMOVED_CONTENT_ATTRIBUTE_NAME = "data-single-file-removed-content";
 	const PRESERVED_SPACE_ELEMENT_ATTRIBUTE_NAME = "data-single-file-preserved-space-element";
 	const WIN_ID_ATTRIBUTE_NAME = "data-frame-tree-win-id";
+	const RESPONSIVE_IMAGE_ATTRIBUTE_NAME = "data-single-file-responsive-image";
 
 	return {
 		preProcessDoc,
@@ -30,7 +31,8 @@ this.docHelper = this.docHelper || (() => {
 		serialize,
 		windowIdAttributeName,
 		preservedSpaceAttributeName,
-		removedContentAttributeName
+		removedContentAttributeName,
+		responsiveImagesAttributeName
 	};
 
 	function preProcessDoc(doc, win, options) {
@@ -61,7 +63,7 @@ this.docHelper = this.docHelper || (() => {
 		return {
 			canvasData: getCanvasData(doc),
 			stylesheetContents: getStylesheetContents(doc),
-			currentSrcImages: getCurrentSrcImages(doc)
+			imageData: getImageData(doc, options)
 		};
 	}
 
@@ -78,7 +80,11 @@ this.docHelper = this.docHelper || (() => {
 		if (options.compressHTML) {
 			doc.querySelectorAll("[" + preservedSpaceAttributeName(options.sessionId) + "]").forEach(element => element.removeAttribute(preservedSpaceAttributeName(options.sessionId)));
 		}
-		doc.querySelectorAll("[" + windowIdAttributeName(options.sessionId) + "]").forEach(element => element.removeAttribute(windowIdAttributeName(options.sessionId)));
+		doc.querySelectorAll("[" + responsiveImagesAttributeName(options.sessionId) + "]").forEach(element => element.removeAttribute(responsiveImagesAttributeName(options.sessionId)));
+	}
+
+	function responsiveImagesAttributeName(sessionId) {
+		return RESPONSIVE_IMAGE_ATTRIBUTE_NAME + (sessionId ? "-" + sessionId : "");
 	}
 
 	function preservedSpaceAttributeName(sessionId) {
@@ -121,26 +127,35 @@ this.docHelper = this.docHelper || (() => {
 		}
 	}
 
-	function getCurrentSrcImages(doc) {
+	function getImageData(doc, options) {
 		if (doc) {
-			const urls = [];
-			doc.querySelectorAll("[srcset], [data-srcset]").forEach((element, elementIndex) => {
+			const data = [];
+			doc.querySelectorAll("picture, img[srcset]").forEach((element, elementIndex) => {
 				const tagName = element.tagName.toLowerCase();
-				let imageElement;
-				if (tagName == "source") {
-					const parentElement = element.parentElement;
-					if (parentElement.tagName.toLowerCase() == "picture") {
-						imageElement = parentElement.querySelector("img");
-					}
+				let imageData = {}, imageElement;
+				element.setAttribute(responsiveImagesAttributeName(options.sessionId), elementIndex);
+				if (tagName == "picture") {
+					const sources = Array.from(element.querySelectorAll("source")).map(sourceElement => (
+						{ src: sourceElement.src, srcset: sourceElement.srcset }
+					));
+					imageElement = element.querySelector("img");
+					imageData.sources = sources;
 				}
 				if (tagName == "img") {
 					imageElement = element;
 				}
-				if (imageElement.naturalWidth > 1 && imageElement.naturalHeight > 1 && !imageElement.currentSrc.startsWith("data:")) {
-					urls[elementIndex] = imageElement.currentSrc;
-				}
+				imageData.source = {
+					clientWidth: imageElement.clientWidth,
+					clientHeight: imageElement.clientHeight,
+					naturalWidth: imageElement.naturalWidth,
+					naturalHeight: imageElement.naturalHeight,
+					width: imageElement.width,
+					height: imageElement.height,
+					src: (!imageElement.currentSrc.startsWith("data:") && imageElement.currentSrc) || (!imageElement.src.startsWith("data:") && imageElement.src)
+				};
+				data.push(imageData);
 			});
-			return urls;
+			return data;
 		}
 	}
 

+ 2 - 2
lib/single-file/frame-tree.js

@@ -90,7 +90,7 @@ this.frameTree = this.frameTree || (() => {
 				frameData.baseURI = messageFrameData.baseURI;
 				frameData.title = messageFrameData.title;
 				frameData.stylesheetContents = messageFrameData.stylesheetContents;
-				frameData.currentSrcImages = messageFrameData.currentSrcImages;
+				frameData.imageData = messageFrameData.imageData;
 				frameData.canvasData = messageFrameData.canvasData;
 				frameData.processed = messageFrameData.processed;
 				frameData.timeout = messageFrameData.timeout;
@@ -172,7 +172,7 @@ this.frameTree = this.frameTree || (() => {
 		const content = docHelper.serialize(document);
 		docHelper.postProcessDoc(document, window, options);
 		const baseURI = document.baseURI.split("#")[0];
-		return { windowId, content, baseURI, title: document.title, stylesheetContents: docData.stylesheetContents, currentSrcImages: docData.currentSrcImages, canvasData: docData.canvasData, processed: true };
+		return { windowId, content, baseURI, title: document.title, stylesheetContents: docData.stylesheetContents, imageData: docData.imageData, canvasData: docData.canvasData, processed: true };
 	}
 
 })();

+ 4 - 0
lib/single-file/single-file-browser.js

@@ -186,6 +186,10 @@ this.SingleFile = this.SingleFile || (() => {
 		static removedContentAttributeName(sessionId) {
 			return docHelper.removedContentAttributeName(sessionId);
 		}
+
+		static responsiveImagesAttributeName(sessionId) {
+			return docHelper.responsiveImagesAttributeName(sessionId);
+		}
 	}
 
 	return { getClass: () => SingleFileCore.getClass(Download, DOM, URL) };

+ 42 - 18
lib/single-file/single-file-core.js

@@ -130,7 +130,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 				const docData = DOM.preProcessDoc(this.options.doc, this.options.win, this.options);
 				this.options.canvasData = docData.canvasData;
 				this.options.stylesheetContents = docData.stylesheetContents;
-				this.options.currentSrcImages = docData.currentSrcImages;
+				this.options.imageData = docData.imageData;
 			}
 			this.options.content = this.options.content || (this.options.doc ? DOM.serialize(this.options.doc, false) : null);
 			this.onprogress = options.onprogress || (() => { });
@@ -399,26 +399,50 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 		}
 
 		removeSrcSet() {
-			this.doc.querySelectorAll("[srcset], [data-srcset]").forEach((element, elementIndex) => {
+			this.doc.querySelectorAll("picture, img[srcset]").forEach(element => {
 				const tagName = element.tagName.toLowerCase();
-				const currentSrcImage = this.options.currentSrcImages && this.options.currentSrcImages[elementIndex];
-				if (tagName == "source") {
-					const parentElement = element.parentElement;
-					if (parentElement.tagName.toLowerCase() == "picture") {
-						const imageElement = parentElement.querySelector("img");
-						if (imageElement && (imageElement.src || currentSrcImage)) {
-							element.remove();
-							if (currentSrcImage) {
-								imageElement.src = currentSrcImage;
-							}
+				const dataAttributeName = DOM.responsiveImagesAttributeName(this.options.sessionId);
+				const imageData = this.options.imageData[Number(element.getAttribute(dataAttributeName))];
+				element.removeAttribute(dataAttributeName);
+				if (imageData) {
+					if (tagName == "img") {
+						if (imageData.source.src && imageData.source.naturalWidth > 1 && imageData.source.naturalHeight > 1) {
+							element.removeAttribute("srcset");
+							element.removeAttribute("sizes");
+							element.src = imageData.source.src;
 						}
 					}
-				}
-				if (tagName == "img" && (element.src || currentSrcImage)) {
-					element.removeAttribute("srcset");
-					element.removeAttribute("sizes");
-					if (currentSrcImage) {
-						element.src = currentSrcImage;
+					if (tagName == "picture") {
+						const imageElement = element.querySelector("img");
+						if (imageData.source.src && imageData.source.naturalWidth > 1 && imageData.source.naturalHeight > 1) {
+							imageElement.removeAttribute("srcset");
+							imageElement.removeAttribute("sizes");
+							imageElement.src = imageData.source.src;
+							element.querySelectorAll("source").forEach(sourceElement => sourceElement.remove());
+						} else {
+							if (imageData.sources) {
+								element.querySelectorAll("source").forEach(sourceElement => {
+									if (!sourceElement.srcset && !sourceElement.dataset.srcset && !sourceElement.src) {
+										sourceElement.remove();
+									}
+								});
+								const sourceElements = element.querySelectorAll("source");
+								if (sourceElements.length) {
+									const lastSourceElement = sourceElements[sourceElements.length - 1];
+									if (lastSourceElement.src) {
+										imageElement.src = lastSourceElement.src;
+									} else {
+										imageElement.removeAttribute("src");
+									}
+									if (lastSourceElement.srcset || lastSourceElement.dataset.srcset) {
+										imageElement.srcset = lastSourceElement.srcset || lastSourceElement.dataset.srcset;
+									} else {
+										imageElement.removeAttribute("srcset");
+									}
+									element.querySelectorAll("source").forEach(sourceElement => sourceElement.remove());
+								}
+							}
+						}
 					}
 				}
 			});