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

219 lines
5.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2010-2018 Tim Düsterhus.
*
* Use of this software is governed by the Business Source License
* included in the LICENSE file.
*
* Change Date: 2024-11-01
*
* 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')
)
}
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)
)
} 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)
)
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
})