|
|
@@ -31,10 +31,11 @@ this.singlefile.lib.processors.frameTree.content.frames = this.singlefile.lib.pr
|
|
|
const FRAMES_CSS_SELECTOR = "iframe, frame, object[type=\"text/html\"][data]";
|
|
|
const ALL_ELEMENTS_CSS_SELECTOR = "*";
|
|
|
const INIT_REQUEST_MESSAGE = "singlefile.frameTree.initRequest";
|
|
|
+ const ACK_INIT_REQUEST_MESSAGE = "singlefile.frameTree.ackInitRequest";
|
|
|
const CLEANUP_REQUEST_MESSAGE = "singlefile.frameTree.cleanupRequest";
|
|
|
const INIT_RESPONSE_MESSAGE = "singlefile.frameTree.initResponse";
|
|
|
const TARGET_ORIGIN = "*";
|
|
|
- const TIMEOUT_INIT_REQUEST_MESSAGE = 5000;
|
|
|
+ const TIMEOUT_INIT_REQUEST_MESSAGE = 750;
|
|
|
const TOP_WINDOW_ID = "0";
|
|
|
const WINDOW_ID_SEPARATOR = ".";
|
|
|
const TOP_WINDOW = window == window.top;
|
|
|
@@ -45,6 +46,7 @@ this.singlefile.lib.processors.frameTree.content.frames = this.singlefile.lib.pr
|
|
|
const MessageChannel = window.MessageChannel;
|
|
|
const document = window.document;
|
|
|
const setTimeout = window.setTimeout;
|
|
|
+ const clearTimeout = window.clearTimeout;
|
|
|
|
|
|
const sessions = new Map();
|
|
|
let windowId;
|
|
|
@@ -56,6 +58,9 @@ this.singlefile.lib.processors.frameTree.content.frames = this.singlefile.lib.pr
|
|
|
if (message.method == INIT_RESPONSE_MESSAGE) {
|
|
|
initResponse(message);
|
|
|
return Promise.resolve({});
|
|
|
+ } else if (message.method == ACK_INIT_REQUEST_MESSAGE) {
|
|
|
+ clearFrameTimeout(message.sessionId, message.windowId);
|
|
|
+ return Promise.resolve({});
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
@@ -65,12 +70,17 @@ this.singlefile.lib.processors.frameTree.content.frames = this.singlefile.lib.pr
|
|
|
event.preventDefault();
|
|
|
event.stopPropagation();
|
|
|
const message = JSON.parse(event.data.substring(MESSAGE_PREFIX.length));
|
|
|
- if (!TOP_WINDOW && message.method == INIT_REQUEST_MESSAGE) {
|
|
|
- window.stop();
|
|
|
- if (message.options.loadDeferredImages && singlefile.lib.processors.lazy.content.loader) {
|
|
|
- singlefile.lib.processors.lazy.content.loader.process(message.options);
|
|
|
+ if (message.method == INIT_REQUEST_MESSAGE) {
|
|
|
+ sendMessage(event.source, { method: ACK_INIT_REQUEST_MESSAGE, windowId: message.windowId, sessionId: message.sessionId });
|
|
|
+ if (!TOP_WINDOW) {
|
|
|
+ window.stop();
|
|
|
+ if (message.options.loadDeferredImages && singlefile.lib.processors.lazy.content.loader) {
|
|
|
+ singlefile.lib.processors.lazy.content.loader.process(message.options);
|
|
|
+ }
|
|
|
+ await initRequestAsync(message);
|
|
|
}
|
|
|
- await initRequestAsync(message);
|
|
|
+ } else if (message.method == ACK_INIT_REQUEST_MESSAGE) {
|
|
|
+ clearFrameTimeout(message.sessionId, message.windowId);
|
|
|
} else if (message.method == CLEANUP_REQUEST_MESSAGE) {
|
|
|
cleanupRequest(message);
|
|
|
} else if ((!browser || !browser.runtime) && message.method == INIT_RESPONSE_MESSAGE) {
|
|
|
@@ -84,14 +94,14 @@ this.singlefile.lib.processors.frameTree.content.frames = this.singlefile.lib.pr
|
|
|
const sessionId = options.sessionId || 0;
|
|
|
options = JSON.parse(JSON.stringify(options));
|
|
|
return new Promise(async resolve => {
|
|
|
- sessions.set(sessionId, { frames: [], resolve });
|
|
|
+ sessions.set(sessionId, { frames: [], timeouts: {}, resolve });
|
|
|
await initRequestAsync({ windowId, sessionId, options });
|
|
|
});
|
|
|
},
|
|
|
getSync: options => {
|
|
|
const sessionId = options.sessionId || 0;
|
|
|
options = JSON.parse(JSON.stringify(options));
|
|
|
- sessions.set(sessionId, { frames: [] });
|
|
|
+ sessions.set(sessionId, { frames: [], timeouts: {} });
|
|
|
initRequestSync({ windowId, sessionId, options });
|
|
|
return sessions.get(sessionId).frames;
|
|
|
},
|
|
|
@@ -199,18 +209,28 @@ this.singlefile.lib.processors.frameTree.content.frames = this.singlefile.lib.pr
|
|
|
|
|
|
function processFramesAsync(doc, frameElements, options, parentWindowId, sessionId) {
|
|
|
const frames = [];
|
|
|
+ let timeouts;
|
|
|
+ if (sessions.get(sessionId)) {
|
|
|
+ timeouts = sessions.get(sessionId).timeouts;
|
|
|
+ } else {
|
|
|
+ timeouts = {};
|
|
|
+ sessions.set(sessionId, { timeouts });
|
|
|
+ }
|
|
|
frameElements.forEach((frameElement, frameIndex) => {
|
|
|
const windowId = parentWindowId + WINDOW_ID_SEPARATOR + frameIndex;
|
|
|
frameElement.setAttribute(singlefile.lib.helper.WIN_ID_ATTRIBUTE_NAME, windowId);
|
|
|
frames.push({ windowId });
|
|
|
+ });
|
|
|
+ sendInitResponse({ frames, sessionId, requestedFrameId: doc.documentElement.dataset.requestedFrameId && parentWindowId });
|
|
|
+ frameElements.forEach((frameElement, frameIndex) => {
|
|
|
+ const windowId = parentWindowId + WINDOW_ID_SEPARATOR + frameIndex;
|
|
|
try {
|
|
|
sendMessage(frameElement.contentWindow, { method: INIT_REQUEST_MESSAGE, windowId, sessionId, options });
|
|
|
} catch (error) {
|
|
|
// ignored
|
|
|
}
|
|
|
- setTimeout.call(window, () => sendInitResponse({ frames: [{ windowId, processed: true }], sessionId }), TIMEOUT_INIT_REQUEST_MESSAGE);
|
|
|
+ timeouts[windowId] = setTimeout.call(window, () => sendInitResponse({ frames: [{ windowId, processed: true }], sessionId }), TIMEOUT_INIT_REQUEST_MESSAGE);
|
|
|
});
|
|
|
- sendInitResponse({ frames, sessionId, requestedFrameId: doc.documentElement.dataset.requestedFrameId && parentWindowId });
|
|
|
delete doc.documentElement.dataset.requestedFrameId;
|
|
|
}
|
|
|
|
|
|
@@ -228,6 +248,7 @@ this.singlefile.lib.processors.frameTree.content.frames = this.singlefile.lib.pr
|
|
|
try {
|
|
|
const frameWindow = frameElement.contentWindow;
|
|
|
frameWindow.stop();
|
|
|
+ clearFrameTimeout(sessionId, windowId);
|
|
|
processFrames(frameDoc, options, windowId, sessionId);
|
|
|
frames.push(getFrameData(frameDoc, frameWindow, windowId, options));
|
|
|
} catch (error) {
|
|
|
@@ -239,6 +260,17 @@ this.singlefile.lib.processors.frameTree.content.frames = this.singlefile.lib.pr
|
|
|
delete doc.documentElement.dataset.requestedFrameId;
|
|
|
}
|
|
|
|
|
|
+ function clearFrameTimeout(sessionId, windowId) {
|
|
|
+ const session = sessions.get(sessionId);
|
|
|
+ if (session && session.timeouts) {
|
|
|
+ const timeout = session.timeouts[windowId];
|
|
|
+ if (timeout) {
|
|
|
+ clearTimeout.call(window, timeout);
|
|
|
+ delete session.timeouts[windowId];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
function cleanupFrames(frameElements, parentWindowId, sessionId) {
|
|
|
frameElements.forEach((frameElement, frameIndex) => {
|
|
|
const windowId = parentWindowId + WINDOW_ID_SEPARATOR + frameIndex;
|