From 4b0da08573b0919a06056302a5e9986d1be88fcb Mon Sep 17 00:00:00 2001 From: Daniel Glazman Date: Mon, 7 Apr 2014 10:14:01 +0200 Subject: [PATCH] Implement Document.createElementNS. --- .../script/dom/bindings/codegen/Bindings.conf | 2 + src/components/script/dom/document.rs | 55 +++++++++++++++++-- src/components/script/dom/element.rs | 12 +++- src/components/script/dom/node.rs | 5 +- .../script/dom/webidls/Document.webidl | 2 + .../test_document_createElementNS.html | 33 +++++++++++ 6 files changed, 101 insertions(+), 8 deletions(-) create mode 100644 src/test/content/test_document_createElementNS.html diff --git a/src/components/script/dom/bindings/codegen/Bindings.conf b/src/components/script/dom/bindings/codegen/Bindings.conf index 2ba358e4753f..a40dfdf1fe6d 100644 --- a/src/components/script/dom/bindings/codegen/Bindings.conf +++ b/src/components/script/dom/bindings/codegen/Bindings.conf @@ -33,6 +33,7 @@ DOMInterfaces = { 'createComment', 'createDocumentFragment', 'createElement', + 'createElementNS', 'createProcessingInstruction', 'createTextNode', 'embeds', @@ -95,6 +96,7 @@ DOMInterfaces = { 'contains', 'insertBefore', 'isEqualNode', + 'namespaceURI', 'nodeName', 'nodeValue', 'normalize', diff --git a/src/components/script/dom/document.rs b/src/components/script/dom/document.rs index 16a96c0bb95f..6d8c7fe9313e 100644 --- a/src/components/script/dom/document.rs +++ b/src/components/script/dom/document.rs @@ -9,13 +9,13 @@ use dom::bindings::codegen::InheritTypes::{DocumentTypeCast, HTMLHtmlElementCast use dom::bindings::codegen::DocumentBinding; use dom::bindings::js::JS; use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; -use dom::bindings::error::{ErrorResult, Fallible, NotSupported, InvalidCharacter, HierarchyRequest}; -use dom::bindings::utils::{xml_name_type, InvalidXMLName}; +use dom::bindings::error::{ErrorResult, Fallible, NotSupported, InvalidCharacter, HierarchyRequest, NamespaceError}; +use dom::bindings::utils::{xml_name_type, InvalidXMLName, Name, QName}; use dom::comment::Comment; use dom::documentfragment::DocumentFragment; use dom::documenttype::DocumentType; 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::{HTMLBodyElementTypeId, HTMLFrameSetElementTypeId}; use dom::event::Event; @@ -37,8 +37,9 @@ use dom::location::Location; use html::hubbub_html_parser::build_element_from_tag; use hubbub::hubbub::{QuirksMode, NoQuirks, LimitedQuirks, FullQuirks}; use layout_interface::{DocumentDamageLevel, ContentChangedDocumentDamage}; +use servo_util::namespace; 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 js::jsapi::JSContext; @@ -263,6 +264,52 @@ impl Document { Ok(build_element_from_tag(local_name, abstract_self)) } + // http://dom.spec.whatwg.org/#dom-document-createelementns + pub fn CreateElementNS(&self, abstract_self: &JS, + namespace: Option, + qualified_name: DOMString) -> Fallible> { + 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 pub fn CreateDocumentFragment(&self, abstract_self: &JS) -> JS { DocumentFragment::new(abstract_self) diff --git a/src/components/script/dom/element.rs b/src/components/script/dom/element.rs index 11b836840907..fca1f9ad78c9 100644 --- a/src/components/script/dom/element.rs +++ b/src/components/script/dom/element.rs @@ -6,6 +6,7 @@ use dom::attr::Attr; use dom::attrlist::AttrList; +use dom::bindings::codegen::ElementBinding; use dom::bindings::codegen::InheritTypes::{ElementDerived, HTMLImageElementCast}; use dom::bindings::codegen::InheritTypes::{HTMLIFrameElementCast, NodeCast}; use dom::bindings::codegen::InheritTypes::HTMLObjectElementCast; @@ -133,6 +134,8 @@ pub enum ElementTypeId { HTMLUListElementTypeId, HTMLVideoElementTypeId, HTMLUnknownElementTypeId, + + ElementTypeId, } // @@ -140,7 +143,7 @@ pub enum ElementTypeId { // impl Element { - pub fn new_inherited(type_id: ElementTypeId, tag_name: ~str, namespace: Namespace, document: JS) -> Element { + pub fn new_inherited(type_id: ElementTypeId, tag_name: DOMString, namespace: Namespace, document: JS) -> Element { Element { node: Node::new_inherited(ElementNodeTypeId(type_id), document), tag_name: tag_name, @@ -151,6 +154,11 @@ impl Element { } } + pub fn new(tag_name: DOMString, namespace: Namespace, document: &JS) -> JS { + 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 { self.namespace == namespace::HTML && self.node.owner_doc().get().is_html_document @@ -647,7 +655,7 @@ impl IElement for JS { } } -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 XMLNS-invalid names let (prefix, local_name) = if name.contains(":") { diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs index 0a35b5b6b0d8..77ca388be9ef 100644 --- a/src/components/script/dom/node.rs +++ b/src/components/script/dom/node.rs @@ -1734,8 +1734,9 @@ impl Node { } // http://dom.spec.whatwg.org/#dom-node-namespaceuri - pub fn GetNamespaceURI(&self) -> Option { - None + pub fn GetNamespaceURI(&self, abstract_self: &JS) -> Option { + let element: Option> = ElementCast::to(abstract_self); + element.map(|element| element.get().namespace.to_str().to_owned()) } // http://dom.spec.whatwg.org/#dom-node-prefix diff --git a/src/components/script/dom/webidls/Document.webidl b/src/components/script/dom/webidls/Document.webidl index 81a54021ee70..6dd0cb658a22 100644 --- a/src/components/script/dom/webidls/Document.webidl +++ b/src/components/script/dom/webidls/Document.webidl @@ -28,6 +28,8 @@ interface Document : Node { [Creator, Throws] Element createElement(DOMString localName); + [Creator, Throws] + Element createElementNS(DOMString? namespace, DOMString qualifiedName); [Creator] DocumentFragment createDocumentFragment(); [Creator] diff --git a/src/test/content/test_document_createElementNS.html b/src/test/content/test_document_createElementNS.html new file mode 100644 index 000000000000..6ff35d4d6c1a --- /dev/null +++ b/src/test/content/test_document_createElementNS.html @@ -0,0 +1,33 @@ + + + + + + +