mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-08-20 14:45:59 +00:00
187 lines
6.1 KiB
JavaScript
187 lines
6.1 KiB
JavaScript
/*\
|
|
title: $:/core/modules/parsers/wikiparser/rules/table.js
|
|
type: application/javascript
|
|
module-type: wikirule
|
|
|
|
Wiki text block rule for tables.
|
|
|
|
\*/
|
|
(function(){
|
|
|
|
/*jslint node: true, browser: true */
|
|
/*global $tw: false */
|
|
"use strict";
|
|
|
|
exports.name = "table";
|
|
exports.types = {block: true};
|
|
|
|
exports.init = function(parser) {
|
|
this.parser = parser;
|
|
// Regexp to match
|
|
this.matchRegExp = /^\|(?:[^\n]*)\|(?:[fhck]?)\r?(?:\n|$)/mg;
|
|
};
|
|
|
|
var processRow = function(prevColumns) {
|
|
var cellRegExp = /(?:\|([^\n\|]*)\|)|(\|[fhck]?\r?(?:\n|$))/mg,
|
|
cellTermRegExp = /((?:\x20*)\|)/mg,
|
|
tree = [],
|
|
col = 0,
|
|
colSpanCount = 1,
|
|
prevCell;
|
|
// Match a single cell
|
|
cellRegExp.lastIndex = this.parser.pos;
|
|
var cellMatch = cellRegExp.exec(this.parser.source);
|
|
while(cellMatch && cellMatch.index === this.parser.pos) {
|
|
if(cellMatch[1] === "~") {
|
|
// Rowspan
|
|
var last = prevColumns[col];
|
|
if(last) {
|
|
last.rowSpanCount++;
|
|
$tw.utils.addAttributeToParseTreeNode(last.element,"rowspan",last.rowSpanCount);
|
|
var vAlign = $tw.utils.getAttributeValueFromParseTreeNode(last.element,"valign","center");
|
|
$tw.utils.addAttributeToParseTreeNode(last.element,"valign",vAlign);
|
|
if(colSpanCount > 1) {
|
|
$tw.utils.addAttributeToParseTreeNode(last.element,"colspan",colSpanCount);
|
|
colSpanCount = 1;
|
|
}
|
|
}
|
|
// Move to just before the `|` terminating the cell
|
|
this.parser.pos = cellRegExp.lastIndex - 1;
|
|
} else if(cellMatch[1] === ">") {
|
|
// Colspan
|
|
colSpanCount++;
|
|
// Move to just before the `|` terminating the cell
|
|
this.parser.pos = cellRegExp.lastIndex - 1;
|
|
} else if(cellMatch[1] === "<" && prevCell) {
|
|
colSpanCount = 1 + $tw.utils.getAttributeValueFromParseTreeNode(prevCell,"colspan",1);
|
|
$tw.utils.addAttributeToParseTreeNode(prevCell,"colspan",colSpanCount);
|
|
colSpanCount = 1;
|
|
// Move to just before the `|` terminating the cell
|
|
this.parser.pos = cellRegExp.lastIndex - 1;
|
|
} else if(cellMatch[2]) {
|
|
// End of row
|
|
if(prevCell && colSpanCount > 1) {
|
|
if(prevCell.attributes && prevCell.attributes && prevCell.attributes.colspan) {
|
|
colSpanCount += prevCell.attributes.colspan.value;
|
|
} else {
|
|
colSpanCount -= 1;
|
|
}
|
|
$tw.utils.addAttributeToParseTreeNode(prevCell,"colspan",colSpanCount);
|
|
}
|
|
this.parser.pos = cellRegExp.lastIndex - 1;
|
|
break;
|
|
} else {
|
|
// For ordinary cells, step beyond the opening `|`
|
|
this.parser.pos++;
|
|
// Look for a space at the start of the cell
|
|
var spaceLeft = false,
|
|
vAlign = null;
|
|
if(this.parser.source.substr(this.parser.pos).search(/^\^([^\^]|\^\^)/) === 0) {
|
|
vAlign = "top";
|
|
} else if(this.parser.source.substr(this.parser.pos).search(/^,([^,]|,,)/) === 0) {
|
|
vAlign = "bottom";
|
|
}
|
|
if(vAlign) {
|
|
this.parser.pos++;
|
|
}
|
|
var chr = this.parser.source.substr(this.parser.pos,1);
|
|
while(chr === " ") {
|
|
spaceLeft = true;
|
|
this.parser.pos++;
|
|
chr = this.parser.source.substr(this.parser.pos,1);
|
|
}
|
|
// Check whether this is a heading cell
|
|
var cell;
|
|
if(chr === "!") {
|
|
this.parser.pos++;
|
|
cell = {type: "element", tag: "th", children: []};
|
|
} else {
|
|
cell = {type: "element", tag: "td", children: []};
|
|
}
|
|
tree.push(cell);
|
|
// Record information about this cell
|
|
prevCell = cell;
|
|
prevColumns[col] = {rowSpanCount:1,element:cell};
|
|
// Check for a colspan
|
|
if(colSpanCount > 1) {
|
|
$tw.utils.addAttributeToParseTreeNode(cell,"colspan",colSpanCount);
|
|
colSpanCount = 1;
|
|
}
|
|
// Parse the cell
|
|
cell.children = this.parser.parseInlineRun(cellTermRegExp,{eatTerminator: true});
|
|
// Set the alignment for the cell
|
|
if(vAlign) {
|
|
$tw.utils.addAttributeToParseTreeNode(cell,"valign",vAlign);
|
|
}
|
|
if(this.parser.source.substr(this.parser.pos - 2,1) === " ") { // spaceRight
|
|
$tw.utils.addAttributeToParseTreeNode(cell,"align",spaceLeft ? "center" : "left");
|
|
} else if(spaceLeft) {
|
|
$tw.utils.addAttributeToParseTreeNode(cell,"align","right");
|
|
}
|
|
// Move back to the closing `|`
|
|
this.parser.pos--;
|
|
}
|
|
col++;
|
|
cellRegExp.lastIndex = this.parser.pos;
|
|
cellMatch = cellRegExp.exec(this.parser.source);
|
|
}
|
|
return tree;
|
|
};
|
|
|
|
exports.parse = function() {
|
|
var rowContainerTypes = {"c":"caption", "h":"thead", "":"tbody", "f":"tfoot"},
|
|
table = {type: "element", tag: "table", children: []},
|
|
rowRegExp = /^\|([^\n]*)\|([fhck]?)\r?(?:\n|$)/mg,
|
|
rowTermRegExp = /(\|(?:[fhck]?)\r?(?:\n|$))/mg,
|
|
prevColumns = [],
|
|
currRowType,
|
|
rowContainer,
|
|
rowCount = 0;
|
|
// Match the row
|
|
rowRegExp.lastIndex = this.parser.pos;
|
|
var rowMatch = rowRegExp.exec(this.parser.source);
|
|
while(rowMatch && rowMatch.index === this.parser.pos) {
|
|
var rowType = rowMatch[2];
|
|
// Check if it is a class assignment
|
|
if(rowType === "k") {
|
|
$tw.utils.addClassToParseTreeNode(table,rowMatch[1]);
|
|
this.parser.pos = rowMatch.index + rowMatch[0].length;
|
|
} else {
|
|
// Otherwise, create a new row if this one is of a different type
|
|
if(rowType !== currRowType) {
|
|
rowContainer = {type: "element", tag: rowContainerTypes[rowType], children: []};
|
|
table.children.push(rowContainer);
|
|
currRowType = rowType;
|
|
}
|
|
// Is this a caption row?
|
|
if(currRowType === "c") {
|
|
// If so, move past the opening `|` of the row
|
|
this.parser.pos++;
|
|
// Move the caption to the first row if it isn't already
|
|
if(table.children.length !== 1) {
|
|
table.children.pop(); // Take rowContainer out of the children array
|
|
table.children.splice(0,0,rowContainer); // Insert it at the bottom
|
|
}
|
|
// Set the alignment - TODO: figure out why TW did this
|
|
// rowContainer.attributes.align = rowCount === 0 ? "top" : "bottom";
|
|
// Parse the caption
|
|
rowContainer.children = this.parser.parseInlineRun(rowTermRegExp,{eatTerminator: true});
|
|
} else {
|
|
// Create the row
|
|
var theRow = {type: "element", tag: "tr", children: []};
|
|
$tw.utils.addClassToParseTreeNode(theRow,rowCount%2 ? "oddRow" : "evenRow");
|
|
rowContainer.children.push(theRow);
|
|
// Process the row
|
|
theRow.children = processRow.call(this,prevColumns);
|
|
this.parser.pos = rowMatch.index + rowMatch[0].length;
|
|
// Increment the row count
|
|
rowCount++;
|
|
}
|
|
}
|
|
rowMatch = rowRegExp.exec(this.parser.source);
|
|
}
|
|
return [table];
|
|
};
|
|
|
|
})();
|