diff options
author | Chris Paris <cap@chrisparis.org> | 2015-02-10 02:27:20 -1000 |
---|---|---|
committer | Chris Paris <cap@chrisparis.org> | 2015-03-18 11:20:47 -1000 |
commit | 99286e4b4fe267d123fbdd5484612840300ab30e (patch) | |
tree | 1bd121c8d8f32e13e47fbd5ba5d324c577a07b4d /components/script | |
parent | a5217556072390131f41a7a4cd07e8eb5a671d06 (diff) | |
download | servo-99286e4b4fe267d123fbdd5484612840300ab30e.tar.gz servo-99286e4b4fe267d123fbdd5484612840300ab30e.zip |
Implement Element.innerHTML setter
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/dom/domparser.rs | 2 | ||||
-rw-r--r-- | components/script/dom/element.rs | 58 | ||||
-rw-r--r-- | components/script/dom/servohtmlparser.rs | 41 | ||||
-rw-r--r-- | components/script/dom/webidls/Element.webidl | 2 | ||||
-rw-r--r-- | components/script/parse/html.rs | 10 | ||||
-rw-r--r-- | components/script/script_task.rs | 2 |
6 files changed, 109 insertions, 6 deletions
diff --git a/components/script/dom/domparser.rs b/components/script/dom/domparser.rs index 02ef2b78ff5..72190ccb1b6 100644 --- a/components/script/dom/domparser.rs +++ b/components/script/dom/domparser.rs @@ -58,7 +58,7 @@ impl<'a> DOMParserMethods for JSRef<'a, DOMParser> { Some(content_type), None, DocumentSource::FromParser).root(); - parse_html(document.r(), HTMLInput::InputString(s), &url); + parse_html(document.r(), HTMLInput::InputString(s), &url, None); document.r().set_ready_state(DocumentReadyState::Complete); Ok(Temporary::from_rooted(document.r())) } diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index d8ebb804c87..da9d4691f2b 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -10,11 +10,13 @@ use dom::attr::AttrValue; use dom::namednodemap::NamedNodeMap; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods; +use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; use dom::bindings::codegen::Bindings::ElementBinding; use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods; use dom::bindings::codegen::Bindings::EventBinding::EventMethods; use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods; use dom::bindings::codegen::Bindings::NamedNodeMapBinding::NamedNodeMapMethods; +use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use dom::bindings::codegen::InheritTypes::{ElementCast, ElementDerived, EventTargetCast}; use dom::bindings::codegen::InheritTypes::{HTMLBodyElementDerived, HTMLInputElementCast}; use dom::bindings::codegen::InheritTypes::{HTMLInputElementDerived, HTMLTableElementCast}; @@ -22,6 +24,7 @@ use dom::bindings::codegen::InheritTypes::{HTMLTableElementDerived, HTMLTableCel use dom::bindings::codegen::InheritTypes::{HTMLTableRowElementDerived, HTMLTextAreaElementDerived}; use dom::bindings::codegen::InheritTypes::{HTMLTableSectionElementDerived, NodeCast}; use dom::bindings::codegen::InheritTypes::HTMLAnchorElementCast; +use dom::bindings::codegen::InheritTypes::HTMLFormElementDerived; use dom::bindings::error::{ErrorResult, Fallible}; use dom::bindings::error::Error::{NamespaceError, InvalidCharacter, Syntax}; use dom::bindings::js::{MutNullableJS, JS, JSRef, LayoutJS, Temporary, TemporaryPushable}; @@ -32,6 +35,7 @@ use dom::create::create_element; use dom::domrect::DOMRect; use dom::domrectlist::DOMRectList; use dom::document::{Document, DocumentHelpers, LayoutDocumentHelpers}; +use dom::document::{DocumentSource, IsHTMLDocument}; use dom::domtokenlist::DOMTokenList; use dom::event::{Event, EventHelpers}; use dom::eventtarget::{EventTarget, EventTargetTypeId}; @@ -50,8 +54,10 @@ use dom::node::{CLICK_IN_PROGRESS, LayoutNodeHelpers, Node, NodeHelpers, NodeTyp use dom::node::{NodeIterator, document_from_node, NodeDamage}; use dom::node::{window_from_node}; use dom::nodelist::NodeList; +use dom::servohtmlparser::FragmentContext; use dom::virtualmethods::{VirtualMethods, vtable_for}; use devtools_traits::AttrInfo; +use parse::html::{HTMLInput, parse_html}; use style::legacy::{SimpleColorAttribute, UnsignedIntegerAttribute, IntegerAttribute, LengthAttribute}; use selectors::matching::matches; use style::properties::{PropertyDeclarationBlock, PropertyDeclaration, parse_style_attribute}; @@ -1117,6 +1123,58 @@ impl<'a> ElementMethods for JSRef<'a, Element> { Ok(serialize(&mut NodeIterator::new(NodeCast::from_ref(self), false, false))) } + fn SetInnerHTML(self, value: DOMString) -> Fallible<()> { + let window = window_from_node(self).root(); + let context_document = document_from_node(self).root(); + let context_node: JSRef<Node> = NodeCast::from_ref(self); + let url = context_document.r().url(); + + // Follows https://html.spec.whatwg.org/multipage/syntax.html#parsing-html-fragments + + // 1. Create a new Document node, and mark it as being an HTML document. + let document = Document::new(window.r(), Some(url.clone()), + IsHTMLDocument::HTMLDocument, + None, None, + DocumentSource::FromParser).root(); + + // 2. If the node document of the context element is in quirks mode, + // then let the Document be in quirks mode. Otherwise, + // the node document of the context element is in limited-quirks mode, + // then let the Document be in limited-quirks mode. Otherwise, + // leave the Document in no-quirks mode. + document.r().set_quirks_mode(context_document.r().quirks_mode()); + + // 11. Set the parser's form element pointer to the nearest node to + // the context element that is a form element (going straight up + // the ancestor chain, and including the element itself, if it + // is a form element), if any. (If there is no such form element, + // the form element pointer keeps its initial value, null.) + let form = context_node.inclusive_ancestors() + .find(|element| element.is_htmlformelement()); + let fragment_context = FragmentContext { + context_elem: context_node, + form_elem: form, + }; + parse_html(document.r(), HTMLInput::InputString(value), &url, Some(fragment_context)); + + // "14. Return the child nodes of root, in tree order." + // We do this by deleting all nodes of the context node, + // and then moving all nodes parsed into the new root_node + // into the context node. + while let Some(child) = context_node.GetFirstChild() { + try!(context_node.RemoveChild(child.root().r())); + } + let root_element = document.r().GetDocumentElement().expect("no document element").root(); + let root_node: JSRef<Node> = NodeCast::from_ref(root_element.r()); + while let Some(child) = root_node.GetFirstChild() { + let child = child.root(); + try!(root_node.RemoveChild(child.r())); + try!(context_node.AppendChild(child.r())); + } + + Ok(()) + } + fn GetOuterHTML(self) -> Fallible<DOMString> { Ok(serialize(&mut NodeIterator::new(NodeCast::from_ref(self), true, false))) } diff --git a/components/script/dom/servohtmlparser.rs b/components/script/dom/servohtmlparser.rs index c41cdcdd93c..a1122df4ab1 100644 --- a/components/script/dom/servohtmlparser.rs +++ b/components/script/dom/servohtmlparser.rs @@ -31,6 +31,14 @@ pub struct Sink { pub document: JS<Document>, } +/// FragmentContext is used only to pass this group of related values +/// into functions. +#[derive(Copy)] +pub struct FragmentContext<'a> { + pub context_elem: JSRef<'a, Node>, + pub form_elem: Option<JSRef<'a, Node>>, +} + pub type Tokenizer = tokenizer::Tokenizer<TreeBuilder<JS<Node>, Sink>>; // NB: JSTraceable is *not* auto-derived. @@ -76,6 +84,39 @@ impl ServoHTMLParser { ServoHTMLParserBinding::Wrap) } + #[allow(unrooted_must_root)] + pub fn new_for_fragment(base_url: Option<Url>, document: JSRef<Document>, + fragment_context: FragmentContext) -> Temporary<ServoHTMLParser> { + let window = document.window().root(); + let sink = Sink { + base_url: base_url, + document: JS::from_rooted(document), + }; + + let tb_opts = TreeBuilderOpts { + ignore_missing_rules: true, + .. Default::default() + }; + let tb = TreeBuilder::new_for_fragment(sink, + JS::from_rooted(fragment_context.context_elem), + fragment_context.form_elem.map(|n| JS::from_rooted(n)), + tb_opts); + + let tok_opts = tokenizer::TokenizerOpts { + initial_state: Some(tb.tokenizer_state_for_context_elem()), + .. Default::default() + }; + let tok = tokenizer::Tokenizer::new(tb, tok_opts); + + let parser = ServoHTMLParser { + reflector_: Reflector::new(), + tokenizer: DOMRefCell::new(tok), + }; + + reflect_dom_object(box parser, GlobalRef::Window(window.r()), + ServoHTMLParserBinding::Wrap) + } + #[inline] pub fn tokenizer<'a>(&'a self) -> &'a DOMRefCell<Tokenizer> { &self.tokenizer diff --git a/components/script/dom/webidls/Element.webidl b/components/script/dom/webidls/Element.webidl index 820d8b5b4f2..245df78e812 100644 --- a/components/script/dom/webidls/Element.webidl +++ b/components/script/dom/webidls/Element.webidl @@ -64,7 +64,7 @@ partial interface Element { // http://domparsing.spec.whatwg.org/#extensions-to-the-element-interface partial interface Element { [Throws,TreatNullAs=EmptyString] - readonly attribute DOMString innerHTML; + attribute DOMString innerHTML; [Throws,TreatNullAs=EmptyString] readonly attribute DOMString outerHTML; }; diff --git a/components/script/parse/html.rs b/components/script/parse/html.rs index 836eac6dfba..200f11a0bfa 100644 --- a/components/script/parse/html.rs +++ b/components/script/parse/html.rs @@ -16,7 +16,7 @@ use dom::htmlscriptelement::HTMLScriptElement; use dom::htmlscriptelement::HTMLScriptElementHelpers; use dom::node::{Node, NodeHelpers}; use dom::servohtmlparser; -use dom::servohtmlparser::ServoHTMLParser; +use dom::servohtmlparser::{ServoHTMLParser, FragmentContext}; use dom::text::Text; use parse::Parser; @@ -171,8 +171,12 @@ impl<'a> TreeSink for servohtmlparser::Sink { pub fn parse_html(document: JSRef<Document>, input: HTMLInput, - url: &Url) { - let parser = ServoHTMLParser::new(Some(url.clone()), document).root(); + url: &Url, + fragment_context: Option<FragmentContext>) { + let parser = match fragment_context { + None => ServoHTMLParser::new(Some(url.clone()), document).root(), + Some(fc) => ServoHTMLParser::new_for_fragment(Some(url.clone()), document, fc).root(), + }; let parser: JSRef<ServoHTMLParser> = parser.r(); let nested_parse = task_state::get().contains(task_state::IN_HTML_PARSER); diff --git a/components/script/script_task.rs b/components/script/script_task.rs index 238763f3035..ce4dd123d00 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -1013,7 +1013,7 @@ impl ScriptTask { HTMLInput::InputUrl(response) }; - parse_html(document.r(), parse_input, &final_url); + parse_html(document.r(), parse_input, &final_url, None); document.r().set_ready_state(DocumentReadyState::Interactive); self.compositor.borrow_mut().set_ready_state(incomplete.pipeline_id, PerformingLayout); |