Parcourir la source

execute content-hooks-web synchronously

Gildas il y a 6 ans
Parent
commit
7c6bc75541
2 fichiers modifiés avec 163 ajouts et 171 suppressions
  1. 2 170
      lib/hooks/content/content-hooks-frames.js
  2. 161 1
      lib/hooks/content/content-hooks-web.js

+ 2 - 170
lib/hooks/content/content-hooks-frames.js

@@ -21,7 +21,7 @@
  *   Source.
  */
 
-/* global browser, window, addEventListener, dispatchEvent, CustomEvent, document, HTMLDocument, FileReader, Blob */
+/* global browser, addEventListener, dispatchEvent, CustomEvent, document, HTMLDocument */
 
 this.singlefile.lib.hooks.content.frames = this.singlefile.lib.hooks.content.frames || (() => {
 
@@ -36,15 +36,12 @@ this.singlefile.lib.hooks.content.frames = this.singlefile.lib.hooks.content.fra
 		let scriptElement = document.createElement("script");
 		if (this.browser && browser.runtime && browser.runtime.getURL) {
 			scriptElement.src = browser.runtime.getURL("/lib/hooks/content/content-hooks-web.js");
+			scriptElement.async = false;
 		} else if (this.singlefile.lib.getFileContent) {
 			scriptElement.textContent = this.singlefile.lib.getFileContent("/lib/hooks/content/content-hooks-web.js");
 		}
 		(document.documentElement || document).appendChild(scriptElement);
 		scriptElement.remove();
-		scriptElement = document.createElement("script");
-		scriptElement.textContent = `(${hook.toString()})(${JSON.stringify({ LOAD_DEFERRED_IMAGES_START_EVENT, LOAD_DEFERRED_IMAGES_END_EVENT, NEW_FONT_FACE_EVENT })})`;
-		(document.documentElement || document).appendChild(scriptElement);
-		scriptElement.remove();
 		addEventListener(NEW_FONT_FACE_EVENT, event => fontFaces.push(event.detail));
 	}
 
@@ -56,169 +53,4 @@ this.singlefile.lib.hooks.content.frames = this.singlefile.lib.hooks.content.fra
 		IMAGE_LOADED_EVENT
 	};
 
