Ver Fonte

added "maximum idle time" option

Gildas há 7 anos atrás
pai
commit
369a1109ca

+ 20 - 0
_locales/en/messages.json

@@ -151,6 +151,10 @@
         "message": "save deferred images",
         "description": "Options page label: 'save deferred images'"
     },
+    "optionMaxLazyLoadImagesIdleTime": {
+        "message": "maximum idle time (ms)",
+        "description": "Options page label: 'maximum idle time (ms)'"
+    },
     "optionRemoveAlternativeImages": {
         "message": "remove images for alternative screen resolutions",
         "description": "Options page label: 'remove images for alternative screen resolutions'"
@@ -246,5 +250,21 @@
     "optionsResetTooltip": {
         "message": "Reset all options to their default values",
         "description": "Options 'Reset' button tooltip"
+    },
+    "logPanelDeferredImages": {
+        "message": "Deferred images",
+        "description": "Label 'Deferred images' in the log panel"
+    },
+    "logPanelFrameContents": {
+        "message": "Frame contents",
+        "description": "Label 'Frame contents' in the log panel"
+    },
+    "logPanelStep": {
+        "message": "Step",
+        "description": "Label 'Step' (for 'Step x / 4') in the log panel"
+    },
+    "logPanelWidth": {
+        "message": "120px",
+        "description": "Width of the log panel"
     }
 }

+ 20 - 0
_locales/fr/messages.json

@@ -151,6 +151,10 @@
         "message": "sauver les images chargées de manière différées",
         "description": "Options page label: 'save deferred images'"
     },
+    "optionMaxLazyLoadImagesIdleTime": {
+        "message": "temps d'inactivité maximal (ms)",
+        "description": "Options page label: 'maximum idle time (ms)'"
+    },
     "optionRemoveAlternativeImages": {
         "message": "supprimer les images pour des résolutions d'écran alternatives",
         "description": "Options page label: 'remove images for alternative screen resolutions'"
@@ -246,5 +250,21 @@
     "optionsResetTooltip": {
         "message": "Remet toutes les options à leur valeur par défaut",
         "description": "Options 'Reset' button tooltip"
+    },
+    "logPanelDeferredImages": {
+        "message": "Image différées",
+        "description": "Label 'Deferred images' in the log panel"
+    },
+    "logPanelFrameContents": {
+        "message": "Contenus de frame",
+        "description": "Label 'Frame contents' in the log panel"
+    },
+    "logPanelStep": {
+        "message": "Etape",
+        "description": "Label 'Step' (for 'Step x / 4') in the log panel"
+    },
+    "logPanelWidth": {
+        "message": "130px",
+        "description": "Width of the log panel"
     }
 }

+ 20 - 0
_locales/ja/messages.json

@@ -151,6 +151,10 @@
         "message": "遅延画像を保存する",
         "description": "オプションのページラベル: '遅延画像を保存する'"
     },
+    "optionMaxLazyLoadImagesIdleTime": {
+        "message": "maximum idle time (ms)",
+        "description": "Options page label: 'maximum idle time (ms)'"
+    },
     "optionRemoveAlternativeImages": {
         "message": "代替画面解像度用の画像を削除します",
         "description": "オプションのページラベル: '代替画面解像度用の画像を削除します'"
@@ -246,5 +250,21 @@
     "optionsResetTooltip": {
         "message": "すべてのオプションを規定値にリセットする",
         "description": "オプション 'リセット'ボタンのツールチップ"
+    },
+    "logPanelDeferredImages": {
+        "message": "Deferred images",
+        "description": "Label 'Deferred images' in the log panel"
+    },
+    "logPanelFrameContents": {
+        "message": "Frame contents",
+        "description": "Label 'Frame contents' in the log panel"
+    },
+    "logPanelStep": {
+        "message": "Step",
+        "description": "Label 'Step' (for 'Step x / 4') in the log panel"
+    },
+    "logPanelWidth": {
+        "message": "120px",
+        "description": "Width of the log panel"
     }
 }

+ 20 - 0
_locales/pl/messages.json

