Skip to content

Commit 702aa59

Browse files
committed
Add support for headless tables
Closes GH-59.
1 parent 0ade128 commit 702aa59

File tree

4 files changed

+177
-47
lines changed

4 files changed

+177
-47
lines changed

lib/handlers/table.js

Lines changed: 48 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -7,67 +7,58 @@ var visit = require('unist-util-visit')
77
var all = require('../all')
88

99
function table(h, node) {
10-
var align = alignment(node)
11-
return h(node, 'table', {align: align}, toRows(all(h, node), align.length))
10+
var info = inspect(node)
11+
return h(node, 'table', {align: info.align}, toRows(all(h, node), info))
1212
}
1313

14-
// Infer the alignment of the table.
15-
function alignment(node) {
14+
// Infer whether the HTML table has a head and how it aligns.
15+
function inspect(node) {
16+
var headless = true
1617
var align = []
18+
var rowIndex = 0
19+
var cellIndex = 0
1720

18-
visit(node, visitor)
21+
visit(node, 'element', visitor)
1922

20-
return align
23+
return {align: align, headless: headless}
2124

22-
function visitor(child, index, parent) {
23-
var pos
25+
function visitor(child) {
26+
var name = child.tagName
2427

25-
if (cell(child)) {
26-
pos = cellsBefore(parent, child)
27-
if (!align[pos]) {
28-
align[pos] = child.properties.align || null
28+
// If there is a `thead`, assume there is a header row.
29+
if (name === 'thead') {
30+
headless = false
31+
} else if (name === 'tr') {
32+
rowIndex++
33+
cellIndex = 0
34+
} else if (name === 'th' || name === 'td') {
35+
if (!align[cellIndex]) {
36+
align[cellIndex] = child.properties.align || null
2937
}
30-
}
31-
}
32-
}
33-
34-
// Count cells in `parent` before `node`.
35-
function cellsBefore(parent, node) {
36-
var children = parent.children
37-
var length = children.length
38-
var index = -1
39-
var child
40-
var pos = 0
4138

42-
while (++index < length) {
43-
child = children[index]
44-
45-
if (child === node) {
46-
break
47-
}
39+
// If there is a th in the first row, assume there is a header row.
40+
if (headless && rowIndex < 2 && child.tagName === 'th') {
41+
headless = false
42+
}
4843

49-
/* istanbul ignore else - When proper HTML, should always be a cell */
50-
if (cell(child)) {
51-
pos++
44+
cellIndex++
5245
}
5346
}
54-
55-
return pos
56-
}
57-
58-
// Check if `node` is a cell.
59-
function cell(node) {
60-
return node.tagName === 'th' || node.tagName === 'td'
6147
}
6248

63-
// Ensure the amount of cells in a row matches `align.left`.
64-
function toRows(rows, count) {
49+
// Ensure the rows are properly structured.
50+
function toRows(rows, info) {
6551
var nodes = []
6652
var length = rows.length
6753
var index = -1
6854
var node
6955
var queue
7056

57+
// Add an empty header row.
58+
if (info.headless) {
59+
add(tableRow([]))
60+
}
61+
7162
while (++index < length) {
7263
node = rows[index]
7364

@@ -85,17 +76,19 @@ function toRows(rows, count) {
8576

8677
function flush() {
8778
if (queue) {
88-
add({type: 'tableRow', children: queue})
79+
add(tableRow(queue))
8980
queue = undefined
9081
}
9182
}
9283

9384
function add(node) {
94-
nodes.push(cells(node, count))
85+
nodes.push(cells(node, info))
9586
}
9687
}
9788

98-
function cells(row, count) {
89+
// Ensure the cells in a row are properly structured.
90+
function cells(row, info) {
91+
var columnCount = info.align.length
9992
var nodes = []
10093
var cells = row.children
10194
var length = cells.length
@@ -117,18 +110,26 @@ function cells(row, count) {
117110
flush()
118111

119112
index = nodes.length
120-
length = count + 1
113+
length = columnCount + 1
121114

122115
while (++index < length) {
123-
nodes.push({type: 'tableCell', children: []})
116+
nodes.push(tableCell([]))
124117
}
125118

126119
return xtend(row, {children: nodes})
127120

128121
function flush() {
129122
if (queue) {
130-
nodes.push({type: 'tableCell', children: queue})
123+
nodes.push(tableCell(queue))
131124
queue = undefined
132125
}
133126
}
134127
}
128+
129+
function tableRow(children) {
130+
return {type: 'tableRow', children: children}
131+
}
132+
133+
function tableCell(children) {
134+
return {type: 'tableCell', children: children}
135+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
No wrapping elements:
2+
3+
<table>
4+
<tr>
5+
<td>Cell 1</td>
6+
<td>Cell 2</td>
7+
</tr>
8+
<tr>
9+
<td>Cell 3</td>
10+
<td>Cell 4</td>
11+
</tr>
12+
</table>
13+
14+
No <code>thead</code>:
15+
16+
<table>
17+
<tbody>
18+
<tr>
19+
<td>Cell 1</td>
20+
<td>Cell 2</td>
21+
</tr>
22+
<tr>
23+
<td>Cell 3</td>
24+
<td>Cell 4</td>
25+
</tr>
26+
</tbody>
27+
</table>
28+
29+
With align:
30+
31+
<table>
32+
<tr>
33+
<td align="left">Cell 1</td>
34+
<td align="right">Cell 2</td>
35+
</tr>
36+
<tr>
37+
<td align="left">Cell 3</td>
38+
<td align="right">Cell 4</td>
39+
</tr>
40+
</table>
41+
42+
<p>Here’s a Sudoku:</p>
43+
44+
<table>
45+
<colgroup><col><col><col>
46+
<colgroup><col><col><col>
47+
<colgroup><col><col><col>
48+
<tbody>
49+
<tr><td> 1 <td> <td> 3 <td> 6 <td> <td> 4 <td> 7 <td> <td> 9
50+
<tr><td> <td> 2 <td> <td> <td> 9 <td> <td> <td> 1 <td>
51+
<tr><td> 7 <td> <td> <td> <td> <td> <td> <td> <td> 6
52+
<tbody>
53+
<tr><td> 2 <td> <td> 4 <td> <td> 3 <td> <td> 9 <td> <td> 8
54+
<tr><td> <td> <td> <td> <td> <td> <td> <td> <td>
55+
<tr><td> 5 <td> <td> <td> 9 <td> <td> 7 <td> <td> <td> 1
56+
<tbody>
57+
<tr><td> 6 <td> <td> <td> <td> 5 <td> <td> <td> <td> 2
58+
<tr><td> <td> <td> <td> <td> 7 <td> <td> <td> <td>
59+
<tr><td> 9 <td> <td> <td> 8 <td> <td> 2 <td> <td> <td> 5
60+
</table>
61+
62+
<p>Here’s a table with a <code>thead</code> with <em>two</em> rows:</p>
63+
64+
<table>
65+
<caption> School auction sign-up sheet </caption>
66+
<thead>
67+
<tr>
68+
<th>Name
69+
<th>Product
70+
<th>Price
71+
<tr>
72+
<td>Your name here
73+
<td>What are you selling?
74+
<td>Your reserve price
75+
<tbody>
76+
<tr>
77+
<td>Ms Danus
78+
<td>Doughnuts
79+
<td>$45
80+
<tr>
81+
<td>
82+
<td>
83+
<td>
84+
</table>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"fragment": true
3+
}

test/fixtures/table-headless/index.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
No wrapping elements:
2+
3+
| | |
4+
| ------ | ------ |
5+
| Cell 1 | Cell 2 |
6+
| Cell 3 | Cell 4 |
7+
8+
No `thead`:
9+
10+
| | |
11+
| ------ | ------ |
12+
| Cell 1 | Cell 2 |
13+
| Cell 3 | Cell 4 |
14+
15+
With align:
16+
17+
| | |
18+
| :----- | -----: |
19+
| Cell 1 | Cell 2 |
20+
| Cell 3 | Cell 4 |
21+
22+
Here’s a Sudoku:
23+
24+
| | | | | | | | | |
25+
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
26+
| 1 | | 3 | 6 | | 4 | 7 | | 9 |
27+
| | 2 | | | 9 | | | 1 | |
28+
| 7 | | | | | | | | 6 |
29+
| 2 | | 4 | | 3 | | 9 | | 8 |
30+
| | | | | | | | | |
31+
| 5 | | | 9 | | 7 | | | 1 |
32+
| 6 | | | | 5 | | | | 2 |
33+
| | | | | 7 | | | | |
34+
| 9 | | | 8 | | 2 | | | 5 |
35+
36+
Here’s a table with a `thead` with _two_ rows:
37+
38+
| Name | Product | Price |
39+
| -------------- | --------------------- | ------------------ |
40+
| Your name here | What are you selling? | Your reserve price |
41+
| Ms Danus | Doughnuts | $45 |
42+
| | | |

0 commit comments

Comments
 (0)