aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/components/script/dom/bindings/codegen/Node.webidl4
-rw-r--r--src/components/script/dom/document.rs6
-rw-r--r--src/components/script/dom/node.rs172
-rw-r--r--src/components/script/html/hubbub_html_parser.rs2
-rw-r--r--src/components/util/tree.rs45
5 files changed, 176 insertions, 53 deletions
diff --git a/src/components/script/dom/bindings/codegen/Node.webidl b/src/components/script/dom/bindings/codegen/Node.webidl
index 5e099c217a4..5f32ff93f67 100644
--- a/src/components/script/dom/bindings/codegen/Node.webidl
+++ b/src/components/script/dom/bindings/codegen/Node.webidl
@@ -57,8 +57,8 @@ interface Node /*: EventTarget*/ {
attribute DOMString? nodeValue;
[SetterThrows, Pure]
attribute DOMString? textContent;
- /*[Throws]
- Node insertBefore(Node node, Node? child);*/ //XXXjdm we don't deal well with Node? parameters
+ [Throws]
+ Node insertBefore(Node node, Node? child);
[Throws]
Node appendChild(Node node);
[Throws]
diff --git a/src/components/script/dom/document.rs b/src/components/script/dom/document.rs
index d0a40235878..d2bee663740 100644
--- a/src/components/script/dom/document.rs
+++ b/src/components/script/dom/document.rs
@@ -315,7 +315,7 @@ impl Document {
for title_child in child.children() {
child.remove_child(title_child);
}
- child.add_child(self.CreateTextNode(abstract_self, title));
+ child.AppendChild(self.CreateTextNode(abstract_self, title));
break;
}
if !has_title {
@@ -325,8 +325,8 @@ impl Document {
let new_title = unsafe {
Node::as_abstract_node(self.get_cx(), new_title)
};
- new_title.add_child(self.CreateTextNode(abstract_self, title));
- node.add_child(new_title);
+ new_title.AppendChild(self.CreateTextNode(abstract_self, title));
+ node.AppendChild(new_title);
}
break;
}
diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs
index 680f6fbab19..0929060086f 100644
--- a/src/components/script/dom/node.rs
+++ b/src/components/script/dom/node.rs
@@ -455,6 +455,12 @@ impl<'self, View> AbstractNode<View> {
}
}
+impl AbstractNode<ScriptView> {
+ pub fn AppendChild(self, node: AbstractNode<ScriptView>) -> Fallible<AbstractNode<ScriptView>> {
+ self.node().AppendChild(self, node)
+ }
+}
+
impl<View> Iterator<AbstractNode<View>> for AbstractNodeChildrenIterator<View> {
fn next(&mut self) -> Option<AbstractNode<View>> {
let node = self.current_node;
@@ -691,6 +697,129 @@ impl Node<ScriptView> {
}
}
+ // http://dom.spec.whatwg.org/#concept-node-adopt
+ pub fn adopt(node: AbstractNode<ScriptView>,
+ document: AbstractDocument) {
+ // Step 1.
+ match node.parent_node() {
+ Some(parent) => parent.remove_child(node),
+ None => (),
+ }
+
+ // Step 2.
+ if node.node().owner_doc() != document {
+ for descendant in node.traverse_preorder() {
+ descendant.mut_node().set_owner_doc(document);
+ }
+ }
+
+ // Step 3.
+ // If node is an element, it is _affected by a base URL change_.
+ }
+
+ // http://dom.spec.whatwg.org/#concept-node-pre-insert
+ pub fn pre_insert(node: AbstractNode<ScriptView>,
+ parent: AbstractNode<ScriptView>,
+ child: Option<AbstractNode<ScriptView>>) -> Fallible<AbstractNode<ScriptView>> {
+ fn is_inclusive_ancestor_of(node: AbstractNode<ScriptView>,
+ parent: AbstractNode<ScriptView>) -> bool {
+ node == parent || parent.ancestors().any(|ancestor| ancestor == node)
+ }
+ // Step 1.
+ match parent.type_id() {
+ // DocumentNodeTypeId |
+ DocumentFragmentNodeTypeId |
+ ElementNodeTypeId(*) => (),
+ _ => {
+ return Err(HierarchyRequest);
+ },
+ }
+
+ // Step 2.
+ if is_inclusive_ancestor_of(node, parent) {
+ return Err(HierarchyRequest);
+ }
+
+ // Step 3.
+ match child {
+ Some(child) => {
+ if child.parent_node() != Some(parent) {
+ return Err(NotFound);
+ }
+ },
+ None => (),
+ }
+
+ // Step 4.
+ match node.type_id() {
+ DocumentFragmentNodeTypeId |
+ DoctypeNodeTypeId |
+ ElementNodeTypeId(_) |
+ TextNodeTypeId |
+ // ProcessingInstructionNodeTypeId |
+ CommentNodeTypeId => (),
+ /*_ => { XXX #838
+ return Err(HierarchyRequest);
+ },*/
+ }
+
+ // Step 5.
+ match node.type_id() {
+ TextNodeTypeId => {
+ if false { // XXX #838
+ return Err(HierarchyRequest);
+ }
+ },
+ DoctypeNodeTypeId => {
+ if true { // XXX #838
+ return Err(HierarchyRequest);
+ }
+ },
+ _ => (),
+ }
+
+ // Step 6.
+ // XXX #838
+
+ // Step 7-8.
+ let referenceChild = if child != Some(node) {
+ child
+ } else {
+ node.next_sibling()
+ };
+
+ // Step 9.
+ Node::adopt(node, parent.node().owner_doc());
+
+ // Step 10.
+ Node::insert(node, parent, referenceChild, false);
+
+ // Step 11.
+ return Ok(node)
+ }
+
+ pub fn insert(node: AbstractNode<ScriptView>,
+ parent: AbstractNode<ScriptView>,
+ child: Option<AbstractNode<ScriptView>>,
+ _suppressObserversFlag: bool) {
+ // Step 1-3: ranges.
+ // Step 4.
+ let nodes = match node.type_id() {
+ DocumentFragmentNodeTypeId => node.children().collect(),
+ _ => ~[node],
+ };
+
+ // Step 5: DocumentFragment, mutation records.
+ // Step 6: DocumentFragment.
+ // Step 7: mutation records.
+ // Step 8.
+ for node in nodes.iter() {
+ parent.add_child(*node, child);
+ }
+
+ // Step 9: _node is inserted_.
+ }
+
// http://dom.spec.whatwg.org/#concept-node-replace-all
pub fn replace_all(&mut self,
abstract_self: AbstractNode<ScriptView>,
@@ -740,8 +869,11 @@ impl Node<ScriptView> {
Ok(())
}
- pub fn InsertBefore(&mut self, _node: AbstractNode<ScriptView>, _child: Option<AbstractNode<ScriptView>>) -> Fallible<AbstractNode<ScriptView>> {
- fail!("stub")
+ pub fn InsertBefore(&self,
+ node: AbstractNode<ScriptView>,
+ child: Option<AbstractNode<ScriptView>>) -> Fallible<AbstractNode<ScriptView>> {
+ self.wait_until_safe_to_modify_dom();
+ return Node::pre_insert(node, node, child);
}
fn wait_until_safe_to_modify_dom(&self) {
@@ -749,43 +881,11 @@ impl Node<ScriptView> {
document.document().wait_until_safe_to_modify_dom();
}
- pub fn AppendChild(&mut self,
+ pub fn AppendChild(&self,
abstract_self: AbstractNode<ScriptView>,
node: AbstractNode<ScriptView>) -> Fallible<AbstractNode<ScriptView>> {
- fn is_hierarchy_request_err(this_node: AbstractNode<ScriptView>,
- new_child: AbstractNode<ScriptView>) -> bool {
- if new_child.is_doctype() {
- return true;
- }
- if !this_node.is_element() {
- // FIXME: This should also work for Document and DocumentFragments when they inherit from node.
- // per jgraham
- return true;
- }
- if this_node == new_child {
- return true;
- }
- for ancestor in this_node.ancestors() {
- if ancestor == new_child {
- return true;
- }
- }
- false
- }
-
- if is_hierarchy_request_err(abstract_self, node) {
- return Err(HierarchyRequest);
- }
-
- // TODO: Should we handle WRONG_DOCUMENT_ERR here?
-
self.wait_until_safe_to_modify_dom();
-
- // If the node already exists it is removed from current parent node.
- node.parent_node().map(|parent| parent.remove_child(node));
- abstract_self.add_child(node);
- node.mut_node().add_to_doc(node, self.owner_doc());
- Ok(node)
+ return Node::pre_insert(node, abstract_self, None);
}
pub fn ReplaceChild(&mut self, _node: AbstractNode<ScriptView>, _child: AbstractNode<ScriptView>) -> Fallible<AbstractNode<ScriptView>> {
diff --git a/src/components/script/html/hubbub_html_parser.rs b/src/components/script/html/hubbub_html_parser.rs
index cbcab035578..77693cb6522 100644
--- a/src/components/script/html/hubbub_html_parser.rs
+++ b/src/components/script/html/hubbub_html_parser.rs
@@ -477,7 +477,7 @@ pub fn parse_html(cx: *JSContext,
debug!("append child %x %x", cast::transmute(parent), cast::transmute(child));
let parent: AbstractNode<ScriptView> = NodeWrapping::from_hubbub_node(parent);
let child: AbstractNode<ScriptView> = NodeWrapping::from_hubbub_node(child);
- parent.add_child(child);
+ parent.AppendChild(child);
}
child
},
diff --git a/src/components/util/tree.rs b/src/components/util/tree.rs
index 4c6cfaa4962..f2a80342655 100644
--- a/src/components/util/tree.rs
+++ b/src/components/util/tree.rs
@@ -145,24 +145,47 @@ pub trait TreeNodeRef<Node>: Clone {
/// Adds a new child to the end of this node's list of children.
///
/// Fails unless `new_child` is disconnected from the tree.
- fn add_child(&self, new_child: Self) {
+ fn add_child(&self, new_child: Self, before: Option<Self>) {
let this_node = self.mut_node();
let new_child_node = new_child.mut_node();
assert!((get!(new_child_node, parent_node)).is_none());
assert!((get!(new_child_node, prev_sibling)).is_none());
assert!((get!(new_child_node, next_sibling)).is_none());
-
- match get!(this_node, last_child) {
- None => set!(this_node, set_first_child, Some(new_child.clone())),
- Some(last_child) => {
- let last_child_node = last_child.mut_node();
- assert!((get!(last_child_node, next_sibling)).is_none());
- set!(last_child_node, set_next_sibling, Some(new_child.clone()));
- set!(new_child_node, set_prev_sibling, Some(last_child.clone()));
- }
+ match before {
+ Some(before) => {
+ let before_node = before.mut_node();
+ // XXX Should assert that parent is self.
+ assert!((get!(before_node, parent_node)).is_some());
+ set!(before_node, set_prev_sibling, Some(new_child.clone()));
+ set!(new_child_node, set_next_sibling, Some(before.clone()));
+ match get!(before_node, prev_sibling) {
+ None => {
+ // XXX Should assert that before is the first child of
+ // self.
+ set!(this_node, set_first_child, Some(new_child.clone()));
+ },
+ Some(prev_sibling) => {
+ let prev_sibling_node = prev_sibling.mut_node();
+ set!(prev_sibling_node, set_next_sibling, Some(new_child.clone()));
+ set!(new_child_node, set_prev_sibling, Some(prev_sibling.clone()));
+ },
+ }
+ },
+ None => {
+ match get!(this_node, last_child) {
+ None => set!(this_node, set_first_child, Some(new_child.clone())),
+ Some(last_child) => {
+ let last_child_node = last_child.mut_node();
+ assert!((get!(last_child_node, next_sibling)).is_none());
+ set!(last_child_node, set_next_sibling, Some(new_child.clone()));
+ set!(new_child_node, set_prev_sibling, Some(last_child.clone()));
+ }
+ }
+
+ set!(this_node, set_last_child, Some(new_child.clone()));
+ },
}
- set!(this_node, set_last_child, Some(new_child.clone()));
set!(new_child_node, set_parent_node, Some((*self).clone()));
}