@@ -151,6 +151,10 @@
         "message": "zapisuj odroczone obrazy",
         "description": "Options page label: 'save deferred images'"
     },
+    "optionMaxLazyLoadImagesIdleTime": {
+        "message": "maximum idle time (ms)",
+        "description": "Options page label: 'maximum idle time (ms)'"
+    },
     "optionRemoveAlternativeImages": {
         "message": "usuwaj obrazy dla alternatywnych rozdzielczości ekranu",
         "description": "Options page label: 'remove images for alternative screen resolutions'"
@@ -246,5 +250,21 @@
     "optionsResetTooltip": {
         "message": "Zresetuj wszystkie opcje do ich wartości domyślnych",
         "description": "Options 'Reset' button tooltip"
+    },
+    "logPanelDeferredImages": {
+        "message": "Deferred images",
+        "description": "Label 'Deferred images' in the log panel"
+    },
+    "logPanelFrameContents": {
+        "message": "Frame contents",
+        "description": "Label 'Frame contents' in the log panel"
+    },
+    "logPanelStep": {
+        "message": "Step",
+        "description": "Label 'Step' (for 'Step x / 4') in the log panel"
+    },
+    "logPanelWidth": {
+        "message": "120px",
+        "description": "Width of the log panel"
     }
 }

+ 20 - 0
_locales/ru/messages.json

@@ -151,6 +151,10 @@
         "message": "сохранить отложенные изображения",
         "description": "Options page label: 'save deferred images'"
     },
+    "optionMaxLazyLoadImagesIdleTime": {
+        "message": "maximum idle time (ms)",
+        "description": "Options page label: 'maximum idle time (ms)'"
+    },
     "optionRemoveAlternativeImages": {
         "message": "удалить изображения для альтернативных разрешений экрана",
         "description": "Options page label: 'remove images for alternative screen resolutions'"
@@ -246,5 +250,21 @@
     "optionsResetTooltip": {
         "message": "Сбросить все параметры к значениям по умолчанию",
         "description": "Options 'Reset' button tooltip"
+    },
+    "logPanelDeferredImages": {
+        "message": "Deferred images",
+        "description": "Label 'Deferred images' in the log panel"
+    },
+    "logPanelFrameContents": {
+        "message": "Frame contents",
+        "description": "Label 'Frame contents' in the log panel"
+    },
+    "logPanelStep": {
+        "message": "Step",
+        "description": "Label 'Step' (for 'Step x / 4') in the log panel"
+    },
+    "logPanelWidth": {
+        "message": "120px",
+        "description": "Width of the log panel"
     }
 }

+ 25 - 4
_locales/zh_CN/messages.json

@@ -131,7 +131,7 @@
     "optionConfirmInfobar": {
         "message": "打开一个提示窗口以编辑信息栏内容",
         "description": "选项页标签: '打开一个提示窗口以编辑信息栏内容'"
-},
+    },
     "optionsFileNameSubTitle": {
         "message": "文件名",
         "description": "选项页副标题: '文件名'",
@@ -187,6 +187,10 @@
         "description": "选项页标签: '保存延迟加载的图像'",
         "hash": "5f4eed2da3b26bbeec69d425849a83ab"
     },
+    "optionMaxLazyLoadImagesIdleTime": {
+        "message": "maximum idle time (ms)",
+        "description": "Options page label: 'maximum idle time (ms)'"
+    },
     "optionRemoveAlternativeImages": {
         "message": "移除备用分辨率的图像",
         "description": "选项页标签: '移除备用分辨率的图像'",
@@ -307,6 +311,23 @@
         "description": "选项按钮'重置'的提示",
         "hash": "4e8ef324894a6ed91b686843cacb2118"
     },
