Persistent storage controller (#1478)
* Add PersistentStorageController * Update DictionaryController * Update DictionaryImportController * Update when storage stats are updated
This commit is contained in:
parent
571b865ae5
commit
4208595293
@ -190,10 +190,9 @@ class DictionaryEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class DictionaryController {
|
class DictionaryController {
|
||||||
constructor(settingsController, modalController, storageController, statusFooter) {
|
constructor(settingsController, modalController, statusFooter) {
|
||||||
this._settingsController = settingsController;
|
this._settingsController = settingsController;
|
||||||
this._modalController = modalController;
|
this._modalController = modalController;
|
||||||
this._storageController = storageController;
|
|
||||||
this._statusFooter = statusFooter;
|
this._statusFooter = statusFooter;
|
||||||
this._dictionaries = null;
|
this._dictionaries = null;
|
||||||
this._dictionaryEntries = [];
|
this._dictionaryEntries = [];
|
||||||
@ -436,7 +435,6 @@ class DictionaryController {
|
|||||||
const index = this._dictionaryEntries.findIndex((entry) => entry.dictionaryTitle === dictionaryTitle);
|
const index = this._dictionaryEntries.findIndex((entry) => entry.dictionaryTitle === dictionaryTitle);
|
||||||
if (index < 0) { return; }
|
if (index < 0) { return; }
|
||||||
|
|
||||||
const storageController = this._storageController;
|
|
||||||
const statusFooter = this._statusFooter;
|
const statusFooter = this._statusFooter;
|
||||||
const {node} = this._dictionaryEntries[index];
|
const {node} = this._dictionaryEntries[index];
|
||||||
const progressSelector = '.dictionary-delete-progress';
|
const progressSelector = '.dictionary-delete-progress';
|
||||||
@ -483,7 +481,7 @@ class DictionaryController {
|
|||||||
if (statusFooter !== null) { statusFooter.setTaskActive(progressSelector, false); }
|
if (statusFooter !== null) { statusFooter.setTaskActive(progressSelector, false); }
|
||||||
this._setButtonsEnabled(true);
|
this._setButtonsEnabled(true);
|
||||||
this._isDeleting = false;
|
this._isDeleting = false;
|
||||||
if (storageController !== null) { storageController.updateStats(); }
|
this._triggerStorageChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -547,6 +545,10 @@ class DictionaryController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_triggerStorageChanged() {
|
||||||
|
yomichan.trigger('storageChanged');
|
||||||
|
}
|
||||||
|
|
||||||
static createDefaultDictionarySettings() {
|
static createDefaultDictionarySettings() {
|
||||||
return {
|
return {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
|
@ -22,10 +22,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class DictionaryImportController {
|
class DictionaryImportController {
|
||||||
constructor(settingsController, modalController, storageController, statusFooter) {
|
constructor(settingsController, modalController, statusFooter) {
|
||||||
this._settingsController = settingsController;
|
this._settingsController = settingsController;
|
||||||
this._modalController = modalController;
|
this._modalController = modalController;
|
||||||
this._storageController = storageController;
|
|
||||||
this._statusFooter = statusFooter;
|
this._statusFooter = statusFooter;
|
||||||
this._modifying = false;
|
this._modifying = false;
|
||||||
this._purgeButton = null;
|
this._purgeButton = null;
|
||||||
@ -92,7 +91,6 @@ class DictionaryImportController {
|
|||||||
if (this._modifying) { return; }
|
if (this._modifying) { return; }
|
||||||
|
|
||||||
const purgeNotification = this._purgeNotification;
|
const purgeNotification = this._purgeNotification;
|
||||||
const storageController = this._storageController;
|
|
||||||
const prevention = this._preventPageExit();
|
const prevention = this._preventPageExit();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -114,7 +112,7 @@ class DictionaryImportController {
|
|||||||
if (purgeNotification !== null) { purgeNotification.hidden = true; }
|
if (purgeNotification !== null) { purgeNotification.hidden = true; }
|
||||||
this._setSpinnerVisible(false);
|
this._setSpinnerVisible(false);
|
||||||
this._setModifying(false);
|
this._setModifying(false);
|
||||||
if (storageController !== null) { storageController.updateStats(); }
|
this._triggerStorageChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +120,6 @@ class DictionaryImportController {
|
|||||||
if (this._modifying) { return; }
|
if (this._modifying) { return; }
|
||||||
|
|
||||||
const statusFooter = this._statusFooter;
|
const statusFooter = this._statusFooter;
|
||||||
const storageController = this._storageController;
|
|
||||||
const importInfo = document.querySelector('#dictionary-import-info');
|
const importInfo = document.querySelector('#dictionary-import-info');
|
||||||
const progressSelector = '.dictionary-import-progress';
|
const progressSelector = '.dictionary-import-progress';
|
||||||
const progressContainers = [
|
const progressContainers = [
|
||||||
@ -156,7 +153,7 @@ class DictionaryImportController {
|
|||||||
const statusString = `${percent.toFixed(0)}%`;
|
const statusString = `${percent.toFixed(0)}%`;
|
||||||
for (const progressBar of progressBars) { progressBar.style.width = cssString; }
|
for (const progressBar of progressBars) { progressBar.style.width = cssString; }
|
||||||
for (const label of statusLabels) { label.textContent = statusString; }
|
for (const label of statusLabels) { label.textContent = statusString; }
|
||||||
if (storageController !== null) { storageController.updateStats(); }
|
this._triggerStorageChanged();
|
||||||
};
|
};
|
||||||
|
|
||||||
const fileCount = files.length;
|
const fileCount = files.length;
|
||||||
@ -186,7 +183,7 @@ class DictionaryImportController {
|
|||||||
}
|
}
|
||||||
this._setSpinnerVisible(false);
|
this._setSpinnerVisible(false);
|
||||||
this._setModifying(false);
|
this._setModifying(false);
|
||||||
if (storageController !== null) { storageController.updateStats(); }
|
this._triggerStorageChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,4 +339,8 @@ class DictionaryImportController {
|
|||||||
}
|
}
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_triggerStorageChanged() {
|
||||||
|
yomichan.trigger('storageChanged');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
* GenericSettingController
|
* GenericSettingController
|
||||||
* ModalController
|
* ModalController
|
||||||
* PermissionsToggleController
|
* PermissionsToggleController
|
||||||
|
* PersistentStorageController
|
||||||
* PopupPreviewController
|
* PopupPreviewController
|
||||||
* ProfileController
|
* ProfileController
|
||||||
* ScanInputsController
|
* ScanInputsController
|
||||||
@ -63,7 +64,10 @@ async function setupEnvironmentInfo() {
|
|||||||
const settingsController = new SettingsController(optionsFull.profileCurrent);
|
const settingsController = new SettingsController(optionsFull.profileCurrent);
|
||||||
settingsController.prepare();
|
settingsController.prepare();
|
||||||
|
|
||||||
const storageController = new StorageController();
|
const persistentStorageController = new PersistentStorageController();
|
||||||
|
persistentStorageController.prepare();
|
||||||
|
|
||||||
|
const storageController = new StorageController(persistentStorageController);
|
||||||
storageController.prepare();
|
storageController.prepare();
|
||||||
|
|
||||||
const genericSettingController = new GenericSettingController(settingsController);
|
const genericSettingController = new GenericSettingController(settingsController);
|
||||||
@ -81,10 +85,10 @@ async function setupEnvironmentInfo() {
|
|||||||
const profileController = new ProfileController(settingsController, modalController);
|
const profileController = new ProfileController(settingsController, modalController);
|
||||||
profileController.prepare();
|
profileController.prepare();
|
||||||
|
|
||||||
const dictionaryController = new DictionaryController(settingsController, modalController, storageController, null);
|
const dictionaryController = new DictionaryController(settingsController, modalController, null);
|
||||||
dictionaryController.prepare();
|
dictionaryController.prepare();
|
||||||
|
|
||||||
const dictionaryImportController = new DictionaryImportController(settingsController, modalController, storageController, null);
|
const dictionaryImportController = new DictionaryImportController(settingsController, modalController, null);
|
||||||
dictionaryImportController.prepare();
|
dictionaryImportController.prepare();
|
||||||
|
|
||||||
const ankiController = new AnkiController(settingsController);
|
const ankiController = new AnkiController(settingsController);
|
||||||
|
94
ext/js/pages/settings/persistent-storage-controller.js
Normal file
94
ext/js/pages/settings/persistent-storage-controller.js
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Yomichan Authors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class PersistentStorageController {
|
||||||
|
constructor() {
|
||||||
|
this._persistentStorageCheckbox = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async prepare() {
|
||||||
|
this._persistentStorageCheckbox = document.querySelector('#storage-persistent-checkbox');
|
||||||
|
this._persistentStorageCheckbox.addEventListener('change', this._onPersistentStorageCheckboxChange.bind(this), false);
|
||||||
|
|
||||||
|
const button = document.querySelector('#storage-persistent-button');
|
||||||
|
if (button !== null) {
|
||||||
|
button.hidden = false;
|
||||||
|
button.addEventListener('click', this._onPersistStorageButtonClick.bind(this), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this._isPersistentStorageSupported()) { return; }
|
||||||
|
|
||||||
|
const info = document.querySelector('#storage-persistent-info');
|
||||||
|
if (info !== null) { info.hidden = false; }
|
||||||
|
|
||||||
|
const isStoragePeristent = await this.isStoragePeristent();
|
||||||
|
this._updateCheckbox(isStoragePeristent);
|
||||||
|
}
|
||||||
|
|
||||||
|
async isStoragePeristent() {
|
||||||
|
try {
|
||||||
|
return await navigator.storage.persisted();
|
||||||
|
} catch (e) {
|
||||||
|
// NOP
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private
|
||||||
|
|
||||||
|
_onPersistentStorageCheckboxChange(e) {
|
||||||
|
const node = e.currentTarget;
|
||||||
|
if (node.checked) {
|
||||||
|
node.checked = false;
|
||||||
|
this._attemptPersistStorage();
|
||||||
|
} else {
|
||||||
|
node.checked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_onPersistStorageButtonClick() {
|
||||||
|
const {checked} = this._persistentStorageCheckbox;
|
||||||
|
if (checked) { return; }
|
||||||
|
this._persistentStorageCheckbox.checked = !checked;
|
||||||
|
this._persistentStorageCheckbox.dispatchEvent(new Event('change'));
|
||||||
|
}
|
||||||
|
|
||||||
|
async _attemptPersistStorage() {
|
||||||
|
let isStoragePeristent = false;
|
||||||
|
try {
|
||||||
|
isStoragePeristent = await navigator.storage.persist();
|
||||||
|
} catch (e) {
|
||||||
|
// NOP
|
||||||
|
}
|
||||||
|
|
||||||
|
this._updateCheckbox(isStoragePeristent);
|
||||||
|
|
||||||
|
const node = document.querySelector('#storage-persistent-fail-warning');
|
||||||
|
if (node !== null) { node.hidden = isStoragePeristent; }
|
||||||
|
|
||||||
|
yomichan.trigger('storageChanged');
|
||||||
|
}
|
||||||
|
|
||||||
|
_isPersistentStorageSupported() {
|
||||||
|
return isObject(navigator.storage) && typeof navigator.storage.persist === 'function';
|
||||||
|
}
|
||||||
|
|
||||||
|
_updateCheckbox(isStoragePeristent) {
|
||||||
|
this._persistentStorageCheckbox.checked = isStoragePeristent;
|
||||||
|
this._persistentStorageCheckbox.readOnly = isStoragePeristent;
|
||||||
|
}
|
||||||
|
}
|
@ -30,6 +30,7 @@
|
|||||||
* ModalController
|
* ModalController
|
||||||
* NestedPopupsController
|
* NestedPopupsController
|
||||||
* PermissionsToggleController
|
* PermissionsToggleController
|
||||||
|
* PersistentStorageController
|
||||||
* PopupPreviewController
|
* PopupPreviewController
|
||||||
* PopupWindowController
|
* PopupWindowController
|
||||||
* ProfileController
|
* ProfileController
|
||||||
@ -79,13 +80,16 @@ async function setupGenericSettingsController(genericSettingController) {
|
|||||||
const settingsController = new SettingsController(optionsFull.profileCurrent);
|
const settingsController = new SettingsController(optionsFull.profileCurrent);
|
||||||
settingsController.prepare();
|
settingsController.prepare();
|
||||||
|
|
||||||
const storageController = new StorageController();
|
const persistentStorageController = new PersistentStorageController();
|
||||||
|
persistentStorageController.prepare();
|
||||||
|
|
||||||
|
const storageController = new StorageController(persistentStorageController);
|
||||||
storageController.prepare();
|
storageController.prepare();
|
||||||
|
|
||||||
const dictionaryController = new DictionaryController(settingsController, modalController, storageController, statusFooter);
|
const dictionaryController = new DictionaryController(settingsController, modalController, statusFooter);
|
||||||
dictionaryController.prepare();
|
dictionaryController.prepare();
|
||||||
|
|
||||||
const dictionaryImportController = new DictionaryImportController(settingsController, modalController, storageController, statusFooter);
|
const dictionaryImportController = new DictionaryImportController(settingsController, modalController, statusFooter);
|
||||||
dictionaryImportController.prepare();
|
dictionaryImportController.prepare();
|
||||||
|
|
||||||
const genericSettingController = new GenericSettingController(settingsController);
|
const genericSettingController = new GenericSettingController(settingsController);
|
||||||
|
@ -16,11 +16,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class StorageController {
|
class StorageController {
|
||||||
constructor() {
|
constructor(persistentStorageController) {
|
||||||
|
this._persistentStorageController = persistentStorageController;
|
||||||
this._mostRecentStorageEstimate = null;
|
this._mostRecentStorageEstimate = null;
|
||||||
this._storageEstimateFailed = false;
|
this._storageEstimateFailed = false;
|
||||||
this._isUpdating = false;
|
this._isUpdating = false;
|
||||||
this._persistentStorageCheckbox = false;
|
|
||||||
this._storageUsageNode = null;
|
this._storageUsageNode = null;
|
||||||
this._storageQuotaNode = null;
|
this._storageQuotaNode = null;
|
||||||
this._storageUseFiniteNodes = null;
|
this._storageUseFiniteNodes = null;
|
||||||
@ -30,7 +30,6 @@ class StorageController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
prepare() {
|
prepare() {
|
||||||
this._persistentStorageCheckbox = document.querySelector('#storage-persistent-checkbox');
|
|
||||||
this._storageUsageNodes = document.querySelectorAll('.storage-usage');
|
this._storageUsageNodes = document.querySelectorAll('.storage-usage');
|
||||||
this._storageQuotaNodes = document.querySelectorAll('.storage-quota');
|
this._storageQuotaNodes = document.querySelectorAll('.storage-quota');
|
||||||
this._storageUseFiniteNodes = document.querySelectorAll('.storage-use-finite');
|
this._storageUseFiniteNodes = document.querySelectorAll('.storage-use-finite');
|
||||||
@ -38,13 +37,23 @@ class StorageController {
|
|||||||
this._storageUseValidNodes = document.querySelectorAll('.storage-use-valid');
|
this._storageUseValidNodes = document.querySelectorAll('.storage-use-valid');
|
||||||
this._storageUseInvalidNodes = document.querySelectorAll('.storage-use-invalid');
|
this._storageUseInvalidNodes = document.querySelectorAll('.storage-use-invalid');
|
||||||
|
|
||||||
this._preparePersistentStorage();
|
document.querySelector('#storage-refresh').addEventListener('click', this._onStorageRefreshButtonClick.bind(this), false);
|
||||||
this.updateStats();
|
yomichan.on('storageChanged', this._onStorageChanged.bind(this));
|
||||||
this._persistentStorageCheckbox.addEventListener('change', this._onPersistentStorageCheckboxChange.bind(this), false);
|
|
||||||
document.querySelector('#storage-refresh').addEventListener('click', this.updateStats.bind(this), false);
|
this._updateStats();
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateStats() {
|
// Private
|
||||||
|
|
||||||
|
_onStorageRefreshButtonClick() {
|
||||||
|
this._updateStats();
|
||||||
|
}
|
||||||
|
|
||||||
|
_onStorageChanged() {
|
||||||
|
this._updateStats();
|
||||||
|
}
|
||||||
|
|
||||||
|
async _updateStats() {
|
||||||
if (this._isUpdating) { return; }
|
if (this._isUpdating) { return; }
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -54,7 +63,7 @@ class StorageController {
|
|||||||
const valid = (estimate !== null);
|
const valid = (estimate !== null);
|
||||||
|
|
||||||
// Firefox reports usage as 0 when persistent storage is enabled.
|
// Firefox reports usage as 0 when persistent storage is enabled.
|
||||||
const finite = valid && (estimate.usage > 0 || !(await this._isStoragePeristent()));
|
const finite = valid && (estimate.usage > 0 || !(await this._persistentStorageController.isStoragePeristent()));
|
||||||
if (finite) {
|
if (finite) {
|
||||||
for (const node of this._storageUsageNodes) {
|
for (const node of this._storageUsageNodes) {
|
||||||
node.textContent = this._bytesToLabeledString(estimate.usage);
|
node.textContent = this._bytesToLabeledString(estimate.usage);
|
||||||
@ -77,61 +86,6 @@ class StorageController {
|
|||||||
|
|
||||||
// Private
|
// Private
|
||||||
|
|
||||||
async _preparePersistentStorage() {
|
|
||||||
if (!(navigator.storage && navigator.storage.persist)) {
|
|
||||||
// Not supported
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const info = document.querySelector('#storage-persistent-info');
|
|
||||||
if (info !== null) { info.hidden = false; }
|
|
||||||
|
|
||||||
const isStoragePeristent = await this._isStoragePeristent();
|
|
||||||
this._updateCheckbox(isStoragePeristent);
|
|
||||||
|
|
||||||
const button = document.querySelector('#storage-persistent-button');
|
|
||||||
if (button !== null) {
|
|
||||||
button.hidden = false;
|
|
||||||
button.addEventListener('click', this._onPersistStorageButtonClick.bind(this), false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_onPersistentStorageCheckboxChange(e) {
|
|
||||||
const node = e.currentTarget;
|
|
||||||
if (!node.checked) {
|
|
||||||
node.checked = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._attemptPersistStorage();
|
|
||||||
}
|
|
||||||
|
|
||||||
_onPersistStorageButtonClick() {
|
|
||||||
const {checked} = this._persistentStorageCheckbox;
|
|
||||||
if (checked) { return; }
|
|
||||||
this._persistentStorageCheckbox.checked = !checked;
|
|
||||||
this._persistentStorageCheckbox.dispatchEvent(new Event('change'));
|
|
||||||
}
|
|
||||||
|
|
||||||
async _attemptPersistStorage() {
|
|
||||||
if (await this._isStoragePeristent()) { return; }
|
|
||||||
|
|
||||||
let isStoragePeristent = false;
|
|
||||||
try {
|
|
||||||
isStoragePeristent = await navigator.storage.persist();
|
|
||||||
} catch (e) {
|
|
||||||
// NOP
|
|
||||||
}
|
|
||||||
|
|
||||||
this._updateCheckbox(isStoragePeristent);
|
|
||||||
|
|
||||||
if (isStoragePeristent) {
|
|
||||||
this.updateStats();
|
|
||||||
} else {
|
|
||||||
const node = document.querySelector('#storage-persistent-fail-warning');
|
|
||||||
if (node !== null) { node.hidden = false; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async _storageEstimate() {
|
async _storageEstimate() {
|
||||||
if (this._storageEstimateFailed && this._mostRecentStorageEstimate === null) {
|
if (this._storageEstimateFailed && this._mostRecentStorageEstimate === null) {
|
||||||
return null;
|
return null;
|
||||||
@ -159,21 +113,6 @@ class StorageController {
|
|||||||
return `${label}${labels[labelIndex]}`;
|
return `${label}${labels[labelIndex]}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
async _isStoragePeristent() {
|
|
||||||
try {
|
|
||||||
return await navigator.storage.persisted();
|
|
||||||
} catch (e) {
|
|
||||||
// NOP
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_updateCheckbox(isStoragePeristent) {
|
|
||||||
const checkbox = this._persistentStorageCheckbox;
|
|
||||||
checkbox.checked = isStoragePeristent;
|
|
||||||
checkbox.readOnly = isStoragePeristent;
|
|
||||||
}
|
|
||||||
|
|
||||||
_setElementsVisible(elements, visible) {
|
_setElementsVisible(elements, visible) {
|
||||||
visible = !visible;
|
visible = !visible;
|
||||||
for (const element of elements) {
|
for (const element of elements) {
|
||||||
|
@ -62,10 +62,10 @@ async function setupGenericSettingsController(genericSettingController) {
|
|||||||
const settingsController = new SettingsController(optionsFull.profileCurrent);
|
const settingsController = new SettingsController(optionsFull.profileCurrent);
|
||||||
settingsController.prepare();
|
settingsController.prepare();
|
||||||
|
|
||||||
const dictionaryController = new DictionaryController(settingsController, modalController, null, statusFooter);
|
const dictionaryController = new DictionaryController(settingsController, modalController, statusFooter);
|
||||||
dictionaryController.prepare();
|
dictionaryController.prepare();
|
||||||
|
|
||||||
const dictionaryImportController = new DictionaryImportController(settingsController, modalController, null, statusFooter);
|
const dictionaryImportController = new DictionaryImportController(settingsController, modalController, statusFooter);
|
||||||
dictionaryImportController.prepare();
|
dictionaryImportController.prepare();
|
||||||
|
|
||||||
const genericSettingController = new GenericSettingController(settingsController);
|
const genericSettingController = new GenericSettingController(settingsController);
|
||||||
|
@ -1319,6 +1319,7 @@
|
|||||||
<script src="/js/pages/settings/modal-controller.js"></script>
|
<script src="/js/pages/settings/modal-controller.js"></script>
|
||||||
<script src="/js/pages/settings/modal-jquery.js"></script>
|
<script src="/js/pages/settings/modal-jquery.js"></script>
|
||||||
<script src="/js/pages/settings/permissions-toggle-controller.js"></script>
|
<script src="/js/pages/settings/permissions-toggle-controller.js"></script>
|
||||||
|
<script src="/js/pages/settings/persistent-storage-controller.js"></script>
|
||||||
<script src="/js/pages/settings/popup-preview-controller.js"></script>
|
<script src="/js/pages/settings/popup-preview-controller.js"></script>
|
||||||
<script src="/js/pages/settings/profile-conditions-ui.js"></script>
|
<script src="/js/pages/settings/profile-conditions-ui.js"></script>
|
||||||
<script src="/js/pages/settings/profile-controller.js"></script>
|
<script src="/js/pages/settings/profile-controller.js"></script>
|
||||||
|
@ -3270,6 +3270,7 @@
|
|||||||
<script src="/js/pages/settings/modal-controller.js"></script>
|
<script src="/js/pages/settings/modal-controller.js"></script>
|
||||||
<script src="/js/pages/settings/nested-popups-controller.js"></script>
|
<script src="/js/pages/settings/nested-popups-controller.js"></script>
|
||||||
<script src="/js/pages/settings/permissions-toggle-controller.js"></script>
|
<script src="/js/pages/settings/permissions-toggle-controller.js"></script>
|
||||||
|
<script src="/js/pages/settings/persistent-storage-controller.js"></script>
|
||||||
<script src="/js/pages/settings/popup-preview-controller.js"></script>
|
<script src="/js/pages/settings/popup-preview-controller.js"></script>
|
||||||
<script src="/js/pages/settings/popup-window-controller.js"></script>
|
<script src="/js/pages/settings/popup-window-controller.js"></script>
|
||||||
<script src="/js/pages/settings/profile-conditions-ui.js"></script>
|
<script src="/js/pages/settings/profile-conditions-ui.js"></script>
|
||||||
|
Loading…
Reference in New Issue
Block a user