Explorar el Código

added option "synchronize options" (fix #296)

Former-commit-id: 67fa429d0496a0470c3ad15676c487a0196d5e72
Gildas hace 6 años
padre
commit
663158c82f

+ 4 - 0
_locales/de/messages.json

@@ -391,6 +391,10 @@
 		"message": "Hilfe",
 		"description": "Options help link"
 	},
+	"optionSynchronize": {
+		"message": "Optionen synchronisieren",
+		"description": "Options label: 'synchronize options'"
+	},
 	"optionsResetButton": {
 		"message": "Zurücksetzen",
 		"description": "Options button: 'Reset'"

+ 4 - 0
_locales/en/messages.json

@@ -391,6 +391,10 @@
 		"message": "help",
 		"description": "Options help link"
 	},
+	"optionSynchronize": {
+		"message": "synchronize options",
+		"description": "Options label: 'synchronize options'"
+	},
 	"optionsResetButton": {
 		"message": "Reset",
 		"description": "Options button: 'Reset'"

+ 4 - 0
_locales/es/messages.json

@@ -391,6 +391,10 @@
 		"message": "ayuda",
 		"description": "Options help link"
 	},
+	"optionSynchronize": {
+		"message": "sincronizar opciones",
+		"description": "Options label: 'synchronize options'"
+	},
 	"optionsResetButton": {
 		"message": "Restablecer",
 		"description": "Options button: 'Reset'"

+ 4 - 0
_locales/fr/messages.json

@@ -391,6 +391,10 @@
 		"message": "aide (anglais)",
 		"description": "Options help link"
 	},
+	"optionSynchronize": {
+		"message": "synchronizer les options",
+		"description": "Options label: 'Synchronize options'"
+	},
 	"optionsResetButton": {
 		"message": "Remise à zéro",
 		"description": "Options button: 'Reset'"

+ 4 - 0
_locales/ja/messages.json

@@ -391,6 +391,10 @@
 		"message": "ヘルプ",
 		"description": "Options help link"
 	},
+	"optionSynchronize": {
+		"message": "synchronize options",
+		"description": "Options label: 'synchronize options'"
+	},
 	"optionsResetButton": {
 		"message": "リセット",
 		"description": "Options button: 'Reset'"

+ 4 - 0
_locales/pl/messages.json

@@ -391,6 +391,10 @@
 		"message": "pomoc (w języku angielskim)",
 		"description": "Options help link"
 	},
+	"optionSynchronize": {
+		"message": "synchronize options",
+		"description": "Options label: 'synchronize options'"
+	},
 	"optionsResetButton": {
 		"message": "Resetuj",
 		"description": "Options button: 'Reset'"

+ 4 - 0
_locales/ru/messages.json

@@ -391,6 +391,10 @@
 		"message": "помощь",
 		"description": "Options help link"
 	},
+	"optionSynchronize": {
+		"message": "synchronize options",
+		"description": "Options label: 'synchronize options'"
+	},
 	"optionsResetButton": {
 		"message": "Сброс",
 		"description": "Options button: 'Reset'"

+ 4 - 0
_locales/uk/messages.json

@@ -391,6 +391,10 @@
 		"message": "допомога",
 		"description": "Options help link"
 	},
+	"optionSynchronize": {
+		"message": "synchronize options",
+		"description": "Options label: 'synchronize options'"
+	},
 	"optionsResetButton": {
 		"message": "Скидання",
 		"description": "Options button: 'Reset'"

+ 4 - 0
_locales/zh_CN/messages.json

@@ -391,6 +391,10 @@
 		"message": "帮助",
 		"description": "选项页帮助链接"
 	},
+	"optionSynchronize": {
+		"message": "synchronize options",
+		"description": "Options label: 'synchronize options'"
+	},
 	"optionsResetButton": {
 		"message": "重置",
 		"description": "选项按钮: '重置'"

+ 4 - 0
_locales/zh_TW/messages.json

@@ -391,6 +391,10 @@
 		"message": "幫助",
 		"description": "選項頁幫助鏈接"
 	},
