mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-08-28 20:12:41 +00:00
160 lines
4.6 KiB
JavaScript
160 lines
4.6 KiB
JavaScript
/*\
|
|
title: $:/core/modules/parsers/wikitextparser/rules/table.js
|
|
type: application/javascript
|
|
module-type: wikitextrule
|
|
|
|
Wiki text block rule for tables.
|
|
|
|
\*/
|
|
(function(){
|
|
|
|
/*jslint node: true, browser: true */
|
|
/*global $tw: false */
|
|
"use strict";
|
|
|
|
exports.name = "table";
|
|
|
|
exports.blockParser = true;
|
|
|
|
exports.regExpString = "^\\|(?:[^\\n]*)\\|(?:[fhck]?)\\r?\\n";
|
|
|
|
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.pos;
|
|
var cellMatch = cellRegExp.exec(this.source);
|
|
while(cellMatch && cellMatch.index === this.pos) {
|
|
if(cellMatch[1] === "~") {
|
|
// Rowspan
|
|
var last = prevColumns[col];
|
|
if(last) {
|
|
last.rowSpanCount++;
|
|
last.element.attributes.rowspan = last.rowSpanCount;
|
|
last.element.attributes.valign = "center";
|
|
if(colSpanCount > 1) {
|
|
last.element.attributes.colspan = colSpanCount;
|
|
colSpanCount = 1;
|
|
}
|
|
}
|
|
// Move to just before the `|` terminating the cell
|
|
this.pos = cellRegExp.lastIndex - 1;
|
|
} else if(cellMatch[1] === ">") {
|
|
// Colspan
|
|
colSpanCount++;
|
|
// Move to just before the `|` terminating the cell
|
|
this.pos = cellRegExp.lastIndex - 1;
|
|
} else if(cellMatch[2]) {
|
|
// End of row
|
|
if(prevCell && colSpanCount > 1) {
|
|
prevCell.attributes.colspan = colSpanCount;
|
|
}
|
|
this.pos = cellRegExp.lastIndex - 1;
|
|
break;
|
|
} else {
|
|
// For ordinary cells, step beyond the opening `|`
|
|
this.pos++;
|
|
// Look for a space at the start of the cell
|
|
var spaceLeft = false,
|
|
chr = this.source.substr(this.pos,1);
|
|
while(chr === " ") {
|
|
spaceLeft = true;
|
|
this.pos++;
|
|
chr = this.source.substr(this.pos,1);
|
|
}
|
|
// Check whether this is a heading cell
|
|
var cell;
|
|
if(chr === "!") {
|
|
this.pos++;
|
|
cell = $tw.Tree.Element("th",{},[]);
|
|
} else {
|
|
cell = $tw.Tree.Element("td",{},[]);
|
|
}
|
|
tree.push(cell);
|
|
// Record information about this cell
|
|
prevCell = cell;
|
|
prevColumns[col] = {rowSpanCount:1,element:cell};
|
|
// Check for a colspan
|
|
if(colSpanCount > 1) {
|
|
cell.attributes.colspan = colSpanCount;
|
|
colSpanCount = 1;
|
|
}
|
|
// Parse the cell
|
|
cell.children = this.parseRun(cellTermRegExp);
|
|
// Set the alignment for the cell
|
|
if(cellMatch[1].substr(cellMatch[1].length-1,1) === " ") { // spaceRight
|
|
cell.attributes.align = spaceLeft ? "center" : "left";
|
|
} else if(spaceLeft) {
|
|
cell.attributes.align = "right";
|
|
}
|
|
// Move back to the closing `|`
|
|
this.pos--;
|
|
}
|
|
col++;
|
|
cellRegExp.lastIndex = this.pos;
|
|
cellMatch = cellRegExp.exec(this.source);
|
|
}
|
|
return tree;
|
|
};
|
|
|
|
exports.parse = function(match,isBlock) {
|
|
var rowContainerTypes = {"c":"caption", "h":"thead", "":"tbody", "f":"tfoot"},
|
|
table = $tw.Tree.Element("table",{"class": ["table"]},[]),
|
|
rowRegExp = /^\|([^\n]*)\|([fhck]?)\r?\n/mg,
|
|
rowTermRegExp = /(\|(?:[fhck]?)\r?\n)/mg,
|
|
prevColumns = [],
|
|
currRowType,
|
|
rowContainer,
|
|
rowCount = 0;
|
|
// Match the row
|
|
rowRegExp.lastIndex = this.pos;
|
|
var rowMatch = rowRegExp.exec(this.source);
|
|
while(rowMatch && rowMatch.index === this.pos) {
|
|
var rowType = rowMatch[2];
|
|
// Check if it is a class assignment
|
|
if(rowType === "k") {
|
|
table.attributes["class"].push(rowMatch[1]);
|
|
this.pos = rowMatch.index + rowMatch[0].length;
|
|
} else {
|
|
// Otherwise, create a new row if this one is of a different type
|
|
if(rowType != currRowType) {
|
|
rowContainer = $tw.Tree.Element(rowContainerTypes[rowType],{},[]);
|
|
table.children.push(rowContainer);
|
|
currRowType = rowType;
|
|
}
|
|
// Is this a caption row?
|
|
if(currRowType === "c") {
|
|
// If so, move past the opening `|` of the row
|
|
this.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.parseRun(rowTermRegExp);
|
|
} else {
|
|
// Create the row
|
|
var theRow = $tw.Tree.Element("tr",{},[]);
|
|
theRow.attributes["class"] = rowCount%2 ? "oddRow" : "evenRow";
|
|
rowContainer.children.push(theRow);
|
|
// Process the row
|
|
theRow.children = processRow.call(this,prevColumns);
|
|
this.pos = rowMatch.index + rowMatch[0].length;
|
|
// Increment the row count
|
|
rowCount++;
|
|
}
|
|
}
|
|
rowMatch = rowRegExp.exec(this.source);
|
|
}
|
|
return [table];
|
|
};
|
|
|
|
})();
|