From 63ced23fca19a75aa02a2d1ba11e1df8cd60ea05 Mon Sep 17 00:00:00 2001 From: Chris Paris Date: Fri, 20 Mar 2015 22:37:05 -1000 Subject: [PATCH 01/10] Refactor fragment parsing --- components/script/dom/element.rs | 62 +++++--------------------------- components/script/dom/node.rs | 23 +++++++++++- components/script/parse/html.rs | 44 +++++++++++++++++++++++ 3 files changed, 74 insertions(+), 55 deletions(-) diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 544aa918c6d..66ca145d623 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -10,13 +10,11 @@ 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}; @@ -24,7 +22,6 @@ 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; use dom::bindings::error::Error::{InvalidCharacter, Syntax}; @@ -37,7 +34,6 @@ 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}; @@ -55,10 +51,9 @@ use dom::node::{CLICK_IN_PROGRESS, LayoutNodeHelpers, Node, NodeHelpers, NodeTyp use dom::node::{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 parse::html::HTMLInput; use style::legacy::{SimpleColorAttribute, UnsignedIntegerAttribute, IntegerAttribute, LengthAttribute}; use selectors::matching::matches; use style::properties::{PropertyDeclarationBlock, PropertyDeclaration, parse_style_attribute}; @@ -1169,61 +1164,20 @@ impl<'a> ElementMethods for JSRef<'a, Element> { rect.origin.x + rect.size.width) } + // https://dvcs.w3.org/hg/innerhtml/raw-file/tip/index.html#extensions-to-the-element-interface fn GetInnerHTML(self) -> Fallible { //XXX TODO: XML case self.serialize(ChildrenOnly) } fn SetInnerHTML(self, value: DOMString) -> Fallible<()> { - let window = window_from_node(self).root(); - let context_document = document_from_node(self).root(); + // 1. Let fragment be the result of invoking the fragment parsing algorithm + // with the new value as markup, and the context object as the context element. + // 2. Replace all with fragment within the context object. let context_node: JSRef = 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 = 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(()) + context_node.parse_fragment(HTMLInput::InputString(value)) + .and_then(|frag| Ok(Node::replace_all(Some(NodeCast::from_ref(frag.root().r())), + context_node))) } fn GetOuterHTML(self) -> Fallible { diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 6d69e4cf7e5..9bc8e9879a4 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -46,6 +46,7 @@ use dom::window::{Window, WindowHelpers}; use geom::rect::Rect; use layout_interface::{LayoutChan, Msg}; use devtools_traits::NodeInfo; +use parse::html::{HTMLInput, parse_html_fragment}; use script_traits::UntrustedNodeAddress; use util::geometry::Au; use util::str::{DOMString, null_str_as_empty}; @@ -502,6 +503,8 @@ pub trait NodeHelpers<'a> { fn summarize(self) -> NodeInfo; fn teardown(self); + + fn parse_fragment(self, markup: HTMLInput) -> Fallible>; } impl<'a> NodeHelpers<'a> for JSRef<'a, Node> { @@ -929,6 +932,24 @@ impl<'a> NodeHelpers<'a> for JSRef<'a, Node> { } } + // https://dvcs.w3.org/hg/innerhtml/raw-file/tip/index.html#dfn-concept-parse-fragment + fn parse_fragment(self, markup: HTMLInput) -> Fallible> { + let context_node: JSRef = NodeCast::from_ref(self); + let context_document = document_from_node(self).root(); + let new_children = + if context_document.r().is_html_document() { + parse_html_fragment(context_node, markup) + } else { + // FIXME: XML case + unimplemented!() + }; + let fragment = DocumentFragment::new(context_document.r()).root(); + let fragment_node: JSRef = NodeCast::from_ref(fragment.r()); + for node in new_children { + try!(fragment_node.AppendChild(node.root().r())); + } + Ok(Temporary::from_rooted(fragment.r())) + } } /// If the given untrusted node address represents a valid DOM node in the given runtime, @@ -1456,7 +1477,7 @@ impl Node { } // http://dom.spec.whatwg.org/#concept-node-replace-all - fn replace_all(node: Option>, parent: JSRef) { + pub fn replace_all(node: Option>, parent: JSRef) { // Step 1. match node { Some(node) => { diff --git a/components/script/parse/html.rs b/components/script/parse/html.rs index 794c6824ba8..1667afe288d 100644 --- a/components/script/parse/html.rs +++ b/components/script/parse/html.rs @@ -5,18 +5,22 @@ #![allow(unsafe_code, unrooted_must_root)] use dom::attr::AttrHelpers; +use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast, HTMLScriptElementCast}; use dom::bindings::codegen::InheritTypes::{DocumentTypeCast, TextCast, CommentCast}; use dom::bindings::codegen::InheritTypes::ProcessingInstructionCast; +use dom::bindings::codegen::InheritTypes::HTMLFormElementDerived; use dom::bindings::js::{JS, JSRef, Temporary, OptionalRootable, Root}; use dom::comment::Comment; use dom::document::{Document, DocumentHelpers}; +use dom::document::{DocumentSource, IsHTMLDocument}; use dom::documenttype::DocumentType; use dom::element::{Element, AttributeHandlers, ElementHelpers, ElementCreator}; use dom::htmlscriptelement::HTMLScriptElement; use dom::htmlscriptelement::HTMLScriptElementHelpers; use dom::node::{Node, NodeHelpers, NodeTypeId}; +use dom::node::{document_from_node, window_from_node}; use dom::processinginstruction::ProcessingInstruction; use dom::servohtmlparser; use dom::servohtmlparser::{ServoHTMLParser, FragmentContext}; @@ -324,3 +328,43 @@ pub fn parse_html(document: JSRef, debug!("finished parsing"); } + +// https://html.spec.whatwg.org/multipage/syntax.html#parsing-html-fragments +pub fn parse_html_fragment(context_node: JSRef, input: HTMLInput) -> Vec> { + let window = window_from_node(context_node).root(); + let context_document = document_from_node(context_node).root(); + let url = context_document.r().url(); + + // 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(), input, &url, Some(fragment_context)); + + // "14. Return the child nodes of root, in tree order." + let root_element = document.r().GetDocumentElement().expect("no document element").root(); + let root_node: JSRef = NodeCast::from_ref(root_element.r()); + root_node.children() + .map(|node| Temporary::from_rooted(node)) + .collect() +} From 2cc5bad21ea9eb65d8e2f30e7a43aca0ecd7c86e Mon Sep 17 00:00:00 2001 From: Chris Paris Date: Sat, 21 Mar 2015 13:51:26 -1000 Subject: [PATCH 02/10] Implement Element.outerHTML setter --- components/script/dom/element.rs | 43 +++++++++++++++++++ components/script/dom/webidls/Element.webidl | 2 +- .../nodes/Document-getElementById.html.ini | 8 ---- 3 files changed, 44 insertions(+), 9 deletions(-) delete mode 100644 tests/wpt/metadata/dom/nodes/Document-getElementById.html.ini diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 66ca145d623..b67014f5676 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -15,6 +15,7 @@ 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}; @@ -25,6 +26,7 @@ use dom::bindings::codegen::InheritTypes::HTMLAnchorElementCast; use dom::bindings::error::{ErrorResult, Fallible}; use dom::bindings::error::Error; use dom::bindings::error::Error::{InvalidCharacter, Syntax}; +use dom::bindings::error::Error::NoModificationAllowed; use dom::bindings::js::{MutNullableJS, JS, JSRef, LayoutJS, Temporary, TemporaryPushable}; use dom::bindings::js::OptionalRootable; use dom::bindings::trace::RootedVec; @@ -1184,6 +1186,47 @@ impl<'a> ElementMethods for JSRef<'a, Element> { self.serialize(IncludeNode) } + fn SetOuterHTML(self, value: DOMString) -> Fallible<()> { + let context_document = document_from_node(self).root(); + let context_node: JSRef = NodeCast::from_ref(self); + // 1. Let parent be the context object's parent. + let context_parent = match context_node.parent_node() { + // 2. If parent is null, terminate these steps. + None => return Ok(()), + Some(parent) => parent.root() + }; + + let parent: Root = match context_parent.r().type_id() { + // 3. If parent is a Document, throw a DOMException + // with name "NoModificationAllowedError" exception. + NodeTypeId::Document => return Err(NoModificationAllowed), + + // 4. If parent is a DocumentFragment, let parent be a new Element with + // body as its local name, + // The HTML namespace as its namespace, and + // The context object's node document as its node document. + NodeTypeId::DocumentFragment => { + let body_elem = Element::create(QualName::new(ns!(HTML), atom!(body)), + None, context_document.r(), + ElementCreator::ScriptCreated); + let body_node: Temporary = NodeCast::from_temporary(body_elem); + body_node.root() + }, + _ => context_node.parent_node().unwrap().root() + }; + + // 5. Let fragment be the result of invoking the fragment parsing algorithm with + // the new value as markup, and parent as the context element. + // 6. Replace the context object with fragment within the context object's parent. + parent.r().parse_fragment(HTMLInput::InputString(value)) + .and_then(|frag| { + let frag = frag.root(); + let frag_node: JSRef = NodeCast::from_ref(frag.r()); + try!(context_parent.r().ReplaceChild(frag_node, context_node)); + Ok(()) + }) + } + // http://dom.spec.whatwg.org/#dom-parentnode-children fn Children(self) -> Temporary { let window = window_from_node(self).root(); diff --git a/components/script/dom/webidls/Element.webidl b/components/script/dom/webidls/Element.webidl index 245df78e812..8d08717cd31 100644 --- a/components/script/dom/webidls/Element.webidl +++ b/components/script/dom/webidls/Element.webidl @@ -66,7 +66,7 @@ partial interface Element { [Throws,TreatNullAs=EmptyString] attribute DOMString innerHTML; [Throws,TreatNullAs=EmptyString] - readonly attribute DOMString outerHTML; + attribute DOMString outerHTML; }; Element implements ChildNode; diff --git a/tests/wpt/metadata/dom/nodes/Document-getElementById.html.ini b/tests/wpt/metadata/dom/nodes/Document-getElementById.html.ini deleted file mode 100644 index 5f10bd87f50..00000000000 --- a/tests/wpt/metadata/dom/nodes/Document-getElementById.html.ini +++ /dev/null @@ -1,8 +0,0 @@ -[Document-getElementById.html] - type: testharness - [add id attribute via outerHTML] - expected: FAIL - - [remove id attribute via outerHTML] - expected: FAIL - From cc771fdd68e885be4c1ceb432c6a28781aaec47a Mon Sep 17 00:00:00 2001 From: Chris Paris Date: Thu, 26 Mar 2015 12:50:29 -1000 Subject: [PATCH 03/10] fragment parsing functions take DOMString instead of HTMLInput --- components/script/dom/element.rs | 5 ++--- components/script/dom/node.rs | 6 +++--- components/script/parse/html.rs | 5 +++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index b67014f5676..0aa5f9327b4 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -55,7 +55,6 @@ use dom::node::{window_from_node}; use dom::nodelist::NodeList; use dom::virtualmethods::{VirtualMethods, vtable_for}; use devtools_traits::AttrInfo; -use parse::html::HTMLInput; use style::legacy::{SimpleColorAttribute, UnsignedIntegerAttribute, IntegerAttribute, LengthAttribute}; use selectors::matching::matches; use style::properties::{PropertyDeclarationBlock, PropertyDeclaration, parse_style_attribute}; @@ -1177,7 +1176,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> { // with the new value as markup, and the context object as the context element. // 2. Replace all with fragment within the context object. let context_node: JSRef = NodeCast::from_ref(self); - context_node.parse_fragment(HTMLInput::InputString(value)) + context_node.parse_fragment(value) .and_then(|frag| Ok(Node::replace_all(Some(NodeCast::from_ref(frag.root().r())), context_node))) } @@ -1218,7 +1217,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> { // 5. Let fragment be the result of invoking the fragment parsing algorithm with // the new value as markup, and parent as the context element. // 6. Replace the context object with fragment within the context object's parent. - parent.r().parse_fragment(HTMLInput::InputString(value)) + parent.r().parse_fragment(value) .and_then(|frag| { let frag = frag.root(); let frag_node: JSRef = NodeCast::from_ref(frag.r()); diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 9bc8e9879a4..53a3e1792b7 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -46,7 +46,7 @@ use dom::window::{Window, WindowHelpers}; use geom::rect::Rect; use layout_interface::{LayoutChan, Msg}; use devtools_traits::NodeInfo; -use parse::html::{HTMLInput, parse_html_fragment}; +use parse::html::parse_html_fragment; use script_traits::UntrustedNodeAddress; use util::geometry::Au; use util::str::{DOMString, null_str_as_empty}; @@ -504,7 +504,7 @@ pub trait NodeHelpers<'a> { fn teardown(self); - fn parse_fragment(self, markup: HTMLInput) -> Fallible>; + fn parse_fragment(self, markup: DOMString) -> Fallible>; } impl<'a> NodeHelpers<'a> for JSRef<'a, Node> { @@ -933,7 +933,7 @@ impl<'a> NodeHelpers<'a> for JSRef<'a, Node> { } // https://dvcs.w3.org/hg/innerhtml/raw-file/tip/index.html#dfn-concept-parse-fragment - fn parse_fragment(self, markup: HTMLInput) -> Fallible> { + fn parse_fragment(self, markup: DOMString) -> Fallible> { let context_node: JSRef = NodeCast::from_ref(self); let context_document = document_from_node(self).root(); let new_children = diff --git a/components/script/parse/html.rs b/components/script/parse/html.rs index 1667afe288d..ad8c56ba613 100644 --- a/components/script/parse/html.rs +++ b/components/script/parse/html.rs @@ -31,6 +31,7 @@ use encoding::all::UTF_8; use encoding::types::{Encoding, DecoderTrap}; use net_traits::{ProgressMsg, LoadResponse}; +use util::str::DOMString; use util::task_state; use util::task_state::IN_HTML_PARSER; use std::ascii::AsciiExt; @@ -330,7 +331,7 @@ pub fn parse_html(document: JSRef, } // https://html.spec.whatwg.org/multipage/syntax.html#parsing-html-fragments -pub fn parse_html_fragment(context_node: JSRef, input: HTMLInput) -> Vec> { +pub fn parse_html_fragment(context_node: JSRef, input: DOMString) -> Vec> { let window = window_from_node(context_node).root(); let context_document = document_from_node(context_node).root(); let url = context_document.r().url(); @@ -359,7 +360,7 @@ pub fn parse_html_fragment(context_node: JSRef, input: HTMLInput) -> Vec Date: Thu, 26 Mar 2015 13:06:33 -1000 Subject: [PATCH 04/10] get rid of and_then in innerHTML setter --- components/script/dom/element.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 0aa5f9327b4..63ccf21bdde 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -1176,9 +1176,9 @@ impl<'a> ElementMethods for JSRef<'a, Element> { // with the new value as markup, and the context object as the context element. // 2. Replace all with fragment within the context object. let context_node: JSRef = NodeCast::from_ref(self); - context_node.parse_fragment(value) - .and_then(|frag| Ok(Node::replace_all(Some(NodeCast::from_ref(frag.root().r())), - context_node))) + let frag = try!(context_node.parse_fragment(value)); + Node::replace_all(Some(NodeCast::from_ref(frag.root().r())), context_node); + Ok(()) } fn GetOuterHTML(self) -> Fallible { From d83f4d8a6ec63d3755ad43f10f3cfbf2155dd48a Mon Sep 17 00:00:00 2001 From: Chris Paris Date: Thu, 26 Mar 2015 13:10:56 -1000 Subject: [PATCH 05/10] get rid of and_then in outerHTML setter --- components/script/dom/element.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 63ccf21bdde..37bf2d2ca23 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -1217,13 +1217,10 @@ impl<'a> ElementMethods for JSRef<'a, Element> { // 5. Let fragment be the result of invoking the fragment parsing algorithm with // the new value as markup, and parent as the context element. // 6. Replace the context object with fragment within the context object's parent. - parent.r().parse_fragment(value) - .and_then(|frag| { - let frag = frag.root(); - let frag_node: JSRef = NodeCast::from_ref(frag.r()); - try!(context_parent.r().ReplaceChild(frag_node, context_node)); - Ok(()) - }) + let frag = try!(parent.r().parse_fragment(value)); + try!(context_parent.r().ReplaceChild(NodeCast::from_ref(frag.root().r()), + context_node)); + Ok(()) } // http://dom.spec.whatwg.org/#dom-parentnode-children From b0ba4d17eef198c40e87230a817f33dc9740ec09 Mon Sep 17 00:00:00 2001 From: Chris Paris Date: Fri, 27 Mar 2015 06:56:32 -1000 Subject: [PATCH 06/10] drop try! from parse_fragment --- components/script/dom/node.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 53a3e1792b7..bd82119a8c6 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -946,7 +946,7 @@ impl<'a> NodeHelpers<'a> for JSRef<'a, Node> { let fragment = DocumentFragment::new(context_document.r()).root(); let fragment_node: JSRef = NodeCast::from_ref(fragment.r()); for node in new_children { - try!(fragment_node.AppendChild(node.root().r())); + let _ = fragment_node.AppendChild(node.root().r()); } Ok(Temporary::from_rooted(fragment.r())) } From d1c5ac31abce995da0919c3bb41c23a3e29a63aa Mon Sep 17 00:00:00 2001 From: Chris Paris Date: Fri, 27 Mar 2015 10:34:12 -1000 Subject: [PATCH 07/10] unwrap AppendChild result in parse_fragment --- components/script/dom/node.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index bd82119a8c6..3b49ba01ba9 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -946,7 +946,7 @@ impl<'a> NodeHelpers<'a> for JSRef<'a, Node> { let fragment = DocumentFragment::new(context_document.r()).root(); let fragment_node: JSRef = NodeCast::from_ref(fragment.r()); for node in new_children { - let _ = fragment_node.AppendChild(node.root().r()); + fragment_node.AppendChild(node.root().r()).unwrap(); } Ok(Temporary::from_rooted(fragment.r())) } From ce16075588de7a23c426af650f4cc8079719f501 Mon Sep 17 00:00:00 2001 From: Chris Paris Date: Wed, 1 Apr 2015 11:05:00 -1000 Subject: [PATCH 08/10] Replace spec quotes with spec step numbers --- components/script/dom/element.rs | 22 ++++++++-------------- components/script/parse/html.rs | 16 ++++------------ 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 37bf2d2ca23..cc3a6304eb3 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -1172,11 +1172,10 @@ impl<'a> ElementMethods for JSRef<'a, Element> { } fn SetInnerHTML(self, value: DOMString) -> Fallible<()> { - // 1. Let fragment be the result of invoking the fragment parsing algorithm - // with the new value as markup, and the context object as the context element. - // 2. Replace all with fragment within the context object. let context_node: JSRef = NodeCast::from_ref(self); + // Step 1. let frag = try!(context_node.parse_fragment(value)); + // Step 2. Node::replace_all(Some(NodeCast::from_ref(frag.root().r())), context_node); Ok(()) } @@ -1188,22 +1187,18 @@ impl<'a> ElementMethods for JSRef<'a, Element> { fn SetOuterHTML(self, value: DOMString) -> Fallible<()> { let context_document = document_from_node(self).root(); let context_node: JSRef = NodeCast::from_ref(self); - // 1. Let parent be the context object's parent. + // Step 1. let context_parent = match context_node.parent_node() { - // 2. If parent is null, terminate these steps. + // Step 2. None => return Ok(()), Some(parent) => parent.root() }; let parent: Root = match context_parent.r().type_id() { - // 3. If parent is a Document, throw a DOMException - // with name "NoModificationAllowedError" exception. + // Step 3. NodeTypeId::Document => return Err(NoModificationAllowed), - // 4. If parent is a DocumentFragment, let parent be a new Element with - // body as its local name, - // The HTML namespace as its namespace, and - // The context object's node document as its node document. + // Step 4. NodeTypeId::DocumentFragment => { let body_elem = Element::create(QualName::new(ns!(HTML), atom!(body)), None, context_document.r(), @@ -1214,10 +1209,9 @@ impl<'a> ElementMethods for JSRef<'a, Element> { _ => context_node.parent_node().unwrap().root() }; - // 5. Let fragment be the result of invoking the fragment parsing algorithm with - // the new value as markup, and parent as the context element. - // 6. Replace the context object with fragment within the context object's parent. + // Step 5. let frag = try!(parent.r().parse_fragment(value)); + // Step 6. try!(context_parent.r().ReplaceChild(NodeCast::from_ref(frag.root().r()), context_node)); Ok(()) diff --git a/components/script/parse/html.rs b/components/script/parse/html.rs index ad8c56ba613..f6cf86bf122 100644 --- a/components/script/parse/html.rs +++ b/components/script/parse/html.rs @@ -336,24 +336,16 @@ pub fn parse_html_fragment(context_node: JSRef, input: DOMString) -> Vec, input: DOMString) -> Vec = NodeCast::from_ref(root_element.r()); root_node.children() From 6422f3857430a50a320bf004023988a1d0c22273 Mon Sep 17 00:00:00 2001 From: Chris Paris Date: Wed, 1 Apr 2015 15:00:12 -1000 Subject: [PATCH 09/10] Remove Root type annotation in SetOuterHTML The 'use ... Root' was removed from the file by another commit, and this annotation wasn't necessary anyway. --- components/script/dom/element.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index cc3a6304eb3..4cfa77fdb4b 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -1194,7 +1194,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> { Some(parent) => parent.root() }; - let parent: Root = match context_parent.r().type_id() { + let parent = match context_parent.r().type_id() { // Step 3. NodeTypeId::Document => return Err(NoModificationAllowed), From f76a137344dfcc78d4d7c01dced36dad3591e35e Mon Sep 17 00:00:00 2001 From: Chris Paris Date: Wed, 1 Apr 2015 16:10:43 -1000 Subject: [PATCH 10/10] Produce output of fragment parsing in &mut RootedVec> argument --- components/script/dom/node.rs | 16 ++++++++-------- components/script/parse/html.rs | 11 +++++++---- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 3b49ba01ba9..7cd01875b15 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -936,16 +936,16 @@ impl<'a> NodeHelpers<'a> for JSRef<'a, Node> { fn parse_fragment(self, markup: DOMString) -> Fallible> { let context_node: JSRef = NodeCast::from_ref(self); let context_document = document_from_node(self).root(); - let new_children = - if context_document.r().is_html_document() { - parse_html_fragment(context_node, markup) - } else { - // FIXME: XML case - unimplemented!() - }; + let mut new_children: RootedVec> = RootedVec::new(); + if context_document.r().is_html_document() { + parse_html_fragment(context_node, markup, &mut new_children); + } else { + // FIXME: XML case + unimplemented!(); + } let fragment = DocumentFragment::new(context_document.r()).root(); let fragment_node: JSRef = NodeCast::from_ref(fragment.r()); - for node in new_children { + for node in new_children.iter() { fragment_node.AppendChild(node.root().r()).unwrap(); } Ok(Temporary::from_rooted(fragment.r())) diff --git a/components/script/parse/html.rs b/components/script/parse/html.rs index f6cf86bf122..2aecd9264e9 100644 --- a/components/script/parse/html.rs +++ b/components/script/parse/html.rs @@ -12,6 +12,7 @@ use dom::bindings::codegen::InheritTypes::{DocumentTypeCast, TextCast, CommentCa use dom::bindings::codegen::InheritTypes::ProcessingInstructionCast; use dom::bindings::codegen::InheritTypes::HTMLFormElementDerived; use dom::bindings::js::{JS, JSRef, Temporary, OptionalRootable, Root}; +use dom::bindings::trace::RootedVec; use dom::comment::Comment; use dom::document::{Document, DocumentHelpers}; use dom::document::{DocumentSource, IsHTMLDocument}; @@ -331,7 +332,9 @@ pub fn parse_html(document: JSRef, } // https://html.spec.whatwg.org/multipage/syntax.html#parsing-html-fragments -pub fn parse_html_fragment(context_node: JSRef, input: DOMString) -> Vec> { +pub fn parse_html_fragment(context_node: JSRef, + input: DOMString, + output: &mut RootedVec>) { let window = window_from_node(context_node).root(); let context_document = document_from_node(context_node).root(); let url = context_document.r().url(); @@ -357,7 +360,7 @@ pub fn parse_html_fragment(context_node: JSRef, input: DOMString) -> Vec = NodeCast::from_ref(root_element.r()); - root_node.children() - .map(|node| Temporary::from_rooted(node)) - .collect() + for child in root_node.children() { + output.push(JS::from_rooted(child)); + } }