Feature: Add import and export settings buttons (fixes #2)
This commit is contained in:
parent
2203cb0f90
commit
b063e1507c
|
@ -74,8 +74,10 @@
|
|||
"ts"
|
||||
],
|
||||
"global": [
|
||||
"Blob",
|
||||
"confirm",
|
||||
"document",
|
||||
"FileReader",
|
||||
"performance",
|
||||
"window"
|
||||
],
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
"description": "An updated and reimagined recreation of Tildes Extended to enhance and improve the experience of Tildes.net.",
|
||||
"version": "0.1.1",
|
||||
"permissions": [
|
||||
"downloads",
|
||||
"storage",
|
||||
"*://tildes.net/*"
|
||||
],
|
||||
|
|
|
@ -157,6 +157,16 @@
|
|||
please use the "Copy Bug Template" button below and fill out
|
||||
the template in your message.
|
||||
</p>
|
||||
<form id="import-export">
|
||||
<input class="trx-hidden" accept="application/json" type="file"
|
||||
id="import-file">
|
||||
<button id="import-button">Import Settings</button>
|
||||
<button id="export-button">Export Settings</button>
|
||||
</form>
|
||||
<p>
|
||||
When importing settings, note that your current settings will be
|
||||
deleted and overwritten with the new ones.
|
||||
</p>
|
||||
</div>
|
||||
<div id="debug-buttons">
|
||||
<button id="copy-bug-template-button">
|
||||
|
|
|
@ -200,6 +200,28 @@ p > .red-re {
|
|||
}
|
||||
}
|
||||
|
||||
#import-export {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
> button {
|
||||
border: none;
|
||||
color: $foreground;
|
||||
background-color: $cyan;
|
||||
padding: 1rem;
|
||||
|
||||
&:hover {
|
||||
background-color: darken($cyan, 10%);
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#footer {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
import {browser} from 'webextension-polyfill-ts';
|
||||
import {
|
||||
querySelector,
|
||||
flashMessage,
|
||||
Settings,
|
||||
log,
|
||||
getSettings,
|
||||
isValidTildesUsername,
|
||||
isValidHexColor,
|
||||
setSettings
|
||||
} from './utilities';
|
||||
import {themeColors} from './theme-colors';
|
||||
|
||||
export async function importSettingsHandler(event: MouseEvent): Promise<void> {
|
||||
event.preventDefault();
|
||||
const fileInput: HTMLInputElement = querySelector('#import-file');
|
||||
fileInput.click();
|
||||
}
|
||||
|
||||
export async function importFileHandler(event: Event): Promise<void> {
|
||||
const fileList: FileList | null = (event.target as HTMLInputElement).files;
|
||||
if (fileList === null) {
|
||||
flashMessage('No file imported.');
|
||||
return;
|
||||
}
|
||||
|
||||
const reader: FileReader = new FileReader();
|
||||
reader.addEventListener(
|
||||
'load',
|
||||
async (): Promise<void> => {
|
||||
let data: Partial<Settings>;
|
||||
try {
|
||||
data = JSON.parse(reader.result!.toString());
|
||||
} catch (error) {
|
||||
log(error, true);
|
||||
flashMessage(error, true);
|
||||
return;
|
||||
}
|
||||
|
||||
const settings: Settings = await getSettings();
|
||||
const newSettings: Settings = {...settings};
|
||||
if (typeof data.data !== 'undefined') {
|
||||
if (typeof data.data.userLabels !== 'undefined') {
|
||||
newSettings.data.userLabels = [];
|
||||
for (const label of data.data.userLabels) {
|
||||
if (
|
||||
typeof label.username === 'undefined' ||
|
||||
!isValidTildesUsername(label.username)
|
||||
) {
|
||||
log(`Invalid username in imported labels: ${label.username}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
newSettings.data.userLabels.push({
|
||||
color: isValidHexColor(label.color)
|
||||
? label.color
|
||||
: themeColors.white.backgroundAlt,
|
||||
id: newSettings.data.userLabels.length + 1,
|
||||
priority: isNaN(label.priority) ? 0 : label.priority,
|
||||
text: typeof label.text === 'undefined' ? 'Label' : label.text,
|
||||
username: label.username
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof data.features !== 'undefined') {
|
||||
newSettings.features = {...data.features};
|
||||
}
|
||||
|
||||
await setSettings(newSettings);
|
||||
flashMessage(
|
||||
'Successfully imported your settings, reloading the page to apply.'
|
||||
);
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 2500);
|
||||
}
|
||||
);
|
||||
reader.addEventListener('error', (): void => {
|
||||
log(reader.error, true);
|
||||
reader.abort();
|
||||
});
|
||||
reader.readAsText(fileList[0]);
|
||||
}
|
||||
|
||||
export async function exportSettingsHandler(event: MouseEvent): Promise<void> {
|
||||
event.preventDefault();
|
||||
const settings: Settings = await getSettings();
|
||||
const settingsBlob: Blob = new Blob([JSON.stringify(settings, null, 2)], {
|
||||
type: 'text/json'
|
||||
});
|
||||
const blobObjectURL: string = URL.createObjectURL(settingsBlob);
|
||||
try {
|
||||
await browser.downloads.download({
|
||||
filename: 'tildes_reextended-settings.json',
|
||||
url: blobObjectURL,
|
||||
saveAs: true
|
||||
});
|
||||
} catch (error) {
|
||||
log(error);
|
||||
} finally {
|
||||
// According to MDN, when creating an object URL we should also revoke it
|
||||
// when "it's safe to do so" to prevent excess memory/storage use. 60
|
||||
// seconds should be enough time to download the settings.
|
||||
setTimeout(() => URL.revokeObjectURL(blobObjectURL), 60000);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,10 @@
|
|||
import platform from 'platform';
|
||||
import {browser} from 'webextension-polyfill-ts';
|
||||
import {
|
||||
importSettingsHandler,
|
||||
importFileHandler,
|
||||
exportSettingsHandler
|
||||
} from './import-export';
|
||||
import {
|
||||
getSettings,
|
||||
Settings,
|
||||
|
@ -33,6 +38,19 @@ window.addEventListener(
|
|||
)
|
||||
);
|
||||
|
||||
const importSettingsButton: HTMLButtonElement = querySelector(
|
||||
'#import-button'
|
||||
);
|
||||
importSettingsButton.addEventListener('click', importSettingsHandler);
|
||||
|
||||
const importFileInput: HTMLInputElement = querySelector('#import-file');
|
||||
importFileInput.addEventListener('change', importFileHandler);
|
||||
|
||||
const exportSettingsButton: HTMLButtonElement = querySelector(
|
||||
'#export-button'
|
||||
);
|
||||
exportSettingsButton.addEventListener('click', exportSettingsHandler);
|
||||
|
||||
const copyBugTemplateButton: HTMLButtonElement = querySelector(
|
||||
'#copy-bug-template-button'
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue