1use std::convert::TryFrom;
2use std::fmt;
3
4use delegate::delegate;
5use wasm_bindgen::JsCast;
6
7use crate::attribute::Attribute;
8use crate::console::{Write, Writer};
9use crate::error::SyntaxError;
10use crate::{
11 GenericNode, InvalidCast, InvalidPointerId, Node, PointerId, QuerySelectorAll, ScrollByOptions,
12 ScrollIntoViewOptions, ScrollToOptions,
13};
14
15pub trait Element: AsRef<web_sys::Element> {
16 fn matches(&self, selector: &str) -> Result<bool, SyntaxError> {
28 self.as_ref()
29 .matches(selector)
30 .map_err(|err| SyntaxError::new(err.unchecked_into()))
31 }
32
33 fn query_selector_first(&self, selector: &str) -> Result<Option<GenericElement>, SyntaxError> {
34 self.as_ref()
35 .query_selector(selector)
36 .map(|ok| ok.map(|e| e.into()))
37 .map_err(|err| SyntaxError::new(err.unchecked_into()))
38 }
39
40 fn query_selector_all(&self, selector: &str) -> Result<QuerySelectorAll, SyntaxError> {
41 self.as_ref()
42 .query_selector_all(selector)
43 .map(|inner| QuerySelectorAll::new(inner))
44 .map_err(|err| SyntaxError::new(err.unchecked_into()))
45 }
46
47 fn closest(&self, selector: &str) -> Result<Option<GenericElement>, SyntaxError> {
82 self.as_ref()
83 .closest(selector)
84 .map(|ok| ok.map(|e| e.into()))
85 .map_err(|err| SyntaxError::new(err.unchecked_into()))
86 }
87
88 fn set_pointer_capture(&self, pointer_id: PointerId) -> Result<(), InvalidPointerId> {
89 self.as_ref()
90 .set_pointer_capture(pointer_id.into())
91 .map_err(|_| InvalidPointerId(pointer_id))
92 }
93
94 fn has_pointer_capture(&self, pointer_id: PointerId) -> bool {
95 self.as_ref().has_pointer_capture(pointer_id.into())
96 }
97
98 fn release_pointer_capture(&self, pointer_id: PointerId) -> Result<(), InvalidPointerId> {
99 self.as_ref()
100 .release_pointer_capture(pointer_id.into())
101 .map_err(|_| InvalidPointerId(pointer_id))
102 }
103
104 fn bounding_client_rect(&self) -> ClientRect {
105 ClientRect {
106 inner: self.as_ref().get_bounding_client_rect(),
107 }
108 }
109
110 fn client_rects(&self) -> ClientRects {
111 ClientRects {
112 inner: self.as_ref().get_client_rects(),
113 }
114 }
115
116 fn attributes(&self) -> Attributes {
117 Attributes {
118 element: self.as_ref(),
119 attributes: self.as_ref().attributes(),
120 }
121 }
122
123 fn classes(&self) -> Classes {
124 Classes {
125 element: &self.as_ref(),
126 class_list: self.as_ref().class_list(),
127 }
128 }
129
130 fn set_classes(&self, classes: &str) {
131 self.as_ref().set_class_name(classes);
132 }
133
134 fn disconnect(&self) {
135 self.as_ref().remove();
136 }
137
138 fn previous_sibling_element(&self) -> Option<GenericElement> {
139 self.as_ref().previous_element_sibling().map(|e| e.into())
140 }
141
142 fn next_sibling_element(&self) -> Option<GenericElement> {
143 self.as_ref().next_element_sibling().map(|e| e.into())
144 }
145
146 fn child_elements(&self) -> ChildElements {
147 ChildElements {
148 parent: self.as_ref(),
149 children: self.as_ref().children(),
150 }
151 }
152
153 fn tag_name(&self) -> String {
154 self.as_ref().tag_name()
155 }
156
157 fn namespace_uri(&self) -> Option<String> {
158 self.as_ref().namespace_uri()
159 }
160
161 fn local_name(&self) -> String {
162 self.as_ref().local_name()
163 }
164
165 fn prefix(&self) -> Option<String> {
166 self.as_ref().prefix()
167 }
168
169 fn client_width(&self) -> i32 {
170 self.as_ref().client_width()
171 }
172
173 fn client_height(&self) -> i32 {
174 self.as_ref().client_height()
175 }
176
177 fn client_top(&self) -> i32 {
178 self.as_ref().client_top()
179 }
180
181 fn client_left(&self) -> i32 {
182 self.as_ref().client_left()
183 }
184
185 fn id(&self) -> String {
186 self.as_ref().id()
187 }
188
189 fn set_id(&self, id: &str) {
190 self.as_ref().set_id(id);
191 }
192
193 fn slot(&self) -> String {
194 self.as_ref().slot()
195 }
196
197 fn set_slot(&self, slot: &str) {
198 self.as_ref().set_slot(slot);
199 }
200
201 fn inner_html(&self) -> String {
202 self.as_ref().inner_html()
203 }
204
205 fn set_inner_html(&self, html: &str) {
206 self.as_ref().set_inner_html(html);
207 }
208
209 fn outer_html(&self) -> String {
210 self.as_ref().outer_html()
211 }
212
213 fn set_outer_html(&self, html: &str) {
214 self.as_ref().set_outer_html(html);
215 }
216
217 fn replace_with<T>(&self, replacement: &T)
218 where
219 T: ElementReplacement,
220 Self: Sized,
221 {
222 replacement.replace(self);
223 }
224
225 fn scroll_left(&self) -> i32 {
226 self.as_ref().scroll_left()
227 }
228
229 fn scroll_top(&self) -> i32 {
230 self.as_ref().scroll_top()
231 }
232
233 fn scroll_width(&self) -> i32 {
234 self.as_ref().scroll_width()
235 }
236
237 fn scroll_height(&self) -> i32 {
238 self.as_ref().scroll_height()
239 }
240
241 fn scroll_to(&self, options: ScrollToOptions) {
242 let mut opts = web_sys::ScrollToOptions::new();
243
244 opts.left(options.left.into());
245 opts.top(options.top.into());
246 opts.behavior(options.behavior.into());
247
248 self.as_ref().scroll_to_with_scroll_to_options(&opts);
249 }
250
251 fn scroll_by(&self, options: ScrollByOptions) {
252 let mut opts = web_sys::ScrollToOptions::new();
253
254 opts.left(options.x.into());
255 opts.top(options.y.into());
256 opts.behavior(options.behavior.into());
257
258 self.as_ref().scroll_by_with_scroll_to_options(&opts);
259 }
260
261 fn scroll_into_view(&self, options: ScrollIntoViewOptions) {
262 let mut opts = web_sys::ScrollIntoViewOptions::new();
263
264 opts.behavior(options.behavior.into());
265 opts.block(options.block.into());
266 opts.inline(options.inline.into());
267
268 self.as_ref()
269 .scroll_into_view_with_scroll_into_view_options(&opts);
270 }
271}
272
273pub trait ElementReplacement: element_replacement_seal::Sealed {
274 fn replace<E>(&self, element: &E)
275 where
276 E: Element;
277}
278
279impl<T> ElementReplacement for T
280where
281 T: Element,
282{
283 fn replace<E>(&self, element: &E)
284 where
285 E: Element,
286 {
287 element
288 .as_ref()
289 .replace_with_with_node_1(self.as_ref())
290 .unwrap();
291 }
292}
293
294impl ElementReplacement for str {
295 fn replace<E>(&self, element: &E)
296 where
297 E: Element,
298 {
299 element.as_ref().replace_with_with_str_1(self).unwrap();
300 }
301}
302
303mod element_replacement_seal {
304 use super::*;
305
306 pub trait Sealed {}
307
308 impl<T> Sealed for T where T: Element {}
309 impl Sealed for str {}
310}
311
312pub struct Attributes<'a> {
313 element: &'a web_sys::Element,
314 attributes: web_sys::NamedNodeMap,
315}
316
317impl<'a> Attributes<'a> {
318 pub fn get(&self, name: &str) -> Option<Attribute> {
319 self.attributes
320 .get_named_item(name)
321 .map(|a| Attribute::new(a))
322 }
323
324 pub fn get_namespaced(&self, namespace: Option<&str>, local_name: &str) -> Option<Attribute> {
325 self.attributes
326 .get_named_item_ns(namespace, local_name)
327 .map(|a| Attribute::new(a))
328 }
329
330 pub fn contains_name(&self, name: &str) -> bool {
331 self.element.has_attribute(name)
332 }
333
334 pub fn contains_name_namespaced(&self, namespace: Option<&str>, local_name: &str) -> bool {
335 self.element.has_attribute_ns(namespace, local_name)
336 }
337
338 pub fn names(&self) -> AttributeNames {
339 AttributeNames {
340 inner: self.element.get_attribute_names(),
341 }
342 }
343
344 pub fn len(&self) -> usize {
345 self.attributes.length() as usize
346 }
347
348 pub fn is_empty(&self) -> bool {
349 self.len() == 0
350 }
351
352 pub fn is_not_empty(&self) -> bool {
353 !self.is_empty()
354 }
355
356 pub fn toggle(&self, name: &str) -> Result<bool, InvalidAttributeName> {
357 self.element
358 .toggle_attribute(name)
359 .map_err(|_| InvalidAttributeName(name.to_string()))
360 }
361
362 pub fn force_toggle(&self, name: &str) -> Result<bool, InvalidAttributeName> {
363 self.element
364 .toggle_attribute_with_force(name, true)
365 .map_err(|_| InvalidAttributeName(name.to_string()))
366 }
367
368 pub fn remove(&self, name: &str) -> Option<Attribute> {
369 self.attributes
370 .remove_named_item(name)
371 .ok()
372 .map(|attr| Attribute::new(attr))
373 }
374
375 pub fn remove_namespaced(
376 &self,
377 namespace: Option<&str>,
378 local_name: &str,
379 ) -> Option<Attribute> {
380 self.attributes
381 .remove_named_item_ns(namespace, local_name)
382 .ok()
383 .map(|attr| Attribute::new(attr))
384 }
385
386 pub fn remove_node<T>(&self, attribute: &Attribute) -> bool
387 where
388 T: Node,
389 {
390 self.element
391 .remove_attribute_node(attribute.as_ref())
392 .ok()
393 .flatten()
394 .is_some()
395 }
396}
397
398impl<'a> Write for Attributes<'a> {
399 fn write(&self, writer: &mut Writer) {
400 writer.write_1(self.attributes.as_ref())
401 }
402}
403
404pub struct AttributeNames {
405 inner: js_sys::Array,
406}
407
408impl AttributeNames {
409 pub fn get(&self, index: usize) -> Option<String> {
410 u32::try_from(index).ok().map(|index| {
411 let name: js_sys::JsString = self.inner.get(index).unchecked_into();
412
413 String::from(name)
414 })
415 }
416
417 pub fn len(&self) -> usize {
418 self.inner.length() as usize
419 }
420
421 pub fn is_empty(&self) -> bool {
422 self.len() == 0
423 }
424
425 pub fn is_not_empty(&self) -> bool {
426 !self.is_empty()
427 }
428
429 pub fn first(&self) -> Option<String> {
430 self.get(0)
431 }
432
433 pub fn last(&self) -> Option<String> {
434 let len = self.len();
435
436 if len > 0 {
437 self.get(len - 1)
438 } else {
439 None
440 }
441 }
442
443 pub fn iter(&self) -> AttributeNamesIter {
444 AttributeNamesIter {
445 attribute_names: self,
446 current: 0,
447 }
448 }
449}
450
451impl Write for AttributeNames {
452 fn write(&self, writer: &mut Writer) {
453 writer.write_1(self.inner.as_ref())
454 }
455}
456
457impl IntoIterator for AttributeNames {
458 type Item = String;
459 type IntoIter = AttributeNamesIntoIter;
460
461 fn into_iter(self) -> Self::IntoIter {
462 AttributeNamesIntoIter {
463 attribute_names: self,
464 current: 0,
465 }
466 }
467}
468
469pub struct AttributeNamesIter<'a> {
470 attribute_names: &'a AttributeNames,
471 current: usize,
472}
473
474impl<'a> Iterator for AttributeNamesIter<'a> {
475 type Item = String;
476
477 fn next(&mut self) -> Option<Self::Item> {
478 let current = self.current;
479
480 self.current += 1;
481
482 self.attribute_names.get(current)
483 }
484}
485
486pub struct AttributeNamesIntoIter {
487 attribute_names: AttributeNames,
488 current: usize,
489}
490
491impl Iterator for AttributeNamesIntoIter {
492 type Item = String;
493
494 fn next(&mut self) -> Option<Self::Item> {
495 let current = self.current;
496
497 self.current += 1;
498
499 self.attribute_names.get(current)
500 }
501}
502
503pub struct Classes<'a> {
504 element: &'a web_sys::Element,
505 class_list: web_sys::DomTokenList,
506}
507
508impl<'a> Classes<'a> {
509 pub fn get(&self, index: usize) -> Option<String> {
510 u32::try_from(index)
511 .ok()
512 .and_then(|index| self.class_list.item(index))
513 }
514
515 pub fn len(&self) -> usize {
516 self.class_list.length() as usize
517 }
518
519 pub fn is_empty(&self) -> bool {
520 self.len() == 0
521 }
522
523 pub fn is_not_empty(&self) -> bool {
524 !self.is_empty()
525 }
526
527 pub fn contains(&self, class: &str) -> bool {
528 self.class_list.contains(class)
529 }
530
531 pub fn insert(&self, class: &str) {
534 self.class_list.toggle_with_force(class, true).unwrap();
535 }
536
537 pub fn remove(&self, class: &str) {
538 self.class_list.remove_1(class).unwrap();
539 }
540
541 pub fn toggle(&self, class: &str) -> bool {
542 self.class_list.toggle(class).unwrap()
543 }
544
545 pub fn replace(&self, old: &str, new: &str) -> bool {
546 self.class_list.replace(old, new).unwrap()
550 }
551
552 pub fn iter(&self) -> ClassesIter {
553 ClassesIter {
554 classes: self,
555 current: 0,
556 }
557 }
558}
559
560impl<'a> Write for Classes<'a> {
561 fn write(&self, writer: &mut Writer) {
562 writer.write_1(self.class_list.as_ref())
563 }
564}
565
566impl<'a> ToString for Classes<'a> {
567 fn to_string(&self) -> String {
568 self.element.class_name()
569 }
570}
571
572impl<'a> IntoIterator for Classes<'a> {
573 type Item = String;
574 type IntoIter = ClassesIntoIter<'a>;
575
576 fn into_iter(self) -> Self::IntoIter {
577 ClassesIntoIter {
578 classes: self,
579 current: 0,
580 }
581 }
582}
583
584pub struct ClassesIter<'a> {
585 classes: &'a Classes<'a>,
586 current: usize,
587}
588
589impl<'a> Iterator for ClassesIter<'a> {
590 type Item = String;
591
592 fn next(&mut self) -> Option<Self::Item> {
593 let current = self.current;
594
595 self.current += 1;
596
597 self.classes.get(current)
598 }
599}
600
601pub struct ClassesIntoIter<'a> {
602 classes: Classes<'a>,
603 current: usize,
604}
605
606impl<'a> Iterator for ClassesIntoIter<'a> {
607 type Item = String;
608
609 fn next(&mut self) -> Option<Self::Item> {
610 let current = self.current;
611
612 self.current += 1;
613
614 self.classes.get(current)
615 }
616}
617
618pub struct ChildElements<'a> {
619 parent: &'a web_sys::Element,
620 children: web_sys::HtmlCollection,
621}
622
623impl<'a> ChildElements<'a> {
624 pub fn get(&self, index: usize) -> Option<GenericElement> {
625 u32::try_from(index)
626 .ok()
627 .and_then(|index| self.children.item(index))
628 .map(|e| {
629 let e: web_sys::Element = e.unchecked_into();
630
631 e.into()
632 })
633 }
634
635 pub fn len(&self) -> usize {
636 self.parent.child_element_count() as usize
637 }
638
639 pub fn is_empty(&self) -> bool {
640 self.len() == 0
641 }
642
643 pub fn is_not_empty(&self) -> bool {
644 !self.is_empty()
645 }
646
647 pub fn first(&self) -> Option<GenericElement> {
648 self.parent.first_element_child().map(|e| e.into())
649 }
650
651 pub fn last(&self) -> Option<GenericElement> {
652 self.parent.last_element_child().map(|e| e.into())
653 }
654
655 pub fn find_by_id(&self, id: &str) -> Option<GenericElement> {
656 self.children.get_with_name(id).map(|e| {
657 let e: web_sys::Element = e.unchecked_into();
658
659 e.into()
660 })
661 }
662
663 pub fn append<C>(&self, child: &C)
664 where
665 C: ElementChild,
666 {
667 child.append_to(self);
668 }
669
670 pub fn prepend<C>(&self, child: &C)
671 where
672 C: ElementChild,
673 {
674 child.prepend_to(self);
675 }
676
677 pub fn iter(&self) -> ChildElementsIter {
678 ChildElementsIter {
679 child_elements: self,
680 current: 0,
681 }
682 }
683}
684
685impl<'a> Write for ChildElements<'a> {
686 fn write(&self, writer: &mut Writer) {
687 writer.write_1(self.children.as_ref())
688 }
689}
690
691impl<'a> IntoIterator for ChildElements<'a> {
692 type Item = GenericElement;
693 type IntoIter = ChildElementsIntoIter<'a>;
694
695 fn into_iter(self) -> Self::IntoIter {
696 ChildElementsIntoIter {
697 child_elements: self,
698 current: 0,
699 }
700 }
701}
702
703pub struct ChildElementsIter<'a> {
704 child_elements: &'a ChildElements<'a>,
705 current: usize,
706}
707
708impl<'a> Iterator for ChildElementsIter<'a> {
709 type Item = GenericElement;
710
711 fn next(&mut self) -> Option<Self::Item> {
712 let current = self.current;
713
714 self.current += 1;
715
716 self.child_elements.get(current)
717 }
718}
719
720pub struct ChildElementsIntoIter<'a> {
721 child_elements: ChildElements<'a>,
722 current: usize,
723}
724
725impl<'a> Iterator for ChildElementsIntoIter<'a> {
726 type Item = GenericElement;
727
728 fn next(&mut self) -> Option<Self::Item> {
729 let current = self.current;
730
731 self.current += 1;
732
733 self.child_elements.get(current)
734 }
735}
736
737pub trait ElementChild: element_child_seal::Sealed {
738 fn prepend_to(&self, parent_children: &ChildElements);
742
743 fn append_to(&self, parent_children: &ChildElements);
744}
745
746impl<T> ElementChild for T
747where
748 T: Element,
749{
750 fn prepend_to(&self, parent_children: &ChildElements) {
755 parent_children
756 .parent
757 .prepend_with_node_1(self.as_ref())
758 .expect(
759 "Element cannot be an ancestor of the element into which it is being inserted.",
760 );
761 }
762
763 fn append_to(&self, parent_children: &ChildElements) {
764 parent_children
765 .parent
766 .append_with_node_1(self.as_ref())
767 .expect(
768 "Element cannot be an ancestor of the element into which it is being inserted.",
769 );
770 }
771}
772
773impl ElementChild for str {
774 fn prepend_to(&self, parent_children: &ChildElements) {
775 parent_children.parent.prepend_with_str_1(self).unwrap();
776 }
777
778 fn append_to(&self, parent_children: &ChildElements) {
779 parent_children.parent.append_with_str_1(self).unwrap();
780 }
781}
782
783mod element_child_seal {
784 use super::*;
785
786 pub trait Sealed {}
787
788 impl<T> Sealed for T where T: Element {}
789 impl Sealed for str {}
790}
791
792pub struct GenericElement {
892 inner: web_sys::Element,
893}
894
895impl fmt::Debug for GenericElement {
896 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
897 self.inner.fmt(f)
898 }
899}
900
901impl From<web_sys::Element> for GenericElement {
902 fn from(inner: web_sys::Element) -> Self {
903 GenericElement { inner }
904 }
905}
906
907impl From<GenericElement> for web_sys::Element {
908 fn from(value: GenericElement) -> Self {
909 value.inner
910 }
911}
912
913impl TryFrom<GenericNode> for GenericElement {
914 type Error = InvalidCast<GenericNode>;
915
916 fn try_from(value: GenericNode) -> Result<Self, Self::Error> {
917 let value: web_sys::Node = value.into();
918
919 value
920 .dyn_into::<web_sys::Element>()
921 .map(|e| e.into())
922 .map_err(|e| InvalidCast(e.into()))
923 }
924}
925
926impl AsRef<web_sys::Element> for GenericElement {
927 fn as_ref(&self) -> &web_sys::Element {
928 &self.inner
929 }
930}
931
932impl Write for GenericElement {
933 fn write(&self, writer: &mut Writer) {
934 writer.write_1(self.inner.as_ref())
935 }
936}
937
938pub struct ClientRect {
939 inner: web_sys::DomRect,
940}
941
942impl ClientRect {
943 delegate! {
944 target self.inner {
945 pub fn x(&self) -> f64;
946
947 pub fn y(&self) -> f64;
948
949 pub fn width(&self) -> f64;
950
951 pub fn height(&self) -> f64;
952
953 pub fn top(&self) -> f64;
954
955 pub fn bottom(&self) -> f64;
956
957 pub fn left(&self) -> f64;
958
959 pub fn right(&self) -> f64;
960 }
961 }
962}
963
964impl Write for ClientRect {
965 fn write(&self, writer: &mut Writer) {
966 writer.write_1(self.inner.as_ref())
967 }
968}
969
970pub struct ClientRects {
971 inner: web_sys::DomRectList,
972}
973
974impl ClientRects {
975 pub fn get(&self, index: usize) -> Option<ClientRect> {
976 u32::try_from(index)
977 .ok()
978 .and_then(|index| self.inner.get(index))
979 .map(|inner| ClientRect { inner })
980 }
981
982 pub fn len(&self) -> usize {
983 self.inner.length() as usize
984 }
985
986 pub fn is_empty(&self) -> bool {
987 self.len() == 0
988 }
989
990 pub fn is_not_empty(&self) -> bool {
991 !self.is_empty()
992 }
993
994 pub fn first(&self) -> Option<ClientRect> {
995 self.get(0)
996 }
997
998 pub fn last(&self) -> Option<ClientRect> {
999 let len = self.len();
1000
1001 if len > 0 {
1002 self.get(len - 1)
1003 } else {
1004 None
1005 }
1006 }
1007
1008 pub fn iter(&self) -> ClientRectsIter {
1009 ClientRectsIter {
1010 client_rects: self,
1011 current: 0,
1012 }
1013 }
1014}
1015
1016impl Write for ClientRects {
1017 fn write(&self, writer: &mut Writer) {
1018 writer.write_1(self.inner.as_ref())
1019 }
1020}
1021
1022impl IntoIterator for ClientRects {
1023 type Item = ClientRect;
1024 type IntoIter = ClientRectsIntoIter;
1025
1026 fn into_iter(self) -> Self::IntoIter {
1027 ClientRectsIntoIter {
1028 client_rects: self,
1029 current: 0,
1030 }
1031 }
1032}
1033
1034pub struct ClientRectsIntoIter {
1035 client_rects: ClientRects,
1036 current: usize,
1037}
1038
1039impl Iterator for ClientRectsIntoIter {
1040 type Item = ClientRect;
1041
1042 fn next(&mut self) -> Option<Self::Item> {
1043 let current = self.current;
1044
1045 self.current += 1;
1046
1047 self.client_rects.get(current)
1048 }
1049}
1050
1051pub struct ClientRectsIter<'a> {
1052 client_rects: &'a ClientRects,
1053 current: usize,
1054}
1055
1056impl<'a> Iterator for ClientRectsIter<'a> {
1057 type Item = ClientRect;
1058
1059 fn next(&mut self) -> Option<Self::Item> {
1060 let current = self.current;
1061
1062 self.current += 1;
1063
1064 self.client_rects.get(current)
1065 }
1066}
1067
1068#[derive(Clone, PartialEq, Debug)]
1069pub struct InvalidAttributeName(String);