-
-    "__WET_LOCALE__": { "message": "zh-cn" }
-}
+    "logPanelDeferredImages": {
+        "message": "Deferred images",
+        "description": "Label 'Deferred images' in the log panel"
+    },
+    "logPanelFrameContents": {
+        "message": "Frame contents",
+        "description": "Label 'Frame contents' in the log panel"
+    },
+    "logPanelStep": {
+        "message": "Step",
+        "description": "Label 'Step' (for 'Step x / 4') in the log panel"
+    },
+    "logPanelWidth": {
+        "message": "120px",
+        "description": "Width of the log panel"
+    },
+    "__WET_LOCALE__": {
+        "message": "zh-cn"
+    }
+}

+ 4 - 0
extension/core/bg/config.js

@@ -32,6 +32,7 @@ singlefile.config = (() => {
 		compressHTML: true,
 		compressCSS: true,
 		lazyLoadImages: true,
+		maxLazyLoadImagesIdleTime: 1000,
 		filenameTemplate: "{page-title} ({date-iso} {time-locale}).html",
 		infobarTemplate: "",
 		confirmInfobar: false,
@@ -159,6 +160,9 @@ singlefile.config = (() => {
 			config.autoSaveLoad = false;
 			config.autoSaveUnload = false;
 		}
+		if (config.maxLazyLoadImagesIdleTime === undefined) {
+			config.maxLazyLoadImagesIdleTime = 1000;
+		}
 	}
 
 	async function getConfig() {

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

@@ -93,7 +93,7 @@ this.singlefile.top = this.singlefile.top || (() => {
 			preInitializationPromises.push(frameTreePromise);
 		}
 		if (options.lazyLoadImages) {
-			const lazyLoadPromise = lazyLoader.process();
+			const lazyLoadPromise = lazyLoader.process(options);
 			singlefile.ui.onLoadingDeferResources();
 			lazyLoadPromise.then(() => singlefile.ui.onLoadDeferResources());
 			preInitializationPromises.push(lazyLoadPromise);

+ 9 - 3
extension/ui/bg/options.js

@@ -32,6 +32,7 @@
 	const compressHTMLLabel = document.getElementById("compressHTMLLabel");
 	const compressCSSLabel = document.getElementById("compressCSSLabel");
 	const lazyLoadImagesLabel = document.getElementById("lazyLoadImagesLabel");
+	const maxLazyLoadImagesIdleTimeLabel = document.getElementById("maxLazyLoadImagesIdleTimeLabel");
 	const addMenuEntryLabel = document.getElementById("addMenuEntryLabel");
 	const filenameTemplateLabel = document.getElementById("filenameTemplateLabel");
 	const shadowEnabledLabel = document.getElementById("shadowEnabledLabel");
@@ -64,7 +65,6 @@
 	const miscLabel = document.getElementById("miscLabel");
 	const helpLabel = document.getElementById("helpLabel");
 	const resetButton = document.getElementById("resetButton");
-
 	const removeHiddenElementsInput = document.getElementById("removeHiddenElementsInput");
 	const removeUnusedStylesInput = document.getElementById("removeUnusedStylesInput");
 	const removeFramesInput = document.getElementById("removeFramesInput");
@@ -74,6 +74,7 @@
 	const compressHTMLInput = document.getElementById("compressHTMLInput");
 	const compressCSSInput = document.getElementById("compressCSSInput");
 	const lazyLoadImagesInput = document.getElementById("lazyLoadImagesInput");
+	const maxLazyLoadImagesIdleTimeInput = document.getElementById("maxLazyLoadImagesIdleTimeInput");
 	const contextMenuEnabledInput = document.getElementById("contextMenuEnabledInput");
 	const filenameTemplateInput = document.getElementById("filenameTemplateInput");
 	const shadowEnabledInput = document.getElementById("shadowEnabledInput");
@@ -125,6 +126,7 @@
 		}
 		document.querySelectorAll("details").forEach(detailElement => detailElement.open = Boolean(expandAllButton.className));
 	}, false);
+	lazyLoadImagesInput.addEventListener("click", () => maxLazyLoadImagesIdleTimeInput.disabled = !lazyLoadImagesInput.checked, false);
 	document.body.onchange = update;
 	removeHiddenElementsLabel.textContent = browser.i18n.getMessage("optionRemoveHiddenElements");
 	removeUnusedStylesLabel.textContent = browser.i18n.getMessage("optionRemoveUnusedStyles");
@@ -135,6 +137,7 @@
 	compressHTMLLabel.textContent = browser.i18n.getMessage("optionCompressHTML");
 	compressCSSLabel.textContent = browser.i18n.getMessage("optionCompressCSS");
 	lazyLoadImagesLabel.textContent = browser.i18n.getMessage("optionLazyLoadImages");
+	maxLazyLoadImagesIdleTimeLabel.textContent = browser.i18n.getMessage("optionMaxLazyLoadImagesIdleTime");
 	addMenuEntryLabel.textContent = browser.i18n.getMessage("optionAddMenuEntry");
 	filenameTemplateLabel.textContent = browser.i18n.getMessage("optionFilenameTemplate");
 	shadowEnabledLabel.textContent = browser.i18n.getMessage("optionDisplayShadow");
@@ -182,6 +185,8 @@
 		compressHTMLInput.checked = config.compressHTML;
 		compressCSSInput.checked = config.compressCSS;
 		lazyLoadImagesInput.checked = config.lazyLoadImages;
+		maxLazyLoadImagesIdleTimeInput.value = config.maxLazyLoadImagesIdleTime;
+		maxLazyLoadImagesIdleTimeInput.disabled = !config.lazyLoadImages;
 		contextMenuEnabledInput.checked = config.contextMenuEnabled;
 		filenameTemplateInput.value = config.filenameTemplate;
 		shadowEnabledInput.checked = config.shadowEnabled;
@@ -221,18 +226,19 @@
 			compressHTML: compressHTMLInput.checked,
 			compressCSS: compressCSSInput.checked,
 			lazyLoadImages: lazyLoadImagesInput.checked,
+			maxLazyLoadImagesIdleTime: Math.max(maxLazyLoadImagesIdleTimeInput.value, 0),
 			contextMenuEnabled: contextMenuEnabledInput.checked,
 			filenameTemplate: filenameTemplateInput.value,
 			shadowEnabled: shadowEnabledInput.checked,
 			maxResourceSizeEnabled: maxResourceSizeEnabledInput.checked,
-			maxResourceSize: maxResourceSizeInput.value,
+			maxResourceSize: Math.max(maxResourceSizeInput.value, 0),
 			confirmFilename: confirmFilenameInput.checked,
 			removeAudioSrc: removeAudioSrcInput.checked,
 			removeVideoSrc: removeVideoSrcInput.checked,
 			displayInfobar: displayInfobarInput.checked,
 			displayStats: displayStatsInput.checked,
 			backgroundSave: backgroundSaveInput.checked,
-			autoSaveDelay: autoSaveDelayInput.value,
+			autoSaveDelay: Math.max(autoSaveDelayInput.value, 0),
 			autoSaveLoad: autoSaveLoadInput.checked,
 			autoSaveUnload: autoSaveUnloadInput.checked,
 			autoSaveLoadOrUnload: autoSaveLoadOrUnloadInput.checked,

+ 9 - 9
extension/ui/content/content-ui.js

@@ -18,7 +18,7 @@
  *   along with SingleFile.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-/* global document, getComputedStyle, addEventListener, removeEventListener, requestAnimationFrame, scrollX, scrollY, setTimeout */
+/* global browser, document, getComputedStyle, addEventListener, removeEventListener, requestAnimationFrame, scrollX, scrollY, setTimeout */
 
 this.singlefile.ui = this.singlefile.ui || (() => {
 
@@ -67,22 +67,22 @@ this.singlefile.ui = this.singlefile.ui || (() => {
 			}
 		},
 		onLoadingDeferResources() {
-			appendLog("Deferred images", "…");
+			appendLog(browser.i18n.getMessage("logPanelDeferredImages"), "…");
 		},
 		onLoadDeferResources() {
-			appendLog("Deferred images", "✓");
+			appendLog(browser.i18n.getMessage("logPanelDeferredImages"), "✓");
 		},
 		onLoadingFrames() {
-			appendLog("Frame contents", "…");
+			appendLog(browser.i18n.getMessage("logPanelFrameContents"), "…");
 		},
 		onLoadFrames() {
-			appendLog("Frame contents", "✓");
+			appendLog(browser.i18n.getMessage("logPanelFrameContents"), "✓");
 		},
 		onStartStage(step) {
-			appendLog(`Step ${step + 1} / 4`, "…");
+			appendLog(`${browser.i18n.getMessage("logPanelStep")} ${step + 1} / 4`, "…");
 		},
 		onEndStage(step) {
-			appendLog(`Step ${step + 1} / 4`, "✓");
+			appendLog(`${browser.i18n.getMessage("logPanelStep")} ${step + 1} / 4`, "✓");
 		},
 		onPageLoading() { },
 		onLoadPage() { },
@@ -261,11 +261,11 @@ this.singlefile.ui = this.singlefile.ui || (() => {
 		logsWindowElement.style.setProperty("opacity", "0.9", "important");
 		logsWindowElement.style.setProperty("padding", "4px", "important");
 		logsWindowElement.style.setProperty("position", "fixed", "important");
-		logsWindowElement.style.setProperty("bottom", "8px", "important");
+		logsWindowElement.style.setProperty("bottom", "24px", "important");
 		logsWindowElement.style.setProperty("left", "8px", "important");
 		logsWindowElement.style.setProperty("z-index", 2147483647, "important");
 		logsWindowElement.style.setProperty("background-color", "white", "important");
-		logsWindowElement.style.setProperty("min-width", "120px", "important");
+		logsWindowElement.style.setProperty("min-width", browser.i18n.getMessage("logPanelWidth"), "important");
 		logsWindowElement.style.setProperty("min-height", "16px", "important");
 		logsWindowElement.style.setProperty("transition", "height 100ms", "important");
 		logsWindowElement.style.setProperty("will-change", "height", "important");

+ 7 - 2
extension/ui/pages/help.html

@@ -224,12 +224,17 @@
 					<li>
 						<span class="option">save deferred images</span>
 						<p>Check this option to save all the deferred images that are not displayed. This may help to save all the
-							images
-							without scrolling the page. This feature does its best effort and is not guaranteed to work on all sites.</p>
+							images without scrolling the page. This feature does its best effort and is not guaranteed to work on all sites.</p>
 						<p class="notice">It is recommended to
 							<u>check</u> this option</p>
 					</li>
 
+					<li>
+						<span class="option">maximum idle time (ms)</span>
+						<p>Specify the maximum delay of time to wait for deferred images. You can increase this value if for example the
+							network conditions are degraded. You can also decrease this value otherwise.</p>
+					</li>
+
 					<li>
 						<span class="option">remove images for alternative screen resolutions</span>
 						<p>Check this option to remove images that are alternatives in lower and/or higher resolutions to the ones

+ 4 - 0
extension/ui/pages/options.css

@@ -37,6 +37,10 @@ input[type="number"] {
     max-width: 40px;
 }
 
+input.large-input {
+    min-width: 60px;
+}
+
 h3 {
     padding-left: 8px;
     margin-bottom: 10px;

+ 4 - 0
extension/ui/pages/options.html

@@ -72,6 +72,10 @@
 			<label for="lazyLoadImagesInput" id="lazyLoadImagesLabel"></label>
 			<input type="checkbox" id="lazyLoadImagesInput">
 		</div>
+		<div class="option second-level">
+			<label for="maxLazyLoadImagesIdleTimeInput" id="maxLazyLoadImagesIdleTimeLabel"></label>
+			<input type="number" class="large-input" id="maxLazyLoadImagesIdleTimeInput">
+		</div>
 		<div class="option">
 			<label for="removeAlternativeImagesInput" id="removeAlternativeImagesLabel"></label>
 			<input type="checkbox" id="removeAlternativeImagesInput">

+ 10 - 13
lib/lazy/content-lazy-loader.js

@@ -22,9 +22,6 @@
 
 this.lazyLoader = this.lazyLoader || (() => {
 
-	const LAZY_LOADING_TIMEOUT = 1000;
-	const IDLE_LAZY_LOADING_TIMEOUT = 1200;
-	const MAX_LAZY_LOADING_TIMEOUT = 30000;
 	const SCRIPT_TAG_NAME = "script";
 	const MONITORED_ATTRIBUTES = ["src", "srcset"];
 	const ATTRIBUTES_MUTATION_TYPE = "attributes";
@@ -33,19 +30,19 @@ this.lazyLoader = this.lazyLoader || (() => {
 
 	return { process };
 
-	function process() {
+	function process(options) {
 		return new Promise(resolve => {
 			let timeoutId, srcAttributeChanged;
 			const idleTimeoutId = timeout.set(() => {
 				if (!srcAttributeChanged) {
 					timeout.clear(timeoutId);
-					lazyLoadEnd(maxTimeoutId, idleTimeoutId, observer, resolve);
+					lazyLoadEnd(maxTimeoutId, idleTimeoutId, observer, options, resolve);
 				}
-			}, IDLE_LAZY_LOADING_TIMEOUT);
+			}, options.maxLazyLoadImagesIdleTime * 1.2);
 			const maxTimeoutId = timeout.set(() => {
 				timeout.clear(timeoutId);
-				lazyLoadEnd(maxTimeoutId, idleTimeoutId, observer, resolve);
-			}, MAX_LAZY_LOADING_TIMEOUT);
+				lazyLoadEnd(maxTimeoutId, idleTimeoutId, observer, options, resolve);
+			}, options.maxLazyLoadImagesIdleTime * 10);
 			const observer = new MutationObserver(mutations => {
 				mutations = mutations.filter(mutation => mutation.type == ATTRIBUTES_MUTATION_TYPE);
 				if (mutations.length) {
@@ -55,7 +52,7 @@ this.lazyLoader = this.lazyLoader || (() => {
 						}
 					});
 					srcAttributeChanged = true;
-					timeoutId = deferLazyLoadEnd(timeoutId, maxTimeoutId, idleTimeoutId, observer, resolve);
+					timeoutId = deferLazyLoadEnd(timeoutId, maxTimeoutId, idleTimeoutId, observer, options, resolve);
 				}
 			});
 			observer.observe(document, { attributeFilter: MONITORED_ATTRIBUTES, subtree: true, childList: true, attributes: true });
@@ -63,15 +60,15 @@ this.lazyLoader = this.lazyLoader || (() => {
 		});
 	}
 
-	function deferLazyLoadEnd(timeoutId, maxTimeoutId, idleTimeoutId, observer, resolve) {
+	function deferLazyLoadEnd(timeoutId, maxTimeoutId, idleTimeoutId, observer, options, resolve) {
 		timeout.clear(timeoutId);
-		return timeout.set(() => lazyLoadEnd(maxTimeoutId, idleTimeoutId, observer, resolve), LAZY_LOADING_TIMEOUT);
+		return timeout.set(() => lazyLoadEnd(maxTimeoutId, idleTimeoutId, observer, options, resolve), options.maxLazyLoadImagesIdleTime);
 	}
 
-	function lazyLoadEnd(maxTimeoutId, idleTimeoutId, observer, resolve) {
+	function lazyLoadEnd(maxTimeoutId, idleTimeoutId, observer, options, resolve) {
 		timeout.clear(maxTimeoutId);
 		timeout.clear(idleTimeoutId);
-		timeout.set(resolve, LAZY_LOADING_TIMEOUT);
+		timeout.set(resolve, options.maxLazyLoadImagesIdleTime);
 		injectScript(SCRIPT_AFTER_PATH);
 		observer.disconnect();
 	}

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

@@ -46,7 +46,7 @@ this.frameTree = this.frameTree || (() => {
 				window.stop();
 				initRequest(message);
 				if (message.options.lazyLoadImages && window.lazyLoader) {
-					lazyLoader.process();
+					lazyLoader.process(message.options);
 				}
 			} else if (message.method == INIT_RESPONSE_MESSAGE) {
 				const port = event.ports[0];