aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/script/dom/node.rs
diff options
context:
space:
mode:
authorBruno de Oliveira Abinader <bruno.d@partner.samsung.com>2014-01-06 18:32:55 -0400
committerBruno de Oliveira Abinader <bruno.d@partner.samsung.com>2014-01-16 10:25:17 -0400
commit3b82b11054645908c42ccd95f826322a2dc8a329 (patch)
treed279adfde8c70ea88cac30823f48230bac8b94ac /src/components/script/dom/node.rs
parent9b7425000b6b5df1e409699f8faead47eb9e41a8 (diff)
downloadservo-3b82b11054645908c42ccd95f826322a2dc8a329.tar.gz
servo-3b82b11054645908c42ccd95f826322a2dc8a329.zip
Implement Node::replaceChild()
Implements Node:replaceChild() according to spec below: http://dom.spec.whatwg.org/#concept-node-replace Closes #1430.
Diffstat (limited to 'src/components/script/dom/node.rs')
-rw-r--r--src/components/script/dom/node.rs226
1 files changed, 171 insertions, 55 deletions
diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs
index c9f8f06f7b7..1d7acb41906 100644
--- a/src/components/script/dom/node.rs
+++ b/src/components/script/dom/node.rs
@@ -258,6 +258,37 @@ impl AbstractNode {
AbstractNode::from_box(boxed_node)
}
}
+
+ pub fn is_inclusive_ancestor_of(&self, parent: AbstractNode) -> bool {
+ *self == parent || parent.ancestors().any(|ancestor| ancestor == *self)
+ }
+
+ pub fn is_parent_of(&self, child: AbstractNode) -> bool {
+ child.parent_node() == Some(*self)
+ }
+
+ fn followed_by_doctype(child: AbstractNode) -> bool {
+ let mut iter = child;
+ loop {
+ match iter.next_sibling() {
+ Some(sibling) => {
+ if sibling.is_doctype() {
+ return true;
+ }
+ iter = sibling;
+ },
+ None => return false
+ }
+ }
+ }
+
+ fn inclusively_followed_by_doctype(child: Option<AbstractNode>) -> bool {
+ match child {
+ Some(child) if child.is_doctype() => true,
+ Some(child) => AbstractNode::followed_by_doctype(child),
+ None => false
+ }
+ }
}
impl<'a> AbstractNode {
@@ -528,7 +559,7 @@ impl AbstractNode {
}
pub fn ReplaceChild(self, node: AbstractNode, child: AbstractNode) -> Fallible<AbstractNode> {
- self.mut_node().ReplaceChild(node, child)
+ self.node().ReplaceChild(self, node, child)
}
pub fn RemoveChild(self, node: AbstractNode) -> Fallible<AbstractNode> {
@@ -1041,87 +1072,49 @@ impl Node {
// http://dom.spec.whatwg.org/#concept-node-pre-insert
fn pre_insert(node: AbstractNode, parent: AbstractNode, child: Option<AbstractNode>)
-> Fallible<AbstractNode> {
- fn is_inclusive_ancestor_of(node: AbstractNode, parent: AbstractNode) -> bool {
- node == parent || parent.ancestors().any(|ancestor| ancestor == node)
- }
-
// Step 1.
match parent.type_id() {
DocumentNodeTypeId(..) |
DocumentFragmentNodeTypeId |
ElementNodeTypeId(..) => (),
- _ => {
- return Err(HierarchyRequest);
- },
+ _ => return Err(HierarchyRequest)
}
// Step 2.
- if is_inclusive_ancestor_of(node, parent) {
+ if node.is_inclusive_ancestor_of(parent) {
return Err(HierarchyRequest);
}
// Step 3.
match child {
- Some(child) => {
- if child.parent_node() != Some(parent) {
- return Err(NotFound);
- }
- },
- None => (),
+ Some(child) if !parent.is_parent_of(child) => return Err(NotFound),
+ _ => ()
}
- // Step 4.
- match node.type_id() {
- DocumentFragmentNodeTypeId |
- DoctypeNodeTypeId |
- ElementNodeTypeId(_) |
- TextNodeTypeId |
- // ProcessingInstructionNodeTypeId |
- CommentNodeTypeId => (),
- DocumentNodeTypeId(..) => return Err(HierarchyRequest),
- }
-
- // Step 5.
+ // Step 4-5.
match node.type_id() {
TextNodeTypeId => {
match node.parent_node() {
Some(parent) if parent.is_document() => return Err(HierarchyRequest),
_ => ()
}
- },
+ }
DoctypeNodeTypeId => {
match node.parent_node() {
Some(parent) if !parent.is_document() => return Err(HierarchyRequest),
_ => ()
}
- },
- _ => (),
+ }
+ DocumentFragmentNodeTypeId |
+ ElementNodeTypeId(_) |
+ // ProcessingInstructionNodeTypeId |
+ CommentNodeTypeId => (),
+ DocumentNodeTypeId(..) => return Err(HierarchyRequest)
}
// Step 6.
match parent.type_id() {
DocumentNodeTypeId(_) => {
- fn inclusively_followed_by_doctype(child: Option<AbstractNode>) -> bool{
- match child {
- Some(child) if child.is_doctype() => true,
- Some(child) => {
- let mut iter = child;
- loop {
- match iter.next_sibling() {
- Some(sibling) => {
- if sibling.is_doctype() {
- return true;
- }
- iter = sibling;
- },
- None => return false,
- }
- }
- },
- None => false,
- }
- }
-
match node.type_id() {
// Step 6.1
DocumentFragmentNodeTypeId => {
@@ -1138,7 +1131,7 @@ impl Node {
if parent.child_elements().len() > 0 {
return Err(HierarchyRequest);
}
- if inclusively_followed_by_doctype(child) {
+ if AbstractNode::inclusively_followed_by_doctype(child) {
return Err(HierarchyRequest);
}
},
@@ -1153,7 +1146,7 @@ impl Node {
if parent.child_elements().len() > 0 {
return Err(HierarchyRequest);
}
- if inclusively_followed_by_doctype(child) {
+ if AbstractNode::inclusively_followed_by_doctype(child) {
return Err(HierarchyRequest);
}
},
@@ -1362,9 +1355,132 @@ impl Node {
Node::pre_insert(node, abstract_self, None)
}
- pub fn ReplaceChild(&mut self, _node: AbstractNode, _child: AbstractNode)
+ // http://dom.spec.whatwg.org/#concept-node-replace
+ pub fn ReplaceChild(&self, parent: AbstractNode, node: AbstractNode, child: AbstractNode)
-> Fallible<AbstractNode> {
- fail!("stub")
+ // Step 1.
+ match parent.type_id() {
+ DocumentNodeTypeId(..) |
+ DocumentFragmentNodeTypeId |
+ ElementNodeTypeId(..) => (),
+ _ => return Err(HierarchyRequest)
+ }
+
+ // Step 2.
+ if node.is_inclusive_ancestor_of(parent) {
+ return Err(HierarchyRequest);
+ }
+
+ // Step 3.
+ if !parent.is_parent_of(child) {
+ return Err(NotFound);
+ }
+
+ // Step 4-5.
+ match node.type_id() {
+ TextNodeTypeId if parent.is_document() => return Err(HierarchyRequest),
+ DoctypeNodeTypeId if !parent.is_document() => return Err(HierarchyRequest),
+ DocumentFragmentNodeTypeId |
+ DoctypeNodeTypeId |
+ ElementNodeTypeId(..) |
+ TextNodeTypeId |
+ // ProcessingInstructionNodeTypeId |
+ CommentNodeTypeId => (),
+ DocumentNodeTypeId(..) => return Err(HierarchyRequest)
+ }
+
+ // Step 6.
+ match parent.type_id() {
+ DocumentNodeTypeId(..) => {
+ match node.type_id() {
+ // Step 6.1
+ DocumentFragmentNodeTypeId => {
+ // Step 6.1.1(b)
+ if node.children().any(|c| c.is_text()) {
+ return Err(HierarchyRequest);
+ }
+ match node.child_elements().len() {
+ 0 => (),
+ // Step 6.1.2
+ 1 => {
+ if parent.child_elements().any(|c| c != child) {
+ return Err(HierarchyRequest);
+ }
+ if AbstractNode::followed_by_doctype(child) {
+ return Err(HierarchyRequest);
+ }
+ },
+ // Step 6.1.1(a)
+ _ => return Err(HierarchyRequest)
+ }
+ },
+ // Step 6.2
+ ElementNodeTypeId(..) => {
+ if parent.child_elements().any(|c| c != child) {
+ return Err(HierarchyRequest);
+ }
+ if AbstractNode::followed_by_doctype(child) {
+ return Err(HierarchyRequest);
+ }
+ },
+ // Step 6.3
+ DoctypeNodeTypeId => {
+ if parent.children().any(|c| c.is_doctype() && c != child) {
+ return Err(HierarchyRequest);
+ }
+ if parent.children()
+ .take_while(|&c| c != child)
+ .any(|c| c.is_element()) {
+ return Err(HierarchyRequest);
+ }
+ },
+ TextNodeTypeId |
+ // ProcessingInstructionNodeTypeId |
+ CommentNodeTypeId => (),
+ DocumentNodeTypeId(..) => unreachable!()
+ }
+ },
+ _ => ()
+ }
+
+ // Ok if not caught by previous error checks.
+ if node == child {
+ return Ok(child);
+ }
+
+ // Step 7-8.
+ let reference_child = if child.next_sibling() != Some(node) {
+ child.next_sibling()
+ } else {
+ node.next_sibling()
+ };
+
+ // Step 9.
+ Node::adopt(node, parent.node().owner_doc());
+
+ {
+ let suppress_observers = true;
+
+ // Step 10.
+ Node::remove(child, parent, suppress_observers);
+
+ // Step 11.
+ Node::insert(node, parent, reference_child, suppress_observers);
+ }
+
+ // Step 12-14.
+ // Step 13: mutation records.
+ child.node_removed();
+ if node.type_id() == DocumentFragmentNodeTypeId {
+ for child_node in node.children() {
+ child_node.node_inserted();
+ }
+ } else {
+ node.node_inserted();
+ }
+
+ // Step 15.
+ Ok(child)
}
pub fn RemoveChild(&self, abstract_self: AbstractNode, node: AbstractNode)