Added new extension registering method

This commit is contained in:
Estevão Soares dos Santos 2015-03-01 18:15:32 +00:00
parent 8ee87ead9f
commit 0fd10cb56a
9 changed files with 150 additions and 27 deletions

BIN
dist/showdown.js vendored

Binary file not shown.

BIN
dist/showdown.js.map vendored

Binary file not shown.

BIN
dist/showdown.min.js vendored

Binary file not shown.

Binary file not shown.

View File

@ -8,6 +8,7 @@ if (!showdown.hasOwnProperty('helper')) {
/**
* Check if var is string
* @static
* @param {string} a
* @returns {boolean}
*/
@ -18,6 +19,7 @@ showdown.helper.isString = function isString(a) {
/**
* ForEach helper function
* @static
* @param {*} obj
* @param {function} callback
*/
@ -26,8 +28,7 @@ showdown.helper.forEach = function forEach(obj, callback) {
if (typeof obj.forEach === 'function') {
obj.forEach(callback);
} else {
var i, len = obj.length;
for (i = 0; i < len; i++) {
for (var i = 0; i < obj.length; i++) {
callback(obj[i], i, obj);
}
}
@ -35,6 +36,7 @@ showdown.helper.forEach = function forEach(obj, callback) {
/**
* isArray helper function
* @static
* @param {*} a
* @returns {boolean}
*/
@ -45,7 +47,6 @@ showdown.helper.isArray = function isArray(a) {
/**
* Check if value is undefined
*
* @static
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.
@ -55,6 +56,17 @@ showdown.helper.isUndefined = function isUndefined(value) {
return typeof value === 'undefined';
};
/**
* Standardidize extension name
* @static
* @param {string} s extension name
* @returns {string}
*/
showdown.helper.stdExtName = function (s) {
'use strict';
return s.replace(/[_-]||\s/g, '').toLowerCase();
};
function escapeCharactersCallback(wholeMatch, m1) {
'use strict';
var charCodeToEscape = m1.charCodeAt(0);
@ -63,6 +75,7 @@ function escapeCharactersCallback(wholeMatch, m1) {
/**
* Callback used to escape characters when passing through String.replace
* @static
* @param {string} wholeMatch
* @param {string} m1
* @returns {string}
@ -71,7 +84,7 @@ showdown.helper.escapeCharactersCallback = escapeCharactersCallback;
/**
* Escape characters in a string
*
* @static
* @param {string} text
* @param {string} charsToEscape
* @param {boolean} afterBackslash

View File

@ -5,32 +5,24 @@
// Private properties
var showdown = {},
parsers = {},
extensions = {},
globalOptions = {
omitExtraWLInCodeBlocks: false,
prefixHeaderId: false
prefixHeaderId: false
};
///////////////////////////////////////////////////////////////////////////
// Public API
//
/**
* helper namespace
* @type {{}}
*/
showdown.helper = {};
///////////////////////////////////////////////////////////////////////////
// API
//
// Public properties
showdown.extensions = {};
//Public methods
/**
* Set a global option
*
* @static
* @param {string} key
* @param {string} value
* @returns {showdown}
@ -43,7 +35,7 @@ showdown.setOption = function (key, value) {
/**
* Get a global option
*
* @static
* @param {string} key
* @returns {*}
*/
@ -54,6 +46,7 @@ showdown.getOption = function (key) {
/**
* Get the global options
* @static
* @returns {{omitExtraWLInCodeBlocks: boolean, prefixHeaderId: boolean}}
*/
showdown.getOptions = function () {
@ -66,6 +59,7 @@ showdown.getOptions = function () {
*
* subParser(name) - Get a registered subParser
* subParser(name, func) - Register a subParser
* @static
* @param {string} name
* @param {function} [func]
* @returns {*}
@ -85,6 +79,47 @@ showdown.subParser = function (name, func) {
}
};
showdown.extension = function (name, ext) {
'use strict';
if (!showdown.helper.isString(name)) {
throw Error('Extension \'name\' must be a string');
}
name = showdown.helper.stdExtName(name);
if (showdown.helper.isUndefined(ext)) {
return getExtension();
} else {
return setExtension();
}
};
function getExtension(name) {
'use strict';
if (!extensions.hasOwnProperty(name)) {
throw Error('Extension named ' + name + ' is not registered!');
}
return extensions[name];
}
function setExtension(name, ext) {
'use strict';
if (typeof ext !== 'object') {
throw Error('A Showdown Extension must be an object, ' + typeof ext + ' given');
}
if (!showdown.helper.isString(ext.type)) {
throw Error('When registering a showdown extension, "type" must be a string, ' + typeof ext.type + ' given');
}
ext.type = ext.type.toLowerCase();
extensions[name] = ext;
}
/**
* Showdown Converter class
*
@ -97,10 +132,9 @@ showdown.Converter = function (converterOptions) {
converterOptions = converterOptions || {};
var options = globalOptions,
langExtensions = [],
outputModifiers = [],
parserOrder = [
'detab',
'stripBlankLines',
//runLanguageExtensions,
'githubCodeBlocks',
'hashHTMLBlocks',
'stripLinkDefinitions',
@ -117,6 +151,38 @@ showdown.Converter = function (converterOptions) {
}
}
// Parse options
if (options.extensions) {
// Iterate over each plugin
showdown.helper.forEach(options.extensions, function (plugin) {
// Assume it's a bundled plugin if a string is given
if (typeof plugin === 'string') {
plugin = extensions[showdown.helper.stdExtName(plugin)];
}
if (typeof plugin === 'function') {
// Iterate over each extension within that plugin
showdown.helper.forEach(plugin(self), function (ext) {
// Sort extensions by type
if (ext.type) {
if (ext.type === 'language' || ext.type === 'lang') {
langExtensions.push(ext);
} else if (ext.type === 'output' || ext.type === 'html') {
outputModifiers.push(ext);
}
} else {
// Assume language extension
outputModifiers.push(ext);
}
});
} else {
throw 'Extension "' + plugin + '" could not be loaded. It was either not found or is not a valid extension.';
}
});
}
/**
* Converts a markdown string into HTML
* @param {string} text
@ -130,11 +196,13 @@ showdown.Converter = function (converterOptions) {
}
var globals = {
gHtmlBlocks: [],
gUrls: {},
gTitles: {},
gListLevel: 0,
hashLinkCounts: {}
gHtmlBlocks: [],
gUrls: {},
gTitles: {},
gListLevel: 0,
hashLinkCounts: {},
langExtensions: langExtensions,
outputModifiers: outputModifiers
};
// attacklab: Replace ~ with ~T
@ -155,6 +223,15 @@ showdown.Converter = function (converterOptions) {
// Make sure text begins and ends with a couple of newlines:
text = '\n\n' + text + '\n\n';
// detab
text = parsers.detab(text, options, globals);
// stripBlankLines
text = parsers.stripBlankLines(text, options, globals);
//run languageExtensions
text = parsers.languageExtensions(text, options, globals);
// Run all registered parsers
for (var i = 0; i < parserOrder.length; ++i) {
var name = parserOrder[i];
@ -168,9 +245,7 @@ showdown.Converter = function (converterOptions) {
text = text.replace(/~T/g, '~');
// Run output modifiers
//showdown.forEach(g_output_modifiers, function (x) {
// text = _ExecuteExtension(x, text);
//});
text = parsers.outputModifiers(text, options, globals);
return text;
}

View File

@ -0,0 +1,11 @@
/**
* Run language extensions
*/
showdown.subParser('languageExtensions', function (text, config, globals) {
'use strict';
showdown.helper.forEach(globals.langExtensions, function (ext) {
text = showdown.subParser('runExtension')(ext, text);
});
return text;
});

View File

@ -0,0 +1,11 @@
/**
* Run language extensions
*/
showdown.subParser('outputModifiers', function (text, config, globals) {
'use strict';
showdown.helper.forEach(globals.outputModifiers, function (ext) {
text = showdown.subParser('runExtension')(ext, text);
});
return text;
});

View File

@ -0,0 +1,13 @@
/**
* Run language extensions
*/
showdown.subParser('runExtension', function (ext, text) {
'use strict';
if (ext.regex) {
var re = new RegExp(ext.regex, 'g');
return text.replace(re, ext.replace);
} else if (ext.filter) {
return ext.filter(text);
}
});