// Copyright 2014-2017 The html5ever Project Developers. See the // COPYRIGHT file at the top-level directory of this distribution. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. /// Something which can be inserted into the DOM. /// /// Adjacent sibling text nodes are merged into a single node, so /// the sink may not want to allocate a `Handle` for each. #[allow(unused_imports)] use std::ascii::AsciiExt; use std::borrow::Cow; use tendril::StrTendril; use interface::{QualName, ExpandedName, Attribute}; pub use self::NodeOrText::{AppendNode, AppendText}; pub use self::QuirksMode::{Quirks, LimitedQuirks, NoQuirks}; /// Something which can be inserted into the DOM. /// /// Adjacent sibling text nodes are merged into a single node, so /// the sink may not want to allocate a `Handle` for each. pub enum NodeOrText { AppendNode(Handle), AppendText(StrTendril), } /// A document's quirks mode. #[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)] pub enum QuirksMode { Quirks, LimitedQuirks, NoQuirks, } /// Whether to interrupt further parsing of the current input until /// the next explicit resumption of the tokenizer, or continue without /// any interruption. #[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)] pub enum NextParserState { /// Stop further parsing. Suspend, /// Continue without interruptions. Continue, } #[derive(Default)] pub struct ElementFlags { /// A document fragment should be created, associated with the element, /// and returned in TreeSink::get_template_contents /// /// https://html.spec.whatwg.org/multipage/#template-contents pub template: bool, /// This boolean should be recorded with the element and returned /// in TreeSink::is_mathml_annotation_xml_integration_point /// /// https://html.spec.whatwg.org/multipage/#html-integration-point pub mathml_annotation_xml_integration_point: bool, _private: () } pub fn create_element(sink: &mut Sink, name: QualName, attrs: Vec) -> Sink::Handle where Sink: TreeSink { let mut flags = ElementFlags::default(); match name.expanded() { expanded_name!(html "template") => { flags.template = true } expanded_name!(mathml "annotation-xml") => { flags.mathml_annotation_xml_integration_point = attrs.iter().any(|attr| { attr.name.expanded() == expanded_name!("", "encoding") && ( attr.value.eq_ignore_ascii_case("text/html") || attr.value.eq_ignore_ascii_case("application/xhtml+xml") ) }) } _ => {} } sink.create_element(name, attrs, flags) } pub trait TreeSink { /// `Handle` is a reference to a DOM node. The tree builder requires /// that a `Handle` implements `Clone` to get another reference to /// the same node. type Handle: Clone; /// The overall result of parsing. /// /// This should default to Self, but default associated types are not stable yet. /// (https://github.com/rust-lang/rust/issues/29661) type Output; /// Consume this sink and return the overall result of parsing. /// /// TODO:This should default to `fn finish(self) -> Self::Output { self }`, /// but default associated types are not stable yet. /// (https://github.com/rust-lang/rust/issues/29661) fn finish(self) -> Self::Output; /// Signal a parse error. fn parse_error(&mut self, msg: Cow<'static, str>); /// Get a handle to the `Document` node. fn get_document(&mut self) -> Self::Handle; /// What is the name of this element? /// /// Should never be called on a non-element node; /// feel free to `panic!`. fn elem_name<'a>(&'a self, target: &'a Self::Handle) -> ExpandedName<'a>; /// Create an element. /// /// When creating a template element (`name.ns.expanded() == expanded_name!(html "template")`), /// an associated document fragment called the "template contents" should /// also be created. Later calls to self.get_template_contents() with that /// given element return it. /// https://html.spec.whatwg.org/multipage/#the-template-element fn create_element(&mut self, name: QualName, attrs: Vec, flags: ElementFlags) -> Self::Handle; /// Create a comment node. fn create_comment(&mut self, text: StrTendril) -> Self::Handle; /// Create a Processing Instruction node. fn create_pi(&mut self, target: StrTendril, data: StrTendril) -> Self::Handle; /// Append a node as the last child of the given node. If this would /// produce adjacent sibling text nodes, it should concatenate the text /// instead. /// /// The child node will not already have a parent. fn append(&mut self, parent: &Self::Handle, child: NodeOrText); /// When the insertion point is decided by the existence of a parent node of the /// element, we consider both possibilities and send the element which will be used /// if a parent node exists, along with the element to be used if there isn't one. fn append_based_on_parent_node(&mut self, element: &Self::Handle, prev_element: &Self::Handle, child: NodeOrText); /// Append a `DOCTYPE` element to the `Document` node. fn append_doctype_to_document(&mut self, name: StrTendril, public_id: StrTendril, system_id: StrTendril); /// Mark a HTML `