auto merge of #1431 : brunoabinader/servo/document-body, r=jdm

Implement Document's 'body' attribute (getter and setter). Proper
implementation of setter requires Node::ReplaceChild(), which is
currently a stub and will be done on a later step.

This patch is for:
https://github.com/mozilla/servo/issues/1428
This commit is contained in:
bors-servo 2013-12-20 07:28:07 -08:00
commit 34746fe974
5 changed files with 140 additions and 3 deletions

View file

@ -156,6 +156,7 @@ DOMInterfaces = {
'createElement',
'createTextNode',
'title',
'body',
],
},

View file

@ -100,7 +100,7 @@ partial interface Document {
[SetterThrows]
attribute DOMString title;
// attribute DOMString dir;
//(HTML only) attribute HTMLElement? body;
attribute HTMLElement? body;
//(HTML only)readonly attribute HTMLHeadElement? head;
//(HTML only)readonly attribute HTMLCollection images;
//(HTML only)readonly attribute HTMLCollection embeds;

View file

@ -5,12 +5,12 @@
use dom::comment::Comment;
use dom::bindings::codegen::DocumentBinding;
use dom::bindings::utils::{Reflectable, Reflector, Traceable, reflect_dom_object};
use dom::bindings::utils::{ErrorResult, Fallible, NotSupported, InvalidCharacter};
use dom::bindings::utils::{ErrorResult, Fallible, NotSupported, InvalidCharacter, HierarchyRequest};
use dom::bindings::utils::DOMString;
use dom::bindings::utils::{xml_name_type, InvalidXMLName};
use dom::documentfragment::DocumentFragment;
use dom::element::{Element};
use dom::element::{HTMLHeadElementTypeId, HTMLTitleElementTypeId};
use dom::element::{HTMLHtmlElementTypeId, HTMLHeadElementTypeId, HTMLTitleElementTypeId, HTMLBodyElementTypeId, HTMLFrameSetElementTypeId};
use dom::event::{AbstractEvent, Event};
use dom::htmlcollection::HTMLCollection;
use dom::htmldocument::HTMLDocument;
@ -295,6 +295,63 @@ impl Document {
Ok(())
}
fn get_html_element(&self) -> Option<AbstractNode> {
do self.GetDocumentElement().filtered |root| {
match root.type_id() {
ElementNodeTypeId(HTMLHtmlElementTypeId) => true,
_ => false
}
}
}
pub fn GetBody(&self, _: AbstractDocument) -> Option<AbstractNode> {
match self.get_html_element() {
None => None,
Some(root) => {
do root.children().find |child| {
match child.type_id() {
ElementNodeTypeId(HTMLBodyElementTypeId) |
ElementNodeTypeId(HTMLFrameSetElementTypeId) => true,
_ => false
}
}
}
}
}
// http://www.whatwg.org/specs/web-apps/current-work/#dom-document-body
pub fn SetBody(&self, abstract_self: AbstractDocument, new_body: Option<AbstractNode>) -> ErrorResult {
// Step 1.
match new_body {
Some(node) => {
match node.type_id() {
ElementNodeTypeId(HTMLBodyElementTypeId) | ElementNodeTypeId(HTMLFrameSetElementTypeId) => {}
_ => return Err(HierarchyRequest)
}
}
None => return Err(HierarchyRequest)
}
// Step 2.
let old_body: Option<AbstractNode> = self.GetBody(abstract_self);
if old_body == new_body {
return Ok(());
}
// Step 3.
match self.get_html_element() {
// Step 4.
None => return Err(HierarchyRequest),
Some(root) => {
match old_body {
Some(child) => { root.ReplaceChild(new_body.unwrap(), child); }
None => { root.AppendChild(new_body.unwrap()); }
}
}
}
Ok(())
}
pub fn GetElementsByName(&self, name: DOMString) -> @mut HTMLCollection {
self.createHTMLCollection(|elem|
elem.get_attr(None, "name").is_some() && eq_slice(elem.get_attr(None, "name").unwrap(), name))

View file

@ -496,6 +496,10 @@ impl AbstractNode {
self.node().AppendChild(self, node)
}
pub fn ReplaceChild(self, node: AbstractNode, child: AbstractNode) -> Fallible<AbstractNode> {
self.mut_node().ReplaceChild(node, child)
}
pub fn RemoveChild(self, node: AbstractNode) -> Fallible<AbstractNode> {
self.node().RemoveChild(self, node)
}

View file

@ -0,0 +1,75 @@
<html>
<head>
<script src="harness.js"></script>
</head>
<body>
<script>
// test1: existing document's body
{
isnot(document.body, null, "test1-0, existing document's body");
is_a(document.body, HTMLBodyElement, "test1-1, exising document's body");
is(document.body && document.body.tagName, "BODY", "test1-2, existing document's body");
}
/* TODO: Depends on https://github.com/mozilla/servo/issues/1430
// test2: replace document's body with new body
{
let new_body = document.createElement("body");
isnot(new_body, null, "test2-0, replace document's body with new body");
document.body = new_body;
is(new_body, document.body, "test2-1, replace document's body with new body");
}
// test3: replace document's body with new frameset
{
let new_frameset = document.createElement("frameset");
isnot(new_frameset, null, "test2-0, replace document's body with new frameset");
document.body = new_frameset;
is(new_frameset, document.body, "test2-1, replace document's body with new frameset");
}
*/
// test4: append an invalid element to a new document
{
let new_document = new Document();
new_document.appendChild(new_document.createElement("html"));
let new_div = new_document.createElement("div");
isnot(new_div, null, "test4-0, append an invalid element to a new document");
new_document.body = new_div;
is(new_document.body, null, "test4-1, append an invalid element to a new document");
}
// test5: append body to a new document
{
let new_document = new Document();
new_document.appendChild(new_document.createElement("html"));
let new_body = new_document.createElement("body");
isnot(new_body, null, "test5-0, append body to a new document");
is_a(new_body, HTMLBodyElement, "test5-1, append body to a new document");
is(new_body && new_body.tagName, "BODY", "test5-2, append body to a new document");
new_document.body = new_body;
is(new_document.body, new_body, "test5-3, append body to a new document");
}
// test6: append frameset to a new document
{
let new_document = new Document();
new_document.appendChild(new_document.createElement("html"));
let new_frameset = new_document.createElement("frameset");
isnot(new_frameset, null, "test6-0, append frameset to a new document");
is_a(new_frameset, HTMLFrameSetElement, "test6-1, append frameset to a new document");
is(new_frameset && new_frameset.tagName, "FRAMESET", "test6-2, append frameset to a new document");
new_document.body = new_frameset;
is(new_document.body, new_frameset, "test6-3, append frameset to a new document");
}
finish();
</script>
</body>
</html>