-	function hook(constants) {
-		const {
-			LOAD_DEFERRED_IMAGES_START_EVENT,
-			LOAD_DEFERRED_IMAGES_END_EVENT,
-			NEW_FONT_FACE_EVENT
-		} = constants;
-		const FONT_STYLE_PROPERTIES = {
-			family: "font-family",
-			style: "font-style",
-			weight: "font-weight",
-			stretch: "font-stretch",
-			unicodeRange: "unicode-range",
-			variant: "font-variant",
-			featureSettings: "font-feature-settings"
-		};
-
-		const requestAnimationFrame = window.requestAnimationFrame;
-		const cancelAnimationFrame = window.cancelAnimationFrame;
-		const observers = new Map();
-		const observedElements = new Map();
-		let loadDeferredImages;
-
-		addEventListener(LOAD_DEFERRED_IMAGES_START_EVENT, () => {
-			loadDeferredImages = true;
-			const docBoundingRect = document.documentElement.getBoundingClientRect();
-			Array.from(observers).forEach(([intersectionObserver, observer]) => {
-				const rootBoundingRect = observer.options.root && observer.options.root.getBoundingClientRect();
-				observer.callback(observedElements.get(intersectionObserver).map(target => {
-					const boundingClientRect = target.getBoundingClientRect();
-					const isIntersecting = true;
-					const intersectionRatio = 1;
-					const rootBounds = observer.options && observer.options.root ? rootBoundingRect : docBoundingRect;
-					const time = 0;
-					return { target, intersectionRatio, boundingClientRect, intersectionRect: boundingClientRect, isIntersecting, rootBounds, time };
-				}), intersectionObserver);
-			});
-			if (pendingRequestAnimationFrameCalls.size) {
-				Array.from(pendingRequestAnimationFrameCalls).forEach(([id, callback]) => {
-					cancelAnimationFrame(id);
-					callback();
-				});
-			}
-		});
-
-		addEventListener(LOAD_DEFERRED_IMAGES_END_EVENT, () => {
-			loadDeferredImages = false;
-		});
-
-		let warningRequestAnimationFrameDisplayed;
-		const pendingRequestAnimationFrameCalls = new Map();
-		let lastTimestamp = 0;
-		let errorDetected;
-		window.requestAnimationFrame = function (callback) {
-			if (!warningRequestAnimationFrameDisplayed) {
-				console.warn("SingleFile is hooking the requestAnimationFrame and cancelAnimationFrame functions to load deferred images."); // eslint-disable-line no-console
-				warningRequestAnimationFrameDisplayed = true;
-			}
-			let requestId;
-			if (loadDeferredImages && !errorDetected) {
-				try {
-					requestId = 0;
-					callback(lastTimestamp);
-				} catch (error) {
-					errorDetected = true;
-					requestId = requestAnimationFrame(timestamp => {
-						lastTimestamp = timestamp;
-						callback(timestamp);
-					});
-				}
-			} else {
-				if (!loadDeferredImages) {
-					errorDetected = false;
-				}
-				requestId = requestAnimationFrame(timestamp => {
-					pendingRequestAnimationFrameCalls.delete(requestId);
-					lastTimestamp = timestamp;
-					callback(timestamp);
-				});
-				pendingRequestAnimationFrameCalls.set(requestId, callback);
-			}
-			return requestId;
-		};
-		window.requestAnimationFrame.toString = function () { return "requestAnimationFrame() { [native code] }"; };
-
-		window.cancelAnimationFrame = function (requestId) {
-			pendingRequestAnimationFrameCalls.delete(requestId);
-			return cancelAnimationFrame(requestId);
-		};
-		window.cancelAnimationFrame.toString = function () { return "cancelAnimationFrame() { [native code] }"; };
-
-		if (window.FontFace) {
-			const FontFace = window.FontFace;
-			let warningFontFaceDisplayed;
-			window.FontFace = function () {
-				if (!warningFontFaceDisplayed) {
-					console.warn("SingleFile is hooking the FontFace constructor to get font URLs."); // eslint-disable-line no-console
-					warningFontFaceDisplayed = true;
-				}
-				const detail = {};
-				detail["font-family"] = arguments[0];
-				detail.src = arguments[1];
-				const descriptors = arguments[2];
-				if (descriptors) {
-					Object.keys(descriptors).forEach(descriptor => {
-						if (FONT_STYLE_PROPERTIES[descriptor]) {
-							detail[FONT_STYLE_PROPERTIES[descriptor]] = descriptors[descriptor];
-						}
-					});
-				}
-				if (detail.src instanceof ArrayBuffer) {
-					const reader = new FileReader();
-					reader.readAsDataURL(new Blob([detail.src]));
-					reader.addEventListener("load", () => {
-						detail.src = "url(" + reader.result + ")";
-						dispatchEvent(new CustomEvent(NEW_FONT_FACE_EVENT, { detail }));
-					});
-				} else {
-					dispatchEvent(new CustomEvent(NEW_FONT_FACE_EVENT, { detail }));
-				}
-				return new FontFace(...arguments);
-			};
-			window.FontFace.toString = function () { return "function FontFace() { [native code]"; };
-		}
-
-		if (window.IntersectionObserver) {
-			const IntersectionObserver = window.IntersectionObserver;
-			const observeIntersection = IntersectionObserver.prototype.observe;
-			const unobserveIntersection = IntersectionObserver.prototype.unobserve;
-			let warningIntersectionObserverDisplayed;
-			window.IntersectionObserver = function () {
-				if (!warningIntersectionObserverDisplayed) {
-					console.warn("SingleFile is hooking the IntersectionObserver API to detect and load deferred images."); // eslint-disable-line no-console
-					warningIntersectionObserverDisplayed = true;
-				}
-				const intersectionObserver = new IntersectionObserver(...arguments);
-				const callback = arguments[0];
-				const options = arguments[1];
-				intersectionObserver.observe = function (targetElement) {
-					let targetElements = observedElements.get(intersectionObserver);
-					if (!targetElements) {
-						targetElements = [];
-						observedElements.set(intersectionObserver, targetElements);
-					}
-					targetElements.push(targetElement);
-					return observeIntersection.call(intersectionObserver, targetElement);
-				};
-				intersectionObserver.unobserve = function (targetElement) {
-					let targetElements = observedElements.get(intersectionObserver);
-					if (targetElements) {
-						targetElements = targetElements.filter(element => element <= targetElement);
-						if (targetElements.length) {
-							observedElements.set(intersectionObserver, targetElements);
-						} else {
-							observedElements.delete(intersectionObserver);
-						}
-					}
-					return unobserveIntersection.call(intersectionObserver, targetElement);
-				};
-				observers.set(intersectionObserver, { callback, options });
-				return intersectionObserver;
-			};
-			window.IntersectionObserver.toString = function () { return "function IntersectionObserver() { [native code]"; };
-		}
-	}
-
 })();

