/*global require: false, exports: false, process: false */ "use strict"; var util = require("util"); var textPrimitives = { upperLetter: "[A-Z\u00c0-\u00de\u0150\u0170]", lowerLetter: "[a-z0-9_\\-\u00df-\u00ff\u0151\u0171]", anyLetter: "[A-Za-z0-9_\\-\u00c0-\u00de\u00df-\u00ff\u0150\u0170\u0151\u0171]", anyLetterStrict: "[A-Za-z0-9\u00c0-\u00de\u00df-\u00ff\u0150\u0170\u0151\u0171]", sliceSeparator: "::", sectionSeparator: "##", urlPattern: "(?:file|http|https|mailto|ftp|irc|news|data):[^\\s'\"]+(?:/|\\b)", unWikiLink: "~", brackettedLink: "\\[\\[([^\\]]+)\\]\\]", titledBrackettedLink: "\\[\\[([^\\[\\]\\|]+)\\|([^\\[\\]\\|]+)\\]\\]" }; textPrimitives.wikiLink = "(?:(?:" + textPrimitives.upperLetter + "+" + textPrimitives.lowerLetter + "+" + textPrimitives.upperLetter + textPrimitives.anyLetter + "*)|(?:" + textPrimitives.upperLetter + "{2,}" + textPrimitives.lowerLetter + "+))"; textPrimitives.cssLookahead = "(?:(" + textPrimitives.anyLetter + "+)\\(([^\\)\\|\\n]+)(?:\\):))|(?:(" + textPrimitives.anyLetter + "+):([^;\\|\\n]+);)"; textPrimitives.cssLookaheadRegExp = new RegExp(textPrimitives.cssLookahead,"mg"); textPrimitives.tiddlerForcedLinkRegExp = new RegExp("(?:" + textPrimitives.titledBrackettedLink + ")|(?:" + textPrimitives.brackettedLink + ")|(?:" + textPrimitives.urlPattern + ")","mg"); textPrimitives.tiddlerAnyLinkRegExp = new RegExp("("+ textPrimitives.wikiLink + ")|(?:" + textPrimitives.titledBrackettedLink + ")|(?:" + textPrimitives.brackettedLink + ")|(?:" + textPrimitives.urlPattern + ")","mg"); function WikiTextRules() { var pattern = []; this.rules = WikiTextRules.rules; for(var n=0; n 1) { last.element.attributes.colspan = colSpanCount; 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.attributes.colspan = colSpanCount; } w.nextMatch = this.cellRegExp.lastIndex; break; } else { // Cell w.nextMatch++; var styles = WikiTextRules.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 = {type: "th", attributes: {}, children: []}; e.push(cell); w.nextMatch++; } else { cell = {type: "td", attributes: {}, children: []}; e.push(cell); } prevCell = cell; prevColumns[col] = {rowSpanCount:1,element:cell}; if(colSpanCount > 1) { cell.attributes.colspan = colSpanCount; colSpanCount = 1; } WikiTextRules.applyCssHelper(cell,styles); w.subWikifyTerm(cell,this.cellTermRegExp); if(w.matchText.substr(w.matchText.length-2,1) == " ") // spaceRight cell.attributes.align = spaceLeft ? "center" : "left"; else if(spaceLeft) cell.attributes.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) { var e = {type: "h" + w.matchLength, children: []}; w.output.push(e); w.subWikifyTerm(e.children,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,e; if(listLevel > currLevel) { for(t=currLevel; tlistLevel; t--) stack.pop(); } else if(listLevel == currLevel && listType != currType) { stack.pop(); e = {type: listType, children: []}; stack[stack.length-1].push(e); stack.push(e.children); } currLevel = listLevel; currType = listType; e = {type: itemType, children: []}; stack[stack.length-1].push(e); w.subWikifyTerm(e.children,this.termRegExp); this.lookaheadRegExp.lastIndex = w.nextMatch; lookaheadMatch = this.lookaheadRegExp.exec(w.source); } } }, { name: "quoteByBlock", match: "^<<<\\n", termRegExp: /(^<<<(\n|$))/mg, element: "blockquote", handler: WikiTextRules.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,e; do { if(newLevel > currLevel) { for(t=currLevel; tnewLevel; t--) stack.pop(); } currLevel = newLevel; w.subWikifyTerm(stack[stack.length-1],this.termRegExp); stack[stack.length-1].push({type: "br", attributes: {}}); 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?|
\\n?", handler: function(w) { var e = {type: "hr", attributes: {}}; w.output.push(e); } }, { 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; } WikiTextRules.enclosedTextHelper.call(this,w); } }, { name: "wikifyComment", match: "^(?:/\\*\\*\\*|\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; w.output.push({type: "macro", name: lookaheadMatch[1], params: lookaheadMatch[2]}); } } }, { 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]; if(!lookaheadMatch[2] && WikiTextRules.isExternalLink(w,link)) { e = {type: "a", href: link, children: []}; } else { e = {type: "tiddlerLink", href: link, children: []}; } } else { // Simple bracketted link e = {type: "tiddlerLink", href: text, children: []}; } w.output.push(e); e.children.push({type: "text", value: text}); w.nextMatch = this.lookaheadRegExp.lastIndex; } } }, { name: "wikiLink", match: textPrimitives.unWikiLink+"?"+textPrimitives.wikiLink, handler: function(w) { if(w.matchText.substr(0,1) == textPrimitives.unWikiLink) { w.outputText(w.output,w.matchStart+1,w.nextMatch); return; } if(w.matchStart > 0) { var preRegExp = new RegExp(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) { var link = {type: "tiddlerLink", href: w.matchText, children: []}; w.output.push(link); w.outputText(link.children,w.matchStart,w.nextMatch); } else { w.outputText(w.output,w.matchStart,w.nextMatch); } } }, { name: "urlLink", match: textPrimitives.urlPattern, handler: function(w) { var e = {type: "a", href: w.matchText, children: []}; w.output.push(e); w.outputText(e.children,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],t; if(WikiTextRules.isExternalLink(w,link)) { t = {type: "a", href: link, children: []}; w.output.push(t); e = t.children; } else { t = {type: "tiddlerLink", href: link, children: []}; w.output.push(t); e = t.children; } t.attributes.className = "imageLink"; } var img = {type: "img"}; e.push(img); if(lookaheadMatch[1]) WikiTextRules.setAttr(img,"align","left"); else if(lookaheadMatch[2]) WikiTextRules.setAttr(img,"align","right"); if(lookaheadMatch[3]) { WikiTextRules.setAttr(img,"title",lookaheadMatch[3]); WikiTextRules.setAttr(img,"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) { w.output.push({type: "html", value: 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) { var e; switch(w.matchText) { case "''": e = {type: "strong", children: []}; w.output.push(e); w.subWikifyTerm(e.children,/('')/mg); break; case "//": e = {type: "em", children: []}; w.output.push(e); w.subWikifyTerm(e.children,/(\/\/)/mg); break; case "__": e = {type: "u", children: []}; w.output.push(e); w.subWikifyTerm(e.children,/(__)/mg); break; case "^^": e = {type: "sup", children: []}; w.output.push(e); w.subWikifyTerm(e.children,/(\^\^)/mg); break; case "~~": e = {type: "sub", children: []}; w.output.push(e); w.subWikifyTerm(e.children,/(~~)/mg); break; case "--": e = {type: "strike", children: []}; w.output.push(e); w.subWikifyTerm(e.children,/(--)/mg); break; case "{{{": var lookaheadRegExp = /\{\{\{((?:.|\n)*?)\}\}\}/mg; lookaheadRegExp.lastIndex = w.matchStart; var lookaheadMatch = lookaheadRegExp.exec(w.source); if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { w.output.push({type: "code", children: [ {type: "text", value: lookaheadMatch[1]} ]}); w.nextMatch = lookaheadRegExp.lastIndex; } break; } } }, { name: "customFormat", match: "@@|\\{\\{", handler: function(w) { switch(w.matchText) { case "@@": var e = {type: "span", attributes: {}, children: []}; w.output.push(e); var styles = WikiTextRules.inlineCssHelper(w); if(styles.length === 0) e.className = "marked"; else WikiTextRules.applyCssHelper(e,styles); w.subWikifyTerm(e.children,/(@@)/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 = {type: lookaheadMatch[2] == "\n" ? "div" : "span", children: [ {type: "text", value: lookaheadMatch[1]} ]}; w.output.push(e); w.subWikifyTerm(e.children,/(\}\}\})/mg); } break; } } }, { name: "mdash", match: "--", handler: function(w) { w.output.push({type: "text", value: "—"}); } }, { name: "lineBreak", match: "\\n|
", handler: function(w) { w.output.push({type: "br"}); } }, { name: "rawText", match: "\"{3}|", lookaheadRegExp: /(?:\"{3}|)((?:.|\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) { w.output.push({type: "text", value: 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) { w.output.push({type: "text", value: w.matchText}); } } ]; exports.wikiTextRules = new WikiTextRules();