Explorar el Código

removed usage of native popups (fixes #132, #138)

Gildas hace 7 años
padre
commit
8031ef85be

+ 24 - 8
_locales/en/messages.json

@@ -244,8 +244,8 @@
         "description": "Options sub-title: 'Auto-settings rules'"
     },
     "optionsDeleteDisplayedRulesConfirm": {
-        "message": "Confirm deletion of all displayed rules",
-        "description": "Popup text 'Confirm deletion of all displayed rules'"
+        "message": "Confirm the deletion of all displayed rules",
+        "description": "Popup text 'Confirm the deletion of all displayed rules'"
     },
     "optionsDeleteRulesTooltip": {
         "message": "Delete all displayed rules",
@@ -292,8 +292,8 @@
         "description": "Popup text 'Validate changes' in the options page"
     },
     "optionsDeleteRuleConfirm": {
-        "message": "Confirm deletion of the selected rule",
-        "description": "Popup text 'Confirm deletion of the selected rule' in the options page"
+        "message": "Confirm the deletion of the selected rule",
+        "description": "Popup text 'Confirm the deletion of the selected rule' in the options page"
     },
     "optionAutoSaveLoadOrUnload": {
         "message": "auto-save after page load or on page unload",
@@ -348,8 +348,24 @@
         "description": "Options 'Reset' button tooltip"
     },
     "optionsResetConfirm": {
-        "message": "Confirm the reset of all options",
-        "description": "Popup text 'Confirm the reset of all options' in the options page"
+        "message": "Confirm the reset of all options or the current profile",
+        "description": "Popup text 'Confirm the reset of all options or the current profile' in the options page"
+    },
+    "optionsResetAllButton": {
+        "message": "Reset all options",
+        "description": "Options confirm button: 'Reset all options'"
+    },
+    "optionsResetCurrentButton": {
+        "message": "Reset the current profile",
+        "description": "Options confirm button: 'Reset current profile'"
+    },
+    "optionsOKButton": {
+        "message": "OK",
+        "description": "Options confirm button: 'OK'"
+    },
+    "optionsCancelButton": {
+        "message": "Cancel",
+        "description": "Options confirm button: 'Cancel'"
     },
     "optionsExportButton": {
         "message": "Export",
@@ -400,8 +416,8 @@
         "description": "Popup text 'Enter a name for this new profile' in the options page"
     },
     "profileDeleteConfirm": {
-        "message": "Confirm deletion of the selected profile",
-        "description": "Popup text 'Confirm deletion of the selected profile' in the options page"
+        "message": "Confirm the deletion of the selected profile",
+        "description": "Popup text 'Confirm the deletion of the selected profile' in the options page"
     },
     "profileRenamePrompt": {
         "message": "Enter a new name for the selected profile",

+ 18 - 2
_locales/fr/messages.json

@@ -348,8 +348,24 @@
         "description": "Options 'Reset' button tooltip"
     },
     "optionsResetConfirm": {
-        "message": "Confirmez la remise à zéro de toutes les options",
-        "description": "Popup text 'Confirm the reset of all options' in the options page"
+        "message": "Confirmer la remise à zéro de toutes les options ou la remise à zéro du profil courant",
+        "description": "Popup text 'Confirm the reset of all options or the current profile' in the options page"
+    },
+    "optionsResetAllButton": {
+        "message": "Remettre à zéro toutes les options",
+        "description": "Options confirm button: 'Reset all options'"
+    },
+    "optionsResetCurrentButton": {
+        "message": "Remettre à zéro le profil courant",
+        "description": "Options confirm button: 'Reset current profile'"
+    },
+    "optionsOKButton": {
+        "message": "OK",
+        "description": "Options confirm button: 'OK'"
+    },
+    "optionsCancelButton": {
+        "message": "Annuler",
+        "description": "Options confirm button: 'Cancel'"
     },
     "optionsExportButton": {
         "message": "Exporter",

+ 18 - 2
_locales/ja/messages.json

@@ -348,8 +348,24 @@
         "description": "オプション 'リセット'ボタンのツールチップ"
     },
     "optionsResetConfirm": {
-        "message": "すべてのオプションのリセットを確認する",
-        "description": "Popup text 'Confirm the reset of all options' in the options page"
+        "message": "Confirm the reset of all options or the current profile",
+        "description": "Popup text 'Confirm the reset of all options or the current profile' in the options page"
+    },
+    "optionsResetAllButton": {
+        "message": "Reset all options",
+        "description": "Options confirm button: 'Reset all options'"
+    },
+    "optionsResetCurrentButton": {
+        "message": "Reset the current profile",
+        "description": "Options confirm button: 'Reset current profile'"
+    },
+    "optionsOKButton": {
+        "message": "OK",
+        "description": "Options confirm button: 'OK'"
+    },
+    "optionsCancelButton": {
+        "message": "キャンセル",
+        "description": "Options confirm button: 'Cancel'"
     },
     "optionsExportButton": {
         "message": "エクスポート",

+ 18 - 2
_locales/pl/messages.json

@@ -348,8 +348,24 @@
         "description": "Options 'Reset' button tooltip"
     },
     "optionsResetConfirm": {
-        "message": "Potwierdź reset wszystkich opcji",
-        "description": "Popup text 'Confirm the reset of all options' in the options page"
+        "message": "Confirm the reset of all options or the current profile",
+        "description": "Popup text 'Confirm the reset of all options or the current profile' in the options page"
+    },
+    "optionsResetAllButton": {
+        "message": "Reset all options",
+        "description": "Options confirm button: 'Reset all options'"
+    },
+    "optionsResetCurrentButton": {
+        "message": "Reset the current profile",
+        "description": "Options confirm button: 'Reset current profile'"
+    },
+    "optionsOKButton": {
+        "message": "OK",
+        "description": "Options confirm button: 'OK'"
+    },
+    "optionsCancelButton": {
+        "message": "Anuluj",
+        "description": "Options confirm button: 'Cancel'"
     },
     "optionsExportButton": {
         "message": "Eksportuj",

+ 19 - 3
_locales/ru/messages.json

@@ -348,8 +348,24 @@
         "description": "Options 'Reset' button tooltip"
     },
     "optionsResetConfirm": {
-        "message": "Подтвердите сброс всех параметров",
-        "description": "Popup text 'Confirm the reset of all options' in the options page"
+        "message": "Confirm the reset of all options or the current profile",
+        "description": "Popup text 'Confirm the reset of all options or the current profile' in the options page"
+    },
+    "optionsResetAllButton": {
+        "message": "Reset all options",
+        "description": "Options confirm button: 'Reset all options'"
+    },
+    "optionsResetCurrentButton": {
+        "message": "Reset the current profile",
+        "description": "Options confirm button: 'Reset current profile'"
+    },
+    "optionsOKButton": {
+        "message": "OK",
+        "description": "Options confirm button: 'OK'"
+    },
+    "optionsCancelButton": {
+        "message": "Отмена",
+        "description": "Options confirm button: 'Cancel'"
     },
     "optionsExportButton": {
         "message": "Экспорт",
@@ -407,4 +423,4 @@
         "message": "Введите новое имя для выбранного профиля",
         "description": "Popup text 'Enter a new name for the selected profile' in the options page"
     }