+ 161 - 1
lib/hooks/content/content-hooks-web.js

@@ -21,14 +21,32 @@
  *   Source.
  */
 
-/* global window, addEventListener, dispatchEvent, CustomEvent, document, screen, Element, UIEvent */
+/* global window, addEventListener, dispatchEvent, CustomEvent, document, screen, Element, UIEvent, FileReader, Blob */
 
 (() => {
 
+	// debugger
+
 	const LOAD_DEFERRED_IMAGES_START_EVENT = "single-file-load-deferred-images-start";
 	const LOAD_DEFERRED_IMAGES_END_EVENT = "single-file-load-deferred-images-end";
 	const LOAD_IMAGE_EVENT = "single-file-load-image";
 	const IMAGE_LOADED_EVENT = "single-file-image-loaded";
+	const NEW_FONT_FACE_EVENT = "single-file-new-font-face";
+	const FONT_STYLE_PROPERTIES = {
+		family: "font-family",
+		style: "font-style",
+		weight: "font-weight",
+		stretch: "font-stretch",
+		unicodeRange: "unicode-range",
+		variant: "font-variant",
+		featureSettings: "font-feature-settings"
+	};
+
+	const requestAnimationFrame = window.requestAnimationFrame;
+	const cancelAnimationFrame = window.cancelAnimationFrame;
+	const observers = new Map();
+	const observedElements = new Map();
+	let loadDeferredImages;
 
 	addEventListener(LOAD_DEFERRED_IMAGES_START_EVENT, () => {
 		const clientHeight = document.documentElement.clientHeight;
@@ -150,4 +168,146 @@
 		dispatchEvent(new UIEvent("scroll"));
 	});
 
+	addEventListener(LOAD_DEFERRED_IMAGES_START_EVENT, () => {
+		loadDeferredImages = true;
+		const docBoundingRect = document.documentElement.getBoundingClientRect();
+		Array.from(observers).forEach(([intersectionObserver, observer]) => {
+			const rootBoundingRect = observer.options.root && observer.options.root.getBoundingClientRect();
+			observer.callback(observedElements.get(intersectionObserver).map(target => {
+				const boundingClientRect = target.getBoundingClientRect();
+				const isIntersecting = true;
+				const intersectionRatio = 1;
+				const rootBounds = observer.options && observer.options.root ? rootBoundingRect : docBoundingRect;
+				const time = 0;
+				return { target, intersectionRatio, boundingClientRect, intersectionRect: boundingClientRect, isIntersecting, rootBounds, time };
+			}), intersectionObserver);
+		});
+		if (pendingRequestAnimationFrameCalls.size) {
+			Array.from(pendingRequestAnimationFrameCalls).forEach(([id, callback]) => {
+				cancelAnimationFrame(id);
+				callback();
+			});
+		}
+	});
+
+	addEventListener(LOAD_DEFERRED_IMAGES_END_EVENT, () => {
+		loadDeferredImages = false;
+	});
+
+	let warningRequestAnimationFrameDisplayed;
+	const pendingRequestAnimationFrameCalls = new Map();
+	let lastTimestamp = 0;
+	let errorDetected;
+	window.requestAnimationFrame = function (callback) {
+		if (!warningRequestAnimationFrameDisplayed) {
+			console.warn("SingleFile is hooking the requestAnimationFrame and cancelAnimationFrame functions to load deferred images."); // eslint-disable-line no-console
+			warningRequestAnimationFrameDisplayed = true;
+		}
+		let requestId;
+		if (loadDeferredImages && !errorDetected) {
+			try {
+				requestId = 0;
+				callback(lastTimestamp);
+			} catch (error) {
+				errorDetected = true;
+				requestId = requestAnimationFrame(timestamp => {
+					lastTimestamp = timestamp;
+					callback(timestamp);
+				});
+			}
+		} else {
+			if (!loadDeferredImages) {
+				errorDetected = false;
+			}
+			requestId = requestAnimationFrame(timestamp => {
+				pendingRequestAnimationFrameCalls.delete(requestId);
+				lastTimestamp = timestamp;
+				callback(timestamp);
+			});
+			pendingRequestAnimationFrameCalls.set(requestId, callback);
+		}
+		return requestId;
+	};
+	window.requestAnimationFrame.toString = function () { return "requestAnimationFrame() { [native code] }"; };
+
+	window.cancelAnimationFrame = function (requestId) {
+		pendingRequestAnimationFrameCalls.delete(requestId);
+		return cancelAnimationFrame(requestId);
+	};
+	window.cancelAnimationFrame.toString = function () { return "cancelAnimationFrame() { [native code] }"; };
+
+	if (window.FontFace) {
+		const FontFace = window.FontFace;
+		let warningFontFaceDisplayed;
+		window.FontFace = function () {
+			if (!warningFontFaceDisplayed) {
+				console.warn("SingleFile is hooking the FontFace constructor to get font URLs."); // eslint-disable-line no-console
+				warningFontFaceDisplayed = true;
+			}
+			const detail = {};
+			detail["font-family"] = arguments[0];
+			detail.src = arguments[1];
+			const descriptors = arguments[2];
+			if (descriptors) {
+				Object.keys(descriptors).forEach(descriptor => {
+					if (FONT_STYLE_PROPERTIES[descriptor]) {
+						detail[FONT_STYLE_PROPERTIES[descriptor]] = descriptors[descriptor];
+					}
+				});
+			}
+			if (detail.src instanceof ArrayBuffer) {
+				const reader = new FileReader();
+				reader.readAsDataURL(new Blob([detail.src]));
+				reader.addEventListener("load", () => {
+					detail.src = "url(" + reader.result + ")";
+					dispatchEvent(new CustomEvent(NEW_FONT_FACE_EVENT, { detail }));
+				});
+			} else {
+				dispatchEvent(new CustomEvent(NEW_FONT_FACE_EVENT, { detail }));
+			}
+			return new FontFace(...arguments);
+		};
+		window.FontFace.toString = function () { return "function FontFace() { [native code]"; };
+	}
+
+	if (window.IntersectionObserver) {
+		const IntersectionObserver = window.IntersectionObserver;
+		const observeIntersection = IntersectionObserver.prototype.observe;
+		const unobserveIntersection = IntersectionObserver.prototype.unobserve;
+		let warningIntersectionObserverDisplayed;
+		window.IntersectionObserver = function () {
+			if (!warningIntersectionObserverDisplayed) {
+				console.warn("SingleFile is hooking the IntersectionObserver API to detect and load deferred images."); // eslint-disable-line no-console
+				warningIntersectionObserverDisplayed = true;
+			}
+			const intersectionObserver = new IntersectionObserver(...arguments);
+			const callback = arguments[0];
+			const options = arguments[1];
+			intersectionObserver.observe = function (targetElement) {
+				let targetElements = observedElements.get(intersectionObserver);
+				if (!targetElements) {
+					targetElements = [];
+					observedElements.set(intersectionObserver, targetElements);
+				}
+				targetElements.push(targetElement);
+				return observeIntersection.call(intersectionObserver, targetElement);
+			};
+			intersectionObserver.unobserve = function (targetElement) {
+				let targetElements = observedElements.get(intersectionObserver);
+				if (targetElements) {
+					targetElements = targetElements.filter(element => element <= targetElement);
+					if (targetElements.length) {
+						observedElements.set(intersectionObserver, targetElements);
+					} else {
+						observedElements.delete(intersectionObserver);
+					}
+				}
+				return unobserveIntersection.call(intersectionObserver, targetElement);
+			};
+			observers.set(intersectionObserver, { callback, options });
+			return intersectionObserver;
+		};
+		window.IntersectionObserver.toString = function () { return "function IntersectionObserver() { [native code]"; };
+	}
+
 })();