FIX: Markdown references within a list were not working properly.

This commit is contained in:
Robin Ward 2013-08-28 13:06:41 -04:00
parent f7ad80ff7b
commit 550ef104c6
2 changed files with 51 additions and 26 deletions

View file

@ -8,6 +8,8 @@
* We don't escape the contents of HTML as we prefer to use a whitelist. * We don't escape the contents of HTML as we prefer to use a whitelist.
* We fixed a bug where references can be created directly following a list.
* Note the name BetterMarkdown doesn't mean it's *better* than markdown-js, it refers * Note the name BetterMarkdown doesn't mean it's *better* than markdown-js, it refers
to it being better than our previous markdown parser! to it being better than our previous markdown parser!
@ -205,6 +207,35 @@ Markdown.prototype.split_blocks = function splitBlocks( input, startLine ) {
return blocks; return blocks;
}; };
function create_attrs() {
if ( !extract_attr( this.tree ) ) {
this.tree.splice( 1, 0, {} );
}
var attrs = extract_attr( this.tree );
// make a references hash if it doesn't exist
if ( attrs.references === undefined ) {
attrs.references = {};
}
return attrs;
}
function create_reference(attrs, m) {
if ( m[2] && m[2][0] == "<" && m[2][m[2].length-1] == ">" )
m[2] = m[2].substring( 1, m[2].length - 1 );
var ref = attrs.references[ m[1].toLowerCase() ] = {
href: m[2]
};
if ( m[4] !== undefined )
ref.title = m[4];
else if ( m[5] !== undefined )
ref.title = m[5];
}
/** /**
* Markdown#processBlock( block, next ) -> undefined | [ JsonML, ... ] * Markdown#processBlock( block, next ) -> undefined | [ JsonML, ... ]
* - block (String): the block to process * - block (String): the block to process
@ -531,6 +562,7 @@ Markdown.dialects.Gruber = {
// The matcher function // The matcher function
return function( block, next ) { return function( block, next ) {
var m = block.match( is_list_re ); var m = block.match( is_list_re );
if ( !m ) return undefined; if ( !m ) return undefined;
@ -682,6 +714,7 @@ Markdown.dialects.Gruber = {
})(), })(),
blockquote: function blockquote( block, next ) { blockquote: function blockquote( block, next ) {
if ( !block.match( /^>/m ) ) if ( !block.match( /^>/m ) )
return undefined; return undefined;
@ -736,39 +769,18 @@ Markdown.dialects.Gruber = {
}, },
referenceDefn: function referenceDefn( block, next) { referenceDefn: function referenceDefn( block, next) {
var re = /^\s*\[(.*?)\]:\s*(\S+)(?:\s+(?:(['"])(.*?)\3|\((.*?)\)))?\n?/; var re = /^\s*\[(.*?)\]:\s*(\S+)(?:\s+(?:(['"])(.*?)\3|\((.*?)\)))?\n?/;
// interesting matches are [ , ref_id, url, , title, title ] // interesting matches are [ , ref_id, url, , title, title ]
if ( !block.match(re) ) if ( !block.match(re) )
return undefined; return undefined;
// make an attribute node if it doesn't exist var attrs = create_attrs.call(this);
if ( !extract_attr( this.tree ) ) {
this.tree.splice( 1, 0, {} );
}
var attrs = extract_attr( this.tree );
// make a references hash if it doesn't exist
if ( attrs.references === undefined ) {
attrs.references = {};
}
var b = this.loop_re_over_block(re, block, function( m ) { var b = this.loop_re_over_block(re, block, function( m ) {
create_reference(attrs, m);
if ( m[2] && m[2][0] == "<" && m[2][m[2].length-1] == ">" ) });
m[2] = m[2].substring( 1, m[2].length - 1 );
var ref = attrs.references[ m[1].toLowerCase() ] = {
href: m[2]
};
if ( m[4] !== undefined )
ref.title = m[4];
else if ( m[5] !== undefined )
ref.title = m[5];
} );
if ( b.length ) if ( b.length )
next.unshift( mk_block( b, block.trailing ) ); next.unshift( mk_block( b, block.trailing ) );
@ -891,6 +903,7 @@ Markdown.dialects.Gruber.inline = {
"[": function link( text ) { "[": function link( text ) {
var orig = String(text); var orig = String(text);
// Inline content is possible inside `link text` // Inline content is possible inside `link text`
var res = Markdown.DialectHelpers.inline_until_char.call( this, text.substr(1), "]" ); var res = Markdown.DialectHelpers.inline_until_char.call( this, text.substr(1), "]" );
@ -954,7 +967,6 @@ Markdown.dialects.Gruber.inline = {
m = text.match( /^\s*\[(.*?)\]/ ); m = text.match( /^\s*\[(.*?)\]/ );
if ( m ) { if ( m ) {
consumed += m[ 0 ].length; consumed += m[ 0 ].length;
// [links][] uses links as its reference // [links][] uses links as its reference
@ -968,6 +980,15 @@ Markdown.dialects.Gruber.inline = {
return [ consumed, link ]; return [ consumed, link ];
} }
m = orig.match(/^\s*\[(.*?)\]:\s*(\S+)(?:\s+(?:(['"])(.*?)\3|\((.*?)\)))?\n?/);
if (m) {
var attrs = create_attrs.call(this);
create_reference(attrs, m);
return [ m[0].length ]
}
// [id] // [id]
// Only if id is plain (no formatting.) // Only if id is plain (no formatting.)
if ( children.length == 1 && typeof children[0] == "string" ) { if ( children.length == 1 && typeof children[0] == "string" ) {

View file

@ -103,6 +103,10 @@ test("Links", function() {
"<a href=\"http://www.imdb.com/name/nm2225369\">http://www.imdb.com/name/nm2225369</a></p>", "<a href=\"http://www.imdb.com/name/nm2225369\">http://www.imdb.com/name/nm2225369</a></p>",
'allows multiple links on one line'); 'allows multiple links on one line');
cooked("* [Evil Trout][1]\n [1]: http://eviltrout.com",
"<ul><li><a href=\"http://eviltrout.com\">Evil Trout</a><br></li></ul>",
"allows markdown link references in a list");
}); });
test("Quotes", function() { test("Quotes", function() {