spacedocs 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/README.md +6 -2
  2. data/{source → lib}/class.html.haml +1 -4
  3. data/{source → lib}/index.html.haml +2 -2
  4. data/{dox → lib/node_modules/dox}/History.md +0 -0
  5. data/{dox → lib/node_modules/dox}/Makefile +0 -0
  6. data/{dox → lib/node_modules/dox}/Readme.md +0 -0
  7. data/{dox → lib/node_modules/dox}/bin/dox +0 -0
  8. data/{dox → lib/node_modules/dox}/index.js +0 -0
  9. data/{dox → lib/node_modules/dox}/lib/dox.js +1 -10
  10. data/{dox → lib/node_modules/dox}/lib/utils.js +0 -0
  11. data/lib/node_modules/dox/node_modules/commander/History.md +99 -0
  12. data/lib/node_modules/dox/node_modules/commander/Makefile +7 -0
  13. data/lib/node_modules/dox/node_modules/commander/Readme.md +263 -0
  14. data/lib/node_modules/dox/node_modules/commander/index.js +2 -0
  15. data/lib/node_modules/dox/node_modules/commander/lib/commander.js +992 -0
  16. data/lib/node_modules/dox/node_modules/commander/package.json +38 -0
  17. data/lib/node_modules/dox/node_modules/github-flavored-markdown/README.md +17 -0
  18. data/lib/node_modules/dox/node_modules/github-flavored-markdown/_config.yml +3 -0
  19. data/lib/node_modules/dox/node_modules/github-flavored-markdown/_layouts/default.html +77 -0
  20. data/lib/node_modules/dox/node_modules/github-flavored-markdown/code.rb +67 -0
  21. data/lib/node_modules/dox/node_modules/github-flavored-markdown/images/gfm.png +0 -0
  22. data/lib/node_modules/dox/node_modules/github-flavored-markdown/index.md +78 -0
  23. data/lib/node_modules/dox/node_modules/github-flavored-markdown/package.json +27 -0
  24. data/lib/node_modules/dox/node_modules/github-flavored-markdown/preview.md +27 -0
  25. data/lib/node_modules/dox/node_modules/github-flavored-markdown/sample_content.html +169 -0
  26. data/lib/node_modules/dox/node_modules/github-flavored-markdown/scripts/preview.js +18 -0
  27. data/lib/node_modules/dox/node_modules/github-flavored-markdown/scripts/showdown.js +1414 -0
  28. data/lib/node_modules/dox/node_modules/github-flavored-markdown/stylesheets/screen.css +20 -0
  29. data/lib/node_modules/dox/package.json +43 -0
  30. data/lib/spacedocs.rb +42 -53
  31. data/lib/{assets/stylesheets/spacedocs/docs.css.sass → spacedocs.sass} +0 -0
  32. data/lib/spacedocs/version.rb +1 -1
  33. metadata +116 -25
  34. data/dox/package.json +0 -16
  35. data/dox/test/dox.test.js +0 -287
  36. data/dox/test/fixtures/a.js +0 -12
  37. data/dox/test/fixtures/b.js +0 -26
  38. data/dox/test/fixtures/c.js +0 -266
  39. data/dox/test/fixtures/d.js +0 -15
  40. data/dox/test/fixtures/titles.js +0 -14
  41. data/lib/spacedocs/engine.rb +0 -6
