///|
fn is_table_start_foster_target(name : StringView) -> Bool {
match name {
"table" | "tbody" | "tfoot" | "thead" | "tr" => true
_ => false
}
}
///|
fn Parser::table_start_foster_mode(self : Parser, name : StringView) -> Int {
if name == "style" || name == "script" || name == "template" {
return 0
}
if is_table_internal_start_name(name) {
return 0
}
let table_index = self.table_context_without_cell_or_caption()
if table_index < 0 {
return 0
}
let current = self.current_node()
if current.kind != Element || !is_table_start_foster_target(current.name) {
return 0
}
if current.name == "tr" {
1
} else {
2
}
}
///|
fn Parser::table_index_is_fragment_context_table(
self : Parser,
table_index : Int,
) -> Bool {
if table_index < 0 {
return false
}
match self.fragment_context_table {
Some(table) => physical_equal(self.stack[table_index], table)
None => false
}
}
///|
fn Parser::insert_node_before_open_table(
self : Parser,
node : @dom.Node,
table_index : Int,
) -> Unit {
let table = self.stack[table_index]
match table.parent {
Some(parent) => parent.insert_before(node, Some(table))
None => self.root.append_child(node)
}
}
///|
fn Parser::append_start_tag_node(
self : Parser,
node : @dom.Node,
name : StringView,
start : Int,
) -> Unit {
let foster_mode = self.table_start_foster_mode(name)
if foster_mode == 0 {
self.record_template_content_flow_insert(name)
if self.bare_template_row_fosters(name) && !node_is_hidden_input(node) {
// Hidden inputs are the table-mode exception: they stay at the
// insertion point instead of being foster-parented.
match self.current_node().parent {
Some(contents) => {
contents.append_child(node)
return
}
None => ()
}
}
self.current_node().append_child(node)
self.mark_forced_body_node(node)
return
}
if foster_mode == 2 {
self.error_at("foster-parenting-start-tag", start)
self.foster_parented_start_error_nodes.push(node)
}
let table_index = self.last_open_table_index()
if self.table_index_is_fragment_context_table(table_index) {
self.current_node().append_child(node)
return
}
self.insert_node_before_open_table(node, self.last_open_table_index())
// A foster-parented element is body content even when it precedes the
// table at the document top level; without the marker the scaffolder
// would file head-ish names (title, meta, ...) into the head.
self.forced_body_nodes.push(node)
}
///|
fn Parser::remove_foster_parented_start_error_node(
self : Parser,
target : @dom.Node,
) -> Bool {
let mut index = 0
while index < self.foster_parented_start_error_nodes.length() {
if physical_equal(self.foster_parented_start_error_nodes[index], target) {
ignore(self.foster_parented_start_error_nodes.remove(index))
return true
}
index += 1
}
false
}
///|
fn Parser::handle_foster_parented_end_tag(
self : Parser,
name : String,
start : Int,
) -> Bool {
let table_index = self.table_context_without_cell_or_caption()
if table_index < 0 {
return false
}
let target_index = self.last_stack_index_of(name)
if target_index <= table_index {
return false
}
if active_formatting_element_name(name) &&
self.active_formatting_index(name) >= 0 {
// Formatting end tags in table context use the in-body rules with
// foster parenting: the adoption agency algorithm restructures the
// fostered elements (its common-ancestor insertion fosters before
// the table).
return false
}
let target = self.stack[target_index]
if self.remove_foster_parented_start_error_node(target) {
self.error_at("unexpected-end-tag-implies-table-voodoo", start)
}
self.pop_until(name, start)
true
}
///|
fn node_is_hidden_input(node : @dom.Node) -> Bool {
if node.kind != Element || node.name != "input" {
return false
}
match node.attrs.get("type") {
Some(Some(value)) => @syn.lower_ascii(value) == "hidden"
_ => false
}
}