1use dom_struct::dom_struct;
6use js::context::JSContext;
7use js::rust::HandleObject;
8use script_bindings::cell::DomRefCell;
9use script_bindings::domstring::TracedDOMString;
10use script_bindings::reflector::reflect_dom_object_with_proto;
11use stylo_atoms::Atom;
12
13use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
14use crate::dom::bindings::codegen::Bindings::StorageEventBinding;
15use crate::dom::bindings::codegen::Bindings::StorageEventBinding::StorageEventMethods;
16use crate::dom::bindings::error::Fallible;
17use crate::dom::bindings::inheritance::Castable;
18use crate::dom::bindings::root::{DomRoot, MutNullableDom};
19use crate::dom::bindings::str::{DOMString, USVString};
20use crate::dom::event::{Event, EventBubbles, EventCancelable};
21use crate::dom::storage::Storage;
22use crate::dom::window::Window;
23
24#[dom_struct]
25pub(crate) struct StorageEvent {
26 event: Event,
27 key: DomRefCell<Option<TracedDOMString>>,
28 old_value: DomRefCell<Option<TracedDOMString>>,
29 new_value: DomRefCell<Option<TracedDOMString>>,
30 url: DomRefCell<TracedDOMString>,
31 storage_area: MutNullableDom<Storage>,
32}
33
34#[expect(non_snake_case)]
35impl StorageEvent {
36 pub(crate) fn new_inherited(
37 key: Option<DOMString>,
38 old_value: Option<DOMString>,
39 new_value: Option<DOMString>,
40 url: DOMString,
41 storage_area: Option<&Storage>,
42 ) -> StorageEvent {
43 StorageEvent {
44 event: Event::new_inherited(),
45 key: DomRefCell::new(key.map(|domstring| domstring.traced())),
46 old_value: DomRefCell::new(old_value.map(|domstring| domstring.traced())),
47 new_value: DomRefCell::new(new_value.map(|domstring| domstring.traced())),
48 url: DomRefCell::new(url.traced()),
49 storage_area: MutNullableDom::new(storage_area),
50 }
51 }
52
53 pub(crate) fn new_uninitialized(
54 cx: &mut JSContext,
55 window: &Window,
56 url: DOMString,
57 ) -> DomRoot<StorageEvent> {
58 Self::new_uninitialized_with_proto(cx, window, None, url)
59 }
60
61 fn new_uninitialized_with_proto(
62 cx: &mut JSContext,
63 window: &Window,
64 proto: Option<HandleObject>,
65 url: DOMString,
66 ) -> DomRoot<StorageEvent> {
67 reflect_dom_object_with_proto(
68 cx,
69 Box::new(StorageEvent::new_inherited(None, None, None, url, None)),
70 window,
71 proto,
72 )
73 }
74
75 #[expect(clippy::too_many_arguments)]
76 pub(crate) fn new(
77 cx: &mut JSContext,
78 global: &Window,
79 type_: Atom,
80 bubbles: EventBubbles,
81 cancelable: EventCancelable,
82 key: Option<DOMString>,
83 oldValue: Option<DOMString>,
84 newValue: Option<DOMString>,
85 url: DOMString,
86 storageArea: Option<&Storage>,
87 ) -> DomRoot<StorageEvent> {
88 Self::new_with_proto(
89 cx,
90 global,
91 None,
92 type_,
93 bubbles,
94 cancelable,
95 key,
96 oldValue,
97 newValue,
98 url,
99 storageArea,
100 )
101 }
102
103 #[expect(clippy::too_many_arguments)]
104 fn new_with_proto(
105 cx: &mut JSContext,
106 global: &Window,
107 proto: Option<HandleObject>,
108 type_: Atom,
109 bubbles: EventBubbles,
110 cancelable: EventCancelable,
111 key: Option<DOMString>,
112 oldValue: Option<DOMString>,
113 newValue: Option<DOMString>,
114 url: DOMString,
115 storageArea: Option<&Storage>,
116 ) -> DomRoot<StorageEvent> {
117 let ev = reflect_dom_object_with_proto(
118 cx,
119 Box::new(StorageEvent::new_inherited(
120 key,
121 oldValue,
122 newValue,
123 url,
124 storageArea,
125 )),
126 global,
127 proto,
128 );
129 {
130 let event = ev.upcast::<Event>();
131 event.init_event(type_, bool::from(bubbles), bool::from(cancelable));
132 }
133 ev
134 }
135}
136
137#[expect(non_snake_case)]
138impl StorageEventMethods<crate::DomTypeHolder> for StorageEvent {
139 fn Constructor(
141 cx: &mut JSContext,
142 global: &Window,
143 proto: Option<HandleObject>,
144 type_: DOMString,
145 init: &StorageEventBinding::StorageEventInit,
146 ) -> Fallible<DomRoot<StorageEvent>> {
147 let key = init.key.clone();
148 let oldValue = init.oldValue.clone();
149 let newValue = init.newValue.clone();
150 let url = init.url.clone();
151 let storageArea = init.storageArea.as_deref();
152 let bubbles = EventBubbles::from(init.parent.bubbles);
153 let cancelable = EventCancelable::from(init.parent.cancelable);
154 let event = StorageEvent::new_with_proto(
155 cx,
156 global,
157 proto,
158 Atom::from(type_),
159 bubbles,
160 cancelable,
161 key,
162 oldValue,
163 newValue,
164 url,
165 storageArea,
166 );
167 Ok(event)
168 }
169
170 fn GetKey(&self) -> Option<DOMString> {
172 self.key.borrow().clone().map(|domstring| domstring.root())
173 }
174
175 fn GetOldValue(&self) -> Option<DOMString> {
177 self.old_value
178 .borrow()
179 .clone()
180 .map(|domstring| domstring.root())
181 }
182
183 fn GetNewValue(&self) -> Option<DOMString> {
185 self.new_value
186 .borrow()
187 .clone()
188 .map(|domstring| domstring.root())
189 }
190
191 fn Url(&self) -> DOMString {
193 self.url.borrow().clone().root()
194 }
195
196 fn GetStorageArea(&self) -> Option<DomRoot<Storage>> {
198 self.storage_area.get()
199 }
200
201 fn IsTrusted(&self) -> bool {
203 self.event.IsTrusted()
204 }
205
206 fn InitStorageEvent(
208 &self,
209 type_: DOMString,
210 bubbles: bool,
211 cancelable: bool,
212 key: Option<DOMString>,
213 oldValue: Option<DOMString>,
214 newValue: Option<DOMString>,
215 url: USVString,
216 storageArea: Option<&Storage>,
217 ) {
218 self.event
219 .init_event(Atom::from(type_), bubbles, cancelable);
220 *self.key.borrow_mut() = key.map(|domstring| domstring.traced());
221 *self.old_value.borrow_mut() = oldValue.map(|domstring| domstring.traced());
222 *self.new_value.borrow_mut() = newValue.map(|domstring| domstring.traced());
223 let url: DOMString = url.into();
224 *self.url.borrow_mut() = url.traced();
225 self.storage_area.set(storageArea);
226 }
227}