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

View File

@ -5,32 +5,24 @@
// Private properties // Private properties
var showdown = {}, var showdown = {},
parsers = {}, parsers = {},
extensions = {},
globalOptions = { globalOptions = {
omitExtraWLInCodeBlocks: false, omitExtraWLInCodeBlocks: false,
prefixHeaderId: false prefixHeaderId: false
}; };
///////////////////////////////////////////////////////////////////////////
// Public API
//
/** /**
* helper namespace * helper namespace
* @type {{}} * @type {{}}
*/ */
showdown.helper = {}; showdown.helper = {};
///////////////////////////////////////////////////////////////////////////
// API
//
// Public properties // Public properties
showdown.extensions = {}; showdown.extensions = {};
//Public methods
/** /**
* Set a global option * Set a global option
* * @static
* @param {string} key * @param {string} key
* @param {string} value * @param {string} value
* @returns {showdown} * @returns {showdown}
@ -43,7 +35,7 @@ showdown.setOption = function (key, value) {
/** /**
* Get a global option * Get a global option
* * @static
* @param {string} key * @param {string} key
* @returns {*} * @returns {*}
*/ */
@ -54,6 +46,7 @@ showdown.getOption = function (key) {
/** /**
* Get the global options * Get the global options
* @static
* @returns {{omitExtraWLInCodeBlocks: boolean, prefixHeaderId: boolean}} * @returns {{omitExtraWLInCodeBlocks: boolean, prefixHeaderId: boolean}}
*/ */
showdown.getOptions = function () { showdown.getOptions = function () {
@ -66,6 +59,7 @@ showdown.getOptions = function () {
* *
* subParser(name) - Get a registered subParser * subParser(name) - Get a registered subParser
* subParser(name, func) - Register a subParser * subParser(name, func) - Register a subParser
* @static
* @param {string} name * @param {string} name
* @param {function} [func] * @param {function} [func]
* @returns {*} * @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 * Showdown Converter class
* *
@ -97,10 +132,9 @@ showdown.Converter = function (converterOptions) {
converterOptions = converterOptions || {}; converterOptions = converterOptions || {};
var options = globalOptions, var options = globalOptions,
langExtensions = [],
outputModifiers = [],
parserOrder = [ parserOrder = [
'detab',
'stripBlankLines',
//runLanguageExtensions,
'githubCodeBlocks', 'githubCodeBlocks',
'hashHTMLBlocks', 'hashHTMLBlocks',
'stripLinkDefinitions', '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 * Converts a markdown string into HTML
* @param {string} text * @param {string} text
@ -134,7 +200,9 @@ showdown.Converter = function (converterOptions) {
gUrls: {}, gUrls: {},
gTitles: {}, gTitles: {},
gListLevel: 0, gListLevel: 0,
hashLinkCounts: {} hashLinkCounts: {},
langExtensions: langExtensions,
outputModifiers: outputModifiers
}; };
// attacklab: Replace ~ with ~T // attacklab: Replace ~ with ~T
@ -155,6 +223,15 @@ showdown.Converter = function (converterOptions) {
// Make sure text begins and ends with a couple of newlines: // Make sure text begins and ends with a couple of newlines:
text = '\n\n' + text + '\n\n'; 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 // Run all registered parsers
for (var i = 0; i < parserOrder.length; ++i) { for (var i = 0; i < parserOrder.length; ++i) {
var name = parserOrder[i]; var name = parserOrder[i];
@ -168,9 +245,7 @@ showdown.Converter = function (converterOptions) {
text = text.replace(/~T/g, '~'); text = text.replace(/~T/g, '~');
// Run output modifiers // Run output modifiers
//showdown.forEach(g_output_modifiers, function (x) { text = parsers.outputModifiers(text, options, globals);
// text = _ExecuteExtension(x, text);
//});
return text; 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);
}
});