+	"optionSynchronize": {
+		"message": "synchronize options",
+		"description": "Options label: 'synchronize options'"
+	},
 	"optionsResetButton": {
 		"message": "重置",
 		"description": "選項按鈕: '重置'"

+ 52 - 22
extension/core/bg/config.js

@@ -87,6 +87,7 @@ singlefile.extension.core.bg.config = (() => {
 		autoOpenEditor: false
 	};
 
+	let configStorage;
 	let pendingUpgradePromise = upgrade();
 	return {
 		DEFAULT_PROFILE_NAME,
@@ -105,25 +106,31 @@ singlefile.extension.core.bg.config = (() => {
 	};
 
 	async function upgrade() {
-		const config = await browser.storage.local.get();
+		const { sync } = await browser.storage.local.get();
+		if (sync) {
+			configStorage = browser.storage.sync;
+		} else {
+			configStorage = browser.storage.local;
+		}
+		const config = await configStorage.get();
 		if (!config.profiles) {
 			const defaultConfig = config;
 			delete defaultConfig.tabsData;
 			applyUpgrade(defaultConfig);
 			const newConfig = { profiles: {}, rules: [] };
 			newConfig.profiles[DEFAULT_PROFILE_NAME] = defaultConfig;
-			browser.storage.local.remove(Object.keys(DEFAULT_CONFIG));
-			await browser.storage.local.set(newConfig);
+			configStorage.remove(Object.keys(DEFAULT_CONFIG));
+			await configStorage.set(newConfig);
 		} else {
 			if (!config.rules) {
 				config.rules = [];
 			}
 			Object.keys(config.profiles).forEach(profileName => applyUpgrade(config.profiles[profileName]));
-			await browser.storage.local.remove(["profiles", "defaultProfile", "rules"]);
-			await browser.storage.local.set({ profiles: config.profiles, rules: config.rules });
+			await configStorage.remove(["profiles", "defaultProfile", "rules"]);
+			await configStorage.set({ profiles: config.profiles, rules: config.rules });
 		}
 		if (!config.maxParallelWorkers) {
-			await browser.storage.local.set({ maxParallelWorkers: navigator.hardwareConcurrency || 4 });
+			await configStorage.set({ maxParallelWorkers: navigator.hardwareConcurrency || 4 });
 		}
 	}
 
@@ -157,7 +164,7 @@ singlefile.extension.core.bg.config = (() => {
 
 	async function getConfig() {
 		await pendingUpgradePromise;
-		return browser.storage.local.get(["profiles", "rules", "maxParallelWorkers"]);
+		return configStorage.get(["profiles", "rules", "maxParallelWorkers"]);
 	}
 
 	function sortRules(ruleLeft, ruleRight) {
@@ -218,6 +225,27 @@ singlefile.extension.core.bg.config = (() => {
 		if (message.method.endsWith(".exportConfig")) {
 			return exportConfig();
 		}
+		if (message.method.endsWith(".enableSync")) {
+			await browser.storage.local.set({ sync: true });
+			const syncConfig = await browser.storage.sync.get();
+			if (!syncConfig || !syncConfig.profiles) {
+				const localConfig = await browser.storage.local.get();
+				await browser.storage.sync.set({ profiles: localConfig.profiles, rules: localConfig.rules, maxParallelWorkers: localConfig.maxParallelWorkers });
+			}
+			configStorage = browser.storage.sync;
+			return {};
+		}
+		if (message.method.endsWith(".disableSync")) {
+			await browser.storage.local.set({ sync: false });
+			const syncConfig = await browser.storage.sync.get();
+			if (syncConfig && syncConfig.profiles) {
+				await browser.storage.local.set({ profiles: syncConfig.profiles, rules: syncConfig.rules, maxParallelWorkers: syncConfig.maxParallelWorkers });
+			}
+			configStorage = browser.storage.local;
+		}
+		if (message.method.endsWith(".isSync")) {
+			return { sync: (await browser.storage.local.get()).sync };
+		}
 		return {};
 	}
 
@@ -227,7 +255,7 @@ singlefile.extension.core.bg.config = (() => {
 			throw new Error("Duplicate profile name");
 		}
 		config.profiles[profileName] = JSON.parse(JSON.stringify(config.profiles[fromProfileName]));
-		await browser.storage.local.set({ profiles: config.profiles });
+		await configStorage.set({ profiles: config.profiles });
 	}
 
 	async function getProfiles() {
@@ -252,7 +280,7 @@ singlefile.extension.core.bg.config = (() => {
 			throw new Error("Profile not found");
 		}
 		Object.keys(profile).forEach(key => config.profiles[profileName][key] = profile[key]);
-		await browser.storage.local.set({ profiles: config.profiles });
+		await configStorage.set({ profiles: config.profiles });
 	}
 
 	async function renameProfile(oldProfileName, profileName) {
@@ -280,7 +308,7 @@ singlefile.extension.core.bg.config = (() => {
 			}
 		});
 		delete config.profiles[oldProfileName];
-		await browser.storage.local.set({ profiles: config.profiles, rules: config.rules });
+		await configStorage.set({ profiles: config.profiles, rules: config.rules });
 	}
 
 	async function deleteProfile(profileName) {
@@ -304,7 +332,7 @@ singlefile.extension.core.bg.config = (() => {
 			}
 		});
 		delete config.profiles[profileName];
-		await browser.storage.local.set({ profiles: config.profiles, rules: config.rules });
+		await configStorage.set({ profiles: config.profiles, rules: config.rules });
 	}
 
 	async function getRules() {
@@ -325,7 +353,7 @@ singlefile.extension.core.bg.config = (() => {
 			profile,
 			autoSaveProfile
 		});
-		await browser.storage.local.set({ rules: config.rules });
+		await configStorage.set({ rules: config.rules });
 	}
 
 	async function deleteRule(url) {
@@ -334,13 +362,13 @@ singlefile.extension.core.bg.config = (() => {
 		}
 		const config = await getConfig();
 		config.rules = config.rules.filter(rule => rule.url != url);
-		await browser.storage.local.set({ rules: config.rules });
+		await configStorage.set({ rules: config.rules });
 	}
 
 	async function deleteRules(profileName) {
 		const config = await getConfig();
 		config.rules = config.rules = profileName ? config.rules.filter(rule => rule.autoSaveProfile != profileName && rule.profile != profileName) : [];
-		await browser.storage.local.set({ rules: config.rules });
+		await configStorage.set({ rules: config.rules });
 	}
 
 	async function updateRule(url, newURL, profile, autoSaveProfile) {
@@ -358,15 +386,15 @@ singlefile.extension.core.bg.config = (() => {
 		urlConfig.url = newURL;
 		urlConfig.profile = profile;
 		urlConfig.autoSaveProfile = autoSaveProfile;
-		await browser.storage.local.set({ rules: config.rules });
+		await configStorage.set({ rules: config.rules });
 	}
 
 	async function getAuthInfo() {
-		return (await browser.storage.local.get(["authInfo"])).authInfo;
+		return (await configStorage.get()).authInfo;
 	}
 
 	async function setAuthInfo(authInfo) {
-		await browser.storage.local.set({ authInfo });
+		await configStorage.set({ authInfo });
 	}
 
 	async function removeAuthInfo() {
@@ -374,7 +402,7 @@ singlefile.extension.core.bg.config = (() => {
 		if (authInfo.revokableAccessToken) {
 			setAuthInfo({ revokableAccessToken: authInfo.revokableAccessToken });
 		} else {
-			await browser.storage.local.remove(["authInfo"]);
+			await configStorage.remove(["authInfo"]);
 		}
 	}
 
@@ -383,7 +411,7 @@ singlefile.extension.core.bg.config = (() => {
 		const tabsData = await singlefile.extension.core.bg.tabsData.get();
 		delete tabsData.profileName;
 		await singlefile.extension.core.bg.tabsData.set(tabsData);
-		await browser.storage.local.remove(["profiles", "rules", "maxParallelWorkers"]);
+		await configStorage.remove(["profiles", "rules", "maxParallelWorkers"]);
 		await upgrade();
 	}
 
@@ -393,7 +421,9 @@ singlefile.extension.core.bg.config = (() => {
 			throw new Error("Profile not found");
 		}
 		config.profiles[profileName] = DEFAULT_CONFIG;
-		await browser.storage.local.set({ profiles: config.profiles });
+		await configStorage.set({ profiles: config.profiles });
+		await browser.storage.local.set({ sync: false });
+		configStorage = browser.storage.local;
 	}
 
 	async function exportConfig() {
@@ -412,8 +442,8 @@ singlefile.extension.core.bg.config = (() => {
 	}
 
 	async function importConfig(config) {
-		await browser.storage.local.remove(["profiles", "rules", "maxParallelWorkers"]);
-		await browser.storage.local.set({ profiles: config.profiles, rules: config.rules, maxParallelWorkers: config.maxParallelWorkers });
+		await configStorage.remove(["profiles", "rules", "maxParallelWorkers"]);
+		await configStorage.set({ profiles: config.profiles, rules: config.rules, maxParallelWorkers: config.maxParallelWorkers });
 		await upgrade();
 	}
 

+ 38 - 0
extension/lib/single-file/browser-polyfill/chrome-browser-polyfill.js

@@ -312,6 +312,44 @@
 							}
 						});
 					})
+				},
+				sync: {
+					set: value => new Promise((resolve, reject) => {
+						nativeAPI.storage.sync.set(value, () => {
+							if (nativeAPI.runtime.lastError) {
+								reject(nativeAPI.runtime.lastError);
+							} else {
+								resolve();
+							}
+						});
+					}),
+					get: () => new Promise((resolve, reject) => {
+						nativeAPI.storage.sync.get(null, value => {
+							if (nativeAPI.runtime.lastError) {
+								reject(nativeAPI.runtime.lastError);
+							} else {
+								resolve(value);
+							}
+						});
+					}),
+					clear: () => new Promise((resolve, reject) => {
+						nativeAPI.storage.sync.clear(() => {
+							if (nativeAPI.runtime.lastError) {
+								reject(nativeAPI.runtime.lastError);
+							} else {
+								resolve();
+							}
+						});
+					}),
+					remove: keys => new Promise((resolve, reject) => {
+						nativeAPI.storage.sync.remove(keys, () => {
+							if (nativeAPI.runtime.lastError) {
+								reject(nativeAPI.runtime.lastError);
+							} else {
+								resolve();
+							}
+						});
+					})
 				}
 			},
 			tabs: {

+ 13 - 0
extension/ui/bg/ui-options.js

@@ -89,6 +89,7 @@
 	const includeInfobarLabel = document.getElementById("includeInfobarLabel");
 	const miscLabel = document.getElementById("miscLabel");
 	const helpLabel = document.getElementById("helpLabel");
+	const synchronizeLabel = document.getElementById("synchronizeLabel");
 	const addProfileButton = document.getElementById("addProfileButton");
 	const deleteProfileButton = document.getElementById("deleteProfileButton");
 	const renameProfileButton = document.getElementById("renameProfileButton");
@@ -153,6 +154,7 @@
 	const createURLElement = rulesElement.querySelector(".rule-create");
 	const showAllProfilesInput = document.getElementById("showAllProfilesInput");
 	const showAutoSaveProfileInput = document.getElementById("showAutoSaveProfileInput");
+	const synchronizeInput = document.getElementById("synchronizeInput");
 	const resetAllButton = document.getElementById("resetAllButton");
 	const resetCurrentButton = document.getElementById("resetCurrentButton");
 	const resetCancelButton = document.getElementById("resetCancelButton");
@@ -356,6 +358,16 @@
 			await browser.runtime.sendMessage({ method: "downloads.disableGDrive" });
 		}
 	}, false);
+	synchronizeInput.checked = (await browser.runtime.sendMessage({ method: "config.isSync" })).sync;
+	synchronizeInput.addEventListener("click", async () => {
+		if (synchronizeInput.checked) {
+			await browser.runtime.sendMessage({ method: "config.enableSync" });
+			await refresh(DEFAULT_PROFILE_NAME);
+		} else {
+			await browser.runtime.sendMessage({ method: "config.disableSync" });
+			await refresh();
+		}
+	}, false);
 	document.body.onchange = async event => {
 		let target = event.target;
 		if (target != ruleUrlInput && target != ruleProfileInput && target != ruleAutoSaveProfileInput && target != ruleEditUrlInput && target != ruleEditProfileInput && target != ruleEditAutoSaveProfileInput && target != showAutoSaveProfileInput) {
@@ -453,6 +465,7 @@
 	showAllProfilesLabel.textContent = browser.i18n.getMessage("optionsAutoSettingsShowAllProfiles");
 	showAutoSaveProfileLabel.textContent = browser.i18n.getMessage("optionsAutoSettingsShowAutoSaveProfile");
 	ruleUrlInput.placeholder = ruleEditUrlInput.placeholder = browser.i18n.getMessage("optionsAutoSettingsUrlPlaceholder");
+	synchronizeLabel.textContent = browser.i18n.getMessage("optionSynchronize");
 	resetAllButton.textContent = browser.i18n.getMessage("optionsResetAllButton");
 	resetCurrentButton.textContent = browser.i18n.getMessage("optionsResetCurrentButton");
 	resetCancelButton.textContent = promptCancelButton.textContent = cancelButton.textContent = browser.i18n.getMessage("optionsCancelButton");

+ 12 - 1
extension/ui/pages/options.css

@@ -86,6 +86,17 @@ h3 a {
     padding-left: 5px;
 }
 
+.sync-input {
+    margin-bottom: 20px;
+    text-align: right;
+}
+
+.sync-input input {
+    margin: 0;
+    margin-right: 4px;
+    vertical-align: bottom;
+}
+
 .buttons {
     white-space: nowrap;
 }
@@ -491,7 +502,7 @@ html.maximized {
 .maximized #helpLabel {
     padding-left: 4px;
     padding-right: 4px;
-    padding-top: 7px;
+    padding-top: 0;
 }
 
 @media (max-width:400px) {

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

@@ -272,6 +272,10 @@
 		<div class="option bottom">
 			<a href="help.html" target="SingleFileHelpPage" id="helpLabel"></a>
 			<div class="buttons">
+				<div class="sync-input">
+					<input type="checkbox" id="synchronizeInput">
+					<label for="synchronizeInput" id="synchronizeLabel"></label>
+				</div>
 				<button id="importButton"></button>
 				<button id="exportButton"></button>
 				<button id="resetButton"></button>