"use strict"; const DOMException = require("../generated/DOMException"); const StorageEvent = require("../generated/StorageEvent"); const idlUtils = require("../generated/utils"); const { fireAnEvent } = require("../helpers/events"); // https://html.spec.whatwg.org/multipage/webstorage.html#the-storage-interface class StorageImpl { constructor(globalObject, args, privateData) { const { associatedWindow, storageArea, url, type, storageQuota } = privateData; this._associatedWindow = associatedWindow; this._items = storageArea; this._url = url; this._type = type; this._quota = storageQuota; this._globalObject = globalObject; } _dispatchStorageEvent(key, oldValue, newValue) { return this._associatedWindow._currentOriginData.windowsInSameOrigin .filter(target => target !== this._associatedWindow) .forEach(target => fireAnEvent("storage", target, StorageEvent, { key, oldValue, newValue, url: this._url, storageArea: target["_" + this._type] })); } get length() { return this._items.size; } key(n) { if (n >= this._items.size) { return null; } return [...this._items.keys()][n]; } getItem(key) { if (this._items.has(key)) { return this._items.get(key); } return null; } setItem(key, value) { const oldValue = this._items.get(key) || null; if (oldValue === value) { return; } // Concatenate all keys and values to measure their length against the quota let itemsTotalLength = key.length + value.length; for (const [curKey, curValue] of this._items) { // If the key already exists, skip it as it will be set to the new value instead if (key !== curKey) { itemsTotalLength += curKey.length + curValue.length; } } if (itemsTotalLength > this._quota) { throw DOMException.create(this._globalObject, [ `The ${this._quota}-code unit storage quota has been exceeded.`, "QuotaExceededError" ]); } setTimeout(this._dispatchStorageEvent.bind(this), 0, key, oldValue, value); this._items.set(key, value); } removeItem(key) { if (this._items.has(key)) { setTimeout(this._dispatchStorageEvent.bind(this), 0, key, this._items.get(key), null); this._items.delete(key); } } clear() { if (this._items.size > 0) { setTimeout(this._dispatchStorageEvent.bind(this), 0, null, null, null); this._items.clear(); } } get [idlUtils.supportedPropertyNames]() { return this._items.keys(); } } module.exports = { implementation: StorageImpl };