|
@@ -1,4 +1,4 @@
|
|
-;/*! showdown 19-01-2015 */
|
|
|
|
|
|
+;/*! showdown 01-03-2015 */
|
|
(function(){
|
|
(function(){
|
|
/**
|
|
/**
|
|
* Created by Tivie on 06-01-2015.
|
|
* Created by Tivie on 06-01-2015.
|
|
@@ -7,49 +7,61 @@
|
|
// 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
|
|
|
|
+ * @static
|
|
|
|
+ * @param {string} key
|
|
|
|
+ * @param {string} value
|
|
|
|
+ * @returns {showdown}
|
|
|
|
+ */
|
|
showdown.setOption = function (key, value) {
|
|
showdown.setOption = function (key, value) {
|
|
'use strict';
|
|
'use strict';
|
|
globalOptions[key] = value;
|
|
globalOptions[key] = value;
|
|
return this;
|
|
return this;
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * Get a global option
|
|
|
|
+ * @static
|
|
|
|
+ * @param {string} key
|
|
|
|
+ * @returns {*}
|
|
|
|
+ */
|
|
showdown.getOption = function (key) {
|
|
showdown.getOption = function (key) {
|
|
'use strict';
|
|
'use strict';
|
|
return globalOptions[key];
|
|
return globalOptions[key];
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * Get the global options
|
|
|
|
+ * @static
|
|
|
|
+ * @returns {{omitExtraWLInCodeBlocks: boolean, prefixHeaderId: boolean}}
|
|
|
|
+ */
|
|
showdown.getOptions = function () {
|
|
showdown.getOptions = function () {
|
|
'use strict';
|
|
'use strict';
|
|
return globalOptions;
|
|
return globalOptions;
|
|
};
|
|
};
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Static Method
|
|
|
|
|
|
+ * Get or set a subParser
|
|
*
|
|
*
|
|
* 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 {*}
|
|
@@ -69,7 +81,49 @@ 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
|
|
*
|
|
*
|
|
* @param {object} [converterOptions]
|
|
* @param {object} [converterOptions]
|
|
* @returns {{makeHtml: Function}}
|
|
* @returns {{makeHtml: Function}}
|
|
@@ -80,10 +134,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',
|
|
@@ -100,7 +153,44 @@ showdown.Converter = function (converterOptions) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- var makeHtml = function (text) {
|
|
|
|
|
|
+ // 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
|
|
|
|
+ * @returns {*}
|
|
|
|
+ */
|
|
|
|
+ function makeHtml(text) {
|
|
|
|
|
|
//check if text is not falsy
|
|
//check if text is not falsy
|
|
if (!text) {
|
|
if (!text) {
|
|
@@ -108,11 +198,13 @@ showdown.Converter = function (converterOptions) {
|
|
}
|
|
}
|
|
|
|
|
|
var globals = {
|
|
var globals = {
|
|
- gHtmlBlocks: [],
|
|
|
|
- gUrls: {},
|
|
|
|
- gTitles: {},
|
|
|
|
- gListLevel: 0,
|
|
|
|
- hashLinkCounts: {}
|
|
|
|
|
|
+ gHtmlBlocks: [],
|
|
|
|
+ gUrls: {},
|
|
|
|
+ gTitles: {},
|
|
|
|
+ gListLevel: 0,
|
|
|
|
+ hashLinkCounts: {},
|
|
|
|
+ langExtensions: langExtensions,
|
|
|
|
+ outputModifiers: outputModifiers
|
|
};
|
|
};
|
|
|
|
|
|
// attacklab: Replace ~ with ~T
|
|
// attacklab: Replace ~ with ~T
|
|
@@ -133,6 +225,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];
|
|
@@ -146,12 +247,10 @@ 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 = _ExecuteExtension(x, text);
|
|
|
|
- //});
|
|
|
|
|
|
+ text = parsers.outputModifiers(text, options, globals);
|
|
|
|
|
|
return text;
|
|
return text;
|
|
- };
|
|
|
|
|
|
+ }
|
|
|
|
|
|
return {
|
|
return {
|
|
makeHtml: makeHtml
|
|
makeHtml: makeHtml
|
|
@@ -168,6 +267,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}
|
|
*/
|
|
*/
|
|
@@ -178,6 +278,7 @@ showdown.helper.isString = function isString(a) {
|
|
|
|
|
|
/**
|
|
/**
|
|
* ForEach helper function
|
|
* ForEach helper function
|
|
|
|
+ * @static
|
|
* @param {*} obj
|
|
* @param {*} obj
|
|
* @param {function} callback
|
|
* @param {function} callback
|
|
*/
|
|
*/
|
|
@@ -186,8 +287,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 (i = 0; i < len; i++) {
|
|
|
|
|
|
+ for (var i = 0; i < obj.length; i++) {
|
|
callback(obj[i], i, obj);
|
|
callback(obj[i], i, obj);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -195,6 +295,7 @@ showdown.helper.forEach = function forEach(obj, callback) {
|
|
|
|
|
|
/**
|
|
/**
|
|
* isArray helper function
|
|
* isArray helper function
|
|
|
|
+ * @static
|
|
* @param {*} a
|
|
* @param {*} a
|
|
* @returns {boolean}
|
|
* @returns {boolean}
|
|
*/
|
|
*/
|
|
@@ -205,7 +306,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`.
|
|
@@ -215,6 +315,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);
|
|
@@ -223,6 +334,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}
|
|
@@ -231,7 +343,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
|
|
@@ -1140,6 +1252,18 @@ showdown.subParser('italicsAndBold', function (text) {
|
|
return text;
|
|
return text;
|
|
});
|
|
});
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * 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;
|
|
|
|
+});
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* Form HTML ordered (numbered) and unordered (bulleted) lists.
|
|
* Form HTML ordered (numbered) and unordered (bulleted) lists.
|
|
*/
|
|
*/
|
|
@@ -1301,6 +1425,18 @@ showdown.subParser('outdent', function (text) {
|
|
return text;
|
|
return text;
|
|
});
|
|
});
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * 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;
|
|
|
|
+});
|
|
|
|
+
|
|
/**
|
|
/**
|
|
*
|
|
*
|
|
*/
|
|
*/
|
|
@@ -1343,6 +1479,20 @@ showdown.subParser('paragraphs', function (text, options, globals) {
|
|
return grafsOut.join('\n\n');
|
|
return grafsOut.join('\n\n');
|
|
});
|
|
});
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * 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);
|
|
|
|
+ }
|
|
|
|
+});
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* These are all the transformations that occur *within* block-level
|
|
* These are all the transformations that occur *within* block-level
|
|
* tags like paragraphs, headers, and list items.
|
|
* tags like paragraphs, headers, and list items.
|