Serenity Operating System
at master 190 lines 5.5 kB view raw
1/* 2 * Copyright (c) 2022, Andreas Kling <kling@serenityos.org> 3 * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org> 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include <AK/DeprecatedString.h> 9#include <LibWeb/Bindings/Intrinsics.h> 10#include <LibWeb/HTML/Storage.h> 11 12namespace Web::HTML { 13 14WebIDL::ExceptionOr<JS::NonnullGCPtr<Storage>> Storage::create(JS::Realm& realm) 15{ 16 return MUST_OR_THROW_OOM(realm.heap().allocate<Storage>(realm, realm)); 17} 18 19Storage::Storage(JS::Realm& realm) 20 : Bindings::LegacyPlatformObject(realm) 21{ 22} 23 24Storage::~Storage() = default; 25 26JS::ThrowCompletionOr<void> Storage::initialize(JS::Realm& realm) 27{ 28 MUST_OR_THROW_OOM(Base::initialize(realm)); 29 set_prototype(&Bindings::ensure_web_prototype<Bindings::StoragePrototype>(realm, "Storage")); 30 31 return {}; 32} 33 34// https://html.spec.whatwg.org/multipage/webstorage.html#dom-storage-length 35size_t Storage::length() const 36{ 37 // The length getter steps are to return this's map's size. 38 return m_map.size(); 39} 40 41// https://html.spec.whatwg.org/multipage/webstorage.html#dom-storage-key 42DeprecatedString Storage::key(size_t index) 43{ 44 // 1. If index is greater than or equal to this's map's size, then return null. 45 if (index >= m_map.size()) 46 return {}; 47 48 // 2. Let keys be the result of running get the keys on this's map. 49 auto keys = m_map.keys(); 50 51 // 3. Return keys[index]. 52 return keys[index]; 53} 54 55// https://html.spec.whatwg.org/multipage/webstorage.html#dom-storage-getitem 56DeprecatedString Storage::get_item(DeprecatedString const& key) const 57{ 58 // 1. If this's map[key] does not exist, then return null. 59 auto it = m_map.find(key); 60 if (it == m_map.end()) 61 return {}; 62 63 // 2. Return this's map[key]. 64 return it->value; 65} 66 67// https://html.spec.whatwg.org/multipage/webstorage.html#dom-storage-setitem 68WebIDL::ExceptionOr<void> Storage::set_item(DeprecatedString const& key, DeprecatedString const& value) 69{ 70 // 1. Let oldValue be null. 71 DeprecatedString old_value; 72 73 // 2. Let reorder be true. 74 bool reorder = true; 75 76 // 3. If this's map[key] exists: 77 if (auto it = m_map.find(key); it != m_map.end()) { 78 // 1. Set oldValue to this's map[key]. 79 old_value = it->value; 80 81 // 2. If oldValue is value, then return. 82 if (old_value == value) 83 return {}; 84 85 // 3. Set reorder to false. 86 reorder = false; 87 } 88 89 // FIXME: 4. If value cannot be stored, then throw a "QuotaExceededError" DOMException exception. 90 91 // 5. Set this's map[key] to value. 92 m_map.set(key, value); 93 94 // 6. If reorder is true, then reorder this. 95 if (reorder) 96 this->reorder(); 97 98 // 7. Broadcast this with key, oldValue, and value. 99 broadcast(key, old_value, value); 100 101 return {}; 102} 103 104// https://html.spec.whatwg.org/multipage/webstorage.html#dom-storage-removeitem 105void Storage::remove_item(DeprecatedString const& key) 106{ 107 // 1. If this's map[key] does not exist, then return null. 108 // FIXME: Return null? 109 auto it = m_map.find(key); 110 if (it == m_map.end()) 111 return; 112 113 // 2. Set oldValue to this's map[key]. 114 auto old_value = it->value; 115 116 // 3. Remove this's map[key]. 117 m_map.remove(it); 118 119 // 4. Reorder this. 120 reorder(); 121 122 // 5. Broadcast this with key, oldValue, and null. 123 broadcast(key, old_value, {}); 124} 125 126// https://html.spec.whatwg.org/multipage/webstorage.html#dom-storage-clear 127void Storage::clear() 128{ 129 // 1. Clear this's map. 130 m_map.clear(); 131 132 // 2. Broadcast this with null, null, and null. 133 broadcast({}, {}, {}); 134} 135 136// https://html.spec.whatwg.org/multipage/webstorage.html#concept-storage-reorder 137void Storage::reorder() 138{ 139 // To reorder a Storage object storage, reorder storage's map's entries in an implementation-defined manner. 140 // NOTE: This basically means that we're not required to maintain any particular iteration order. 141} 142 143// https://html.spec.whatwg.org/multipage/webstorage.html#concept-storage-broadcast 144void Storage::broadcast(DeprecatedString const& key, DeprecatedString const& old_value, DeprecatedString const& new_value) 145{ 146 (void)key; 147 (void)old_value; 148 (void)new_value; 149 // FIXME: Implement. 150} 151 152Vector<DeprecatedString> Storage::supported_property_names() const 153{ 154 // The supported property names on a Storage object storage are the result of running get the keys on storage's map. 155 return m_map.keys(); 156} 157 158WebIDL::ExceptionOr<JS::Value> Storage::named_item_value(DeprecatedFlyString const& name) const 159{ 160 auto value = get_item(name); 161 if (value.is_null()) 162 return JS::js_null(); 163 return JS::PrimitiveString::create(vm(), value); 164} 165 166WebIDL::ExceptionOr<Bindings::LegacyPlatformObject::DidDeletionFail> Storage::delete_value(DeprecatedString const& name) 167{ 168 remove_item(name); 169 return DidDeletionFail::NotRelevant; 170} 171 172WebIDL::ExceptionOr<void> Storage::set_value_of_named_property(DeprecatedString const& key, JS::Value unconverted_value) 173{ 174 // NOTE: Since LegacyPlatformObject does not know the type of value, we must convert it ourselves. 175 // The type of `value` is `DOMString`. 176 auto value = TRY(unconverted_value.to_deprecated_string(vm())); 177 return set_item(key, value); 178} 179 180void Storage::dump() const 181{ 182 dbgln("Storage ({} key(s))", m_map.size()); 183 size_t i = 0; 184 for (auto const& it : m_map) { 185 dbgln("[{}] \"{}\": \"{}\"", i, it.key, it.value); 186 ++i; 187 } 188} 189 190}