arwa/
element.rs

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    // TODO: skip `attach_shadow` here, add it to the specific elements for which it is valid.
17
18    // TODO: implement `request_full_screen` as a future.
19
20    // TODO: is there a (reasonable) way to pre-compile the selector as a typed object and get the
21    // syntax error handling out of the way at that stage? Would give cleaner return types.
22
23    // TODO: before/after/insert_adjacent
24
25    // TODO: convert from point/quad/rect? Should that live on Document?
26
27    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    // TODO: I can perhaps be argued that get_elements_by_tag_name and get_elements_by_class_name
48    // have been superseded by query_selector_all (especially since the newer DocumentFragment
49    // interface does not include them), even though they are not entirely equivalent (live
50    // collection vs non-live collection respectively) and perhaps not equally performant (I don't
51    // know to what extent browser implementations pre-parse and/or cache parsed selector strings).
52    //
53    // Omitted for now, but might look like this:
54    //
55    //    fn query_tag_name(&self, tag_name: &str) -> LiveQueriedElements {
56    //        LiveQueriedElements {
57    //            inner: self.as_ref().get_elements_by_tag_name(tag_name),
58    //        }
59    //    }
60    //
61    //    fn query_tag_name_namespaced(
62    //        &self,
63    //        namespace: Option<&str>,
64    //        local_name: &str,
65    //    ) -> LiveQueriedElements {
66    //        LiveQueriedElements {
67    //            // MDN gives no indication that this could actually fail, so just unwrap for now
68    //            inner: self
69    //                .as_ref()
70    //                .get_elements_by_tag_name_ns(namespace, local_name)
71    //                .unwrap(),
72    //        }
73    //    }
74    //
75    //    fn query_class_name(&self, class_name: &str) -> LiveQueriedElements {
76    //        LiveQueriedElements {
77    //            inner: self.as_ref().get_elements_by_class_name(class_name),
78    //        }
79    //    }
80
81    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    // TODO: make insert and remove add a bool by adding a `contains` check?
532
533    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        // It seems the error case covers old browser returning void instead of a bool, but I don't
547        // believe there's any overlap between browsers that support WASM and browsers that still
548        // return void, so this should never cause an error.
549        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    // Note, this construct *should* be locked down enough to avoid any "HierarchyRequestError" and
739    // thus these operations should never fail.
740
741    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    // TODO: decide on panic vs error on append/prepend when trying to insert an element into an
751    // element that is a descendant. May be argued to be in the same class of errors as indexing
752    // error, std handles these with panics (e.g. Vec::insert).
753
754    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
792/*
793pub struct LiveQueriedElements {
794    inner: web_sys::HtmlCollection,
795}
796
797impl LiveQueriedElements {
798    pub fn get(&self, index: usize) -> Option<GenericElement> {
799        u32::try_from(index)
800            .ok()
801            .and_then(|index| self.inner.get_with_index(index))
802            .map(|inner| GenericElement { inner })
803    }
804
805    pub fn find_by_id(&self, id: &str) -> Option<GenericElement> {
806        self.inner
807            .get_with_name(id)
808            .map(|inner| GenericElement { inner })
809    }
810
811    pub fn len(&self) -> usize {
812        self.inner.length() as usize
813    }
814
815    pub fn is_empty(&self) -> bool {
816        self.len() == 0
817    }
818
819    pub fn is_not_empty(&self) -> bool {
820        !self.is_empty()
821    }
822
823    pub fn first(&self) -> Option<GenericElement> {
824        self.get(0)
825    }
826
827    pub fn last(&self) -> Option<GenericElement> {
828        let len = self.len();
829
830        if len > 0 {
831            self.get(len - 1)
832        } else {
833            None
834        }
835    }
836
837    pub fn iter(&self) -> LiveQueriedElementsIter {
838        LiveQueriedElementsIter {
839            elements: self,
840            current: 0,
841        }
842    }
843}
844
845impl IntoIterator for LiveQueriedElements {
846    type Item = GenericElement;
847    type IntoIter = LiveQueriedElementsIntoIter;
848
849    fn into_iter(self) -> Self::IntoIter {
850        LiveQueriedElementsIntoIter {
851            elements: self,
852            current: 0,
853        }
854    }
855}
856
857pub struct LiveQueriedElementsIter<'a> {
858    elements: &'a LiveQueriedElements,
859    current: usize,
860}
861
862impl<'a> Iterator for LiveQueriedElementsIter<'a> {
863    type Item = GenericElement;
864
865    fn next(&mut self) -> Option<Self::Item> {
866        let current = self.current;
867
868        self.current += 1;
869
870        self.elements.get(current)
871    }
872}
873
874pub struct LiveQueriedElementsIntoIter {
875    elements: LiveQueriedElements,
876    current: usize,
877}
878
879impl Iterator for LiveQueriedElementsIntoIter {
880    type Item = GenericElement;
881
882    fn next(&mut self) -> Option<Self::Item> {
883        let current = self.current;
884
885        self.current += 1;
886
887        self.elements.get(current)
888    }
889}
890*/
891pub 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);