123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378 |
- /**
- * Created by Tivie on 06-01-2015.
- */
- // Private properties
- var showdown = {},
- parsers = {},
- extensions = {},
- globalOptions = getDefaultOpts(true),
- setFlavor = 'vanilla',
- flavor = {
- github: {
- omitExtraWLInCodeBlocks: true,
- simplifiedAutoLink: true,
- excludeTrailingPunctuationFromURLs: true,
- literalMidWordUnderscores: true,
- strikethrough: true,
- tables: true,
- tablesHeaderId: true,
- ghCodeBlocks: true,
- tasklists: true,
- disableForced4SpacesIndentedSublists: true,
- simpleLineBreaks: true,
- requireSpaceBeforeHeadingText: true,
- ghCompatibleHeaderId: true,
- ghMentions: true,
- backslashEscapesHTMLTags: true
- },
- original: {
- noHeaderId: true,
- ghCodeBlocks: false
- },
- ghost: {
- omitExtraWLInCodeBlocks: true,
- parseImgDimensions: true,
- simplifiedAutoLink: true,
- excludeTrailingPunctuationFromURLs: true,
- literalMidWordUnderscores: true,
- strikethrough: true,
- tables: true,
- tablesHeaderId: true,
- ghCodeBlocks: true,
- tasklists: true,
- smoothLivePreview: true,
- simpleLineBreaks: true,
- requireSpaceBeforeHeadingText: true,
- ghMentions: false,
- encodeEmails: true
- },
- vanilla: getDefaultOpts(true),
- allOn: allOptionsOn()
- };
- /**
- * helper namespace
- * @type {{}}
- */
- showdown.helper = {};
- /**
- * TODO LEGACY SUPPORT CODE
- * @type {{}}
- */
- showdown.extensions = {};
- /**
- * Set a global option
- * @static
- * @param {string} key
- * @param {*} value
- * @returns {showdown}
- */
- showdown.setOption = function (key, value) {
- 'use strict';
- globalOptions[key] = value;
- return this;
- };
- /**
- * Get a global option
- * @static
- * @param {string} key
- * @returns {*}
- */
- showdown.getOption = function (key) {
- 'use strict';
- return globalOptions[key];
- };
- /**
- * Get the global options
- * @static
- * @returns {{}}
- */
- showdown.getOptions = function () {
- 'use strict';
- return globalOptions;
- };
- /**
- * Reset global options to the default values
- * @static
- */
- showdown.resetOptions = function () {
- 'use strict';
- globalOptions = getDefaultOpts(true);
- };
- /**
- * Set the flavor showdown should use as default
- * @param {string} name
- */
- showdown.setFlavor = function (name) {
- 'use strict';
- if (!flavor.hasOwnProperty(name)) {
- throw Error(name + ' flavor was not found');
- }
- showdown.resetOptions();
- var preset = flavor[name];
- setFlavor = name;
- for (var option in preset) {
- if (preset.hasOwnProperty(option)) {
- globalOptions[option] = preset[option];
- }
- }
- };
- /**
- * Get the currently set flavor
- * @returns {string}
- */
- showdown.getFlavor = function () {
- 'use strict';
- return setFlavor;
- };
- /**
- * Get the options of a specified flavor. Returns undefined if the flavor was not found
- * @param {string} name Name of the flavor
- * @returns {{}|undefined}
- */
- showdown.getFlavorOptions = function (name) {
- 'use strict';
- if (flavor.hasOwnProperty(name)) {
- return flavor[name];
- }
- };
- /**
- * Get the default options
- * @static
- * @param {boolean} [simple=true]
- * @returns {{}}
- */
- showdown.getDefaultOptions = function (simple) {
- 'use strict';
- return getDefaultOpts(simple);
- };
- /**
- * Get or set a subParser
- *
- * subParser(name) - Get a registered subParser
- * subParser(name, func) - Register a subParser
- * @static
- * @param {string} name
- * @param {function} [func]
- * @returns {*}
- */
- showdown.subParser = function (name, func) {
- 'use strict';
- if (showdown.helper.isString(name)) {
- if (typeof func !== 'undefined') {
- parsers[name] = func;
- } else {
- if (parsers.hasOwnProperty(name)) {
- return parsers[name];
- } else {
- throw Error('SubParser named ' + name + ' not registered!');
- }
- }
- }
- };
- /**
- * Gets or registers an extension
- * @static
- * @param {string} name
- * @param {object|function=} ext
- * @returns {*}
- */
- 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);
- // Getter
- if (showdown.helper.isUndefined(ext)) {
- if (!extensions.hasOwnProperty(name)) {
- throw Error('Extension named ' + name + ' is not registered!');
- }
- return extensions[name];
- // Setter
- } else {
- // Expand extension if it's wrapped in a function
- if (typeof ext === 'function') {
- ext = ext();
- }
- // Ensure extension is an array
- if (!showdown.helper.isArray(ext)) {
- ext = [ext];
- }
- var validExtension = validate(ext, name);
- if (validExtension.valid) {
- extensions[name] = ext;
- } else {
- throw Error(validExtension.error);
- }
- }
- };
- /**
- * Gets all extensions registered
- * @returns {{}}
- */
- showdown.getAllExtensions = function () {
- 'use strict';
- return extensions;
- };
- /**
- * Remove an extension
- * @param {string} name
- */
- showdown.removeExtension = function (name) {
- 'use strict';
- delete extensions[name];
- };
- /**
- * Removes all extensions
- */
- showdown.resetExtensions = function () {
- 'use strict';
- extensions = {};
- };
- /**
- * Validate extension
- * @param {array} extension
- * @param {string} name
- * @returns {{valid: boolean, error: string}}
- */
- function validate (extension, name) {
- 'use strict';
- var errMsg = (name) ? 'Error in ' + name + ' extension->' : 'Error in unnamed extension',
- ret = {
- valid: true,
- error: ''
- };
- if (!showdown.helper.isArray(extension)) {
- extension = [extension];
- }
- for (var i = 0; i < extension.length; ++i) {
- var baseMsg = errMsg + ' sub-extension ' + i + ': ',
- ext = extension[i];
- if (typeof ext !== 'object') {
- ret.valid = false;
- ret.error = baseMsg + 'must be an object, but ' + typeof ext + ' given';
- return ret;
- }
- if (!showdown.helper.isString(ext.type)) {
- ret.valid = false;
- ret.error = baseMsg + 'property "type" must be a string, but ' + typeof ext.type + ' given';
- return ret;
- }
- var type = ext.type = ext.type.toLowerCase();
- // normalize extension type
- if (type === 'language') {
- type = ext.type = 'lang';
- }
- if (type === 'html') {
- type = ext.type = 'output';
- }
- if (type !== 'lang' && type !== 'output' && type !== 'listener') {
- ret.valid = false;
- ret.error = baseMsg + 'type ' + type + ' is not recognized. Valid values: "lang/language", "output/html" or "listener"';
- return ret;
- }
- if (type === 'listener') {
- if (showdown.helper.isUndefined(ext.listeners)) {
- ret.valid = false;
- ret.error = baseMsg + '. Extensions of type "listener" must have a property called "listeners"';
- return ret;
- }
- } else {
- if (showdown.helper.isUndefined(ext.filter) && showdown.helper.isUndefined(ext.regex)) {
- ret.valid = false;
- ret.error = baseMsg + type + ' extensions must define either a "regex" property or a "filter" method';
- return ret;
- }
- }
- if (ext.listeners) {
- if (typeof ext.listeners !== 'object') {
- ret.valid = false;
- ret.error = baseMsg + '"listeners" property must be an object but ' + typeof ext.listeners + ' given';
- return ret;
- }
- for (var ln in ext.listeners) {
- if (ext.listeners.hasOwnProperty(ln)) {
- if (typeof ext.listeners[ln] !== 'function') {
- ret.valid = false;
- ret.error = baseMsg + '"listeners" property must be an hash of [event name]: [callback]. listeners.' + ln +
- ' must be a function but ' + typeof ext.listeners[ln] + ' given';
- return ret;
- }
- }
- }
- }
- if (ext.filter) {
- if (typeof ext.filter !== 'function') {
- ret.valid = false;
- ret.error = baseMsg + '"filter" must be a function, but ' + typeof ext.filter + ' given';
- return ret;
- }
- } else if (ext.regex) {
- if (showdown.helper.isString(ext.regex)) {
- ext.regex = new RegExp(ext.regex, 'g');
- }
- if (!(ext.regex instanceof RegExp)) {
- ret.valid = false;
- ret.error = baseMsg + '"regex" property must either be a string or a RegExp object, but ' + typeof ext.regex + ' given';
- return ret;
- }
- if (showdown.helper.isUndefined(ext.replace)) {
- ret.valid = false;
- ret.error = baseMsg + '"regex" extensions must implement a replace string or function';
- return ret;
- }
- }
- }
- return ret;
- }
- /**
- * Validate extension
- * @param {object} ext
- * @returns {boolean}
- */
- showdown.validateExtension = function (ext) {
- 'use strict';
- var validateExtension = validate(ext, null);
- if (!validateExtension.valid) {
- console.warn(validateExtension.error);
- return false;
- }
- return true;
- };
|