From f6e6a138db9b960cd04acfe8f3ea1276fc04e33d Mon Sep 17 00:00:00 2001 From: eight Date: Sun, 12 Dec 2021 08:05:58 +0800 Subject: [PATCH] Add: webdav sync (#1363) --- _locales/en/messages.json | 9 +++++++++ background/sync-manager.js | 27 +++++++++++++++++++-------- options.html | 17 +++++++++++++++++ options/options.css | 22 ++++++++++++++++++++-- options/options.js | 27 +++++++++++++++++++++++++-- 5 files changed, 90 insertions(+), 12 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index c65b08a7..3e6a9326 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1200,6 +1200,15 @@ } } }, + "optionsSyncUsername": { + "message": "Username" + }, + "optionsSyncPassword": { + "message": "Password" + }, + "optionsSyncUrl": { + "message": "URL" + }, "optionsSyncStatusRelogin": { "message": "Session expired, please login again." }, diff --git a/background/sync-manager.js b/background/sync-manager.js index cb51498d..e1aafd4e 100644 --- a/background/sync-manager.js +++ b/background/sync-manager.js @@ -1,5 +1,5 @@ /* global API msg */// msg.js -/* global chromeLocal */// storage-util.js +/* global chromeLocal chromeSync */// storage-util.js /* global compareRevision */// common.js /* global iconMan */ /* global prefs */ @@ -18,6 +18,7 @@ const syncMan = (() => { disconnecting: 'disconnecting', }); const STORAGE_KEY = 'sync/state/'; + const NO_LOGIN = ['webdav']; const status = /** @namespace SyncManager.Status */ { STATES, state: STATES.disconnected, @@ -85,19 +86,29 @@ const syncMan = (() => { return ctrl.put(...args); }, + async setDriveOptions(driveName, options) { + const key = `secure/sync/driveOptions/${driveName}`; + await chromeSync.setValue(key, options); + }, + + async getDriveOptions(driveName) { + const key = `secure/sync/driveOptions/${driveName}`; + return await chromeSync.getValue(key) || {}; + }, + async start(name, fromPref = false) { if (ready.then) await ready; if (!ctrl) await initController(); if (currentDrive) return; - currentDrive = getDrive(name); + currentDrive = await getDrive(name); ctrl.use(currentDrive); status.state = STATES.connecting; status.currentDriveName = currentDrive.name; emitStatusChange(); - if (fromPref) { + if (fromPref || NO_LOGIN.includes(currentDrive.name)) { status.login = true; } else { try { @@ -240,11 +251,11 @@ const syncMan = (() => { } } - function getDrive(name) { - if (name === 'dropbox' || name === 'google' || name === 'onedrive') { - return dbToCloud.drive[name]({ - getAccessToken: () => tokenMan.getToken(name), - }); + async function getDrive(name) { + if (name === 'dropbox' || name === 'google' || name === 'onedrive' || name === 'webdav') { + const options = await syncMan.getDriveOptions(name); + options.getAccessToken = () => tokenMan.getToken(name); + return dbToCloud.drive[name](options); } throw new Error(`unknown cloud name: ${name}`); } diff --git a/options.html b/options.html index a6170f82..7705accf 100644 --- a/options.html +++ b/options.html @@ -199,10 +199,27 @@ + +
+
+ + + +
+
diff --git a/options/options.css b/options/options.css index 283522bd..8ace53b5 100644 --- a/options/options.css +++ b/options/options.css @@ -163,7 +163,7 @@ label > :first-child { } label:not([disabled]), -label:not([disabled]) :not([type="number"]) { +label:not([disabled]) :not([type="number"]):not([type="text"]):not([type="password"]) { cursor: pointer; } @@ -437,7 +437,25 @@ input[type="radio"].radio:checked::after { .sync-status::first-letter { text-transform: uppercase; } - +.sync-options .drive-options { + margin: 0; + padding: 0; + border: 0; +} +.drive-options > :not([hidden]) { + display: table; + width: 100%; +} +.drive-options > * > label { + display: table-row; +} +.drive-options > * > label > * { + display: table-cell; +} +.drive-options > * input { + width: 100%; + box-sizing: border-box; +} .sync-options .actions button { margin-top: .5em; } diff --git a/options/options.js b/options/options.js index 9d8c061e..fbaa7f12 100644 --- a/options/options.js +++ b/options/options.js @@ -96,6 +96,7 @@ document.onclick = e => { const elSyncNow = $('.sync-options .sync-now'); const elStatus = $('.sync-options .sync-status'); const elLogin = $('.sync-options .sync-login'); + const elDriveOptions = $('.sync-options .drive-options'); /** @type {Sync.Status} */ let status = {}; msg.onExtension(e => { @@ -108,7 +109,10 @@ document.onclick = e => { elCloud.on('change', updateButtons); for (const [btn, fn] of [ - [elStart, () => API.sync.start(elCloud.value)], + [elStart, async () => { + await API.sync.setDriveOptions(elCloud.value, getDriveOptions()); + await API.sync.start(elCloud.value); + }], [elStop, API.sync.stop], [elSyncNow, API.sync.syncNow], [elLogin, async () => { @@ -123,12 +127,26 @@ document.onclick = e => { }); } + function getDriveOptions() { + const result = {}; + for (const el of $$(`[data-drive=${elCloud.value}] [data-option]`)) { + result[el.dataset.option] = el.value; + } + return result; + } + + function setDriveOptions(options) { + for (const el of $$(`[data-drive=${elCloud.value}] [data-option]`)) { + el.value = options[el.dataset.option] || ''; + } + } + function setStatus(newStatus) { status = newStatus; updateButtons(); } - function updateButtons() { + async function updateButtons() { const {state, STATES} = status; const isConnected = state === STATES.connected; const isDisconnected = state === STATES.disconnected; @@ -137,6 +155,7 @@ document.onclick = e => { } for (const [el, enable] of [ [elCloud, isDisconnected], + [elDriveOptions, isDisconnected], [elStart, isDisconnected && elCloud.value !== 'none'], [elStop, isConnected && !status.syncing], [elSyncNow, isConnected && !status.syncing && status.login], @@ -145,6 +164,10 @@ document.onclick = e => { } elStatus.textContent = getStatusText(); elLogin.hidden = !isConnected || status.login; + for (const el of elDriveOptions.children) { + el.hidden = el.dataset.drive !== elCloud.value; + } + setDriveOptions(await API.sync.getDriveOptions(elCloud.value)); } function getStatusText() {