Browse Source

Added support of user scripts in iframes

Former-commit-id: 94d4a773286b75456c41d118f7f051751ddff409
Gildas 6 years ago
parent
commit
3f0c339ea3

+ 7 - 15
extension/core/content/content-bootstrap.js

@@ -21,7 +21,7 @@
  *   Source.
  */
 
-/* global browser, window, addEventListener, removeEventListener, document, location, setTimeout, CustomEvent, dispatchEvent */
+/* global browser, window, addEventListener, removeEventListener, document, location, setTimeout */
 
 this.singlefile.extension.core.content.bootstrap = this.singlefile.extension.core.content.bootstrap || (async () => {
 
@@ -37,14 +37,6 @@ this.singlefile.extension.core.content.bootstrap = this.singlefile.extension.cor
 	browser.runtime.onMessage.addListener(message => { onMessage(message); });
 	browser.runtime.sendMessage({ method: "ui.processInit" });
 	addEventListener("single-file-push-state", () => browser.runtime.sendMessage({ method: "ui.processInit" }));
-	addEventListener("single-file-user-script-init", () => singlefile.waitForUserScript = async eventPrefixName => {
-		const event = new CustomEvent(eventPrefixName + "-request", { cancelable: true });
-		const promiseResponse = new Promise(resolve => addEventListener(eventPrefixName + "-response", resolve));
-		dispatchEvent(event);
-		if (event.defaultPrevented) {
-			await promiseResponse;
-		}
-	});
 	return {};
 
 	async function onMessage(message) {
@@ -84,14 +76,14 @@ this.singlefile.extension.core.content.bootstrap = this.singlefile.extension.cor
 				if (!options.removeFrames && singlefile.lib.frameTree.content.frames && window.frames && window.frames.length) {
 					frames = await singlefile.lib.frameTree.content.frames.getAsync(options);
 				}
-				if (options.userScriptEnabled && singlefile.waitForUserScript) {
-					await singlefile.waitForUserScript("single-file-on-before-capture");
+				if (options.userScriptEnabled && helper.waitForUserScript) {
+					await helper.waitForUserScript(helper.ON_BEFORE_CAPTURE_EVENT_NAME);
 				}
 				const docData = helper.preProcessDoc(document, window, options);
 				savePage(docData, frames);
 				helper.postProcessDoc(document, docData.markedElements);
-				if (options.userScriptEnabled && singlefile.waitForUserScript) {
-					await singlefile.waitForUserScript("single-file-on-after-capture");
+				if (options.userScriptEnabled && helper.waitForUserScript) {
+					await helper.waitForUserScript(helper.ON_AFTER_CAPTURE_EVENT_NAME);
 				}
 				pageAutoSaved = true;
 				autoSavingPage = false;
@@ -120,8 +112,8 @@ this.singlefile.extension.core.content.bootstrap = this.singlefile.extension.cor
 			if (!options.removeFrames && singlefile.lib.frameTree.content.frames && window.frames && window.frames.length) {
 				frames = singlefile.lib.frameTree.content.frames.getSync(options);
 			}
-			if (options.userScriptEnabled && singlefile.waitForUserScript) {
-				singlefile.waitForUserScript("single-file-on-before-capture");
+			if (options.userScriptEnabled && helper.waitForUserScript) {
+				helper.waitForUserScript(helper.ON_BEFORE_CAPTURE_EVENT_NAME);
 			}
 			const docData = helper.preProcessDoc(document, window, options);
 			savePage(docData, frames);

+ 0 - 6
extension/core/content/content-main.js

@@ -188,17 +188,11 @@ this.singlefile.extension.core.content.main = this.singlefile.extension.core.con
 			options.doc = document;
 		}
 		if (!processor.cancelled) {
-			if (options.userScriptEnabled && singlefile.waitForUserScript) {
-				await singlefile.waitForUserScript("single-file-on-before-capture");
-			}
 			await processor.run();
 		}
 		if (!options.saveRawPage && !options.removeFrames && frames) {
 			frames.cleanup(options);
 		}
-		if (options.userScriptEnabled && singlefile.waitForUserScript) {
-			await singlefile.waitForUserScript("single-file-on-after-capture");
-		}
 		let page;
 		if (!processor.cancelled) {
 			if (options.confirmInfobarContent) {

+ 32 - 6
lib/frame-tree/content/content-frame-tree.js

@@ -60,7 +60,7 @@ this.singlefile.lib.frameTree.content.frames = this.singlefile.lib.frameTree.con
 			});
 		}
 	}
-	addEventListener.call(window, "message", event => {
+	addEventListener.call(window, "message", async event => {
 		if (typeof event.data == "string" && event.data.startsWith(MESSAGE_PREFIX)) {
 			event.preventDefault();
 			event.stopPropagation();
@@ -70,7 +70,7 @@ this.singlefile.lib.frameTree.content.frames = this.singlefile.lib.frameTree.con
 				if (message.options.loadDeferredImages && singlefile.lib.lazy.content.loader) {
 					singlefile.lib.lazy.content.loader.process(message.options);
 				}
-				initRequest(message);
+				await initRequestAsync(message);
 			} else if (message.method == CLEANUP_REQUEST_MESSAGE) {
 				cleanupRequest(message);
 			} else if ((!browser || !browser.runtime) && message.method == INIT_RESPONSE_MESSAGE) {
@@ -83,16 +83,16 @@ this.singlefile.lib.frameTree.content.frames = this.singlefile.lib.frameTree.con
 		getAsync: async options => {
 			const sessionId = options.sessionId || 0;
 			options = JSON.parse(JSON.stringify(options));
-			return new Promise(resolve => {
+			return new Promise(async resolve => {
 				sessions.set(sessionId, { frames: [], resolve });
-				initRequest({ windowId, sessionId, options });
+				await initRequestAsync({ windowId, sessionId, options });
 			});
 		},
 		getSync: options => {
 			const sessionId = options.sessionId || 0;
 			options = JSON.parse(JSON.stringify(options));
 			sessions.set(sessionId, { frames: [] });
-			initRequest({ windowId, sessionId, options });
+			initRequestSync({ windowId, sessionId, options });
 			return sessions.get(sessionId).frames;
 		},
 		cleanup: options => {
@@ -103,14 +103,40 @@ this.singlefile.lib.frameTree.content.frames = this.singlefile.lib.frameTree.con
 		TIMEOUT_INIT_REQUEST_MESSAGE
 	};
 
-	function initRequest(message) {
+	function initRequestSync(message) {
+		const waitForUserScript = singlefile.lib.helper.waitForUserScript;
 		const sessionId = message.sessionId;
 		if (!TOP_WINDOW) {
 			windowId = window.frameId = message.windowId;
 		}
 		processFrames(document, message.options, windowId, sessionId);
 		if (!TOP_WINDOW) {
+			if (message.options.userScriptEnabled && waitForUserScript) {
+				waitForUserScript(singlefile.lib.helper.ON_BEFORE_CAPTURE_EVENT_NAME);
+			}
 			sendInitResponse({ frames: [getFrameData(document, window, windowId, message.options)], sessionId, requestedFrameId: document.documentElement.dataset.requestedFrameId && windowId });
+			if (message.options.userScriptEnabled && waitForUserScript) {
+				waitForUserScript(singlefile.lib.helper.ON_AFTER_CAPTURE_EVENT_NAME);
+			}
+			delete document.documentElement.dataset.requestedFrameId;
+		}
+	}
+
+	async function initRequestAsync(message) {
+		const waitForUserScript = singlefile.lib.helper.waitForUserScript;
+		const sessionId = message.sessionId;
+		if (!TOP_WINDOW) {
+			windowId = window.frameId = message.windowId;
+		}
+		processFrames(document, message.options, windowId, sessionId);
+		if (!TOP_WINDOW) {
+			if (message.options.userScriptEnabled && waitForUserScript) {
+				await waitForUserScript(singlefile.lib.helper.ON_BEFORE_CAPTURE_EVENT_NAME);
+			}
+			sendInitResponse({ frames: [getFrameData(document, window, windowId, message.options)], sessionId, requestedFrameId: document.documentElement.dataset.requestedFrameId && windowId });
+			if (message.options.userScriptEnabled && waitForUserScript) {
+				await waitForUserScript(singlefile.lib.helper.ON_AFTER_CAPTURE_EVENT_NAME);
+			}
 			delete document.documentElement.dataset.requestedFrameId;
 		}
 	}

+ 6 - 0
lib/single-file/single-file-core.js

@@ -42,9 +42,15 @@ this.singlefile.lib.core = this.singlefile.lib.core || (() => {
 			}
 		}
 		async run() {
+			if (this.options.userScriptEnabled) {
+				await util.waitForUserScript(util.ON_BEFORE_CAPTURE_EVENT_NAME);
+			}
 			this.runner = new Runner(this.options, true);
 			await this.runner.loadPage();
 			await this.runner.initialize();
+			if (this.options.userScriptEnabled) {
+				await util.waitForUserScript(util.ON_AFTER_CAPTURE_EVENT_NAME);
+			}
 			await this.runner.run();
 		}
 		cancel() {

+ 14 - 0
lib/single-file/single-file-helper.js

@@ -21,10 +21,14 @@
  *   Source.
  */
 
+/* global CustomEvent, addEventListener, dispatchEvent */
+
 this.singlefile.lib.helper = this.singlefile.lib.helper || (() => {
 
 	const singlefile = this.singlefile;
 
+	const ON_BEFORE_CAPTURE_EVENT_NAME = "single-file-on-before-capture";
+	const ON_AFTER_CAPTURE_EVENT_NAME = "single-file-on-after-capture";
 	const REMOVED_CONTENT_ATTRIBUTE_NAME = "data-single-file-removed-content";
 	const HIDDEN_CONTENT_ATTRIBUTE_NAME = "data-single-file-hidden-content";
 	const PRESERVED_SPACE_ELEMENT_ATTRIBUTE_NAME = "data-single-file-preserved-space-element";
@@ -46,12 +50,22 @@ this.singlefile.lib.helper = this.singlefile.lib.helper || (() => {
 		bold: "700"
 	};
 
+	addEventListener("single-file-user-script-init", () => singlefile.lib.helper.waitForUserScript = async eventPrefixName => {
+		const event = new CustomEvent(eventPrefixName + "-request", { cancelable: true });
+		const promiseResponse = new Promise(resolve => addEventListener(eventPrefixName + "-response", resolve));
+		dispatchEvent(event);
+		if (event.defaultPrevented) {
+			await promiseResponse;
+		}
+	});
 	return {
 		initDoc,
 		preProcessDoc,
 		postProcessDoc,
 		serialize,
 		removeQuotes,
+		ON_BEFORE_CAPTURE_EVENT_NAME,
+		ON_AFTER_CAPTURE_EVENT_NAME,
 		WIN_ID_ATTRIBUTE_NAME,
 		PRESERVED_SPACE_ELEMENT_ATTRIBUTE_NAME,
 		REMOVED_CONTENT_ATTRIBUTE_NAME,

+ 9 - 0
lib/single-file/single-file-util.js

@@ -181,6 +181,15 @@ this.singlefile.lib.util = this.singlefile.lib.util || (() => {
 				removeQuotes(string) {
 					return helper.removeQuotes(string);
 				},
+				async waitForUserScript(eventPrefixName) {
+					if (helper.waitForUserScript) {
+						return helper.waitForUserScript(eventPrefixName);
+					} else {
+						return Promise.resolve();
+					}
+				},
+				ON_BEFORE_CAPTURE_EVENT_NAME: helper.ON_BEFORE_CAPTURE_EVENT_NAME,
+				ON_AFTER_CAPTURE_EVENT_NAME: helper.ON_AFTER_CAPTURE_EVENT_NAME,
 				WIN_ID_ATTRIBUTE_NAME: helper.WIN_ID_ATTRIBUTE_NAME,
 				REMOVED_CONTENT_ATTRIBUTE_NAME: helper.REMOVED_CONTENT_ATTRIBUTE_NAME,
 				HIDDEN_CONTENT_ATTRIBUTE_NAME: helper.HIDDEN_CONTENT_ATTRIBUTE_NAME,