Convert dictionaries.js and storage.js to classes (#570)
* Convert dictionaries.js to a class * Remove storage spinner * Convert storage.js to a class * Move dataset assignments into main.js
This commit is contained in:
parent
c62f980f37
commit
418e8a57bf
@ -18,7 +18,7 @@
|
||||
|
||||
#anki-spinner,
|
||||
#dict-spinner, #dict-import-progress,
|
||||
.storage-hidden, #storage-spinner {
|
||||
.storage-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
@ -22,14 +22,9 @@
|
||||
* getOptionsFullMutable
|
||||
* getOptionsMutable
|
||||
* settingsSaveOptions
|
||||
* storageEstimate
|
||||
* storageUpdateStats
|
||||
* utilBackgroundIsolate
|
||||
*/
|
||||
|
||||
let dictionaryUI = null;
|
||||
|
||||
|
||||
class SettingsDictionaryListUI {
|
||||
constructor(container, template, extraContainer, extraTemplate) {
|
||||
this.container = container;
|
||||
@ -308,13 +303,13 @@ class SettingsDictionaryEntryUI {
|
||||
|
||||
await api.deleteDictionary(this.dictionaryInfo.title, onProgress);
|
||||
} catch (e) {
|
||||
dictionaryErrorsShow([e]);
|
||||
this.dictionaryErrorsShow([e]);
|
||||
} finally {
|
||||
prevention.end();
|
||||
this.isDeleting = false;
|
||||
progress.hidden = true;
|
||||
|
||||
onDatabaseUpdated();
|
||||
this.onDatabaseUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
@ -388,59 +383,63 @@ class SettingsDictionaryExtraUI {
|
||||
}
|
||||
}
|
||||
|
||||
class DictionaryController {
|
||||
constructor(storageController) {
|
||||
this._storageController = storageController;
|
||||
this._dictionaryUI = null;
|
||||
this._dictionaryErrorToStringOverrides = [
|
||||
[
|
||||
'A mutation operation was attempted on a database that did not allow mutations.',
|
||||
'Access to IndexedDB appears to be restricted. Firefox seems to require that the history preference is set to "Remember history" before IndexedDB use of any kind is allowed.'
|
||||
],
|
||||
[
|
||||
'The operation failed for reasons unrelated to the database itself and not covered by any other error code.',
|
||||
'Unable to access IndexedDB due to a possibly corrupt user profile. Try using the "Refresh Firefox" feature to reset your user profile.'
|
||||
],
|
||||
[
|
||||
'BulkError',
|
||||
'Unable to finish importing dictionary data into IndexedDB. This may indicate that you do not have sufficient disk space available to complete this operation.'
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
async function dictSettingsInitialize() {
|
||||
dictionaryUI = new SettingsDictionaryListUI(
|
||||
async prepare() {
|
||||
this._dictionaryUI = new SettingsDictionaryListUI(
|
||||
document.querySelector('#dict-groups'),
|
||||
document.querySelector('#dict-template'),
|
||||
document.querySelector('#dict-groups-extra'),
|
||||
document.querySelector('#dict-extra-template')
|
||||
);
|
||||
dictionaryUI.save = settingsSaveOptions;
|
||||
this._dictionaryUI.save = settingsSaveOptions;
|
||||
|
||||
document.querySelector('#dict-purge-button').addEventListener('click', onDictionaryPurgeButtonClick, false);
|
||||
document.querySelector('#dict-purge-confirm').addEventListener('click', onDictionaryPurge, false);
|
||||
document.querySelector('#dict-file-button').addEventListener('click', onDictionaryImportButtonClick, false);
|
||||
document.querySelector('#dict-file').addEventListener('change', onDictionaryImport, false);
|
||||
document.querySelector('#dict-main').addEventListener('change', onDictionaryMainChanged, false);
|
||||
document.querySelector('#database-enable-prefix-wildcard-searches').addEventListener('change', onDatabaseEnablePrefixWildcardSearchesChanged, false);
|
||||
document.querySelector('#dict-purge-button').addEventListener('click', this._onPurgeButtonClick.bind(this), false);
|
||||
document.querySelector('#dict-purge-confirm').addEventListener('click', this._onPurgeConfirmButtonClick.bind(this), false);
|
||||
document.querySelector('#dict-file-button').addEventListener('click', this._onImportButtonClick.bind(this), false);
|
||||
document.querySelector('#dict-file').addEventListener('change', this._onImportFileChange.bind(this), false);
|
||||
document.querySelector('#dict-main').addEventListener('change', this._onDictionaryMainChanged.bind(this), false);
|
||||
document.querySelector('#database-enable-prefix-wildcard-searches').addEventListener('change', this._onDatabaseEnablePrefixWildcardSearchesChanged.bind(this), false);
|
||||
|
||||
await onDictionaryOptionsChanged();
|
||||
await onDatabaseUpdated();
|
||||
}
|
||||
await this.optionsChanged();
|
||||
await this._onDatabaseUpdated();
|
||||
}
|
||||
|
||||
async function onDictionaryOptionsChanged() {
|
||||
if (dictionaryUI === null) { return; }
|
||||
async optionsChanged() {
|
||||
if (this._dictionaryUI === null) { return; }
|
||||
|
||||
const optionsContext = getOptionsContext();
|
||||
const options = await getOptionsMutable(optionsContext);
|
||||
|
||||
dictionaryUI.setOptionsDictionaries(options.dictionaries);
|
||||
this._dictionaryUI.setOptionsDictionaries(options.dictionaries);
|
||||
|
||||
const optionsFull = await api.optionsGetFull();
|
||||
document.querySelector('#database-enable-prefix-wildcard-searches').checked = optionsFull.global.database.prefixWildcardsSupported;
|
||||
|
||||
await updateMainDictionarySelectValue();
|
||||
}
|
||||
|
||||
async function onDatabaseUpdated() {
|
||||
try {
|
||||
const dictionaries = await api.getDictionaryInfo();
|
||||
dictionaryUI.setDictionaries(dictionaries);
|
||||
|
||||
document.querySelector('#dict-warning').hidden = (dictionaries.length > 0);
|
||||
|
||||
updateMainDictionarySelectOptions(dictionaries);
|
||||
await updateMainDictionarySelectValue();
|
||||
|
||||
const {counts, total} = await api.getDictionaryCounts(dictionaries.map((v) => v.title), true);
|
||||
dictionaryUI.setCounts(counts, total);
|
||||
} catch (e) {
|
||||
dictionaryErrorsShow([e]);
|
||||
await this._updateMainDictionarySelectValue();
|
||||
}
|
||||
}
|
||||
|
||||
function updateMainDictionarySelectOptions(dictionaries) {
|
||||
// Private
|
||||
|
||||
_updateMainDictionarySelectOptions(dictionaries) {
|
||||
const select = document.querySelector('#dict-main');
|
||||
select.textContent = ''; // Empty
|
||||
|
||||
@ -458,9 +457,9 @@ function updateMainDictionarySelectOptions(dictionaries) {
|
||||
option.textContent = title;
|
||||
select.appendChild(option);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function updateMainDictionarySelectValue() {
|
||||
async _updateMainDictionarySelectValue() {
|
||||
const optionsContext = getOptionsContext();
|
||||
const options = await api.optionsGet(optionsContext);
|
||||
|
||||
@ -492,32 +491,16 @@ async function updateMainDictionarySelectValue() {
|
||||
}
|
||||
|
||||
select.value = value;
|
||||
}
|
||||
|
||||
async function onDictionaryMainChanged(e) {
|
||||
const select = e.target;
|
||||
const value = select.value;
|
||||
|
||||
const missingNodeOption = select.querySelector('option[data-not-installed=true]');
|
||||
if (missingNodeOption !== null && missingNodeOption.value !== value) {
|
||||
missingNodeOption.parentNode.removeChild(missingNodeOption);
|
||||
}
|
||||
|
||||
const optionsContext = getOptionsContext();
|
||||
const options = await getOptionsMutable(optionsContext);
|
||||
options.general.mainDictionary = value;
|
||||
await settingsSaveOptions();
|
||||
}
|
||||
|
||||
|
||||
function dictionaryErrorToString(error) {
|
||||
_dictionaryErrorToString(error) {
|
||||
if (error.toString) {
|
||||
error = error.toString();
|
||||
} else {
|
||||
error = `${error}`;
|
||||
}
|
||||
|
||||
for (const [match, subst] of dictionaryErrorToString.overrides) {
|
||||
for (const [match, subst] of this._dictionaryErrorToStringOverrides) {
|
||||
if (error.includes(match)) {
|
||||
error = subst;
|
||||
break;
|
||||
@ -525,23 +508,9 @@ function dictionaryErrorToString(error) {
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
dictionaryErrorToString.overrides = [
|
||||
[
|
||||
'A mutation operation was attempted on a database that did not allow mutations.',
|
||||
'Access to IndexedDB appears to be restricted. Firefox seems to require that the history preference is set to "Remember history" before IndexedDB use of any kind is allowed.'
|
||||
],
|
||||
[
|
||||
'The operation failed for reasons unrelated to the database itself and not covered by any other error code.',
|
||||
'Unable to access IndexedDB due to a possibly corrupt user profile. Try using the "Refresh Firefox" feature to reset your user profile.'
|
||||
],
|
||||
[
|
||||
'BulkError',
|
||||
'Unable to finish importing dictionary data into IndexedDB. This may indicate that you do not have sufficient disk space available to complete this operation.'
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
function dictionaryErrorsShow(errors) {
|
||||
_dictionaryErrorsShow(errors) {
|
||||
const dialog = document.querySelector('#dict-error');
|
||||
dialog.textContent = '';
|
||||
|
||||
@ -549,7 +518,7 @@ function dictionaryErrorsShow(errors) {
|
||||
const uniqueErrors = new Map();
|
||||
for (let e of errors) {
|
||||
yomichan.logError(e);
|
||||
e = dictionaryErrorToString(e);
|
||||
e = this._dictionaryErrorToString(e);
|
||||
let count = uniqueErrors.get(e);
|
||||
if (typeof count === 'undefined') {
|
||||
count = 0;
|
||||
@ -574,29 +543,69 @@ function dictionaryErrorsShow(errors) {
|
||||
} else {
|
||||
dialog.hidden = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function dictionarySpinnerShow(show) {
|
||||
_dictionarySpinnerShow(show) {
|
||||
const spinner = $('#dict-spinner');
|
||||
if (show) {
|
||||
spinner.show();
|
||||
} else {
|
||||
spinner.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onDictionaryImportButtonClick() {
|
||||
_dictReadFile(file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => resolve(reader.result);
|
||||
reader.onerror = () => reject(reader.error);
|
||||
reader.readAsBinaryString(file);
|
||||
});
|
||||
}
|
||||
|
||||
async _onDatabaseUpdated() {
|
||||
try {
|
||||
const dictionaries = await api.getDictionaryInfo();
|
||||
this._dictionaryUI.setDictionaries(dictionaries);
|
||||
|
||||
document.querySelector('#dict-warning').hidden = (dictionaries.length > 0);
|
||||
|
||||
this._updateMainDictionarySelectOptions(dictionaries);
|
||||
await this._updateMainDictionarySelectValue();
|
||||
|
||||
const {counts, total} = await api.getDictionaryCounts(dictionaries.map((v) => v.title), true);
|
||||
this._dictionaryUI.setCounts(counts, total);
|
||||
} catch (e) {
|
||||
this._dictionaryErrorsShow([e]);
|
||||
}
|
||||
}
|
||||
|
||||
async _onDictionaryMainChanged(e) {
|
||||
const select = e.target;
|
||||
const value = select.value;
|
||||
|
||||
const missingNodeOption = select.querySelector('option[data-not-installed=true]');
|
||||
if (missingNodeOption !== null && missingNodeOption.value !== value) {
|
||||
missingNodeOption.parentNode.removeChild(missingNodeOption);
|
||||
}
|
||||
|
||||
const optionsContext = getOptionsContext();
|
||||
const options = await getOptionsMutable(optionsContext);
|
||||
options.general.mainDictionary = value;
|
||||
await settingsSaveOptions();
|
||||
}
|
||||
|
||||
_onImportButtonClick() {
|
||||
const dictFile = document.querySelector('#dict-file');
|
||||
dictFile.click();
|
||||
}
|
||||
}
|
||||
|
||||
function onDictionaryPurgeButtonClick(e) {
|
||||
_onPurgeButtonClick(e) {
|
||||
e.preventDefault();
|
||||
$('#dict-purge-modal').modal('show');
|
||||
}
|
||||
}
|
||||
|
||||
async function onDictionaryPurge(e) {
|
||||
async _onPurgeConfirmButtonClick(e) {
|
||||
e.preventDefault();
|
||||
|
||||
$('#dict-purge-modal').modal('hide');
|
||||
@ -609,8 +618,8 @@ async function onDictionaryPurge(e) {
|
||||
|
||||
try {
|
||||
prevention.start();
|
||||
dictionaryErrorsShow(null);
|
||||
dictionarySpinnerShow(true);
|
||||
this._dictionaryErrorsShow(null);
|
||||
this._dictionarySpinnerShow(true);
|
||||
|
||||
await api.purgeDatabase();
|
||||
for (const {options} of toIterable((await getOptionsFullMutable()).profiles)) {
|
||||
@ -619,24 +628,22 @@ async function onDictionaryPurge(e) {
|
||||
}
|
||||
await settingsSaveOptions();
|
||||
|
||||
onDatabaseUpdated();
|
||||
this._onDatabaseUpdated();
|
||||
} catch (err) {
|
||||
dictionaryErrorsShow([err]);
|
||||
this._dictionaryErrorsShow([err]);
|
||||
} finally {
|
||||
prevention.end();
|
||||
|
||||
dictionarySpinnerShow(false);
|
||||
this._dictionarySpinnerShow(false);
|
||||
|
||||
dictControls.show();
|
||||
dictProgress.hidden = true;
|
||||
|
||||
if (storageEstimate.mostRecent !== null) {
|
||||
storageUpdateStats();
|
||||
this._storageController.updateStats();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function onDictionaryImport(e) {
|
||||
async _onImportFileChange(e) {
|
||||
const files = [...e.target.files];
|
||||
e.target.value = null;
|
||||
|
||||
@ -649,15 +656,13 @@ async function onDictionaryImport(e) {
|
||||
|
||||
try {
|
||||
prevention.start();
|
||||
dictionaryErrorsShow(null);
|
||||
dictionarySpinnerShow(true);
|
||||
this._dictionaryErrorsShow(null);
|
||||
this._dictionarySpinnerShow(true);
|
||||
|
||||
const setProgress = (percent) => dictProgress.find('.progress-bar').css('width', `${percent}%`);
|
||||
const updateProgress = (total, current) => {
|
||||
setProgress(current / total * 100.0);
|
||||
if (storageEstimate.mostRecent !== null && !storageUpdateStats.isUpdating) {
|
||||
storageUpdateStats();
|
||||
}
|
||||
this._storageController.updateStats();
|
||||
};
|
||||
|
||||
const optionsFull = await api.optionsGetFull();
|
||||
@ -673,7 +678,7 @@ async function onDictionaryImport(e) {
|
||||
dictImportInfo.textContent = `(${i + 1} of ${ii})`;
|
||||
}
|
||||
|
||||
const archiveContent = await dictReadFile(files[i]);
|
||||
const archiveContent = await this._dictReadFile(files[i]);
|
||||
const {result, errors} = await api.importDictionaryArchive(archiveContent, importDetails, updateProgress);
|
||||
for (const {options} of toIterable((await getOptionsFullMutable()).profiles)) {
|
||||
const dictionaryOptions = SettingsDictionaryListUI.createDictionaryOptions();
|
||||
@ -689,16 +694,16 @@ async function onDictionaryImport(e) {
|
||||
if (errors.length > 0) {
|
||||
const errors2 = errors.map((error) => jsonToError(error));
|
||||
errors2.push(`Dictionary may not have been imported properly: ${errors2.length} error${errors2.length === 1 ? '' : 's'} reported.`);
|
||||
dictionaryErrorsShow(errors2);
|
||||
this._dictionaryErrorsShow(errors2);
|
||||
}
|
||||
|
||||
onDatabaseUpdated();
|
||||
this._onDatabaseUpdated();
|
||||
}
|
||||
} catch (err) {
|
||||
dictionaryErrorsShow([err]);
|
||||
this._dictionaryErrorsShow([err]);
|
||||
} finally {
|
||||
prevention.end();
|
||||
dictionarySpinnerShow(false);
|
||||
this._dictionarySpinnerShow(false);
|
||||
|
||||
dictImportInfo.hidden = false;
|
||||
dictImportInfo.textContent = '';
|
||||
@ -706,22 +711,13 @@ async function onDictionaryImport(e) {
|
||||
dictControls.show();
|
||||
dictProgress.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function dictReadFile(file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => resolve(reader.result);
|
||||
reader.onerror = () => reject(reader.error);
|
||||
reader.readAsBinaryString(file);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async function onDatabaseEnablePrefixWildcardSearchesChanged(e) {
|
||||
async _onDatabaseEnablePrefixWildcardSearchesChanged(e) {
|
||||
const optionsFull = await getOptionsFullMutable();
|
||||
const v = !!e.target.checked;
|
||||
if (optionsFull.global.database.prefixWildcardsSupported === v) { return; }
|
||||
optionsFull.global.database.prefixWildcardsSupported = !!e.target.checked;
|
||||
await settingsSaveOptions();
|
||||
}
|
||||
}
|
||||
|
@ -19,14 +19,13 @@
|
||||
* AnkiController
|
||||
* AnkiTemplatesController
|
||||
* AudioController
|
||||
* DictionaryController
|
||||
* ProfileController
|
||||
* SettingsBackup
|
||||
* SettingsController
|
||||
* StorageController
|
||||
* api
|
||||
* appearanceInitialize
|
||||
* dictSettingsInitialize
|
||||
* onDictionaryOptionsChanged
|
||||
* storageInfoInitialize
|
||||
* utilBackend
|
||||
* utilBackgroundIsolate
|
||||
*/
|
||||
@ -270,7 +269,9 @@ async function onOptionsUpdated({source}) {
|
||||
if (ankiTemplatesController !== null) {
|
||||
ankiTemplatesController.updateValue();
|
||||
}
|
||||
onDictionaryOptionsChanged();
|
||||
if (dictionaryController !== null) {
|
||||
dictionaryController.optionsChanged();
|
||||
}
|
||||
if (ankiController !== null) {
|
||||
ankiController.optionsChanged();
|
||||
}
|
||||
@ -304,8 +305,15 @@ async function settingsPopulateModifierKeys() {
|
||||
}
|
||||
}
|
||||
|
||||
async function setupEnvironmentInfo() {
|
||||
const {browser, platform} = await api.getEnvironmentInfo();
|
||||
document.documentElement.dataset.browser = browser;
|
||||
document.documentElement.dataset.operatingSystem = platform.os;
|
||||
}
|
||||
|
||||
let ankiController = null;
|
||||
let ankiTemplatesController = null;
|
||||
let dictionaryController = null;
|
||||
|
||||
async function onReady() {
|
||||
api.forwardLogsToBackend();
|
||||
@ -314,22 +322,25 @@ async function onReady() {
|
||||
const settingsController = new SettingsController();
|
||||
settingsController.prepare();
|
||||
|
||||
setupEnvironmentInfo();
|
||||
showExtensionInformation();
|
||||
|
||||
const storageController = new StorageController();
|
||||
storageController.prepare();
|
||||
|
||||
await settingsPopulateModifierKeys();
|
||||
formSetupEventListeners();
|
||||
appearanceInitialize();
|
||||
new AudioController().prepare();
|
||||
await (new ProfileController()).prepare();
|
||||
await dictSettingsInitialize();
|
||||
dictionaryController = new DictionaryController(storageController);
|
||||
dictionaryController.prepare();
|
||||
ankiController = new AnkiController();
|
||||
ankiController.prepare();
|
||||
ankiTemplatesController = new AnkiTemplatesController(ankiController);
|
||||
ankiTemplatesController.prepare();
|
||||
new SettingsBackup().prepare();
|
||||
|
||||
storageInfoInitialize();
|
||||
|
||||
yomichan.on('optionsUpdated', onOptionsUpdated);
|
||||
}
|
||||
|
||||
|
@ -15,94 +15,49 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* global
|
||||
* api
|
||||
*/
|
||||
|
||||
function storageBytesToLabeledString(size) {
|
||||
const base = 1000;
|
||||
const labels = [' bytes', 'KB', 'MB', 'GB'];
|
||||
let labelIndex = 0;
|
||||
while (size >= base) {
|
||||
size /= base;
|
||||
++labelIndex;
|
||||
class StorageController {
|
||||
constructor() {
|
||||
this._mostRecentStorageEstimate = null;
|
||||
this._storageEstimateFailed = false;
|
||||
this._isUpdating = false;
|
||||
}
|
||||
const label = labelIndex === 0 ? `${size}` : size.toFixed(1);
|
||||
return `${label}${labels[labelIndex]}`;
|
||||
}
|
||||
|
||||
async function storageEstimate() {
|
||||
prepare() {
|
||||
this._preparePersistentStorage();
|
||||
this.updateStats();
|
||||
document.querySelector('#storage-refresh').addEventListener('click', this.updateStats.bind(this), false);
|
||||
}
|
||||
|
||||
async updateStats() {
|
||||
try {
|
||||
return (storageEstimate.mostRecent = await navigator.storage.estimate());
|
||||
} catch (e) {
|
||||
// NOP
|
||||
}
|
||||
return null;
|
||||
}
|
||||
storageEstimate.mostRecent = null;
|
||||
this._isUpdating = true;
|
||||
|
||||
async function isStoragePeristent() {
|
||||
try {
|
||||
return await navigator.storage.persisted();
|
||||
} catch (e) {
|
||||
// NOP
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async function storageInfoInitialize() {
|
||||
storagePersistInitialize();
|
||||
const {browser, platform} = await api.getEnvironmentInfo();
|
||||
document.documentElement.dataset.browser = browser;
|
||||
document.documentElement.dataset.operatingSystem = platform.os;
|
||||
|
||||
await storageShowInfo();
|
||||
|
||||
document.querySelector('#storage-refresh').addEventListener('click', storageShowInfo, false);
|
||||
}
|
||||
|
||||
async function storageUpdateStats() {
|
||||
storageUpdateStats.isUpdating = true;
|
||||
|
||||
const estimate = await storageEstimate();
|
||||
const estimate = await this._storageEstimate();
|
||||
const valid = (estimate !== null);
|
||||
|
||||
if (valid) {
|
||||
// Firefox reports usage as 0 when persistent storage is enabled.
|
||||
const finite = (estimate.usage > 0 || !(await isStoragePeristent()));
|
||||
const finite = (estimate.usage > 0 || !(await this._isStoragePeristent()));
|
||||
if (finite) {
|
||||
document.querySelector('#storage-usage').textContent = storageBytesToLabeledString(estimate.usage);
|
||||
document.querySelector('#storage-quota').textContent = storageBytesToLabeledString(estimate.quota);
|
||||
document.querySelector('#storage-usage').textContent = this._bytesToLabeledString(estimate.usage);
|
||||
document.querySelector('#storage-quota').textContent = this._bytesToLabeledString(estimate.quota);
|
||||
}
|
||||
document.querySelector('#storage-use-finite').classList.toggle('storage-hidden', !finite);
|
||||
document.querySelector('#storage-use-infinite').classList.toggle('storage-hidden', finite);
|
||||
}
|
||||
|
||||
storageUpdateStats.isUpdating = false;
|
||||
return valid;
|
||||
}
|
||||
storageUpdateStats.isUpdating = false;
|
||||
|
||||
async function storageShowInfo() {
|
||||
storageSpinnerShow(true);
|
||||
|
||||
const valid = await storageUpdateStats();
|
||||
document.querySelector('#storage-use').classList.toggle('storage-hidden', !valid);
|
||||
document.querySelector('#storage-error').classList.toggle('storage-hidden', valid);
|
||||
|
||||
storageSpinnerShow(false);
|
||||
}
|
||||
|
||||
function storageSpinnerShow(show) {
|
||||
const spinner = $('#storage-spinner');
|
||||
if (show) {
|
||||
spinner.show();
|
||||
} else {
|
||||
spinner.hide();
|
||||
return valid;
|
||||
} finally {
|
||||
this._isUpdating = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function storagePersistInitialize() {
|
||||
// Private
|
||||
|
||||
async _preparePersistentStorage() {
|
||||
if (!(navigator.storage && navigator.storage.persist)) {
|
||||
// Not supported
|
||||
return;
|
||||
@ -115,7 +70,7 @@ async function storagePersistInitialize() {
|
||||
info.classList.remove('storage-hidden');
|
||||
button.classList.remove('storage-hidden');
|
||||
|
||||
let persisted = await isStoragePeristent();
|
||||
let persisted = await this._isStoragePeristent();
|
||||
checkbox.checked = persisted;
|
||||
|
||||
button.addEventListener('click', async () => {
|
||||
@ -132,9 +87,45 @@ async function storagePersistInitialize() {
|
||||
if (result) {
|
||||
persisted = true;
|
||||
checkbox.checked = true;
|
||||
storageShowInfo();
|
||||
this.updateStats();
|
||||
} else {
|
||||
$('.storage-persist-fail-warning').removeClass('storage-hidden');
|
||||
document.querySelector('.storage-persist-fail-warning').classList.remove('storage-hidden');
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
|
||||
async _storageEstimate() {
|
||||
if (this._storageEstimateFailed && this._mostRecentStorageEstimate === null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const value = await navigator.storage.estimate();
|
||||
this._mostRecentStorageEstimate = value;
|
||||
return value;
|
||||
} catch (e) {
|
||||
this._storageEstimateFailed = true;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
_bytesToLabeledString(size) {
|
||||
const base = 1000;
|
||||
const labels = [' bytes', 'KB', 'MB', 'GB'];
|
||||
let labelIndex = 0;
|
||||
while (size >= base) {
|
||||
size /= base;
|
||||
++labelIndex;
|
||||
}
|
||||
const label = labelIndex === 0 ? `${size}` : size.toFixed(1);
|
||||
return `${label}${labels[labelIndex]}`;
|
||||
}
|
||||
|
||||
async _isStoragePeristent() {
|
||||
try {
|
||||
return await navigator.storage.persisted();
|
||||
} catch (e) {
|
||||
// NOP
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -711,7 +711,6 @@
|
||||
|
||||
<div id="storage-info">
|
||||
<div>
|
||||
<img src="/mixed/img/spinner.gif" class="pull-right" id="storage-spinner" />
|
||||
<h3>Storage</h3>
|
||||
</div>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user