///|
fn is_table_or_section_context(name : StringView) -> Bool {
match name {
"table" | "tbody" | "tfoot" | "thead" => true
_ => false
}
}
///|
fn is_table_internal_start_name(name : StringView) -> Bool {
match name {
"caption"
| "col"
| "colgroup"
| "tbody"
| "td"
| "tfoot"
| "th"
| "thead"
| "tr"
| "table" => true
_ => false
}
}
///|
fn Parser::last_open_table_index(self : Parser) -> Int {
let mut index = self.stack.length()
while index > 0 {
index -= 1
let node = self.stack[index]
if node.kind == Element && node.name == "table" {
return index
}
}
-1
}
///|
fn Parser::table_text_is_inside_cell_or_caption(
self : Parser,
table_index : Int,
) -> Bool {
let mut index = table_index + 1
while index < self.stack.length() {
let node = self.stack[index]
if node.kind == Element &&
(node.name == "td" || node.name == "th" || node.name == "caption") {
return true
}
index += 1
}
false
}
///|
fn Parser::current_is_table_or_section_context(self : Parser) -> Bool {
let table_index = self.table_context_without_cell_or_caption()
if table_index < 0 {
return false
}
let current = self.current_node()
current.kind == Element && is_table_or_section_context(current.name)
}
///|
fn input_attrs_type_is_hidden(attrs : Map[String, String?]) -> Bool {
match attrs.get("type") {
Some(Some(value)) => value[:].compare_ignore_ascii_case("hidden") == 0
_ => false
}
}
///|
fn Parser::handle_table_context_hidden_input_or_form_start(
self : Parser,
name : String,
attrs : Map[String, String?],
start : Int,
error_pos : Int,
) -> Bool {
if !self.current_is_table_or_section_context() {
return false
}
if name == "input" && input_attrs_type_is_hidden(attrs) {
self.error_at("unexpected-hidden-input-in-table", error_pos)
self
.current_node()
.append_child(self.node_with_origin(@dom.element(name, attrs~), start))
return true
}
if name == "form" {
self.error_at("unexpected-form-in-table", error_pos)
if self.form_element is None {
let node = self.node_with_origin(@dom.element(name, attrs~), start)
self.form_element = Some(node)
self.current_node().append_child(node)
}
return true
}
false
}
///|
fn Parser::handle_nested_table_start_tag(
self : Parser,
name : String,
tag_close_pos : Int,
) -> Bool {
if name != "table" {
return false
}
let table_index = self.table_context_without_cell_or_caption()
if table_index < 0 {
return false
}
let current = self.current_node()
if current.kind != Element || !is_table_start_foster_target(current.name) {
return false
}
self.error_at("unexpected-start-tag-implies-end-tag", tag_close_pos)
ignore(self.close_open_element("table"))
true
}
///|
fn Parser::report_unexpected_table_body_cell_start(
self : Parser,
name : String,
tag_close_pos : Int,
) -> Unit {
let current = self.current_node()
if (name == "td" || name == "th") &&
(
self.current_is_table_or_section_context() ||
(
self.in_template_content_without_inner_table() &&
current.kind == Element &&
is_table_or_section_context(current.name)
)
) {
self.error_at("unexpected-cell-in-table-body", tag_close_pos)
}
}
///|
fn Parser::table_context_without_cell_or_caption(self : Parser) -> Int {
let table_index = self.last_open_table_index()
if table_index < 0 || self.table_text_is_inside_cell_or_caption(table_index) {
-1
} else {
table_index
}
}
///|
fn Parser::last_table_section_index_after(
self : Parser,
table_index : Int,
) -> Int {
let mut index = self.stack.length()
while index > table_index + 1 {
index -= 1
let node = self.stack[index]
if node.kind == Element && is_table_section_name(node.name) {
return index
}
}
-1
}
///|
fn Parser::table_context_keep_index_for_start(
self : Parser,
name : StringView,
table_index : Int,
) -> Int {
match name {
"col" => {
let colgroup_index = self.last_stack_index_of("colgroup")
if colgroup_index > table_index {
colgroup_index
} else {
table_index
}
}
"td" | "th" => {
let row_index = self.last_stack_index_of("tr")
if row_index > table_index {
return row_index
}
let section_index = self.last_table_section_index_after(table_index)
if section_index > table_index {
return section_index
}
table_index
}
"tr" => {
let section_index = self.last_table_section_index_after(table_index)
if section_index > table_index {
section_index
} else {
table_index
}
}
_ => table_index
}
}
///|
fn Parser::clear_stack_to_table_context_for_start(
self : Parser,
name : StringView,
) -> Unit {
if !is_table_internal_start_name(name) {
return
}
let table_index = self.table_context_without_cell_or_caption()
if table_index < 0 {
return
}
let keep_index = self.table_context_keep_index_for_start(name, table_index)
while self.stack.length() > keep_index + 1 {
ignore(self.stack.pop())
}
}
///|
fn Parser::table_context_start_skips_active_reconstruction(
self : Parser,
name : StringView,
) -> Bool {
is_table_internal_start_name(name) &&
self.table_context_without_cell_or_caption() >= 0
}
///|
fn Parser::current_table_last_child_is_col(self : Parser) -> Bool {
let current = self.current_node()
if current.kind != Element || current.name != "table" {
return false
}
match current.children.last() {
Some(child) => child.kind == Element && child.name == "col"
None => false
}
}