1use std::convert::TryFrom;
2
3use wasm_bindgen::JsCast;
4
5use crate::console::{Write, Writer};
6use crate::error::{AdoptNodeError, HierarchyRequestError, NotSupportedError, SyntaxError};
7use crate::event::{OnFullscreenChange, OnFullscreenError, OnReadyStateChange, OnVisibilityChange};
8use crate::html::{
9 GenericHtmlElement, HtmlBodyElement, HtmlFormElement, HtmlHeadElement, HtmlImageElement,
10};
11use crate::{
12 DocumentFragment, DocumentType, Element, GenericElement, GenericNode, GlobalEventHandlers,
13 Location, Node, QuerySelectorAll, TextDirectionality,
14};
15
16pub trait Document: AsRef<web_sys::Document> {
17 fn body(&self) -> Option<HtmlBodyElement> {
22 self.as_ref()
24 .body()
25 .and_then(|e| e.dyn_into::<web_sys::HtmlBodyElement>().ok())
26 .map(|body| body.into())
27 }
28
29 fn set_body(&self, body: Option<&HtmlBodyElement>) {
30 self.as_ref().set_body(body.map(|b| b.as_ref()));
31 }
32
33 fn character_set(&self) -> String {
34 self.as_ref().character_set()
35 }
36
37 fn child_elements(&self) -> DocumentChildElements {
38 DocumentChildElements {
39 document: self.as_ref(),
40 children: self.as_ref().children(),
41 }
42 }
43
44 fn dir(&self) -> TextDirectionality {
45 match &*self.as_ref().dir().to_lowercase() {
46 "ltr" => TextDirectionality::LeftToRight,
47 "rtl" => TextDirectionality::RightToLeft,
48 _ => TextDirectionality::Auto,
49 }
50 }
51
52 fn set_dir(&self, dir: TextDirectionality) {
53 let text_directionality = match dir {
54 TextDirectionality::Auto => "auto",
55 TextDirectionality::LeftToRight => "ltr",
56 TextDirectionality::RightToLeft => "rtl",
57 };
58
59 self.as_ref().set_dir(text_directionality);
60 }
61
62 fn doctype(&self) -> Option<DocumentType> {
63 self.as_ref().doctype().map(|d| d.into())
64 }
65
66 fn document_element(&self) -> Option<GenericElement> {
67 self.as_ref().document_element().map(|e| e.into())
68 }
69
70 fn document_uri(&self) -> String {
71 self.as_ref().document_uri().unwrap()
73 }
74
75 fn forms(&self) -> DocumentForms {
79 DocumentForms {
80 inner: self.as_ref().forms(),
81 }
82 }
83
84 fn fullscreen_enabled(&self) -> bool {
85 self.as_ref().fullscreen_enabled()
86 }
87
88 fn has_focus(&self) -> bool {
89 self.as_ref().has_focus().unwrap()
91 }
92
93 fn head(&self) -> Option<HtmlHeadElement> {
94 self.as_ref().head().map(|h| h.into())
95 }
96
97 fn hidden(&self) -> bool {
98 self.as_ref().hidden()
99 }
100
101 fn images(&self) -> DocumentImages {
102 DocumentImages {
103 inner: self.as_ref().images(),
104 }
105 }
106
107 fn last_modified(&self) -> String {
108 self.as_ref().last_modified()
109 }
110
111 fn links(&self) -> DocumentLinks {
112 DocumentLinks {
113 inner: self.as_ref().links(),
114 }
115 }
116
117 fn location(&self) -> Option<Location> {
118 self.as_ref().location().map(|l| l.into())
119 }
120
121 fn referrer(&self) -> String {
122 self.as_ref().referrer()
123 }
124
125 fn title(&self) -> String {
126 self.as_ref().title()
127 }
128
129 fn set_title(&self, title: &str) {
130 self.as_ref().set_title(title);
131 }
132
133 fn on_fullscreen_change(&self) -> OnFullscreenChange {
136 OnFullscreenChange::new(self.as_ref().clone().into())
137 }
138
139 fn on_fullscreen_error(&self) -> OnFullscreenError {
140 OnFullscreenError::new(self.as_ref().clone().into())
141 }
142
143 fn on_ready_state_change(&self) -> OnReadyStateChange {
144 OnReadyStateChange::new(self.as_ref().clone().into())
145 }
146
147 fn on_visibility_change(&self) -> OnVisibilityChange {
148 OnVisibilityChange::new(self.as_ref().clone().into())
149 }
150
151 fn adopt_node<T>(&self, node: &T) -> Result<GenericNode, AdoptNodeError>
152 where
153 T: Node,
154 {
155 self.as_ref()
156 .adopt_node(node.as_ref())
157 .map(|ok| ok.into())
158 .map_err(|err| {
159 let err: web_sys::DomException = err.unchecked_into();
160
161 match &*err.name() {
162 "NotSupportedError" => NotSupportedError::new(err).into(),
163 "HierarchyRequestError" => HierarchyRequestError::new(err).into(),
164 _ => unreachable!(),
165 }
166 })
167 }
168
169 fn import_node<T>(&self, node: &T) -> Result<GenericNode, NotSupportedError>
170 where
171 T: Node,
172 {
173 self.as_ref()
174 .import_node(node.as_ref())
175 .map(|ok| ok.into())
176 .map_err(|err| NotSupportedError::new(err.unchecked_into()))
177 }
178
179 fn import_node_deep<T>(&self, node: &T) -> Result<GenericNode, NotSupportedError>
180 where
181 T: Node,
182 {
183 self.as_ref()
184 .import_node_with_deep(node.as_ref(), true)
185 .map(|ok| ok.into())
186 .map_err(|err| NotSupportedError::new(err.unchecked_into()))
187 }
188
189 fn query_id(&self, id: &str) -> Option<GenericElement> {
193 self.as_ref().get_element_by_id(id).map(|e| e.into())
194 }
195
196 fn query_selector_first(&self, selector: &str) -> Result<Option<GenericElement>, SyntaxError> {
197 self.as_ref()
198 .query_selector(selector)
199 .map(|ok| ok.map(|e| e.into()))
200 .map_err(|err| SyntaxError::new(err.unchecked_into()))
201 }
202
203 fn query_selector_all(&self, selector: &str) -> Result<QuerySelectorAll, SyntaxError> {
204 self.as_ref()
205 .query_selector_all(selector)
206 .map(|inner| QuerySelectorAll::new(inner))
207 .map_err(|err| SyntaxError::new(err.unchecked_into()))
208 }
209
210 fn enable_style_sheets_for_set(&self, set_name: Option<&str>) {
214 self.as_ref().enable_style_sheets_for_set(set_name);
215 }
216
217 fn create_document_fragment(&self) -> DocumentFragment {
222 DocumentFragment::from(self.as_ref().create_document_fragment())
223 }
224
225 fn element_from_point(&self, x: f32, y: f32) -> Option<GenericElement> {
226 self.as_ref().element_from_point(x, y).map(|e| e.into())
227 }
228}
229
230pub struct GenericDocument {
231 inner: web_sys::Document,
232}
233
234impl From<web_sys::Document> for GenericDocument {
235 fn from(inner: web_sys::Document) -> Self {
236 GenericDocument { inner }
237 }
238}
239
240impl AsRef<web_sys::Document> for GenericDocument {
241 fn as_ref(&self) -> &web_sys::Document {
242 &self.inner
243 }
244}
245
246impl AsRef<web_sys::Node> for GenericDocument {
247 fn as_ref(&self) -> &web_sys::Node {
248 self.inner.as_ref()
249 }
250}
251
252impl AsRef<web_sys::EventTarget> for GenericDocument {
253 fn as_ref(&self) -> &web_sys::EventTarget {
254 self.inner.as_ref()
255 }
256}
257
258impl Write for GenericDocument {
259 fn write(&self, writer: &mut Writer) {
260 writer.write_1(self.inner.as_ref());
261 }
262}
263
264impl GlobalEventHandlers for GenericDocument {}
265impl Node for GenericDocument {}
266impl Document for GenericDocument {}
267
268pub struct DocumentChildElements<'a> {
269 document: &'a web_sys::Document,
270 children: web_sys::HtmlCollection,
271}
272
273impl<'a> DocumentChildElements<'a> {
274 pub fn get(&self, index: usize) -> Option<GenericElement> {
275 u32::try_from(index)
276 .ok()
277 .and_then(|index| self.children.get_with_index(index))
278 .map(|e| e.into())
279 }
280
281 pub fn find_by_id(&self, id: &str) -> Option<GenericElement> {
282 self.children.get_with_name(id).map(|e| e.into())
283 }
284
285 pub fn len(&self) -> usize {
286 self.document.child_element_count() as usize
287 }
288
289 pub fn is_empty(&self) -> bool {
290 self.len() == 0
291 }
292
293 pub fn is_not_empty(&self) -> bool {
294 !self.is_empty()
295 }
296
297 pub fn first(&self) -> Option<GenericElement> {
298 self.document.first_element_child().map(|e| e.into())
299 }
300
301 pub fn last(&self) -> Option<GenericElement> {
302 self.document.last_element_child().map(|e| e.into())
303 }
304
305 pub fn append<C>(&self, child: &C)
306 where
307 C: DocumentChild,
308 {
309 child.append_to(self);
310 }
311
312 pub fn prepend<C>(&self, child: &C)
313 where
314 C: DocumentChild,
315 {
316 child.prepend_to(self);
317 }
318
319 pub fn iter(&self) -> DocumentChildElementsIter {
320 DocumentChildElementsIter {
321 document_child_elements: self,
322 current: 0,
323 }
324 }
325}
326
327impl<'a> Write for DocumentChildElements<'a> {
328 fn write(&self, writer: &mut Writer) {
329 writer.write_1(self.children.as_ref());
330 }
331}
332
333impl<'a> IntoIterator for DocumentChildElements<'a> {
334 type Item = GenericElement;
335 type IntoIter = DocumentChildElementsIntoIter<'a>;
336
337 fn into_iter(self) -> Self::IntoIter {
338 DocumentChildElementsIntoIter {
339 document_child_elements: self,
340 current: 0,
341 }
342 }
343}
344
345pub trait DocumentChild: document_child_seal::Sealed {
346 fn prepend_to(&self, document_children: &DocumentChildElements);
350
351 fn append_to(&self, document_children: &DocumentChildElements);
352}
353
354impl<T> DocumentChild for T
355where
356 T: Element,
357{
358 fn prepend_to(&self, document_children: &DocumentChildElements) {
363 document_children
364 .document
365 .prepend_with_node_1(self.as_ref())
366 .expect(
367 "Element cannot be an ancestor of the element into which it is being inserted.",
368 );
369 }
370
371 fn append_to(&self, document_children: &DocumentChildElements) {
372 document_children
373 .document
374 .append_with_node_1(self.as_ref())
375 .expect(
376 "Element cannot be an ancestor of the element into which it is being inserted.",
377 );
378 }
379}
380
381impl DocumentChild for str {
382 fn prepend_to(&self, document_children: &DocumentChildElements) {
383 document_children.document.prepend_with_str_1(self).unwrap();
384 }
385
386 fn append_to(&self, document_children: &DocumentChildElements) {
387 document_children.document.append_with_str_1(self).unwrap();
388 }
389}
390
391mod document_child_seal {
392 use super::*;
393
394 pub trait Sealed {}
395
396 impl<T> Sealed for T where T: Element {}
397 impl Sealed for str {}
398}
399
400pub struct DocumentChildElementsIter<'a> {
401 document_child_elements: &'a DocumentChildElements<'a>,
402 current: usize,
403}
404
405impl<'a> Iterator for DocumentChildElementsIter<'a> {
406 type Item = GenericElement;
407
408 fn next(&mut self) -> Option<Self::Item> {
409 let current = self.current;
410
411 self.current += 1;
412
413 self.document_child_elements.get(current)
414 }
415}
416
417pub struct DocumentChildElementsIntoIter<'a> {
418 document_child_elements: DocumentChildElements<'a>,
419 current: usize,
420}
421
422impl<'a> Iterator for DocumentChildElementsIntoIter<'a> {
423 type Item = GenericElement;
424
425 fn next(&mut self) -> Option<Self::Item> {
426 let current = self.current;
427
428 self.current += 1;
429
430 self.document_child_elements.get(current)
431 }
432}
433
434pub struct DocumentForms {
435 inner: web_sys::HtmlCollection,
436}
437
438impl DocumentForms {
439 pub fn get(&self, index: usize) -> Option<HtmlFormElement> {
440 u32::try_from(index)
441 .ok()
442 .and_then(|index| self.inner.get_with_index(index))
443 .map(|e| {
444 let e: web_sys::HtmlFormElement = e.unchecked_into();
445
446 e.into()
447 })
448 }
449
450 pub fn find_by_id(&self, id: &str) -> Option<HtmlFormElement> {
451 self.inner.get_with_name(id).map(|e| {
452 let e: web_sys::HtmlFormElement = e.unchecked_into();
453
454 e.into()
455 })
456 }
457
458 pub fn len(&self) -> usize {
459 self.inner.length() as usize
460 }
461
462 pub fn is_empty(&self) -> bool {
463 self.len() == 0
464 }
465
466 pub fn is_not_empty(&self) -> bool {
467 !self.is_empty()
468 }
469
470 pub fn first(&self) -> Option<HtmlFormElement> {
471 self.get(0)
472 }
473
474 pub fn last(&self) -> Option<HtmlFormElement> {
475 let len = self.len();
476
477 if len > 0 {
478 self.get(len - 1)
479 } else {
480 None
481 }
482 }
483
484 pub fn iter(&self) -> DocumentFormsIter {
485 DocumentFormsIter {
486 document_forms: self,
487 current: 0,
488 }
489 }
490}
491
492impl Write for DocumentForms {
493 fn write(&self, writer: &mut Writer) {
494 writer.write_1(self.inner.as_ref());
495 }
496}
497
498impl IntoIterator for DocumentForms {
499 type Item = HtmlFormElement;
500 type IntoIter = DocumentFormsIntoIter;
501
502 fn into_iter(self) -> Self::IntoIter {
503 DocumentFormsIntoIter {
504 document_forms: self,
505 current: 0,
506 }
507 }
508}
509
510pub struct DocumentFormsIter<'a> {
511 document_forms: &'a DocumentForms,
512 current: usize,
513}
514
515impl<'a> Iterator for DocumentFormsIter<'a> {
516 type Item = HtmlFormElement;
517
518 fn next(&mut self) -> Option<Self::Item> {
519 let current = self.current;
520
521 self.current += 1;
522
523 self.document_forms.get(current)
524 }
525}
526
527pub struct DocumentFormsIntoIter {
528 document_forms: DocumentForms,
529 current: usize,
530}
531
532impl Iterator for DocumentFormsIntoIter {
533 type Item = HtmlFormElement;
534
535 fn next(&mut self) -> Option<Self::Item> {
536 let current = self.current;
537
538 self.current += 1;
539
540 self.document_forms.get(current)
541 }
542}
543
544pub struct DocumentImages {
545 inner: web_sys::HtmlCollection,
546}
547
548impl DocumentImages {
549 pub fn get(&self, index: usize) -> Option<HtmlImageElement> {
550 u32::try_from(index)
551 .ok()
552 .and_then(|index| self.inner.get_with_index(index))
553 .map(|e| {
554 let e: web_sys::HtmlImageElement = e.unchecked_into();
555
556 e.into()
557 })
558 }
559
560 pub fn find_by_id(&self, id: &str) -> Option<HtmlImageElement> {
561 self.inner.get_with_name(id).map(|e| {
562 let e: web_sys::HtmlImageElement = e.unchecked_into();
563
564 e.into()
565 })
566 }
567
568 pub fn len(&self) -> usize {
569 self.inner.length() as usize
570 }
571
572 pub fn is_empty(&self) -> bool {
573 self.len() == 0
574 }
575
576 pub fn is_not_empty(&self) -> bool {
577 !self.is_empty()
578 }
579
580 pub fn first(&self) -> Option<HtmlImageElement> {
581 self.get(0)
582 }
583
584 pub fn last(&self) -> Option<HtmlImageElement> {
585 let len = self.len();
586
587 if len > 0 {
588 self.get(len - 1)
589 } else {
590 None
591 }
592 }
593
594 pub fn iter(&self) -> DocumentImagesIter {
595 DocumentImagesIter {
596 document_images: self,
597 current: 0,
598 }
599 }
600}
601
602impl Write for DocumentImages {
603 fn write(&self, writer: &mut Writer) {
604 writer.write_1(self.inner.as_ref());
605 }
606}
607
608impl IntoIterator for DocumentImages {
609 type Item = HtmlImageElement;
610 type IntoIter = DocumentImagesIntoIter;
611
612 fn into_iter(self) -> Self::IntoIter {
613 DocumentImagesIntoIter {
614 document_images: self,
615 current: 0,
616 }
617 }
618}
619
620pub struct DocumentImagesIter<'a> {
621 document_images: &'a DocumentImages,
622 current: usize,
623}
624
625impl<'a> Iterator for DocumentImagesIter<'a> {
626 type Item = HtmlImageElement;
627
628 fn next(&mut self) -> Option<Self::Item> {
629 let current = self.current;
630
631 self.current += 1;
632
633 self.document_images.get(current)
634 }
635}
636
637pub struct DocumentImagesIntoIter {
638 document_images: DocumentImages,
639 current: usize,
640}
641
642impl Iterator for DocumentImagesIntoIter {
643 type Item = HtmlImageElement;
644
645 fn next(&mut self) -> Option<Self::Item> {
646 let current = self.current;
647
648 self.current += 1;
649
650 self.document_images.get(current)
651 }
652}
653
654pub struct DocumentLinks {
655 inner: web_sys::HtmlCollection,
656}
657
658impl DocumentLinks {
659 pub fn get(&self, index: usize) -> Option<GenericHtmlElement> {
660 u32::try_from(index)
661 .ok()
662 .and_then(|index| self.inner.get_with_index(index))
663 .map(|e| {
664 let e: web_sys::HtmlElement = e.unchecked_into();
665
666 e.into()
667 })
668 }
669
670 pub fn find_by_id(&self, id: &str) -> Option<GenericHtmlElement> {
671 self.inner.get_with_name(id).map(|e| {
672 let e: web_sys::HtmlElement = e.unchecked_into();
673
674 e.into()
675 })
676 }
677
678 pub fn len(&self) -> usize {
679 self.inner.length() as usize
680 }
681
682 pub fn is_empty(&self) -> bool {
683 self.len() == 0
684 }
685
686 pub fn is_not_empty(&self) -> bool {
687 !self.is_empty()
688 }
689
690 pub fn first(&self) -> Option<GenericHtmlElement> {
691 self.get(0)
692 }
693
694 pub fn last(&self) -> Option<GenericHtmlElement> {
695 let len = self.len();
696
697 if len > 0 {
698 self.get(len - 1)
699 } else {
700 None
701 }
702 }
703
704 pub fn iter(&self) -> DocumentLinksIter {
705 DocumentLinksIter {
706 document_links: self,
707 current: 0,
708 }
709 }
710}
711
712impl Write for DocumentLinks {
713 fn write(&self, writer: &mut Writer) {
714 writer.write_1(self.inner.as_ref());
715 }
716}
717
718impl IntoIterator for DocumentLinks {
719 type Item = GenericHtmlElement;
720 type IntoIter = DocumentLinksIntoIter;
721
722 fn into_iter(self) -> Self::IntoIter {
723 DocumentLinksIntoIter {
724 document_links: self,
725 current: 0,
726 }
727 }
728}
729
730pub struct DocumentLinksIter<'a> {
731 document_links: &'a DocumentLinks,
732 current: usize,
733}
734
735impl<'a> Iterator for DocumentLinksIter<'a> {
736 type Item = GenericHtmlElement;
737
738 fn next(&mut self) -> Option<Self::Item> {
739 let current = self.current;
740
741 self.current += 1;
742
743 self.document_links.get(current)
744 }
745}
746
747pub struct DocumentLinksIntoIter {
748 document_links: DocumentLinks,
749 current: usize,
750}
751
752impl Iterator for DocumentLinksIntoIter {
753 type Item = GenericHtmlElement;
754
755 fn next(&mut self) -> Option<Self::Item> {
756 let current = self.current;
757
758 self.current += 1;
759
760 self.document_links.get(current)
761 }
762}