Tims-Chat/files_wcf/js/Bastelstu.be/Chat/LocalStorage.js

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

219 lines
5.1 KiB
JavaScript
Raw Normal View History

2018-08-16 22:30:59 +00:00
/*
2021-02-04 22:04:35 +00:00
* Copyright (c) 2010-2021 Tim Düsterhus.
2018-08-16 22:30:59 +00:00
*
* Use of this software is governed by the Business Source License
* included in the LICENSE file.
*
2022-03-04 20:21:52 +00:00
* Change Date: 2026-03-04
2018-08-16 22:30:59 +00:00
*
* On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2
* or later of the General Public License.
*/
define(['WoltLabSuite/Core/Core', './LocalStorageEmulator'], function (
Core,
LocalStorageEmulator
) {
'use strict'
const DEPENDENCIES = []
class LocalStorage {
constructor(subprefix) {
this.subprefix = subprefix
this.hasLocalStorage = false
this.setupStorage()
}
static isQuotaExceeded(error) {
return (
error instanceof DOMException &&
// everything except Firefox
(error.code === 22 ||
// Firefox
error.code === 1014 ||
// everything except Firefox
error.name === 'QuotaExceededError' ||
// Firefox
error.name === 'NS_ERROR_DOM_QUOTA_REACHED')
2020-11-01 16:41:19 +00:00
)
2018-08-16 22:30:59 +00:00
}
static isAvailable() {
try {
const x = '__storage_test__'
window.localStorage.setItem(x, x)
window.localStorage.removeItem(x)
return true
} catch (error) {
return LocalStorage.isQuotaExceeded(error)
}
}
setupStorage() {
if (LocalStorage.isAvailable()) {
this.storage = window.localStorage
this.hasLocalStorage = true
} else {
console.info('Falling back to in-memory local storage emulation')
this.storage = new LocalStorageEmulator()
}
}
/**
* Return the prefix to use for the local storage
*
* @returns {string} The storage prefix
*/
get storagePrefix() {
let prefix = ''
// WSC 3.1
if (typeof Core.getStoragePrefix === 'function') {
prefix = Core.getStoragePrefix()
}
return `${prefix}be.bastelstu.Chat.${this.subprefix}`
}
/**
* Calls listener, whenever key changes.
*
* @param {string} key The key to observe.
* @param {*} listener The listener to call.
*/
observe(key, listener) {
window.addEventListener('storage', (event) => {
if (event.storageArea !== window.localStorage) return
if (event.key !== `${this.storagePrefix}${key}`) return
listener(event)
})
}
/**
* Sets the value of a setting
*
* @param {string} key The key of the setting to set
* @param {string} value The new value of the setting
* @returns {string}
*/
set(key, value) {
try {
this.storage.setItem(
`${this.storagePrefix}${key}`,
JSON.stringify(value)
2020-11-01 16:41:19 +00:00
)
2018-08-16 22:30:59 +00:00
} catch (error) {
if (!LocalStorage.isQuotaExceeded(error)) throw error
console.warn(
`Your localStorage has exceeded the size quota for this domain`
)
console.warn(
`We are falling back to an in-memory storage, this does not persist data!`
)
console.error(error)
const storage = new LocalStorageEmulator()
// Make a copy of the current localStorage
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i)
const value = localStorage.getItem(key)
storage.setItem(key, value)
}
// Replace the localStorage with our in-memory variant
this.storage = storage
}
return this.get(key)
}
/**
* Retrieves the value of a setting
*
* @param {string} key The key of the setting to retrieve
* @returns {string} The current value of the setting
*/
get(key) {
const value = this.storage.getItem(`${this.storagePrefix}${key}`)
if (value == null) return null
return JSON.parse(value)
}
/**
* Returns whether the given setting has a value.
*
* @param {string} key The key of the setting to check
* @returns {boolean}
*/
has(key) {
return this.storage.getItem(`${this.storagePrefix}${key}`) != null
}
/**
* Removes a single setting
*
* @param {string} key The key of the setting to remove
* @returns {string} The last value of the provided setting
*/
remove(key) {
const value = this.get(key)
const storageKey = `${this.storagePrefix}${key}`
this.storage.removeItem(storageKey)
return value
}
/**
* Removes all of the chat settings with the right prefix
* and try to use the real localStorage again, if the qouta isnt exceeded anymore
*/
clear() {
const _clear = (target) => {
for (let key in target) {
if (
!key.startsWith(this.storagePrefix) ||
!target.hasOwnProperty(key)
2020-11-01 16:41:19 +00:00
)
2018-08-16 22:30:59 +00:00
continue
target.removeItem(key)
}
}
if (
this.hasLocalStorage &&
this.storage instanceof LocalStorageEmulator
) {
try {
// Try to clear the real localStorage
_clear(localStorage)
// Check if we can use the localStorage again
const x = '__storage_test__'
window.localStorage.setItem(x, x)
window.localStorage.removeItem(x)
// It should be safe to use the localStorage again, as the storage
// of this instance (given by the prefix) has been cleared completely
this.storage = localStorage
console.log('Switched back to using the localStorage')
} catch (error) {
/* no we cant */
}
}
_clear(this.storage)
}
}
LocalStorage.DEPENDENCIES = DEPENDENCIES
return LocalStorage
})