"use strict";
const DOMException = require("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(args, { associatedWindow, storageArea, url, type, storageQuota }) {
this._associatedWindow = associatedWindow;
this._items = storageArea;
this._url = url;
this._type = type;
this._quota = storageQuota;
}
_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 new DOMException(`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
};