2017-11-24 11:18:27 +00:00
|
|
|
var indexOf = Array.prototype.indexOf
|
|
|
|
var every = Array.prototype.every
|
2017-11-10 14:21:46 +00:00
|
|
|
var rules = {}
|
|
|
|
|
|
|
|
rules.tableCell = {
|
|
|
|
filter: ['th', 'td'],
|
|
|
|
replacement: function (content, node) {
|
|
|
|
return cell(content, node)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rules.tableRow = {
|
|
|
|
filter: 'tr',
|
|
|
|
replacement: function (content, node) {
|
|
|
|
var borderCells = ''
|
|
|
|
var alignMap = { left: ':--', right: '--:', center: ':-:' }
|
|
|
|
|
2017-11-24 11:18:27 +00:00
|
|
|
if (isHeadingRow(node)) {
|
2017-11-10 14:21:46 +00:00
|
|
|
for (var i = 0; i < node.childNodes.length; i++) {
|
|
|
|
var border = '---'
|
2017-12-12 22:55:54 +00:00
|
|
|
var align = (
|
|
|
|
node.childNodes[i].getAttribute('align') || ''
|
|
|
|
).toLowerCase()
|
2017-11-10 14:21:46 +00:00
|
|
|
|
2017-12-12 22:55:54 +00:00
|
|
|
if (align) border = alignMap[align] || border
|
2017-11-10 14:21:46 +00:00
|
|
|
|
|
|
|
borderCells += cell(border, node.childNodes[i])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return '\n' + content + (borderCells ? '\n' + borderCells : '')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rules.table = {
|
2018-05-11 11:55:21 +01:00
|
|
|
// Only convert tables with a heading row.
|
|
|
|
// Tables with no heading row are kept using `keep` (see below).
|
|
|
|
filter: function (node) {
|
|
|
|
return node.nodeName === 'TABLE' && isHeadingRow(node.rows[0])
|
|
|
|
},
|
|
|
|
|
2017-11-10 14:21:46 +00:00
|
|
|
replacement: function (content) {
|
|
|
|
// Ensure there are no blank lines
|
|
|
|
content = content.replace('\n\n', '\n')
|
|
|
|
return '\n\n' + content + '\n\n'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rules.tableSection = {
|
|
|
|
filter: ['thead', 'tbody', 'tfoot'],
|
|
|
|
replacement: function (content) {
|
|
|
|
return content
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-24 11:18:27 +00:00
|
|
|
// A tr is a heading row if:
|
|
|
|
// - the parent is a THEAD
|
|
|
|
// - or if its the first child of the TABLE or the first TBODY (possibly
|
|
|
|
// following a blank THEAD)
|
|
|
|
// - and every cell is a TH
|
|
|
|
function isHeadingRow (tr) {
|
|
|
|
var parentNode = tr.parentNode
|
|
|
|
return (
|
|
|
|
parentNode.nodeName === 'THEAD' ||
|
|
|
|
(
|
|
|
|
parentNode.firstChild === tr &&
|
|
|
|
(parentNode.nodeName === 'TABLE' || isFirstTbody(parentNode)) &&
|
|
|
|
every.call(tr.childNodes, function (n) { return n.nodeName === 'TH' })
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
function isFirstTbody (element) {
|
|
|
|
var previousSibling = element.previousSibling
|
|
|
|
return (
|
|
|
|
element.nodeName === 'TBODY' && (
|
|
|
|
!previousSibling ||
|
|
|
|
(
|
|
|
|
previousSibling.nodeName === 'THEAD' &&
|
|
|
|
/^\s*$/i.test(previousSibling.textContent)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2017-11-10 14:21:46 +00:00
|
|
|
function cell (content, node) {
|
2017-11-24 11:18:27 +00:00
|
|
|
var index = indexOf.call(node.parentNode.childNodes, node)
|
2017-11-10 14:21:46 +00:00
|
|
|
var prefix = ' '
|
|
|
|
if (index === 0) prefix = '| '
|
|
|
|
return prefix + content + ' |'
|
|
|
|
}
|
|
|
|
|
|
|
|
export default function tables (turndownService) {
|
2018-05-11 11:55:21 +01:00
|
|
|
turndownService.keep(function (node) {
|
|
|
|
return node.nodeName === 'TABLE' && !isHeadingRow(node.rows[0])
|
|
|
|
})
|
2017-11-10 14:21:46 +00:00
|
|
|
for (var key in rules) turndownService.addRule(key, rules[key])
|
|
|
|
}
|