aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
authorChris Paris <cap@chrisparis.org>2015-02-10 02:27:20 -1000
committerChris Paris <cap@chrisparis.org>2015-03-18 11:20:47 -1000
commit99286e4b4fe267d123fbdd5484612840300ab30e (patch)
tree1bd121c8d8f32e13e47fbd5ba5d324c577a07b4d /components/script
parenta5217556072390131f41a7a4cd07e8eb5a671d06 (diff)
downloadservo-99286e4b4fe267d123fbdd5484612840300ab30e.tar.gz
servo-99286e4b4fe267d123fbdd5484612840300ab30e.zip
Implement Element.innerHTML setter
Diffstat (limited to 'components/script')
-rw-r--r--components/script/dom/domparser.rs2
-rw-r--r--components/script/dom/element.rs58
-rw-r--r--components/script/dom/servohtmlparser.rs41
-rw-r--r--components/script/dom/webidls/Element.webidl2
-rw-r--r--components/script/parse/html.rs10
-rw-r--r--components/script/script_task.rs2
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);