Fix bulk export
This commit is contained in:
parent
a7026bdeee
commit
44889f6158
|
@ -93,7 +93,8 @@
|
|||
"description": "Message for backup"
|
||||
},
|
||||
"bckpInstStyles": {
|
||||
"message": "Export styles"
|
||||
"message": "Local device",
|
||||
"description": "Selected option to backup indicated styles to local device/drive"
|
||||
},
|
||||
"checkAllUpdates": {
|
||||
"message": "Check all styles for updates",
|
||||
|
@ -1238,6 +1239,10 @@
|
|||
"message": "Click to open the filter, search and bulk actions panel",
|
||||
"description": "Text for button to apply the selected action"
|
||||
},
|
||||
"bulkActionsError": {
|
||||
"message": "Choose at least one style",
|
||||
"description": "Error displayed in a tooltip when the user attempts to apply an action with no styles selected"
|
||||
},
|
||||
"sectionAdd": {
|
||||
"message": "Add another section",
|
||||
"description": "Label for the button to add a section"
|
||||
|
|
|
@ -27,6 +27,7 @@ self.prefs = self.INJECTED === 1 ? self.prefs : (() => {
|
|||
'manage.onlyEnabled.invert': false, // display only disabled styles
|
||||
'manage.onlyLocal.invert': false, // display only externally installed styles
|
||||
'manage.onlyUsercss.invert': false, // display only non-usercss (standard) styles
|
||||
'manage.export.destination': 'local', // default export destination (local or dropbox)
|
||||
|
||||
'manage.newUI.favicons': false, // show favicons for the sites in applies-to
|
||||
'manage.newUI.faviconsGray': true, // gray out favicons
|
||||
|
|
12
manage.html
12
manage.html
|
@ -175,7 +175,7 @@
|
|||
|
||||
<div class="dropdown-content">
|
||||
<a href="#" class="unfile-all-styles" i18n-text="retrieveBckp"></a>
|
||||
<a href="#" class="sync-dropbox-import" i18n-text="retrieveDropboxSync"></a>
|
||||
<a href="#" class="sync-dropbox-import" i18n-text="syncDropboxStyles"></a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -360,7 +360,7 @@
|
|||
</svg>
|
||||
</label>
|
||||
<span class="select-resizer">
|
||||
<select id="manage.onlyLocal.invert" i18n-data-title="manageOnlyLocalTooltip">
|
||||
<select id="manage.onlyLocal.invert" class="tt-s" i18n-data-title="manageOnlyLocalTooltip">
|
||||
<option i18n-text="manageOnlyLocal" value="false"></option>
|
||||
<option i18n-text="manageOnlyExternal" value="true"></option>
|
||||
</select>
|
||||
|
@ -430,7 +430,7 @@
|
|||
</select>
|
||||
<svg class="svg-icon select-arrow"><use xlink:href="#svg-icon-select-arrow"/></svg>
|
||||
</span>
|
||||
<button id="bulk-actions-apply" i18n-text="bulkActionsApply">
|
||||
<button id="bulk-actions-apply" i18n-text="bulkActionsApply" class="tt-e" disabled>
|
||||
<span id="update-progress"></span>
|
||||
</button>
|
||||
<span id="bulk-info">
|
||||
|
@ -445,9 +445,9 @@
|
|||
<span data-bulk="export" class="dropdown export hidden">
|
||||
Export to:
|
||||
<span class="select-resizer">
|
||||
<select id="manage.onlyEnabled.invert">
|
||||
<option id="file-all-styles" i18n-text="bckpInstStyles"></option>
|
||||
<option id="sync-dropbox-export" i18n-text="syncDropboxStyles"></option>
|
||||
<select id="manage.export.destination">
|
||||
<option value="local" i18n-text="bckpInstStyles"></option>
|
||||
<option value="dropbox" i18n-text="syncDropboxStyles"></option>
|
||||
</select>
|
||||
<svg class="svg-icon select-arrow"><use xlink:href="#svg-icon-select-arrow"/></svg>
|
||||
</span>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* global $ $$ handleEvent installed exportToFile checkUpdateAll */
|
||||
/* global $ $$ API t prefs handleEvent installed exportToFile checkUpdateAll exportDropbox
|
||||
messageBox */
|
||||
/* exported bulk */
|
||||
'use strict';
|
||||
|
||||
|
@ -13,14 +14,13 @@ const bulk = {
|
|||
handleSelect: event => {
|
||||
event.preventDefault();
|
||||
$$('[data-bulk]').forEach(el => el.classList.add('hidden'));
|
||||
console.log('select', this.value)
|
||||
|
||||
switch (event.target.value) {
|
||||
case 'enable':
|
||||
break;
|
||||
case 'disable':
|
||||
break;
|
||||
case 'export':
|
||||
console.log('got here')
|
||||
$('[data-bulk="export"]').classList.remove('hidden');
|
||||
break;
|
||||
case 'update':
|
||||
|
@ -51,10 +51,14 @@ console.log('select', this.value)
|
|||
});
|
||||
break;
|
||||
}
|
||||
case 'export':
|
||||
case 'export': {
|
||||
styles = entries.map(entry => entry.styleMeta);
|
||||
exportToFile(styles);
|
||||
break;
|
||||
const destination = prefs.get('manage.export.destination');
|
||||
if (destination === 'dropbox') {
|
||||
return exportDropbox(styles);
|
||||
}
|
||||
return exportToFile(styles);
|
||||
}
|
||||
case 'update':
|
||||
checkUpdateAll(entries); // TO DO
|
||||
break;
|
||||
|
@ -99,6 +103,12 @@ console.log('select', this.value)
|
|||
}
|
||||
const count = $$('.entry-filter-toggle').filter(entry => entry.checked).length;
|
||||
$('#bulk-filter-count').textContent = count || '';
|
||||
|
||||
if (count > 0 && $('#bulk-actions-select').value !== '') {
|
||||
$('#bulk-actions-apply').removeAttribute('disabled');
|
||||
} else {
|
||||
$('#bulk-actions-apply').setAttribute('disabled', true);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -118,4 +128,4 @@ console.log('select', this.value)
|
|||
});
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
[data-title] {
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
[data-title]:after {
|
||||
|
@ -161,4 +162,3 @@
|
|||
.update-problem .check-update:before {
|
||||
border-right-color: var(--tooltip-error);
|
||||
}
|
||||
|
||||
|
|
177
sync/import-export-dropbox.js
Normal file
177
sync/import-export-dropbox.js
Normal file
|
@ -0,0 +1,177 @@
|
|||
/* global messageBox Dropbox createZipFileFromText readZipFileFromBlob
|
||||
launchWebAuthFlow getRedirectUrlAuthFlow importFromString resolve
|
||||
$ $create t chromeLocal API getOwnTab */
|
||||
/* exported exportDropbox */
|
||||
'use strict';
|
||||
|
||||
const DROPBOX_API_KEY = 'zg52vphuapvpng9';
|
||||
const FILENAME_ZIP_FILE = 'stylus.json';
|
||||
const DROPBOX_FILE = 'stylus.zip';
|
||||
const API_ERROR_STATUS_FILE_NOT_FOUND = 409;
|
||||
const HTTP_STATUS_CANCEL = 499;
|
||||
|
||||
function messageProgressBar(data) {
|
||||
return messageBox({
|
||||
title: `${data.title}`,
|
||||
className: 'config-dialog',
|
||||
contents: [
|
||||
$create('p', data.text)
|
||||
],
|
||||
buttons: [{
|
||||
textContent: t('confirmClose'),
|
||||
dataset: {cmd: 'close'},
|
||||
}],
|
||||
}).then(() => {
|
||||
document.body.style.minWidth = '';
|
||||
document.body.style.minHeight = '';
|
||||
});
|
||||
}
|
||||
|
||||
function hasDropboxAccessToken() {
|
||||
return chromeLocal.getValue('dropbox_access_token');
|
||||
}
|
||||
|
||||
function requestDropboxAccessToken() {
|
||||
const client = new Dropbox.Dropbox({
|
||||
clientId: DROPBOX_API_KEY,
|
||||
fetch
|
||||
});
|
||||
const authUrl = client.getAuthenticationUrl(getRedirectUrlAuthFlow());
|
||||
return launchWebAuthFlow({url: authUrl, interactive: true})
|
||||
.then(urlReturned => {
|
||||
const params = new URLSearchParams(new URL(urlReturned).hash.replace('#', ''));
|
||||
chromeLocal.setValue('dropbox_access_token', params.get('access_token'));
|
||||
return params.get('access_token');
|
||||
});
|
||||
}
|
||||
|
||||
function uploadFileDropbox(client, stylesText) {
|
||||
return client.filesUpload({path: '/' + DROPBOX_FILE, contents: stylesText});
|
||||
}
|
||||
|
||||
function exportDropbox(styles) {
|
||||
const mode = localStorage.installType;
|
||||
const title = t('syncDropboxStyles');
|
||||
const text = mode === 'normal' ? t('connectingDropbox') : t('connectingDropboxNotAllowed');
|
||||
messageProgressBar({title, text});
|
||||
if (mode !== 'normal') return;
|
||||
|
||||
hasDropboxAccessToken()
|
||||
.then(token => token || requestDropboxAccessToken())
|
||||
.then(token => {
|
||||
const client = new Dropbox.Dropbox({
|
||||
clientId: DROPBOX_API_KEY,
|
||||
accessToken: token,
|
||||
fetch
|
||||
});
|
||||
return client.filesDownload({path: '/' + DROPBOX_FILE})
|
||||
.then(() => messageBox.confirm(t('overwriteFileExport')))
|
||||
.then(ok => {
|
||||
// deletes file if user want to
|
||||
if (!ok) {
|
||||
return Promise.reject({status: HTTP_STATUS_CANCEL});
|
||||
}
|
||||
return client.filesDelete({path: '/' + DROPBOX_FILE});
|
||||
})
|
||||
// file deleted with success, process styles and create a file
|
||||
.then(() => {
|
||||
messageProgressBar({title: title, text: t('gettingStyles')});
|
||||
return JSON.stringify(styles, null, '\t');
|
||||
})
|
||||
// create zip file
|
||||
.then(stylesText => {
|
||||
messageProgressBar({title: title, text: t('zipStyles')});
|
||||
return createZipFileFromText(FILENAME_ZIP_FILE, stylesText);
|
||||
})
|
||||
// create file dropbox
|
||||
.then(zipedText => {
|
||||
messageProgressBar({title: title, text: t('uploadingFile')});
|
||||
return uploadFileDropbox(client, zipedText);
|
||||
})
|
||||
// gives feedback to user
|
||||
.then(() => messageProgressBar({title: title, text: t('exportSavedSuccess')}))
|
||||
// handle not found cases and cancel action
|
||||
.catch(error => {
|
||||
console.log(error);
|
||||
// saving file first time
|
||||
if (error.status === API_ERROR_STATUS_FILE_NOT_FOUND) {
|
||||
API.getAllStyles()
|
||||
.then(styles => {
|
||||
messageProgressBar({title: title, text: t('gettingStyles')});
|
||||
return JSON.stringify(styles, null, '\t');
|
||||
})
|
||||
.then(stylesText => {
|
||||
messageProgressBar({title: title, text: t('zipStyles')});
|
||||
return createZipFileFromText(FILENAME_ZIP_FILE, stylesText);
|
||||
})
|
||||
.then(zipedText => {
|
||||
messageProgressBar({title: title, text: t('uploadingFile')});
|
||||
return uploadFileDropbox(client, zipedText);
|
||||
})
|
||||
.then(() => messageProgressBar({title: title, text: t('exportSavedSuccess')}))
|
||||
.catch(err => messageBox.alert(err));
|
||||
return;
|
||||
}
|
||||
|
||||
// user cancelled the flow
|
||||
if (error.status === HTTP_STATUS_CANCEL) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.error(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$('#sync-dropbox-import').onclick = () => {
|
||||
const mode = localStorage.installType;
|
||||
const title = t('syncDropboxStyles');
|
||||
const text = mode === 'normal' ? t('connectingDropbox') : t('connectingDropboxNotAllowed');
|
||||
messageProgressBar({title, text});
|
||||
if (mode !== 'normal') return;
|
||||
|
||||
hasDropboxAccessToken()
|
||||
.then(token => token || requestDropboxAccessToken())
|
||||
.then(token => {
|
||||
const client = new Dropbox.Dropbox({
|
||||
clientId: DROPBOX_API_KEY,
|
||||
accessToken: token,
|
||||
fetch
|
||||
});
|
||||
return client.filesDownload({path: '/' + DROPBOX_FILE})
|
||||
.then(response => {
|
||||
messageProgressBar({title: title, text: t('unzipStyles')});
|
||||
return readZipFileFromBlob(response.fileBlob);
|
||||
})
|
||||
.then(zipedFileBlob => {
|
||||
messageProgressBar({title: title, text: t('readingStyles')});
|
||||
document.body.style.cursor = 'wait';
|
||||
const fReader = new FileReader();
|
||||
fReader.onloadend = event => {
|
||||
const text = event.target.result;
|
||||
const maybeUsercss = !/^[\s\r\n]*\[/.test(text) &&
|
||||
(text.includes('==UserStyle==') || /==UserStyle==/i.test(text));
|
||||
(!maybeUsercss ?
|
||||
importFromString(text) :
|
||||
getOwnTab().then(tab => {
|
||||
tab.url = URL.createObjectURL(new Blob([text], {type: 'text/css'}));
|
||||
return API.openUsercssInstallPage({direct: true, tab})
|
||||
.then(() => URL.revokeObjectURL(tab.url));
|
||||
})
|
||||
).then(numStyles => {
|
||||
document.body.style.cursor = '';
|
||||
resolve(numStyles);
|
||||
});
|
||||
};
|
||||
fReader.readAsText(zipedFileBlob, 'utf-8');
|
||||
})
|
||||
.catch(error => {
|
||||
// no file
|
||||
if (error.status === API_ERROR_STATUS_FILE_NOT_FOUND) {
|
||||
messageBox.alert(t('noFileToImport'));
|
||||
return;
|
||||
}
|
||||
messageBox.alert(error);
|
||||
});
|
||||
});
|
||||
};
|
Loading…
Reference in New Issue
Block a user