///|
fn is_table_section_name(name : StringView) -> Bool {
name is ("tbody" | "thead" | "tfoot")
}
///|
fn is_table_cell_name(name : StringView) -> Bool {
name is ("td" | "th")
}
///|
fn normalize_table_section(section : @dom.Node) -> Unit {
let original = section.children.copy()
section.children.clear()
let mut current_row : @dom.Node? = None
for child in original {
normalize_tables(child)
if child.kind == Element && is_table_cell_name(child.name) {
let row = match current_row {
Some(row) => row
None => {
let row = @dom.element("tr")
section.append_child(row)
current_row = Some(row)
row
}
}
row.append_child(child)
} else {
section.append_child(child)
current_row = None
}
}
}
///|
fn table_implicit_body(
table : @dom.Node,
current_body : @dom.Node?,
) -> (@dom.Node, @dom.Node?) {
match current_body {
Some(body) => (body, current_body)
None => {
let body = @dom.element("tbody")
table.append_child(body)
(body, Some(body))
}
}
}
///|
fn table_implicit_colgroup(
table : @dom.Node,
current_colgroup : @dom.Node?,
) -> (@dom.Node, @dom.Node?) {
match current_colgroup {
Some(colgroup) => (colgroup, current_colgroup)
None => {
let colgroup = @dom.element("colgroup")
table.append_child(colgroup)
(colgroup, Some(colgroup))
}
}
}
///|
fn normalize_table(table : @dom.Node) -> Unit {
let original = table.children.copy()
table.children.clear()
let mut current_body : @dom.Node? = None
let mut current_row : @dom.Node? = None
let mut current_colgroup : @dom.Node? = None
let mut in_implicit_section = false
for child in original {
normalize_tables(child)
if child.kind == Element && child.name == "col" {
let (colgroup, next_colgroup) = table_implicit_colgroup(
table, current_colgroup,
)
current_colgroup = next_colgroup
colgroup.append_child(child)
current_body = None
current_row = None
} else if child.kind == Text &&
current_colgroup is Some(colgroup) &&
!text_has_non_ascii_whitespace(child.data) {
colgroup.append_child(child)
current_body = None
current_row = None
} else if child.kind == Element && child.name == "tr" {
let (body, next_body) = table_implicit_body(table, current_body)
current_body = next_body
body.append_child(child)
current_row = None
current_colgroup = None
in_implicit_section = true
} else if child.kind == Element && is_table_cell_name(child.name) {
let (body, next_body) = table_implicit_body(table, current_body)
current_body = next_body
let row = match current_row {
Some(row) => row
None => {
let row = @dom.element("tr")
body.append_child(row)
current_row = Some(row)
row
}
}
row.append_child(child)
current_colgroup = None
in_implicit_section = true
} else {
if child.kind == Comment &&
in_implicit_section &&
current_row is Some(row) {
// A comment between bare cells stays in the still-open implicit
// row; the next cell continues it.
row.append_child(child)
continue
}
if (
child.kind == Comment ||
(child.kind == Text && is_whitespace_text_node(child))
) &&
in_implicit_section &&
table.children.length() > 0 {
// Whitespace while an implicit row group is still open stays
// inside it (the in-table-body insertion point); after an
// explicitly closed section it remains a table child.
let last = table.children[table.children.length() - 1]
if last.kind == Element && is_table_section_name(last.name) {
// The implicit row group stays open: a following row joins it
// rather than starting a new one.
last.append_child(child)
current_body = Some(last)
current_row = None
current_colgroup = None
continue
}
}
table.append_child(child)
current_body = None
current_row = None
current_colgroup = None
in_implicit_section = false
}
}
}
///|
fn normalize_tables(node : @dom.Node) -> Unit {
if node.template_contents is Some(contents) {
normalize_tables(contents)
}
let html_ns = node.ns is None || node.ns is Some("html")
match node.kind {
Element if html_ns && node.name == "table" => normalize_table(node)
Element if html_ns && is_table_section_name(node.name) =>
normalize_table_section(node)
_ =>
for child in node.children {
normalize_tables(child)
}
}
}