Print cells in table header as <th> as opposed to <td>.

This commit is contained in:
Michael Färber 2025-01-21 11:07:52 +01:00
parent b112772a1e
commit b2b2593832

View File

@ -9,9 +9,9 @@ use crate::foundations::{
cast, elem, scope, Content, NativeElement, Packed, Show, Smart, StyleChain, cast, elem, scope, Content, NativeElement, Packed, Show, Smart, StyleChain,
TargetElem, TargetElem,
}; };
use crate::html::{tag, HtmlAttr, HtmlAttrs, HtmlElem}; use crate::html::{tag, HtmlAttr, HtmlAttrs, HtmlElem, HtmlTag};
use crate::introspection::Locator; use crate::introspection::Locator;
use crate::layout::grid::resolve::table_to_cellgrid; use crate::layout::grid::resolve::{table_to_cellgrid, Cell, CellGrid, Entry};
use crate::layout::{ use crate::layout::{
show_grid_cell, Abs, Alignment, BlockElem, Celled, GridCell, GridFooter, GridHLine, show_grid_cell, Abs, Alignment, BlockElem, Celled, GridCell, GridFooter, GridHLine,
GridHeader, GridVLine, Length, OuterHAlignment, OuterVAlignment, Rel, Sides, GridHeader, GridVLine, Length, OuterHAlignment, OuterVAlignment, Rel, Sides,
@ -262,34 +262,61 @@ impl TableElem {
type TableFooter; type TableFooter;
} }
impl Show for Packed<TableElem> { fn show_cell_html(tag: HtmlTag, cell: &Cell, styles: StyleChain) -> Content {
fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let cell = cell.body.clone();
Ok(if TargetElem::target_in(styles).is_html() { let Some(cell) = cell.to_packed::<TableCell>() else { return cell };
// TODO: This is a hack, it is not clear whether the locator is actually used by HTML. let mut attrs = HtmlAttrs::default();
// How can we find out whether locator is actually used? let span = |n: NonZeroUsize| (n != NonZeroUsize::MIN).then(|| n.to_string());
let locator = Locator::root(); if let Some(colspan) = span(cell.colspan(styles)) {
attrs.push(HtmlAttr::constant("colspan"), colspan);
}
if let Some(rowspan) = span(cell.rowspan(styles)) {
attrs.push(HtmlAttr::constant("rowspan"), rowspan);
}
HtmlElem::new(tag)
.with_body(Some(cell.body.clone()))
.with_attrs(attrs)
.pack()
.spanned(cell.span())
}
fn show_cellgrid_html(grid: CellGrid, styles: StyleChain) -> Content {
let elem = |tag, body| HtmlElem::new(tag).with_body(Some(body)).pack(); let elem = |tag, body| HtmlElem::new(tag).with_body(Some(body)).pack();
let grid = table_to_cellgrid(self, engine, locator, styles)?; let mut rows: Vec<_> = grid.entries.chunks(grid.cols.len()).collect();
let rows = grid.entries.chunks(grid.cols.len()).map(|row| {
let row = row.iter().flat_map(|entry| entry.as_cell()); let tr = |tag, row: &[Entry]| {
elem(tag::tr, Content::sequence(row.map(|cell| cell.body.clone()))) let row = row
}); .iter()
let mut rows: Vec<_> = rows.collect(); .flat_map(|entry| entry.as_cell())
.map(|cell| show_cell_html(tag, cell, styles));
elem(tag::tr, Content::sequence(row))
};
let footer = grid.footer.map(|ft| { let footer = grid.footer.map(|ft| {
elem(tag::tfoot, Content::sequence(rows.drain(ft.unwrap().start..))) let rows = rows.drain(ft.unwrap().start..);
elem(tag::tfoot, Content::sequence(rows.map(|row| tr(tag::td, row))))
}); });
let header = grid.header.map(|hd| { let header = grid.header.map(|hd| {
elem(tag::thead, Content::sequence(rows.drain(..hd.unwrap().end))) let rows = rows.drain(..hd.unwrap().end);
elem(tag::thead, Content::sequence(rows.map(|row| tr(tag::th, row))))
}); });
let mut body = Content::sequence(rows); let mut body = Content::sequence(rows.into_iter().map(|row| tr(tag::td, row)));
if header.is_some() || footer.is_some() { if header.is_some() || footer.is_some() {
body = elem(tag::tbody, body); body = elem(tag::tbody, body);
} }
let content = header.into_iter().chain(core::iter::once(body)).chain(footer); let content = header.into_iter().chain(core::iter::once(body)).chain(footer);
elem(tag::table, Content::sequence(content)) elem(tag::table, Content::sequence(content))
}
impl Show for Packed<TableElem> {
fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
Ok(if TargetElem::target_in(styles).is_html() {
// TODO: This is a hack, it is not clear whether the locator is actually used by HTML.
// How can we find out whether locator is actually used?
let locator = Locator::root();
show_cellgrid_html(table_to_cellgrid(self, engine, locator, styles)?, styles)
} else { } else {
BlockElem::multi_layouter(self.clone(), engine.routines.layout_table).pack() BlockElem::multi_layouter(self.clone(), engine.routines.layout_table).pack()
} }
@ -737,22 +764,9 @@ cast! {
impl Show for Packed<TableCell> { impl Show for Packed<TableCell> {
fn show(&self, _engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { fn show(&self, _engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
if TargetElem::target_in(styles).is_html() {
let mut attrs = HtmlAttrs::default();
let span = |n: NonZeroUsize| (n != NonZeroUsize::MIN).then(|| n.to_string());
if let Some(colspan) = span(self.colspan(styles)) {
attrs.push(HtmlAttr::constant("colspan"), colspan);
}
if let Some(rowspan) = span(self.rowspan(styles)) {
attrs.push(HtmlAttr::constant("rowspan"), rowspan);
}
let body = Some(self.body.clone());
Ok(HtmlElem::new(tag::td).with_body(body).with_attrs(attrs).pack())
} else {
show_grid_cell(self.body.clone(), self.inset(styles), self.align(styles)) show_grid_cell(self.body.clone(), self.inset(styles), self.align(styles))
} }
} }
}
impl Default for Packed<TableCell> { impl Default for Packed<TableCell> {
fn default() -> Self { fn default() -> Self {