mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Auto merge of #5338 - ChrisParis:outerhtml, r=jdm
The first commit refactors the fragment parsing and innerHTML setter. This makes the code mirror the structure of the spec more closely, and also prepares for reusing code with the outerHTML setter.
This commit is contained in:
commit
45b40d49a5
5 changed files with 102 additions and 62 deletions
|
@ -10,7 +10,6 @@ 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;
|
||||
|
@ -24,10 +23,10 @@ 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};
|
||||
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;
|
||||
|
@ -37,7 +36,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 +53,8 @@ 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 style::legacy::{SimpleColorAttribute, UnsignedIntegerAttribute, IntegerAttribute, LengthAttribute};
|
||||
use selectors::matching::matches;
|
||||
use style::properties::{PropertyDeclarationBlock, PropertyDeclaration, parse_style_attribute};
|
||||
|
@ -1169,60 +1165,18 @@ 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<DOMString> {
|
||||
//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();
|
||||
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()));
|
||||
}
|
||||
|
||||
// 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(())
|
||||
}
|
||||
|
||||
|
@ -1230,6 +1184,39 @@ 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<Node> = NodeCast::from_ref(self);
|
||||
// Step 1.
|
||||
let context_parent = match context_node.parent_node() {
|
||||
// Step 2.
|
||||
None => return Ok(()),
|
||||
Some(parent) => parent.root()
|
||||
};
|
||||
|
||||
let parent = match context_parent.r().type_id() {
|
||||
// Step 3.
|
||||
NodeTypeId::Document => return Err(NoModificationAllowed),
|
||||
|
||||
// Step 4.
|
||||
NodeTypeId::DocumentFragment => {
|
||||
let body_elem = Element::create(QualName::new(ns!(HTML), atom!(body)),
|
||||
None, context_document.r(),
|
||||
ElementCreator::ScriptCreated);
|
||||
let body_node: Temporary<Node> = NodeCast::from_temporary(body_elem);
|
||||
body_node.root()
|
||||
},
|
||||
_ => context_node.parent_node().unwrap().root()
|
||||
};
|
||||
|
||||
// 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(())
|
||||
}
|
||||
|
||||
// http://dom.spec.whatwg.org/#dom-parentnode-children
|
||||
fn Children(self) -> Temporary<HTMLCollection> {
|
||||
let window = window_from_node(self).root();
|
||||
|
|
|
@ -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::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: DOMString) -> Fallible<Temporary<DocumentFragment>>;
|
||||
}
|
||||
|
||||
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: DOMString) -> Fallible<Temporary<DocumentFragment>> {
|
||||
let context_node: JSRef<Node> = NodeCast::from_ref(self);
|
||||
let context_document = document_from_node(self).root();
|
||||
let mut new_children: RootedVec<JS<Node>> = 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<Node> = NodeCast::from_ref(fragment.r());
|
||||
for node in new_children.iter() {
|
||||
fragment_node.AppendChild(node.root().r()).unwrap();
|
||||
}
|
||||
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<JSRef<Node>>, parent: JSRef<Node>) {
|
||||
pub fn replace_all(node: Option<JSRef<Node>>, parent: JSRef<Node>) {
|
||||
// Step 1.
|
||||
match node {
|
||||
Some(node) => {
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue