/extras/t2tformatterplugin.tiddly
Unknown | 952 lines | 888 code | 64 blank | 0 comment | 0 complexity | b9a2656348a8e54e7ea5cd5796347f74 MD5 | raw file
1/*** 2|''Name:''|T2tFormatterPlugin| 3|''Description:''|Allows Tiddlers to use [[txt2tags|http://txt2tags.org/markup.html]] formatting| 4|''Author:''|David Young (david (dot) a (dot) young (at) gmail (dot) com)| 5|''Credit:''|Copied and modified from Martin Budden's http://www.martinswiki.com/#ExampleFormatterPlugin | 6|''CodeRepository:''|NA | 7|''Version:''|0.4| 8|''Status:''|Rough Draft| 9|''Date:''|Jul 5, 2011| 10|''Comments:''|Please make comments at http://groups.google.co.uk/group/TiddlyWikiDev | 11|''License:''|NA | 12|''~CoreVersion:''|2.6.1| 13 14! Installation Instructions 15 16Apply the following tags to this tiddler: 17 18* systemConfig 19* excludeLists 20* excludeSearch 21 22You can make a tiddler with the tag ''t2t'' and the Txt2Tags markup will be used instead of TiddlyWiki markup. You can eliminate the need to manually tag by modifying your ''Create New Tiddler'' macro in your [[MainMenu]] to set the //wikiformat// field to ''t2t'': 23 24{{{ 25<<newTiddler 26label: "New t2t" 27title: "New t2t tiddler" 28fields: "wikiformat:t2t" 29prompt: "Create a new tiddler using the t2t formatter">> 30}}} 31 32You should also get into [[AdvancedOptions]] or //backstage -> Tweaks -> chkInsertTabs// because that lets you hit the tab button in the tiddly text field. Tab will still move your cursor around the page, from title input to tiddly text input, etc. It only effects the text field. Vital for t2t blockquote syntax (prepending with tabs). 33 34!Features/ Progress 35 36| ''Markup'' | ''Feature'' | ''Status'' | ''Version'' | ''Comment'' | 37| several | \n vs. \r in input | ''WAITING'' | NA |Applied to tagged and raw, but I am uncertain if this is OK.<br>Emailed twdev mailing list. | 38| ''FONT/INLINE'' ||||| 39|{{{**}}}''bold''{{{**}}} | All | ''OK'' | 0.1 |Hasn't been heavily tested on any platform. | 40|{{{//}}}//italic//{{{//}}} | All | ''OK'' | 0.1 |Hasn't been heavily tested on any platform. | 41|{{{__}}}__under__{{{__}}} | All | ''OK'' | 0.1 |Hasn't been heavily tested on any platform. | 42|{{{--}}}--strike--{{{--}}} | All | ''OK'' | 0.1 |Hasn't been heavily tested on any platform.| 43|{{{^^}}}^^super^^{{{^^}}} | All | ''OK'' | 0.1 |Hasn't been heavily tested on any platform.<br>Not Official Markup.| 44|{{{,,}}}~~sub~~{{{,,}}} | All | ''OK'' | 0.1 |Hasn't been heavily tested on any platform.<br>Not Official Markup.| 45|{{{``monospace``}}} | All | ''OK'' | 0.1 |Hasn't been heavily tested on any platform.| 46|{{{''}}}tagged/html{{{''}}} | All | ''OK'' | 0.1 |Hasn't been heavily tested on any platform.| 47|{{{""}}}raw{{{""}}} | All | ''OK'' | 0.1 |Hasn't been heavily tested on any platform.<br>Overrides WikiWords and Markup.| 48| ''SINGLE-LINE'' ||||| 49|{{{``` monospace}}} | All | ''OK'' | 0.1 |Hasn't been heavily tested on any platform. | 50|{{{'''}}} tagged/html | All | ''OK'' | 0.1 |Hasn't been heavily tested on any platform. | 51|{{{"""}}} raw | All | ''OK'' | 0.1 |Hasn't been heavily tested on any platform. | 52|{{{%}}}comments | ALL | ''OK'' | 0.1 |Hasn't been heavily tested on any platform. | 53| ''BLOCKS'' ||||| 54|{{{```}}}<br>{{{monospace}}}<br>{{{```}}} | All | ''OK'' | 0.1 |Hasn't been heavily tested on any platform. | 55|{{{'''}}}<br>tagged/html<br>{{{'''}}} | All | ''OK'' | 0.1 |Hasn't been heavily tested on any platform. | 56|{{{"""}}}<br>raw<br>{{{"""}}} | All | ''OK'' | 0.1 |Hasn't been heavily tested on any platform. | 57|{{{%%%}}}<br>comments<br>{{{%%%}}} | All | ''OK'' | 0.1 |Hasn't been heavily tested on any platform | 58|\t<html> </html>block<br>\t<html> </html>quotes | All | ''OK'' | 0.1 |Hasn't been heavily tested on any platform.<br>Tiddlywiki interprets all markup inside the block; unlike txt2tags (only some markup). | 59| ''HEADERS'' ||||| 60|{{{=}}}un-numbered{{{=}}} | ALL | ''OK'' | 0.1 |Hasn't been heavily tested on any platform. | 61|{{{+}}}numbered{{{+}}} | HEADING | ''OK'' | 0.1 |Hasn't been heavily tested on any platform. | 62|{{{+}}}numbered{{{+}}} | NUMBERING | ''OK'' | 0.1 |Hasn't been heavily tested on any platform.<br>Unknown if array length modification or array[6] reassignment is faster on a per-iteration basis. | 63| ''MISC'' ||||| 64|horizontal rule<br>{{{--------------------}}} | RULE | ''OK'' | 0.1 |Hasn't been heavily tested on any platform. | 65|{{{====================}}}<br>{{{____________________}}}| THICKNESS | ''??'' | 0.1 |The alternative rules are interpreted and classes //heavy// or //light// are assigned; but my theme doesn't use them so I can't tell.<br>Maybe tiddlywiki doesn't use those css classes at all?<br>If so, delete this functionality. | 66|Paragraphs | ALL | ''CAN'T FIX'' | 0.1 |Multiple newlines are concatenated into {{{<p><\p>}}}.<br>Visually they appear correctly (line spacing, etc), but it isn't a real paragraph.<br>If you try to make {{{<p>}}} elements wrap the text, then they are nested improperly if you look at the html.<br>This nesting lead to a stack busting on tiddlers if you have around 200 paragraphs or more.<br>This resulted in content truncation, so {{{<p><\p>}}} it shall be.<br>Historical bug in tiddlywiki's core, so I can't do much about it.<br>This is certainly a kludge, maybe {{{<br><br>}}} would be better, but that seems equally kludgy and all block-type syntax must be careful. | 67| ''LISTS'' ||||| 68|{{{- }}}unordered | ALL | ''OK'' | 0.1 |t2t allows complex lists (paragraphs inside list items).<br>Can't figure out a good regex to match "X blank lines" that works with paragraph.<br>Interim solution: terminate list with empty item. | 69|{{{+ }}}ordered | ALL | ''OK'' | 0.1 |t2t allows complex lists (paragraphs inside list items).<br>Can't figure out a good regex to match "X blank lines" that works with paragraph.<br>Interim solution: terminate list with empty item.<br>INTERFERES WITH NUMBERED HEADINGS. | 70|{{{: }}}word<br><html> </html>definitions | ALL | ''TIDDLY'' | NA |Difficult to pull off since "definition" part of t2t uses whitespaces.<br>Interim solution: use tiddlywiki ; word \n : definition format. | 71| ''COMPLEX'' ||||| 72|~WikiWords | ALL | ''TIDDLY'' | 0.1 |Self-updating link to core formatter.<br>Not Official Markup. | 73|{{{<<macros>>}}} | ALL | ''TIDDLY'' | 0.1 |Self-updating link to core formatter.<br>By changing the header syntax, the {{{<<tiddler##section>>}}} section transclusion macro won't work.<br>Not Official Markup. | 74|http url recognition | ALL | ''TIDDLY'' | 0.1 |Self-updating link to core formatter.<br>Not Official Markup. | 75|email recognition | ALL | ''NA'' | NA |Is this at all worth it? t2t will mask or convert to mailto...<br>don't take this lightly- it wrecked the works last time. | 76|{{{[}}}links{{{]}}} | ALL | ''OK'' | 0.1 |Links to internal tiddlers (as long as their title has no spaces), links to external websites | 77|{{{[}}}named links{{{]}}} | ALL | ''OK'' | 0.1 |Links to internal tiddlers (as long as their title has no spaces), links to external websites | 78|'image-related' | ALL | ''OK'' | 0.1 |an image or image link supports whitespace-alignment.<br>If the {{{[}}} starts at the newline, the image will float to the left (equivalent to the {{{<}}} markup in tiddly images).<br>If the {{{]}}} ends the line, the image will float to the right (equivalent to the {{{>}}} markup in tiddly images).<br>If the image is both the start and end of line, it is neither left nor right.<br>No centering image support yet. | 79|{{{[}}}images{{{]}}} | ALL | ''OK'' | 0.1 |Supports .png .gif .jpg .jpeg, just grep for IMAGE-EXTENSION-REGEX in this tiddler to expand the list.<br>Works for local and external image files | 80|{{{[[image] links]}}} | ALL | ''OK'' | 0.1 |A twist here is that the link can have spaces in the name, but I don't recommend trying that. | 81|{{{|}}}tables{{{|}}} | ALL | ''TIDDLY'' | 0.1 |Tiddlywiki tables are supported. Self-updating link to core formatter. | 82 83***/ 84 85//{{{ 86//REGEXES found in txt2tags.py:1920 (getRegexes) 87// Ensure that the plugin is only installed once. 88 89if(!version.extensions.T2tFormatterPlugin) { 90version.extensions.T2tFormatterPlugin = {installed:true}; 91 92//Should test this backwards until I find the revision that is actually useless 93if(version.major < 2 || (version.major == 2 && version.minor < 6)) 94 {alertAndThrow('T2tFormatterPlugin requires TiddlyWiki 2.6 or later.');} 95 96t2tFormatter = {}; // 'namespace' for local functions 97 98t2tDebug = function(out,str) 99{ 100 createTiddlyText(out,str.replace(/\n/mg,'\\n').replace(/\r/mg,'RR')); 101 createTiddlyElement(out,'br'); 102}; 103 104/* 105wikify = function(source,output,highlightRegExp,tiddler) 106{ 107 if(source && source !== '') { 108 var w = new Wikifier(source,getParser(tiddler),highlightRegExp,tiddler); 109 w.output = tiddler ? createTiddlyElement(output,'p') : output; 110 w.subWikifyUnterm(w.output); 111 } 112}; 113*/ 114 115// COPY from EnclosedTextHelper Tiddlywiki v2.6.1 line 2923 116// If the lookaheadRegexp fails, use the string in "restore:" 117// define the element "restore:" as the static string equal to your 118// "match:"'s result. 119// 120// If your markup rules are more complex/less dynamic (like ==headers==); 121// then you must copy this and make up your own combo of parenthesis. 122config.formatterHelpers.nonDestructiveEnclosedTextHelper = function(w) 123{ 124 this.lookaheadRegExp.lastIndex = w.matchStart; 125 var lookaheadMatch = this.lookaheadRegExp.exec(w.source); 126 if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { 127 //Everything that uses this function is a one-liner syntax 128 /* 129 var text = lookaheadMatch[1]; 130 if(config.browser.isIE) 131 text = text.replace(/\n/g,"\r"); 132 createTiddlyElement(w.output,this.element,null,null,text); 133 */ 134 //createTiddlyElement(w.output,this.element,null,null,lookaheadMatch[1]); 135 w.subWikifyTerm(createTiddlyElement(w.output,this.element),this.termRegExp); 136 w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length; 137 } else { 138 w.output.appendChild(document.createTextNode(w.matchText)); 139 } 140}; 141 142/* 143// Like nonDestructiveEnclosedTextHelper, only you can define what is 144// restored with a regular expression instead of a static string. 145// This is helpful for when the "match" is more dynamic. Just define 146// element "restoreRegExp:" and the first parenthesis in it will be used 147// to restore the consumed "match" text. 148// NOTE: this comes at the cost of ANOTHER grepping of your input! 149config.formatterHelpers.nonDestructiveEnclosedTextHelperRegEx = function(w) 150{ 151 this.lookaheadRegExp.lastIndex = w.matchStart; 152 var lookaheadMatch = this.lookaheadRegExp.exec(w.source); 153 if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { 154 var text = lookaheadMatch[1]; 155 if(config.browser.isIE) 156 text = text.replace(/\n/g,"\r"); 157 createTiddlyElement(w.output,this.element,null,null,text); 158 w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length; 159 } else { 160 this.restoreRegExp.lastIndex = w.matchStart; 161 var restoreMatch = this.restoreRegExp.exec(w.source); 162 if (restoreMatch && restoreMatch.index == w.matchStart) { 163 w.output.appendChild(document.createTextNode(restoreMatch[1])); 164 } else { 165 //shouldn't be possible! 166 //Only if you don't define restoreRegExp: properly 167 w.output.appendChild(document.createTextNode("### SYNTAX ERROR ###")); 168 } 169 } 170}; 171*/ 172 173/* 174config.formatterHelpers.setAttributesFromParams = function(e,p) 175{ 176 var re = /\s*(.*?)=(?:(?:"(.*?)")|(?:'(.*?)')|((?:\w|%|#)*))/mg; 177 var match = re.exec(p); 178 while(match) { 179 var s = match[1].unDash(); 180 if(s=='bgcolor') { 181 s = 'backgroundColor'; 182 } 183 try { 184 if(match[2]) { 185 e.setAttribute(s,match[2]); 186 } else if(match[3]) { 187 e.setAttribute(s,match[3]); 188 } else { 189 e.setAttribute(s,match[4]); 190 } 191 } 192 catch(ex) {} 193 match = re.exec(p); 194 } 195}; 196*/ 197 198config.t2tFormatters = [ 199 200//SPEED: COMBINE ALL BEAUTIFIERS LIKE TIDDLY DOES ALREADY 201// bold uses syntax **bold** no whitespace in the bookends. 202{ 203 name: 't2tBold', 204 match: '\\*\\*', 205 element: 'strong', 206 lookaheadRegExp: /\*\*([^\s](|.*?[^\s])\**)\*\*/mg, 207 termRegExp: /(\*\*)/mg, 208 handler: config.formatterHelpers.nonDestructiveEnclosedTextHelper 209}, 210 211// italic uses //italic// 212{ 213 name: 't2tItalic', 214 match: '//', 215 element: 'em', 216 lookaheadRegExp: /\/\/([^\s](|.*?[^\s])[\/]*)(\/\/)/mg, 217 termRegExp: /(\/\/)/mg, 218 handler: config.formatterHelpers.nonDestructiveEnclosedTextHelper 219}, 220 221// Horizontal rules can be made up of 20 or more - characters on a line with 222// whitespace on the ends. Alternatively 20 or more _ characters is accepted. 223// 20 or more = characters also work, but that makes a "thicker" horizontal rule 224// see t2tHeavyRule. 225{ 226 name: 't2tRule', 227 match: '^[ \\t]*[-_]{20,}[ \\t]*$', 228 handler: function(w) 229 { 230 createTiddlyElement(w.output,'hr',null,'light'); 231 } 232}, 233 234// Default tiddler theme doesn't differentiate between heavy and light. 235// TODO: Try some other themes otherwise roll this into t2tRule. 236{ 237 name: 't2tHeavyRule', 238 match: '^[ \\t]*={20,}[ \\t]*$', 239 handler: function(w) 240 { 241 createTiddlyElement(w.output,'hr',null,'heavy'); 242 } 243}, 244 245// underline uses __underline__ 246{ 247 name: 't2tUnderline', 248 match: '__', 249 element: 'ins', 250 lookaheadRegExp: /__([^\s](|.*?[^\s])_*)__/mg, 251 termRegExp: /(__)/mg, 252 handler: config.formatterHelpers.nonDestructiveEnclosedTextHelper 253}, 254 255// strikethrough uses --strike-- 256{ 257 name: 't2tStrike', 258 match: '--', 259 element: 'del', 260 lookaheadRegExp: /--([^\s](|.*?[^\s])-*)--/mg, 261 termRegExp: /(--)/mg, 262 handler: config.formatterHelpers.nonDestructiveEnclosedTextHelper 263}, 264 265/* 266// superscript uses ^^super^^ 267// this is unofficial 268{ 269 name: 't2tSuperscript', 270 match: '\\^\\^', 271 element: 'sup', 272 lookaheadRegExp: /\^\^([^\s](|.*?[^\s])\^*)\^\^/mg, 273 handler: config.formatterHelpers.nonDestructiveEnclosedTextHelper 274}, 275 276// subscript uses ,,sub,, 277// this is unofficial 278{ 279 name: 't2tSubscript', 280 match: ',,', 281 element: 'sub', 282 lookaheadRegExp: /,,([^\s](|.*?[^\s]),*),,/mg, 283 handler: config.formatterHelpers.nonDestructiveEnclosedTextHelper 284}, 285*/ 286 287// Monospace uses different variants of backticks 288// blocks are bordered with lines containing only 3 backticks 289// ``` 290{ 291 name: 't2tMonospaceBlock', 292 match: '^```[ \\t]*$', 293 lookaheadRegExp: /^```[ \t]*(?:\n?((?:.|\n)*?\n)```[ \t]*$)|((?:.|\n)*$)/gm, 294 handler: function(w) { 295 this.lookaheadRegExp.lastIndex = w.matchStart; 296 var lookaheadMatch = this.lookaheadRegExp.exec(w.source); 297 if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { 298 if (lookaheadMatch[1]) { 299 var text = lookaheadMatch[1]; 300 } else { 301 var text = lookaheadMatch[2].substr(w.matchLength+1); 302 } 303 if(config.browser.isIE) 304 text = text.replace(/\n/g,"\r"); 305 createTiddlyElement(w.output,"pre",null,null,text); 306 w.nextMatch = this.lookaheadRegExp.lastIndex; 307 } else w.output.appendChild(document.createTextNode(w.matchText)); 308 } 309}, 310 311// lines prefixed with 3 backticks are preformatted blocks as well 312// one block per line! putting backtic-prefixed lines consecutively will 313// result in 2 preformatted blocks! 314//SPEED: this can be like tiddly's termregexp syntax like a "Heading" 315{ 316 name: 't2tMonospaceLine', 317 match: '^``` ', 318 lookaheadRegExp: /^``` ((?:.)*?)$/mg, 319 element: 'pre', 320 handler: config.formatterHelpers.enclosedTextHelper 321}, 322 323// inline monospaced text ``like this``. 324// terminates at the first newline without matching backtics. 325// this version uses code instead of pre. 326{ 327 name: 't2tMonospace', 328 match: '``', 329 element: 'code', 330 lookaheadRegExp: /``([^\s](|.*?[^\s])`*)``/mg, 331 termRegExp: /(``)/mg, 332 handler: config.formatterHelpers.nonDestructiveEnclosedTextHelper 333}, 334 335//t2tCommentblock 336{ 337 name: 't2tCommentBlock', 338 match: '^%%%[ \\t]*\\n', 339 //emptyblock but no unclosed trailer 340 //lookaheadRegExp: /^%%%[ \t]*((?:.|\n)*?)\n%%%[ \t]*(\n|$)/mg, 341 // match next %%% line OR match to EOF 342 lookaheadRegExp: /^%%%[ \t]*(?:(?:[.|\n]*?)\n%%%[ \t]*$)|(?:[.\n]*$)/gm, 343 handler: function(w) 344 { 345 this.lookaheadRegExp.lastIndex = w.matchStart; 346 var lookaheadMatch = this.lookaheadRegExp.exec(w.source); 347 if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { 348 w.nextMatch = this.lookaheadRegExp.lastIndex; 349 } else w.output.appendChild(document.createTextNode(w.matchText)); 350 } 351}, 352 353//SPEED: this can be like tiddly's termregexp syntax like a "Heading" 354{ 355 name: 't2tCommentLine', 356 match: '^%' , 357 lookaheadRegExp: /^%.*?$/mg, 358 handler: function(w) 359 { 360 this.lookaheadRegExp.lastIndex = w.matchStart; 361 var lookaheadMatch = this.lookaheadRegExp.exec(w.source); 362 if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { 363 w.nextMatch = this.lookaheadRegExp.lastIndex; 364 } else w.output.appendChild(document.createTextNode(w.matchText)); 365 } 366}, 367 368// nonstandard br insertion 369// I like tex's \\ 370{ 371 name: 't2tLineBreak', 372 match: '\\\\\\\\', 373 handler: function(w) 374 { 375 createTiddlyElement(w.output,'br'); 376 } 377}, 378 379//TODO: tagged text doesn't get the \n \r IE replacement... test in IE 380// t2t tagged text is "passthrough" so what you type is passed on to 381// the html interpreter. t2t formatting isn't converted into html. 382// Raw html is interpreted by your browser. 383// Tagged uses various forms of single-quotes. 384// multi-line blocks are bordered by lines containing only ''' 385{ 386 name: 't2tTaggedBlock', 387 match: '^\'\'\'[ \\t]*$', 388 lookaheadRegExp: /^'''[ \t]*(?:((?:.|\n)*?\n)'''[ \t]*$)|((?:.|\n)*$)/gm, 389 handler: function(w) 390 { 391 this.lookaheadRegExp.lastIndex = w.matchStart; 392 var lookaheadMatch = this.lookaheadRegExp.exec(w.source); 393 if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { 394 if (lookaheadMatch[1]) { 395 var text = lookaheadMatch[1]; 396 } else { 397 var text = lookaheadMatch[2].substr(w.matchLength+1); 398 } 399 if(config.browser.isIE) 400 text = text.replace(/\n/g,"\r"); 401 createTiddlyElement(w.output,"span").innerHTML = text; 402 w.nextMatch = this.lookaheadRegExp.lastIndex; 403 } else w.output.appendChild(document.createTextNode(w.matchText)); 404 } 405}, 406 407// Single lines prepended with ''' will be considered "tagged" 408// Unlike monospace, tagged isn't really a "block" so having multiple 409// pre-pended lines won't look any different than one multi-line block. 410//SPEED: this can be like tiddly's termregexp syntax like a "Heading" 411{ 412 name: 't2tTaggedLine', 413 match: '^\'\'\' ', 414 lookaheadRegExp: /^''' ((?:.)*?)$/mg, 415 handler: function(w) 416 { 417 this.lookaheadRegExp.lastIndex = w.matchStart; 418 var lookaheadMatch = this.lookaheadRegExp.exec(w.source); 419 if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { 420 createTiddlyElement(w.output,"span").innerHTML = lookaheadMatch[1]; 421 w.nextMatch = this.lookaheadRegExp.lastIndex; 422 } else w.output.appendChild(document.createTextNode(w.matchText)); 423 } 424}, 425 426// inline tagged text is wrapped ''in 2 single quotes''. This type ends at 427// the newline if there is no matching ''. 428{ 429 name: 't2tTagged', 430 match: '\'\'', 431 lookaheadRegExp: /''([^\s](|.*?[^\s])'*)''/mg, 432 handler: function(w) 433 { 434 this.lookaheadRegExp.lastIndex = w.matchStart; 435 var lookaheadMatch = this.lookaheadRegExp.exec(w.source); 436 if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { 437 createTiddlyElement(w.output,"span").innerHTML = lookaheadMatch[1]; 438 w.nextMatch = this.lookaheadRegExp.lastIndex; 439 } else w.output.appendChild(document.createTextNode(w.matchText)); 440 } 441}, 442 443//TODO: RAW text doesn't get the \n \r IE replacement... test in IE 444// t2t Raw text ignores t2t formatting (any wiki formatting); but characters 445// are still 'escaped' out to be displayed by the brower. 446// e.g. ""**bold**"" isn't made bold; you see the astrices; while lines using 447// html tags will convert angle brackets to < > 448// This is synonymous with nowiki 449 450// Blocks of raw text are bordered with blank lines of 3 double quotes. 451{ 452 name: 't2tRawBlock', 453 match: '^\\"\\"\\"[ \\t]*$', 454 lookaheadRegExp: /^"""[ \t]*(?:((?:.|\n)*?\n)"""[ \t]*$)|((?:.|\n)*$)/gm, 455 handler: function(w) 456 { 457 this.lookaheadRegExp.lastIndex = w.matchStart; 458 var lookaheadMatch = this.lookaheadRegExp.exec(w.source); 459 if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { 460 if (lookaheadMatch[1]) { 461 var text = lookaheadMatch[1]; 462 } else { 463 var text = lookaheadMatch[2].substr(w.matchLength+1); 464 } 465 //rawblock may not work with this properly? 466 if(config.browser.isIE) 467 text = text.replace(/\n/g,"\r"); 468 createTiddlyElement(w.output,"span",null,null,text); 469 w.nextMatch = this.lookaheadRegExp.lastIndex; 470 } else w.output.appendChild(document.createTextNode(w.matchText)); 471 } 472}, 473 474// Any line prepended with 3 double quotes is interpreted as raw. 475// Unlike monospace, raw isn't really a "block" so consecutive pre-pended lines 476// will have no difference with a multi-line block. 477//SPEED: this can be like tiddly's termregexp syntax like a "Heading" 478{ 479 name: 't2tRawLine', 480 match: '^\\"\\"\\" ', 481 lookaheadRegExp: /^""" ((?:.)*?)$/mg, 482 handler: function(w) 483 { 484 this.lookaheadRegExp.lastIndex = w.matchStart; 485 var lookaheadMatch = this.lookaheadRegExp.exec(w.source); 486 if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { 487 createTiddlyElement(w.output,'span',null,null,lookaheadMatch[1]); 488 w.nextMatch = this.lookaheadRegExp.lastIndex; 489 } else w.output.appendChild(document.createTextNode(w.matchText)); 490 } 491}, 492 493// The in-line format uses 2 double quotes ""raw"". 494// The end of the line terminates raw if there is no matching "". 495{ 496 name: 't2tRaw', 497 match: '\\"\\"', 498 lookaheadRegExp: /""([^\s](|.*?[^\s])"*)""/mg, 499 handler: function(w) 500 { 501 this.lookaheadRegExp.lastIndex = w.matchStart; 502 var lookaheadMatch = this.lookaheadRegExp.exec(w.source); 503 if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { 504 createTiddlyElement(w.output,'span',null,null,lookaheadMatch[1]); 505 w.nextMatch = this.lookaheadRegExp.lastIndex; 506 } else w.output.appendChild(document.createTextNode(w.matchText)); 507 } 508}, 509 510// Section headings are bookended by matching sets of = signs. 511// It must all be on one line 512//SPEED: simplify match 513{ 514 name: 't2tHeading', 515 //no whitespace at the start 516 //match: '^ *={1,6}[^=\n]', 517 //lookaheadRegExp: /^ *(={1,6})([^=\n][^\n]*[^=\n])\1[ \t]*$/mg, 518 match: '^={1,6}[^ =\n]', 519 lookaheadRegExp: /^(={1,6})([^ =\n][^\n]*[^=\n])\1[ \t]*$/mg, 520 handler: function(w) 521 { 522 this.lookaheadRegExp.lastIndex = w.matchStart; 523 var lookaheadMatch = this.lookaheadRegExp.exec(w.source); 524 if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { 525 //headings in t2t don't allow markup inside, so we DO NOT use the subwikifyterm here. 526 createTiddlyElement(w.output,'h'+lookaheadMatch[1].length,null,null,lookaheadMatch[2]); 527 w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length; 528 } else w.output.appendChild(document.createTextNode(w.matchText)); 529 } 530}, 531 532/* 533//This breaks everything. T2T converts emails into mailto:s or it masks them: 534// dave@gmail.com --> <dave (AT) gmail dOT com> 535{ 536 name: 't2tEmailHiding', 537 match: '[\\w]+(\\.[\\w\\-\\+_]+)*\\@[\\w\\-\\+_]+\\.[\\w\\-\\+_]+(\\.[\\w\\-\\+_]+)*', 538 lookaheadRegExp: /([\w]+(?:\.[\w\-\+_]+)*)\@([\w\-\+_]+\.[\w\-\+_]+(?:\.[\w\-\+_]+)*)/mg, 539 handler: function(w) 540 { 541 this.lookaheadRegExp.lastIndex = w.matchStart; 542 var lookaheadMatch = this.lookaheadRegExp.exec(w.source); 543 if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { 544 var text = '<' + lookaheadMatch[1] + " (AT) " + lookaheadMatch[2] + '>'; 545 text = text.replace(/\./g," DOT "); 546 createTiddlyElement(w.output,"span",null,null,text); 547 w.nextMatch = this.lookaheadRegExp.lastIndex; 548 } 549 } 550}, 551*/ 552 553// push-pop version keeps the array sized to whatever it should be. This is 554// probably faster than the array reassignment (below this function) especially 555// in the simplest and more likely use case: only using top-level headings. 556// In practice, though, 10k numbered headings takes forever in BOTH cases. 557// HTML doesn't have an inherent number scheme for header tags. Just treat 558// them as unnumbered for now. 559// SPEED: simplify match. see what termregexp can do. 560{ 561 name: 't2tNumberedHeading', 562 //no whitespace at the start. 563 //match: '^ *\\+{1,6}[^\\+\\n]', 564 //lookaheadRegExp: /^ *(\+{1,6})([^\+\n][^\n]*[^\+\n])\1[ \t]*$/mg, 565 match: '^\\+{1,6}[^ \\+\\n]', 566 lookaheadRegExp: /^(\+{1,6})([^ \+\n][^\n]*[^\+\n])\1[ \t]*$/mg, 567 handler: function(w) 568 { 569 if (! w.numheading) { 570 w.numheading = [0,0]; 571 } 572 this.lookaheadRegExp.lastIndex = w.matchStart; 573 var lookaheadMatch = this.lookaheadRegExp.exec(w.source); 574 if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { 575 var text = lookaheadMatch[2]; 576 // since length=1 == arrayindex 0 577 var headingindex = lookaheadMatch[1].length - 1; 578 // since length1 means we want 2 items in the array 579 var targetlength = headingindex + 2; 580 //add or remove values until numheading.length = lookaheadMatch[1].length 581 //push 0's first to add 582 for (var i = w.numheading.length; i < targetlength; i++) 583 w.numheading.push(0); 584 //removing is eashy, you can just change length and it truncates array (garbage later) 585 w.numheading.length = targetlength; 586 //increment this heading 587 w.numheading[headingindex]++; 588 //reset the next level down to 0 589 w.numheading[headingindex + 1] = 0; 590 text = " " + text; 591 for (headingindex; headingindex >= 0; headingindex--) { 592 text = w.numheading[headingindex] + "." + text; 593 } 594 createTiddlyElement(w.output,'h'+lookaheadMatch[1].length,null,null,text); 595 w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length; 596 } else w.output.appendChild(document.createTextNode(w.matchText)); 597 } 598}, 599 600// t2t concatenates newlines to make paragraphs. 601// WARNING: tiddly doesn't support this very well; the appearance is 602// OK but the dynamic HTML has oddly-nested paragraphs. 603{ 604 name: 't2tParagraph', 605 match: '\\n{2,}', 606 handler: function(w) 607 { 608 //do you like stack overflows in your html engine? 609 //try making 200 paragraphs with this. 610 //createTiddlyElement(w.output,'p'); 611 612 //Looks ok-ish, but now you have manual BR's mixed in 613 //with the implied whitespace by an <h1> or <quote>. 614 //createTiddlyElement(w.output,'br'); 615 //createTiddlyElement(w.output,'br'); 616 617 //ohh this is so wrong to do, but it works pretty well. 618 //no stack explosions, and it looks visually correct. 619 createTiddlyElement(w.output,"span").innerHTML = "<p></p>"; 620 } 621}, 622 623{ 624 name: 't2tLinkImg', 625 match: '(?:^\\[)|(?:\\[)', 626 // ([^\n\r]*?) matches 2 separate entities: [foo] and [soft] 627 // ([^\n\r]*) matches entity: [(foo] and [soft)] 628 // use *? or include [] us unallowed chaaracters 629 lookaheadRegExp: /(?:(^\[)|(?:\[))(?:(\[([^\[\]\n\r\f]+)\] ?([^\n\r\[\]]*))|([^\s\[\]]+)|(([^\[\]\n\r\f]+) ([^\[\]\s]+)))(?:(\]$)|(?:\]))/mg, 630 handler: function(w) 631 { 632 this.lookaheadRegExp.lastIndex = w.matchStart; 633 var lookaheadMatch = this.lookaheadRegExp.exec(w.source); 634 if(lookaheadMatch && lookaheadMatch.index == w.matchStart) 635 { 636 //first and last group match for alignment to be used for images. 637 if (lookaheadMatch[1] && (! lookaheadMatch[9])) 638 { 639 var imagealign = "left"; 640 641 } 642 else if ( (! lookaheadMatch[1]) && lookaheadMatch[9]) 643 { 644 var imagealign = "right"; 645 } 646 //alignment discovered, now see what type of bracket link. 647 648 // [[image] link] 649 //2 = imglink; 3 img 4 link 650 if (lookaheadMatch[2]) 651 { 652 var e = w.output; 653 // 4 may not exist, it could just be an image formatted [[image]] 654 if (lookaheadMatch[4]) { 655 var link = lookaheadMatch[4]; 656 e = config.formatterHelpers.isExternalLink(link) ? 657 createExternalLink(w.output,link) : 658 createTiddlyLink(w.output,link,false,null,w.isStatic,w.tiddler); 659 addClass(e,"imageLink"); 660 } 661 var img = createTiddlyElement(e,"img"); 662 if (imagealign) img.align = imagealign; 663 img.src = lookaheadMatch[3]; 664 img.title = lookaheadMatch[4]; 665 img.setAttribute("alt",lookaheadMatch[4]); 666 w.nextMatch = this.lookaheadRegExp.lastIndex; 667 /* 668 if (align) 669 { 670 alert( align+"-ed image\nfile: '"+lookaheadMatch[3]+"'\nurl: '"+lookaheadMatch[4]+"'"); 671 } else { 672 alert( "unaligned image\nfile: '"+lookaheadMatch[3]+"'\nurl: '"+lookaheadMatch[4]+"'"); 673 } 674 */ 675 } 676 677 // [link] or [image] 678 //5 = url or img 679 else if (lookaheadMatch[5]) 680 { 681 // IMAGE-EXTENSION-REGEX 682 if (/\.((gif)|(je?pg)|(png)|(bmp)|(tif))$/i.exec(lookaheadMatch[5])) 683 { 684 //alert("image extension found"); 685 var e = w.output; 686 var img = createTiddlyElement(e,"img"); 687 if (imagealign) img.align = imagealign; 688 img.src = lookaheadMatch[5]; 689 img.title = lookaheadMatch[5]; 690 img.setAttribute("alt",lookaheadMatch[5]); 691 w.nextMatch = this.lookaheadRegExp.lastIndex; 692 /* 693 if (align) 694 { 695 alert( align+"-ed image\nfile: '"+lookaheadMatch[5]+"'"); 696 } else { 697 alert( "unaligned image\nfile: '"+lookaheadMatch[5]+"'"); 698 } 699 */ 700 } 701 else 702 { 703 //alert("no image extension found"); 704 //obviously this isn't an image by the extension, so it is just a link. 705 var link = lookaheadMatch[5]; 706 var e = (config.formatterHelpers.isExternalLink(link)) ? 707 createExternalLink(w.output,link) : 708 createTiddlyLink(w.output,link,false,null,w.isStatic,w.tiddler); 709 createTiddlyText(e,link); 710 w.nextMatch = this.lookaheadRegExp.lastIndex; 711 //alert("Simple link to url: '"+lookaheadMatch[5]+"'"); 712 } 713 } 714 // [some name text linkWithNoSpaces] the existence of a space is the key! 715 //6 named link 7 = name 8 = link 716 else if (lookaheadMatch[6]) 717 { 718 var text = lookaheadMatch[7]; 719 var link = lookaheadMatch[8]; 720 var e = (config.formatterHelpers.isExternalLink(link)) ? 721 createExternalLink(w.output,link) : 722 createTiddlyLink(w.output,link,false,null,w.isStatic,w.tiddler); 723 createTiddlyText(e,text); 724 w.nextMatch = this.lookaheadRegExp.lastIndex; 725 //alert( "name: '"+lookaheadMatch[8]+"'\nurl: '"+lookaheadMatch[9]+"'"); 726 } else w.output.appendChild(document.createTextNode(w.matchText)); 727 } else w.output.appendChild(document.createTextNode(w.matchText)); 728 } 729}, 730 731// COPY from tiddlywiki code 732{ 733 name: "t2tList", 734 match: "^(?:[ ]*[\\+-;:] )", 735 //lookaheadRegExp: /^(?:[ ]*(?:(-)|(\+)|(:)|( )) )/mg, 736 lookaheadRegExp: /^(?:[ ]*(?:(-)|(\+)|(;)|(:)) )/mg, 737 738 //http://stackoverflow.com/questions/5531899/regex-do-not-include-a-substring-within-a-group/5531972#5531972 739 // V~do include this if it matched 740 termRegExp: /(\n(?:(?=[ ]*[\+;:-] )|[ ]*[\+;:-]))/mg, 741 // ^~lookahead for this but don't include it 742 handler: function(w) 743 { 744 //if (! w.lengths) { 745 w.lengths = [0]; 746 //} 747 var stack = [w.output]; 748 var currLevel = 0, currType = null; 749 var listLevel, listType, itemType, baseType; 750 w.nextMatch = w.matchStart; 751 this.lookaheadRegExp.lastIndex = w.nextMatch; 752 var lookaheadMatch = this.lookaheadRegExp.exec(w.source); 753 while(lookaheadMatch && lookaheadMatch.index == w.nextMatch) { 754 if(lookaheadMatch[1]) { 755 listType = "ul"; 756 itemType = "li"; 757 } else if(lookaheadMatch[2]) { 758 listType = "ol"; 759 itemType = "li"; 760 } else if(lookaheadMatch[3]) { 761 listType = "dl"; 762 itemType = "dt"; 763 } else if(lookaheadMatch[4]) { 764 listType = "dl"; 765 itemType = "dd"; 766 } 767 if(!baseType) 768 baseType = listType; 769 //fill levelstack 770 var l = lookaheadMatch[0].length 771 while ( w.lengths[w.lengths.length-1] != l ) { 772 if ( l > w.lengths[w.lengths.length-1] ) { 773 w.lengths.push(l); 774 break; 775 } else { 776 w.lengths.pop(); 777 } 778 } 779 listLevel = w.lengths.length-1; 780 w.nextMatch += l; 781 var t; 782 if(listLevel > currLevel) { 783 for(t=currLevel; t<listLevel; t++) { 784 var target = (currLevel == 0) ? stack[stack.length-1] : stack[stack.length-1].lastChild; 785 stack.push(createTiddlyElement(target,listType)); 786 } 787 } else if(listType!=baseType && listLevel==1) { 788 w.nextMatch -= lookaheadMatch[0].length; 789 return; 790 } else if(listLevel < currLevel) { 791 for(t=currLevel; t>listLevel; t--) 792 stack.pop(); 793 } else if(listLevel == currLevel && listType != currType) { 794 stack.pop(); 795 stack.push(createTiddlyElement(stack[stack.length-1].lastChild,listType)); 796 } 797 currLevel = listLevel; 798 currType = listType; 799 var e = createTiddlyElement(stack[stack.length-1],itemType); 800 w.subWikifyTerm(e,this.termRegExp); 801 this.lookaheadRegExp.lastIndex = w.nextMatch; 802 lookaheadMatch = this.lookaheadRegExp.exec(w.source); 803 } 804 } 805}, 806 807/* 808//array reassignment version. I think that the up-to-6 assignments per iteration 809//could have worse performance that resizing the array. 810//see above for array re-sizing. 811// HTML doesn't have an inherent number scheme for header tags. Just treat 812// them as unnumbered for now. 813{ 814 name: 't2tNumberedHeading', 815 match: '^ *\\+{1,6}[^\\+\n]', 816 lookaheadRegExp: / *(\+{1,6})([^\+\n][^\n]*[^\+\n])\1[ \t]*$/mg, 817 handler: function(w) 818 { 819 if (! w.numheading) { 820 w.numheading = [0,0,0,0,0,0]; 821 } 822 this.lookaheadRegExp.lastIndex = w.matchStart; 823 var lookaheadMatch = this.lookaheadRegExp.exec(w.source); 824 if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { 825 var text = lookaheadMatch[2]; 826 var headingindex = lookaheadMatch[1].length - 1; 827 w.numheading[headingindex]++; 828 //reset the next levels down to 0 829 for(var i = headingindex + 1; i<=5; i++){ 830 w.numheading[i] = 0; 831 } 832 text = " " + text; 833 for (headingindex; headingindex >= 0; headingindex--) { 834 text = w.numheading[headingindex] + "." + text; 835 } 836 createTiddlyElement(w.output,'h'+lookaheadMatch[1].length,null,null,text); 837 w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length; 838 } else { 839 w.output.appendChild(document.createTextNode(w.matchText)); 840 } 841 } 842}, 843*/ 844 845// t2t prepends TABs on lines that form blockquotes. 846// Consecutive lines of the same depth of tabs are in the same block. 847// This is just like tiddly markup, only they use angle brackets. 848// Thus, I am ripping this code from a 2.6.1 formatters. 849{ 850 name: 't2tQuoteByLine', 851 match: '\\t+', 852 lookaheadRegExp: /^\t+/mg, 853 termRegExp: /(\n)/mg, 854 element: 'blockquote', 855 handler: function(w) 856 { 857 var stack = [w.output]; 858 var currLevel = 0; 859 var newLevel = w.matchLength; 860 var t; 861 do { 862 if(newLevel > currLevel) { 863 for(t=currLevel; t<newLevel; t++) 864 stack.push(createTiddlyElement(stack[stack.length-1],this.element)); 865 } else if(newLevel < currLevel) { 866 for(t=currLevel; t>newLevel; t--) 867 stack.pop(); 868 } 869 currLevel = newLevel; 870 w.subWikifyTerm(stack[stack.length-1],this.termRegExp); 871 //originally they insert linebreaks... not in t2t 872 //createTiddlyElement(stack[stack.length-1],'br'); 873 //replace the newline that was consumed 874 if(config.browser.isIE) { 875 var e = document.createTextNode('\r'); 876 } else { 877 var e = document.createTextNode('\n'); 878 } 879 stack[stack.length-1].appendChild(e); 880 this.lookaheadRegExp.lastIndex = w.nextMatch; 881 var lookaheadMatch = this.lookaheadRegExp.exec(w.source); 882 var matched = lookaheadMatch && lookaheadMatch.index == w.nextMatch; 883 if(matched) { 884 newLevel = lookaheadMatch[0].length; 885 w.nextMatch += lookaheadMatch[0].length; 886 } 887 } while(matched); 888 } 889}, 890 891/* 892//COPY from tiddlywiki config.formatters 893{ 894 name: "macro", 895 match: "<<", 896 ////don't start new macro << HERE 897 //lookaheadRegExp: /<<([^>\s(?:<<)]+)(?:\s*)((?:[^>]|(?:>(?!>)))*)>>/mg, 898 lookaheadRegExp: /<<([^>\s]+)(?:\s*)((?:[^>]|(?:>(?!>)))*)>>/mg, 899 handler: function(w) 900 { 901 this.lookaheadRegExp.lastIndex = w.matchStart; 902 var lookaheadMatch = this.lookaheadRegExp.exec(w.source); 903 if(lookaheadMatch && lookaheadMatch.index == w.matchStart && lookaheadMatch[1]) { 904 w.nextMatch = this.lookaheadRegExp.lastIndex; 905 invokeMacro(w.output,lookaheadMatch[1],lookaheadMatch[2],w,w.tiddler); 906 //with this modification for nondestructiveness. 907 } else { 908 w.output.appendChild(document.createTextNode(w.matchText)); 909 } 910 } 911}, 912*/ 913 914 915]; 916 917t2tReuse = function(name) 918{ 919 var i; 920 for (i = 0; i < config.formatters.length; i++) { 921 if (name == config.formatters[i].name) 922 return config.formatters[i]; 923 } 924 return null; 925 926}; 927 928//attach reused formatters from standard config.formatters. 929config.t2tFormatters.push(t2tReuse("macro")); 930config.t2tFormatters.push(t2tReuse("wikiLink")); 931config.t2tFormatters.push(t2tReuse("urlLink")); 932config.t2tFormatters.push(t2tReuse("htmlEntitiesEncoding")); 933//config.t2tFormatters.push(t2tReuse("mdash")); 934config.t2tFormatters.push(t2tReuse("table")); 935 936/* 937var text = "t2tFormatters:\n"; 938for (var i=0; i < config.t2tFormatters.length; i++) 939 text = text + config.t2tFormatters[i].name + "\n"; 940alert(text); 941*/ 942 943config.parsers.t2tFormatter = new Formatter(config.t2tFormatters); 944 945config.parsers.t2tFormatter.format = 't2t'; 946config.parsers.t2tFormatter.formatTag = 't2t'; 947} // end of 'install only once' 948//}}} 949/*** 950vim: ft=javascript 951***/ 952