@@ -0,0 +1,18 @@
1
+ $(function() {
2
+ var converter = new Showdown.converter();
3
+ $("#user_input").keyup(function(){
4
+ var txt = $("#user_input").val();
5
+ var html = converter.makeHtml(txt);
6
+ $("#result").html(html)
7
+ $("#html_result").val(html.replace(/>/g, ">\n").replace(/</g, "\n<").replace(/\n{2,}/g, "\n\n"));
8
+ });
9
+
10
+ var sample = "#### Underscores\nthis should have _emphasis_\nthis_should_not\n_nor_should_this\n\n\
11
+ #### Autolinking\na non-markdown link: http://github.com/blog\nthis one is [a markdown link](http://github.com/blog)\nEmail test: support@github.com\n\n\
12
+ #### Commit links\nc4149e7bac80fcd1295060125670e78d3f15bf2e\ntekkub@c4149e7bac80fcd1295060125670e78d3f15bf2e\nmojombo/god@c4149e7bac80fcd1295060125670e78d3f15bf2e\n\n\
13
+ #### Issue links\nissue #1\ntekkub#1\nmojombo/god#1";
14
+ $("#user_input").text(sample);
15
+ var html = converter.makeHtml(sample);
16
+ $("#result").html(html);
17
+ $("#html_result").val(html.replace(/>/g, ">\n").replace(/</g, "\n<").replace(/\n{2,}/g, "\n\n"));
18
+ });
@@ -0,0 +1,1414 @@
1
+ //
2
+ // showdown.js -- A javascript port of Markdown.
3
+ //
4
+ // Copyright (c) 2007 John Fraser.
5
+ //
6
+ // Original Markdown Copyright (c) 2004-2005 John Gruber
7
+ // <http://daringfireball.net/projects/markdown/>
8
+ //
9
+ // Redistributable under a BSD-style open source license.
10
+ // See license.txt for more information.
11
+ //
12
+ // The full source distribution is at:
13
+ //
14
+ // A A L
15
+ // T C A
16
+ // T K B
17
+ //
18
+ // <http://www.attacklab.net/>
19
+ //
20
+
21
+ //
22
+ // Wherever possible, Showdown is a straight, line-by-line port
23
+ // of the Perl version of Markdown.
24
+ //
25
+ // This is not a normal parser design; it's basically just a
26
+ // series of string substitutions. It's hard to read and
27
+ // maintain this way, but keeping Showdown close to the original
28
+ // design makes it easier to port new features.
29
+ //
30
+ // More importantly, Showdown behaves like markdown.pl in most
31
+ // edge cases. So web applications can do client-side preview
32
+ // in Javascript, and then build identical HTML on the server.
33
+ //
34
+ // This port needs the new RegExp functionality of ECMA 262,
35
+ // 3rd Edition (i.e. Javascript 1.5). Most modern web browsers
36
+ // should do fine. Even with the new regular expression features,
37
+ // We do a lot of work to emulate Perl's regex functionality.
38
+ // The tricky changes in this file mostly have the "attacklab:"
39
+ // label. Major or self-explanatory changes don't.
40
+ //
41
+ // Smart diff tools like Araxis Merge will be able to match up
42
+ // this file with markdown.pl in a useful way. A little tweaking
43
+ // helps: in a copy of markdown.pl, replace "#" with "//" and
44
+ // replace "$text" with "text". Be sure to ignore whitespace
45
+ // and line endings.
46
+ //
47
+
48
+
49
+ //
50
+ // Showdown usage:
51
+ //
52
+ // var text = "Markdown *rocks*.";
53
+ //
54
+ // var converter = new Showdown.converter();
55
+ // var html = converter.makeHtml(text);
56
+ //
57
+ // alert(html);
58
+ //
59
+ // Note: move the sample code to the bottom of this
60
+ // file before uncommenting it.
61
+ //
62
+
63
+
64
+ // **************************************************
65
+ // GitHub Flavored Markdown modifications by Tekkub
66
+ // http://github.github.com/github-flavored-markdown/
67
+ //
68
+ // Modifications are tagged with "GFM"
69
+ // **************************************************
70
+
71
+ // **************************************************
72
+ // Node.JS port by Isaac Z. Schlueter
73
+ //
74
+ // Modifications are tagged with "isaacs"
75
+ // **************************************************
76
+
77
+ //
78
+ // Showdown namespace
79
+ //
80
+ var Showdown = {};
81
+
82
+ //
83
+ // isaacs: export the Showdown object
84
+ //
85
+ if (typeof exports === "object") {
86
+ Showdown = exports;
87
+ // isaacs: expose top-level parse() method, like other to-html parsers.
88
+ Showdown.parse = function (md, gh) {
89
+ var converter = new Showdown.converter();
90
+ return converter.makeHtml(md, gh);
91
+ };
92
+ }
93
+
94
+ //
95
+ // isaacs: Declare "GitHub" object in here, since Node modules
96
+ // execute in a closure or separate context, rather than right
97
+ // in the global scope. If in the browser, this does nothing.
98
+ //
99
+ var GitHub;
100
+
101
+ //
102
+ // converter
103
+ //
104
+ // Wraps all "globals" so that the only thing
105
+ // exposed is makeHtml().
106
+ //
107
+ Showdown.converter = function() {
108
+
109
+ //
110
+ // Globals:
111
+ //
112
+
113
+ // Global hashes, used by various utility routines
114
+ var g_urls;
115
+ var g_titles;
116
+ var g_html_blocks;
117
+
118
+ // Used to track when we're inside an ordered or unordered list
119
+ // (see _ProcessListItems() for details):
120
+ var g_list_level = 0;
121
+
122
+ // isaacs - Allow passing in the GitHub object as an argument.
123
+ this.makeHtml = function(text, gh) {
124
+ if (typeof gh !== "undefined") {
125
+ if (typeof gh === "string") gh = {nameWithOwner:gh};
126
+ GitHub = gh;
127
+ }
128
+
129
+ //
130
+ // Main function. The order in which other subs are called here is
131
+ // essential. Link and image substitutions need to happen before
132
+ // _EscapeSpecialCharsWithinTagAttributes(), so that any *'s or _'s in the <a>
133
+ // and <img> tags get encoded.
134
+ //
135
+
136
+ // Clear the global hashes. If we don't clear these, you get conflicts
137
+ // from other articles when generating a page which contains more than
138
+ // one article (e.g. an index page that shows the N most recent
139
+ // articles):
140
+ g_urls = new Array();
141
+ g_titles = new Array();
142
+ g_html_blocks = new Array();
143
+
144
+ // attacklab: Replace ~ with ~T
145
+ // This lets us use tilde as an escape char to avoid md5 hashes
146
+ // The choice of character is arbitray; anything that isn't
147
+ // magic in Markdown will work.
148
+ text = text.replace(/~/g,"~T");
149
+
150
+ // attacklab: Replace $ with ~D
151
+ // RegExp interprets $ as a special character
152
+ // when it's in a replacement string
153
+ text = text.replace(/\$/g,"~D");
154
+
155
+ // Standardize line endings
156
+ text = text.replace(/\r\n/g,"\n"); // DOS to Unix
157
+ text = text.replace(/\r/g,"\n"); // Mac to Unix
158
+
159
+ // Make sure text begins and ends with a couple of newlines:
160
+ text = "\n\n" + text + "\n\n";
161
+
162
+ // Convert all tabs to spaces.
163
+ text = _Detab(text);
164
+
165
+ // Strip any lines consisting only of spaces and tabs.
166
+ // This makes subsequent regexen easier to write, because we can
167
+ // match consecutive blank lines with /\n+/ instead of something
168
+ // contorted like /[ \t]*\n+/ .
169
+ text = text.replace(/^[ \t]+$/mg,"");
170
+
171
+ // Turn block-level HTML blocks into hash entries
172
+ text = _HashHTMLBlocks(text);
173
+
174
+ // Strip link definitions, store in hashes.
175
+ text = _StripLinkDefinitions(text);
176
+
177
+ text = _RunBlockGamut(text);
178
+
179
+ text = _UnescapeSpecialChars(text);
180
+
181
+ // attacklab: Restore dollar signs
182
+ text = text.replace(/~D/g,"$$");
183
+
184
+ // attacklab: Restore tildes
185
+ text = text.replace(/~T/g,"~");
186
+
187
+ // ** GFM ** Auto-link URLs and emails
188
+ text = text.replace(/https?\:\/\/[^"\s\<\>]*[^.,;'">\:\s\<\>\)\]\!]/g, function(wholeMatch,matchIndex){
189
+ var left = text.slice(0, matchIndex), right = text.slice(matchIndex)
190
+ if (left.match(/<[^>]+$/) && right.match(/^[^>]*>/)) {return wholeMatch}
191
+ return "<a href='" + wholeMatch + "'>" + wholeMatch + "</a>";
192
+ });
193
+ text = text.replace(/[a-z0-9_\-+=.]+@[a-z0-9\-]+(\.[a-z0-9-]+)+/ig, function(wholeMatch){return "<a href='mailto:" + wholeMatch + "'>" + wholeMatch + "</a>";});
194
+
195
+ // ** GFM ** Auto-link sha1 if GitHub.nameWithOwner is defined
196
+ text = text.replace(/[a-f0-9]{40}/ig, function(wholeMatch,matchIndex){
197
+ if (typeof(GitHub) == "undefined" || typeof(GitHub.nameWithOwner) == "undefined") {return wholeMatch;}
198
+ var left = text.slice(0, matchIndex), right = text.slice(matchIndex)
199
+ if (left.match(/@$/) || (left.match(/<[^>]+$/) && right.match(/^[^>]*>/))) {return wholeMatch;}
200
+ return "<a href='http://github.com/" + GitHub.nameWithOwner + "/commit/" + wholeMatch + "'>" + wholeMatch.substring(0,7) + "</a>";
201
+ });
202
+
203
+ // ** GFM ** Auto-link user@sha1 if GitHub.nameWithOwner is defined
204
+ text = text.replace(/([a-z0-9_\-+=.]+)@([a-f0-9]{40})/ig, function(wholeMatch,username,sha,matchIndex){
205
+ if (typeof(GitHub) == "undefined" || typeof(GitHub.nameWithOwner) == "undefined") {return wholeMatch;}
206
+ GitHub.repoName = GitHub.repoName || _GetRepoName()
207
+ var left = text.slice(0, matchIndex), right = text.slice(matchIndex)
208
+ if (left.match(/\/$/) || (left.match(/<[^>]+$/) && right.match(/^[^>]*>/))) {return wholeMatch;}
209
+ return "<a href='http://github.com/" + username + "/" + GitHub.repoName + "/commit/" + sha + "'>" + username + "@" + sha.substring(0,7) + "</a>";
210
+ });
211
+
212
+ // ** GFM ** Auto-link user/repo@sha1
213
+ text = text.replace(/([a-z0-9_\-+=.]+\/[a-z0-9_\-+=.]+)@([a-f0-9]{40})/ig, function(wholeMatch,repo,sha){
214
+ return "<a href='http://github.com/" + repo + "/commit/" + sha + "'>" + repo + "@" + sha.substring(0,7) + "</a>";
215
+ });
216
+
217
+ // ** GFM ** Auto-link #issue if GitHub.nameWithOwner is defined
218
+ text = text.replace(/#([0-9]+)/ig, function(wholeMatch,issue,matchIndex){
219
+ if (typeof(GitHub) == "undefined" || typeof(GitHub.nameWithOwner) == "undefined") {return wholeMatch;}
220
+ var left = text.slice(0, matchIndex), right = text.slice(matchIndex)
221
+ if (left == "" || left.match(/[a-z0-9_\-+=.]$/) || (left.match(/<[^>]+$/) && right.match(/^[^>]*>/))) {return wholeMatch;}
222
+ return "<a href='http://github.com/" + GitHub.nameWithOwner + "/issues/#issue/" + issue + "'>" + wholeMatch + "</a>";
223
+ });
224
+
225
+ // ** GFM ** Auto-link user#issue if GitHub.nameWithOwner is defined
226
+ text = text.replace(/([a-z0-9_\-+=.]+)#([0-9]+)/ig, function(wholeMatch,username,issue,matchIndex){
227
+ if (typeof(GitHub) == "undefined" || typeof(GitHub.nameWithOwner) == "undefined") {return wholeMatch;}
228
+ GitHub.repoName = GitHub.repoName || _GetRepoName()
229
+ var left = text.slice(0, matchIndex), right = text.slice(matchIndex)
230
+ if (left.match(/\/$/) || (left.match(/<[^>]+$/) && right.match(/^[^>]*>/))) {return wholeMatch;}
231
+ return "<a href='http://github.com/" + username + "/" + GitHub.repoName + "/issues/#issue/" + issue + "'>" + wholeMatch + "</a>";
232
+ });
233
+
234
+ // ** GFM ** Auto-link user/repo#issue
235
+ text = text.replace(/([a-z0-9_\-+=.]+\/[a-z0-9_\-+=.]+)#([0-9]+)/ig, function(wholeMatch,repo,issue){
236
+ return "<a href='http://github.com/" + repo + "/issues/#issue/" + issue + "'>" + wholeMatch + "</a>";
237
+ });
238
+
239
+ return text;
240
+ }
241
+
242
+
243
+ var _GetRepoName = function() {
244
+ return GitHub.nameWithOwner.match(/^.+\/(.+)$/)[1]
245
+ }
246
+
247
+ var _StripLinkDefinitions = function(text) {
248
+ //
249
+ // Strips link definitions from text, stores the URLs and titles in
250
+ // hash references.
251
+ //
252
+
253
+ // Link defs are in the form: ^[id]: url "optional title"
254
+
255
+ /*
256
+ var text = text.replace(/
257
+ ^[ ]{0,3}\[(.+)\]: // id = $1 attacklab: g_tab_width - 1
258
+ [ \t]*
259
+ \n? // maybe *one* newline
260
+ [ \t]*
261
+ <?(\S+?)>? // url = $2
262
+ [ \t]*
263
+ \n? // maybe one newline
264
+ [ \t]*
265
+ (?:
266
+ (\n*) // any lines skipped = $3 attacklab: lookbehind removed
267
+ ["(]
268
+ (.+?) // title = $4
269
+ [")]
270
+ [ \t]*
271
+ )? // title is optional
272
+ (?:\n+|$)
273
+ /gm,
274
+ function(){...});
275
+ */
276
+ var text = text.replace(/^[ ]{0,3}\[(.+)\]:[ \t]*\n?[ \t]*<?(\S+?)>?[ \t]*\n?[ \t]*(?:(\n*)["(](.+?)[")][ \t]*)?(?:\n+|\Z)/gm,
277
+ function (wholeMatch,m1,m2,m3,m4) {
278
+ m1 = m1.toLowerCase();
279
+ g_urls[m1] = _EncodeAmpsAndAngles(m2); // Link IDs are case-insensitive
280
+ if (m3) {
281
+ // Oops, found blank lines, so it's not a title.
282
+ // Put back the parenthetical statement we stole.
283
+ return m3+m4;
284
+ } else if (m4) {
285
+ g_titles[m1] = m4.replace(/"/g,"&quot;");
286
+ }
287
+
288
+ // Completely remove the definition from the text
289
+ return "";
290
+ }
291
+ );
292
+
293
+ return text;
294
+ }
295
+
296
+
297
+ var _HashHTMLBlocks = function(text) {
298
+ // attacklab: Double up blank lines to reduce lookaround
299
+ text = text.replace(/\n/g,"\n\n");
300
+
301
+ // Hashify HTML blocks:
302
+ // We only want to do this for block-level HTML tags, such as headers,
303
+ // lists, and tables. That's because we still want to wrap <p>s around
304
+ // "paragraphs" that are wrapped in non-block-level tags, such as anchors,
305
+ // phrase emphasis, and spans. The list of tags we're looking for is
306
+ // hard-coded:
307
+ var block_tags_a = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del"
308
+ var block_tags_b = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math"
309
+
310
+ // First, look for nested blocks, e.g.:
311
+ // <div>
312
+ // <div>
313
+ // tags for inner block must be indented.
314
+ // </div>
315
+ // </div>
316
+ //
317
+ // The outermost tags must start at the left margin for this to match, and
318
+ // the inner nested divs must be indented.
319
+ // We need to do this before the next, more liberal match, because the next
320
+ // match will start at the first `<div>` and stop at the first `</div>`.
321
+
322
+ // attacklab: This regex can be expensive when it fails.
323
+ /*
324
+ var text = text.replace(/
325
+ ( // save in $1
326
+ ^ // start of line (with /m)
327
+ <($block_tags_a) // start tag = $2
328
+ \b // word break
329
+ // attacklab: hack around khtml/pcre bug...
330
+ [^\r]*?\n // any number of lines, minimally matching
331
+ </\2> // the matching end tag
332
+ [ \t]* // trailing spaces/tabs
333
+ (?=\n+) // followed by a newline
334
+ ) // attacklab: there are sentinel newlines at end of document
335
+ /gm,function(){...}};
336
+ */
337
+ text = text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)\b[^\r]*?\n<\/\2>[ \t]*(?=\n+))/gm,hashElement);
338
+
339
+ //
340
+ // Now match more liberally, simply from `\n<tag>` to `</tag>\n`
341
+ //
342
+
343
+ /*
344
+ var text = text.replace(/
345
+ ( // save in $1
346
+ ^ // start of line (with /m)
347
+ <($block_tags_b) // start tag = $2
348
+ \b // word break
349
+ // attacklab: hack around khtml/pcre bug...
350
+ [^\r]*? // any number of lines, minimally matching
351
+ .*</\2> // the matching end tag
352
+ [ \t]* // trailing spaces/tabs
353
+ (?=\n+) // followed by a newline
354
+ ) // attacklab: there are sentinel newlines at end of document
355
+ /gm,function(){...}};
356
+ */
357
+ text = text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math)\b[^\r]*?.*<\/\2>[ \t]*(?=\n+)\n)/gm,hashElement);
358
+
359
+ // Special case just for <hr />. It was easier to make a special case than
360
+ // to make the other regex more complicated.
361
+
362
+ /*
363
+ text = text.replace(/
364
+ ( // save in $1
365
+ \n\n // Starting after a blank line
366
+ [ ]{0,3}
367
+ (<(hr) // start tag = $2
368
+ \b // word break
369
+ ([^<>])*? //
370
+ \/?>) // the matching end tag
371
+ [ \t]*
372
+ (?=\n{2,}) // followed by a blank line
373
+ )
374
+ /g,hashElement);
375
+ */
376
+ text = text.replace(/(\n[ ]{0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,hashElement);
377
+
378
+ // Special case for standalone HTML comments:
379
+
380
+ /*
381
+ text = text.replace(/
382
+ ( // save in $1
383
+ \n\n // Starting after a blank line
384
+ [ ]{0,3} // attacklab: g_tab_width - 1
385
+ <!
386
+ (--[^\r]*?--\s*)+
387
+ >
388
+ [ \t]*
389
+ (?=\n{2,}) // followed by a blank line
390
+ )
391
+ /g,hashElement);
392
+ */
393
+ text = text.replace(/(\n\n[ ]{0,3}<!(--[^\r]*?--\s*)+>[ \t]*(?=\n{2,}))/g,hashElement);
394
+
395
+ // PHP and ASP-style processor instructions (<?...?> and <%...%>)
396
+
397
+ /*
398
+ text = text.replace(/
399
+ (?:
400
+ \n\n // Starting after a blank line
401
+ )
402
+ ( // save in $1
403
+ [ ]{0,3} // attacklab: g_tab_width - 1
404
+ (?:
405
+ <([?%]) // $2
406
+ [^\r]*?
407
+ \2>
408
+ )
409
+ [ \t]*
410
+ (?=\n{2,}) // followed by a blank line
411
+ )
412
+ /g,hashElement);
413
+ */
414
+ text = text.replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,hashElement);
415
+
416
+ // attacklab: Undo double lines (see comment at top of this function)
417
+ text = text.replace(/\n\n/g,"\n");
418
+ return text;
419
+ }
420
+
421
+ var hashElement = function(wholeMatch,m1) {
422
+ var blockText = m1;
423
+
424
+ // Undo double lines
425
+ blockText = blockText.replace(/\n\n/g,"\n");
426
+ blockText = blockText.replace(/^\n/,"");
427
+
428
+ // strip trailing blank lines
429
+ blockText = blockText.replace(/\n+$/g,"");
430
+
431
+ // Replace the element text with a marker ("~KxK" where x is its key)
432
+ blockText = "\n\n~K" + (g_html_blocks.push(blockText)-1) + "K\n\n";
433
+
434
+ return blockText;
435
+ };
436
+
437
+ var _RunBlockGamut = function(text) {
438
+ //
439
+ // These are all the transformations that form block-level
440
+ // tags like paragraphs, headers, and list items.
441
+ //
442
+ text = _DoHeaders(text);
443
+
444
+ // Do Horizontal Rules:
445
+ var key = hashBlock("<hr />");
446
+ text = text.replace(/^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$/gm,key);
447
+ text = text.replace(/^[ ]{0,2}([ ]?\-[ ]?){3,}[ \t]*$/gm,key);
448
+ text = text.replace(/^[ ]{0,2}([ ]?\_[ ]?){3,}[ \t]*$/gm,key);
449
+
450
+ text = _DoLists(text);
451
+ text = _DoCodeFencing(text);
452
+ text = _DoCodeBlocks(text);
453
+ text = _DoBlockQuotes(text);
454
+
455
+ // We already ran _HashHTMLBlocks() before, in Markdown(), but that
456
+ // was to escape raw HTML in the original Markdown source. This time,
457
+ // we're escaping the markup we've just created, so that we don't wrap
458
+ // <p> tags around block-level tags.
459
+ text = _HashHTMLBlocks(text);
460
+ text = _FormParagraphs(text);
461
+
462
+ return text;
463
+ }
464
+
465
+
466
+ var _RunSpanGamut = function(text) {
467
+ //
468
+ // These are all the transformations that occur *within* block-level
469
+ // tags like paragraphs, headers, and list items.
470
+ //
471
+
472
+ text = _DoCodeSpans(text);
473
+ text = _EscapeSpecialCharsWithinTagAttributes(text);
474
+ text = _EncodeBackslashEscapes(text);
475
+
476
+ // Process anchor and image tags. Images must come first,
477
+ // because ![foo][f] looks like an anchor.
478
+ text = _DoImages(text);
479
+ text = _DoAnchors(text);
480
+
481
+ // Make links out of things like `<http://example.com/>`
482
+ // Must come after _DoAnchors(), because you can use < and >
483
+ // delimiters in inline links like [this](<url>).
484
+ text = _DoAutoLinks(text);
485
+ text = _EncodeAmpsAndAngles(text);
486
+ text = _DoItalicsAndBold(text);
487
+
488
+ // Do hard breaks:
489
+ text = text.replace(/ +\n/g," <br />\n");
490
+
491
+ return text;
492
+ }
493
+
494
+ var _EscapeSpecialCharsWithinTagAttributes = function(text) {
495
+ //
496
+ // Within tags -- meaning between < and > -- encode [\ ` * _] so they
497
+ // don't conflict with their use in Markdown for code, italics and strong.
498
+ //
499
+
500
+ // Build a regex to find HTML tags and comments. See Friedl's
501
+ // "Mastering Regular Expressions", 2nd Ed., pp. 200-201.
502
+ var regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|<!(--.*?--\s*)+>)/gi;
503
+
504
+ text = text.replace(regex, function(wholeMatch) {
505
+ var tag = wholeMatch.replace(/(.)<\/?code>(?=.)/g,"$1`");
506
+ tag = escapeCharacters(tag,"\\`*_");
507
+ return tag;
508
+ });
509
+
510
+ return text;
511
+ }
512
+
513
+ var _DoAnchors = function(text) {
514
+ //
515
+ // Turn Markdown link shortcuts into XHTML <a> tags.
516
+ //
517
+ //
518
+ // First, handle reference-style links: [link text] [id]
519
+ //
520
+
521
+ /*
522
+ text = text.replace(/
523
+ ( // wrap whole match in $1
524
+ \[
525
+ (
526
+ (?:
527
+ \[[^\]]*\] // allow brackets nested one level
528
+ |
529
+ [^\[] // or anything else
530
+ )*
531
+ )
532
+ \]
533
+
534
+ [ ]? // one optional space
535
+ (?:\n[ ]*)? // one optional newline followed by spaces
536
+
537
+ \[
538
+ (.*?) // id = $3
539
+ \]
540
+ )()()()() // pad remaining backreferences
541
+ /g,_DoAnchors_callback);
542
+ */
543
+ text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,writeAnchorTag);
544
+
545
+ //
546
+ // Next, inline-style links: [link text](url "optional title")
547
+ //
548
+
549
+ /*
550
+ text = text.replace(/
551
+ ( // wrap whole match in $1
552
+ \[
553
+ (
554
+ (?:
555
+ \[[^\]]*\] // allow brackets nested one level
556
+ |
557
+ [^\[\]] // or anything else
558
+ )
559
+ )
560
+ \]
561
+ \( // literal paren
562
+ [ \t]*
563
+ () // no id, so leave $3 empty
564
+ <?(.*?)>? // href = $4
565
+ [ \t]*
566
+ ( // $5
567
+ (['"]) // quote char = $6
568
+ (.*?) // Title = $7
569
+ \6 // matching quote
570
+ [ \t]* // ignore any spaces/tabs between closing quote and )
571
+ )? // title is optional
572
+ \)
573
+ )
574
+ /g,writeAnchorTag);
575
+ */
576
+ text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()<?(.*?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,writeAnchorTag);
577
+
578
+ //
579
+ // Last, handle reference-style shortcuts: [link text]
580
+ // These must come last in case you've also got [link test][1]
581
+ // or [link test](/foo)
582
+ //
583
+
584
+ /*
585
+ text = text.replace(/
586
+ ( // wrap whole match in $1
587
+ \[
588
+ ([^\[\]]+) // link text = $2; can't contain '[' or ']'
589
+ \]
590
+ )()()()()() // pad rest of backreferences
591
+ /g, writeAnchorTag);
592
+ */
593
+ text = text.replace(/(\[([^\[\]]+)\])()()()()()/g, writeAnchorTag);
594
+
595
+ return text;
596
+ }
597
+
598
+ var writeAnchorTag = function(wholeMatch,m1,m2,m3,m4,m5,m6,m7) {
599
+ if (m7 == undefined) m7 = "";
600
+ var whole_match = m1;
601
+ var link_text = m2;
602
+ var link_id = m3.toLowerCase();
603
+ var url = m4;
604
+ var title = m7;
605
+
606
+ if (url == "") {
607
+ if (link_id == "") {
608
+ // lower-case and turn embedded newlines into spaces
609
+ link_id = link_text.toLowerCase().replace(/ ?\n/g," ");
610
+ }
611
+ url = "#"+link_id;
612
+
613
+ if (g_urls[link_id] != undefined) {
614
+ url = g_urls[link_id];
615
+ if (g_titles[link_id] != undefined) {
616
+ title = g_titles[link_id];
617
+ }
618
+ }
619
+ else {
620
+ if (whole_match.search(/\(\s*\)$/m)>-1) {
621
+ // Special case for explicit empty url
622
+ url = "";
623
+ } else {
624
+ return whole_match;
625
+ }
626
+ }
627
+ }
628
+
629
+ url = escapeCharacters(url,"*_");
630
+ var result = "<a href=\"" + url + "\"";
631
+
632
+ if (title != "") {
633
+ title = title.replace(/"/g,"&quot;");
634
+ title = escapeCharacters(title,"*_");
635
+ result += " title=\"" + title + "\"";
636
+ }
637
+
638
+ result += ">" + link_text + "</a>";
639
+
640
+ return result;
641
+ }
642
+
643
+
644
+ var _DoImages = function(text) {
645
+ //
646
+ // Turn Markdown image shortcuts into <img> tags.
647
+ //
648
+
649
+ //
650
+ // First, handle reference-style labeled images: ![alt text][id]
651
+ //
652
+
653
+ /*
654
+ text = text.replace(/
655
+ ( // wrap whole match in $1
656
+ !\[
657
+ (.*?) // alt text = $2
658
+ \]
659
+
660
+ [ ]? // one optional space
661
+ (?:\n[ ]*)? // one optional newline followed by spaces
662
+
663
+ \[
664
+ (.*?) // id = $3
665
+ \]
666
+ )()()()() // pad rest of backreferences
667
+ /g,writeImageTag);
668
+ */
669
+ text = text.replace(/(!\[(.*?)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,writeImageTag);
670
+
671
+ //
672
+ // Next, handle inline images: ![alt text](url "optional title")
673
+ // Don't forget: encode * and _
674
+
675
+ /*
676
+ text = text.replace(/
677
+ ( // wrap whole match in $1
678
+ !\[
679
+ (.*?) // alt text = $2
680
+ \]
681
+ \s? // One optional whitespace character
682
+ \( // literal paren
683
+ [ \t]*
684
+ () // no id, so leave $3 empty
685
+ <?(\S+?)>? // src url = $4
686
+ [ \t]*
687
+ ( // $5
688
+ (['"]) // quote char = $6
689
+ (.*?) // title = $7
690
+ \6 // matching quote
691
+ [ \t]*
692
+ )? // title is optional
693
+ \)
694
+ )
695
+ /g,writeImageTag);
696
+ */
697
+ text = text.replace(/(!\[(.*?)\]\s?\([ \t]*()<?(\S+?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,writeImageTag);
698
+
699
+ return text;
700
+ }
701
+
702
+ var writeImageTag = function(wholeMatch,m1,m2,m3,m4,m5,m6,m7) {
703
+ var whole_match = m1;
704
+ var alt_text = m2;
705
+ var link_id = m3.toLowerCase();
706
+ var url = m4;
707
+ var title = m7;
708
+
709
+ if (!title) title = "";
710
+
711
+ if (url == "") {
712
+ if (link_id == "") {
713
+ // lower-case and turn embedded newlines into spaces
714
+ link_id = alt_text.toLowerCase().replace(/ ?\n/g," ");
715
+ }
716
+ url = "#"+link_id;
717
+
718
+ if (g_urls[link_id] != undefined) {
719
+ url = g_urls[link_id];
720
+ if (g_titles[link_id] != undefined) {
721
+ title = g_titles[link_id];
722
+ }
723
+ }
724
+ else {
725
+ return whole_match;
726
+ }
727
+ }
728
+
729
+ alt_text = alt_text.replace(/"/g,"&quot;");
730
+ url = escapeCharacters(url,"*_");
731
+ var result = "<img src=\"" + url + "\" alt=\"" + alt_text + "\"";
732
+
733
+ // attacklab: Markdown.pl adds empty title attributes to images.
734
+ // Replicate this bug.
735
+
736
+ //if (title != "") {
737
+ title = title.replace(/"/g,"&quot;");
738
+ title = escapeCharacters(title,"*_");
739
+ result += " title=\"" + title + "\"";
740
+ //}
741
+
742
+ result += " />";
743
+
744
+ return result;
745
+ }
746
+
747
+
748
+ var _DoHeaders = function(text) {
749
+
750
+ // Setext-style headers:
751
+ // Header 1
752
+ // ========
753
+ //
754
+ // Header 2
755
+ // --------
756
+ //
757
+ text = text.replace(/^(.+)[ \t]*\n=+[ \t]*\n+/gm,
758
+ function(wholeMatch,m1){return hashBlock("<h1>" + _RunSpanGamut(m1) + "</h1>");});
759
+
760
+ text = text.replace(/^(.+)[ \t]*\n-+[ \t]*\n+/gm,
761
+ function(matchFound,m1){return hashBlock("<h2>" + _RunSpanGamut(m1) + "</h2>");});
762
+
763
+ // atx-style headers:
764
+ // # Header 1
765
+ // ## Header 2
766
+ // ## Header 2 with closing hashes ##
767
+ // ...
768
+ // ###### Header 6
769
+ //
770
+
771
+ /*
772
+ text = text.replace(/
773
+ ^(\#{1,6}) // $1 = string of #'s
774
+ [ \t]*
775
+ (.+?) // $2 = Header text
776
+ [ \t]*
777
+ \#* // optional closing #'s (not counted)
778
+ \n+
779
+ /gm, function() {...});
780
+ */
781
+
782
+ text = text.replace(/^(\#{1,6})[ \t]*(.+?)[ \t]*\#*\n+/gm,
783
+ function(wholeMatch,m1,m2) {
784
+ var h_level = m1.length;
785
+ return hashBlock("<h" + h_level + ">" + _RunSpanGamut(m2) + "</h" + h_level + ">");
786
+ });
787
+
788
+ return text;
789
+ }
790
+
791
+ // This declaration keeps Dojo compressor from outputting garbage:
792
+ var _ProcessListItems;
793
+
794
+ var _DoLists = function(text) {
795
+ //
796
+ // Form HTML ordered (numbered) and unordered (bulleted) lists.
797
+ //
798
+
799
+ // attacklab: add sentinel to hack around khtml/safari bug:
800
+ // http://bugs.webkit.org/show_bug.cgi?id=11231
801
+ text += "~0";
802
+
803
+ // Re-usable pattern to match any entirel ul or ol list:
804
+
805
+ /*
806
+ var whole_list = /
807
+ ( // $1 = whole list
808
+ ( // $2
809
+ [ ]{0,3} // attacklab: g_tab_width - 1
810
+ ([*+-]|\d+[.]) // $3 = first list item marker
811
+ [ \t]+
812
+ )
813
+ [^\r]+?
814
+ ( // $4
815
+ ~0 // sentinel for workaround; should be $
816
+ |
817
+ \n{2,}
818
+ (?=\S)
819
+ (?! // Negative lookahead for another list item marker
820
+ [ \t]*
821
+ (?:[*+-]|\d+[.])[ \t]+
822
+ )
823
+ )
824
+ )/g
825
+ */
826
+ var whole_list = /^(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;
827
+
828
+ if (g_list_level) {
829
+ text = text.replace(whole_list,function(wholeMatch,m1,m2) {
830
+ var list = m1;
831
+ var list_type = (m2.search(/[*+-]/g)>-1) ? "ul" : "ol";
832
+
833
+ // Turn double returns into triple returns, so that we can make a
834
+ // paragraph for the last item in a list, if necessary:
835
+ list = list.replace(/\n{2,}/g,"\n\n\n");;
836
+ var result = _ProcessListItems(list);
837
+
838
+ // Trim any trailing whitespace, to put the closing `</$list_type>`
839
+ // up on the preceding line, to get it past the current stupid
840
+ // HTML block parser. This is a hack to work around the terrible
841
+ // hack that is the HTML block parser.
842
+ result = result.replace(/\s+$/,"");
843
+ result = "<"+list_type+">" + result + "</"+list_type+">\n";
844
+ return result;
845
+ });
846
+ } else {
847
+ whole_list = /(\n\n|^\n?)(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/g;
848
+ text = text.replace(whole_list,function(wholeMatch,m1,m2,m3) {
849
+ var runup = m1;
850
+ var list = m2;
851
+
852
+ var list_type = (m3.search(/[*+-]/g)>-1) ? "ul" : "ol";
853
+ // Turn double returns into triple returns, so that we can make a
854
+ // paragraph for the last item in a list, if necessary:
855
+ var list = list.replace(/\n{2,}/g,"\n\n\n");;
856
+ var result = _ProcessListItems(list);
857
+ result = runup + "<"+list_type+">\n" + result + "</"+list_type+">\n";
858
+ return result;
859
+ });
860
+ }
861
+
862
+ // attacklab: strip sentinel
863
+ text = text.replace(/~0/,"");
864
+
865
+ return text;
866
+ }
867
+
868
+ _ProcessListItems = function(list_str) {
869
+ //
870
+ // Process the contents of a single ordered or unordered list, splitting it
871
+ // into individual list items.
872
+ //
873
+ // The $g_list_level global keeps track of when we're inside a list.
874
+ // Each time we enter a list, we increment it; when we leave a list,
875
+ // we decrement. If it's zero, we're not in a list anymore.
876
+ //
877
+ // We do this because when we're not inside a list, we want to treat
878
+ // something like this:
879
+ //
880
+ // I recommend upgrading to version
881
+ // 8. Oops, now this line is treated
882
+ // as a sub-list.
883
+ //
884
+ // As a single paragraph, despite the fact that the second line starts
885
+ // with a digit-period-space sequence.
886
+ //
887
+ // Whereas when we're inside a list (or sub-list), that line will be
888
+ // treated as the start of a sub-list. What a kludge, huh? This is
889
+ // an aspect of Markdown's syntax that's hard to parse perfectly
890
+ // without resorting to mind-reading. Perhaps the solution is to
891
+ // change the syntax rules such that sub-lists must start with a
892
+ // starting cardinal number; e.g. "1." or "a.".
893
+
894
+ g_list_level++;
895
+
896
+ // trim trailing blank lines:
897
+ list_str = list_str.replace(/\n{2,}$/,"\n");
898
+
899
+ // attacklab: add sentinel to emulate \z
900
+ list_str += "~0";
901
+
902
+ /*
903
+ list_str = list_str.replace(/
904
+ (\n)? // leading line = $1
905
+ (^[ \t]*) // leading whitespace = $2
906
+ ([*+-]|\d+[.]) [ \t]+ // list marker = $3
907
+ ([^\r]+? // list item text = $4
908
+ (\n{1,2}))
909
+ (?= \n* (~0 | \2 ([*+-]|\d+[.]) [ \t]+))
910
+ /gm, function(){...});
911
+ */
912
+ list_str = list_str.replace(/(\n)?(^[ \t]*)([*+-]|\d+[.])[ \t]+([^\r]+?(\n{1,2}))(?=\n*(~0|\2([*+-]|\d+[.])[ \t]+))/gm,
913
+ function(wholeMatch,m1,m2,m3,m4){
914
+ var item = m4;
915
+ var leading_line = m1;
916
+ var leading_space = m2;
917
+
918
+ if (leading_line || (item.search(/\n{2,}/)>-1)) {
919
+ item = _RunBlockGamut(_Outdent(item));
920
+ }
921
+ else {
922
+ // Recursion for sub-lists:
923
+ item = _DoLists(_Outdent(item));
924
+ item = item.replace(/\n$/,""); // chomp(item)
925
+ item = _RunSpanGamut(item);
926
+ }
927
+
928
+ return "<li>" + item + "</li>\n";
929
+ }
930
+ );
931
+
932
+ // attacklab: strip sentinel
933
+ list_str = list_str.replace(/~0/g,"");
934
+
935
+ g_list_level--;
936
+ return list_str;
937
+ }
938
+
939
+
940
+ var _DoCodeBlocks = function(text) {
941
+ //
942
+ // Process Markdown `<pre><code>` blocks.
943
+ //
944
+
945
+ /*
946
+ text = text.replace(text,
947
+ /(?:\n\n|^)
948
+ ( // $1 = the code block -- one or more lines, starting with a space/tab
949
+ (?:
950
+ (?:[ ]{4}|\t) // Lines must start with a tab or a tab-width of spaces - attacklab: g_tab_width
951
+ .*\n+
952
+ )+
953
+ )
954
+ (\n*[ ]{0,3}[^ \t\n]|(?=~0)) // attacklab: g_tab_width
955
+ /g,function(){...});
956
+ */
957
+
958
+ // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug
959
+ text += "~0";
960
+
961
+ text = text.replace(/(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g,
962
+ function(wholeMatch,m1,m2) {
963
+ var codeblock = m1;
964
+ var nextChar = m2;
965
+
966
+ codeblock = _EncodeCode( _Outdent(codeblock));
967
+ codeblock = _Detab(codeblock);
968
+ codeblock = codeblock.replace(/^\n+/g,""); // trim leading newlines
969
+ codeblock = codeblock.replace(/\n+$/g,""); // trim trailing whitespace
970
+
971
+ codeblock = "<pre><code>" + codeblock + "\n</code></pre>";
972
+
973
+ return hashBlock(codeblock) + nextChar;
974
+ }
975
+ );
976
+
977
+ // attacklab: strip sentinel
978
+ text = text.replace(/~0/,"");
979
+
980
+ return text;
981
+ }
982
+
983
+ //
984
+ // Code Fencing is a GitHub flavored MD concept. Basically you can wrap
985
+ // your code like this:
986
+ //
987
+ // ```{language}
988
+ // {code}
989
+ // ```
990
+ //
991
+ // Where {language} is the language of the code (useful for coloring code)
992
+ // and {code} is your code
993
+ //
994
+ var _DoCodeFencing = function(text) {
995
+ text = text.replace(/`{3}(?:(.*$)\n)?([\s\S]*?)`{3}/gm,
996
+ function(wholeMatch,m1,m2){
997
+ //HTML for this is copied from GitHub directly for compatibility, except the lang="" attribute
998
+ var codeblock = '<div class="highlight"><pre lang="'+m1+'">'+m2+'</pre></div>';
999
+ return codeblock;
1000
+ }
1001
+ )
1002
+ return text;
1003
+ }
1004
+
1005
+ var hashBlock = function(text) {
1006
+ text = text.replace(/(^\n+|\n+$)/g,"");
1007
+ return "\n\n~K" + (g_html_blocks.push(text)-1) + "K\n\n";
1008
+ }
1009
+
1010
+
1011
+ var _DoCodeSpans = function(text) {
1012
+ //
1013
+ // * Backtick quotes are used for <code></code> spans.
1014
+ //
1015
+ // * You can use multiple backticks as the delimiters if you want to
1016
+ // include literal backticks in the code span. So, this input:
1017
+ //
1018
+ // Just type ``foo `bar` baz`` at the prompt.
1019
+ //
1020
+ // Will translate to:
1021
+ //
1022
+ // <p>Just type <code>foo `bar` baz</code> at the prompt.</p>
1023
+ //
1024
+ // There's no arbitrary limit to the number of backticks you
1025
+ // can use as delimters. If you need three consecutive backticks
1026
+ // in your code, use four for delimiters, etc.
1027
+ //
1028
+ // * You can use spaces to get literal backticks at the edges:
1029
+ //
1030
+ // ... type `` `bar` `` ...
1031
+ //
1032
+ // Turns to:
1033
+ //
1034
+ // ... type <code>`bar`</code> ...
1035
+ //
1036
+
1037
+ /*
1038
+ text = text.replace(/
1039
+ (^|[^\\]) // Character before opening ` can't be a backslash
1040
+ (`+) // $2 = Opening run of `
1041
+ ( // $3 = The code block
1042
+ [^\r]*?
1043
+ [^`] // attacklab: work around lack of lookbehind
1044
+ )
1045
+ \2 // Matching closer
1046
+ (?!`)
1047
+ /gm, function(){...});
1048
+ */
1049
+
1050
+ text = text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,
1051
+ function(wholeMatch,m1,m2,m3,m4) {
1052
+ var c = m3;
1053
+ c = c.replace(/^([ \t]*)/g,""); // leading whitespace
1054
+ c = c.replace(/[ \t]*$/g,""); // trailing whitespace
1055
+ c = _EncodeCode(c);
1056
+ return m1+"<code>"+c+"</code>";
1057
+ });
1058
+
1059
+ return text;
1060
+ }
1061
+
1062
+
1063
+ var _EncodeCode = function(text) {
1064
+ //
1065
+ // Encode/escape certain characters inside Markdown code runs.
1066
+ // The point is that in code, these characters are literals,
1067
+ // and lose their special Markdown meanings.
1068
+ //
1069
+ // Encode all ampersands; HTML entities are not
1070
+ // entities within a Markdown code span.
1071
+ text = text.replace(/&/g,"&amp;");
1072
+
1073
+ // Do the angle bracket song and dance:
1074
+ text = text.replace(/</g,"&lt;");
1075
+ text = text.replace(/>/g,"&gt;");
1076
+
1077
+ // Now, escape characters that are magic in Markdown:
1078
+ text = escapeCharacters(text,"\*_{}[]\\",false);
1079
+
1080
+ // jj the line above breaks this:
1081
+ //---
1082
+
1083
+ //* Item
1084
+
1085
+ // 1. Subitem
1086
+
1087
+ // special char: *
1088
+ //---
1089
+
1090
+ return text;
1091
+ }
1092
+
1093
+
1094
+ var _DoItalicsAndBold = function(text) {
1095
+
1096
+ // <strong> must go first:
1097
+ text = text.replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g,
1098
+ "<strong>$2</strong>");
1099
+
1100
+ text = text.replace(/(\w)_(\w)/g, "$1~E95E$2") // ** GFM ** "~E95E" == escaped "_"
1101
+ text = text.replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g,
1102
+ "<em>$2</em>");
1103
+
1104
+ return text;
1105
+ }
1106
+
1107
+
1108
+ var _DoBlockQuotes = function(text) {
1109
+
1110
+ /*
1111
+ text = text.replace(/
1112
+ ( // Wrap whole match in $1
1113
+ (
1114
+ ^[ \t]*>[ \t]? // '>' at the start of a line
1115
+ .+\n // rest of the first line
1116
+ (.+\n)* // subsequent consecutive lines
1117
+ \n* // blanks
1118
+ )+
1119
+ )
1120
+ /gm, function(){...});
1121
+ */
1122
+
1123
+ text = text.replace(/((^[ \t]*>[ \t]?.+\n(.+\n)*\n*)+)/gm,
1124
+ function(wholeMatch,m1) {
1125
+ var bq = m1;
1126
+
1127
+ // attacklab: hack around Konqueror 3.5.4 bug:
1128
+ // "----------bug".replace(/^-/g,"") == "bug"
1129
+
1130
+ bq = bq.replace(/^[ \t]*>[ \t]?/gm,"~0"); // trim one level of quoting
1131
+
1132
+ // attacklab: clean up hack
1133
+ bq = bq.replace(/~0/g,"");
1134
+
1135
+ bq = bq.replace(/^[ \t]+$/gm,""); // trim whitespace-only lines
1136
+ bq = _RunBlockGamut(bq); // recurse
1137
+
1138
+ bq = bq.replace(/(^|\n)/g,"$1 ");
1139
+ // These leading spaces screw with <pre> content, so we need to fix that:
1140
+ bq = bq.replace(
1141
+ /(\s*<pre>[^\r]+?<\/pre>)/gm,
1142
+ function(wholeMatch,m1) {
1143
+ var pre = m1;
1144
+ // attacklab: hack around Konqueror 3.5.4 bug:
1145
+ pre = pre.replace(/^ /mg,"~0");
1146
+ pre = pre.replace(/~0/g,"");
1147
+ return pre;
1148
+ });
1149
+
1150
+ return hashBlock("<blockquote>\n" + bq + "\n</blockquote>");
1151
+ });
1152
+ return text;
1153
+ }
1154
+
1155
+
1156
+ var _FormParagraphs = function(text) {
1157
+ //
1158
+ // Params:
1159
+ // $text - string to process with html <p> tags
1160
+ //
1161
+
1162
+ // Strip leading and trailing lines:
1163
+ text = text.replace(/^\n+/g,"");
1164
+ text = text.replace(/\n+$/g,"");
1165
+
1166
+ var grafs = text.split(/\n{2,}/g);
1167
+ var grafsOut = new Array();
1168
+
1169
+ //
1170
+ // Wrap <p> tags.
1171
+ //
1172
+ var end = grafs.length;
1173
+ for (var i=0; i<end; i++) {
1174
+ var str = grafs[i];
1175
+
1176
+ // if this is an HTML marker, copy it
1177
+ if (str.search(/~K(\d+)K/g) >= 0) {
1178
+ grafsOut.push(str);
1179
+ }
1180
+ else if (str.search(/\S/) >= 0) {
1181
+ str = _RunSpanGamut(str);
1182
+ str = str.replace(/\n/g,"<br />"); // ** GFM **
1183
+ str = str.replace(/^([ \t]*)/g,"<p>");
1184
+ str += "</p>"
1185
+ grafsOut.push(str);
1186
+ }
1187
+
1188
+ }
1189
+
1190
+ //
1191
+ // Unhashify HTML blocks
1192
+ //
1193
+ end = grafsOut.length;
1194
+ for (var i=0; i<end; i++) {
1195
+ // if this is a marker for an html block...
1196
+ while (grafsOut[i].search(/~K(\d+)K/) >= 0) {
1197
+ var blockText = g_html_blocks[RegExp.$1];
1198
+ blockText = blockText.replace(/\$/g,"$$$$"); // Escape any dollar signs
1199
+ grafsOut[i] = grafsOut[i].replace(/~K\d+K/,blockText);
1200
+ }
1201
+ }
1202
+
1203
+ return grafsOut.join("\n\n");
1204
+ }
1205
+
1206
+
1207
+ var _EncodeAmpsAndAngles = function(text) {
1208
+ // Smart processing for ampersands and angle brackets that need to be encoded.
1209
+
1210
+ // Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:
1211
+ // http://bumppo.net/projects/amputator/
1212
+ text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g,"&amp;");
1213
+
1214
+ // Encode naked <'s
1215
+ text = text.replace(/<(?![a-z\/?\$!])/gi,"&lt;");
1216
+
1217
+ return text;
1218
+ }
1219
+
1220
+
1221
+ var _EncodeBackslashEscapes = function(text) {
1222
+ //
1223
+ // Parameter: String.
1224
+ // Returns: The string, with after processing the following backslash
1225
+ // escape sequences.
1226
+ //
1227
+
1228
+ // attacklab: The polite way to do this is with the new
1229
+ // escapeCharacters() function:
1230
+ //
1231
+ // text = escapeCharacters(text,"\\",true);
1232
+ // text = escapeCharacters(text,"`*_{}[]()>#+-.!",true);
1233
+ //
1234
+ // ...but we're sidestepping its use of the (slow) RegExp constructor
1235
+ // as an optimization for Firefox. This function gets called a LOT.
1236
+
1237
+ text = text.replace(/\\(\\)/g,escapeCharacters_callback);
1238
+ text = text.replace(/\\([`*_{}\[\]()>#+-.!])/g,escapeCharacters_callback);
1239
+ return text;
1240
+ }
1241
+
1242
+
1243
+ var _DoAutoLinks = function(text) {
1244
+
1245
+ text = text.replace(/<((https?|ftp|dict):[^'">\s]+)>/gi,"<a href=\"$1\">$1</a>");
1246
+
1247
+ // Email addresses: <address@domain.foo>
1248
+
1249
+ /*
1250
+ text = text.replace(/
1251
+ <
1252
+ (?:mailto:)?
1253
+ (
1254
+ [-.\w]+
1255
+ \@
1256
+ [-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+
1257
+ )
1258
+ >
1259
+ /gi, _DoAutoLinks_callback());
1260
+ */
1261
+ text = text.replace(/<(?:mailto:)?([-.\w]+\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi,
1262
+ function(wholeMatch,m1) {
1263
+ return _EncodeEmailAddress( _UnescapeSpecialChars(m1) );
1264
+ }
1265
+ );
1266
+
1267
+ return text;
1268
+ }
1269
+
1270
+
1271
+ var _EncodeEmailAddress = function(addr) {
1272
+ //
1273
+ // Input: an email address, e.g. "foo@example.com"
1274
+ //
1275
+ // Output: the email address as a mailto link, with each character
1276
+ // of the address encoded as either a decimal or hex entity, in
1277
+ // the hopes of foiling most address harvesting spam bots. E.g.:
1278
+ //
1279
+ // <a href="&#x6D;&#97;&#105;&#108;&#x74;&#111;:&#102;&#111;&#111;&#64;&#101;
1280
+ // x&#x61;&#109;&#x70;&#108;&#x65;&#x2E;&#99;&#111;&#109;">&#102;&#111;&#111;
1281
+ // &#64;&#101;x&#x61;&#109;&#x70;&#108;&#x65;&#x2E;&#99;&#111;&#109;</a>
1282
+ //
1283
+ // Based on a filter by Matthew Wickline, posted to the BBEdit-Talk
1284
+ // mailing list: <http://tinyurl.com/yu7ue>
1285
+ //
1286
+
1287
+ // attacklab: why can't javascript speak hex?
1288
+ function char2hex(ch) {
1289
+ var hexDigits = '0123456789ABCDEF';
1290
+ var dec = ch.charCodeAt(0);
1291
+ return(hexDigits.charAt(dec>>4) + hexDigits.charAt(dec&15));
1292
+ }
1293
+
1294
+ var encode = [
1295
+ function(ch){return "&#"+ch.charCodeAt(0)+";";},
1296
+ function(ch){return "&#x"+char2hex(ch)+";";},
1297
+ function(ch){return ch;}
1298
+ ];
1299
+
1300
+ addr = "mailto:" + addr;
1301
+
1302
+ addr = addr.replace(/./g, function(ch) {
1303
+ if (ch == "@") {
1304
+ // this *must* be encoded. I insist.
1305
+ ch = encode[Math.floor(Math.random()*2)](ch);
1306
+ } else if (ch !=":") {
1307
+ // leave ':' alone (to spot mailto: later)
1308
+ var r = Math.random();
1309
+ // roughly 10% raw, 45% hex, 45% dec
1310
+ ch = (
1311
+ r > .9 ? encode[2](ch) :
1312
+ r > .45 ? encode[1](ch) :
1313
+ encode[0](ch)
1314
+ );
1315
+ }
1316
+ return ch;
1317
+ });
1318
+
1319
+ addr = "<a href=\"" + addr + "\">" + addr + "</a>";
1320
+ addr = addr.replace(/">.+:/g,"\">"); // strip the mailto: from the visible part
1321
+
1322
+ return addr;
1323
+ }
1324
+
1325
+
1326
+ var _UnescapeSpecialChars = function(text) {
1327
+ //
1328
+ // Swap back in all the special characters we've hidden.
1329
+ //
1330
+ text = text.replace(/~E(\d+)E/g,
1331
+ function(wholeMatch,m1) {
1332
+ var charCodeToReplace = parseInt(m1);
1333
+ return String.fromCharCode(charCodeToReplace);
1334
+ }
1335
+ );
1336
+ return text;
1337
+ }
1338
+
1339
+
1340
+ var _Outdent = function(text) {
1341
+ //
1342
+ // Remove one level of line-leading tabs or spaces
1343
+ //
1344
+
1345
+ // attacklab: hack around Konqueror 3.5.4 bug:
1346
+ // "----------bug".replace(/^-/g,"") == "bug"
1347
+
1348
+ text = text.replace(/^(\t|[ ]{1,4})/gm,"~0"); // attacklab: g_tab_width
1349
+
1350
+ // attacklab: clean up hack
1351
+ text = text.replace(/~0/g,"")
1352
+
1353
+ return text;
1354
+ }
1355
+
1356
+ var _Detab = function(text) {
1357
+ // attacklab: Detab's completely rewritten for speed.
1358
+ // In perl we could fix it by anchoring the regexp with \G.
1359
+ // In javascript we're less fortunate.
1360
+
1361
+ // expand first n-1 tabs
1362
+ text = text.replace(/\t(?=\t)/g," "); // attacklab: g_tab_width
1363
+
1364
+ // replace the nth with two sentinels
1365
+ text = text.replace(/\t/g,"~A~B");
1366
+
1367
+ // use the sentinel to anchor our regex so it doesn't explode
1368
+ text = text.replace(/~B(.+?)~A/g,
1369
+ function(wholeMatch,m1,m2) {
1370
+ var leadingText = m1;
1371
+ var numSpaces = 4 - leadingText.length % 4; // attacklab: g_tab_width
1372
+
1373
+ // there *must* be a better way to do this:
1374
+ for (var i=0; i<numSpaces; i++) leadingText+=" ";
1375
+
1376
+ return leadingText;
1377
+ }
1378
+ );
1379
+
1380
+ // clean up sentinels
1381
+ text = text.replace(/~A/g," "); // attacklab: g_tab_width
1382
+ text = text.replace(/~B/g,"");
1383
+
1384
+ return text;
1385
+ }
1386
+
1387
+
1388
+ //
1389
+ // attacklab: Utility functions
1390
+ //
1391
+
1392
+
1393
+ var escapeCharacters = function(text, charsToEscape, afterBackslash) {
1394
+ // First we have to escape the escape characters so that
1395
+ // we can build a character class out of them
1396
+ var regexString = "([" + charsToEscape.replace(/([\[\]\\])/g,"\\$1") + "])";
1397
+
1398
+ if (afterBackslash) {
1399
+ regexString = "\\\\" + regexString;
1400
+ }
1401
+
1402
+ var regex = new RegExp(regexString,"g");
1403
+ text = text.replace(regex,escapeCharacters_callback);
1404
+
1405
+ return text;
1406
+ }
1407
+
1408
+
1409
+ var escapeCharacters_callback = function(wholeMatch,m1) {
1410
+ var charCodeToEscape = m1.charCodeAt(0);
1411
+ return "~E"+charCodeToEscape+"E";
1412
+ }
1413
+
1414
+ } // end of Showdown.converter