Implement Document.createElementNS.

This commit is contained in:
Daniel Glazman 2014-04-07 10:14:01 +02:00 committed by Ms2ger
parent 86c83f7bfc
commit 4b0da08573
6 changed files with 101 additions and 8 deletions

View file

@ -33,6 +33,7 @@ DOMInterfaces = {
'createComment', 'createComment',
'createDocumentFragment', 'createDocumentFragment',
'createElement', 'createElement',
'createElementNS',
'createProcessingInstruction', 'createProcessingInstruction',
'createTextNode', 'createTextNode',
'embeds', 'embeds',
@ -95,6 +96,7 @@ DOMInterfaces = {
'contains', 'contains',
'insertBefore', 'insertBefore',
'isEqualNode', 'isEqualNode',
'namespaceURI',
'nodeName', 'nodeName',
'nodeValue', 'nodeValue',
'normalize', 'normalize',

View file

@ -9,13 +9,13 @@ use dom::bindings::codegen::InheritTypes::{DocumentTypeCast, HTMLHtmlElementCast
use dom::bindings::codegen::DocumentBinding; use dom::bindings::codegen::DocumentBinding;
use dom::bindings::js::JS; use dom::bindings::js::JS;
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::bindings::error::{ErrorResult, Fallible, NotSupported, InvalidCharacter, HierarchyRequest}; use dom::bindings::error::{ErrorResult, Fallible, NotSupported, InvalidCharacter, HierarchyRequest, NamespaceError};
use dom::bindings::utils::{xml_name_type, InvalidXMLName}; use dom::bindings::utils::{xml_name_type, InvalidXMLName, Name, QName};
use dom::comment::Comment; use dom::comment::Comment;
use dom::documentfragment::DocumentFragment; use dom::documentfragment::DocumentFragment;
use dom::documenttype::DocumentType; use dom::documenttype::DocumentType;
use dom::domimplementation::DOMImplementation; use dom::domimplementation::DOMImplementation;
use dom::element::{Element, AttributeHandlers}; use dom::element::{Element, AttributeHandlers, get_attribute_parts};
use dom::element::{HTMLHtmlElementTypeId, HTMLHeadElementTypeId, HTMLTitleElementTypeId}; use dom::element::{HTMLHtmlElementTypeId, HTMLHeadElementTypeId, HTMLTitleElementTypeId};
use dom::element::{HTMLBodyElementTypeId, HTMLFrameSetElementTypeId}; use dom::element::{HTMLBodyElementTypeId, HTMLFrameSetElementTypeId};
use dom::event::Event; use dom::event::Event;
@ -37,8 +37,9 @@ use dom::location::Location;
use html::hubbub_html_parser::build_element_from_tag; use html::hubbub_html_parser::build_element_from_tag;
use hubbub::hubbub::{QuirksMode, NoQuirks, LimitedQuirks, FullQuirks}; use hubbub::hubbub::{QuirksMode, NoQuirks, LimitedQuirks, FullQuirks};
use layout_interface::{DocumentDamageLevel, ContentChangedDocumentDamage}; use layout_interface::{DocumentDamageLevel, ContentChangedDocumentDamage};
use servo_util::namespace;
use servo_util::namespace::{Namespace, Null}; use servo_util::namespace::{Namespace, Null};
use servo_util::str::DOMString; use servo_util::str::{DOMString, null_str_as_empty_ref};
use collections::hashmap::HashMap; use collections::hashmap::HashMap;
use js::jsapi::JSContext; use js::jsapi::JSContext;
@ -263,6 +264,52 @@ impl Document {
Ok(build_element_from_tag(local_name, abstract_self)) Ok(build_element_from_tag(local_name, abstract_self))
} }
// http://dom.spec.whatwg.org/#dom-document-createelementns
pub fn CreateElementNS(&self, abstract_self: &JS<Document>,
namespace: Option<DOMString>,
qualified_name: DOMString) -> Fallible<JS<Element>> {
let ns = Namespace::from_str(null_str_as_empty_ref(&namespace));
match xml_name_type(qualified_name) {
InvalidXMLName => {
debug!("Not a valid element name");
return Err(InvalidCharacter);
},
Name => {
debug!("Not a valid qualified element name");
return Err(NamespaceError);
},
QName => {}
}
let (prefix_from_qname, local_name_from_qname) = get_attribute_parts(qualified_name);
match (&ns, prefix_from_qname, local_name_from_qname.as_slice()) {
// throw if prefix is not null and namespace is null
(&namespace::Null, Some(_), _) => {
debug!("Namespace can't be null with a non-null prefix");
return Err(NamespaceError);
},
// throw if prefix is "xml" and namespace is not the XML namespace
(_, Some(ref prefix), _) if "xml" == *prefix && ns != namespace::XML => {
debug!("Namespace must be the xml namespace if the prefix is 'xml'");
return Err(NamespaceError);
},
// throw if namespace is the XMLNS namespace and neither qualifiedName nor prefix is "xmlns"
(&namespace::XMLNS, Some(ref prefix), _) if "xmlns" == *prefix => {},
(&namespace::XMLNS, _, "xmlns") => {},
(&namespace::XMLNS, _, _) => {
debug!("The prefix or the qualified name must be 'xmlns' if namespace is the XMLNS namespace ");
return Err(NamespaceError);
},
_ => {}
}
if ns == namespace::HTML {
Ok(build_element_from_tag(local_name_from_qname, abstract_self))
} else {
Ok(Element::new(local_name_from_qname, ns, abstract_self))
}
}
// http://dom.spec.whatwg.org/#dom-document-createdocumentfragment // http://dom.spec.whatwg.org/#dom-document-createdocumentfragment
pub fn CreateDocumentFragment(&self, abstract_self: &JS<Document>) -> JS<DocumentFragment> { pub fn CreateDocumentFragment(&self, abstract_self: &JS<Document>) -> JS<DocumentFragment> {
DocumentFragment::new(abstract_self) DocumentFragment::new(abstract_self)

View file

@ -6,6 +6,7 @@
use dom::attr::Attr; use dom::attr::Attr;
use dom::attrlist::AttrList; use dom::attrlist::AttrList;
use dom::bindings::codegen::ElementBinding;
use dom::bindings::codegen::InheritTypes::{ElementDerived, HTMLImageElementCast}; use dom::bindings::codegen::InheritTypes::{ElementDerived, HTMLImageElementCast};
use dom::bindings::codegen::InheritTypes::{HTMLIFrameElementCast, NodeCast}; use dom::bindings::codegen::InheritTypes::{HTMLIFrameElementCast, NodeCast};
use dom::bindings::codegen::InheritTypes::HTMLObjectElementCast; use dom::bindings::codegen::InheritTypes::HTMLObjectElementCast;
@ -133,6 +134,8 @@ pub enum ElementTypeId {
HTMLUListElementTypeId, HTMLUListElementTypeId,
HTMLVideoElementTypeId, HTMLVideoElementTypeId,
HTMLUnknownElementTypeId, HTMLUnknownElementTypeId,
ElementTypeId,
} }
// //
@ -140,7 +143,7 @@ pub enum ElementTypeId {
// //
impl Element { impl Element {
pub fn new_inherited(type_id: ElementTypeId, tag_name: ~str, namespace: Namespace, document: JS<Document>) -> Element { pub fn new_inherited(type_id: ElementTypeId, tag_name: DOMString, namespace: Namespace, document: JS<Document>) -> Element {
Element { Element {
node: Node::new_inherited(ElementNodeTypeId(type_id), document), node: Node::new_inherited(ElementNodeTypeId(type_id), document),
tag_name: tag_name, tag_name: tag_name,
@ -151,6 +154,11 @@ impl Element {
} }
} }
pub fn new(tag_name: DOMString, namespace: Namespace, document: &JS<Document>) -> JS<Element> {
let element = Element::new_inherited(ElementTypeId, tag_name, namespace, document.clone());
Node::reflect_node(~element, document, ElementBinding::Wrap)
}
pub fn html_element_in_html_document(&self) -> bool { pub fn html_element_in_html_document(&self) -> bool {
self.namespace == namespace::HTML && self.namespace == namespace::HTML &&
self.node.owner_doc().get().is_html_document self.node.owner_doc().get().is_html_document
@ -647,7 +655,7 @@ impl IElement for JS<Element> {
} }
} }
fn get_attribute_parts(name: DOMString) -> (Option<~str>, ~str) { pub fn get_attribute_parts(name: DOMString) -> (Option<~str>, ~str) {
//FIXME: Throw for XML-invalid names //FIXME: Throw for XML-invalid names
//FIXME: Throw for XMLNS-invalid names //FIXME: Throw for XMLNS-invalid names
let (prefix, local_name) = if name.contains(":") { let (prefix, local_name) = if name.contains(":") {

View file

@ -1734,8 +1734,9 @@ impl Node {
} }
// http://dom.spec.whatwg.org/#dom-node-namespaceuri // http://dom.spec.whatwg.org/#dom-node-namespaceuri
pub fn GetNamespaceURI(&self) -> Option<DOMString> { pub fn GetNamespaceURI(&self, abstract_self: &JS<Node>) -> Option<DOMString> {
None let element: Option<JS<Element>> = ElementCast::to(abstract_self);
element.map(|element| element.get().namespace.to_str().to_owned())
} }
// http://dom.spec.whatwg.org/#dom-node-prefix // http://dom.spec.whatwg.org/#dom-node-prefix

View file

@ -28,6 +28,8 @@ interface Document : Node {
[Creator, Throws] [Creator, Throws]
Element createElement(DOMString localName); Element createElement(DOMString localName);
[Creator, Throws]
Element createElementNS(DOMString? namespace, DOMString qualifiedName);
[Creator] [Creator]
DocumentFragment createDocumentFragment(); DocumentFragment createDocumentFragment();
[Creator] [Creator]

View file

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html>
<head>
<script src="harness.js"></script>
<script id="script">
// test1: createElementNS
{
var htmlElt = document.createElementNS("http://www.w3.org/1999/xhtml", "p");
is_not(htmlElt, null, "test1-0: createElementNS");
is_a(htmlElt, Element, "test1-1: createElementNS");
is_a(htmlElt, HTMLElement, "test1-2: createElementNS");
is_a(htmlElt, HTMLParagraphElement, "test1-3: createElementNS");
is(htmlElt.namespaceURI, "http://www.w3.org/1999/xhtml", "test1-4: createElementNS");
var otherNsElt = document.createElementNS("http://www.example.org/dummy", "p");
is_not(otherNsElt, null, "test1-5: createElementNS");
is_a(otherNsElt, Element, "test1-6: createElementNS");
is_not_a(otherNsElt, HTMLElement, "test1-7: createElementNS");
is(otherNsElt.namespaceURI, "http://www.example.org/dummy", "test1-8: createElementNS");
}
// test2: Node.namespaceURI
{
is(document.namespaceURI, null, "test2.0: createElementNS");
is(document.documentElement.namespaceURI, "http://www.w3.org/1999/xhtml", "test2.1: createElementNS");
var scriptElt = document.getElementById("script");
is(scriptElt.firstChild.namespaceURI, null, "test2.2: createElementNS");
is(scriptElt.nextSibling.namespaceURI, null, "test2.3: createElementNS");
}
finish();
</script><!-- this is a comment -->
</head>
</html>