-}
+}

+ 18 - 2
_locales/zh_CN/messages.json

@@ -348,8 +348,24 @@
         "description": "选项按钮'重置'的提示"
     },
     "optionsResetConfirm": {
-        "message": "确认重置所有选项",
-        "description": "Popup text 'Confirm the reset of all options' in the options page"
+        "message": "Confirm the reset of all options or the current profile",
+        "description": "Popup text 'Confirm the reset of all options or the current profile' in the options page"
+    },
+    "optionsResetAllButton": {
+        "message": "Reset all options",
+        "description": "Options confirm button: 'Reset all options'"
+    },
+    "optionsResetCurrentButton": {
+        "message": "Reset the current profile",
+        "description": "Options confirm button: 'Reset current profile'"
+    },
+    "optionsOKButton": {
+        "message": "确定",
+        "description": "Options confirm button: 'OK'"
+    },
+    "optionsCancelButton": {
+        "message": "取消",
+        "description": "Options confirm button: 'Cancel'"
     },
     "optionsExportButton": {
         "message": "导出",

+ 9 - 1
extension/core/bg/data/config.js

@@ -277,7 +277,7 @@ singlefile.config = (() => {
 			urlConfig.autoSaveProfile = autoSaveProfile;
 			await browser.storage.local.set({ rules: config.rules });
 		},
-		async reset() {
+		async resetProfiles() {
 			await pendingUpgradePromise;
 			const tabsData = await singlefile.tabsData.get();
 			delete tabsData.profileName;
@@ -285,6 +285,14 @@ singlefile.config = (() => {
 			await browser.storage.local.remove(["profiles", "rules"]);
 			await browser.storage.local.set({ profiles: { [DEFAULT_PROFILE_NAME]: DEFAULT_CONFIG }, rules: [] });
 		},
+		async resetProfile(profileName) {
+			const config = await getConfig();
+			if (!Object.keys(config.profiles).includes(profileName)) {
+				throw new Error("Profile not found");
+			}
+			config.profiles[profileName] = DEFAULT_CONFIG;
+			await browser.storage.local.set({ profiles: config.profiles });
+		},
 		async export() {
 			const config = await getConfig();
 			const url = URL.createObjectURL(new Blob([JSON.stringify({ profiles: config.profiles, rules: config.rules }, null, 2)], { type: "text/json" }));

+ 100 - 14
extension/ui/bg/ui-options.js

@@ -22,12 +22,8 @@
 
 (async () => {
 
-	const CHROME_BROWSER_NAME = "Chrome";
-
-	const [bgPage, browserInfo] = await Promise.all([browser.runtime.getBackgroundPage(), browser.runtime.getBrowserInfo()]);
+	const bgPage = await browser.runtime.getBackgroundPage();
 	const singlefile = bgPage.singlefile;
-	const prompt = browserInfo.name == CHROME_BROWSER_NAME ? (message, defaultMessage) => bgPage.prompt(message, defaultMessage) : (message, defaultMessage) => { document.body.style.opacity = 0; const value = window.prompt(message, defaultMessage); document.body.style.opacity = 1; return value; };
-	const confirm = browserInfo.name == CHROME_BROWSER_NAME ? message => bgPage.confirm(message) : message => { document.body.style.opacity = 0; const value = window.confirm(message); document.body.style.opacity = 1; return value; };
 	const removeHiddenElementsLabel = document.getElementById("removeHiddenElementsLabel");
 	const removeUnusedStylesLabel = document.getElementById("removeUnusedStylesLabel");
 	const removeUnusedFontsLabel = document.getElementById("removeUnusedFontsLabel");
@@ -137,6 +133,15 @@
 	const createURLElement = rulesElement.querySelector(".rule-create");
 	const showAllProfilesInput = document.getElementById("showAllProfilesInput");
 	const showAutoSaveProfileInput = document.getElementById("showAutoSaveProfileInput");
+	const resetAllButton = document.getElementById("resetAllButton");
+	const resetCurrentButton = document.getElementById("resetCurrentButton");
+	const resetCancelButton = document.getElementById("resetCancelButton");
+	const confirmButton = document.getElementById("confirmButton");
+	const cancelButton = document.getElementById("cancelButton");
+	const promptInput = document.getElementById("promptInput");
+	const promptCancelButton = document.getElementById("promptCancelButton");
+	const promptConfirmButton = document.getElementById("promptConfirmButton");
+
 	let pendingSave = Promise.resolve();
 	let autoSaveProfileChanged;
 	ruleProfileInput.onchange = () => {
@@ -148,7 +153,7 @@
 		autoSaveProfileChanged = true;
 	};
 	rulesDeleteAllButton.addEventListener("click", async () => {
-		if (confirm(browser.i18n.getMessage("optionsDeleteDisplayedRulesConfirm"))) {
+		if (await confirm(browser.i18n.getMessage("optionsDeleteDisplayedRulesConfirm"))) {
 			await singlefile.config.deleteRules(!showAllProfilesInput.checked && profileNamesInput.value);
 			await refresh();
 		}
@@ -204,7 +209,7 @@
 		}
 	}, false);
 	addProfileButton.addEventListener("click", async () => {
-		const profileName = prompt(browser.i18n.getMessage("profileAddPrompt"));
+		const profileName = await prompt(browser.i18n.getMessage("profileAddPrompt"));
 		if (profileName) {
 			try {
 				await singlefile.config.createProfile(profileName);
@@ -215,7 +220,7 @@
 		}
 	}, false);
 	deleteProfileButton.addEventListener("click", async () => {
-		if (confirm(browser.i18n.getMessage("profileDeleteConfirm"))) {
+		if (await confirm(browser.i18n.getMessage("profileDeleteConfirm"))) {
 			try {
 				await singlefile.config.deleteProfile(profileNamesInput.value);
 				profileNamesInput.value = null;
@@ -226,7 +231,7 @@
 		}
 	}, false);
 	renameProfileButton.addEventListener("click", async () => {
-		const profileName = prompt(browser.i18n.getMessage("profileRenamePrompt"), profileNamesInput.value);
+		const profileName = await prompt(browser.i18n.getMessage("profileRenamePrompt"), profileNamesInput.value);
 		if (profileName) {
 			try {
 				await singlefile.config.renameProfile(profileNamesInput.value, profileName);
@@ -237,9 +242,16 @@
 		}
 	}, false);
 	resetButton.addEventListener("click", async () => {
-		if (confirm(browser.i18n.getMessage("optionsResetConfirm"))) {
-			await singlefile.config.reset();
-			await Promise.all([refresh(singlefile.config.DEFAULT_PROFILE_NAME), singlefile.ui.menu.refresh()]);
+		const choice = await reset();
+		if (choice) {
+			if (choice == "all") {
+				await singlefile.config.resetProfiles();
+				await Promise.all([refresh(singlefile.config.DEFAULT_PROFILE_NAME), singlefile.ui.menu.refresh()]);
+			}
+			if (choice == "current") {
+				await singlefile.config.resetProfile(profileNamesInput.value);
+				await refresh();
+			}
 			await update();
 		}
 	}, false);
@@ -365,7 +377,11 @@
 	showAllProfilesLabel.textContent = browser.i18n.getMessage("optionsAutoSettingsShowAllProfiles");
 	showAutoSaveProfileLabel.textContent = browser.i18n.getMessage("optionsAutoSettingsShowAutoSaveProfile");
 	ruleUrlInput.placeholder = ruleEditUrlInput.placeholder = browser.i18n.getMessage("optionsAutoSettingsUrlPlaceholder");
-
+	resetAllButton.textContent = browser.i18n.getMessage("optionsResetAllButton");
+	resetCurrentButton.textContent = browser.i18n.getMessage("optionsResetCurrentButton");
+	resetCancelButton.textContent = promptCancelButton.textContent = cancelButton.textContent = browser.i18n.getMessage("optionsCancelButton");
+	confirmButton.textContent = promptConfirmButton.textContent = browser.i18n.getMessage("optionsOKButton");
+	document.getElementById("resetConfirmLabel").textContent = browser.i18n.getMessage("optionsResetConfirm");
 	refresh();
 
 	async function refresh(profileName) {
@@ -426,7 +442,7 @@
 				const ruleUpdateButton = ruleElement.querySelector(".rule-update-button");
 				ruleDeleteButton.title = browser.i18n.getMessage("optionsDeleteRuleTooltip");
 				ruleDeleteButton.addEventListener("click", async () => {
-					if (confirm(browser.i18n.getMessage("optionsDeleteRuleConfirm"))) {
+					if (await confirm(browser.i18n.getMessage("optionsDeleteRuleConfirm"))) {
 						await singlefile.config.deleteRule(rule.url);
 						await refresh();
 					}
@@ -544,4 +560,74 @@
 		await singlefile.ui.menu.refresh();
 	}
 
+	async function confirm(message) {
+		document.getElementById("confirmLabel").textContent = message;
+		document.getElementById("formConfirmContainer").hidden = false;
+		confirmButton.focus();
+		document.body.style.overflowY = "hidden";
+		return new Promise(resolve => {
+			confirmButton.onclick = event => hideAndResolve(event, true);
+			cancelButton.onclick = event => hideAndResolve(event);
+			window.onkeyup = event => {
+				if (event.key == "Escape") {
+					hideAndResolve(event);
+				}
+			};
+
+			function hideAndResolve(event, value) {
+				event.preventDefault();
+				document.getElementById("formConfirmContainer").hidden = true;
+				document.body.style.overflowY = "";
+				resolve(value);
+			}
+		});
+	}
+
+	async function reset() {
+		document.getElementById("formResetContainer").hidden = false;
+		resetCancelButton.focus();
+		document.body.style.overflowY = "hidden";
+		return new Promise(resolve => {
+			resetAllButton.onclick = event => hideAndResolve(event, "all");
+			resetCurrentButton.onclick = event => hideAndResolve(event, "current");
+			resetCancelButton.onclick = event => hideAndResolve(event);
+			window.onkeyup = event => {
+				if (event.key == "Escape") {
+					hideAndResolve(event);
+				}
+			};
+
+			function hideAndResolve(event, value) {
+				event.preventDefault();
+				document.getElementById("formResetContainer").hidden = true;
+				document.body.style.overflowY = "";
+				resolve(value);
+			}
+		});
+	}
+
+	async function prompt(message, defaultValue = "") {
+		document.getElementById("promptLabel").textContent = message;
+		document.getElementById("formPromptContainer").hidden = false;
+		promptInput.value = defaultValue;
+		promptInput.focus();
+		document.body.style.overflowY = "hidden";
+		return new Promise(resolve => {
+			promptConfirmButton.onclick = event => hideAndResolve(event, promptInput.value);
+			promptCancelButton.onclick = event => hideAndResolve(event);
+			window.onkeyup = event => {
+				if (event.key == "Escape") {
+					hideAndResolve(event);
+				}
+			};
+
+			function hideAndResolve(event, value) {
+				event.preventDefault();
+				document.getElementById("formPromptContainer").hidden = true;
+				document.body.style.overflowY = "";
+				resolve(value);
+			}
+		});
+	}
+
 })();

+ 68 - 3
extension/ui/pages/options.css

@@ -2,7 +2,10 @@ body {
     background-color: transparent;
     font-family: sans-serif;
     max-width: 800px;
+    width: 100%;
     margin: 0;
+    margin-left: auto;
+    margin-right: auto;
 }
 
 button {
@@ -31,6 +34,11 @@ button:active {
     border-color: rgb(237, 237, 237);
 }
 
+button:focus {
+    border-color: black;
+    background-color: #fefefe;
+}
+
 input {
     margin-left: 5px;
 }
@@ -54,8 +62,12 @@ input.large-input {
 
 h3 {
     padding-left: 8px;
-    margin-bottom: 10px;
-    margin-top: 10px;
+    padding-top: 10px;
+    margin-top: 4px;
+}
+
+h3 a {
+    padding-left: 5px;
 }
 
 .buttons {
@@ -66,7 +78,7 @@ h3 {
     float: right;
     margin-right: 12px;
     position: relative;
-    top: -3px;
+    top: 0;
     max-width: calc(100% - 100px);
 }
 
@@ -278,6 +290,7 @@ a {
 .option.bottom {
     padding-top: 24px;
     padding-right: 12px;
+    padding-bottom: 12px;
 }
 
 #expandAllButton {
@@ -307,6 +320,58 @@ a {
     opacity: 1;
 }
 
+.popup {
+    width: 100%;
+    height: 100%;
+    position: fixed;
+    top: 0;
+    left: 0;
+    background-color: rgba(191, 191, 191, .75);
+}
+
+.popup-content {
+    width: 90%;
+    max-width: 320px;
+    margin-top: 50vh;
+    transform: translateY(-50%);
+    margin-left: auto;
+    margin-right: auto;
+    background-color: white;
+    box-shadow: 5px 5px #ababab;
+}
+
+.popup-content header {
+    padding-top: 10px;
+    padding-left: 10px;
+    padding-bottom: 20px;
+    font-size: 14px;
+    line-height: 20px;
+}
+
+.popup-content main {
+    padding-top: 10px;
+    padding-left: 10px;
+    padding-bottom: 10px;
+}
+
+.popup-content main input {
+    margin-bottom: 10px;
+    padding: 2px;
+    font-size: 13px;
+    margin-left: 0px;
+    width: calc(100% - 16px);
+}
+
+.popup-content footer {
+    text-align: right;
+    padding-left: 10px;
+    padding-right: 10px;
+}
+
+.popup-content footer button {
+    margin-bottom: 10px;
+}
+
 @media (max-width:400px) {
     body,
     input,

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

@@ -235,6 +235,41 @@
 			<input type="file" id="fileInput" hidden>
 		</div>
 	</div>
+	<div id="formResetContainer" class="popup" hidden>
+		<form class="popup-content">
+			<header>
+				<span id="resetConfirmLabel"></span>
+			</header>
+			<footer>
+				<button type="submit" id="resetAllButton"></button>
+				<button id="resetCurrentButton"></button>
+				<button id="resetCancelButton"></button>
+			</footer>
+		</form>
+	</div>
+	<div id="formConfirmContainer" class="popup" hidden>
+		<form class="popup-content">
+			<header>
+				<span id="confirmLabel"></span>
+			</header>
+			<footer>
+				<button type="submit" id="confirmButton"></button>
+				<button id="cancelButton"></button>
+			</footer>
+		</form>
+	</div>
+	<div id="formPromptContainer" class="popup" hidden>
+		<form class="popup-content">
+			<header>
+				<span id="promptLabel"></span>
+			</header>
+			<main><input id="promptInput" type="text"></main>
+			<footer>
+				<button type="submit" id="promptConfirmButton"></button>
+				<button id="promptCancelButton"></button>
+			</footer>
+		</form>
+	</div>
 	<script type="text/javascript" src="/lib/browser-polyfill/chrome-browser-polyfill.js"></script>
 	<script type="text/javascript" src="../bg/ui-options.js"></script>
 </body>

+ 0 - 1
lib/browser-polyfill/chrome-browser-polyfill.js

@@ -152,7 +152,6 @@
 				})
 			},
 			runtime: {
-				getBrowserInfo: () => Promise.resolve({ name: isChrome ? "Chrome" : "Unknown" }),
 				onMessage: {
 					addListener: listener => nativeAPI.runtime.onMessage.addListener((message, sender, sendResponse) => {
 						const response = listener(message, sender);