jsdom
Version:
A JavaScript implementation of many web standards
103 lines (83 loc) • 2.66 kB
JavaScript
"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
};