mirror of
https://github.com/showdownjs/showdown.git
synced 2024-03-22 13:30:55 +08:00
fix(tables): fix tables to match github's md spec
Now Leading and trailing pipes (|) are optional in tables Closes #230
This commit is contained in:
parent
8d0cf545b8
commit
f58f014bc3
BIN
dist/showdown.js
vendored
BIN
dist/showdown.js
vendored
Binary file not shown.
BIN
dist/showdown.js.map
vendored
BIN
dist/showdown.js.map
vendored
Binary file not shown.
BIN
dist/showdown.min.js
vendored
BIN
dist/showdown.min.js
vendored
Binary file not shown.
BIN
dist/showdown.min.js.map
vendored
BIN
dist/showdown.min.js.map
vendored
Binary file not shown.
|
@ -1,164 +1,129 @@
|
|||
showdown.subParser('tables', function (text, options, globals) {
|
||||
'use strict';
|
||||
|
||||
var table = function () {
|
||||
|
||||
var tables = {},
|
||||
filter;
|
||||
|
||||
tables.th = function (header, style) {
|
||||
var id = '';
|
||||
header = header.trim();
|
||||
if (header === '') {
|
||||
return '';
|
||||
}
|
||||
if (options.tableHeaderId) {
|
||||
id = ' id="' + header.replace(/ /g, '_').toLowerCase() + '"';
|
||||
}
|
||||
header = showdown.subParser('spanGamut')(header, options, globals);
|
||||
if (!style || style.trim() === '') {
|
||||
style = '';
|
||||
} else {
|
||||
style = ' style="' + style + '"';
|
||||
}
|
||||
return '<th' + id + style + '>' + header + '</th>';
|
||||
};
|
||||
|
||||
tables.td = function (cell, style) {
|
||||
var subText = showdown.subParser('spanGamut')(cell.trim(), options, globals);
|
||||
if (!style || style.trim() === '') {
|
||||
style = '';
|
||||
} else {
|
||||
style = ' style="' + style + '"';
|
||||
}
|
||||
return '<td' + style + '>' + subText + '</td>';
|
||||
};
|
||||
|
||||
tables.ths = function () {
|
||||
var out = '',
|
||||
i = 0,
|
||||
hs = [].slice.apply(arguments[0]),
|
||||
style = [].slice.apply(arguments[1]);
|
||||
|
||||
for (i; i < hs.length; i += 1) {
|
||||
out += tables.th(hs[i], style[i]) + '\n';
|
||||
}
|
||||
|
||||
return out;
|
||||
};
|
||||
|
||||
tables.tds = function () {
|
||||
var out = '',
|
||||
i = 0,
|
||||
ds = [].slice.apply(arguments[0]),
|
||||
style = [].slice.apply(arguments[1]);
|
||||
|
||||
for (i; i < ds.length; i += 1) {
|
||||
out += tables.td(ds[i], style[i]) + '\n';
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
tables.thead = function () {
|
||||
var out,
|
||||
hs = [].slice.apply(arguments[0]),
|
||||
style = [].slice.apply(arguments[1]);
|
||||
|
||||
out = '<thead>\n';
|
||||
out += '<tr>\n';
|
||||
out += tables.ths.apply(this, [hs, style]);
|
||||
out += '</tr>\n';
|
||||
out += '</thead>\n';
|
||||
return out;
|
||||
};
|
||||
|
||||
tables.tr = function () {
|
||||
var out,
|
||||
cs = [].slice.apply(arguments[0]),
|
||||
style = [].slice.apply(arguments[1]);
|
||||
|
||||
out = '<tr>\n';
|
||||
out += tables.tds.apply(this, [cs, style]);
|
||||
out += '</tr>\n';
|
||||
return out;
|
||||
};
|
||||
|
||||
filter = function (text) {
|
||||
var i = 0,
|
||||
lines = text.split('\n'),
|
||||
line,
|
||||
hs,
|
||||
out = [];
|
||||
|
||||
for (i; i < lines.length; i += 1) {
|
||||
line = lines[i];
|
||||
// looks like a table heading
|
||||
if (line.trim().match(/^[|].*[|]$/)) {
|
||||
line = line.trim();
|
||||
|
||||
var tbl = [],
|
||||
align = lines[i + 1].trim(),
|
||||
styles = [],
|
||||
j = 0;
|
||||
|
||||
if (align.match(/^[|][-=|: ]+[|]$/)) {
|
||||
styles = align.substring(1, align.length - 1).split('|');
|
||||
for (j = 0; j < styles.length; ++j) {
|
||||
styles[j] = styles[j].trim();
|
||||
if (styles[j].match(/^[:][-=| ]+[:]$/)) {
|
||||
styles[j] = 'text-align:center;';
|
||||
|
||||
} else if (styles[j].match(/^[-=| ]+[:]$/)) {
|
||||
styles[j] = 'text-align:right;';
|
||||
|
||||
} else if (styles[j].match(/^[:][-=| ]+$/)) {
|
||||
styles[j] = 'text-align:left;';
|
||||
} else {
|
||||
styles[j] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
tbl.push('<table>');
|
||||
hs = line.substring(1, line.length - 1).split('|');
|
||||
|
||||
if (styles.length === 0) {
|
||||
for (j = 0; j < hs.length; ++j) {
|
||||
styles.push('text-align:left');
|
||||
}
|
||||
}
|
||||
tbl.push(tables.thead.apply(this, [hs, styles]));
|
||||
line = lines[++i];
|
||||
if (!line.trim().match(/^[|][-=|: ]+[|]$/)) {
|
||||
// not a table rolling back
|
||||
line = lines[--i];
|
||||
} else {
|
||||
line = lines[++i];
|
||||
tbl.push('<tbody>');
|
||||
while (line.trim().match(/^[|].*[|]$/)) {
|
||||
line = line.trim();
|
||||
tbl.push(tables.tr.apply(this, [line.substring(1, line.length - 1).split('|'), styles]));
|
||||
line = lines[++i];
|
||||
}
|
||||
tbl.push('</tbody>');
|
||||
tbl.push('</table>');
|
||||
// we are done with this table and we move along
|
||||
out.push(tbl.join('\n'));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
out.push(line);
|
||||
}
|
||||
return out.join('\n');
|
||||
};
|
||||
return {parse: filter};
|
||||
};
|
||||
|
||||
if (options.tables) {
|
||||
text = globals.converter._dispatch('tables.before', text, options);
|
||||
var tableParser = table();
|
||||
text = tableParser.parse(text);
|
||||
text = globals.converter._dispatch('tables.after', text, options);
|
||||
if (!options.tables) {
|
||||
return text;
|
||||
}
|
||||
|
||||
var tableRgx = /^[ \t]{0,3}\|?.+\|.+\n[ \t]{0,3}\|?[ \t]*:?[ \t]*(?:-|=){3,}[ \t]*:?[ \t]*\|[ \t]*:?[ \t]*(?:-|=){3,}[^]+?(?:\n\n|~0)/gm;
|
||||
|
||||
function parseStyles(sLine) {
|
||||
if (/^:[ \t]*---*$/.test(sLine)) {
|
||||
return ' style="text-align:left;"';
|
||||
} else if (/^---*[ \t]*:[ \t]*$/.test(sLine)) {
|
||||
return ' style="text-align:right;"';
|
||||
} else if (/^:[ \t]*---*[ \t]*:$/.test(sLine)) {
|
||||
return ' style="text-align:center;"';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function parseHeaders(header, style) {
|
||||
var id = '';
|
||||
header = header.trim();
|
||||
if (options.tableHeaderId) {
|
||||
id = ' id="' + header.replace(/ /g, '_').toLowerCase() + '"';
|
||||
}
|
||||
header = showdown.subParser('spanGamut')(header, options, globals);
|
||||
|
||||
return '<th' + id + style + '>' + header + '</th>';
|
||||
}
|
||||
|
||||
function parseCells(cell, style) {
|
||||
var subText = showdown.subParser('spanGamut')(cell, options, globals);
|
||||
return '<td' + style + '>' + subText + '</td>';
|
||||
}
|
||||
|
||||
function buildTable(headers, cells) {
|
||||
var tb = '<table>\n<thead>\n<tr>\n',
|
||||
tblLgn = headers.length;
|
||||
|
||||
for (var i = 0; i < tblLgn; ++i) {
|
||||
tb += headers[i];
|
||||
}
|
||||
tb += '</tr>\n</thead>\n<tbody>\n';
|
||||
|
||||
for (i = 0; i < cells.length; ++i) {
|
||||
tb += '<tr>';
|
||||
for (var ii = 0; ii < tblLgn; ++ii) {
|
||||
tb += cells[i][ii];
|
||||
}
|
||||
tb += '</tr>';
|
||||
}
|
||||
tb += '</tbody></table>';
|
||||
return tb;
|
||||
}
|
||||
|
||||
text = globals.converter._dispatch('tables.before', text, options);
|
||||
|
||||
text = text.replace(tableRgx, function (rawTable) {
|
||||
|
||||
var i, tableLines = rawTable.split('\n');
|
||||
|
||||
// strip wrong first and last column if wrapped tables are used
|
||||
for (i = 0; i < tableLines.length; ++i) {
|
||||
if (/^[ \t]{0,3}\|/.test(tableLines[i])) {
|
||||
tableLines[i] = tableLines[i].replace(/^[ \t]{0,3}\|/, '');
|
||||
}
|
||||
if (/\|[ \t]*$/.test(tableLines[i])) {
|
||||
tableLines[i] = tableLines[i].replace(/\|[ \t]*$/, '');
|
||||
}
|
||||
}
|
||||
|
||||
var rawHeaders = tableLines[0].split('|').map(function (s) { return s.trim();}),
|
||||
rawStyles = tableLines[1].split('|').map(function (s) { return s.trim();}),
|
||||
rawCells = [],
|
||||
headers = [],
|
||||
styles = [],
|
||||
cells = [];
|
||||
|
||||
tableLines.shift();
|
||||
tableLines.shift();
|
||||
|
||||
for (i = 0; i < tableLines.length; ++i) {
|
||||
if (tableLines[i].trim() === '') {
|
||||
continue;
|
||||
}
|
||||
rawCells.push(
|
||||
tableLines[i]
|
||||
.split('|')
|
||||
.map(function (s) {
|
||||
return s.trim();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (rawHeaders.length < rawStyles.length) {
|
||||
return rawTable;
|
||||
}
|
||||
|
||||
for (i = 0; i < rawStyles.length; ++i) {
|
||||
styles.push(parseStyles(rawStyles[i]));
|
||||
}
|
||||
|
||||
for (i = 0; i < rawHeaders.length; ++i) {
|
||||
if (showdown.helper.isUndefined(styles[i])) {
|
||||
styles[i] = '';
|
||||
}
|
||||
headers.push(parseHeaders(rawHeaders[i], styles[i]));
|
||||
}
|
||||
|
||||
for (i = 0; i < rawCells.length; ++i) {
|
||||
var row = [];
|
||||
for (var ii = 0; ii < headers.length; ++ii) {
|
||||
if (showdown.helper.isUndefined(rawCells[i][ii])) {
|
||||
|
||||
}
|
||||
row.push(parseCells(rawCells[i][ii], styles[ii]));
|
||||
}
|
||||
cells.push(row);
|
||||
}
|
||||
|
||||
return buildTable(headers, cells);
|
||||
});
|
||||
|
||||
text = globals.converter._dispatch('tables.after', text, options);
|
||||
|
||||
return text;
|
||||
});
|
||||
|
|
24
test/features/tables/gh-style-tables.html
Normal file
24
test/features/tables/gh-style-tables.html
Normal file
|
@ -0,0 +1,24 @@
|
|||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>First Header</th>
|
||||
<th>Second Header</th>
|
||||
<th>Third Header</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Content Cell</td>
|
||||
<td>Content Cell</td>
|
||||
<td>C</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Content Cell</td>
|
||||
<td>Content Cell</td>
|
||||
<td>C</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
4
test/features/tables/gh-style-tables.md
Normal file
4
test/features/tables/gh-style-tables.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
First Header | Second Header|Third Header
|
||||
------------- | -------------|---
|
||||
Content Cell | Content Cell|C
|
||||
Content Cell | Content Cell|C
|
Loading…
Reference in New Issue
Block a user