mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Implement Element.innerHTML setter
This commit is contained in:
parent
a521755607
commit
99286e4b4f
9 changed files with 109 additions and 67 deletions
|
@ -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()))
|
||||
}
|
||||
|
|
|
@ -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)))
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
[Document-getElementById.html]
|
||||
type: testharness
|
||||
[add id attribute via innerHTML]
|
||||
expected: FAIL
|
||||
|
||||
[remove id attribute via innerHTML]
|
||||
expected: FAIL
|
||||
|
||||
[add id attribute via outerHTML]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
[disabled-elements-01.html]
|
||||
type: testharness
|
||||
[Test [button\]: default behaviour is NOT disabled]
|
||||
expected: FAIL
|
||||
|
||||
[Test [button\]: verify disabled acts as boolean attribute]
|
||||
expected: FAIL
|
||||
|
||||
[Test [input\]: default behaviour is NOT disabled]
|
||||
expected: FAIL
|
||||
|
||||
[Test [input\]: verify disabled acts as boolean attribute]
|
||||
expected: FAIL
|
||||
|
||||
[Test [select\]: default behaviour is NOT disabled]
|
||||
expected: FAIL
|
||||
|
||||
[Test [select\]: verify disabled acts as boolean attribute]
|
||||
expected: FAIL
|
||||
|
||||
[Test [textarea\]: default behaviour is NOT disabled]
|
||||
expected: FAIL
|
||||
|
||||
[Test [textarea\]: verify disabled acts as boolean attribute]
|
||||
expected: FAIL
|
||||
|
||||
[Test [button\]: synthetic click events should be dispatched]
|
||||
expected: FAIL
|
||||
|
||||
[Test [button\]: click() should not dispatch a click event]
|
||||
expected: FAIL
|
||||
|
||||
[Test [input\]: synthetic click events should be dispatched]
|
||||
expected: FAIL
|
||||
|
||||
[Test [input\]: click() should not dispatch a click event]
|
||||
expected: FAIL
|
||||
|
||||
[Test [select\]: synthetic click events should be dispatched]
|
||||
expected: FAIL
|
||||
|
||||
[Test [select\]: click() should not dispatch a click event]
|
||||
expected: FAIL
|
||||
|
||||
[Test [textarea\]: synthetic click events should be dispatched]
|
||||
expected: FAIL
|
||||
|
||||
[Test [textarea\]: click() should not dispatch a click event]
|
||||
expected: FAIL
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
[033.html]
|
||||
type: testharness
|
||||
[ scheduler: innerHTML and scripts moved in DOM]
|
||||
expected: FAIL
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue