mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-12-28 11:00:27 +00:00
Brought in the TiddlyWiki wikifier code
This is pretty much the raw TiddlyWiki code. Formatter.js incorporates FormatterHelper.js, too.
This commit is contained in:
parent
9d4bfc1dec
commit
28cce8b269
625
js/Formatter.js
Executable file
625
js/Formatter.js
Executable file
@ -0,0 +1,625 @@
|
||||
/*global require: false, exports: false, process: false */
|
||||
"use strict";
|
||||
|
||||
var Tiddler = require("./Tiddler.js").Tiddler,
|
||||
TiddlyWiki = require("./TiddlyWiki.js").TiddlyWiki,
|
||||
utils = require("./Utils.js"),
|
||||
util = require("util");
|
||||
|
||||
|
||||
function Formatter(formatters)
|
||||
{
|
||||
var n;
|
||||
this.formatters = [];
|
||||
var pattern = [];
|
||||
for(n=0; n<formatters.length; n++) {
|
||||
pattern.push("(" + formatters[n].match + ")");
|
||||
this.formatters.push(formatters[n]);
|
||||
}
|
||||
this.formatterRegExp = new RegExp(pattern.join("|"),"mg");
|
||||
}
|
||||
|
||||
config.formatterHelpers = {
|
||||
|
||||
createElementAndWikify: function(w)
|
||||
{
|
||||
w.subWikifyTerm(createTiddlyElement(w.output,this.element),this.termRegExp);
|
||||
},
|
||||
|
||||
inlineCssHelper: function(w)
|
||||
{
|
||||
var styles = [];
|
||||
config.textPrimitives.cssLookaheadRegExp.lastIndex = w.nextMatch;
|
||||
var lookaheadMatch = config.textPrimitives.cssLookaheadRegExp.exec(w.source);
|
||||
while(lookaheadMatch && lookaheadMatch.index == w.nextMatch) {
|
||||
var s,v;
|
||||
if(lookaheadMatch[1]) {
|
||||
s = lookaheadMatch[1].unDash();
|
||||
v = lookaheadMatch[2];
|
||||
} else {
|
||||
s = lookaheadMatch[3].unDash();
|
||||
v = lookaheadMatch[4];
|
||||
}
|
||||
if(s=="bgcolor")
|
||||
s = "backgroundColor";
|
||||
if(s=="float")
|
||||
s = "cssFloat";
|
||||
styles.push({style: s, value: v});
|
||||
w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
|
||||
config.textPrimitives.cssLookaheadRegExp.lastIndex = w.nextMatch;
|
||||
lookaheadMatch = config.textPrimitives.cssLookaheadRegExp.exec(w.source);
|
||||
}
|
||||
return styles;
|
||||
},
|
||||
|
||||
applyCssHelper: function(e,styles)
|
||||
{
|
||||
var t;
|
||||
for(t=0; t< styles.length; t++) {
|
||||
try {
|
||||
e.style[styles[t].style] = styles[t].value;
|
||||
} catch (ex) {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
enclosedTextHelper: function(w)
|
||||
{
|
||||
this.lookaheadRegExp.lastIndex = w.matchStart;
|
||||
var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
|
||||
if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
|
||||
var text = lookaheadMatch[1];
|
||||
if(config.browser.isIE)
|
||||
text = text.replace(/\n/g,"\r");
|
||||
createTiddlyElement(w.output,this.element,null,null,text);
|
||||
w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
|
||||
}
|
||||
},
|
||||
|
||||
isExternalLink: function(link)
|
||||
{
|
||||
if(store.tiddlerExists(link) || store.isShadowTiddler(link)) {
|
||||
//# Definitely not an external link
|
||||
return false;
|
||||
}
|
||||
var urlRegExp = new RegExp(config.textPrimitives.urlPattern,"mg");
|
||||
if(urlRegExp.exec(link)) {
|
||||
//# Definitely an external link
|
||||
return true;
|
||||
}
|
||||
if(link.indexOf(".")!=-1 || link.indexOf("\\")!=-1 || link.indexOf("/")!=-1 || link.indexOf("#")!=-1) {
|
||||
//# Link contains . / \ or # so is probably an external link
|
||||
return true;
|
||||
}
|
||||
//# Otherwise assume it is not an external link
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
config.formatters = [
|
||||
{
|
||||
name: "table",
|
||||
match: "^\\|(?:[^\\n]*)\\|(?:[fhck]?)$",
|
||||
lookaheadRegExp: /^\|([^\n]*)\|([fhck]?)$/mg,
|
||||
rowTermRegExp: /(\|(?:[fhck]?)$\n?)/mg,
|
||||
cellRegExp: /(?:\|([^\n\|]*)\|)|(\|[fhck]?$\n?)/mg,
|
||||
cellTermRegExp: /((?:\x20*)\|)/mg,
|
||||
rowTypes: {"c":"caption", "h":"thead", "":"tbody", "f":"tfoot"},
|
||||
handler: function(w)
|
||||
{
|
||||
var table = createTiddlyElement(w.output,"table",null,"twtable");
|
||||
var prevColumns = [];
|
||||
var currRowType = null;
|
||||
var rowContainer;
|
||||
var rowCount = 0;
|
||||
var onmouseover = function() {jQuery(this).addClass("hoverRow");};
|
||||
var onmouseout = function() {jQuery(this).removeClass("hoverRow");};
|
||||
w.nextMatch = w.matchStart;
|
||||
this.lookaheadRegExp.lastIndex = w.nextMatch;
|
||||
var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
|
||||
while(lookaheadMatch && lookaheadMatch.index == w.nextMatch) {
|
||||
var nextRowType = lookaheadMatch[2];
|
||||
if(nextRowType == "k") {
|
||||
table.className = lookaheadMatch[1];
|
||||
w.nextMatch += lookaheadMatch[0].length+1;
|
||||
} else {
|
||||
if(nextRowType != currRowType) {
|
||||
rowContainer = createTiddlyElement(table,this.rowTypes[nextRowType]);
|
||||
currRowType = nextRowType;
|
||||
}
|
||||
if(currRowType == "c") {
|
||||
// Caption
|
||||
w.nextMatch++;
|
||||
if(rowContainer != table.firstChild)
|
||||
table.insertBefore(rowContainer,table.firstChild);
|
||||
rowContainer.setAttribute("align",rowCount == 0?"top":"bottom");
|
||||
w.subWikifyTerm(rowContainer,this.rowTermRegExp);
|
||||
} else {
|
||||
var theRow = createTiddlyElement(rowContainer,"tr",null,rowCount%2?"oddRow":"evenRow");
|
||||
theRow.onmouseover = onmouseover;
|
||||
theRow.onmouseout = onmouseout;
|
||||
this.rowHandler(w,theRow,prevColumns);
|
||||
rowCount++;
|
||||
}
|
||||
}
|
||||
this.lookaheadRegExp.lastIndex = w.nextMatch;
|
||||
lookaheadMatch = this.lookaheadRegExp.exec(w.source);
|
||||
}
|
||||
},
|
||||
rowHandler: function(w,e,prevColumns)
|
||||
{
|
||||
var col = 0;
|
||||
var colSpanCount = 1;
|
||||
var prevCell = null;
|
||||
this.cellRegExp.lastIndex = w.nextMatch;
|
||||
var cellMatch = this.cellRegExp.exec(w.source);
|
||||
while(cellMatch && cellMatch.index == w.nextMatch) {
|
||||
if(cellMatch[1] == "~") {
|
||||
// Rowspan
|
||||
var last = prevColumns[col];
|
||||
if(last) {
|
||||
last.rowSpanCount++;
|
||||
last.element.setAttribute("rowspan",last.rowSpanCount);
|
||||
last.element.setAttribute("rowSpan",last.rowSpanCount); // Needed for IE
|
||||
last.element.valign = "center";
|
||||
if(colSpanCount > 1) {
|
||||
last.element.setAttribute("colspan",colSpanCount);
|
||||
last.element.setAttribute("colSpan",colSpanCount); // Needed for IE
|
||||
colSpanCount = 1;
|
||||
}
|
||||
}
|
||||
w.nextMatch = this.cellRegExp.lastIndex-1;
|
||||
} else if(cellMatch[1] == ">") {
|
||||
// Colspan
|
||||
colSpanCount++;
|
||||
w.nextMatch = this.cellRegExp.lastIndex-1;
|
||||
} else if(cellMatch[2]) {
|
||||
// End of row
|
||||
if(prevCell && colSpanCount > 1) {
|
||||
prevCell.setAttribute("colspan",colSpanCount);
|
||||
prevCell.setAttribute("colSpan",colSpanCount); // Needed for IE
|
||||
}
|
||||
w.nextMatch = this.cellRegExp.lastIndex;
|
||||
break;
|
||||
} else {
|
||||
// Cell
|
||||
w.nextMatch++;
|
||||
var styles = config.formatterHelpers.inlineCssHelper(w);
|
||||
var spaceLeft = false;
|
||||
var chr = w.source.substr(w.nextMatch,1);
|
||||
while(chr == " ") {
|
||||
spaceLeft = true;
|
||||
w.nextMatch++;
|
||||
chr = w.source.substr(w.nextMatch,1);
|
||||
}
|
||||
var cell;
|
||||
if(chr == "!") {
|
||||
cell = createTiddlyElement(e,"th");
|
||||
w.nextMatch++;
|
||||
} else {
|
||||
cell = createTiddlyElement(e,"td");
|
||||
}
|
||||
prevCell = cell;
|
||||
prevColumns[col] = {rowSpanCount:1,element:cell};
|
||||
if(colSpanCount > 1) {
|
||||
cell.setAttribute("colspan",colSpanCount);
|
||||
cell.setAttribute("colSpan",colSpanCount); // Needed for IE
|
||||
colSpanCount = 1;
|
||||
}
|
||||
config.formatterHelpers.applyCssHelper(cell,styles);
|
||||
w.subWikifyTerm(cell,this.cellTermRegExp);
|
||||
if(w.matchText.substr(w.matchText.length-2,1) == " ") // spaceRight
|
||||
cell.align = spaceLeft ? "center" : "left";
|
||||
else if(spaceLeft)
|
||||
cell.align = "right";
|
||||
w.nextMatch--;
|
||||
}
|
||||
col++;
|
||||
this.cellRegExp.lastIndex = w.nextMatch;
|
||||
cellMatch = this.cellRegExp.exec(w.source);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: "heading",
|
||||
match: "^!{1,6}",
|
||||
termRegExp: /(\n)/mg,
|
||||
handler: function(w)
|
||||
{
|
||||
w.subWikifyTerm(createTiddlyElement(w.output,"h" + w.matchLength),this.termRegExp);
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: "list",
|
||||
match: "^(?:[\\*#;:]+)",
|
||||
lookaheadRegExp: /^(?:(?:(\*)|(#)|(;)|(:))+)/mg,
|
||||
termRegExp: /(\n)/mg,
|
||||
handler: function(w)
|
||||
{
|
||||
var stack = [w.output];
|
||||
var currLevel = 0, currType = null;
|
||||
var listLevel, listType, itemType, baseType;
|
||||
w.nextMatch = w.matchStart;
|
||||
this.lookaheadRegExp.lastIndex = w.nextMatch;
|
||||
var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
|
||||
while(lookaheadMatch && lookaheadMatch.index == w.nextMatch) {
|
||||
if(lookaheadMatch[1]) {
|
||||
listType = "ul";
|
||||
itemType = "li";
|
||||
} else if(lookaheadMatch[2]) {
|
||||
listType = "ol";
|
||||
itemType = "li";
|
||||
} else if(lookaheadMatch[3]) {
|
||||
listType = "dl";
|
||||
itemType = "dt";
|
||||
} else if(lookaheadMatch[4]) {
|
||||
listType = "dl";
|
||||
itemType = "dd";
|
||||
}
|
||||
if(!baseType)
|
||||
baseType = listType;
|
||||
listLevel = lookaheadMatch[0].length;
|
||||
w.nextMatch += lookaheadMatch[0].length;
|
||||
var t;
|
||||
if(listLevel > currLevel) {
|
||||
for(t=currLevel; t<listLevel; t++) {
|
||||
var target = (currLevel == 0) ? stack[stack.length-1] : stack[stack.length-1].lastChild;
|
||||
stack.push(createTiddlyElement(target,listType));
|
||||
}
|
||||
} else if(listType!=baseType && listLevel==1) {
|
||||
w.nextMatch -= lookaheadMatch[0].length;
|
||||
return;
|
||||
} else if(listLevel < currLevel) {
|
||||
for(t=currLevel; t>listLevel; t--)
|
||||
stack.pop();
|
||||
} else if(listLevel == currLevel && listType != currType) {
|
||||
stack.pop();
|
||||
stack.push(createTiddlyElement(stack[stack.length-1].lastChild,listType));
|
||||
}
|
||||
currLevel = listLevel;
|
||||
currType = listType;
|
||||
var e = createTiddlyElement(stack[stack.length-1],itemType);
|
||||
w.subWikifyTerm(e,this.termRegExp);
|
||||
this.lookaheadRegExp.lastIndex = w.nextMatch;
|
||||
lookaheadMatch = this.lookaheadRegExp.exec(w.source);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: "quoteByBlock",
|
||||
match: "^<<<\\n",
|
||||
termRegExp: /(^<<<(\n|$))/mg,
|
||||
element: "blockquote",
|
||||
handler: config.formatterHelpers.createElementAndWikify
|
||||
},
|
||||
|
||||
{
|
||||
name: "quoteByLine",
|
||||
match: "^>+",
|
||||
lookaheadRegExp: /^>+/mg,
|
||||
termRegExp: /(\n)/mg,
|
||||
element: "blockquote",
|
||||
handler: function(w)
|
||||
{
|
||||
var stack = [w.output];
|
||||
var currLevel = 0;
|
||||
var newLevel = w.matchLength;
|
||||
var t,matched;
|
||||
do {
|
||||
if(newLevel > currLevel) {
|
||||
for(t=currLevel; t<newLevel; t++)
|
||||
stack.push(createTiddlyElement(stack[stack.length-1],this.element));
|
||||
} else if(newLevel < currLevel) {
|
||||
for(t=currLevel; t>newLevel; t--)
|
||||
stack.pop();
|
||||
}
|
||||
currLevel = newLevel;
|
||||
w.subWikifyTerm(stack[stack.length-1],this.termRegExp);
|
||||
createTiddlyElement(stack[stack.length-1],"br");
|
||||
this.lookaheadRegExp.lastIndex = w.nextMatch;
|
||||
var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
|
||||
matched = lookaheadMatch && lookaheadMatch.index == w.nextMatch;
|
||||
if(matched) {
|
||||
newLevel = lookaheadMatch[0].length;
|
||||
w.nextMatch += lookaheadMatch[0].length;
|
||||
}
|
||||
} while(matched);
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: "rule",
|
||||
match: "^----+$\\n?|<hr ?/?>\\n?",
|
||||
handler: function(w)
|
||||
{
|
||||
createTiddlyElement(w.output,"hr");
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: "monospacedByLine",
|
||||
match: "^(?:/\\*\\{\\{\\{\\*/|\\{\\{\\{|//\\{\\{\\{|<!--\\{\\{\\{-->)\\n",
|
||||
element: "pre",
|
||||
handler: function(w)
|
||||
{
|
||||
switch(w.matchText) {
|
||||
case "/*{{{*/\n": // CSS
|
||||
this.lookaheadRegExp = /\/\*\{\{\{\*\/\n*((?:^[^\n]*\n)+?)(\n*^\f*\/\*\}\}\}\*\/$\n?)/mg;
|
||||
break;
|
||||
case "{{{\n": // monospaced block
|
||||
this.lookaheadRegExp = /^\{\{\{\n((?:^[^\n]*\n)+?)(^\f*\}\}\}$\n?)/mg;
|
||||
break;
|
||||
case "//{{{\n": // plugin
|
||||
this.lookaheadRegExp = /^\/\/\{\{\{\n\n*((?:^[^\n]*\n)+?)(\n*^\f*\/\/\}\}\}$\n?)/mg;
|
||||
break;
|
||||
case "<!--{{{-->\n": //template
|
||||
this.lookaheadRegExp = /<!--\{\{\{-->\n*((?:^[^\n]*\n)+?)(\n*^\f*<!--\}\}\}-->$\n?)/mg;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
config.formatterHelpers.enclosedTextHelper.call(this,w);
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: "wikifyComment",
|
||||
match: "^(?:/\\*\\*\\*|<!---)\\n",
|
||||
handler: function(w)
|
||||
{
|
||||
var termRegExp = (w.matchText == "/***\n") ? (/(^\*\*\*\/\n)/mg) : (/(^--->\n)/mg);
|
||||
w.subWikifyTerm(w.output,termRegExp);
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: "macro",
|
||||
match: "<<",
|
||||
lookaheadRegExp: /<<([^>\s]+)(?:\s*)((?:[^>]|(?:>(?!>)))*)>>/mg,
|
||||
handler: function(w)
|
||||
{
|
||||
this.lookaheadRegExp.lastIndex = w.matchStart;
|
||||
var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
|
||||
if(lookaheadMatch && lookaheadMatch.index == w.matchStart && lookaheadMatch[1]) {
|
||||
w.nextMatch = this.lookaheadRegExp.lastIndex;
|
||||
invokeMacro(w.output,lookaheadMatch[1],lookaheadMatch[2],w,w.tiddler);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: "prettyLink",
|
||||
match: "\\[\\[",
|
||||
lookaheadRegExp: /\[\[(.*?)(?:\|(~)?(.*?))?\]\]/mg,
|
||||
handler: function(w)
|
||||
{
|
||||
this.lookaheadRegExp.lastIndex = w.matchStart;
|
||||
var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
|
||||
if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
|
||||
var e;
|
||||
var text = lookaheadMatch[1];
|
||||
if(lookaheadMatch[3]) {
|
||||
// Pretty bracketted link
|
||||
var link = lookaheadMatch[3];
|
||||
e = (!lookaheadMatch[2] && config.formatterHelpers.isExternalLink(link)) ?
|
||||
createExternalLink(w.output,link) : createTiddlyLink(w.output,link,false,null,w.isStatic,w.tiddler);
|
||||
} else {
|
||||
// Simple bracketted link
|
||||
e = createTiddlyLink(w.output,text,false,null,w.isStatic,w.tiddler);
|
||||
}
|
||||
createTiddlyText(e,text);
|
||||
w.nextMatch = this.lookaheadRegExp.lastIndex;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: "wikiLink",
|
||||
match: config.textPrimitives.unWikiLink+"?"+config.textPrimitives.wikiLink,
|
||||
handler: function(w)
|
||||
{
|
||||
if(w.matchText.substr(0,1) == config.textPrimitives.unWikiLink) {
|
||||
w.outputText(w.output,w.matchStart+1,w.nextMatch);
|
||||
return;
|
||||
}
|
||||
if(w.matchStart > 0) {
|
||||
var preRegExp = new RegExp(config.textPrimitives.anyLetterStrict,"mg");
|
||||
preRegExp.lastIndex = w.matchStart-1;
|
||||
var preMatch = preRegExp.exec(w.source);
|
||||
if(preMatch.index == w.matchStart-1) {
|
||||
w.outputText(w.output,w.matchStart,w.nextMatch);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(w.autoLinkWikiWords || store.isShadowTiddler(w.matchText)) {
|
||||
var link = createTiddlyLink(w.output,w.matchText,false,null,w.isStatic,w.tiddler);
|
||||
w.outputText(link,w.matchStart,w.nextMatch);
|
||||
} else {
|
||||
w.outputText(w.output,w.matchStart,w.nextMatch);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: "urlLink",
|
||||
match: config.textPrimitives.urlPattern,
|
||||
handler: function(w)
|
||||
{
|
||||
w.outputText(createExternalLink(w.output,w.matchText),w.matchStart,w.nextMatch);
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: "image",
|
||||
match: "\\[[<>]?[Ii][Mm][Gg]\\[",
|
||||
//# [<] sequence below is to avoid lessThan-questionMark sequence so TiddlyWikis can be included in PHP files
|
||||
lookaheadRegExp: /\[([<]?)(>?)[Ii][Mm][Gg]\[(?:([^\|\]]+)\|)?([^\[\]\|]+)\](?:\[([^\]]*)\])?\]/mg,
|
||||
handler: function(w)
|
||||
{
|
||||
this.lookaheadRegExp.lastIndex = w.matchStart;
|
||||
var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
|
||||
if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
|
||||
var e = w.output;
|
||||
if(lookaheadMatch[5]) {
|
||||
var link = lookaheadMatch[5];
|
||||
e = config.formatterHelpers.isExternalLink(link) ? createExternalLink(w.output,link) : createTiddlyLink(w.output,link,false,null,w.isStatic,w.tiddler);
|
||||
jQuery(e).addClass("imageLink");
|
||||
}
|
||||
var img = createTiddlyElement(e,"img");
|
||||
if(lookaheadMatch[1])
|
||||
img.align = "left";
|
||||
else if(lookaheadMatch[2])
|
||||
img.align = "right";
|
||||
if(lookaheadMatch[3]) {
|
||||
img.title = lookaheadMatch[3];
|
||||
img.setAttribute("alt",lookaheadMatch[3]);
|
||||
}
|
||||
img.src = lookaheadMatch[4];
|
||||
w.nextMatch = this.lookaheadRegExp.lastIndex;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: "html",
|
||||
match: "<[Hh][Tt][Mm][Ll]>",
|
||||
lookaheadRegExp: /<[Hh][Tt][Mm][Ll]>((?:.|\n)*?)<\/[Hh][Tt][Mm][Ll]>/mg,
|
||||
handler: function(w)
|
||||
{
|
||||
this.lookaheadRegExp.lastIndex = w.matchStart;
|
||||
var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
|
||||
if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
|
||||
createTiddlyElement(w.output,"span").innerHTML = lookaheadMatch[1];
|
||||
w.nextMatch = this.lookaheadRegExp.lastIndex;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: "commentByBlock",
|
||||
match: "/%",
|
||||
lookaheadRegExp: /\/%((?:.|\n)*?)%\//mg,
|
||||
handler: function(w)
|
||||
{
|
||||
this.lookaheadRegExp.lastIndex = w.matchStart;
|
||||
var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
|
||||
if(lookaheadMatch && lookaheadMatch.index == w.matchStart)
|
||||
w.nextMatch = this.lookaheadRegExp.lastIndex;
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: "characterFormat",
|
||||
match: "''|//|__|\\^\\^|~~|--(?!\\s|$)|\\{\\{\\{",
|
||||
handler: function(w)
|
||||
{
|
||||
switch(w.matchText) {
|
||||
case "''":
|
||||
w.subWikifyTerm(w.output.appendChild(document.createElement("strong")),/('')/mg);
|
||||
break;
|
||||
case "//":
|
||||
w.subWikifyTerm(createTiddlyElement(w.output,"em"),/(\/\/)/mg);
|
||||
break;
|
||||
case "__":
|
||||
w.subWikifyTerm(createTiddlyElement(w.output,"u"),/(__)/mg);
|
||||
break;
|
||||
case "^^":
|
||||
w.subWikifyTerm(createTiddlyElement(w.output,"sup"),/(\^\^)/mg);
|
||||
break;
|
||||
case "~~":
|
||||
w.subWikifyTerm(createTiddlyElement(w.output,"sub"),/(~~)/mg);
|
||||
break;
|
||||
case "--":
|
||||
w.subWikifyTerm(createTiddlyElement(w.output,"strike"),/(--)/mg);
|
||||
break;
|
||||
case "{{{":
|
||||
var lookaheadRegExp = /\{\{\{((?:.|\n)*?)\}\}\}/mg;
|
||||
lookaheadRegExp.lastIndex = w.matchStart;
|
||||
var lookaheadMatch = lookaheadRegExp.exec(w.source);
|
||||
if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
|
||||
createTiddlyElement(w.output,"code",null,null,lookaheadMatch[1]);
|
||||
w.nextMatch = lookaheadRegExp.lastIndex;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: "customFormat",
|
||||
match: "@@|\\{\\{",
|
||||
handler: function(w)
|
||||
{
|
||||
switch(w.matchText) {
|
||||
case "@@":
|
||||
var e = createTiddlyElement(w.output,"span");
|
||||
var styles = config.formatterHelpers.inlineCssHelper(w);
|
||||
if(styles.length == 0)
|
||||
e.className = "marked";
|
||||
else
|
||||
config.formatterHelpers.applyCssHelper(e,styles);
|
||||
w.subWikifyTerm(e,/(@@)/mg);
|
||||
break;
|
||||
case "{{":
|
||||
var lookaheadRegExp = /\{\{[\s]*([\w]+[\s\w]*)[\s]*\{(\n?)/mg;
|
||||
lookaheadRegExp.lastIndex = w.matchStart;
|
||||
var lookaheadMatch = lookaheadRegExp.exec(w.source);
|
||||
if(lookaheadMatch) {
|
||||
w.nextMatch = lookaheadRegExp.lastIndex;
|
||||
e = createTiddlyElement(w.output,lookaheadMatch[2] == "\n" ? "div" : "span",null,lookaheadMatch[1]);
|
||||
w.subWikifyTerm(e,/(\}\}\})/mg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: "mdash",
|
||||
match: "--",
|
||||
handler: function(w)
|
||||
{
|
||||
createTiddlyElement(w.output,"span").innerHTML = "—";
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: "lineBreak",
|
||||
match: "\\n|<br ?/?>",
|
||||
handler: function(w)
|
||||
{
|
||||
createTiddlyElement(w.output,"br");
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: "rawText",
|
||||
match: "\"{3}|<nowiki>",
|
||||
lookaheadRegExp: /(?:\"{3}|<nowiki>)((?:.|\n)*?)(?:\"{3}|<\/nowiki>)/mg,
|
||||
handler: function(w)
|
||||
{
|
||||
this.lookaheadRegExp.lastIndex = w.matchStart;
|
||||
var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
|
||||
if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
|
||||
createTiddlyElement(w.output,"span",null,null,lookaheadMatch[1]);
|
||||
w.nextMatch = this.lookaheadRegExp.lastIndex;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: "htmlEntitiesEncoding",
|
||||
match: "(?:(?:&#?[a-zA-Z0-9]{2,8};|.)(?:&#?(?:x0*(?:3[0-6][0-9a-fA-F]|1D[c-fC-F][0-9a-fA-F]|20[d-fD-F][0-9a-fA-F]|FE2[0-9a-fA-F])|0*(?:76[89]|7[7-9][0-9]|8[0-7][0-9]|761[6-9]|76[2-7][0-9]|84[0-3][0-9]|844[0-7]|6505[6-9]|6506[0-9]|6507[0-1]));)+|&#?[a-zA-Z0-9]{2,8};)",
|
||||
handler: function(w)
|
||||
{
|
||||
createTiddlyElement(w.output,"span").innerHTML = w.matchText;
|
||||
}
|
||||
}
|
||||
|
||||
];
|
||||
|
||||
exports.Formatter = Formatter;
|
211
js/Wikifier.js
Executable file
211
js/Wikifier.js
Executable file
@ -0,0 +1,211 @@
|
||||
/*global require: false, exports: false, process: false */
|
||||
"use strict";
|
||||
|
||||
var Tiddler = require("./Tiddler.js").Tiddler,
|
||||
TiddlyWiki = require("./TiddlyWiki.js").TiddlyWiki,
|
||||
utils = require("./Utils.js"),
|
||||
util = require("util");
|
||||
|
||||
//# Construct a wikifier object
|
||||
//# source - source string that's going to be wikified
|
||||
//# formatter - Formatter() object containing the list of formatters to be used
|
||||
//# highlightRegExp - regular expression of the text string to highlight
|
||||
//# tiddler - reference to the tiddler that's taken to be the container for this wikification
|
||||
var Wikifier = function(source,formatter,highlightRegExp,tiddler)
|
||||
{
|
||||
this.source = source;
|
||||
this.output = null;
|
||||
this.formatter = formatter;
|
||||
this.nextMatch = 0;
|
||||
this.autoLinkWikiWords = tiddler && tiddler.autoLinkWikiWords() == false ? false : true;
|
||||
this.highlightRegExp = highlightRegExp;
|
||||
this.highlightMatch = null;
|
||||
this.isStatic = false;
|
||||
if(highlightRegExp) {
|
||||
highlightRegExp.lastIndex = 0;
|
||||
this.highlightMatch = highlightRegExp.exec(source);
|
||||
}
|
||||
this.tiddler = tiddler;
|
||||
}
|
||||
|
||||
Wikifier.prototype.wikifyPlain = function()
|
||||
{
|
||||
var e = createTiddlyElement(document.body,"div");
|
||||
e.style.display = "none";
|
||||
this.subWikify(e);
|
||||
var text = jQuery(e).text();
|
||||
jQuery(e).remove();
|
||||
return text;
|
||||
};
|
||||
|
||||
Wikifier.prototype.subWikify = function(output,terminator)
|
||||
{
|
||||
//# Handle the terminated and unterminated cases separately, this speeds up wikifikation by about 30%
|
||||
try {
|
||||
if(terminator)
|
||||
this.subWikifyTerm(output,new RegExp("(" + terminator + ")","mg"));
|
||||
else
|
||||
this.subWikifyUnterm(output);
|
||||
} catch(ex) {
|
||||
showException(ex);
|
||||
}
|
||||
};
|
||||
|
||||
Wikifier.prototype.subWikifyUnterm = function(output)
|
||||
{
|
||||
//# subWikify can be indirectly recursive, so we need to save the old output pointer
|
||||
var oldOutput = this.output;
|
||||
this.output = output;
|
||||
//# Get the first match
|
||||
this.formatter.formatterRegExp.lastIndex = this.nextMatch;
|
||||
var formatterMatch = this.formatter.formatterRegExp.exec(this.source);
|
||||
while(formatterMatch) {
|
||||
// Output any text before the match
|
||||
if(formatterMatch.index > this.nextMatch)
|
||||
this.outputText(this.output,this.nextMatch,formatterMatch.index);
|
||||
// Set the match parameters for the handler
|
||||
this.matchStart = formatterMatch.index;
|
||||
this.matchLength = formatterMatch[0].length;
|
||||
this.matchText = formatterMatch[0];
|
||||
this.nextMatch = this.formatter.formatterRegExp.lastIndex;
|
||||
//# Figure out which formatter matched and call its handler
|
||||
var t;
|
||||
for(t=1; t<formatterMatch.length; t++) {
|
||||
if(formatterMatch[t]) {
|
||||
this.formatter.formatters[t-1].handler(this);
|
||||
this.formatter.formatterRegExp.lastIndex = this.nextMatch;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//# Get the next match
|
||||
formatterMatch = this.formatter.formatterRegExp.exec(this.source);
|
||||
}
|
||||
//# Output any text after the last match
|
||||
if(this.nextMatch < this.source.length) {
|
||||
this.outputText(this.output,this.nextMatch,this.source.length);
|
||||
this.nextMatch = this.source.length;
|
||||
}
|
||||
//# Restore the output pointer
|
||||
this.output = oldOutput;
|
||||
};
|
||||
|
||||
Wikifier.prototype.subWikifyTerm = function(output,terminatorRegExp)
|
||||
{
|
||||
//# subWikify can be indirectly recursive, so we need to save the old output pointer
|
||||
var oldOutput = this.output;
|
||||
this.output = output;
|
||||
//# Get the first matches for the formatter and terminator RegExps
|
||||
terminatorRegExp.lastIndex = this.nextMatch;
|
||||
var terminatorMatch = terminatorRegExp.exec(this.source);
|
||||
this.formatter.formatterRegExp.lastIndex = this.nextMatch;
|
||||
var formatterMatch = this.formatter.formatterRegExp.exec(terminatorMatch ? this.source.substr(0,terminatorMatch.index) : this.source);
|
||||
while(terminatorMatch || formatterMatch) {
|
||||
//# Check for a terminator match before the next formatter match
|
||||
if(terminatorMatch && (!formatterMatch || terminatorMatch.index <= formatterMatch.index)) {
|
||||
//# Output any text before the match
|
||||
if(terminatorMatch.index > this.nextMatch)
|
||||
this.outputText(this.output,this.nextMatch,terminatorMatch.index);
|
||||
//# Set the match parameters
|
||||
this.matchText = terminatorMatch[1];
|
||||
this.matchLength = terminatorMatch[1].length;
|
||||
this.matchStart = terminatorMatch.index;
|
||||
this.nextMatch = this.matchStart + this.matchLength;
|
||||
//# Restore the output pointer
|
||||
this.output = oldOutput;
|
||||
return;
|
||||
}
|
||||
//# It must be a formatter match; output any text before the match
|
||||
if(formatterMatch.index > this.nextMatch)
|
||||
this.outputText(this.output,this.nextMatch,formatterMatch.index);
|
||||
//# Set the match parameters
|
||||
this.matchStart = formatterMatch.index;
|
||||
this.matchLength = formatterMatch[0].length;
|
||||
this.matchText = formatterMatch[0];
|
||||
this.nextMatch = this.formatter.formatterRegExp.lastIndex;
|
||||
//# Figure out which formatter matched and call its handler
|
||||
var t;
|
||||
for(t=1; t<formatterMatch.length; t++) {
|
||||
if(formatterMatch[t]) {
|
||||
this.formatter.formatters[t-1].handler(this);
|
||||
this.formatter.formatterRegExp.lastIndex = this.nextMatch;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//# Get the next match
|
||||
terminatorRegExp.lastIndex = this.nextMatch;
|
||||
terminatorMatch = terminatorRegExp.exec(this.source);
|
||||
formatterMatch = this.formatter.formatterRegExp.exec(terminatorMatch ? this.source.substr(0,terminatorMatch.index) : this.source);
|
||||
}
|
||||
//# Output any text after the last match
|
||||
if(this.nextMatch < this.source.length) {
|
||||
this.outputText(this.output,this.nextMatch,this.source.length);
|
||||
this.nextMatch = this.source.length;
|
||||
}
|
||||
//# Restore the output pointer
|
||||
this.output = oldOutput;
|
||||
};
|
||||
|
||||
Wikifier.prototype.outputText = function(place,startPos,endPos)
|
||||
{
|
||||
//# Check for highlights
|
||||
while(this.highlightMatch && (this.highlightRegExp.lastIndex > startPos) && (this.highlightMatch.index < endPos) && (startPos < endPos)) {
|
||||
//# Deal with any plain text before the highlight
|
||||
if(this.highlightMatch.index > startPos) {
|
||||
createTiddlyText(place,this.source.substring(startPos,this.highlightMatch.index));
|
||||
startPos = this.highlightMatch.index;
|
||||
}
|
||||
//# Deal with the highlight
|
||||
var highlightEnd = Math.min(this.highlightRegExp.lastIndex,endPos);
|
||||
createTiddlyElement(place,"span",null,"highlight",this.source.substring(startPos,highlightEnd));
|
||||
startPos = highlightEnd;
|
||||
//# Nudge along to the next highlight if we're done with this one
|
||||
if(startPos >= this.highlightRegExp.lastIndex)
|
||||
this.highlightMatch = this.highlightRegExp.exec(this.source);
|
||||
}
|
||||
//# Do the unhighlighted text left over
|
||||
if(startPos < endPos) {
|
||||
createTiddlyText(place,this.source.substring(startPos,endPos));
|
||||
}
|
||||
};
|
||||
|
||||
Wikifier.wikify = function(source,output,highlightRegExp,tiddler)
|
||||
{
|
||||
if(source) {
|
||||
var wikifier = new Wikifier(source,getParser(tiddler),highlightRegExp,tiddler);
|
||||
var t0 = new Date();
|
||||
wikifier.subWikify(output);
|
||||
if(tiddler && config.options.chkDisplayInstrumentation)
|
||||
displayMessage("wikify:" +tiddler.title+ " in " + (new Date()-t0) + " ms");
|
||||
}
|
||||
};
|
||||
|
||||
Wikifier.wikifyStatic = function(source,highlightRegExp,tiddler,format)
|
||||
{
|
||||
var e = createTiddlyElement(document.body,"pre");
|
||||
e.style.display = "none";
|
||||
var html = "";
|
||||
if(source && source != "") {
|
||||
if(!tiddler)
|
||||
tiddler = new Tiddler("temp");
|
||||
var wikifier = new Wikifier(source,getParser(tiddler,format),highlightRegExp,tiddler);
|
||||
wikifier.isStatic = true;
|
||||
wikifier.subWikify(e);
|
||||
html = e.innerHTML;
|
||||
jQuery(e).remove();
|
||||
}
|
||||
return html;
|
||||
};
|
||||
|
||||
//# Wikify a string to plain text
|
||||
//# text - text to wikify
|
||||
//# limit - maximum number of characters to generate
|
||||
//# tiddler - optional reference to the tiddler containing this text
|
||||
Wikifier.wikifyPlainText = function(text,limit,tiddler)
|
||||
{
|
||||
if(limit > 0)
|
||||
text = text.substr(0,limit);
|
||||
var wikifier = new Wikifier(text,formatter,null,tiddler);
|
||||
return wikifier.wikifyPlain();
|
||||
};
|
||||
|
||||
exports.Wikifier = Wikifier;
|
Loading…
Reference in New Issue
Block a user