diff --git a/servo/components/script/dom/node.rs b/servo/components/script/dom/node.rs index 5df4d633f32c..1f6a681e5827 100644 --- a/servo/components/script/dom/node.rs +++ b/servo/components/script/dom/node.rs @@ -802,40 +802,54 @@ impl<'a> NodeHelpers for &'a Node { // https://dom.spec.whatwg.org/#dom-childnode-before fn before(self, nodes: Vec) -> ErrorResult { - match self.parent_node.get() { - None => { - // Step 1. - Ok(()) - }, - Some(ref parent_node) => { - // Step 2. - let doc = self.owner_doc(); - let node = try!(doc.r().node_from_nodes_and_strings(nodes)); - // Step 3. - Node::pre_insert(node.r(), parent_node.root().r(), - Some(self)).map(|_| ()) - }, - } + // Step 1. + let parent = &self.parent_node; + + // Step 2. + let parent = match parent.get() { + None => return Ok(()), + Some(ref parent) => parent.root(), + }; + + // Step 3. + let viable_previous_sibling = first_node_not_in(self.preceding_siblings(), &nodes); + + // Step 4. + let node = try!(self.owner_doc().node_from_nodes_and_strings(nodes)); + + // Step 5. + let viable_previous_sibling = match viable_previous_sibling { + Some(ref viable_previous_sibling) => viable_previous_sibling.next_sibling.get(), + None => parent.first_child.get(), + }.map(|s| s.root()); + + // Step 6. + try!(Node::pre_insert(&node, &parent, viable_previous_sibling.r())); + + Ok(()) } // https://dom.spec.whatwg.org/#dom-childnode-after fn after(self, nodes: Vec) -> ErrorResult { - match self.parent_node.get() { - None => { - // Step 1. - Ok(()) - }, - Some(ref parent_node) => { - // Step 2. - let doc = self.owner_doc(); - let node = try!(doc.r().node_from_nodes_and_strings(nodes)); - // Step 3. - // FIXME(https://github.com/servo/servo/issues/5720) - let next_sibling = self.next_sibling.get().map(Root::from_rooted); - Node::pre_insert(node.r(), parent_node.root().r(), - next_sibling.r()).map(|_| ()) - }, - } + // Step 1. + let parent = &self.parent_node; + + // Step 2. + let parent = match parent.get() { + None => return Ok(()), + Some(ref parent) => parent.root(), + }; + + // Step 3. + let viable_next_sibling = first_node_not_in(self.following_siblings(), &nodes); + + // Step 4. + let node = try!(self.owner_doc().node_from_nodes_and_strings(nodes)); + + // Step 5. + try!(Node::pre_insert(&node, &parent, viable_next_sibling.r())); + + Ok(()) } // https://dom.spec.whatwg.org/#dom-childnode-replacewith @@ -1028,6 +1042,21 @@ impl<'a> NodeHelpers for &'a Node { } } + +/// Iterate through `nodes` until we find a `Node` that is not in `not_in` +fn first_node_not_in(mut nodes: I, not_in: &[NodeOrString]) -> Option> + where I: Iterator> +{ + nodes.find(|node| { + not_in.iter().all(|n| { + match n { + &NodeOrString::eNode(ref n) => n != node, + _ => true, + } + }) + }) +} + /// If the given untrusted node address represents a valid DOM node in the given runtime, /// returns it. #[allow(unsafe_code)]