diff options
author | James Graham <james@hoppipolla.co.uk> | 2014-01-02 22:49:03 +0000 |
---|---|---|
committer | James Graham <james@hoppipolla.co.uk> | 2014-01-14 13:10:05 +0000 |
commit | 7aee1cae84704b885988a5985a7604747125ec1e (patch) | |
tree | cf0940ecb5d800e2b95cd1afe7524f1fa93fb811 /src/components/script/dom/htmlserializer.rs | |
parent | fc76107a92313f6c2dd9c9b9fc6e588093f73c92 (diff) | |
download | servo-7aee1cae84704b885988a5985a7604747125ec1e.tar.gz servo-7aee1cae84704b885988a5985a7604747125ec1e.zip |
Implement innerHTML getter for HTML documents
XML case is not yet implemented.
Diffstat (limited to 'src/components/script/dom/htmlserializer.rs')
-rw-r--r-- | src/components/script/dom/htmlserializer.rs | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/src/components/script/dom/htmlserializer.rs b/src/components/script/dom/htmlserializer.rs new file mode 100644 index 00000000000..3de36d831f2 --- /dev/null +++ b/src/components/script/dom/htmlserializer.rs @@ -0,0 +1,135 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use dom::namespace; +use dom::attr::Attr; +use dom::node::NodeIterator; +use dom::node::{DoctypeNodeTypeId, DocumentFragmentNodeTypeId, CommentNodeTypeId, DocumentNodeTypeId, ElementNodeTypeId, TextNodeTypeId, AbstractNode}; + +pub fn serialize(iterator: &mut NodeIterator) -> ~str { + let mut html = ~""; + let mut open_elements: ~[~str] = ~[]; + + for node in *iterator { + while open_elements.len() > iterator.depth { + html.push_str(~"</" + open_elements.pop() + ">"); + } + html.push_str( + match node.type_id() { + ElementNodeTypeId(..) => { + serialize_elem(node, &mut open_elements) + } + CommentNodeTypeId => { + serialize_comment(node) + } + TextNodeTypeId => { + serialize_text(node) + } + DoctypeNodeTypeId => { + serialize_doctype(node) + } + DocumentFragmentNodeTypeId => { + ~"" + } + DocumentNodeTypeId(_) => { + fail!("It shouldn't be possible to serialize a document node") + } + } + ); + } + while open_elements.len() > 0 { + html.push_str(~"</" + open_elements.pop() + ">"); + } + html +} + +fn serialize_comment(node: AbstractNode) -> ~str { + node.with_imm_characterdata(|comment| { + ~"<!--" + comment.data + "-->" + }) +} + +fn serialize_text(node: AbstractNode) -> ~str { + node.with_imm_characterdata(|text| { + match node.parent_node() { + Some(parent) if parent.is_element() => { + parent.with_imm_element(|elem| { + match elem.tag_name.as_slice() { + "style" | "script" | "xmp" | "iframe" | + "noembed" | "noframes" | "plaintext" | + "noscript" if elem.namespace == namespace::HTML => { + text.data.clone() + }, + _ => escape(text.data, false) + } + }) + }, + _ => escape(text.data, false) + } + }) +} + +fn serialize_doctype(node: AbstractNode) -> ~str { + node.with_imm_doctype(|doctype| { + ~"<!DOCTYPE" + doctype.name + ">" + }) +} + +fn serialize_elem(node: AbstractNode, open_elements: &mut ~[~str]) -> ~str { + node.with_imm_element(|elem| { + let mut rv = ~"<" + elem.tag_name; + for attr in elem.attrs.iter() { + rv.push_str(serialize_attr(attr)); + }; + rv.push_str(">"); + match elem.tag_name.as_slice() { + "pre" | "listing" | "textarea" if + elem.namespace == namespace::HTML => { + match node.first_child() { + Some(child) if child.is_text() => { + child.with_imm_characterdata(|text| { + if text.data[0] == 0x0A as u8 { + rv.push_str("\x0A"); + } + }) + }, + _ => {} + } + }, + _ => {} + } + if !elem.is_void() { + open_elements.push(elem.tag_name.clone()); + } + rv + }) +} + +fn serialize_attr(attr: &@mut Attr) -> ~str { + let attr_name = if attr.namespace == namespace::XML { + ~"xml:" + attr.local_name.clone() + } else if attr.namespace == namespace::XMLNS && + attr.local_name.as_slice() == "xmlns" { + ~"xmlns" + } else if attr.namespace == namespace::XMLNS { + ~"xmlns:" + attr.local_name.clone() + } else if attr.namespace == namespace::XLink { + ~"xlink:" + attr.local_name.clone() + } else { + attr.name.clone() + }; + ~" " + attr_name + "=\"" + escape(attr.value, true) + "\"" +} + +fn escape(string: &str, attr_mode: bool) -> ~str { + let replaced = string.replace("&", "&").replace("\xA0", " "); + match attr_mode { + true => { + replaced.replace("\"", """) + }, + false => { + replaced.replace("<", "<").replace(">", ">") + } + } +} |