mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
initial html target support
This commit is contained in:
parent
1e3e6167af
commit
07a060a9da
@ -292,18 +292,61 @@ fn show_cellgrid_html(grid: CellGrid, styles: StyleChain) -> Content {
|
|||||||
elem(tag::tr, Content::sequence(row))
|
elem(tag::tr, Content::sequence(row))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO(subfooters): similarly to headers, take consecutive footers from
|
||||||
|
// the end for 'tfoot'.
|
||||||
let footer = grid.footer.map(|ft| {
|
let footer = grid.footer.map(|ft| {
|
||||||
let rows = rows.drain(ft.start..);
|
let rows = rows.drain(ft.start..);
|
||||||
elem(tag::tfoot, Content::sequence(rows.map(|row| tr(tag::td, row))))
|
elem(tag::tfoot, Content::sequence(rows.map(|row| tr(tag::td, row))))
|
||||||
});
|
});
|
||||||
// TODO: Headers and footers in arbitrary positions
|
|
||||||
// Right now, only those at either end are accepted
|
|
||||||
let header = grid.headers.first().filter(|h| h.start == 0).map(|hd| {
|
|
||||||
let rows = rows.drain(..hd.end);
|
|
||||||
elem(tag::thead, Content::sequence(rows.map(|row| tr(tag::th, row))))
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut body = Content::sequence(rows.into_iter().map(|row| tr(tag::td, row)));
|
// Store all consecutive headers at the start in 'thead'. All remaining
|
||||||
|
// headers are just 'th' rows across the table body.
|
||||||
|
let mut consecutive_header_end = 0;
|
||||||
|
let first_mid_table_header = grid
|
||||||
|
.headers
|
||||||
|
.iter()
|
||||||
|
.take_while(|hd| {
|
||||||
|
let is_consecutive = hd.start == consecutive_header_end;
|
||||||
|
consecutive_header_end = hd.end;
|
||||||
|
|
||||||
|
is_consecutive
|
||||||
|
})
|
||||||
|
.count();
|
||||||
|
|
||||||
|
let (y_offset, header) = if first_mid_table_header > 0 {
|
||||||
|
let removed_header_rows =
|
||||||
|
grid.headers.get(first_mid_table_header - 1).unwrap().end;
|
||||||
|
let rows = rows.drain(..removed_header_rows);
|
||||||
|
|
||||||
|
(
|
||||||
|
removed_header_rows,
|
||||||
|
Some(elem(tag::thead, Content::sequence(rows.map(|row| tr(tag::th, row))))),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(0, None)
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Consider improving accessibility properties of multi-level headers
|
||||||
|
// inside tables in the future, e.g. indicating which columns they are
|
||||||
|
// relative to and so on. See also:
|
||||||
|
// https://www.w3.org/WAI/tutorials/tables/multi-level/
|
||||||
|
let mut next_header = first_mid_table_header;
|
||||||
|
let mut body =
|
||||||
|
Content::sequence(rows.into_iter().enumerate().map(|(relative_y, row)| {
|
||||||
|
let y = relative_y + y_offset;
|
||||||
|
if let Some(current_header) =
|
||||||
|
grid.headers.get(next_header).filter(|h| h.range().contains(&y))
|
||||||
|
{
|
||||||
|
if y + 1 == current_header.end {
|
||||||
|
next_header += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr(tag::th, row)
|
||||||
|
} else {
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
69
tests/ref/html/multi-header-inside-table.html
Normal file
69
tests/ref/html/multi-header-inside-table.html
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>First</th>
|
||||||
|
<th>Header</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Second</th>
|
||||||
|
<th>Header</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Level 2</th>
|
||||||
|
<th>Header</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Level 3</th>
|
||||||
|
<th>Header</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Body</td>
|
||||||
|
<td>Cells</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Yet</td>
|
||||||
|
<td>More</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Level 2</th>
|
||||||
|
<th>Header Inside</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Level 3</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Even</td>
|
||||||
|
<td>More</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Body</td>
|
||||||
|
<td>Cells</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>One Last Header</th>
|
||||||
|
<th>For Good Measure</th>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td>Footer</td>
|
||||||
|
<td>Row</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Ending</td>
|
||||||
|
<td>Table</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
49
tests/ref/html/multi-header-table.html
Normal file
49
tests/ref/html/multi-header-table.html
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>First</th>
|
||||||
|
<th>Header</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Second</th>
|
||||||
|
<th>Header</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Level 2</th>
|
||||||
|
<th>Header</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Level 3</th>
|
||||||
|
<th>Header</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Body</td>
|
||||||
|
<td>Cells</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Yet</td>
|
||||||
|
<td>More</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td>Footer</td>
|
||||||
|
<td>Row</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Ending</td>
|
||||||
|
<td>Table</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -57,3 +57,78 @@
|
|||||||
[d], [e], [f],
|
[d], [e], [f],
|
||||||
[g], [h], [i]
|
[g], [h], [i]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
--- multi-header-table html ---
|
||||||
|
#table(
|
||||||
|
columns: 2,
|
||||||
|
|
||||||
|
table.header(
|
||||||
|
[First], [Header]
|
||||||
|
),
|
||||||
|
table.header(
|
||||||
|
[Second], [Header]
|
||||||
|
),
|
||||||
|
table.header(
|
||||||
|
[Level 2], [Header],
|
||||||
|
level: 2,
|
||||||
|
),
|
||||||
|
table.header(
|
||||||
|
[Level 3], [Header],
|
||||||
|
level: 3,
|
||||||
|
),
|
||||||
|
|
||||||
|
[Body], [Cells],
|
||||||
|
[Yet], [More],
|
||||||
|
|
||||||
|
table.footer(
|
||||||
|
[Footer], [Row],
|
||||||
|
[Ending], [Table],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
--- multi-header-inside-table html ---
|
||||||
|
#table(
|
||||||
|
columns: 2,
|
||||||
|
|
||||||
|
table.header(
|
||||||
|
[First], [Header]
|
||||||
|
),
|
||||||
|
table.header(
|
||||||
|
[Second], [Header]
|
||||||
|
),
|
||||||
|
table.header(
|
||||||
|
[Level 2], [Header],
|
||||||
|
level: 2,
|
||||||
|
),
|
||||||
|
table.header(
|
||||||
|
[Level 3], [Header],
|
||||||
|
level: 3,
|
||||||
|
),
|
||||||
|
|
||||||
|
[Body], [Cells],
|
||||||
|
[Yet], [More],
|
||||||
|
|
||||||
|
table.header(
|
||||||
|
[Level 2], [Header Inside],
|
||||||
|
level: 2,
|
||||||
|
),
|
||||||
|
table.header(
|
||||||
|
[Level 3],
|
||||||
|
level: 3,
|
||||||
|
),
|
||||||
|
|
||||||
|
[Even], [More],
|
||||||
|
[Body], [Cells],
|
||||||
|
|
||||||
|
table.header(
|
||||||
|
[One Last Header],
|
||||||
|
[For Good Measure],
|
||||||
|
repeat: false,
|
||||||
|
level: 4,
|
||||||
|
),
|
||||||
|
|
||||||
|
table.footer(
|
||||||
|
[Footer], [Row],
|
||||||
|
[Ending], [Table],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user