script/dom/
urlsearchparams.rs1use dom_struct::dom_struct;
6use js::rust::HandleObject;
7use url::form_urlencoded;
8
9use crate::dom::bindings::cell::DomRefCell;
10use crate::dom::bindings::codegen::Bindings::URLSearchParamsBinding::URLSearchParamsMethods;
11use crate::dom::bindings::codegen::UnionTypes::USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString;
12use crate::dom::bindings::error::{Error, Fallible};
13use crate::dom::bindings::iterable::Iterable;
14use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto};
15use crate::dom::bindings::root::DomRoot;
16use crate::dom::bindings::str::{DOMString, USVString};
17use crate::dom::bindings::weakref::MutableWeakRef;
18use crate::dom::globalscope::GlobalScope;
19use crate::dom::url::URL;
20use crate::script_runtime::CanGc;
21
22#[dom_struct]
24pub(crate) struct URLSearchParams {
25 reflector_: Reflector,
26 list: DomRefCell<Vec<(String, String)>>,
28 url: MutableWeakRef<URL>,
30}
31
32impl URLSearchParams {
33 fn new_inherited(url: Option<&URL>) -> URLSearchParams {
34 URLSearchParams {
35 reflector_: Reflector::new(),
36 list: DomRefCell::new(url.map_or(Vec::new(), |url| url.query_pairs())),
37 url: MutableWeakRef::new(url),
38 }
39 }
40
41 pub(crate) fn new(
42 global: &GlobalScope,
43 url: Option<&URL>,
44 can_gc: CanGc,
45 ) -> DomRoot<URLSearchParams> {
46 Self::new_with_proto(global, None, url, can_gc)
47 }
48
49 pub(crate) fn new_with_proto(
50 global: &GlobalScope,
51 proto: Option<HandleObject>,
52 url: Option<&URL>,
53 can_gc: CanGc,
54 ) -> DomRoot<URLSearchParams> {
55 reflect_dom_object_with_proto(
56 Box::new(URLSearchParams::new_inherited(url)),
57 global,
58 proto,
59 can_gc,
60 )
61 }
62
63 pub(crate) fn set_list(&self, list: Vec<(String, String)>) {
64 *self.list.borrow_mut() = list;
65 }
66}
67
68impl URLSearchParamsMethods<crate::DomTypeHolder> for URLSearchParams {
69 fn Constructor(
71 global: &GlobalScope,
72 proto: Option<HandleObject>,
73 can_gc: CanGc,
74 init: USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString,
75 ) -> Fallible<DomRoot<URLSearchParams>> {
76 let query = URLSearchParams::new_with_proto(global, proto, None, can_gc);
78 match init {
79 USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString::USVStringSequenceSequence(init) => {
80 if init.iter().any(|pair| pair.len() != 2) {
84 return Err(Error::Type("Sequence initializer must only contain pair elements.".to_string()));
85 }
86
87 *query.list.borrow_mut() =
89 init.iter().map(|pair| (pair[0].to_string(), pair[1].to_string())).collect::<Vec<_>>();
90 },
91 USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString::USVStringUSVStringRecord(init) => {
92 *query.list.borrow_mut() =
94 (*init).iter().map(|(name, value)| (name.to_string(), value.to_string())).collect::<Vec<_>>();
95 },
96 USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString::USVString(init) => {
97 let init_bytes = match init.0.chars().next() {
99 Some('?') => {
100 let (_, other_bytes) = init.0.as_bytes().split_at(1);
101
102 other_bytes
103 },
104 _ => init.0.as_bytes(),
105 };
106
107 *query.list.borrow_mut() =
108 form_urlencoded::parse(init_bytes).into_owned().collect();
109 }
110 }
111
112 Ok(query)
114 }
115
116 fn Size(&self) -> u32 {
118 self.list.borrow().len() as u32
119 }
120
121 fn Append(&self, name: USVString, value: USVString) {
123 self.list.borrow_mut().push((name.0, value.0));
125 self.update_steps();
127 }
128
129 fn Delete(&self, name: USVString, value: Option<USVString>) {
131 self.list.borrow_mut().retain(|(k, v)| match &value {
133 Some(value) => !(k == &name.0 && v == &value.0),
134 None => k != &name.0,
135 });
136 self.update_steps();
138 }
139
140 fn Get(&self, name: USVString) -> Option<USVString> {
142 let list = self.list.borrow();
143 list.iter()
144 .find(|&kv| kv.0 == name.0)
145 .map(|kv| USVString(kv.1.clone()))
146 }
147
148 fn GetAll(&self, name: USVString) -> Vec<USVString> {
150 let list = self.list.borrow();
151 list.iter()
152 .filter_map(|(k, v)| {
153 if k == &name.0 {
154 Some(USVString(v.clone()))
155 } else {
156 None
157 }
158 })
159 .collect()
160 }
161
162 fn Has(&self, name: USVString, value: Option<USVString>) -> bool {
164 let list = self.list.borrow();
165 list.iter().any(|(k, v)| match &value {
166 Some(value) => k == &name.0 && v == &value.0,
167 None => k == &name.0,
168 })
169 }
170
171 fn Set(&self, name: USVString, value: USVString) {
173 {
174 let mut list = self.list.borrow_mut();
176 let mut index = None;
177 let mut i = 0;
178 list.retain(|(k, _)| {
179 if index.is_none() {
180 if k == &name.0 {
181 index = Some(i);
182 } else {
183 i += 1;
184 }
185 true
186 } else {
187 k != &name.0
188 }
189 });
190 match index {
191 Some(index) => list[index].1 = value.0,
192 None => list.push((name.0, value.0)), };
194 } self.update_steps();
197 }
198
199 fn Sort(&self) {
201 self.list
203 .borrow_mut()
204 .sort_by(|(a, _), (b, _)| a.encode_utf16().cmp(b.encode_utf16()));
205
206 self.update_steps();
208 }
209
210 fn Stringifier(&self) -> DOMString {
212 DOMString::from(self.serialize_utf8())
213 }
214}
215
216impl URLSearchParams {
217 pub(crate) fn serialize_utf8(&self) -> String {
219 let list = self.list.borrow();
220 form_urlencoded::Serializer::new(String::new())
221 .extend_pairs(&*list)
222 .finish()
223 }
224
225 fn update_steps(&self) {
227 if let Some(url) = self.url.root() {
228 url.set_query_pairs(&self.list.borrow())
229 }
230 }
231}
232
233impl Iterable for URLSearchParams {
234 type Key = USVString;
235 type Value = USVString;
236
237 fn get_iterable_length(&self) -> u32 {
238 self.list.borrow().len() as u32
239 }
240
241 fn get_value_at_index(&self, n: u32) -> USVString {
242 let value = self.list.borrow()[n as usize].1.clone();
243 USVString(value)
244 }
245
246 fn get_key_at_index(&self, n: u32) -> USVString {
247 let key = self.list.borrow()[n as usize].0.clone();
248 USVString(key)
249 }
250}