Permalink
Browse files

tabs to spaces

  • Loading branch information...
1 parent 3ec6750 commit 38c9981257a1ce0c67115dc1c281909d1486674d @youurayy committed Nov 6, 2012
Showing with 1,134 additions and 1,134 deletions.
  1. +6 −6 README.md
  2. +109 −109 gfms.js
  3. +39 −39 package.json
  4. +11 −11 public/gfms.js
  5. +943 −943 showdown.js
  6. +4 −4 views/directory.jade
  7. +6 −6 views/file.jade
  8. +13 −13 views/layout.jade
  9. +3 −3 views/style.styl
View
12 README.md
@@ -11,9 +11,9 @@ Sure, there are various good Markdown editors for all platforms, but only a few
```js
function(arg) {
- // some code here
- for(var i = 0; i < 10; i++)
- console.log('hello ' + i);
+ // some code here
+ for(var i = 0; i < 10; i++)
+ console.log('hello ' + i);
}
```
@@ -27,9 +27,9 @@ Another possible shortcoming is that the URLs of the Github CSS files are scrape
## Usage
- [sudo] npm install gfms -g
- cd your-github-project-dir
- gfms -p 1234
+ [sudo] npm install gfms -g
+ cd your-github-project-dir
+ gfms -p 1234
(If you don't know how to install NPM, see here: http://npmjs.org/)
View
218 gfms.js
@@ -1,12 +1,12 @@
var argv = require('optimist')
- .usage('\nGithub Flavored Markdown Server.\nRun in your project\'s root directory.\nUsage: $0')
- .demand('p')
- .alias('p', 'port')
- .describe('p', 'Port number to listen at.')
- .alias('h', 'host')
- .describe('h', 'Host address to bind to.')
- .default('h', 'localhost')
- .argv;
+ .usage('\nGithub Flavored Markdown Server.\nRun in your project\'s root directory.\nUsage: $0')
+ .demand('p')
+ .alias('p', 'port')
+ .describe('p', 'Port number to listen at.')
+ .alias('h', 'host')
+ .describe('h', 'Host address to bind to.')
+ .default('h', 'localhost')
+ .argv;
var express = require('express');
var stylus = require('stylus');
@@ -15,7 +15,7 @@ var app = express();
var http = require('http');
var server = http.createServer(app);
var markdown = //require('github-flavored-markdown').parse;
- require('./showdown.js').parse;
+ require('./showdown.js').parse;
var _ = require('underscore');
var fs = require('fs');
var ews = require('ws');
@@ -32,125 +32,125 @@ var styles = [];
app.configure(function() {
- var pub = __dirname + '/public';
- var views = __dirname + '/views';
- app.set('views', views);
- app.set('view engine', 'jade');
- app.set('view options', { layout: false });
-
-
- if(process.env.NODE_ENV === 'development') {
- // only use Stylus in development, because when gfms is installed
- // globally with sudo, and then run by an user, it cannot create
- // the generate .css files (and I'm too tired to look for a solution now).
- app.use(stylus.middleware({
- src: views,
- dest: pub,
- compile: function(str, path) {
- return stylus(str)
- .set('filename', path)
- .set('compress', true)
- .use(nib())
- .import('nib');
- }
- }));
- }
-
- app.use(wss.middleware(express));
- app.use(express.favicon());
- app.use(app.router);
- app.use(express.static(pub));
- app.use(express.errorHandler({ dump: true, stack: true }));
+ var pub = __dirname + '/public';
+ var views = __dirname + '/views';
+ app.set('views', views);
+ app.set('view engine', 'jade');
+ app.set('view options', { layout: false });
+
+
+ if(process.env.NODE_ENV === 'development') {
+ // only use Stylus in development, because when gfms is installed
+ // globally with sudo, and then run by an user, it cannot create
+ // the generate .css files (and I'm too tired to look for a solution now).
+ app.use(stylus.middleware({
+ src: views,
+ dest: pub,
+ compile: function(str, path) {
+ return stylus(str)
+ .set('filename', path)
+ .set('compress', true)
+ .use(nib())
+ .import('nib');
+ }
+ }));
+ }
+
+ app.use(wss.middleware(express));
+ app.use(express.favicon());
+ app.use(app.router);
+ app.use(express.static(pub));
+ app.use(express.errorHandler({ dump: true, stack: true }));
});
app.configure('development', function() {
- require('utilz').watchFile(__filename);
+ require('utilz').watchFile(__filename);
});
function basename(fn) {
- var m = fn.match(/.*?([^\/]+)\/?$/);
- return m ? m[1] : fn;
+ var m = fn.match(/.*?([^\/]+)\/?$/);
+ return m ? m[1] : fn;
}
function is_markdown(v) {
- return v.match(/.*?(?:\.md|\.markdown)$/) ? true : false;
+ return v.match(/.*?(?:\.md|\.markdown)$/) ? true : false;
}
app.get('*', function(req, res, next) {
-
- var base = req.path.replace('..', 'DENIED').replace(/\/$/, '');
- var dir = process.cwd() + base;
-
- var stat;
- try {
- stat = fs.statSync(dir);
- }
- catch(e) {
- return next();
- }
-
- if(stat.isDirectory()) {
-
- var files = _.chain(fs.readdirSync(dir)).filter(function(v) {
- var stat = fs.statSync(dir + '/' + v);
- return stat.isDirectory() || (stat.isFile() && is_markdown(v));
- }).map(function(v) {
- return {
- url: base + '/' + v,
- name: v
- };
- }).value();
-
- res.render('directory', {
- files: files,
- dir: dir,
- styles: styles,
- title: basename(dir)
- });
- }
- else if(is_markdown(dir)) {
-
- if(!watched[dir]) {
- fs.watchFile(dir, { interval: 500 }, function(curr, prev) {
- if(curr.mtime.getTime() !== prev.mtime.getTime()) {
- console.log('file ' + dir + ' has changed');
- wss.message('update', { update: dir, content: markdown(fs.readFileSync(dir, 'utf8')) });
- }
- });
- watched[dir] = true;
- }
-
- res.render('file', {
- file: markdown(fs.readFileSync(dir, 'utf8')),
- title: basename(dir),
- styles: styles,
- fullname: dir
- });
- }
- else
- return next();
+
+ var base = req.path.replace('..', 'DENIED').replace(/\/$/, '');
+ var dir = process.cwd() + base;
+
+ var stat;
+ try {
+ stat = fs.statSync(dir);
+ }
+ catch(e) {
+ return next();
+ }
+
+ if(stat.isDirectory()) {
+
+ var files = _.chain(fs.readdirSync(dir)).filter(function(v) {
+ var stat = fs.statSync(dir + '/' + v);
+ return stat.isDirectory() || (stat.isFile() && is_markdown(v));
+ }).map(function(v) {
+ return {
+ url: base + '/' + v,
+ name: v
+ };
+ }).value();
+
+ res.render('directory', {
+ files: files,
+ dir: dir,
+ styles: styles,
+ title: basename(dir)
+ });
+ }
+ else if(is_markdown(dir)) {
+
+ if(!watched[dir]) {
+ fs.watchFile(dir, { interval: 500 }, function(curr, prev) {
+ if(curr.mtime.getTime() !== prev.mtime.getTime()) {
+ console.log('file ' + dir + ' has changed');
+ wss.message('update', { update: dir, content: markdown(fs.readFileSync(dir, 'utf8')) });
+ }
+ });
+ watched[dir] = true;
+ }
+
+ res.render('file', {
+ file: markdown(fs.readFileSync(dir, 'utf8')),
+ title: basename(dir),
+ styles: styles,
+ fullname: dir
+ });
+ }
+ else
+ return next();
});
process.on('SIGINT', function() {
- console.log('\nGFMS exit.');
- return process.exit();
+ console.log('\nGFMS exit.');
+ return process.exit();
});
console.log('Getting .css links from Github...');
request('http://www.github.com', function(err, res, body) {
- if(err || res.statusCode != 200)
- throw 'Cannot load .css links from Github';
-
- var m, re = /<link href="(.+?)" media="screen" rel="stylesheet" type="text\/css" \/>/g;
- while(m = re.exec(body))
- styles.push(m[1]);
-
- if(!styles.length)
- throw 'Cannot parse .css links from Github';
-
- server.listen(argv.p, argv.h);
-
- console.log('GFMS serving ' + process.cwd() + ' at http://' + argv.h + ':' + argv.p + '/ - press CTRL+C to exit.');
+ if(err || res.statusCode != 200)
+ throw 'Cannot load .css links from Github';
+
+ var m, re = /<link href="(.+?)" media="screen" rel="stylesheet" type="text\/css" \/>/g;
+ while(m = re.exec(body))
+ styles.push(m[1]);
+
+ if(!styles.length)
+ throw 'Cannot parse .css links from Github';
+
+ server.listen(argv.p, argv.h);
+
+ console.log('GFMS serving ' + process.cwd() + ' at http://' + argv.h + ':' + argv.p + '/ - press CTRL+C to exit.');
});
View
78 package.json
@@ -1,41 +1,41 @@
{
- "author": "Juraj Vitko (ypocat.com)",
- "name": "gfms",
- "description": "Github Flavored Markdown Server",
- "keywords": [ "markdown", "server", "local", "reloading" ],
- "version": "0.0.4",
- "homepage": "http://github.com/ypocat/gfms",
- "repository": {
- "type": "git",
- "url": "git://github.com/ypocat/gfms.git"
- },
- "main": "gfms.js",
- "directories": {
- "lib": "./lib"
- },
- "bin": {
- "gfms": "./bin/gfms"
- },
- "engines": {
- "node": "*"
- },
- "dependencies": {
- "express": "*",
- "github-flavored-markdown": "*",
- "jade": "*",
- "laeh2": "*",
- "nib": "*",
- "optimist": "*",
- "request": "*",
- "ws": "*",
- "ws-rpc": "*",
- "stylus": "*",
- "underscore": "*",
- "utilz": "*"
- },
- "devDependencies": {
- },
- "licenses": [
- { "type" : "MIT", "url" : "https://raw.github.com/ypocat/gfms/master/LICENSE" }
- ]
+ "author": "Juraj Vitko (ypocat.com)",
+ "name": "gfms",
+ "description": "Github Flavored Markdown Server",
+ "keywords": [ "markdown", "server", "local", "reloading" ],
+ "version": "0.0.4",
+ "homepage": "http://github.com/ypocat/gfms",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/ypocat/gfms.git"
+ },
+ "main": "gfms.js",
+ "directories": {
+ "lib": "./lib"
+ },
+ "bin": {
+ "gfms": "./bin/gfms"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "dependencies": {
+ "express": "*",
+ "github-flavored-markdown": "*",
+ "jade": "*",
+ "laeh2": "*",
+ "nib": "*",
+ "optimist": "*",
+ "request": "*",
+ "ws": "*",
+ "ws-rpc": "*",
+ "stylus": "*",
+ "underscore": "*",
+ "utilz": "*"
+ },
+ "devDependencies": {
+ },
+ "licenses": [
+ { "type" : "MIT", "url" : "https://raw.github.com/ypocat/gfms/master/LICENSE" }
+ ]
}
View
22 public/gfms.js
@@ -1,13 +1,13 @@
$(function() {
-
- var filename = $('#content').data('filename');
-
- var WebSocketRPC = InitWebSocketRPC(WebSocket);
- var ws = new WebSocketRPC('ws://' + window.location.host + '/');
-
- ws.on('update', function(data) {
- if(filename === data.update)
- $('div.markdown-body').html(data.content);
- });
-
+
+ var filename = $('#content').data('filename');
+
+ var WebSocketRPC = InitWebSocketRPC(WebSocket);
+ var ws = new WebSocketRPC('ws://' + window.location.host + '/');
+
+ ws.on('update', function(data) {
+ if(filename === data.update)
+ $('div.markdown-body').html(data.content);
+ });
+
});
View
1,886 showdown.js
@@ -11,9 +11,9 @@
//
// The full source distribution is at:
//
-// A A L
-// T C A
-// T K B
+// A A L
+// T C A
+// T K B
//
// <http://www.attacklab.net/>
//
@@ -140,56 +140,56 @@ this.makeHtml = function(text, gh) {
// and <img> tags get encoded.
//
- // Clear the global hashes. If we don't clear these, you get conflicts
- // from other articles when generating a page which contains more than
- // one article (e.g. an index page that shows the N most recent
- // articles):
- g_urls = new Array();
- g_titles = new Array();
- g_html_blocks = new Array();
+ // Clear the global hashes. If we don't clear these, you get conflicts
+ // from other articles when generating a page which contains more than
+ // one article (e.g. an index page that shows the N most recent
+ // articles):
+ g_urls = new Array();
+ g_titles = new Array();
+ g_html_blocks = new Array();
- // attacklab: Replace ~ with ~T
- // This lets us use tilde as an escape char to avoid md5 hashes
- // The choice of character is arbitray; anything that isn't
+ // attacklab: Replace ~ with ~T
+ // This lets us use tilde as an escape char to avoid md5 hashes
+ // The choice of character is arbitray; anything that isn't
// magic in Markdown will work.
- text = text.replace(/~/g,"~T");
+ text = text.replace(/~/g,"~T");
- // attacklab: Replace $ with ~D
- // RegExp interprets $ as a special character
- // when it's in a replacement string
- text = text.replace(/\$/g,"~D");
+ // attacklab: Replace $ with ~D
+ // RegExp interprets $ as a special character
+ // when it's in a replacement string
+ text = text.replace(/\$/g,"~D");
- // Standardize line endings
- text = text.replace(/\r\n/g,"\n"); // DOS to Unix
- text = text.replace(/\r/g,"\n"); // Mac to Unix
+ // Standardize line endings
+ text = text.replace(/\r\n/g,"\n"); // DOS to Unix
+ text = text.replace(/\r/g,"\n"); // Mac to Unix
- // Make sure text begins and ends with a couple of newlines:
- text = "\n\n" + text + "\n\n";
+ // Make sure text begins and ends with a couple of newlines:
+ text = "\n\n" + text + "\n\n";
- // Convert all tabs to spaces.
- text = _Detab(text);
+ // Convert all tabs to spaces.
+ text = _Detab(text);
- // Strip any lines consisting only of spaces and tabs.
- // This makes subsequent regexen easier to write, because we can
- // match consecutive blank lines with /\n+/ instead of something
- // contorted like /[ \t]*\n+/ .
- text = text.replace(/^[ \t]+$/mg,"");
+ // Strip any lines consisting only of spaces and tabs.
+ // This makes subsequent regexen easier to write, because we can
+ // match consecutive blank lines with /\n+/ instead of something
+ // contorted like /[ \t]*\n+/ .
+ text = text.replace(/^[ \t]+$/mg,"");
- // Turn block-level HTML blocks into hash entries
- text = _HashHTMLBlocks(text);
+ // Turn block-level HTML blocks into hash entries
+ text = _HashHTMLBlocks(text);
- // Strip link definitions, store in hashes.
- text = _StripLinkDefinitions(text);
+ // Strip link definitions, store in hashes.
+ text = _StripLinkDefinitions(text);
- text = _RunBlockGamut(text);
+ text = _RunBlockGamut(text);
- text = _UnescapeSpecialChars(text);
+ text = _UnescapeSpecialChars(text);
- // attacklab: Restore dollar signs
- text = text.replace(/~D/g,"$$");
+ // attacklab: Restore dollar signs
+ text = text.replace(/~D/g,"$$");
- // attacklab: Restore tildes
- text = text.replace(/~T/g,"~");
+ // attacklab: Restore tildes
+ text = text.replace(/~T/g,"~");
// ** GFM ** Auto-link URLs and emails
text = text.replace(/https?\:\/\/[^"\s\<\>]*[^.,;'">\:\s\<\>\)\]\!]/g, function(wholeMatch,matchIndex){
@@ -243,7 +243,7 @@ this.makeHtml = function(text, gh) {
return "<a href='http://github.com/" + repo + "/issues/#issue/" + issue + "'>" + wholeMatch + "</a>";
});
- return text;
+ return text;
}
@@ -257,188 +257,188 @@ var _StripLinkDefinitions = function(text) {
// hash references.
//
- // Link defs are in the form: ^[id]: url "optional title"
-
- /*
- var text = text.replace(/
- ^[ ]{0,3}\[(.+)\]: // id = $1 attacklab: g_tab_width - 1
- [ \t]*
- \n? // maybe *one* newline
- [ \t]*
- <?(\S+?)>? // url = $2
- [ \t]*
- \n? // maybe one newline
- [ \t]*
- (?:
- (\n*) // any lines skipped = $3 attacklab: lookbehind removed
- ["(]
- (.+?) // title = $4
- [")]
- [ \t]*
- )? // title is optional
- (?:\n+|$)
- /gm,
- function(){...});
- */
- var text = text.replace(/^[ ]{0,3}\[(.+)\]:[ \t]*\n?[ \t]*<?(\S+?)>?[ \t]*\n?[ \t]*(?:(\n*)["(](.+?)[")][ \t]*)?(?:\n+|\Z)/gm,
- function (wholeMatch,m1,m2,m3,m4) {
- m1 = m1.toLowerCase();
- g_urls[m1] = _EncodeAmpsAndAngles(m2); // Link IDs are case-insensitive
- if (m3) {
- // Oops, found blank lines, so it's not a title.
- // Put back the parenthetical statement we stole.
- return m3+m4;
- } else if (m4) {
- g_titles[m1] = m4.replace(/"/g,"&quot;");
- }
-
- // Completely remove the definition from the text
- return "";
- }
- );
-
- return text;
+ // Link defs are in the form: ^[id]: url "optional title"
+
+ /*
+ var text = text.replace(/
+ ^[ ]{0,3}\[(.+)\]: // id = $1 attacklab: g_tab_width - 1
+ [ \t]*
+ \n? // maybe *one* newline
+ [ \t]*
+ <?(\S+?)>? // url = $2
+ [ \t]*
+ \n? // maybe one newline
+ [ \t]*
+ (?:
+ (\n*) // any lines skipped = $3 attacklab: lookbehind removed
+ ["(]
+ (.+?) // title = $4
+ [")]
+ [ \t]*
+ )? // title is optional
+ (?:\n+|$)
+ /gm,
+ function(){...});
+ */
+ var text = text.replace(/^[ ]{0,3}\[(.+)\]:[ \t]*\n?[ \t]*<?(\S+?)>?[ \t]*\n?[ \t]*(?:(\n*)["(](.+?)[")][ \t]*)?(?:\n+|\Z)/gm,
+ function (wholeMatch,m1,m2,m3,m4) {
+ m1 = m1.toLowerCase();
+ g_urls[m1] = _EncodeAmpsAndAngles(m2); // Link IDs are case-insensitive
+ if (m3) {
+ // Oops, found blank lines, so it's not a title.
+ // Put back the parenthetical statement we stole.
+ return m3+m4;
+ } else if (m4) {
+ g_titles[m1] = m4.replace(/"/g,"&quot;");
+ }
+
+ // Completely remove the definition from the text
+ return "";
+ }
+ );
+
+ return text;
}
var _HashHTMLBlocks = function(text) {
- // attacklab: Double up blank lines to reduce lookaround
- text = text.replace(/\n/g,"\n\n");
-
- // Hashify HTML blocks:
- // We only want to do this for block-level HTML tags, such as headers,
- // lists, and tables. That's because we still want to wrap <p>s around
- // "paragraphs" that are wrapped in non-block-level tags, such as anchors,
- // phrase emphasis, and spans. The list of tags we're looking for is
- // hard-coded:
- var block_tags_a = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del"
- var block_tags_b = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math"
-
- // First, look for nested blocks, e.g.:
- // <div>
- // <div>
- // tags for inner block must be indented.
- // </div>
- // </div>
- //
- // The outermost tags must start at the left margin for this to match, and
- // the inner nested divs must be indented.
- // We need to do this before the next, more liberal match, because the next
- // match will start at the first `<div>` and stop at the first `</div>`.
-
- // attacklab: This regex can be expensive when it fails.
- /*
- var text = text.replace(/
- ( // save in $1
- ^ // start of line (with /m)
- <($block_tags_a) // start tag = $2
- \b // word break
- // attacklab: hack around khtml/pcre bug...
- [^\r]*?\n // any number of lines, minimally matching
- </\2> // the matching end tag
- [ \t]* // trailing spaces/tabs
- (?=\n+) // followed by a newline
- ) // attacklab: there are sentinel newlines at end of document
- /gm,function(){...}};
- */
- 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);
-
- //
- // Now match more liberally, simply from `\n<tag>` to `</tag>\n`
- //
-
- /*
- var text = text.replace(/
- ( // save in $1
- ^ // start of line (with /m)
- <($block_tags_b) // start tag = $2
- \b // word break
- // attacklab: hack around khtml/pcre bug...
- [^\r]*? // any number of lines, minimally matching
- .*</\2> // the matching end tag
- [ \t]* // trailing spaces/tabs
- (?=\n+) // followed by a newline
- ) // attacklab: there are sentinel newlines at end of document
- /gm,function(){...}};
- */
- 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);
-
- // Special case just for <hr />. It was easier to make a special case than
- // to make the other regex more complicated.
-
- /*
- text = text.replace(/
- ( // save in $1
- \n\n // Starting after a blank line
- [ ]{0,3}
- (<(hr) // start tag = $2
- \b // word break
- ([^<>])*? //
- \/?>) // the matching end tag
- [ \t]*
- (?=\n{2,}) // followed by a blank line
- )
- /g,hashElement);
- */
- text = text.replace(/(\n[ ]{0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,hashElement);
-
- // Special case for standalone HTML comments:
-
- /*
- text = text.replace(/
- ( // save in $1
- \n\n // Starting after a blank line
- [ ]{0,3} // attacklab: g_tab_width - 1
- <!
- (--[^\r]*?--\s*)+
- >
- [ \t]*
- (?=\n{2,}) // followed by a blank line
- )
- /g,hashElement);
- */
- text = text.replace(/(\n\n[ ]{0,3}<!(--[^\r]*?--\s*)+>[ \t]*(?=\n{2,}))/g,hashElement);
-
- // PHP and ASP-style processor instructions (<?...?> and <%...%>)
-
- /*
- text = text.replace(/
- (?:
- \n\n // Starting after a blank line
- )
- ( // save in $1
- [ ]{0,3} // attacklab: g_tab_width - 1
- (?:
- <([?%]) // $2
- [^\r]*?
- \2>
- )
- [ \t]*
- (?=\n{2,}) // followed by a blank line
- )
- /g,hashElement);
- */
- text = text.replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,hashElement);
-
- // attacklab: Undo double lines (see comment at top of this function)
- text = text.replace(/\n\n/g,"\n");
- return text;
+ // attacklab: Double up blank lines to reduce lookaround
+ text = text.replace(/\n/g,"\n\n");
+
+ // Hashify HTML blocks:
+ // We only want to do this for block-level HTML tags, such as headers,
+ // lists, and tables. That's because we still want to wrap <p>s around
+ // "paragraphs" that are wrapped in non-block-level tags, such as anchors,
+ // phrase emphasis, and spans. The list of tags we're looking for is
+ // hard-coded:
+ var block_tags_a = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del"
+ var block_tags_b = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math"
+
+ // First, look for nested blocks, e.g.:
+ // <div>
+ // <div>
+ // tags for inner block must be indented.
+ // </div>
+ // </div>
+ //
+ // The outermost tags must start at the left margin for this to match, and
+ // the inner nested divs must be indented.
+ // We need to do this before the next, more liberal match, because the next
+ // match will start at the first `<div>` and stop at the first `</div>`.
+
+ // attacklab: This regex can be expensive when it fails.
+ /*
+ var text = text.replace(/
+ ( // save in $1
+ ^ // start of line (with /m)
+ <($block_tags_a) // start tag = $2
+ \b // word break
+ // attacklab: hack around khtml/pcre bug...
+ [^\r]*?\n // any number of lines, minimally matching
+ </\2> // the matching end tag
+ [ \t]* // trailing spaces/tabs
+ (?=\n+) // followed by a newline
+ ) // attacklab: there are sentinel newlines at end of document
+ /gm,function(){...}};
+ */
+ 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);
+
+ //
+ // Now match more liberally, simply from `\n<tag>` to `</tag>\n`
+ //
+
+ /*
+ var text = text.replace(/
+ ( // save in $1
+ ^ // start of line (with /m)
+ <($block_tags_b) // start tag = $2
+ \b // word break
+ // attacklab: hack around khtml/pcre bug...
+ [^\r]*? // any number of lines, minimally matching
+ .*</\2> // the matching end tag
+ [ \t]* // trailing spaces/tabs
+ (?=\n+) // followed by a newline
+ ) // attacklab: there are sentinel newlines at end of document
+ /gm,function(){...}};
+ */
+ 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);
+
+ // Special case just for <hr />. It was easier to make a special case than
+ // to make the other regex more complicated.
+
+ /*
+ text = text.replace(/
+ ( // save in $1
+ \n\n // Starting after a blank line
+ [ ]{0,3}
+ (<(hr) // start tag = $2
+ \b // word break
+ ([^<>])*? //
+ \/?>) // the matching end tag
+ [ \t]*
+ (?=\n{2,}) // followed by a blank line
+ )
+ /g,hashElement);
+ */
+ text = text.replace(/(\n[ ]{0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,hashElement);
+
+ // Special case for standalone HTML comments:
+
+ /*
+ text = text.replace(/
+ ( // save in $1
+ \n\n // Starting after a blank line
+ [ ]{0,3} // attacklab: g_tab_width - 1
+ <!
+ (--[^\r]*?--\s*)+
+ >
+ [ \t]*
+ (?=\n{2,}) // followed by a blank line
+ )
+ /g,hashElement);
+ */
+ text = text.replace(/(\n\n[ ]{0,3}<!(--[^\r]*?--\s*)+>[ \t]*(?=\n{2,}))/g,hashElement);
+
+ // PHP and ASP-style processor instructions (<?...?> and <%...%>)
+
+ /*
+ text = text.replace(/
+ (?:
+ \n\n // Starting after a blank line
+ )
+ ( // save in $1
+ [ ]{0,3} // attacklab: g_tab_width - 1
+ (?:
+ <([?%]) // $2
+ [^\r]*?
+ \2>
+ )
+ [ \t]*
+ (?=\n{2,}) // followed by a blank line
+ )
+ /g,hashElement);
+ */
+ text = text.replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,hashElement);
+
+ // attacklab: Undo double lines (see comment at top of this function)
+ text = text.replace(/\n\n/g,"\n");
+ return text;
}
var hashElement = function(wholeMatch,m1) {
- var blockText = m1;
+ var blockText = m1;
- // Undo double lines
- blockText = blockText.replace(/\n\n/g,"\n");
- blockText = blockText.replace(/^\n/,"");
+ // Undo double lines
+ blockText = blockText.replace(/\n\n/g,"\n");
+ blockText = blockText.replace(/^\n/,"");
- // strip trailing blank lines
- blockText = blockText.replace(/\n+$/g,"");
+ // strip trailing blank lines
+ blockText = blockText.replace(/\n+$/g,"");
- // Replace the element text with a marker ("~KxK" where x is its key)
- blockText = "\n\n~K" + (g_html_blocks.push(blockText)-1) + "K\n\n";
+ // Replace the element text with a marker ("~KxK" where x is its key)
+ blockText = "\n\n~K" + (g_html_blocks.push(blockText)-1) + "K\n\n";
- return blockText;
+ return blockText;
};
var _RunBlockGamut = function(text) {
@@ -447,29 +447,29 @@ var _RunBlockGamut = function(text) {
// tags like paragraphs, headers, and list items.
//
- // This must go before _DoHeaders, otherwise e.g. #!/bin/bash is treated as H1
- text = _DoGFMCodeBlocks(text); // ypocat
+ // This must go before _DoHeaders, otherwise e.g. #!/bin/bash is treated as H1
+ text = _DoGFMCodeBlocks(text); // ypocat
- text = _DoHeaders(text);
+ text = _DoHeaders(text);
- // Do Horizontal Rules:
- var key = hashBlock("<hr />");
- text = text.replace(/^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$/gm,key);
- text = text.replace(/^[ ]{0,2}([ ]?\-[ ]?){3,}[ \t]*$/gm,key);
- text = text.replace(/^[ ]{0,2}([ ]?\_[ ]?){3,}[ \t]*$/gm,key);
+ // Do Horizontal Rules:
+ var key = hashBlock("<hr />");
+ text = text.replace(/^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$/gm,key);
+ text = text.replace(/^[ ]{0,2}([ ]?\-[ ]?){3,}[ \t]*$/gm,key);
+ text = text.replace(/^[ ]{0,2}([ ]?\_[ ]?){3,}[ \t]*$/gm,key);
- text = _DoLists(text);
- text = _DoCodeBlocks(text);
- text = _DoBlockQuotes(text);
+ text = _DoLists(text);
+ text = _DoCodeBlocks(text);
+ text = _DoBlockQuotes(text);
- // We already ran _HashHTMLBlocks() before, in Markdown(), but that
- // was to escape raw HTML in the original Markdown source. This time,
- // we're escaping the markup we've just created, so that we don't wrap
- // <p> tags around block-level tags.
- text = _HashHTMLBlocks(text);
- text = _FormParagraphs(text);
+ // We already ran _HashHTMLBlocks() before, in Markdown(), but that
+ // was to escape raw HTML in the original Markdown source. This time,
+ // we're escaping the markup we've just created, so that we don't wrap
+ // <p> tags around block-level tags.
+ text = _HashHTMLBlocks(text);
+ text = _FormParagraphs(text);
- return text;
+ return text;
}
@@ -479,26 +479,26 @@ var _RunSpanGamut = function(text) {
// tags like paragraphs, headers, and list items.
//
- text = _DoCodeSpans(text);
- text = _EscapeSpecialCharsWithinTagAttributes(text);
- text = _EncodeBackslashEscapes(text);
+ text = _DoCodeSpans(text);
+ text = _EscapeSpecialCharsWithinTagAttributes(text);
+ text = _EncodeBackslashEscapes(text);
- // Process anchor and image tags. Images must come first,
- // because ![foo][f] looks like an anchor.
- text = _DoImages(text);
- text = _DoAnchors(text);
+ // Process anchor and image tags. Images must come first,
+ // because ![foo][f] looks like an anchor.
+ text = _DoImages(text);
+ text = _DoAnchors(text);
- // Make links out of things like `<http://example.com/>`
- // Must come after _DoAnchors(), because you can use < and >
- // delimiters in inline links like [this](<url>).
- text = _DoAutoLinks(text);
- text = _EncodeAmpsAndAngles(text);
- text = _DoItalicsAndBold(text);
+ // Make links out of things like `<http://example.com/>`
+ // Must come after _DoAnchors(), because you can use < and >
+ // delimiters in inline links like [this](<url>).
+ text = _DoAutoLinks(text);
+ text = _EncodeAmpsAndAngles(text);
+ text = _DoItalicsAndBold(text);
- // Do hard breaks:
- text = text.replace(/ +\n/g," <br />\n");
+ // Do hard breaks:
+ text = text.replace(/ +\n/g," <br />\n");
- return text;
+ return text;
}
var _EscapeSpecialCharsWithinTagAttributes = function(text) {
@@ -507,147 +507,147 @@ var _EscapeSpecialCharsWithinTagAttributes = function(text) {
// don't conflict with their use in Markdown for code, italics and strong.
//
- // Build a regex to find HTML tags and comments. See Friedl's
- // "Mastering Regular Expressions", 2nd Ed., pp. 200-201.
- var regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|<!(--.*?--\s*)+>)/gi;
+ // Build a regex to find HTML tags and comments. See Friedl's
+ // "Mastering Regular Expressions", 2nd Ed., pp. 200-201.
+ var regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|<!(--.*?--\s*)+>)/gi;
- text = text.replace(regex, function(wholeMatch) {
- var tag = wholeMatch.replace(/(.)<\/?code>(?=.)/g,"$1`");
- tag = escapeCharacters(tag,"\\`*_");
- return tag;
- });
+ text = text.replace(regex, function(wholeMatch) {
+ var tag = wholeMatch.replace(/(.)<\/?code>(?=.)/g,"$1`");
+ tag = escapeCharacters(tag,"\\`*_");
+ return tag;
+ });
- return text;
+ return text;
}
var _DoAnchors = function(text) {
//
// Turn Markdown link shortcuts into XHTML <a> tags.
//
- //
- // First, handle reference-style links: [link text] [id]
- //
-
- /*
- text = text.replace(/
- ( // wrap whole match in $1
- \[
- (
- (?:
- \[[^\]]*\] // allow brackets nested one level
- |
- [^\[] // or anything else
- )*
- )
- \]
-
- [ ]? // one optional space
- (?:\n[ ]*)? // one optional newline followed by spaces
-
- \[
- (.*?) // id = $3
- \]
- )()()()() // pad remaining backreferences
- /g,_DoAnchors_callback);
- */
- text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,writeAnchorTag);
-
- //
- // Next, inline-style links: [link text](url "optional title")
- //
-
- /*
- text = text.replace(/
- ( // wrap whole match in $1
- \[
- (
- (?:
- \[[^\]]*\] // allow brackets nested one level
- |
- [^\[\]] // or anything else
- )
- )
- \]
- \( // literal paren
- [ \t]*
- () // no id, so leave $3 empty
- <?(.*?)>? // href = $4
- [ \t]*
- ( // $5
- (['"]) // quote char = $6
- (.*?) // Title = $7
- \6 // matching quote
- [ \t]* // ignore any spaces/tabs between closing quote and )
- )? // title is optional
- \)
- )
- /g,writeAnchorTag);
- */
- text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()<?(.*?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,writeAnchorTag);
-
- //
- // Last, handle reference-style shortcuts: [link text]
- // These must come last in case you've also got [link test][1]
- // or [link test](/foo)
- //
-
- /*
- text = text.replace(/
- ( // wrap whole match in $1
- \[
- ([^\[\]]+) // link text = $2; can't contain '[' or ']'
- \]
- )()()()()() // pad rest of backreferences
- /g, writeAnchorTag);
- */
- text = text.replace(/(\[([^\[\]]+)\])()()()()()/g, writeAnchorTag);
-
- return text;
+ //
+ // First, handle reference-style links: [link text] [id]
+ //
+
+ /*
+ text = text.replace(/
+ ( // wrap whole match in $1
+ \[
+ (
+ (?:
+ \[[^\]]*\] // allow brackets nested one level
+ |
+ [^\[] // or anything else
+ )*
+ )
+ \]
+
+ [ ]? // one optional space
+ (?:\n[ ]*)? // one optional newline followed by spaces
+
+ \[
+ (.*?) // id = $3
+ \]
+ )()()()() // pad remaining backreferences
+ /g,_DoAnchors_callback);
+ */
+ text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,writeAnchorTag);
+
+ //
+ // Next, inline-style links: [link text](url "optional title")
+ //
+
+ /*
+ text = text.replace(/
+ ( // wrap whole match in $1
+ \[
+ (
+ (?:
+ \[[^\]]*\] // allow brackets nested one level
+ |
+ [^\[\]] // or anything else
+ )
+ )
+ \]
+ \( // literal paren
+ [ \t]*
+ () // no id, so leave $3 empty
+ <?(.*?)>? // href = $4
+ [ \t]*
+ ( // $5
+ (['"]) // quote char = $6
+ (.*?) // Title = $7
+ \6 // matching quote
+ [ \t]* // ignore any spaces/tabs between closing quote and )
+ )? // title is optional
+ \)
+ )
+ /g,writeAnchorTag);
+ */
+ text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()<?(.*?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,writeAnchorTag);
+
+ //
+ // Last, handle reference-style shortcuts: [link text]
+ // These must come last in case you've also got [link test][1]
+ // or [link test](/foo)
+ //
+
+ /*
+ text = text.replace(/
+ ( // wrap whole match in $1
+ \[
+ ([^\[\]]+) // link text = $2; can't contain '[' or ']'
+ \]
+ )()()()()() // pad rest of backreferences
+ /g, writeAnchorTag);
+ */
+ text = text.replace(/(\[([^\[\]]+)\])()()()()()/g, writeAnchorTag);
+
+ return text;
}
var writeAnchorTag = function(wholeMatch,m1,m2,m3,m4,m5,m6,m7) {
- if (m7 == undefined) m7 = "";
- var whole_match = m1;
- var link_text = m2;
- var link_id = m3.toLowerCase();
- var url = m4;
- var title = m7;
-
- if (url == "") {
- if (link_id == "") {
- // lower-case and turn embedded newlines into spaces
- link_id = link_text.toLowerCase().replace(/ ?\n/g," ");
- }
- url = "#"+link_id;
-
- if (g_urls[link_id] != undefined) {
- url = g_urls[link_id];
- if (g_titles[link_id] != undefined) {
- title = g_titles[link_id];
- }
- }
- else {
- if (whole_match.search(/\(\s*\)$/m)>-1) {
- // Special case for explicit empty url
- url = "";
- } else {
- return whole_match;
- }
- }
- }
-
- url = escapeCharacters(url,"*_");
- var result = "<a href=\"" + url + "\"";
-
- if (title != "") {
- title = title.replace(/"/g,"&quot;");
- title = escapeCharacters(title,"*_");
- result += " title=\"" + title + "\"";
- }
-
- result += ">" + link_text + "</a>";
-
- return result;
+ if (m7 == undefined) m7 = "";
+ var whole_match = m1;
+ var link_text = m2;
+ var link_id = m3.toLowerCase();
+ var url = m4;
+ var title = m7;
+
+ if (url == "") {
+ if (link_id == "") {
+ // lower-case and turn embedded newlines into spaces
+ link_id = link_text.toLowerCase().replace(/ ?\n/g," ");
+ }
+ url = "#"+link_id;
+
+ if (g_urls[link_id] != undefined) {
+ url = g_urls[link_id];
+ if (g_titles[link_id] != undefined) {
+ title = g_titles[link_id];
+ }
+ }
+ else {
+ if (whole_match.search(/\(\s*\)$/m)>-1) {
+ // Special case for explicit empty url
+ url = "";
+ } else {
+ return whole_match;
+ }
+ }
+ }
+
+ url = escapeCharacters(url,"*_");
+ var result = "<a href=\"" + url + "\"";
+
+ if (title != "") {
+ title = title.replace(/"/g,"&quot;");
+ title = escapeCharacters(title,"*_");
+ result += " title=\"" + title + "\"";
+ }
+
+ result += ">" + link_text + "</a>";
+
+ return result;
}
@@ -656,146 +656,146 @@ var _DoImages = function(text) {
// Turn Markdown image shortcuts into <img> tags.
//
- //
- // First, handle reference-style labeled images: ![alt text][id]
- //
-
- /*
- text = text.replace(/
- ( // wrap whole match in $1
- !\[
- (.*?) // alt text = $2
- \]
-
- [ ]? // one optional space
- (?:\n[ ]*)? // one optional newline followed by spaces
-
- \[
- (.*?) // id = $3
- \]
- )()()()() // pad rest of backreferences
- /g,writeImageTag);
- */
- text = text.replace(/(!\[(.*?)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,writeImageTag);
-
- //
- // Next, handle inline images: ![alt text](url "optional title")
- // Don't forget: encode * and _
-
- /*
- text = text.replace(/
- ( // wrap whole match in $1
- !\[
- (.*?) // alt text = $2
- \]
- \s? // One optional whitespace character
- \( // literal paren
- [ \t]*
- () // no id, so leave $3 empty
- <?(\S+?)>? // src url = $4
- [ \t]*
- ( // $5
- (['"]) // quote char = $6
- (.*?) // title = $7
- \6 // matching quote
- [ \t]*
- )? // title is optional
- \)
- )
- /g,writeImageTag);
- */
- text = text.replace(/(!\[(.*?)\]\s?\([ \t]*()<?(\S+?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,writeImageTag);
-
- return text;
+ //
+ // First, handle reference-style labeled images: ![alt text][id]
+ //
+
+ /*
+ text = text.replace(/
+ ( // wrap whole match in $1
+ !\[
+ (.*?) // alt text = $2
+ \]
+
+ [ ]? // one optional space
+ (?:\n[ ]*)? // one optional newline followed by spaces
+
+ \[
+ (.*?) // id = $3
+ \]
+ )()()()() // pad rest of backreferences
+ /g,writeImageTag);
+ */
+ text = text.replace(/(!\[(.*?)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,writeImageTag);
+
+ //
+ // Next, handle inline images: ![alt text](url "optional title")
+ // Don't forget: encode * and _
+
+ /*
+ text = text.replace(/
+ ( // wrap whole match in $1
+ !\[
+ (.*?) // alt text = $2
+ \]
+ \s? // One optional whitespace character
+ \( // literal paren
+ [ \t]*
+ () // no id, so leave $3 empty
+ <?(\S+?)>? // src url = $4
+ [ \t]*
+ ( // $5
+ (['"]) // quote char = $6
+ (.*?) // title = $7
+ \6 // matching quote
+ [ \t]*
+ )? // title is optional
+ \)
+ )
+ /g,writeImageTag);
+ */
+ text = text.replace(/(!\[(.*?)\]\s?\([ \t]*()<?(\S+?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,writeImageTag);
+
+ return text;
}
var writeImageTag = function(wholeMatch,m1,m2,m3,m4,m5,m6,m7) {
- var whole_match = m1;
- var alt_text = m2;
- var link_id = m3.toLowerCase();
- var url = m4;
- var title = m7;
-
- if (!title) title = "";
-
- if (url == "") {
- if (link_id == "") {
- // lower-case and turn embedded newlines into spaces
- link_id = alt_text.toLowerCase().replace(/ ?\n/g," ");
- }
- url = "#"+link_id;
-
- if (g_urls[link_id] != undefined) {
- url = g_urls[link_id];
- if (g_titles[link_id] != undefined) {
- title = g_titles[link_id];
- }
- }
- else {
- return whole_match;
- }
- }
-
- alt_text = alt_text.replace(/"/g,"&quot;");
- url = escapeCharacters(url,"*_");
- var result = "<img src=\"" + url + "\" alt=\"" + alt_text + "\"";
-
- // attacklab: Markdown.pl adds empty title attributes to images.
- // Replicate this bug.
-
- //if (title != "") {
- title = title.replace(/"/g,"&quot;");
- title = escapeCharacters(title,"*_");
- result += " title=\"" + title + "\"";
- //}
-
- result += " />";
-
- return result;
+ var whole_match = m1;
+ var alt_text = m2;
+ var link_id = m3.toLowerCase();
+ var url = m4;
+ var title = m7;
+
+ if (!title) title = "";
+
+ if (url == "") {
+ if (link_id == "") {
+ // lower-case and turn embedded newlines into spaces
+ link_id = alt_text.toLowerCase().replace(/ ?\n/g," ");
+ }
+ url = "#"+link_id;
+
+ if (g_urls[link_id] != undefined) {
+ url = g_urls[link_id];
+ if (g_titles[link_id] != undefined) {
+ title = g_titles[link_id];
+ }
+ }
+ else {
+ return whole_match;
+ }
+ }
+
+ alt_text = alt_text.replace(/"/g,"&quot;");
+ url = escapeCharacters(url,"*_");
+ var result = "<img src=\"" + url + "\" alt=\"" + alt_text + "\"";
+
+ // attacklab: Markdown.pl adds empty title attributes to images.
+ // Replicate this bug.
+
+ //if (title != "") {
+ title = title.replace(/"/g,"&quot;");
+ title = escapeCharacters(title,"*_");
+ result += " title=\"" + title + "\"";
+ //}
+
+ result += " />";
+
+ return result;
}
var _DoHeaders = function(text) {
- // Setext-style headers:
- // Header 1
- // ========
- //
- // Header 2
- // --------
- //
- text = text.replace(/^(.+)[ \t]*\n=+[ \t]*\n+/gm,
- function(wholeMatch,m1){return hashBlock("<h1>" + _RunSpanGamut(m1) + "</h1>");});
-
- text = text.replace(/^(.+)[ \t]*\n-+[ \t]*\n+/gm,
- function(matchFound,m1){return hashBlock("<h2>" + _RunSpanGamut(m1) + "</h2>");});
-
- // atx-style headers:
- // # Header 1
- // ## Header 2
- // ## Header 2 with closing hashes ##
- // ...
- // ###### Header 6
- //
-
- /*
- text = text.replace(/
- ^(\#{1,6}) // $1 = string of #'s
- [ \t]*
- (.+?) // $2 = Header text
- [ \t]*
- \#* // optional closing #'s (not counted)
- \n+
- /gm, function() {...});
- */
-
- text = text.replace(/^(\#{1,6})[ \t]*(.+?)[ \t]*\#*\n+/gm,
- function(wholeMatch,m1,m2) {
- var h_level = m1.length;
- return hashBlock("<h" + h_level + ">" + _RunSpanGamut(m2) + "</h" + h_level + ">");
- });
-
- return text;
+ // Setext-style headers:
+ // Header 1
+ // ========
+ //
+ // Header 2
+ // --------
+ //
+ text = text.replace(/^(.+)[ \t]*\n=+[ \t]*\n+/gm,
+ function(wholeMatch,m1){return hashBlock("<h1>" + _RunSpanGamut(m1) + "</h1>");});
+
+ text = text.replace(/^(.+)[ \t]*\n-+[ \t]*\n+/gm,
+ function(matchFound,m1){return hashBlock("<h2>" + _RunSpanGamut(m1) + "</h2>");});
+
+ // atx-style headers:
+ // # Header 1
+ // ## Header 2
+ // ## Header 2 with closing hashes ##
+ // ...
+ // ###### Header 6
+ //
+
+ /*
+ text = text.replace(/
+ ^(\#{1,6}) // $1 = string of #'s
+ [ \t]*
+ (.+?) // $2 = Header text
+ [ \t]*
+ \#* // optional closing #'s (not counted)
+ \n+
+ /gm, function() {...});
+ */
+
+ text = text.replace(/^(\#{1,6})[ \t]*(.+?)[ \t]*\#*\n+/gm,
+ function(wholeMatch,m1,m2) {
+ var h_level = m1.length;
+ return hashBlock("<h" + h_level + ">" + _RunSpanGamut(m2) + "</h" + h_level + ">");
+ });
+
+ return text;
}
// This declaration keeps Dojo compressor from outputting garbage:
@@ -806,144 +806,144 @@ var _DoLists = function(text) {
// Form HTML ordered (numbered) and unordered (bulleted) lists.
//
- // attacklab: add sentinel to hack around khtml/safari bug:
- // http://bugs.webkit.org/show_bug.cgi?id=11231
- text += "~0";
-
- // Re-usable pattern to match any entirel ul or ol list:
-
- /*
- var whole_list = /
- ( // $1 = whole list
- ( // $2
- [ ]{0,3} // attacklab: g_tab_width - 1
- ([*+-]|\d+[.]) // $3 = first list item marker
- [ \t]+
- )
- [^\r]+?
- ( // $4
- ~0 // sentinel for workaround; should be $
- |
- \n{2,}
- (?=\S)
- (?! // Negative lookahead for another list item marker
- [ \t]*
- (?:[*+-]|\d+[.])[ \t]+
- )
- )
- )/g
- */
- var whole_list = /^(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;
-
- if (g_list_level) {
- text = text.replace(whole_list,function(wholeMatch,m1,m2) {
- var list = m1;
- var list_type = (m2.search(/[*+-]/g)>-1) ? "ul" : "ol";
-
- // Turn double returns into triple returns, so that we can make a
- // paragraph for the last item in a list, if necessary:
- list = list.replace(/\n{2,}/g,"\n\n\n");;
- var result = _ProcessListItems(list);
-
- // Trim any trailing whitespace, to put the closing `</$list_type>`
- // up on the preceding line, to get it past the current stupid
- // HTML block parser. This is a hack to work around the terrible
- // hack that is the HTML block parser.
- result = result.replace(/\s+$/,"");
- result = "<"+list_type+">" + result + "</"+list_type+">\n";
- return result;
- });
- } else {
- whole_list = /(\n\n|^\n?)(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/g;
- text = text.replace(whole_list,function(wholeMatch,m1,m2,m3) {
- var runup = m1;
- var list = m2;
-
- var list_type = (m3.search(/[*+-]/g)>-1) ? "ul" : "ol";
- // Turn double returns into triple returns, so that we can make a
- // paragraph for the last item in a list, if necessary:
- var list = list.replace(/\n{2,}/g,"\n\n\n");;
- var result = _ProcessListItems(list);
- result = runup + "<"+list_type+">\n" + result + "</"+list_type+">\n";
- return result;
- });
- }
-
- // attacklab: strip sentinel
- text = text.replace(/~0/,"");
-
- return text;
+ // attacklab: add sentinel to hack around khtml/safari bug:
+ // http://bugs.webkit.org/show_bug.cgi?id=11231
+ text += "~0";
+
+ // Re-usable pattern to match any entirel ul or ol list:
+
+ /*
+ var whole_list = /
+ ( // $1 = whole list
+ ( // $2
+ [ ]{0,3} // attacklab: g_tab_width - 1
+ ([*+-]|\d+[.]) // $3 = first list item marker
+ [ \t]+
+ )
+ [^\r]+?
+ ( // $4
+ ~0 // sentinel for workaround; should be $
+ |
+ \n{2,}
+ (?=\S)
+ (?! // Negative lookahead for another list item marker
+ [ \t]*
+ (?:[*+-]|\d+[.])[ \t]+
+ )
+ )
+ )/g
+ */
+ var whole_list = /^(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;
+
+ if (g_list_level) {
+ text = text.replace(whole_list,function(wholeMatch,m1,m2) {
+ var list = m1;
+ var list_type = (m2.search(/[*+-]/g)>-1) ? "ul" : "ol";
+
+ // Turn double returns into triple returns, so that we can make a
+ // paragraph for the last item in a list, if necessary:
+ list = list.replace(/\n{2,}/g,"\n\n\n");;
+ var result = _ProcessListItems(list);
+
+ // Trim any trailing whitespace, to put the closing `</$list_type>`
+ // up on the preceding line, to get it past the current stupid
+ // HTML block parser. This is a hack to work around the terrible
+ // hack that is the HTML block parser.
+ result = result.replace(/\s+$/,"");
+ result = "<"+list_type+">" + result + "</"+list_type+">\n";
+ return result;
+ });
+ } else {
+ whole_list = /(\n\n|^\n?)(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/g;
+ text = text.replace(whole_list,function(wholeMatch,m1,m2,m3) {
+ var runup = m1;
+ var list = m2;
+
+ var list_type = (m3.search(/[*+-]/g)>-1) ? "ul" : "ol";
+ // Turn double returns into triple returns, so that we can make a
+ // paragraph for the last item in a list, if necessary:
+ var list = list.replace(/\n{2,}/g,"\n\n\n");;
+ var result = _ProcessListItems(list);
+ result = runup + "<"+list_type+">\n" + result + "</"+list_type+">\n";
+ return result;
+ });
+ }
+
+ // attacklab: strip sentinel
+ text = text.replace(/~0/,"");
+
+ return text;
}
_ProcessListItems = function(list_str) {
//
// Process the contents of a single ordered or unordered list, splitting it
// into individual list items.
//
- // The $g_list_level global keeps track of when we're inside a list.
- // Each time we enter a list, we increment it; when we leave a list,
- // we decrement. If it's zero, we're not in a list anymore.
- //
- // We do this because when we're not inside a list, we want to treat
- // something like this:
- //
- // I recommend upgrading to version
- // 8. Oops, now this line is treated
- // as a sub-list.
- //
- // As a single paragraph, despite the fact that the second line starts
- // with a digit-period-space sequence.
- //
- // Whereas when we're inside a list (or sub-list), that line will be
- // treated as the start of a sub-list. What a kludge, huh? This is
- // an aspect of Markdown's syntax that's hard to parse perfectly
- // without resorting to mind-reading. Perhaps the solution is to
- // change the syntax rules such that sub-lists must start with a
- // starting cardinal number; e.g. "1." or "a.".
-
- g_list_level++;
-
- // trim trailing blank lines:
- list_str = list_str.replace(/\n{2,}$/,"\n");
-
- // attacklab: add sentinel to emulate \z
- list_str += "~0";
-
- /*
- list_str = list_str.replace(/
- (\n)? // leading line = $1
- (^[ \t]*) // leading whitespace = $2
- ([*+-]|\d+[.]) [ \t]+ // list marker = $3
- ([^\r]+? // list item text = $4
- (\n{1,2}))
- (?= \n* (~0 | \2 ([*+-]|\d+[.]) [ \t]+))
- /gm, function(){...});
- */
- list_str = list_str.replace(/(\n)?(^[ \t]*)([*+-]|\d+[.])[ \t]+([^\r]+?(\n{1,2}))(?=\n*(~0|\2([*+-]|\d+[.])[ \t]+))/gm,
- function(wholeMatch,m1,m2,m3,m4){
- var item = m4;
- var leading_line = m1;
- var leading_space = m2;
-
- if (leading_line || (item.search(/\n{2,}/)>-1)) {
- item = _RunBlockGamut(_Outdent(item));
- }
- else {
- // Recursion for sub-lists:
- item = _DoLists(_Outdent(item));
- item = item.replace(/\n$/,""); // chomp(item)
- item = _RunSpanGamut(item);
- }
-
- return "<li>" + item + "</li>\n";
- }
- );
-
- // attacklab: strip sentinel
- list_str = list_str.replace(/~0/g,"");
-
- g_list_level--;
- return list_str;
+ // The $g_list_level global keeps track of when we're inside a list.
+ // Each time we enter a list, we increment it; when we leave a list,
+ // we decrement. If it's zero, we're not in a list anymore.
+ //
+ // We do this because when we're not inside a list, we want to treat
+ // something like this:
+ //
+ // I recommend upgrading to version
+ // 8. Oops, now this line is treated
+ // as a sub-list.
+ //
+ // As a single paragraph, despite the fact that the second line starts
+ // with a digit-period-space sequence.
+ //
+ // Whereas when we're inside a list (or sub-list), that line will be
+ // treated as the start of a sub-list. What a kludge, huh? This is
+ // an aspect of Markdown's syntax that's hard to parse perfectly
+ // without resorting to mind-reading. Perhaps the solution is to
+ // change the syntax rules such that sub-lists must start with a
+ // starting cardinal number; e.g. "1." or "a.".
+
+ g_list_level++;
+
+ // trim trailing blank lines:
+ list_str = list_str.replace(/\n{2,}$/,"\n");
+
+ // attacklab: add sentinel to emulate \z
+ list_str += "~0";
+
+ /*
+ list_str = list_str.replace(/
+ (\n)? // leading line = $1
+ (^[ \t]*) // leading whitespace = $2
+ ([*+-]|\d+[.]) [ \t]+ // list marker = $3
+ ([^\r]+? // list item text = $4
+ (\n{1,2}))
+ (?= \n* (~0 | \2 ([*+-]|\d+[.]) [ \t]+))
+ /gm, function(){...});
+ */
+ list_str = list_str.replace(/(\n)?(^[ \t]*)([*+-]|\d+[.])[ \t]+([^\r]+?(\n{1,2}))(?=\n*(~0|\2([*+-]|\d+[.])[ \t]+))/gm,
+ function(wholeMatch,m1,m2,m3,m4){
+ var item = m4;
+ var leading_line = m1;
+ var leading_space = m2;
+
+ if (leading_line || (item.search(/\n{2,}/)>-1)) {
+ item = _RunBlockGamut(_Outdent(item));
+ }
+ else {
+ // Recursion for sub-lists:
+ item = _DoLists(_Outdent(item));
+ item = item.replace(/\n$/,""); // chomp(item)
+ item = _RunSpanGamut(item);
+ }
+
+ return "<li>" + item + "</li>\n";
+ }
+ );
+
+ // attacklab: strip sentinel
+ list_str = list_str.replace(/~0/g,"");
+
+ g_list_level--;
+ return list_str;
}
@@ -952,71 +952,71 @@ var _DoCodeBlocks = function(text) {
// Process Markdown `<pre><code>` blocks.
//
- /*
- text = text.replace(text,
- /(?:\n\n|^)
- ( // $1 = the code block -- one or more lines, starting with a space/tab
- (?:
- (?:[ ]{4}|\t) // Lines must start with a tab or a tab-width of spaces - attacklab: g_tab_width
- .*\n+
- )+
- )
- (\n*[ ]{0,3}[^ \t\n]|(?=~0)) // attacklab: g_tab_width
- /g,function(){...});
- */
+ /*
+ text = text.replace(text,
+ /(?:\n\n|^)
+ ( // $1 = the code block -- one or more lines, starting with a space/tab
+ (?:
+ (?:[ ]{4}|\t) // Lines must start with a tab or a tab-width of spaces - attacklab: g_tab_width
+ .*\n+
+ )+
+ )
+ (\n*[ ]{0,3}[^ \t\n]|(?=~0)) // attacklab: g_tab_width
+ /g,function(){...});
+ */
- // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug
- text += "~0";
+ // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug
+ text += "~0";
- text = text.replace(/(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g,
- function(wholeMatch,m1,m2) {
- var codeblock = m1;
- var nextChar = m2;
+ text = text.replace(/(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g,
+ function(wholeMatch,m1,m2) {
+ var codeblock = m1;
+ var nextChar = m2;
- codeblock = _EncodeCode( _Outdent(codeblock));
- codeblock = _Detab(codeblock);
- codeblock = codeblock.replace(/^\n+/g,""); // trim leading newlines
- codeblock = codeblock.replace(/\n+$/g,""); // trim trailing whitespace
+ codeblock = _EncodeCode( _Outdent(codeblock));
+ codeblock = _Detab(codeblock);
+ codeblock = codeblock.replace(/^\n+/g,""); // trim leading newlines
+ codeblock = codeblock.replace(/\n+$/g,""); // trim trailing whitespace
- codeblock = "<pre><code>" + codeblock + "\n</code></pre>";
+ codeblock = "<pre><code>" + codeblock + "\n</code></pre>";
- return hashBlock(codeblock) + nextChar;
- }
- );
+ return hashBlock(codeblock) + nextChar;
+ }
+ );
- // attacklab: strip sentinel
- text = text.replace(/~0/,"");
+ // attacklab: strip sentinel
+ text = text.replace(/~0/,"");
- return text;
+ return text;
}
var _DoGFMCodeBlocks = function(text) { // ypocat
- text = text.replace(/(?:\n|^)`{3,4}(\w+)((?:\n+.+?)+?)\n*`{3,4}(?:\n|$)/g,
+ text = text.replace(/(?:\n|^)`{3,4}(\w+)((?:\n+.+?)+?)\n*`{3,4}(?:\n|$)/g,
- function(wholeMatch,m1,m2) {
- var lang = m1;
- var codeblock = m2;
+ function(wholeMatch,m1,m2) {
+ var lang = m1;
+ var codeblock = m2;
- codeblock = _EncodeCode(codeblock);
- codeblock = _Detab(codeblock);
- codeblock = codeblock.replace(/^\n+/g,""); // trim leading newlines
- codeblock = codeblock.replace(/\n+$/g,""); // trim trailing whitespace
+ codeblock = _EncodeCode(codeblock);
+ codeblock = _Detab(codeblock);
+ codeblock = codeblock.replace(/^\n+/g,""); // trim leading newlines
+ codeblock = codeblock.replace(/\n+$/g,""); // trim trailing whitespace
- codeblock = "<div class='highlight'><pre><code>" + codeblock + "\n</code></pre></div>";
+ codeblock = "<div class='highlight'><pre><code>" + codeblock + "\n</code></pre></div>";
- return hashBlock(codeblock);
- }
- );
+ return hashBlock(codeblock);
+ }
+ );
- return text;
+ return text;
}
var hashBlock = function(text) {
- text = text.replace(/(^\n+|\n+$)/g,"");
- return "\n\n~K" + (g_html_blocks.push(text)-1) + "K\n\n";
+ text = text.replace(/(^\n+|\n+$)/g,"");
+ return "\n\n~K" + (g_html_blocks.push(text)-1) + "K\n\n";
}
@@ -1025,50 +1025,50 @@ var _DoCodeSpans = function(text) {
// * Backtick quotes are used for <code></code> spans.
//
// * You can use multiple backticks as the delimiters if you want to
-// include literal backticks in the code span. So, this input:
+// include literal backticks in the code span. So, this input:
//
-// Just type ``foo `bar` baz`` at the prompt.
+// Just type ``foo `bar` baz`` at the prompt.
//
-// Will translate to:
+// Will translate to:
//
-// <p>Just type <code>foo `bar` baz</code> at the prompt.</p>
+// <p>Just type <code>foo `bar` baz</code> at the prompt.</p>
//
-// There's no arbitrary limit to the number of backticks you
-// can use as delimters. If you need three consecutive backticks
-// in your code, use four for delimiters, etc.
+// There's no arbitrary limit to the number of backticks you
+// can use as delimters. If you need three consecutive backticks
+// in your code, use four for delimiters, etc.
//
// * You can use spaces to get literal backticks at the edges:
//
-// ... type `` `bar` `` ...
+// ... type `` `bar` `` ...
//
-// Turns to:
+// Turns to:
//
-// ... type <code>`bar`</code> ...
+// ... type <code>`bar`</code> ...
//
- /*
- text = text.replace(/
- (^|[^\\]) // Character before opening ` can't be a backslash
- (`+) // $2 = Opening run of `
- ( // $3 = The code block
- [^\r]*?
- [^`] // attacklab: work around lack of lookbehind
- )
- \2 // Matching closer
- (?!`)
- /gm, function(){...});
- */
+ /*
+ text = text.replace(/
+ (^|[^\\]) // Character before opening ` can't be a backslash
+ (`+) // $2 = Opening run of `
+ ( // $3 = The code block
+ [^\r]*?
+ [^`] // attacklab: work around lack of lookbehind
+ )
+ \2 // Matching closer
+ (?!`)
+ /gm, function(){...});
+ */
- text = text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,
- function(wholeMatch,m1,m2,m3,m4) {
- var c = m3;
- c = c.replace(/^([ \t]*)/g,""); // leading whitespace
- c = c.replace(/[ \t]*$/g,""); // trailing whitespace
- c = _EncodeCode(c);
- return m1+"<code>"+c+"</code>";
- });
+ text = text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,
+ function(wholeMatch,m1,m2,m3,m4) {
+ var c = m3;
+ c = c.replace(/^([ \t]*)/g,""); // leading whitespace
+ c = c.replace(/[ \t]*$/g,""); // trailing whitespace
+ c = _EncodeCode(c);
+ return m1+"<code>"+c+"</code>";
+ });
- return text;
+ return text;
}
@@ -1078,16 +1078,16 @@ var _EncodeCode = function(text) {
// The point is that in code, these characters are literals,
// and lose their special Markdown meanings.
//
- // Encode all ampersands; HTML entities are not
- // entities within a Markdown code span.
- text = text.replace(/&/g,"&amp;");
+ // Encode all ampersands; HTML entities are not
+ // entities within a Markdown code span.
+ text = text.replace(/&/g,"&amp;");
- // Do the angle bracket song and dance:
- text = text.replace(/</g,"&lt;");
- text = text.replace(/>/g,"&gt;");
+ // Do the angle bracket song and dance:
+ text = text.replace(/</g,"&lt;");
+ text = text.replace(/>/g,"&gt;");
- // Now, escape characters that are magic in Markdown:
- text = escapeCharacters(text,"\*_{}[]\\",false);
+ // Now, escape characters that are magic in Markdown:
+ text = escapeCharacters(text,"\*_{}[]\\",false);
// jj the line above breaks this:
//---
@@ -1099,69 +1099,69 @@ var _EncodeCode = function(text) {
// special char: *
//---
- return text;
+ return text;
}
var _DoItalicsAndBold = function(text) {
- // <strong> must go first:
- text = text.replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g,
- "<strong>$2</strong>");
+ // <strong> must go first:
+ text = text.replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g,
+ "<strong>$2</strong>");
- text = text.replace(/(\w)_(\w)/g, "$1~E95E$2") // ** GFM ** "~E95E" == escaped "_"
- text = text.replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g,
- "<em>$2</em>");
+ text = text.replace(/(\w)_(\w)/g, "$1~E95E$2") // ** GFM ** "~E95E" == escaped "_"
+ text = text.replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g,
+ "<em>$2</em>");
- return text;
+ return text;
}
var _DoBlockQuotes = function(text) {
- /*
- text = text.replace(/
- ( // Wrap whole match in $1
- (
- ^[ \t]*>[ \t]? // '>' at the start of a line
- .+\n // rest of the first line
- (.+\n)* // subsequent consecutive lines
- \n* // blanks
- )+
- )
- /gm, function(){...});
- */
-
- text = text.replace(/((^[ \t]*>[ \t]?.+\n(.+\n)*\n*)+)/gm,
- function(wholeMatch,m1) {
- var bq = m1;
-
- // attacklab: hack around Konqueror 3.5.4 bug:
- // "----------bug".replace(/^-/g,"") == "bug"
-
- bq = bq.replace(/^[ \t]*>[ \t]?/gm,"~0"); // trim one level of quoting
-
- // attacklab: clean up hack
- bq = bq.replace(/~0/g,"");
-
- bq = bq.replace(/^[ \t]+$/gm,""); // trim whitespace-only lines
- bq = _RunBlockGamut(bq); // recurse
-
- bq = bq.replace(/(^|\n)/g,"$1 ");
- // These leading spaces screw with <pre> content, so we need to fix that:
- bq = bq.replace(
- /(\s*<pre>[^\r]+?<\/pre>)/gm,
- function(wholeMatch,m1) {
- var pre = m1;
- // attacklab: hack around Konqueror 3.5.4 bug:
- pre = pre.replace(/^ /mg,"~0");
- pre = pre.replace(/~0/g,"");
- return pre;
- });
-
- return hashBlock("<blockquote>\n" + bq + "\n</blockquote>");
- });
- return text;
+ /*
+ text = text.replace(/
+ ( // Wrap whole match in $1
+ (
+ ^[ \t]*>[ \t]? // '>' at the start of a line