Add: webdav sync (#1363)

This commit is contained in:
eight 2021-12-12 08:05:58 +08:00 committed by GitHub
parent 3ea7e45624
commit f6e6a138db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 90 additions and 12 deletions

View File

@ -1200,6 +1200,15 @@
}
}
},
"optionsSyncUsername": {
"message": "Username"
},
"optionsSyncPassword": {
"message": "Password"
},
"optionsSyncUrl": {
"message": "URL"
},
"optionsSyncStatusRelogin": {
"message": "Session expired, please login again."
},

View File

@ -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}`);
}

View File

@ -199,10 +199,27 @@
<option value="dropbox">Dropbox</option>
<option value="google">Google Drive</option>
<option value="onedrive">OneDrive</option>
<option value="webdav">WebDAV</option>
</select>
<svg class="svg-icon select-arrow"><use xlink:href="#svg-icon-select-arrow"/></svg>
</div>
</div>
<fieldset class="drive-options">
<div class="webdav-options" data-drive="webdav">
<label class="url">
<span i18n-text="optionsSyncUrl"></span>
<input type="text" data-option="url">
</label>
<label class="username">
<span i18n-text="optionsSyncUsername"></span>
<input type="text" data-option="username">
</label>
<label class="password">
<span i18n-text="optionsSyncPassword"></span>
<input type="password" data-option="password">
</label>
</div>
</fieldset>
<div class="actions">
<button type="button" class="connect" i18n-text="optionsSyncConnect"></button>
<button type="button" class="disconnect" i18n-text="optionsSyncDisconnect"></button>

View File

@ -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;
}

View File

@ -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() {