mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
Implement insertBefore and reimplement appendChild.
This commit is contained in:
parent
2c3d5ec79f
commit
2ca1eede9a
5 changed files with 175 additions and 52 deletions
|
@ -57,8 +57,8 @@ interface Node /*: EventTarget*/ {
|
||||||
attribute DOMString? nodeValue;
|
attribute DOMString? nodeValue;
|
||||||
[SetterThrows, Pure]
|
[SetterThrows, Pure]
|
||||||
attribute DOMString? textContent;
|
attribute DOMString? textContent;
|
||||||
/*[Throws]
|
[Throws]
|
||||||
Node insertBefore(Node node, Node? child);*/ //XXXjdm we don't deal well with Node? parameters
|
Node insertBefore(Node node, Node? child);
|
||||||
[Throws]
|
[Throws]
|
||||||
Node appendChild(Node node);
|
Node appendChild(Node node);
|
||||||
[Throws]
|
[Throws]
|
||||||
|
|
|
@ -315,7 +315,7 @@ impl Document {
|
||||||
for title_child in child.children() {
|
for title_child in child.children() {
|
||||||
child.remove_child(title_child);
|
child.remove_child(title_child);
|
||||||
}
|
}
|
||||||
child.add_child(self.CreateTextNode(abstract_self, title));
|
child.AppendChild(self.CreateTextNode(abstract_self, title));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if !has_title {
|
if !has_title {
|
||||||
|
@ -325,8 +325,8 @@ impl Document {
|
||||||
let new_title = unsafe {
|
let new_title = unsafe {
|
||||||
Node::as_abstract_node(self.get_cx(), new_title)
|
Node::as_abstract_node(self.get_cx(), new_title)
|
||||||
};
|
};
|
||||||
new_title.add_child(self.CreateTextNode(abstract_self, title));
|
new_title.AppendChild(self.CreateTextNode(abstract_self, title));
|
||||||
node.add_child(new_title);
|
node.AppendChild(new_title);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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> {
|
impl<View> Iterator<AbstractNode<View>> for AbstractNodeChildrenIterator<View> {
|
||||||
fn next(&mut self) -> Option<AbstractNode<View>> {
|
fn next(&mut self) -> Option<AbstractNode<View>> {
|
||||||
let node = self.current_node;
|
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
|
// http://dom.spec.whatwg.org/#concept-node-replace-all
|
||||||
pub fn replace_all(&mut self,
|
pub fn replace_all(&mut self,
|
||||||
abstract_self: AbstractNode<ScriptView>,
|
abstract_self: AbstractNode<ScriptView>,
|
||||||
|
@ -740,8 +869,11 @@ impl Node<ScriptView> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn InsertBefore(&mut self, _node: AbstractNode<ScriptView>, _child: Option<AbstractNode<ScriptView>>) -> Fallible<AbstractNode<ScriptView>> {
|
pub fn InsertBefore(&self,
|
||||||
fail!("stub")
|
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) {
|
fn wait_until_safe_to_modify_dom(&self) {
|
||||||
|
@ -749,43 +881,11 @@ impl Node<ScriptView> {
|
||||||
document.document().wait_until_safe_to_modify_dom();
|
document.document().wait_until_safe_to_modify_dom();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn AppendChild(&mut self,
|
pub fn AppendChild(&self,
|
||||||
abstract_self: AbstractNode<ScriptView>,
|
abstract_self: AbstractNode<ScriptView>,
|
||||||
node: AbstractNode<ScriptView>) -> Fallible<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();
|
self.wait_until_safe_to_modify_dom();
|
||||||
|
return Node::pre_insert(node, abstract_self, None);
|
||||||
// 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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ReplaceChild(&mut self, _node: AbstractNode<ScriptView>, _child: AbstractNode<ScriptView>) -> Fallible<AbstractNode<ScriptView>> {
|
pub fn ReplaceChild(&mut self, _node: AbstractNode<ScriptView>, _child: AbstractNode<ScriptView>) -> Fallible<AbstractNode<ScriptView>> {
|
||||||
|
|
|
@ -477,7 +477,7 @@ pub fn parse_html(cx: *JSContext,
|
||||||
debug!("append child %x %x", cast::transmute(parent), cast::transmute(child));
|
debug!("append child %x %x", cast::transmute(parent), cast::transmute(child));
|
||||||
let parent: AbstractNode<ScriptView> = NodeWrapping::from_hubbub_node(parent);
|
let parent: AbstractNode<ScriptView> = NodeWrapping::from_hubbub_node(parent);
|
||||||
let child: AbstractNode<ScriptView> = NodeWrapping::from_hubbub_node(child);
|
let child: AbstractNode<ScriptView> = NodeWrapping::from_hubbub_node(child);
|
||||||
parent.add_child(child);
|
parent.AppendChild(child);
|
||||||
}
|
}
|
||||||
child
|
child
|
||||||
},
|
},
|
||||||
|
|
|
@ -145,13 +145,33 @@ pub trait TreeNodeRef<Node>: Clone {
|
||||||
/// Adds a new child to the end of this node's list of children.
|
/// Adds a new child to the end of this node's list of children.
|
||||||
///
|
///
|
||||||
/// Fails unless `new_child` is disconnected from the tree.
|
/// 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 this_node = self.mut_node();
|
||||||
let new_child_node = new_child.mut_node();
|
let new_child_node = new_child.mut_node();
|
||||||
assert!((get!(new_child_node, parent_node)).is_none());
|
assert!((get!(new_child_node, parent_node)).is_none());
|
||||||
assert!((get!(new_child_node, prev_sibling)).is_none());
|
assert!((get!(new_child_node, prev_sibling)).is_none());
|
||||||
assert!((get!(new_child_node, next_sibling)).is_none());
|
assert!((get!(new_child_node, next_sibling)).is_none());
|
||||||
|
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) {
|
match get!(this_node, last_child) {
|
||||||
None => set!(this_node, set_first_child, Some(new_child.clone())),
|
None => set!(this_node, set_first_child, Some(new_child.clone())),
|
||||||
Some(last_child) => {
|
Some(last_child) => {
|
||||||
|
@ -163,6 +183,9 @@ pub trait TreeNodeRef<Node>: 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()));
|
set!(new_child_node, set_parent_node, Some((*self).clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue