1use std::mem;
2
3use webcore::value::Reference;
4use webcore::try_from::{TryFrom, TryInto};
5use webapi::document::Document;
6use webapi::dom_exception::{HierarchyRequestError, NotFoundError, SyntaxError};
7use webapi::element::Element;
8use webapi::event_target::{IEventTarget, EventTarget};
9use webapi::node_list::NodeList;
10use private::TODO;
11
12#[derive(Copy, Clone, PartialEq, Eq, Debug)]
17pub enum CloneKind {
18 Shallow,
20 Deep
22}
23
24pub trait INode: IEventTarget {
29 fn as_node( &self ) -> &Node {
31 let reference: &Reference = self.as_ref();
32 unsafe {
33 mem::transmute( reference )
34 }
35 }
36
37 fn append_child< T: INode >( &self, child: &T ) {
46 js! { @(no_return)
47 @{self.as_ref()}.appendChild( @{child.as_ref()} );
48 }
49 }
50
51 fn remove_child< T: INode >( &self, child: &T ) -> Result< Node, NotFoundError > {
56 js_try! (
57 return @{self.as_ref()}.removeChild( @{child.as_ref()} );
58 ).unwrap()
59 }
60
61 fn clone_node( &self, kind: CloneKind ) -> Result< Self, TODO > {
66 let is_deep = match kind {
67 CloneKind::Deep => true,
68 CloneKind::Shallow => false
69 };
70
71 let cloned = js! {
72 return @{self.as_ref()}.cloneNode( @{is_deep} );
73 };
74
75 Ok( cloned.into_reference().unwrap().downcast::< Self >().unwrap() )
76 }
77
78 fn contains< T: INode >( &self, node: &T ) -> bool {
83 js!(
84 return @{self.as_ref()}.contains( @{node.as_ref()} );
85 ).try_into().unwrap()
86 }
87
88 fn insert_before< T: INode, U: INode >( &self, new_node: &T, reference_node: &U ) -> Result< Node, InsertNodeError > {
93 js_try! (
94 return @{self.as_ref()}.insertBefore( @{new_node.as_ref()}, @{reference_node.as_ref()} );
95 ).unwrap()
96 }
97
98 fn replace_child< T: INode, U: INode >( &self, new_child: &T, old_child: &U ) -> Result< Node, InsertNodeError > {
103 js_try! (
104 return @{self.as_ref()}.replaceChild( @{new_child.as_ref()}, @{old_child.as_ref()} );
105 ).unwrap()
106 }
107
108 fn parent_node( &self ) -> Option< Node > {
113 js!(
114 return @{self.as_ref()}.parentNode;
115 ).try_into().ok()
116 }
117
118 fn first_child( &self ) -> Option< Node > {
123 js!(
124 return @{self.as_ref()}.firstChild;
125 ).try_into().ok()
126 }
127
128 fn last_child( &self ) -> Option< Node > {
133 js!(
134 return @{self.as_ref()}.lastChild;
135 ).try_into().ok()
136 }
137
138 fn next_sibling( &self ) -> Option< Node > {
143 js!(
144 return @{self.as_ref()}.nextSibling;
145 ).try_into().ok()
146 }
147
148 fn node_name( &self ) -> String {
153 js!(
154 return @{self.as_ref()}.nodeName;
155 ).try_into().unwrap()
156 }
157
158 fn node_type( &self ) -> NodeType {
163 match js!(
164 return @{self.as_ref()}.nodeType;
165 ).try_into().unwrap() {
166 1 => NodeType::Element,
167 2 => NodeType::Attribute,
168 3 => NodeType::Text,
169 4 => NodeType::CDataSection,
170 7 => NodeType::ProcessingInstruction,
171 8 => NodeType::Comment,
172 9 => NodeType::Document,
173 10 => NodeType::DocumentType,
174 11 => NodeType::DocumentFragment,
175 _ => unreachable!("Unexpected nodeType")
176 }
177 }
178
179 fn node_value( &self ) -> Option<String> {
184 js!(
185 return @{self.as_ref()}.nodeValue;
186 ).try_into().ok()
187 }
188
189 fn set_node_value( &self, value: Option< &str > ) {
194 js! { @(no_return)
195 @{self.as_ref()}.nodeValue = @{value};
196 }
197 }
198
199 fn owner_document( &self ) -> Option< Document > {
204 js!(
205 return @{self.as_ref()}.ownerDocument;
206 ).try_into().ok()
207 }
208
209 fn parent_element( &self ) -> Option< Element > {
215 js!(
216 return @{self.as_ref()}.parentElement;
217 ).try_into().ok()
218 }
219
220 fn previous_sibling( &self ) -> Option< Node > {
225 js!(
226 return @{self.as_ref()}.previousSibling;
227 ).try_into().ok()
228 }
229
230 fn text_content( &self ) -> Option< String > {
235 js!(
236 return @{self.as_ref()}.textContent;
237 ).try_into().unwrap()
238 }
239
240 fn set_text_content( &self, text: &str ) {
247 js! { @(no_return)
248 @{self.as_ref()}.textContent = @{text};
249 }
250 }
251
252 fn child_nodes( &self ) -> NodeList {
257 unsafe {
258 js!(
259 return @{self.as_ref()}.childNodes;
260 ).into_reference_unchecked().unwrap()
261 }
262 }
263
264 fn base_uri( &self ) -> String {
269 js!(
270 return @{self.as_ref()}.baseURI;
271 ).try_into().unwrap()
272 }
273
274 fn has_child_nodes( &self ) -> bool {
279 js!(
280 return @{self.as_ref()}.hasChildNodes();
281 ).try_into().unwrap()
282 }
283
284 fn is_default_namespace( &self, namespace: &str ) -> bool {
289 js!(
290 return @{self.as_ref()}.isDefaultNamespace( @{namespace} );
291 ).try_into().unwrap()
292 }
293
294 fn is_equal_node< T: INode >( &self, node: &T ) -> bool {
301 js!(
302 return @{self.as_ref()}.isEqualNode( @{node.as_ref()} );
303 ).try_into().unwrap()
304 }
305
306 fn is_same_node< T: INode >( &self, node: &T ) -> bool {
311 js!(
312 return @{self.as_ref()}.isSameNode( @{node.as_ref()} );
313 ).try_into().unwrap()
314 }
315
316 fn lookup_prefix( &self, namespace: &str ) -> Option<String> {
321 js!(
322 return @{self.as_ref()}.lookupPrefix( @{namespace} );
323 ).try_into().ok()
324 }
325
326 fn lookup_namespace_uri( &self, prefix: &str ) -> Option<String> {
331 js!(
332 return @{self.as_ref()}.lookupNamespaceURI( @{prefix} );
333 ).try_into().ok()
334 }
335
336 fn normalize( &self ) {
341 js! { @(no_return)
342 @{self.as_ref()}.normalize();
343 }
344 }
345}
346
347error_enum_boilerplate! {
349 InsertNodeError,
350 NotFoundError, HierarchyRequestError
351}
352
353#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
359#[reference(instance_of = "Node")]
360#[reference(subclass_of(EventTarget))]
361pub struct Node( Reference );
362
363impl IEventTarget for Node {}
364impl INode for Node {}
365
366impl Node {
367 pub fn from_html(html: &str) -> Result<Node, SyntaxError> {
384 js_try!(
385 var span = document.createElement("span");
386 span.innerHTML = @{html};
387 if( span.childNodes.length != 1 ) {
388 throw new DOMException(
389 "Node::from_html requires a single root node but has: "
390 + span.childNodes.length,
391 "SyntaxError");
392 }
393 return span.childNodes[0];
394 ).unwrap()
395 }
396}
397
398#[derive(Clone, Copy, Debug, Eq, PartialEq)]
402pub enum NodeType {
403 Element,
405
406 Text,
408
409 ProcessingInstruction,
411
412 Comment,
414
415 Document,
417
418 DocumentType,
420
421 DocumentFragment,
423
424 Attribute,
428
429 CDataSection,
431
432 XmlEntityReference,
434
435 XmlEntity,
437
438 XmlNotation,
440}
441
442#[cfg(all(test, feature = "web_test"))]
443mod tests {
444 use super::*;
445 use webapi::document::document;
446 use webcore::value::Value;
447
448 fn div() -> Node {
449 js!(
450 return document.createElement("div");
451 ).try_into().unwrap()
452 }
453
454 fn text(text: &str) -> Node {
455 js!(
456 return new Text(@{text});
457 ).try_into().unwrap()
458 }
459
460 fn comment(text: &str) -> Node {
461 js!(
462 return document.createComment(@{text});
463 ).try_into().unwrap()
464 }
465
466 fn processing_instruction(target: &str, data: &str) -> Node {
467 js!(
468 return document.createProcessingInstruction(@{target}, @{data});
469 ).try_into().unwrap()
470 }
471
472 fn doc_type() -> Node {
473 js!(
474 return document.implementation.createDocumentType(
475 "svg:svg",
476 "-//W3C//DTD SVG 1.1//EN",
477 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"
478 );
479 ).try_into().unwrap()
480 }
481
482 fn document_fragment() -> Node {
483 js!(
484 return document.createDocumentFragment();
485 ).try_into().unwrap()
486 }
487
488 fn xml(namespace_prefix: &str, namespace_url: &str) -> Node {
489 let xml_text = format!(
490 "<?xml version = \"1.0\"?><foo xmlns:{} = \"{}\" />",
491 namespace_prefix,
492 namespace_url
493 );
494 js!(
495 return new DOMParser().parseFromString(@{xml_text}, "text/xml");
496 ).try_into().unwrap()
497 }
498
499 #[test]
500 fn test_append_child() {
501 let parent = div();
502 let child = div();
503 parent.append_child(&child);
504 assert_eq!(parent.first_child().unwrap().as_ref(), child.as_ref());
505 }
506
507 #[test]
508 fn test_remove_child() {
509 let parent = div();
510 let child1 = div();
511 let child2 = div();
512 parent.append_child(&child1);
513 parent.append_child(&child2);
514
515 let removed = parent.remove_child(&child1).unwrap();
516 assert_eq!(parent.first_child().unwrap().as_ref(), child2.as_ref());
517 assert_eq!(removed.as_ref(), child1.as_ref());
518 match parent.remove_child(&child1) {
519 Err(_) => (),
520 _ => panic!("Expected error")
521 }
522
523 parent.remove_child(&child2).unwrap();
524 assert!(parent.first_child().is_none())
525 }
526
527 #[test]
528 fn test_clone_node() {
529 let node = div();
530 let child = text("test");
531 node.append_child(&child);
532
533 let clone = node.clone_node(CloneKind::Shallow).unwrap();
534 assert_ne!(node.as_ref(), clone.as_ref());
535 assert_eq!(clone.node_name(), "DIV");
536 assert!(clone.first_child().is_none());
537
538 let clone = node.clone_node(CloneKind::Deep).unwrap();
539 assert_ne!(node.as_ref(), clone.as_ref());
540 assert_eq!(clone.node_name(), "DIV");
541 let clone_child = clone.first_child().unwrap();
542 assert_ne!(clone_child.as_ref(), child.as_ref());
543 assert_eq!(&clone_child.node_value().unwrap(), "test");
544 }
545
546 #[test]
547 fn test_contains() {
548 let node = div();
549
550 let child1 = div();
551 node.append_child(&child1);
552
553 let child2 = div();
554 node.append_child(&child2);
555
556 let grandchild = div();
557 child1.append_child(&grandchild);
558
559 assert!(node.contains(&node));
560 assert!(node.contains(&child1));
561 assert!(node.contains(&child2));
562 assert!(node.contains(&grandchild));
563 assert!(child1.contains(&grandchild));
564 assert!(!child1.contains(&child2));
565 assert!(!grandchild.contains(&node));
566 }
567
568 #[test]
569 fn test_insert_before() {
570 let node = div();
571 let child1 = div();
572 let child2 = div();
573 let child3 = div();
574 node.append_child(&child1);
575 node.insert_before(&child2, &child1).unwrap();
576 assert_eq!(node.first_child().unwrap().as_ref(), child2.as_ref());
577
578 match node.insert_before(&child3, &child3) {
579 Err(InsertNodeError::NotFoundError(_)) => (),
580 _ => panic!("Expected NotFoundError")
581 }
582
583 match node.insert_before(&doc_type(), &child1) {
584 Err(InsertNodeError::HierarchyRequestError(_)) => (),
585 _ => panic!("Expected HierarchyRequestError")
586 }
587 }
588
589 #[test]
590 fn test_replace_child() {
591 let node = div();
592 let child1 = div();
593 let child2 = div();
594 node.append_child(&child1);
595 node.replace_child(&child2, &child1).unwrap();
596 assert_eq!(node.first_child().unwrap().as_ref(), child2.as_ref());
597 assert!(child1.parent_node().is_none());
598
599 match node.replace_child(&child2, &child1) {
600 Err(InsertNodeError::NotFoundError(_)) => (),
601 _ => panic!("Expected NotFoundError")
602 }
603
604 match node.replace_child(&doc_type(), &child2) {
605 Err(InsertNodeError::HierarchyRequestError(_)) => (),
606 _ => panic!("Expected HierarchyRequestError")
607 }
608 }
609
610 #[test]
611 fn test_parent_node() {
612 let node = div();
613 let child = div();
614 node.append_child(&child);
615 assert!(node.parent_node().is_none());
616 assert_eq!(child.parent_node().unwrap().as_ref(), node.as_ref());
617 }
618
619 #[test]
620 fn test_first_child() {
621 let node = div();
622 assert!(node.first_child().is_none());
623
624 let child = div();
625 node.append_child(&child);
626 assert_eq!(node.first_child().unwrap().as_ref(), child.as_ref());
627 }
628
629 #[test]
630 fn test_last_child() {
631 let node = div();
632 assert!(node.last_child().is_none());
633
634 let child1 = div();
635 node.append_child(&child1);
636 assert_eq!(node.last_child().unwrap().as_ref(), child1.as_ref());
637
638 let child2 = div();
639 node.append_child(&child2);
640 assert_eq!(node.last_child().unwrap().as_ref(), child2.as_ref());
641 }
642
643 #[test]
644 fn test_next_sibling() {
645 let node = div();
646 let child1 = div();
647 node.append_child(&child1);
648 assert!(child1.next_sibling().is_none());
649
650 let child2 = div();
651 node.append_child(&child2);
652 assert_eq!(child1.next_sibling().unwrap().as_ref(), child2.as_ref());
653 }
654
655 #[test]
656 fn test_previous_sibling() {
657 let node = div();
658 let child1 = div();
659 let child2 = div();
660
661 node.append_child(&child1);
662 assert!(child1.previous_sibling().is_none());
663 node.append_child(&child2);
664 assert_eq!(child2.previous_sibling().unwrap().as_ref(), child1.as_ref());
665 }
666
667 #[test]
668 fn test_node_name() {
669 assert_eq!(div().node_name(), "DIV");
670 assert_eq!(text("x").node_name(), "#text");
671 assert_eq!(document_fragment().node_name(), "#document-fragment");
672 assert_eq!(doc_type().node_name(), "svg:svg");
673 assert_eq!(processing_instruction("foo", "bar").node_name(), "foo");
674 }
675
676 #[test]
677 fn test_node_type() {
678 assert_eq!(div().node_type(), NodeType::Element);
679 assert_eq!(text("x").node_type(), NodeType::Text);
680 assert_eq!(processing_instruction("foo", "bar").node_type(), NodeType::ProcessingInstruction);
681 assert_eq!(comment("foo").node_type(), NodeType::Comment);
682 assert_eq!(document().node_type(), NodeType::Document);
683 assert_eq!(doc_type().node_type(), NodeType::DocumentType);
684 assert_eq!(document_fragment().node_type(), NodeType::DocumentFragment);
685 }
686
687 #[test]
688 fn test_node_value() {
689 let node = text("x");
690 assert_eq!(node.node_value().unwrap(), "x");
691 node.set_node_value(Some("y"));
692 assert_eq!(node.node_value().unwrap(), "y");
693
694 assert_eq!(processing_instruction("foo", "bar").node_value().unwrap(), "bar");
695 assert_eq!(comment("foo").node_value().unwrap(), "foo");
696
697 let node: Node = div();
698 assert!(node.node_value().is_none());
699 node.set_node_value(Some("foo"));
700 assert!(node.node_value().is_none());
701
702 assert!(document().node_value().is_none());
703 assert!(doc_type().node_value().is_none());
704 assert!(document_fragment().node_value().is_none());
705 }
706
707 #[test]
708 fn test_owner_document() {
709 let node = div();
710 assert_eq!(node.owner_document().unwrap().as_ref(), document().as_ref());
711 }
712
713 #[test]
714 fn test_parent_element() {
715 let node = div();
716 let child = div();
717 node.append_child(&child);
718 assert_eq!(child.parent_element().unwrap().as_ref(), node.as_ref());
719 }
720
721 #[test]
722 fn test_text_content() {
723 let node: Node = div();
724 assert_eq!(node.text_content().unwrap(), "");
725 node.append_child(&text("foo "));
726 assert_eq!(node.text_content().unwrap(), "foo ");
727 node.append_child(&text("foo"));
728 assert_eq!(node.text_content().unwrap(), "foo foo");
729 node.set_text_content("bar");
730 assert_eq!(node.text_content().unwrap(), "bar");
731 assert_eq!(node.child_nodes().len(), 1);
732 }
733
734 #[test]
735 fn test_base_uri() {
736 let node = div();
737 assert!(!node.base_uri().is_empty());
738 }
739
740 #[test]
741 fn test_has_child_nodes() {
742 let node = div();
743 assert!(!node.has_child_nodes());
744 node.append_child(&div());
745 assert!(node.has_child_nodes());
746 }
747
748 #[test]
749 fn test_child_nodes() {
750 let node = div();
751 let node_list = node.child_nodes();
752 assert_eq!(node_list.len(), 0);
753 assert!(node_list.iter().next().is_none());
754
755 let child1 = text("foo");
756 node.append_child(&child1);
757 let child2 = text("bar");
758 node.append_child(&child2);
759
760 let node_list = node.child_nodes();
761 assert_eq!(node_list.len(), 2);
762 let mut iter = node_list.iter();
763 assert_eq!(iter.next().unwrap().as_ref(), child1.as_ref());
764 assert_eq!(iter.next().unwrap().as_ref(), child2.as_ref());
765 }
766
767 #[test]
768 fn test_is_default_namespace() {
769 assert!(!div().is_default_namespace("foo"));
770 assert!(div().is_default_namespace("http://www.w3.org/1999/xhtml"));
771 }
772
773 #[test]
774 fn test_is_equal_node() {
775 let node1 = div();
776 let node2 = div();
777 assert!(node1.is_equal_node(&node2));
778
779 let child1 = div();
780 node1.append_child(&child1);
781 assert!(!node1.is_equal_node(&node2));
782
783 let child2 = div();
784 node2.append_child(&child2);
785 assert!(node1.is_equal_node(&node2));
786 }
787
788 #[test]
789 fn test_is_same_node() {
790 let node1 = div();
791 assert!(node1.is_same_node(&node1));
792 assert!(!node1.is_same_node(&div()));
793 }
794
795 #[test]
796 fn test_lookup_prefix() {
797 let xml = xml("x", "http://foo.com");
798 assert!(xml.lookup_prefix("bar").is_none());
799 assert_eq!(xml.lookup_prefix("http://foo.com").unwrap(), "x");
800 }
801
802 #[test]
803 fn test_lookup_namespace_uri() {
804 let xml = xml("x", "http://foo.com");
805 assert!(xml.lookup_namespace_uri("y").is_none());
806 assert_eq!(xml.lookup_namespace_uri("x").unwrap(), "http://foo.com");
807 }
808
809 #[test]
810 fn test_normalize() {
811 let node = div();
812 node.append_child(&text("test "));
813 node.append_child(&text("123"));
814 node.normalize();
815 assert_eq!(node.child_nodes().len(), 1);
816 let child_text = node.first_child().unwrap().text_content().unwrap();
817 assert_eq!(child_text, "test 123");
818 }
819
820 #[test]
821 fn option_node_is_constructible_from_value() {
822 let node: Value = js!( return document.createElement( "div" ) );
823 let opt_node: Option< Node > = node.clone().try_into().unwrap();
824 assert_eq!( opt_node.unwrap().as_ref(), node.as_ref() );
825 }
826
827 #[test]
828 fn empty_option_node_is_constructible_from_null_value() {
829 let empty_opt_node: Option< Node > = Value::Null.try_into().unwrap();
830 assert!( empty_opt_node.is_none() );
831 }
832
833 #[test]
834 fn empty_option_node_is_constructible_from_undefined_value() {
835 let empty_opt_node: Option< Node > = Value::Undefined.try_into().unwrap();
836 assert!( empty_opt_node.is_none() );
837 }
838
839 #[test]
840 fn option_node_from_numeric_value_results_in_an_error() {
841 let value: Value = 123_i32.into();
842 let empty_opt_node: Result< Option< Node >, _ > = value.try_into();
843 assert!( empty_opt_node.is_err() );
844 }
845
846 #[test]
847 fn from_html() {
848 let node = Node::from_html("<div>Some text, horray!</div>").unwrap();
849 let text = node.first_child().unwrap();
850
851 assert_eq!(node.node_name(), "DIV");
852 assert_eq!(node.last_child().unwrap(), text);
853
854 assert_eq!(text.node_name(), "#text");
855 assert_eq!(text.node_value().unwrap(), "Some text, horray!");
856 assert!(text.first_child().is_none());
857
858 let err = Node::from_html("<div>foo</div><div>bar</div>").unwrap_err();
859 assert!(format!("{}", err).contains("requires a single root node"));
860 assert!(Node::from_html("<di").is_err());
861 }
862}