2022-04-28 04:42:24 +08:00
; /*! showdown v 3.0.0-alpha - 25-04-2022 */
( function ( ) {
2022-02-24 08:23:15 +08:00
/ * *
* Created by Tivie on 13 - 07 - 2015.
* /
function getDefaultOpts ( simple ) {
'use strict' ;
2022-04-28 04:42:24 +08:00
let defaultOptions = {
2022-02-24 08:23:15 +08:00
omitExtraWLInCodeBlocks : {
defaultValue : false ,
describe : 'Omit the default extra whiteline added to code blocks' ,
type : 'boolean'
} ,
noHeaderId : {
defaultValue : false ,
describe : 'Turn on/off generated header id' ,
type : 'boolean'
} ,
prefixHeaderId : {
defaultValue : false ,
describe : 'Add a prefix to the generated header ids. Passing a string will prefix that string to the header id. Setting to true will add a generic \'section-\' prefix' ,
type : 'string'
} ,
rawPrefixHeaderId : {
defaultValue : false ,
describe : 'Setting this option to true will prevent showdown from modifying the prefix. This might result in malformed IDs (if, for instance, the " char is used in the prefix)' ,
type : 'boolean'
} ,
ghCompatibleHeaderId : {
defaultValue : false ,
describe : 'Generate header ids compatible with github style (spaces are replaced with dashes, a bunch of non alphanumeric chars are removed)' ,
type : 'boolean'
} ,
rawHeaderId : {
defaultValue : false ,
describe : 'Remove only spaces, \' and " from generated header ids (including prefixes), replacing them with dashes (-). WARNING: This might result in malformed ids' ,
type : 'boolean'
} ,
headerLevelStart : {
2022-04-28 04:42:24 +08:00
defaultValue : 1 ,
2022-02-24 08:23:15 +08:00
describe : 'The header blocks level start' ,
2022-04-28 04:42:24 +08:00
type : 'number'
2022-02-24 08:23:15 +08:00
} ,
parseImgDimensions : {
defaultValue : false ,
describe : 'Turn on/off image dimension parsing' ,
type : 'boolean'
} ,
simplifiedAutoLink : {
defaultValue : false ,
describe : 'Turn on/off GFM autolink style' ,
type : 'boolean'
} ,
literalMidWordUnderscores : {
defaultValue : false ,
describe : 'Parse midword underscores as literal underscores' ,
type : 'boolean'
} ,
literalMidWordAsterisks : {
defaultValue : false ,
describe : 'Parse midword asterisks as literal asterisks' ,
type : 'boolean'
} ,
strikethrough : {
defaultValue : false ,
describe : 'Turn on/off strikethrough support' ,
type : 'boolean'
} ,
tables : {
defaultValue : false ,
describe : 'Turn on/off tables support' ,
type : 'boolean'
} ,
tablesHeaderId : {
defaultValue : false ,
describe : 'Add an id to table headers' ,
type : 'boolean'
} ,
ghCodeBlocks : {
defaultValue : true ,
describe : 'Turn on/off GFM fenced code blocks support' ,
type : 'boolean'
} ,
tasklists : {
defaultValue : false ,
describe : 'Turn on/off GFM tasklist support' ,
type : 'boolean'
} ,
smoothLivePreview : {
defaultValue : false ,
describe : 'Prevents weird effects in live previews due to incomplete input' ,
type : 'boolean'
} ,
smartIndentationFix : {
defaultValue : false ,
2022-03-03 20:15:50 +08:00
describe : 'Tries to smartly fix indentation in es6 strings' ,
2022-02-24 08:23:15 +08:00
type : 'boolean'
} ,
disableForced4SpacesIndentedSublists : {
defaultValue : false ,
2022-03-03 20:15:50 +08:00
describe : 'Disables the requirement of indenting nested sublists by 4 spaces' ,
2022-02-24 08:23:15 +08:00
type : 'boolean'
} ,
simpleLineBreaks : {
defaultValue : false ,
2022-03-03 20:15:50 +08:00
describe : 'Parses simple line breaks as <br> (GFM Style)' ,
2022-02-24 08:23:15 +08:00
type : 'boolean'
} ,
requireSpaceBeforeHeadingText : {
defaultValue : false ,
2022-03-03 20:15:50 +08:00
describe : 'Makes adding a space between `#` and the header text mandatory (GFM Style)' ,
2022-02-24 08:23:15 +08:00
type : 'boolean'
} ,
ghMentions : {
defaultValue : false ,
2022-03-03 20:15:50 +08:00
describe : 'Enables github @mentions' ,
2022-02-24 08:23:15 +08:00
type : 'boolean'
} ,
ghMentionsLink : {
defaultValue : 'https://github.com/{u}' ,
2022-03-03 20:15:50 +08:00
describe : 'Changes the link generated by @mentions. Only applies if ghMentions option is enabled.' ,
2022-02-24 08:23:15 +08:00
type : 'string'
} ,
encodeEmails : {
defaultValue : true ,
2022-03-03 20:15:50 +08:00
describe : 'Encode e-mail addresses through the use of Character Entities, transforming ASCII e-mail addresses into its equivalent decimal entities' ,
2022-02-24 08:23:15 +08:00
type : 'boolean'
} ,
openLinksInNewWindow : {
defaultValue : false ,
2022-03-03 20:15:50 +08:00
describe : 'Open all links in new windows' ,
2022-02-24 08:23:15 +08:00
type : 'boolean'
} ,
backslashEscapesHTMLTags : {
defaultValue : false ,
2022-03-03 20:15:50 +08:00
describe : 'Support for HTML Tag escaping. ex: \<div>foo\</div>' ,
2022-02-24 08:23:15 +08:00
type : 'boolean'
} ,
emoji : {
defaultValue : false ,
2022-03-03 20:15:50 +08:00
describe : 'Enable emoji support. Ex: `this is a :smile: emoji`' ,
2022-02-24 08:23:15 +08:00
type : 'boolean'
} ,
underline : {
defaultValue : false ,
2022-03-03 20:15:50 +08:00
describe : 'Enable support for underline. Syntax is double or triple underscores: `__underline word__`. With this option enabled, underscores no longer parses into `<em>` and `<strong>`' ,
2022-02-24 08:23:15 +08:00
type : 'boolean'
} ,
ellipsis : {
defaultValue : true ,
2022-03-03 20:15:50 +08:00
describe : 'Replaces three dots with the ellipsis unicode character' ,
2022-02-24 08:23:15 +08:00
type : 'boolean'
} ,
completeHTMLDocument : {
defaultValue : false ,
2022-03-03 20:15:50 +08:00
describe : 'Outputs a complete html document, including `<html>`, `<head>` and `<body>` tags' ,
2022-02-24 08:23:15 +08:00
type : 'boolean'
} ,
metadata : {
defaultValue : false ,
2022-03-03 20:15:50 +08:00
describe : 'Enable support for document metadata (defined at the top of the document between `«««` and `»»»` or between `---` and `---`).' ,
2022-02-24 08:23:15 +08:00
type : 'boolean'
} ,
splitAdjacentBlockquotes : {
defaultValue : false ,
2022-03-03 20:15:50 +08:00
describe : 'Split adjacent blockquote blocks' ,
2022-02-24 08:23:15 +08:00
type : 'boolean'
} ,
2022-02-24 09:57:08 +08:00
moreStyling : {
defaultValue : false ,
describe : 'Adds some useful styling css classes in the generated html' ,
type : 'boolean'
} ,
2022-02-24 08:23:15 +08:00
relativePathBaseUrl : {
2022-04-28 04:42:24 +08:00
defaultValue : '' ,
2022-02-24 08:23:15 +08:00
describe : 'Prepends a base URL to relative paths' ,
type : 'string'
} ,
} ;
if ( simple === false ) {
return JSON . parse ( JSON . stringify ( defaultOptions ) ) ;
}
2022-04-28 04:42:24 +08:00
let ret = { } ;
for ( let opt in defaultOptions ) {
2022-02-24 08:23:15 +08:00
if ( defaultOptions . hasOwnProperty ( opt ) ) {
ret [ opt ] = defaultOptions [ opt ] . defaultValue ;
}
}
return ret ;
}
function allOptionsOn ( ) {
'use strict' ;
2022-04-28 04:42:24 +08:00
let options = getDefaultOpts ( true ) ,
2022-02-24 08:23:15 +08:00
ret = { } ;
2022-04-28 04:42:24 +08:00
for ( let opt in options ) {
2022-02-24 08:23:15 +08:00
if ( options . hasOwnProperty ( opt ) ) {
ret [ opt ] = true ;
}
}
return ret ;
}
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
/ * *
* Created by Tivie on 06 - 01 - 2015.
* /
// Private properties
var showdown = { } ,
parsers = { } ,
extensions = { } ,
globalOptions = getDefaultOpts ( true ) ,
setFlavor = 'vanilla' ,
flavor = {
github : {
omitExtraWLInCodeBlocks : true ,
simplifiedAutoLink : 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 ,
emoji : true ,
splitAdjacentBlockquotes : true
} ,
original : {
noHeaderId : true ,
ghCodeBlocks : false
} ,
ghost : {
omitExtraWLInCodeBlocks : true ,
parseImgDimensions : true ,
simplifiedAutoLink : 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!' ) ;
}
}
} else {
throw Error ( 'showdown.subParser function first argument must be a string (the name of the subparser)' ) ;
}
} ;
2022-04-28 04:42:24 +08:00
/ * *
*
* @ returns { { } }
* /
showdown . getSubParserList = function ( ) {
return parsers ;
} ;
2022-02-24 08:23:15 +08:00
/ * *
* Gets or registers an extension
* @ static
* @ param { string } name
2022-03-03 20:15:50 +08:00
* @ param { object | object [ ] | function = } ext
2022-02-24 08:23:15 +08:00
* @ 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 ;
} ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
/ * *
* showdownjs helper functions
* /
if ( ! showdown . hasOwnProperty ( 'helper' ) ) {
showdown . helper = { } ;
}
if ( typeof this === 'undefined' && typeof window !== 'undefined' ) {
showdown . helper . document = window . document ;
} else {
if ( typeof this . document === 'undefined' && typeof this . window === 'undefined' ) {
2022-04-28 04:42:24 +08:00
let jsdom = require ( 'jsdom' ) ;
2022-02-24 08:23:15 +08:00
this . window = new jsdom . JSDOM ( '' , { } ) . window ; // jshint ignore:line
}
showdown . helper . document = this . window . document ;
}
/ * *
* Check if var is string
* @ static
2022-04-28 04:42:24 +08:00
* @ param { * } a
2022-02-24 08:23:15 +08:00
* @ returns { boolean }
* /
showdown . helper . isString = function ( a ) {
'use strict' ;
return ( typeof a === 'string' || a instanceof String ) ;
} ;
2022-04-28 04:42:24 +08:00
/ * *
* Check if var is a number
* @ static
* @ param { * } a
* @ returns { boolean }
* /
showdown . helper . isNumber = function ( a ) {
return ! isNaN ( a ) ;
} ;
2022-02-24 08:23:15 +08:00
/ * *
* Check if var is a function
* @ static
* @ param { * } a
* @ returns { boolean }
* /
showdown . helper . isFunction = function ( a ) {
'use strict' ;
2022-04-28 04:42:24 +08:00
let getType = { } ;
2022-02-24 08:23:15 +08:00
return a && getType . toString . call ( a ) === '[object Function]' ;
} ;
/ * *
* isArray helper function
* @ static
* @ param { * } a
* @ returns { boolean }
* /
showdown . helper . isArray = function ( a ) {
'use strict' ;
2022-04-28 04:42:24 +08:00
let isArray ;
if ( ! Array . isArray ) {
isArray = function ( arg ) {
return Object . prototype . toString . call ( arg ) === '[object Array]' ;
} ;
} else {
isArray = Array . isArray ;
}
return isArray ( a ) ;
2022-02-24 08:23:15 +08:00
} ;
/ * *
* Check if value is undefined
* @ static
* @ param { * } value The value to check .
* @ returns { boolean } Returns ` true ` if ` value ` is ` undefined ` , else ` false ` .
* /
showdown . helper . isUndefined = function ( value ) {
'use strict' ;
return typeof value === 'undefined' ;
} ;
2022-04-28 04:42:24 +08:00
/ * *
* Check if value is an object ( excluding arrays )
* @ param { * } value
* @ returns { boolean }
* /
showdown . helper . isObject = function ( value ) {
'use strict' ;
return (
typeof value === 'object' &&
! Array . isArray ( value ) &&
value !== null
) ;
} ;
2022-02-24 08:23:15 +08:00
/ * *
* ForEach helper function
* Iterates over Arrays and Objects ( own properties only )
* @ static
* @ param { * } obj
* @ param { function } callback Accepts 3 params : 1. value , 2. key , 3. the original array / object
* /
showdown . helper . forEach = function ( obj , callback ) {
'use strict' ;
// check if obj is defined
if ( showdown . helper . isUndefined ( obj ) ) {
throw new Error ( 'obj param is required' ) ;
}
if ( showdown . helper . isUndefined ( callback ) ) {
throw new Error ( 'callback param is required' ) ;
}
if ( ! showdown . helper . isFunction ( callback ) ) {
throw new Error ( 'callback param must be a function/closure' ) ;
}
if ( typeof obj . forEach === 'function' ) {
obj . forEach ( callback ) ;
} else if ( showdown . helper . isArray ( obj ) ) {
2022-04-28 04:42:24 +08:00
for ( let i = 0 ; i < obj . length ; i ++ ) {
2022-02-24 08:23:15 +08:00
callback ( obj [ i ] , i , obj ) ;
}
} else if ( typeof ( obj ) === 'object' ) {
2022-04-28 04:42:24 +08:00
for ( let prop in obj ) {
2022-02-24 08:23:15 +08:00
if ( obj . hasOwnProperty ( prop ) ) {
callback ( obj [ prop ] , prop , obj ) ;
}
}
} else {
throw new Error ( 'obj does not seem to be an array or an iterable object' ) ;
}
} ;
/ * *
2022-04-28 04:42:24 +08:00
* Standardize extension name
2022-02-24 08:23:15 +08:00
* @ static
* @ param { string } s extension name
* @ returns { string }
* /
showdown . helper . stdExtName = function ( s ) {
'use strict' ;
return s . replace ( /[_?*+\/\\.^-]/g , '' ) . replace ( /\s/g , '' ) . toLowerCase ( ) ;
} ;
function escapeCharactersCallback ( wholeMatch , m1 ) {
'use strict' ;
2022-04-28 04:42:24 +08:00
let charCodeToEscape = m1 . charCodeAt ( 0 ) ;
2022-02-24 08:23:15 +08:00
return '¨E' + charCodeToEscape + 'E' ;
}
/ * *
* Callback used to escape characters when passing through String . replace
* @ static
* @ param { string } wholeMatch
* @ param { string } m1
* @ returns { string }
* /
showdown . helper . escapeCharactersCallback = escapeCharactersCallback ;
/ * *
* Escape characters in a string
* @ static
* @ param { string } text
* @ param { string } charsToEscape
* @ param { boolean } afterBackslash
* @ returns { string | void | * }
* /
showdown . helper . escapeCharacters = function ( text , charsToEscape , afterBackslash ) {
'use strict' ;
// First we have to escape the escape characters so that
// we can build a character class out of them
2022-04-28 04:42:24 +08:00
let regexString = '([' + charsToEscape . replace ( /([\[\]\\])/g , '\\$1' ) + '])' ;
2022-02-24 08:23:15 +08:00
if ( afterBackslash ) {
regexString = '\\\\' + regexString ;
}
2022-04-28 04:42:24 +08:00
let regex = new RegExp ( regexString , 'g' ) ;
2022-02-24 08:23:15 +08:00
text = text . replace ( regex , escapeCharactersCallback ) ;
return text ;
} ;
2022-04-28 04:42:24 +08:00
let rgxFindMatchPos = function ( str , left , right , flags ) {
2022-02-24 08:23:15 +08:00
'use strict' ;
2022-04-28 04:42:24 +08:00
let f = flags || '' ,
2022-02-24 08:23:15 +08:00
g = f . indexOf ( 'g' ) > - 1 ,
x = new RegExp ( left + '|' + right , 'g' + f . replace ( /g/g , '' ) ) ,
l = new RegExp ( left , f . replace ( /g/g , '' ) ) ,
pos = [ ] ,
t , s , m , start , end ;
do {
t = 0 ;
while ( ( m = x . exec ( str ) ) ) {
if ( l . test ( m [ 0 ] ) ) {
if ( ! ( t ++ ) ) {
s = x . lastIndex ;
start = s - m [ 0 ] . length ;
}
} else if ( t ) {
if ( ! -- t ) {
end = m . index + m [ 0 ] . length ;
2022-04-28 04:42:24 +08:00
let obj = {
2022-02-24 08:23:15 +08:00
left : { start : start , end : s } ,
match : { start : s , end : m . index } ,
right : { start : m . index , end : end } ,
wholeMatch : { start : start , end : end }
} ;
pos . push ( obj ) ;
if ( ! g ) {
return pos ;
}
}
}
}
} while ( t && ( x . lastIndex = s ) ) ;
return pos ;
} ;
/ * *
* matchRecursiveRegExp
*
* ( c ) 2007 Steven Levithan < stevenlevithan . com >
* MIT License
*
* Accepts a string to search , a left and right format delimiter
* as regex patterns , and optional regex flags . Returns an array
* of matches , allowing nested instances of left / right delimiters .
* Use the "g" flag to return all matches , otherwise only the
* first is returned . Be careful to ensure that the left and
* right format delimiters produce mutually exclusive matches .
* Backreferences are not supported within the right delimiter
* due to how it is internally combined with the left delimiter .
* When matching strings whose format delimiters are unbalanced
* to the left or right , the output is intentionally as a
* conventional regex library with recursion support would
* produce , e . g . "<<x>" and "<x>>" both produce [ "x" ] when using
* "<" and ">" as the delimiters ( both strings contain a single ,
* balanced instance of "<x>" ) .
*
* examples :
* matchRecursiveRegExp ( "test" , "\\(" , "\\)" )
* returns : [ ]
* matchRecursiveRegExp ( "<t<<e>><s>>t<>" , "<" , ">" , "g" )
* returns : [ "t<<e>><s>" , "" ]
* matchRecursiveRegExp ( "<div id=\"x\">test</div>" , "<div\\b[^>]*>" , "</div>" , "gi" )
* returns : [ "test" ]
* /
showdown . helper . matchRecursiveRegExp = function ( str , left , right , flags ) {
'use strict' ;
2022-04-28 04:42:24 +08:00
let matchPos = rgxFindMatchPos ( str , left , right , flags ) ,
2022-02-24 08:23:15 +08:00
results = [ ] ;
2022-04-28 04:42:24 +08:00
for ( let i = 0 ; i < matchPos . length ; ++ i ) {
2022-02-24 08:23:15 +08:00
results . push ( [
str . slice ( matchPos [ i ] . wholeMatch . start , matchPos [ i ] . wholeMatch . end ) ,
str . slice ( matchPos [ i ] . match . start , matchPos [ i ] . match . end ) ,
str . slice ( matchPos [ i ] . left . start , matchPos [ i ] . left . end ) ,
str . slice ( matchPos [ i ] . right . start , matchPos [ i ] . right . end )
] ) ;
}
return results ;
} ;
/ * *
*
* @ param { string } str
* @ param { string | function } replacement
* @ param { string } left
* @ param { string } right
* @ param { string } flags
* @ returns { string }
* /
showdown . helper . replaceRecursiveRegExp = function ( str , replacement , left , right , flags ) {
'use strict' ;
if ( ! showdown . helper . isFunction ( replacement ) ) {
2022-04-28 04:42:24 +08:00
let repStr = replacement ;
2022-02-24 08:23:15 +08:00
replacement = function ( ) {
return repStr ;
} ;
}
2022-04-28 04:42:24 +08:00
let matchPos = rgxFindMatchPos ( str , left , right , flags ) ,
2022-02-24 08:23:15 +08:00
finalStr = str ,
lng = matchPos . length ;
if ( lng > 0 ) {
2022-04-28 04:42:24 +08:00
let bits = [ ] ;
2022-02-24 08:23:15 +08:00
if ( matchPos [ 0 ] . wholeMatch . start !== 0 ) {
bits . push ( str . slice ( 0 , matchPos [ 0 ] . wholeMatch . start ) ) ;
}
2022-04-28 04:42:24 +08:00
for ( let i = 0 ; i < lng ; ++ i ) {
2022-02-24 08:23:15 +08:00
bits . push (
replacement (
str . slice ( matchPos [ i ] . wholeMatch . start , matchPos [ i ] . wholeMatch . end ) ,
str . slice ( matchPos [ i ] . match . start , matchPos [ i ] . match . end ) ,
str . slice ( matchPos [ i ] . left . start , matchPos [ i ] . left . end ) ,
str . slice ( matchPos [ i ] . right . start , matchPos [ i ] . right . end )
)
) ;
if ( i < lng - 1 ) {
bits . push ( str . slice ( matchPos [ i ] . wholeMatch . end , matchPos [ i + 1 ] . wholeMatch . start ) ) ;
}
}
if ( matchPos [ lng - 1 ] . wholeMatch . end < str . length ) {
bits . push ( str . slice ( matchPos [ lng - 1 ] . wholeMatch . end ) ) ;
}
finalStr = bits . join ( '' ) ;
}
return finalStr ;
} ;
/ * *
* Returns the index within the passed String object of the first occurrence of the specified regex ,
* starting the search at fromIndex . Returns - 1 if the value is not found .
*
* @ param { string } str string to search
* @ param { RegExp } regex Regular expression to search
* @ param { int } [ fromIndex = 0 ] Index to start the search
* @ returns { Number }
* @ throws InvalidArgumentError
* /
showdown . helper . regexIndexOf = function ( str , regex , fromIndex ) {
'use strict' ;
if ( ! showdown . helper . isString ( str ) ) {
throw 'InvalidArgumentError: first parameter of showdown.helper.regexIndexOf function must be a string' ;
}
if ( ! ( regex instanceof RegExp ) ) {
throw 'InvalidArgumentError: second parameter of showdown.helper.regexIndexOf function must be an instance of RegExp' ;
}
2022-04-28 04:42:24 +08:00
let indexOf = str . substring ( fromIndex || 0 ) . search ( regex ) ;
2022-02-24 08:23:15 +08:00
return ( indexOf >= 0 ) ? ( indexOf + ( fromIndex || 0 ) ) : indexOf ;
} ;
/ * *
* Splits the passed string object at the defined index , and returns an array composed of the two substrings
* @ param { string } str string to split
* @ param { int } index index to split string at
* @ returns { [ string , string ] }
* @ throws InvalidArgumentError
* /
showdown . helper . splitAtIndex = function ( str , index ) {
'use strict' ;
if ( ! showdown . helper . isString ( str ) ) {
throw 'InvalidArgumentError: first parameter of showdown.helper.regexIndexOf function must be a string' ;
}
return [ str . substring ( 0 , index ) , str . substring ( index ) ] ;
} ;
2022-04-28 04:42:24 +08:00
/ * *
* MurmurHash3 ' s mixing function
* https : //stackoverflow.com/questions/521295/seeding-the-random-number-generator-in-javascript/47593316#47593316
*
* @ param { string } string
* @ returns { Number }
* /
/*jshint bitwise: false*/
function xmur3 ( str ) {
let h ;
for ( let i = 0 , h = 1779033703 ^ str . length ; i < str . length ; i ++ ) {
h = Math . imul ( h ^ str . charCodeAt ( i ) , 3432918353 ) ;
h = h << 13 | h >>> 19 ;
}
return function ( ) {
h = Math . imul ( h ^ h >>> 16 , 2246822507 ) ;
h = Math . imul ( h ^ h >>> 13 , 3266489909 ) ;
return ( h ^= h >>> 16 ) >>> 0 ;
} ;
}
/ * *
* Random Number Generator
* https : //stackoverflow.com/questions/521295/seeding-the-random-number-generator-in-javascript/47593316#47593316
*
* @ param { Number } seed
* @ returns { Number }
* /
/*jshint bitwise: false*/
function mulberry32 ( a ) {
return function ( ) {
let t = a += 0x6D2B79F5 ;
t = Math . imul ( t ^ t >>> 15 , t | 1 ) ;
t ^= t + Math . imul ( t ^ t >>> 7 , t | 61 ) ;
return ( ( t ^ t >>> 14 ) >>> 0 ) / 4294967296 ;
} ;
}
2022-02-24 08:23:15 +08:00
/ * *
* Obfuscate an e - mail address through the use of Character Entities ,
* transforming ASCII characters into their equivalent decimal or hex entities .
*
*
* @ param { string } mail
* @ returns { string }
* /
2022-04-28 04:42:24 +08:00
showdown . helper . encodeEmailAddress = function ( mail ) {
2022-02-24 08:23:15 +08:00
'use strict' ;
2022-04-28 04:42:24 +08:00
let encode = [
2022-02-24 08:23:15 +08:00
function ( ch ) {
return '&#' + ch . charCodeAt ( 0 ) + ';' ;
} ,
function ( ch ) {
return '&#x' + ch . charCodeAt ( 0 ) . toString ( 16 ) + ';' ;
} ,
function ( ch ) {
return ch ;
}
] ;
2022-04-28 04:42:24 +08:00
// RNG seeded with mail, so that we can get determined results for each email.
let rand = mulberry32 ( xmur3 ( mail ) ) ;
2022-02-24 08:23:15 +08:00
mail = mail . replace ( /./g , function ( ch ) {
if ( ch === '@' ) {
// this *must* be encoded. I insist.
2022-04-28 04:42:24 +08:00
ch = encode [ Math . floor ( rand ( ) * 2 ) ] ( ch ) ;
2022-02-24 08:23:15 +08:00
} else {
2022-04-28 04:42:24 +08:00
let r = rand ( ) ;
2022-02-24 08:23:15 +08:00
// roughly 10% raw, 45% hex, 45% dec
ch = (
r > 0.9 ? encode [ 2 ] ( ch ) : r > 0.45 ? encode [ 1 ] ( ch ) : encode [ 0 ] ( ch )
) ;
}
return ch ;
} ) ;
return mail ;
} ;
/ * *
2022-03-10 20:56:34 +08:00
* String . prototype . repeat polyfill
*
* @ param { string } str
* @ param { int } count
* @ returns { string }
* /
showdown . helper . repeat = function ( str , count ) {
'use strict' ;
// use built-in method if it's available
if ( ! showdown . helper . isUndefined ( String . prototype . repeat ) ) {
return str . repeat ( count ) ;
}
str = '' + str ;
if ( count < 0 ) {
throw new RangeError ( 'repeat count must be non-negative' ) ;
}
if ( count === Infinity ) {
throw new RangeError ( 'repeat count must be less than infinity' ) ;
}
count = Math . floor ( count ) ;
if ( str . length === 0 || count === 0 ) {
return '' ;
}
// Ensuring count is a 31-bit integer allows us to heavily optimize the
// main part. But anyway, most current (August 2014) browsers can't handle
// strings 1 << 28 chars or longer, so:
/*jshint bitwise: false*/
if ( str . length * count >= 1 << 28 ) {
throw new RangeError ( 'repeat count must not overflow maximum string size' ) ;
}
/*jshint bitwise: true*/
2022-04-28 04:42:24 +08:00
let maxCount = str . length * count ;
2022-03-10 20:56:34 +08:00
count = Math . floor ( Math . log ( count ) / Math . log ( 2 ) ) ;
while ( count ) {
str += str ;
count -- ;
}
str += str . substring ( 0 , maxCount - str . length ) ;
return str ;
} ;
/ * *
* String . prototype . padEnd polyfill
2022-02-24 08:23:15 +08:00
*
2022-04-28 04:42:24 +08:00
* @ param { string } str
* @ param { int } targetLength
* @ param { string } [ padString ]
2022-02-24 08:23:15 +08:00
* @ returns { string }
* /
showdown . helper . padEnd = function padEnd ( str , targetLength , padString ) {
'use strict' ;
/*jshint bitwise: false*/
// eslint-disable-next-line space-infix-ops
targetLength = targetLength >> 0 ; //floor if number or convert non-number to 0;
/*jshint bitwise: true*/
padString = String ( padString || ' ' ) ;
if ( str . length > targetLength ) {
return String ( str ) ;
} else {
targetLength = targetLength - str . length ;
if ( targetLength > padString . length ) {
2022-03-10 20:56:34 +08:00
padString += showdown . helper . repeat ( padString , targetLength / padString . length ) ; //append to original to ensure we are longer than needed
2022-02-24 08:23:15 +08:00
}
return String ( str ) + padString . slice ( 0 , targetLength ) ;
}
} ;
/ * *
* Unescape HTML entities
* @ param txt
* @ returns { string }
* /
showdown . helper . unescapeHTMLEntities = function ( txt ) {
'use strict' ;
return txt
. replace ( /"/g , '"' )
. replace ( /</g , '<' )
. replace ( />/g , '>' )
. replace ( /&/g , '&' ) ;
} ;
showdown . helper . _hashHTMLSpan = function ( html , globals ) {
return '¨C' + ( globals . gHtmlSpans . push ( html ) - 1 ) + 'C' ;
} ;
/ * *
* Prepends a base URL to relative paths .
*
* @ param { string } baseUrl the base URL to prepend to a relative path
* @ param { string } url the path to modify , which may be relative
* @ returns { string } the full URL
* /
showdown . helper . applyBaseUrl = function ( baseUrl , url ) {
// Only prepend if given a base URL and the path is not absolute.
2022-04-28 04:42:24 +08:00
if ( baseUrl && baseUrl !== '' && ! showdown . helper . isAbsolutePath ( url ) ) {
let urlResolve = new showdown . helper . URLUtils ( url , baseUrl ) ;
url = urlResolve . href ;
2022-02-24 08:23:15 +08:00
}
return url ;
} ;
/ * *
* Checks if the given path is absolute .
*
* @ param { string } path the path to test for absolution
* @ returns { boolean } ` true ` if the given path is absolute , else ` false `
* /
showdown . helper . isAbsolutePath = function ( path ) {
// Absolute paths begin with '[protocol:]//' or '#' (anchors)
return /(^([a-z]+:)?\/\/)|(^#)/i . test ( path ) ;
} ;
2022-04-28 04:42:24 +08:00
showdown . helper . URLUtils = function ( url , baseURL ) {
const pattern2 = /^([^:\/?#]+:)?(?:\/\/(?:([^:@\/?#]*)(?::([^:@\/?#]*))?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/ ;
let m = String ( url )
. trim ( )
. match ( pattern2 ) ;
if ( ! m ) {
throw new RangeError ( ) ;
}
let protocol = m [ 1 ] || '' ;
let username = m [ 2 ] || '' ;
let password = m [ 3 ] || '' ;
let host = m [ 4 ] || '' ;
let hostname = m [ 5 ] || '' ;
let port = m [ 6 ] || '' ;
let pathname = m [ 7 ] || '' ;
let search = m [ 8 ] || '' ;
let hash = m [ 9 ] || '' ;
if ( baseURL !== undefined ) {
let base = new showdown . helper . URLUtils ( baseURL ) ;
let flag = protocol === '' && host === '' && username === '' ;
if ( flag && pathname === '' && search === '' ) {
search = base . search ;
}
if ( flag && pathname . charAt ( 0 ) !== '/' ) {
pathname = ( pathname !== '' ? ( ( ( base . host !== '' || base . username !== '' ) && base . pathname === '' ? '/' : '' ) + base . pathname . slice ( 0 , base . pathname . lastIndexOf ( '/' ) + 1 ) + pathname ) : base . pathname ) ;
}
// dot segments removal
let output = [ ] ;
pathname . replace ( /^(\.\.?(\/|$))+/ , '' )
. replace ( /\/(\.(\/|$))+/g , '/' )
. replace ( /\/\.\.$/ , '/../' )
. replace ( /\/?[^\/]*/g , function ( p ) {
if ( p === '/..' ) {
output . pop ( ) ;
} else {
output . push ( p ) ;
}
} ) ;
pathname = output . join ( '' ) . replace ( /^\// , pathname . charAt ( 0 ) === '/' ? '/' : '' ) ;
if ( flag ) {
port = base . port ;
hostname = base . hostname ;
host = base . host ;
password = base . password ;
username = base . username ;
}
if ( protocol === '' ) {
protocol = base . protocol ;
}
}
this . origin = protocol + ( protocol !== '' || host !== '' ? '//' : '' ) + host ;
this . href = protocol + ( protocol !== '' || host !== '' ? '//' : '' ) + ( username !== '' ? username + ( password !== '' ? ':' + password : '' ) + '@' : '' ) + host + pathname + search + hash ;
this . protocol = protocol ;
this . username = username ;
this . password = password ;
this . host = host ;
this . hostname = hostname ;
this . port = port ;
this . pathname = pathname ;
this . search = search ;
this . hash = hash ;
} ;
2022-02-24 08:23:15 +08:00
/ * *
2022-04-28 04:42:24 +08:00
* Clones an object . If the second parameter is true , it deep clones the object .
* Note : It should not be used in other contexts than showdown , since this algorithm might fail for
* cyclic references , and dataypes such as Dates , RegExps , Typed Arrays , etc ...
* @ param { { } } obj Object to clone
* @ param { boolean } [ deep ] [ optional ] If it should deep clone the object . Default is false
2022-02-24 08:23:15 +08:00
* /
2022-04-28 04:42:24 +08:00
showdown . helper . cloneObject = function ( obj , deep ) {
deep = ! ! deep ;
if ( obj === null || typeof ( obj ) !== 'object' ) {
return obj ;
}
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
if ( obj instanceof Date ) {
return new Date ( obj ) ;
}
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
if ( ! deep ) {
let newObj = { } ;
for ( let key in obj ) {
if ( obj . hasOwnProperty ( key ) ) {
newObj [ key ] = obj [ key ] ;
}
}
return newObj ;
}
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
if ( typeof structuredClone === 'function' ) {
return structuredClone ( obj ) ;
} else {
// note: This is not a real deep clone, and might work in weird ways if used in a dif
//this is costly and should be used sparsly
return JSON . parse ( JSON . stringify ( obj ) ) ;
}
} ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
/ * *
* Populate attributes in output text
* @ param { { } } attributes
* @ returns { string }
* /
showdown . helper . _populateAttributes = function ( attributes ) {
let text = '' ;
if ( ! attributes || ! showdown . helper . isObject ( attributes ) ) {
return text ;
}
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
for ( let attr in attributes ) {
if ( attributes . hasOwnProperty ( attr ) ) {
let key = attr ,
val ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
// since class is a javascript reserved word we use classes
if ( attr === 'classes' ) {
key = 'class' ;
}
if ( attributes [ attr ] === null || showdown . helper . isUndefined ( attributes [ attr ] ) ) {
val = null ;
} else if ( showdown . helper . isArray ( attributes [ attr ] ) ) {
val = attributes [ attr ] . join ( ' ' ) ;
if ( val === '' ) {
val = null ;
}
} else if ( showdown . helper . isString ( attributes [ attr ] ) ) {
val = attributes [ attr ] ;
} else if ( showdown . helper . isNumber ( attributes [ attr ] ) ) {
val = String ( attributes [ attr ] ) ;
} else {
throw new TypeError ( 'Attribute "' + attr + '" must be either an array or string but ' + typeof attributes [ attr ] + ' given' ) ;
}
// special attributes
switch ( attr ) {
// these attributes don't expect a value. If they are false, they should be removed. If they are true,
// they should be present but without any value
case 'checked' :
case 'disabled' :
if ( val === true || val === 'true' || val === attr ) {
text += ' ' + key ;
}
// if falsy, they are just ignored
break ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
// default behavior for all other attributes types
default :
text += ( val === null ) ? '' : ' ' + key + '="' + val + '"' ;
break ;
}
}
}
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
return text ;
} ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
/ * *
* Remove one level of line - leading tabs or spaces
* @ param { string } text
* @ returns { string }
* /
showdown . helper . outdent = function ( text ) {
'use strict' ;
if ( ! showdown . helper . isString ( text ) ) {
2022-02-24 08:23:15 +08:00
return text ;
2022-04-28 04:42:24 +08:00
}
return text . replace ( /^(\t| {1,4})/gm , '' ) ;
} ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
/ * *
* Validate options
* @ param { { } } options
* @ returns { { } }
* /
showdown . helper . validateOptions = function ( options ) {
if ( ! showdown . helper . isObject ( options ) ) {
throw new TypeError ( 'Options must be an object, but ' + typeof options + ' given' ) ;
}
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
let defaultOptions = getDefaultOpts ( false ) ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
for ( let opt in defaultOptions ) {
if ( ! defaultOptions . hasOwnProperty ( opt ) ) {
continue ;
}
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
if ( ! options . hasOwnProperty ( opt ) ) {
options [ opt ] = defaultOptions [ opt ] . defaultValue ;
}
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
// TODO: dirty code. think about this we refactoring options
switch ( opt ) {
case 'prefixHeaderId' :
if ( typeof options [ opt ] !== 'boolean' && ! showdown . helper . isString ( options [ opt ] ) ) {
throw new TypeError ( 'Option prefixHeaderId must be of type boolean or string but ' + typeof options [ opt ] + ' given' ) ;
}
break ;
default :
if ( typeof options [ opt ] !== defaultOptions [ opt ] . type ) {
throw new TypeError ( 'Option ' + opt + ' must be of type ' + defaultOptions [ opt ] . type + ' but ' + typeof options [ opt ] + ' given' ) ;
}
}
}
//options.headerLevelStart = (isNaN(parseInt(options.headerLevelStart))) ? 1 : parseInt(options.headerLevelStart);
return options ;
2022-02-24 08:23:15 +08:00
} ;
/ * *
* POLYFILLS
* /
// use this instead of builtin is undefined for IE8 compatibility
if ( typeof ( console ) === 'undefined' ) {
console = {
warn : function ( msg ) {
'use strict' ;
alert ( msg ) ;
} ,
log : function ( msg ) {
'use strict' ;
alert ( msg ) ;
} ,
error : function ( msg ) {
'use strict' ;
throw msg ;
}
} ;
}
2022-04-28 04:42:24 +08:00
// Math.imul() polyfill
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul
if ( ! Math . imul ) {
Math . imul = function ( opA , opB ) {
opB |= 0 ; // ensure that opB is an integer. opA will automatically be coerced.
// floating points give us 53 bits of precision to work with plus 1 sign bit
// automatically handled for our convienence:
// 1. 0x003fffff /*opA & 0x000fffff*/ * 0x7fffffff /*opB*/ = 0x1fffff7fc00001
// 0x1fffff7fc00001 < Number.MAX_SAFE_INTEGER /*0x1fffffffffffff*/
let result = ( opA & 0x003fffff ) * opB ;
// 2. We can remove an integer coersion from the statement above because:
// 0x1fffff7fc00001 + 0xffc00000 = 0x1fffffff800001
// 0x1fffffff800001 < Number.MAX_SAFE_INTEGER /*0x1fffffffffffff*/
if ( opA & 0xffc00000 /*!== 0*/ ) {
result += ( opA & 0xffc00000 ) * opB | 0 ;
}
return result | 0 ;
} ;
}
2022-02-24 08:23:15 +08:00
/ * *
* Common regexes .
* We declare some common regexes to improve performance
* /
showdown . helper . regexes = {
asteriskDashTildeAndColon : /([*_:~])/g ,
asteriskDashAndTilde : /([*_~])/g
} ;
/ * *
* EMOJIS LIST
* /
showdown . helper . emojis = {
'100' : '\ud83d\udcaf' ,
'1234' : '\ud83d\udd22' ,
'+1' : '\ud83d\udc4d' ,
'-1' : '\ud83d\udc4e' ,
'1st_place_medal' : '\ud83e\udd47' ,
'2nd_place_medal' : '\ud83e\udd48' ,
'3rd_place_medal' : '\ud83e\udd49' ,
'8ball' : '\ud83c\udfb1' ,
'a' : '\ud83c\udd70\ufe0f' ,
'ab' : '\ud83c\udd8e' ,
'abacus' : '\ud83e\uddee' ,
'abc' : '\ud83d\udd24' ,
'abcd' : '\ud83d\udd21' ,
'accept' : '\ud83c\ude51' ,
'adhesive_bandage' : '\ud83e\ude79' ,
'adult' : '\ud83e\uddd1' ,
'aerial_tramway' : '\ud83d\udea1' ,
'afghanistan' : '\ud83c\udde6\ud83c\uddeb' ,
'airplane' : '\u2708\ufe0f' ,
'aland_islands' : '\ud83c\udde6\ud83c\uddfd' ,
'alarm_clock' : '\u23f0' ,
'albania' : '\ud83c\udde6\ud83c\uddf1' ,
'alembic' : '\u2697\ufe0f' ,
'algeria' : '\ud83c\udde9\ud83c\uddff' ,
'alien' : '\ud83d\udc7d' ,
'ambulance' : '\ud83d\ude91' ,
'american_samoa' : '\ud83c\udde6\ud83c\uddf8' ,
'amphora' : '\ud83c\udffa' ,
'anchor' : '\u2693' ,
'andorra' : '\ud83c\udde6\ud83c\udde9' ,
'angel' : '\ud83d\udc7c' ,
'anger' : '\ud83d\udca2' ,
'angola' : '\ud83c\udde6\ud83c\uddf4' ,
'angry' : '\ud83d\ude20' ,
'anguilla' : '\ud83c\udde6\ud83c\uddee' ,
'anguished' : '\ud83d\ude27' ,
'ant' : '\ud83d\udc1c' ,
'antarctica' : '\ud83c\udde6\ud83c\uddf6' ,
'antigua_barbuda' : '\ud83c\udde6\ud83c\uddec' ,
'apple' : '\ud83c\udf4e' ,
'aquarius' : '\u2652' ,
'argentina' : '\ud83c\udde6\ud83c\uddf7' ,
'aries' : '\u2648' ,
'armenia' : '\ud83c\udde6\ud83c\uddf2' ,
'arrow_backward' : '\u25c0\ufe0f' ,
'arrow_double_down' : '\u23ec' ,
'arrow_double_up' : '\u23eb' ,
'arrow_down' : '\u2b07\ufe0f' ,
'arrow_down_small' : '\ud83d\udd3d' ,
'arrow_forward' : '\u25b6\ufe0f' ,
'arrow_heading_down' : '\u2935\ufe0f' ,
'arrow_heading_up' : '\u2934\ufe0f' ,
'arrow_left' : '\u2b05\ufe0f' ,
'arrow_lower_left' : '\u2199\ufe0f' ,
'arrow_lower_right' : '\u2198\ufe0f' ,
'arrow_right' : '\u27a1\ufe0f' ,
'arrow_right_hook' : '\u21aa\ufe0f' ,
'arrow_up' : '\u2b06\ufe0f' ,
'arrow_up_down' : '\u2195\ufe0f' ,
'arrow_up_small' : '\ud83d\udd3c' ,
'arrow_upper_left' : '\u2196\ufe0f' ,
'arrow_upper_right' : '\u2197\ufe0f' ,
'arrows_clockwise' : '\ud83d\udd03' ,
'arrows_counterclockwise' : '\ud83d\udd04' ,
'art' : '\ud83c\udfa8' ,
'articulated_lorry' : '\ud83d\ude9b' ,
'artificial_satellite' : '\ud83d\udef0\ufe0f' ,
'artist' : '\ud83e\uddd1\u200d\ud83c\udfa8' ,
'aruba' : '\ud83c\udde6\ud83c\uddfc' ,
'ascension_island' : '\ud83c\udde6\ud83c\udde8' ,
'asterisk' : '*\ufe0f\u20e3' ,
'astonished' : '\ud83d\ude32' ,
'astronaut' : '\ud83e\uddd1\u200d\ud83d\ude80' ,
'athletic_shoe' : '\ud83d\udc5f' ,
'atm' : '\ud83c\udfe7' ,
'atom_symbol' : '\u269b\ufe0f' ,
'australia' : '\ud83c\udde6\ud83c\uddfa' ,
'austria' : '\ud83c\udde6\ud83c\uddf9' ,
'auto_rickshaw' : '\ud83d\udefa' ,
'avocado' : '\ud83e\udd51' ,
'axe' : '\ud83e\ude93' ,
'azerbaijan' : '\ud83c\udde6\ud83c\uddff' ,
'b' : '\ud83c\udd71\ufe0f' ,
'baby' : '\ud83d\udc76' ,
'baby_bottle' : '\ud83c\udf7c' ,
'baby_chick' : '\ud83d\udc24' ,
'baby_symbol' : '\ud83d\udebc' ,
'back' : '\ud83d\udd19' ,
'bacon' : '\ud83e\udd53' ,
'badger' : '\ud83e\udda1' ,
'badminton' : '\ud83c\udff8' ,
'bagel' : '\ud83e\udd6f' ,
'baggage_claim' : '\ud83d\udec4' ,
'baguette_bread' : '\ud83e\udd56' ,
'bahamas' : '\ud83c\udde7\ud83c\uddf8' ,
'bahrain' : '\ud83c\udde7\ud83c\udded' ,
'balance_scale' : '\u2696\ufe0f' ,
'bald_man' : '\ud83d\udc68\u200d\ud83e\uddb2' ,
'bald_woman' : '\ud83d\udc69\u200d\ud83e\uddb2' ,
'ballet_shoes' : '\ud83e\ude70' ,
'balloon' : '\ud83c\udf88' ,
'ballot_box' : '\ud83d\uddf3\ufe0f' ,
'ballot_box_with_check' : '\u2611\ufe0f' ,
'bamboo' : '\ud83c\udf8d' ,
'banana' : '\ud83c\udf4c' ,
'bangbang' : '\u203c\ufe0f' ,
'bangladesh' : '\ud83c\udde7\ud83c\udde9' ,
'banjo' : '\ud83e\ude95' ,
'bank' : '\ud83c\udfe6' ,
'bar_chart' : '\ud83d\udcca' ,
'barbados' : '\ud83c\udde7\ud83c\udde7' ,
'barber' : '\ud83d\udc88' ,
'baseball' : '\u26be' ,
'basket' : '\ud83e\uddfa' ,
'basketball' : '\ud83c\udfc0' ,
'basketball_man' : '\u26f9\ufe0f\u200d\u2642\ufe0f' ,
'basketball_woman' : '\u26f9\ufe0f\u200d\u2640\ufe0f' ,
'bat' : '\ud83e\udd87' ,
'bath' : '\ud83d\udec0' ,
'bathtub' : '\ud83d\udec1' ,
'battery' : '\ud83d\udd0b' ,
'beach_umbrella' : '\ud83c\udfd6\ufe0f' ,
'bear' : '\ud83d\udc3b' ,
'bearded_person' : '\ud83e\uddd4' ,
'bed' : '\ud83d\udecf\ufe0f' ,
'bee' : '\ud83d\udc1d' ,
'beer' : '\ud83c\udf7a' ,
'beers' : '\ud83c\udf7b' ,
'beetle' : '\ud83d\udc1e' ,
'beginner' : '\ud83d\udd30' ,
'belarus' : '\ud83c\udde7\ud83c\uddfe' ,
'belgium' : '\ud83c\udde7\ud83c\uddea' ,
'belize' : '\ud83c\udde7\ud83c\uddff' ,
'bell' : '\ud83d\udd14' ,
'bellhop_bell' : '\ud83d\udece\ufe0f' ,
'benin' : '\ud83c\udde7\ud83c\uddef' ,
'bento' : '\ud83c\udf71' ,
'bermuda' : '\ud83c\udde7\ud83c\uddf2' ,
'beverage_box' : '\ud83e\uddc3' ,
'bhutan' : '\ud83c\udde7\ud83c\uddf9' ,
'bicyclist' : '\ud83d\udeb4' ,
'bike' : '\ud83d\udeb2' ,
'biking_man' : '\ud83d\udeb4\u200d\u2642\ufe0f' ,
'biking_woman' : '\ud83d\udeb4\u200d\u2640\ufe0f' ,
'bikini' : '\ud83d\udc59' ,
'billed_cap' : '\ud83e\udde2' ,
'biohazard' : '\u2623\ufe0f' ,
'bird' : '\ud83d\udc26' ,
'birthday' : '\ud83c\udf82' ,
'black_circle' : '\u26ab' ,
'black_flag' : '\ud83c\udff4' ,
'black_heart' : '\ud83d\udda4' ,
'black_joker' : '\ud83c\udccf' ,
'black_large_square' : '\u2b1b' ,
'black_medium_small_square' : '\u25fe' ,
'black_medium_square' : '\u25fc\ufe0f' ,
'black_nib' : '\u2712\ufe0f' ,
'black_small_square' : '\u25aa\ufe0f' ,
'black_square_button' : '\ud83d\udd32' ,
'blond_haired_man' : '\ud83d\udc71\u200d\u2642\ufe0f' ,
'blond_haired_person' : '\ud83d\udc71' ,
'blond_haired_woman' : '\ud83d\udc71\u200d\u2640\ufe0f' ,
'blonde_woman' : '\ud83d\udc71\u200d\u2640\ufe0f' ,
'blossom' : '\ud83c\udf3c' ,
'blowfish' : '\ud83d\udc21' ,
'blue_book' : '\ud83d\udcd8' ,
'blue_car' : '\ud83d\ude99' ,
'blue_heart' : '\ud83d\udc99' ,
'blue_square' : '\ud83d\udfe6' ,
'blush' : '\ud83d\ude0a' ,
'boar' : '\ud83d\udc17' ,
'boat' : '\u26f5' ,
'bolivia' : '\ud83c\udde7\ud83c\uddf4' ,
'bomb' : '\ud83d\udca3' ,
'bone' : '\ud83e\uddb4' ,
'book' : '\ud83d\udcd6' ,
'bookmark' : '\ud83d\udd16' ,
'bookmark_tabs' : '\ud83d\udcd1' ,
'books' : '\ud83d\udcda' ,
'boom' : '\ud83d\udca5' ,
'boot' : '\ud83d\udc62' ,
'bosnia_herzegovina' : '\ud83c\udde7\ud83c\udde6' ,
'botswana' : '\ud83c\udde7\ud83c\uddfc' ,
'bouncing_ball_man' : '\u26f9\ufe0f\u200d\u2642\ufe0f' ,
'bouncing_ball_person' : '\u26f9\ufe0f' ,
'bouncing_ball_woman' : '\u26f9\ufe0f\u200d\u2640\ufe0f' ,
'bouquet' : '\ud83d\udc90' ,
'bouvet_island' : '\ud83c\udde7\ud83c\uddfb' ,
'bow' : '\ud83d\ude47' ,
'bow_and_arrow' : '\ud83c\udff9' ,
'bowing_man' : '\ud83d\ude47\u200d\u2642\ufe0f' ,
'bowing_woman' : '\ud83d\ude47\u200d\u2640\ufe0f' ,
'bowl_with_spoon' : '\ud83e\udd63' ,
'bowling' : '\ud83c\udfb3' ,
'boxing_glove' : '\ud83e\udd4a' ,
'boy' : '\ud83d\udc66' ,
'brain' : '\ud83e\udde0' ,
'brazil' : '\ud83c\udde7\ud83c\uddf7' ,
'bread' : '\ud83c\udf5e' ,
'breast_feeding' : '\ud83e\udd31' ,
'bricks' : '\ud83e\uddf1' ,
'bride_with_veil' : '\ud83d\udc70' ,
'bridge_at_night' : '\ud83c\udf09' ,
'briefcase' : '\ud83d\udcbc' ,
'british_indian_ocean_territory' : '\ud83c\uddee\ud83c\uddf4' ,
'british_virgin_islands' : '\ud83c\uddfb\ud83c\uddec' ,
'broccoli' : '\ud83e\udd66' ,
'broken_heart' : '\ud83d\udc94' ,
'broom' : '\ud83e\uddf9' ,
'brown_circle' : '\ud83d\udfe4' ,
'brown_heart' : '\ud83e\udd0e' ,
'brown_square' : '\ud83d\udfeb' ,
'brunei' : '\ud83c\udde7\ud83c\uddf3' ,
'bug' : '\ud83d\udc1b' ,
'building_construction' : '\ud83c\udfd7\ufe0f' ,
'bulb' : '\ud83d\udca1' ,
'bulgaria' : '\ud83c\udde7\ud83c\uddec' ,
'bullettrain_front' : '\ud83d\ude85' ,
'bullettrain_side' : '\ud83d\ude84' ,
'burkina_faso' : '\ud83c\udde7\ud83c\uddeb' ,
'burrito' : '\ud83c\udf2f' ,
'burundi' : '\ud83c\udde7\ud83c\uddee' ,
'bus' : '\ud83d\ude8c' ,
'business_suit_levitating' : '\ud83d\udd74\ufe0f' ,
'busstop' : '\ud83d\ude8f' ,
'bust_in_silhouette' : '\ud83d\udc64' ,
'busts_in_silhouette' : '\ud83d\udc65' ,
'butter' : '\ud83e\uddc8' ,
'butterfly' : '\ud83e\udd8b' ,
'cactus' : '\ud83c\udf35' ,
'cake' : '\ud83c\udf70' ,
'calendar' : '\ud83d\udcc6' ,
'call_me_hand' : '\ud83e\udd19' ,
'calling' : '\ud83d\udcf2' ,
'cambodia' : '\ud83c\uddf0\ud83c\udded' ,
'camel' : '\ud83d\udc2b' ,
'camera' : '\ud83d\udcf7' ,
'camera_flash' : '\ud83d\udcf8' ,
'cameroon' : '\ud83c\udde8\ud83c\uddf2' ,
'camping' : '\ud83c\udfd5\ufe0f' ,
'canada' : '\ud83c\udde8\ud83c\udde6' ,
'canary_islands' : '\ud83c\uddee\ud83c\udde8' ,
'cancer' : '\u264b' ,
'candle' : '\ud83d\udd6f\ufe0f' ,
'candy' : '\ud83c\udf6c' ,
'canned_food' : '\ud83e\udd6b' ,
'canoe' : '\ud83d\udef6' ,
'cape_verde' : '\ud83c\udde8\ud83c\uddfb' ,
'capital_abcd' : '\ud83d\udd20' ,
'capricorn' : '\u2651' ,
'car' : '\ud83d\ude97' ,
'card_file_box' : '\ud83d\uddc3\ufe0f' ,
'card_index' : '\ud83d\udcc7' ,
'card_index_dividers' : '\ud83d\uddc2\ufe0f' ,
'caribbean_netherlands' : '\ud83c\udde7\ud83c\uddf6' ,
'carousel_horse' : '\ud83c\udfa0' ,
'carrot' : '\ud83e\udd55' ,
'cartwheeling' : '\ud83e\udd38' ,
'cat' : '\ud83d\udc31' ,
'cat2' : '\ud83d\udc08' ,
'cayman_islands' : '\ud83c\uddf0\ud83c\uddfe' ,
'cd' : '\ud83d\udcbf' ,
'central_african_republic' : '\ud83c\udde8\ud83c\uddeb' ,
'ceuta_melilla' : '\ud83c\uddea\ud83c\udde6' ,
'chad' : '\ud83c\uddf9\ud83c\udde9' ,
'chains' : '\u26d3\ufe0f' ,
'chair' : '\ud83e\ude91' ,
'champagne' : '\ud83c\udf7e' ,
'chart' : '\ud83d\udcb9' ,
'chart_with_downwards_trend' : '\ud83d\udcc9' ,
'chart_with_upwards_trend' : '\ud83d\udcc8' ,
'checkered_flag' : '\ud83c\udfc1' ,
'cheese' : '\ud83e\uddc0' ,
'cherries' : '\ud83c\udf52' ,
'cherry_blossom' : '\ud83c\udf38' ,
'chess_pawn' : '\u265f\ufe0f' ,
'chestnut' : '\ud83c\udf30' ,
'chicken' : '\ud83d\udc14' ,
'child' : '\ud83e\uddd2' ,
'children_crossing' : '\ud83d\udeb8' ,
'chile' : '\ud83c\udde8\ud83c\uddf1' ,
'chipmunk' : '\ud83d\udc3f\ufe0f' ,
'chocolate_bar' : '\ud83c\udf6b' ,
'chopsticks' : '\ud83e\udd62' ,
'christmas_island' : '\ud83c\udde8\ud83c\uddfd' ,
'christmas_tree' : '\ud83c\udf84' ,
'church' : '\u26ea' ,
'cinema' : '\ud83c\udfa6' ,
'circus_tent' : '\ud83c\udfaa' ,
'city_sunrise' : '\ud83c\udf07' ,
'city_sunset' : '\ud83c\udf06' ,
'cityscape' : '\ud83c\udfd9\ufe0f' ,
'cl' : '\ud83c\udd91' ,
'clamp' : '\ud83d\udddc\ufe0f' ,
'clap' : '\ud83d\udc4f' ,
'clapper' : '\ud83c\udfac' ,
'classical_building' : '\ud83c\udfdb\ufe0f' ,
'climbing' : '\ud83e\uddd7' ,
'climbing_man' : '\ud83e\uddd7\u200d\u2642\ufe0f' ,
'climbing_woman' : '\ud83e\uddd7\u200d\u2640\ufe0f' ,
'clinking_glasses' : '\ud83e\udd42' ,
'clipboard' : '\ud83d\udccb' ,
'clipperton_island' : '\ud83c\udde8\ud83c\uddf5' ,
'clock1' : '\ud83d\udd50' ,
'clock10' : '\ud83d\udd59' ,
'clock1030' : '\ud83d\udd65' ,
'clock11' : '\ud83d\udd5a' ,
'clock1130' : '\ud83d\udd66' ,
'clock12' : '\ud83d\udd5b' ,
'clock1230' : '\ud83d\udd67' ,
'clock130' : '\ud83d\udd5c' ,
'clock2' : '\ud83d\udd51' ,
'clock230' : '\ud83d\udd5d' ,
'clock3' : '\ud83d\udd52' ,
'clock330' : '\ud83d\udd5e' ,
'clock4' : '\ud83d\udd53' ,
'clock430' : '\ud83d\udd5f' ,
'clock5' : '\ud83d\udd54' ,
'clock530' : '\ud83d\udd60' ,
'clock6' : '\ud83d\udd55' ,
'clock630' : '\ud83d\udd61' ,
'clock7' : '\ud83d\udd56' ,
'clock730' : '\ud83d\udd62' ,
'clock8' : '\ud83d\udd57' ,
'clock830' : '\ud83d\udd63' ,
'clock9' : '\ud83d\udd58' ,
'clock930' : '\ud83d\udd64' ,
'closed_book' : '\ud83d\udcd5' ,
'closed_lock_with_key' : '\ud83d\udd10' ,
'closed_umbrella' : '\ud83c\udf02' ,
'cloud' : '\u2601\ufe0f' ,
'cloud_with_lightning' : '\ud83c\udf29\ufe0f' ,
'cloud_with_lightning_and_rain' : '\u26c8\ufe0f' ,
'cloud_with_rain' : '\ud83c\udf27\ufe0f' ,
'cloud_with_snow' : '\ud83c\udf28\ufe0f' ,
'clown_face' : '\ud83e\udd21' ,
'clubs' : '\u2663\ufe0f' ,
'cn' : '\ud83c\udde8\ud83c\uddf3' ,
'coat' : '\ud83e\udde5' ,
'cocktail' : '\ud83c\udf78' ,
'coconut' : '\ud83e\udd65' ,
'cocos_islands' : '\ud83c\udde8\ud83c\udde8' ,
'coffee' : '\u2615' ,
'coffin' : '\u26b0\ufe0f' ,
'cold_face' : '\ud83e\udd76' ,
'cold_sweat' : '\ud83d\ude30' ,
'collision' : '\ud83d\udca5' ,
'colombia' : '\ud83c\udde8\ud83c\uddf4' ,
'comet' : '\u2604\ufe0f' ,
'comoros' : '\ud83c\uddf0\ud83c\uddf2' ,
'compass' : '\ud83e\udded' ,
'computer' : '\ud83d\udcbb' ,
'computer_mouse' : '\ud83d\uddb1\ufe0f' ,
'confetti_ball' : '\ud83c\udf8a' ,
'confounded' : '\ud83d\ude16' ,
'confused' : '\ud83d\ude15' ,
'congo_brazzaville' : '\ud83c\udde8\ud83c\uddec' ,
'congo_kinshasa' : '\ud83c\udde8\ud83c\udde9' ,
'congratulations' : '\u3297\ufe0f' ,
'construction' : '\ud83d\udea7' ,
'construction_worker' : '\ud83d\udc77' ,
'construction_worker_man' : '\ud83d\udc77\u200d\u2642\ufe0f' ,
'construction_worker_woman' : '\ud83d\udc77\u200d\u2640\ufe0f' ,
'control_knobs' : '\ud83c\udf9b\ufe0f' ,
'convenience_store' : '\ud83c\udfea' ,
'cook' : '\ud83e\uddd1\u200d\ud83c\udf73' ,
'cook_islands' : '\ud83c\udde8\ud83c\uddf0' ,
'cookie' : '\ud83c\udf6a' ,
'cool' : '\ud83c\udd92' ,
'cop' : '\ud83d\udc6e' ,
'copyright' : '\u00a9\ufe0f' ,
'corn' : '\ud83c\udf3d' ,
'costa_rica' : '\ud83c\udde8\ud83c\uddf7' ,
'cote_divoire' : '\ud83c\udde8\ud83c\uddee' ,
'couch_and_lamp' : '\ud83d\udecb\ufe0f' ,
'couple' : '\ud83d\udc6b' ,
'couple_with_heart' : '\ud83d\udc91' ,
'couple_with_heart_man_man' : '\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc68' ,
'couple_with_heart_woman_man' : '\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d\udc68' ,
'couple_with_heart_woman_woman' : '\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d\udc69' ,
'couplekiss' : '\ud83d\udc8f' ,
'couplekiss_man_man' : '\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68' ,
'couplekiss_man_woman' : '\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68' ,
'couplekiss_woman_woman' : '\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc69' ,
'cow' : '\ud83d\udc2e' ,
'cow2' : '\ud83d\udc04' ,
'cowboy_hat_face' : '\ud83e\udd20' ,
'crab' : '\ud83e\udd80' ,
'crayon' : '\ud83d\udd8d\ufe0f' ,
'credit_card' : '\ud83d\udcb3' ,
'crescent_moon' : '\ud83c\udf19' ,
'cricket' : '\ud83e\udd97' ,
'cricket_game' : '\ud83c\udfcf' ,
'croatia' : '\ud83c\udded\ud83c\uddf7' ,
'crocodile' : '\ud83d\udc0a' ,
'croissant' : '\ud83e\udd50' ,
'crossed_fingers' : '\ud83e\udd1e' ,
'crossed_flags' : '\ud83c\udf8c' ,
'crossed_swords' : '\u2694\ufe0f' ,
'crown' : '\ud83d\udc51' ,
'cry' : '\ud83d\ude22' ,
'crying_cat_face' : '\ud83d\ude3f' ,
'crystal_ball' : '\ud83d\udd2e' ,
'cuba' : '\ud83c\udde8\ud83c\uddfa' ,
'cucumber' : '\ud83e\udd52' ,
'cup_with_straw' : '\ud83e\udd64' ,
'cupcake' : '\ud83e\uddc1' ,
'cupid' : '\ud83d\udc98' ,
'curacao' : '\ud83c\udde8\ud83c\uddfc' ,
'curling_stone' : '\ud83e\udd4c' ,
'curly_haired_man' : '\ud83d\udc68\u200d\ud83e\uddb1' ,
'curly_haired_woman' : '\ud83d\udc69\u200d\ud83e\uddb1' ,
'curly_loop' : '\u27b0' ,
'currency_exchange' : '\ud83d\udcb1' ,
'curry' : '\ud83c\udf5b' ,
'cursing_face' : '\ud83e\udd2c' ,
'custard' : '\ud83c\udf6e' ,
'customs' : '\ud83d\udec3' ,
'cut_of_meat' : '\ud83e\udd69' ,
'cyclone' : '\ud83c\udf00' ,
'cyprus' : '\ud83c\udde8\ud83c\uddfe' ,
'czech_republic' : '\ud83c\udde8\ud83c\uddff' ,
'dagger' : '\ud83d\udde1\ufe0f' ,
'dancer' : '\ud83d\udc83' ,
'dancers' : '\ud83d\udc6f' ,
'dancing_men' : '\ud83d\udc6f\u200d\u2642\ufe0f' ,
'dancing_women' : '\ud83d\udc6f\u200d\u2640\ufe0f' ,
'dango' : '\ud83c\udf61' ,
'dark_sunglasses' : '\ud83d\udd76\ufe0f' ,
'dart' : '\ud83c\udfaf' ,
'dash' : '\ud83d\udca8' ,
'date' : '\ud83d\udcc5' ,
'de' : '\ud83c\udde9\ud83c\uddea' ,
'deaf_man' : '\ud83e\uddcf\u200d\u2642\ufe0f' ,
'deaf_person' : '\ud83e\uddcf' ,
'deaf_woman' : '\ud83e\uddcf\u200d\u2640\ufe0f' ,
'deciduous_tree' : '\ud83c\udf33' ,
'deer' : '\ud83e\udd8c' ,
'denmark' : '\ud83c\udde9\ud83c\uddf0' ,
'department_store' : '\ud83c\udfec' ,
'derelict_house' : '\ud83c\udfda\ufe0f' ,
'desert' : '\ud83c\udfdc\ufe0f' ,
'desert_island' : '\ud83c\udfdd\ufe0f' ,
'desktop_computer' : '\ud83d\udda5\ufe0f' ,
'detective' : '\ud83d\udd75\ufe0f' ,
'diamond_shape_with_a_dot_inside' : '\ud83d\udca0' ,
'diamonds' : '\u2666\ufe0f' ,
'diego_garcia' : '\ud83c\udde9\ud83c\uddec' ,
'disappointed' : '\ud83d\ude1e' ,
'disappointed_relieved' : '\ud83d\ude25' ,
'diving_mask' : '\ud83e\udd3f' ,
'diya_lamp' : '\ud83e\ude94' ,
'dizzy' : '\ud83d\udcab' ,
'dizzy_face' : '\ud83d\ude35' ,
'djibouti' : '\ud83c\udde9\ud83c\uddef' ,
'dna' : '\ud83e\uddec' ,
'do_not_litter' : '\ud83d\udeaf' ,
'dog' : '\ud83d\udc36' ,
'dog2' : '\ud83d\udc15' ,
'dollar' : '\ud83d\udcb5' ,
'dolls' : '\ud83c\udf8e' ,
'dolphin' : '\ud83d\udc2c' ,
'dominica' : '\ud83c\udde9\ud83c\uddf2' ,
'dominican_republic' : '\ud83c\udde9\ud83c\uddf4' ,
'door' : '\ud83d\udeaa' ,
'doughnut' : '\ud83c\udf69' ,
'dove' : '\ud83d\udd4a\ufe0f' ,
'dragon' : '\ud83d\udc09' ,
'dragon_face' : '\ud83d\udc32' ,
'dress' : '\ud83d\udc57' ,
'dromedary_camel' : '\ud83d\udc2a' ,
'drooling_face' : '\ud83e\udd24' ,
'drop_of_blood' : '\ud83e\ude78' ,
'droplet' : '\ud83d\udca7' ,
'drum' : '\ud83e\udd41' ,
'duck' : '\ud83e\udd86' ,
'dumpling' : '\ud83e\udd5f' ,
'dvd' : '\ud83d\udcc0' ,
'e-mail' : '\ud83d\udce7' ,
'eagle' : '\ud83e\udd85' ,
'ear' : '\ud83d\udc42' ,
'ear_of_rice' : '\ud83c\udf3e' ,
'ear_with_hearing_aid' : '\ud83e\uddbb' ,
'earth_africa' : '\ud83c\udf0d' ,
'earth_americas' : '\ud83c\udf0e' ,
'earth_asia' : '\ud83c\udf0f' ,
'ecuador' : '\ud83c\uddea\ud83c\udde8' ,
'egg' : '\ud83e\udd5a' ,
'eggplant' : '\ud83c\udf46' ,
'egypt' : '\ud83c\uddea\ud83c\uddec' ,
'eight' : '8\ufe0f\u20e3' ,
'eight_pointed_black_star' : '\u2734\ufe0f' ,
'eight_spoked_asterisk' : '\u2733\ufe0f' ,
'eject_button' : '\u23cf\ufe0f' ,
'el_salvador' : '\ud83c\uddf8\ud83c\uddfb' ,
'electric_plug' : '\ud83d\udd0c' ,
'elephant' : '\ud83d\udc18' ,
'elf' : '\ud83e\udddd' ,
'elf_man' : '\ud83e\udddd\u200d\u2642\ufe0f' ,
'elf_woman' : '\ud83e\udddd\u200d\u2640\ufe0f' ,
'email' : '\u2709\ufe0f' ,
'end' : '\ud83d\udd1a' ,
'england' : '\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f' ,
'envelope' : '\u2709\ufe0f' ,
'envelope_with_arrow' : '\ud83d\udce9' ,
'equatorial_guinea' : '\ud83c\uddec\ud83c\uddf6' ,
'eritrea' : '\ud83c\uddea\ud83c\uddf7' ,
'es' : '\ud83c\uddea\ud83c\uddf8' ,
'estonia' : '\ud83c\uddea\ud83c\uddea' ,
'ethiopia' : '\ud83c\uddea\ud83c\uddf9' ,
'eu' : '\ud83c\uddea\ud83c\uddfa' ,
'euro' : '\ud83d\udcb6' ,
'european_castle' : '\ud83c\udff0' ,
'european_post_office' : '\ud83c\udfe4' ,
'european_union' : '\ud83c\uddea\ud83c\uddfa' ,
'evergreen_tree' : '\ud83c\udf32' ,
'exclamation' : '\u2757' ,
'exploding_head' : '\ud83e\udd2f' ,
'expressionless' : '\ud83d\ude11' ,
'eye' : '\ud83d\udc41\ufe0f' ,
'eye_speech_bubble' : '\ud83d\udc41\ufe0f\u200d\ud83d\udde8\ufe0f' ,
'eyeglasses' : '\ud83d\udc53' ,
'eyes' : '\ud83d\udc40' ,
'face_with_head_bandage' : '\ud83e\udd15' ,
'face_with_thermometer' : '\ud83e\udd12' ,
'facepalm' : '\ud83e\udd26' ,
'facepunch' : '\ud83d\udc4a' ,
'factory' : '\ud83c\udfed' ,
'factory_worker' : '\ud83e\uddd1\u200d\ud83c\udfed' ,
'fairy' : '\ud83e\uddda' ,
'fairy_man' : '\ud83e\uddda\u200d\u2642\ufe0f' ,
'fairy_woman' : '\ud83e\uddda\u200d\u2640\ufe0f' ,
'falafel' : '\ud83e\uddc6' ,
'falkland_islands' : '\ud83c\uddeb\ud83c\uddf0' ,
'fallen_leaf' : '\ud83c\udf42' ,
'family' : '\ud83d\udc6a' ,
'family_man_boy' : '\ud83d\udc68\u200d\ud83d\udc66' ,
'family_man_boy_boy' : '\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66' ,
'family_man_girl' : '\ud83d\udc68\u200d\ud83d\udc67' ,
'family_man_girl_boy' : '\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d\udc66' ,
'family_man_girl_girl' : '\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d\udc67' ,
'family_man_man_boy' : '\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc66' ,
'family_man_man_boy_boy' : '\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66' ,
'family_man_man_girl' : '\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc67' ,
'family_man_man_girl_boy' : '\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d\udc66' ,
'family_man_man_girl_girl' : '\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d\udc67' ,
'family_man_woman_boy' : '\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc66' ,
'family_man_woman_boy_boy' : '\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66' ,
'family_man_woman_girl' : '\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc67' ,
'family_man_woman_girl_boy' : '\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d\udc66' ,
'family_man_woman_girl_girl' : '\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d\udc67' ,
'family_woman_boy' : '\ud83d\udc69\u200d\ud83d\udc66' ,
'family_woman_boy_boy' : '\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66' ,
'family_woman_girl' : '\ud83d\udc69\u200d\ud83d\udc67' ,
'family_woman_girl_boy' : '\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d\udc66' ,
'family_woman_girl_girl' : '\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d\udc67' ,
'family_woman_woman_boy' : '\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc66' ,
'family_woman_woman_boy_boy' : '\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66' ,
'family_woman_woman_girl' : '\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc67' ,
'family_woman_woman_girl_boy' : '\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d\udc66' ,
'family_woman_woman_girl_girl' : '\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d\udc67' ,
'farmer' : '\ud83e\uddd1\u200d\ud83c\udf3e' ,
'faroe_islands' : '\ud83c\uddeb\ud83c\uddf4' ,
'fast_forward' : '\u23e9' ,
'fax' : '\ud83d\udce0' ,
'fearful' : '\ud83d\ude28' ,
'feet' : '\ud83d\udc3e' ,
'female_detective' : '\ud83d\udd75\ufe0f\u200d\u2640\ufe0f' ,
'female_sign' : '\u2640\ufe0f' ,
'ferris_wheel' : '\ud83c\udfa1' ,
'ferry' : '\u26f4\ufe0f' ,
'field_hockey' : '\ud83c\udfd1' ,
'fiji' : '\ud83c\uddeb\ud83c\uddef' ,
'file_cabinet' : '\ud83d\uddc4\ufe0f' ,
'file_folder' : '\ud83d\udcc1' ,
'film_projector' : '\ud83d\udcfd\ufe0f' ,
'film_strip' : '\ud83c\udf9e\ufe0f' ,
'finland' : '\ud83c\uddeb\ud83c\uddee' ,
'fire' : '\ud83d\udd25' ,
'fire_engine' : '\ud83d\ude92' ,
'fire_extinguisher' : '\ud83e\uddef' ,
'firecracker' : '\ud83e\udde8' ,
'firefighter' : '\ud83e\uddd1\u200d\ud83d\ude92' ,
'fireworks' : '\ud83c\udf86' ,
'first_quarter_moon' : '\ud83c\udf13' ,
'first_quarter_moon_with_face' : '\ud83c\udf1b' ,
'fish' : '\ud83d\udc1f' ,
'fish_cake' : '\ud83c\udf65' ,
'fishing_pole_and_fish' : '\ud83c\udfa3' ,
'fist' : '\u270a' ,
'fist_left' : '\ud83e\udd1b' ,
'fist_oncoming' : '\ud83d\udc4a' ,
'fist_raised' : '\u270a' ,
'fist_right' : '\ud83e\udd1c' ,
'five' : '5\ufe0f\u20e3' ,
'flags' : '\ud83c\udf8f' ,
'flamingo' : '\ud83e\udda9' ,
'flashlight' : '\ud83d\udd26' ,
'flat_shoe' : '\ud83e\udd7f' ,
'fleur_de_lis' : '\u269c\ufe0f' ,
'flight_arrival' : '\ud83d\udeec' ,
'flight_departure' : '\ud83d\udeeb' ,
'flipper' : '\ud83d\udc2c' ,
'floppy_disk' : '\ud83d\udcbe' ,
'flower_playing_cards' : '\ud83c\udfb4' ,
'flushed' : '\ud83d\ude33' ,
'flying_disc' : '\ud83e\udd4f' ,
'flying_saucer' : '\ud83d\udef8' ,
'fog' : '\ud83c\udf2b\ufe0f' ,
'foggy' : '\ud83c\udf01' ,
'foot' : '\ud83e\uddb6' ,
'football' : '\ud83c\udfc8' ,
'footprints' : '\ud83d\udc63' ,
'fork_and_knife' : '\ud83c\udf74' ,
'fortune_cookie' : '\ud83e\udd60' ,
'fountain' : '\u26f2' ,
'fountain_pen' : '\ud83d\udd8b\ufe0f' ,
'four' : '4\ufe0f\u20e3' ,
'four_leaf_clover' : '\ud83c\udf40' ,
'fox_face' : '\ud83e\udd8a' ,
'fr' : '\ud83c\uddeb\ud83c\uddf7' ,
'framed_picture' : '\ud83d\uddbc\ufe0f' ,
'free' : '\ud83c\udd93' ,
'french_guiana' : '\ud83c\uddec\ud83c\uddeb' ,
'french_polynesia' : '\ud83c\uddf5\ud83c\uddeb' ,
'french_southern_territories' : '\ud83c\uddf9\ud83c\uddeb' ,
'fried_egg' : '\ud83c\udf73' ,
'fried_shrimp' : '\ud83c\udf64' ,
'fries' : '\ud83c\udf5f' ,
'frog' : '\ud83d\udc38' ,
'frowning' : '\ud83d\ude26' ,
'frowning_face' : '\u2639\ufe0f' ,
'frowning_man' : '\ud83d\ude4d\u200d\u2642\ufe0f' ,
'frowning_person' : '\ud83d\ude4d' ,
'frowning_woman' : '\ud83d\ude4d\u200d\u2640\ufe0f' ,
'fu' : '\ud83d\udd95' ,
'fuelpump' : '\u26fd' ,
'full_moon' : '\ud83c\udf15' ,
'full_moon_with_face' : '\ud83c\udf1d' ,
'funeral_urn' : '\u26b1\ufe0f' ,
'gabon' : '\ud83c\uddec\ud83c\udde6' ,
'gambia' : '\ud83c\uddec\ud83c\uddf2' ,
'game_die' : '\ud83c\udfb2' ,
'garlic' : '\ud83e\uddc4' ,
'gb' : '\ud83c\uddec\ud83c\udde7' ,
'gear' : '\u2699\ufe0f' ,
'gem' : '\ud83d\udc8e' ,
'gemini' : '\u264a' ,
'genie' : '\ud83e\uddde' ,
'genie_man' : '\ud83e\uddde\u200d\u2642\ufe0f' ,
'genie_woman' : '\ud83e\uddde\u200d\u2640\ufe0f' ,
'georgia' : '\ud83c\uddec\ud83c\uddea' ,
'ghana' : '\ud83c\uddec\ud83c\udded' ,
'ghost' : '\ud83d\udc7b' ,
'gibraltar' : '\ud83c\uddec\ud83c\uddee' ,
'gift' : '\ud83c\udf81' ,
'gift_heart' : '\ud83d\udc9d' ,
'giraffe' : '\ud83e\udd92' ,
'girl' : '\ud83d\udc67' ,
'globe_with_meridians' : '\ud83c\udf10' ,
'gloves' : '\ud83e\udde4' ,
'goal_net' : '\ud83e\udd45' ,
'goat' : '\ud83d\udc10' ,
'goggles' : '\ud83e\udd7d' ,
'golf' : '\u26f3' ,
'golfing' : '\ud83c\udfcc\ufe0f' ,
'golfing_man' : '\ud83c\udfcc\ufe0f\u200d\u2642\ufe0f' ,
'golfing_woman' : '\ud83c\udfcc\ufe0f\u200d\u2640\ufe0f' ,
'gorilla' : '\ud83e\udd8d' ,
'grapes' : '\ud83c\udf47' ,
'greece' : '\ud83c\uddec\ud83c\uddf7' ,
'green_apple' : '\ud83c\udf4f' ,
'green_book' : '\ud83d\udcd7' ,
'green_circle' : '\ud83d\udfe2' ,
'green_heart' : '\ud83d\udc9a' ,
'green_salad' : '\ud83e\udd57' ,
'green_square' : '\ud83d\udfe9' ,
'greenland' : '\ud83c\uddec\ud83c\uddf1' ,
'grenada' : '\ud83c\uddec\ud83c\udde9' ,
'grey_exclamation' : '\u2755' ,
'grey_question' : '\u2754' ,
'grimacing' : '\ud83d\ude2c' ,
'grin' : '\ud83d\ude01' ,
'grinning' : '\ud83d\ude00' ,
'guadeloupe' : '\ud83c\uddec\ud83c\uddf5' ,
'guam' : '\ud83c\uddec\ud83c\uddfa' ,
'guard' : '\ud83d\udc82' ,
'guardsman' : '\ud83d\udc82\u200d\u2642\ufe0f' ,
'guardswoman' : '\ud83d\udc82\u200d\u2640\ufe0f' ,
'guatemala' : '\ud83c\uddec\ud83c\uddf9' ,
'guernsey' : '\ud83c\uddec\ud83c\uddec' ,
'guide_dog' : '\ud83e\uddae' ,
'guinea' : '\ud83c\uddec\ud83c\uddf3' ,
'guinea_bissau' : '\ud83c\uddec\ud83c\uddfc' ,
'guitar' : '\ud83c\udfb8' ,
'gun' : '\ud83d\udd2b' ,
'guyana' : '\ud83c\uddec\ud83c\uddfe' ,
'haircut' : '\ud83d\udc87' ,
'haircut_man' : '\ud83d\udc87\u200d\u2642\ufe0f' ,
'haircut_woman' : '\ud83d\udc87\u200d\u2640\ufe0f' ,
'haiti' : '\ud83c\udded\ud83c\uddf9' ,
'hamburger' : '\ud83c\udf54' ,
'hammer' : '\ud83d\udd28' ,
'hammer_and_pick' : '\u2692\ufe0f' ,
'hammer_and_wrench' : '\ud83d\udee0\ufe0f' ,
'hamster' : '\ud83d\udc39' ,
'hand' : '\u270b' ,
'hand_over_mouth' : '\ud83e\udd2d' ,
'handbag' : '\ud83d\udc5c' ,
'handball_person' : '\ud83e\udd3e' ,
'handshake' : '\ud83e\udd1d' ,
'hankey' : '\ud83d\udca9' ,
'hash' : '#\ufe0f\u20e3' ,
'hatched_chick' : '\ud83d\udc25' ,
'hatching_chick' : '\ud83d\udc23' ,
'headphones' : '\ud83c\udfa7' ,
'health_worker' : '\ud83e\uddd1\u200d\u2695\ufe0f' ,
'hear_no_evil' : '\ud83d\ude49' ,
'heard_mcdonald_islands' : '\ud83c\udded\ud83c\uddf2' ,
'heart' : '\u2764\ufe0f' ,
'heart_decoration' : '\ud83d\udc9f' ,
'heart_eyes' : '\ud83d\ude0d' ,
'heart_eyes_cat' : '\ud83d\ude3b' ,
'heartbeat' : '\ud83d\udc93' ,
'heartpulse' : '\ud83d\udc97' ,
'hearts' : '\u2665\ufe0f' ,
'heavy_check_mark' : '\u2714\ufe0f' ,
'heavy_division_sign' : '\u2797' ,
'heavy_dollar_sign' : '\ud83d\udcb2' ,
'heavy_exclamation_mark' : '\u2757' ,
'heavy_heart_exclamation' : '\u2763\ufe0f' ,
'heavy_minus_sign' : '\u2796' ,
'heavy_multiplication_x' : '\u2716\ufe0f' ,
'heavy_plus_sign' : '\u2795' ,
'hedgehog' : '\ud83e\udd94' ,
'helicopter' : '\ud83d\ude81' ,
'herb' : '\ud83c\udf3f' ,
'hibiscus' : '\ud83c\udf3a' ,
'high_brightness' : '\ud83d\udd06' ,
'high_heel' : '\ud83d\udc60' ,
'hiking_boot' : '\ud83e\udd7e' ,
'hindu_temple' : '\ud83d\uded5' ,
'hippopotamus' : '\ud83e\udd9b' ,
'hocho' : '\ud83d\udd2a' ,
'hole' : '\ud83d\udd73\ufe0f' ,
'honduras' : '\ud83c\udded\ud83c\uddf3' ,
'honey_pot' : '\ud83c\udf6f' ,
'honeybee' : '\ud83d\udc1d' ,
'hong_kong' : '\ud83c\udded\ud83c\uddf0' ,
'horse' : '\ud83d\udc34' ,
'horse_racing' : '\ud83c\udfc7' ,
'hospital' : '\ud83c\udfe5' ,
'hot_face' : '\ud83e\udd75' ,
'hot_pepper' : '\ud83c\udf36\ufe0f' ,
'hotdog' : '\ud83c\udf2d' ,
'hotel' : '\ud83c\udfe8' ,
'hotsprings' : '\u2668\ufe0f' ,
'hourglass' : '\u231b' ,
'hourglass_flowing_sand' : '\u23f3' ,
'house' : '\ud83c\udfe0' ,
'house_with_garden' : '\ud83c\udfe1' ,
'houses' : '\ud83c\udfd8\ufe0f' ,
'hugs' : '\ud83e\udd17' ,
'hungary' : '\ud83c\udded\ud83c\uddfa' ,
'hushed' : '\ud83d\ude2f' ,
'ice_cream' : '\ud83c\udf68' ,
'ice_cube' : '\ud83e\uddca' ,
'ice_hockey' : '\ud83c\udfd2' ,
'ice_skate' : '\u26f8\ufe0f' ,
'icecream' : '\ud83c\udf66' ,
'iceland' : '\ud83c\uddee\ud83c\uddf8' ,
'id' : '\ud83c\udd94' ,
'ideograph_advantage' : '\ud83c\ude50' ,
'imp' : '\ud83d\udc7f' ,
'inbox_tray' : '\ud83d\udce5' ,
'incoming_envelope' : '\ud83d\udce8' ,
'india' : '\ud83c\uddee\ud83c\uddf3' ,
'indonesia' : '\ud83c\uddee\ud83c\udde9' ,
'infinity' : '\u267e\ufe0f' ,
'information_desk_person' : '\ud83d\udc81' ,
'information_source' : '\u2139\ufe0f' ,
'innocent' : '\ud83d\ude07' ,
'interrobang' : '\u2049\ufe0f' ,
'iphone' : '\ud83d\udcf1' ,
'iran' : '\ud83c\uddee\ud83c\uddf7' ,
'iraq' : '\ud83c\uddee\ud83c\uddf6' ,
'ireland' : '\ud83c\uddee\ud83c\uddea' ,
'isle_of_man' : '\ud83c\uddee\ud83c\uddf2' ,
'israel' : '\ud83c\uddee\ud83c\uddf1' ,
'it' : '\ud83c\uddee\ud83c\uddf9' ,
'izakaya_lantern' : '\ud83c\udfee' ,
'jack_o_lantern' : '\ud83c\udf83' ,
'jamaica' : '\ud83c\uddef\ud83c\uddf2' ,
'japan' : '\ud83d\uddfe' ,
'japanese_castle' : '\ud83c\udfef' ,
'japanese_goblin' : '\ud83d\udc7a' ,
'japanese_ogre' : '\ud83d\udc79' ,
'jeans' : '\ud83d\udc56' ,
'jersey' : '\ud83c\uddef\ud83c\uddea' ,
'jigsaw' : '\ud83e\udde9' ,
'jordan' : '\ud83c\uddef\ud83c\uddf4' ,
'joy' : '\ud83d\ude02' ,
'joy_cat' : '\ud83d\ude39' ,
'joystick' : '\ud83d\udd79\ufe0f' ,
'jp' : '\ud83c\uddef\ud83c\uddf5' ,
'judge' : '\ud83e\uddd1\u200d\u2696\ufe0f' ,
'juggling_person' : '\ud83e\udd39' ,
'kaaba' : '\ud83d\udd4b' ,
'kangaroo' : '\ud83e\udd98' ,
'kazakhstan' : '\ud83c\uddf0\ud83c\uddff' ,
'kenya' : '\ud83c\uddf0\ud83c\uddea' ,
'key' : '\ud83d\udd11' ,
'keyboard' : '\u2328\ufe0f' ,
'keycap_ten' : '\ud83d\udd1f' ,
'kick_scooter' : '\ud83d\udef4' ,
'kimono' : '\ud83d\udc58' ,
'kiribati' : '\ud83c\uddf0\ud83c\uddee' ,
'kiss' : '\ud83d\udc8b' ,
'kissing' : '\ud83d\ude17' ,
'kissing_cat' : '\ud83d\ude3d' ,
'kissing_closed_eyes' : '\ud83d\ude1a' ,
'kissing_heart' : '\ud83d\ude18' ,
'kissing_smiling_eyes' : '\ud83d\ude19' ,
'kite' : '\ud83e\ude81' ,
'kiwi_fruit' : '\ud83e\udd5d' ,
'kneeling_man' : '\ud83e\uddce\u200d\u2642\ufe0f' ,
'kneeling_person' : '\ud83e\uddce' ,
'kneeling_woman' : '\ud83e\uddce\u200d\u2640\ufe0f' ,
'knife' : '\ud83d\udd2a' ,
'koala' : '\ud83d\udc28' ,
'koko' : '\ud83c\ude01' ,
'kosovo' : '\ud83c\uddfd\ud83c\uddf0' ,
'kr' : '\ud83c\uddf0\ud83c\uddf7' ,
'kuwait' : '\ud83c\uddf0\ud83c\uddfc' ,
'kyrgyzstan' : '\ud83c\uddf0\ud83c\uddec' ,
'lab_coat' : '\ud83e\udd7c' ,
'label' : '\ud83c\udff7\ufe0f' ,
'lacrosse' : '\ud83e\udd4d' ,
'lantern' : '\ud83c\udfee' ,
'laos' : '\ud83c\uddf1\ud83c\udde6' ,
'large_blue_circle' : '\ud83d\udd35' ,
'large_blue_diamond' : '\ud83d\udd37' ,
'large_orange_diamond' : '\ud83d\udd36' ,
'last_quarter_moon' : '\ud83c\udf17' ,
'last_quarter_moon_with_face' : '\ud83c\udf1c' ,
'latin_cross' : '\u271d\ufe0f' ,
'latvia' : '\ud83c\uddf1\ud83c\uddfb' ,
'laughing' : '\ud83d\ude06' ,
'leafy_green' : '\ud83e\udd6c' ,
'leaves' : '\ud83c\udf43' ,
'lebanon' : '\ud83c\uddf1\ud83c\udde7' ,
'ledger' : '\ud83d\udcd2' ,
'left_luggage' : '\ud83d\udec5' ,
'left_right_arrow' : '\u2194\ufe0f' ,
'left_speech_bubble' : '\ud83d\udde8\ufe0f' ,
'leftwards_arrow_with_hook' : '\u21a9\ufe0f' ,
'leg' : '\ud83e\uddb5' ,
'lemon' : '\ud83c\udf4b' ,
'leo' : '\u264c' ,
'leopard' : '\ud83d\udc06' ,
'lesotho' : '\ud83c\uddf1\ud83c\uddf8' ,
'level_slider' : '\ud83c\udf9a\ufe0f' ,
'liberia' : '\ud83c\uddf1\ud83c\uddf7' ,
'libra' : '\u264e' ,
'libya' : '\ud83c\uddf1\ud83c\uddfe' ,
'liechtenstein' : '\ud83c\uddf1\ud83c\uddee' ,
'light_rail' : '\ud83d\ude88' ,
'link' : '\ud83d\udd17' ,
'lion' : '\ud83e\udd81' ,
'lips' : '\ud83d\udc44' ,
'lipstick' : '\ud83d\udc84' ,
'lithuania' : '\ud83c\uddf1\ud83c\uddf9' ,
'lizard' : '\ud83e\udd8e' ,
'llama' : '\ud83e\udd99' ,
'lobster' : '\ud83e\udd9e' ,
'lock' : '\ud83d\udd12' ,
'lock_with_ink_pen' : '\ud83d\udd0f' ,
'lollipop' : '\ud83c\udf6d' ,
'loop' : '\u27bf' ,
'lotion_bottle' : '\ud83e\uddf4' ,
'lotus_position' : '\ud83e\uddd8' ,
'lotus_position_man' : '\ud83e\uddd8\u200d\u2642\ufe0f' ,
'lotus_position_woman' : '\ud83e\uddd8\u200d\u2640\ufe0f' ,
'loud_sound' : '\ud83d\udd0a' ,
'loudspeaker' : '\ud83d\udce2' ,
'love_hotel' : '\ud83c\udfe9' ,
'love_letter' : '\ud83d\udc8c' ,
'love_you_gesture' : '\ud83e\udd1f' ,
'low_brightness' : '\ud83d\udd05' ,
'luggage' : '\ud83e\uddf3' ,
'luxembourg' : '\ud83c\uddf1\ud83c\uddfa' ,
'lying_face' : '\ud83e\udd25' ,
'm' : '\u24c2\ufe0f' ,
'macau' : '\ud83c\uddf2\ud83c\uddf4' ,
'macedonia' : '\ud83c\uddf2\ud83c\uddf0' ,
'madagascar' : '\ud83c\uddf2\ud83c\uddec' ,
'mag' : '\ud83d\udd0d' ,
'mag_right' : '\ud83d\udd0e' ,
'mage' : '\ud83e\uddd9' ,
'mage_man' : '\ud83e\uddd9\u200d\u2642\ufe0f' ,
'mage_woman' : '\ud83e\uddd9\u200d\u2640\ufe0f' ,
'magnet' : '\ud83e\uddf2' ,
'mahjong' : '\ud83c\udc04' ,
'mailbox' : '\ud83d\udceb' ,
'mailbox_closed' : '\ud83d\udcea' ,
'mailbox_with_mail' : '\ud83d\udcec' ,
'mailbox_with_no_mail' : '\ud83d\udced' ,
'malawi' : '\ud83c\uddf2\ud83c\uddfc' ,
'malaysia' : '\ud83c\uddf2\ud83c\uddfe' ,
'maldives' : '\ud83c\uddf2\ud83c\uddfb' ,
'male_detective' : '\ud83d\udd75\ufe0f\u200d\u2642\ufe0f' ,
'male_sign' : '\u2642\ufe0f' ,
'mali' : '\ud83c\uddf2\ud83c\uddf1' ,
'malta' : '\ud83c\uddf2\ud83c\uddf9' ,
'man' : '\ud83d\udc68' ,
'man_artist' : '\ud83d\udc68\u200d\ud83c\udfa8' ,
'man_astronaut' : '\ud83d\udc68\u200d\ud83d\ude80' ,
'man_cartwheeling' : '\ud83e\udd38\u200d\u2642\ufe0f' ,
'man_cook' : '\ud83d\udc68\u200d\ud83c\udf73' ,
'man_dancing' : '\ud83d\udd7a' ,
'man_facepalming' : '\ud83e\udd26\u200d\u2642\ufe0f' ,
'man_factory_worker' : '\ud83d\udc68\u200d\ud83c\udfed' ,
'man_farmer' : '\ud83d\udc68\u200d\ud83c\udf3e' ,
'man_firefighter' : '\ud83d\udc68\u200d\ud83d\ude92' ,
'man_health_worker' : '\ud83d\udc68\u200d\u2695\ufe0f' ,
'man_in_manual_wheelchair' : '\ud83d\udc68\u200d\ud83e\uddbd' ,
'man_in_motorized_wheelchair' : '\ud83d\udc68\u200d\ud83e\uddbc' ,
'man_in_tuxedo' : '\ud83e\udd35' ,
'man_judge' : '\ud83d\udc68\u200d\u2696\ufe0f' ,
'man_juggling' : '\ud83e\udd39\u200d\u2642\ufe0f' ,
'man_mechanic' : '\ud83d\udc68\u200d\ud83d\udd27' ,
'man_office_worker' : '\ud83d\udc68\u200d\ud83d\udcbc' ,
'man_pilot' : '\ud83d\udc68\u200d\u2708\ufe0f' ,
'man_playing_handball' : '\ud83e\udd3e\u200d\u2642\ufe0f' ,
'man_playing_water_polo' : '\ud83e\udd3d\u200d\u2642\ufe0f' ,
'man_scientist' : '\ud83d\udc68\u200d\ud83d\udd2c' ,
'man_shrugging' : '\ud83e\udd37\u200d\u2642\ufe0f' ,
'man_singer' : '\ud83d\udc68\u200d\ud83c\udfa4' ,
'man_student' : '\ud83d\udc68\u200d\ud83c\udf93' ,
'man_teacher' : '\ud83d\udc68\u200d\ud83c\udfeb' ,
'man_technologist' : '\ud83d\udc68\u200d\ud83d\udcbb' ,
'man_with_gua_pi_mao' : '\ud83d\udc72' ,
'man_with_probing_cane' : '\ud83d\udc68\u200d\ud83e\uddaf' ,
'man_with_turban' : '\ud83d\udc73\u200d\u2642\ufe0f' ,
'mandarin' : '\ud83c\udf4a' ,
'mango' : '\ud83e\udd6d' ,
'mans_shoe' : '\ud83d\udc5e' ,
'mantelpiece_clock' : '\ud83d\udd70\ufe0f' ,
'manual_wheelchair' : '\ud83e\uddbd' ,
'maple_leaf' : '\ud83c\udf41' ,
'marshall_islands' : '\ud83c\uddf2\ud83c\udded' ,
'martial_arts_uniform' : '\ud83e\udd4b' ,
'martinique' : '\ud83c\uddf2\ud83c\uddf6' ,
'mask' : '\ud83d\ude37' ,
'massage' : '\ud83d\udc86' ,
'massage_man' : '\ud83d\udc86\u200d\u2642\ufe0f' ,
'massage_woman' : '\ud83d\udc86\u200d\u2640\ufe0f' ,
'mate' : '\ud83e\uddc9' ,
'mauritania' : '\ud83c\uddf2\ud83c\uddf7' ,
'mauritius' : '\ud83c\uddf2\ud83c\uddfa' ,
'mayotte' : '\ud83c\uddfe\ud83c\uddf9' ,
'meat_on_bone' : '\ud83c\udf56' ,
'mechanic' : '\ud83e\uddd1\u200d\ud83d\udd27' ,
'mechanical_arm' : '\ud83e\uddbe' ,
'mechanical_leg' : '\ud83e\uddbf' ,
'medal_military' : '\ud83c\udf96\ufe0f' ,
'medal_sports' : '\ud83c\udfc5' ,
'medical_symbol' : '\u2695\ufe0f' ,
'mega' : '\ud83d\udce3' ,
'melon' : '\ud83c\udf48' ,
'memo' : '\ud83d\udcdd' ,
'men_wrestling' : '\ud83e\udd3c\u200d\u2642\ufe0f' ,
'menorah' : '\ud83d\udd4e' ,
'mens' : '\ud83d\udeb9' ,
'mermaid' : '\ud83e\udddc\u200d\u2640\ufe0f' ,
'merman' : '\ud83e\udddc\u200d\u2642\ufe0f' ,
'merperson' : '\ud83e\udddc' ,
'metal' : '\ud83e\udd18' ,
'metro' : '\ud83d\ude87' ,
'mexico' : '\ud83c\uddf2\ud83c\uddfd' ,
'microbe' : '\ud83e\udda0' ,
'micronesia' : '\ud83c\uddeb\ud83c\uddf2' ,
'microphone' : '\ud83c\udfa4' ,
'microscope' : '\ud83d\udd2c' ,
'middle_finger' : '\ud83d\udd95' ,
'milk_glass' : '\ud83e\udd5b' ,
'milky_way' : '\ud83c\udf0c' ,
'minibus' : '\ud83d\ude90' ,
'minidisc' : '\ud83d\udcbd' ,
'mobile_phone_off' : '\ud83d\udcf4' ,
'moldova' : '\ud83c\uddf2\ud83c\udde9' ,
'monaco' : '\ud83c\uddf2\ud83c\udde8' ,
'money_mouth_face' : '\ud83e\udd11' ,
'money_with_wings' : '\ud83d\udcb8' ,
'moneybag' : '\ud83d\udcb0' ,
'mongolia' : '\ud83c\uddf2\ud83c\uddf3' ,
'monkey' : '\ud83d\udc12' ,
'monkey_face' : '\ud83d\udc35' ,
'monocle_face' : '\ud83e\uddd0' ,
'monorail' : '\ud83d\ude9d' ,
'montenegro' : '\ud83c\uddf2\ud83c\uddea' ,
'montserrat' : '\ud83c\uddf2\ud83c\uddf8' ,
'moon' : '\ud83c\udf14' ,
'moon_cake' : '\ud83e\udd6e' ,
'morocco' : '\ud83c\uddf2\ud83c\udde6' ,
'mortar_board' : '\ud83c\udf93' ,
'mosque' : '\ud83d\udd4c' ,
'mosquito' : '\ud83e\udd9f' ,
'motor_boat' : '\ud83d\udee5\ufe0f' ,
'motor_scooter' : '\ud83d\udef5' ,
'motorcycle' : '\ud83c\udfcd\ufe0f' ,
'motorized_wheelchair' : '\ud83e\uddbc' ,
'motorway' : '\ud83d\udee3\ufe0f' ,
'mount_fuji' : '\ud83d\uddfb' ,
'mountain' : '\u26f0\ufe0f' ,
'mountain_bicyclist' : '\ud83d\udeb5' ,
'mountain_biking_man' : '\ud83d\udeb5\u200d\u2642\ufe0f' ,
'mountain_biking_woman' : '\ud83d\udeb5\u200d\u2640\ufe0f' ,
'mountain_cableway' : '\ud83d\udea0' ,
'mountain_railway' : '\ud83d\ude9e' ,
'mountain_snow' : '\ud83c\udfd4\ufe0f' ,
'mouse' : '\ud83d\udc2d' ,
'mouse2' : '\ud83d\udc01' ,
'movie_camera' : '\ud83c\udfa5' ,
'moyai' : '\ud83d\uddff' ,
'mozambique' : '\ud83c\uddf2\ud83c\uddff' ,
'mrs_claus' : '\ud83e\udd36' ,
'muscle' : '\ud83d\udcaa' ,
'mushroom' : '\ud83c\udf44' ,
'musical_keyboard' : '\ud83c\udfb9' ,
'musical_note' : '\ud83c\udfb5' ,
'musical_score' : '\ud83c\udfbc' ,
'mute' : '\ud83d\udd07' ,
'myanmar' : '\ud83c\uddf2\ud83c\uddf2' ,
'nail_care' : '\ud83d\udc85' ,
'name_badge' : '\ud83d\udcdb' ,
'namibia' : '\ud83c\uddf3\ud83c\udde6' ,
'national_park' : '\ud83c\udfde\ufe0f' ,
'nauru' : '\ud83c\uddf3\ud83c\uddf7' ,
'nauseated_face' : '\ud83e\udd22' ,
'nazar_amulet' : '\ud83e\uddff' ,
'necktie' : '\ud83d\udc54' ,
'negative_squared_cross_mark' : '\u274e' ,
'nepal' : '\ud83c\uddf3\ud83c\uddf5' ,
'nerd_face' : '\ud83e\udd13' ,
'netherlands' : '\ud83c\uddf3\ud83c\uddf1' ,
'neutral_face' : '\ud83d\ude10' ,
'new' : '\ud83c\udd95' ,
'new_caledonia' : '\ud83c\uddf3\ud83c\udde8' ,
'new_moon' : '\ud83c\udf11' ,
'new_moon_with_face' : '\ud83c\udf1a' ,
'new_zealand' : '\ud83c\uddf3\ud83c\uddff' ,
'newspaper' : '\ud83d\udcf0' ,
'newspaper_roll' : '\ud83d\uddde\ufe0f' ,
'next_track_button' : '\u23ed\ufe0f' ,
'ng' : '\ud83c\udd96' ,
'ng_man' : '\ud83d\ude45\u200d\u2642\ufe0f' ,
'ng_woman' : '\ud83d\ude45\u200d\u2640\ufe0f' ,
'nicaragua' : '\ud83c\uddf3\ud83c\uddee' ,
'niger' : '\ud83c\uddf3\ud83c\uddea' ,
'nigeria' : '\ud83c\uddf3\ud83c\uddec' ,
'night_with_stars' : '\ud83c\udf03' ,
'nine' : '9\ufe0f\u20e3' ,
'niue' : '\ud83c\uddf3\ud83c\uddfa' ,
'no_bell' : '\ud83d\udd15' ,
'no_bicycles' : '\ud83d\udeb3' ,
'no_entry' : '\u26d4' ,
'no_entry_sign' : '\ud83d\udeab' ,
'no_good' : '\ud83d\ude45' ,
'no_good_man' : '\ud83d\ude45\u200d\u2642\ufe0f' ,
'no_good_woman' : '\ud83d\ude45\u200d\u2640\ufe0f' ,
'no_mobile_phones' : '\ud83d\udcf5' ,
'no_mouth' : '\ud83d\ude36' ,
'no_pedestrians' : '\ud83d\udeb7' ,
'no_smoking' : '\ud83d\udead' ,
'non-potable_water' : '\ud83d\udeb1' ,
'norfolk_island' : '\ud83c\uddf3\ud83c\uddeb' ,
'north_korea' : '\ud83c\uddf0\ud83c\uddf5' ,
'northern_mariana_islands' : '\ud83c\uddf2\ud83c\uddf5' ,
'norway' : '\ud83c\uddf3\ud83c\uddf4' ,
'nose' : '\ud83d\udc43' ,
'notebook' : '\ud83d\udcd3' ,
'notebook_with_decorative_cover' : '\ud83d\udcd4' ,
'notes' : '\ud83c\udfb6' ,
'nut_and_bolt' : '\ud83d\udd29' ,
'o' : '\u2b55' ,
'o2' : '\ud83c\udd7e\ufe0f' ,
'ocean' : '\ud83c\udf0a' ,
'octopus' : '\ud83d\udc19' ,
'oden' : '\ud83c\udf62' ,
'office' : '\ud83c\udfe2' ,
'office_worker' : '\ud83e\uddd1\u200d\ud83d\udcbc' ,
'oil_drum' : '\ud83d\udee2\ufe0f' ,
'ok' : '\ud83c\udd97' ,
'ok_hand' : '\ud83d\udc4c' ,
'ok_man' : '\ud83d\ude46\u200d\u2642\ufe0f' ,
'ok_person' : '\ud83d\ude46' ,
'ok_woman' : '\ud83d\ude46\u200d\u2640\ufe0f' ,
'old_key' : '\ud83d\udddd\ufe0f' ,
'older_adult' : '\ud83e\uddd3' ,
'older_man' : '\ud83d\udc74' ,
'older_woman' : '\ud83d\udc75' ,
'om' : '\ud83d\udd49\ufe0f' ,
'oman' : '\ud83c\uddf4\ud83c\uddf2' ,
'on' : '\ud83d\udd1b' ,
'oncoming_automobile' : '\ud83d\ude98' ,
'oncoming_bus' : '\ud83d\ude8d' ,
'oncoming_police_car' : '\ud83d\ude94' ,
'oncoming_taxi' : '\ud83d\ude96' ,
'one' : '1\ufe0f\u20e3' ,
'one_piece_swimsuit' : '\ud83e\ude71' ,
'onion' : '\ud83e\uddc5' ,
'open_book' : '\ud83d\udcd6' ,
'open_file_folder' : '\ud83d\udcc2' ,
'open_hands' : '\ud83d\udc50' ,
'open_mouth' : '\ud83d\ude2e' ,
'open_umbrella' : '\u2602\ufe0f' ,
'ophiuchus' : '\u26ce' ,
'orange' : '\ud83c\udf4a' ,
'orange_book' : '\ud83d\udcd9' ,
'orange_circle' : '\ud83d\udfe0' ,
'orange_heart' : '\ud83e\udde1' ,
'orange_square' : '\ud83d\udfe7' ,
'orangutan' : '\ud83e\udda7' ,
'orthodox_cross' : '\u2626\ufe0f' ,
'otter' : '\ud83e\udda6' ,
'outbox_tray' : '\ud83d\udce4' ,
'owl' : '\ud83e\udd89' ,
'ox' : '\ud83d\udc02' ,
'oyster' : '\ud83e\uddaa' ,
'package' : '\ud83d\udce6' ,
'page_facing_up' : '\ud83d\udcc4' ,
'page_with_curl' : '\ud83d\udcc3' ,
'pager' : '\ud83d\udcdf' ,
'paintbrush' : '\ud83d\udd8c\ufe0f' ,
'pakistan' : '\ud83c\uddf5\ud83c\uddf0' ,
'palau' : '\ud83c\uddf5\ud83c\uddfc' ,
'palestinian_territories' : '\ud83c\uddf5\ud83c\uddf8' ,
'palm_tree' : '\ud83c\udf34' ,
'palms_up_together' : '\ud83e\udd32' ,
'panama' : '\ud83c\uddf5\ud83c\udde6' ,
'pancakes' : '\ud83e\udd5e' ,
'panda_face' : '\ud83d\udc3c' ,
'paperclip' : '\ud83d\udcce' ,
'paperclips' : '\ud83d\udd87\ufe0f' ,
'papua_new_guinea' : '\ud83c\uddf5\ud83c\uddec' ,
'parachute' : '\ud83e\ude82' ,
'paraguay' : '\ud83c\uddf5\ud83c\uddfe' ,
'parasol_on_ground' : '\u26f1\ufe0f' ,
'parking' : '\ud83c\udd7f\ufe0f' ,
'parrot' : '\ud83e\udd9c' ,
'part_alternation_mark' : '\u303d\ufe0f' ,
'partly_sunny' : '\u26c5' ,
'partying_face' : '\ud83e\udd73' ,
'passenger_ship' : '\ud83d\udef3\ufe0f' ,
'passport_control' : '\ud83d\udec2' ,
'pause_button' : '\u23f8\ufe0f' ,
'paw_prints' : '\ud83d\udc3e' ,
'peace_symbol' : '\u262e\ufe0f' ,
'peach' : '\ud83c\udf51' ,
'peacock' : '\ud83e\udd9a' ,
'peanuts' : '\ud83e\udd5c' ,
'pear' : '\ud83c\udf50' ,
'pen' : '\ud83d\udd8a\ufe0f' ,
'pencil' : '\ud83d\udcdd' ,
'pencil2' : '\u270f\ufe0f' ,
'penguin' : '\ud83d\udc27' ,
'pensive' : '\ud83d\ude14' ,
'people_holding_hands' : '\ud83e\uddd1\u200d\ud83e\udd1d\u200d\ud83e\uddd1' ,
'performing_arts' : '\ud83c\udfad' ,
'persevere' : '\ud83d\ude23' ,
'person_bald' : '\ud83e\uddd1\u200d\ud83e\uddb2' ,
'person_curly_hair' : '\ud83e\uddd1\u200d\ud83e\uddb1' ,
'person_fencing' : '\ud83e\udd3a' ,
'person_in_manual_wheelchair' : '\ud83e\uddd1\u200d\ud83e\uddbd' ,
'person_in_motorized_wheelchair' : '\ud83e\uddd1\u200d\ud83e\uddbc' ,
'person_red_hair' : '\ud83e\uddd1\u200d\ud83e\uddb0' ,
'person_white_hair' : '\ud83e\uddd1\u200d\ud83e\uddb3' ,
'person_with_probing_cane' : '\ud83e\uddd1\u200d\ud83e\uddaf' ,
'person_with_turban' : '\ud83d\udc73' ,
'peru' : '\ud83c\uddf5\ud83c\uddea' ,
'petri_dish' : '\ud83e\uddeb' ,
'philippines' : '\ud83c\uddf5\ud83c\udded' ,
'phone' : '\u260e\ufe0f' ,
'pick' : '\u26cf\ufe0f' ,
'pie' : '\ud83e\udd67' ,
'pig' : '\ud83d\udc37' ,
'pig2' : '\ud83d\udc16' ,
'pig_nose' : '\ud83d\udc3d' ,
'pill' : '\ud83d\udc8a' ,
'pilot' : '\ud83e\uddd1\u200d\u2708\ufe0f' ,
'pinching_hand' : '\ud83e\udd0f' ,
'pineapple' : '\ud83c\udf4d' ,
'ping_pong' : '\ud83c\udfd3' ,
'pirate_flag' : '\ud83c\udff4\u200d\u2620\ufe0f' ,
'pisces' : '\u2653' ,
'pitcairn_islands' : '\ud83c\uddf5\ud83c\uddf3' ,
'pizza' : '\ud83c\udf55' ,
'place_of_worship' : '\ud83d\uded0' ,
'plate_with_cutlery' : '\ud83c\udf7d\ufe0f' ,
'play_or_pause_button' : '\u23ef\ufe0f' ,
'pleading_face' : '\ud83e\udd7a' ,
'point_down' : '\ud83d\udc47' ,
'point_left' : '\ud83d\udc48' ,
'point_right' : '\ud83d\udc49' ,
'point_up' : '\u261d\ufe0f' ,
'point_up_2' : '\ud83d\udc46' ,
'poland' : '\ud83c\uddf5\ud83c\uddf1' ,
'police_car' : '\ud83d\ude93' ,
'police_officer' : '\ud83d\udc6e' ,
'policeman' : '\ud83d\udc6e\u200d\u2642\ufe0f' ,
'policewoman' : '\ud83d\udc6e\u200d\u2640\ufe0f' ,
'poodle' : '\ud83d\udc29' ,
'poop' : '\ud83d\udca9' ,
'popcorn' : '\ud83c\udf7f' ,
'portugal' : '\ud83c\uddf5\ud83c\uddf9' ,
'post_office' : '\ud83c\udfe3' ,
'postal_horn' : '\ud83d\udcef' ,
'postbox' : '\ud83d\udcee' ,
'potable_water' : '\ud83d\udeb0' ,
'potato' : '\ud83e\udd54' ,
'pouch' : '\ud83d\udc5d' ,
'poultry_leg' : '\ud83c\udf57' ,
'pound' : '\ud83d\udcb7' ,
'pout' : '\ud83d\ude21' ,
'pouting_cat' : '\ud83d\ude3e' ,
'pouting_face' : '\ud83d\ude4e' ,
'pouting_man' : '\ud83d\ude4e\u200d\u2642\ufe0f' ,
'pouting_woman' : '\ud83d\ude4e\u200d\u2640\ufe0f' ,
'pray' : '\ud83d\ude4f' ,
'prayer_beads' : '\ud83d\udcff' ,
'pregnant_woman' : '\ud83e\udd30' ,
'pretzel' : '\ud83e\udd68' ,
'previous_track_button' : '\u23ee\ufe0f' ,
'prince' : '\ud83e\udd34' ,
'princess' : '\ud83d\udc78' ,
'printer' : '\ud83d\udda8\ufe0f' ,
'probing_cane' : '\ud83e\uddaf' ,
'puerto_rico' : '\ud83c\uddf5\ud83c\uddf7' ,
'punch' : '\ud83d\udc4a' ,
'purple_circle' : '\ud83d\udfe3' ,
'purple_heart' : '\ud83d\udc9c' ,
'purple_square' : '\ud83d\udfea' ,
'purse' : '\ud83d\udc5b' ,
'pushpin' : '\ud83d\udccc' ,
'put_litter_in_its_place' : '\ud83d\udeae' ,
'qatar' : '\ud83c\uddf6\ud83c\udde6' ,
'question' : '\u2753' ,
'rabbit' : '\ud83d\udc30' ,
'rabbit2' : '\ud83d\udc07' ,
'raccoon' : '\ud83e\udd9d' ,
'racehorse' : '\ud83d\udc0e' ,
'racing_car' : '\ud83c\udfce\ufe0f' ,
'radio' : '\ud83d\udcfb' ,
'radio_button' : '\ud83d\udd18' ,
'radioactive' : '\u2622\ufe0f' ,
'rage' : '\ud83d\ude21' ,
'railway_car' : '\ud83d\ude83' ,
'railway_track' : '\ud83d\udee4\ufe0f' ,
'rainbow' : '\ud83c\udf08' ,
'rainbow_flag' : '\ud83c\udff3\ufe0f\u200d\ud83c\udf08' ,
'raised_back_of_hand' : '\ud83e\udd1a' ,
'raised_eyebrow' : '\ud83e\udd28' ,
'raised_hand' : '\u270b' ,
'raised_hand_with_fingers_splayed' : '\ud83d\udd90\ufe0f' ,
'raised_hands' : '\ud83d\ude4c' ,
'raising_hand' : '\ud83d\ude4b' ,
'raising_hand_man' : '\ud83d\ude4b\u200d\u2642\ufe0f' ,
'raising_hand_woman' : '\ud83d\ude4b\u200d\u2640\ufe0f' ,
'ram' : '\ud83d\udc0f' ,
'ramen' : '\ud83c\udf5c' ,
'rat' : '\ud83d\udc00' ,
'razor' : '\ud83e\ude92' ,
'receipt' : '\ud83e\uddfe' ,
'record_button' : '\u23fa\ufe0f' ,
'recycle' : '\u267b\ufe0f' ,
'red_car' : '\ud83d\ude97' ,
'red_circle' : '\ud83d\udd34' ,
'red_envelope' : '\ud83e\udde7' ,
'red_haired_man' : '\ud83d\udc68\u200d\ud83e\uddb0' ,
'red_haired_woman' : '\ud83d\udc69\u200d\ud83e\uddb0' ,
'red_square' : '\ud83d\udfe5' ,
'registered' : '\u00ae\ufe0f' ,
'relaxed' : '\u263a\ufe0f' ,
'relieved' : '\ud83d\ude0c' ,
'reminder_ribbon' : '\ud83c\udf97\ufe0f' ,
'repeat' : '\ud83d\udd01' ,
'repeat_one' : '\ud83d\udd02' ,
'rescue_worker_helmet' : '\u26d1\ufe0f' ,
'restroom' : '\ud83d\udebb' ,
'reunion' : '\ud83c\uddf7\ud83c\uddea' ,
'revolving_hearts' : '\ud83d\udc9e' ,
'rewind' : '\u23ea' ,
'rhinoceros' : '\ud83e\udd8f' ,
'ribbon' : '\ud83c\udf80' ,
'rice' : '\ud83c\udf5a' ,
'rice_ball' : '\ud83c\udf59' ,
'rice_cracker' : '\ud83c\udf58' ,
'rice_scene' : '\ud83c\udf91' ,
'right_anger_bubble' : '\ud83d\uddef\ufe0f' ,
'ring' : '\ud83d\udc8d' ,
'ringed_planet' : '\ud83e\ude90' ,
'robot' : '\ud83e\udd16' ,
'rocket' : '\ud83d\ude80' ,
'rofl' : '\ud83e\udd23' ,
'roll_eyes' : '\ud83d\ude44' ,
'roll_of_paper' : '\ud83e\uddfb' ,
'roller_coaster' : '\ud83c\udfa2' ,
'romania' : '\ud83c\uddf7\ud83c\uddf4' ,
'rooster' : '\ud83d\udc13' ,
'rose' : '\ud83c\udf39' ,
'rosette' : '\ud83c\udff5\ufe0f' ,
'rotating_light' : '\ud83d\udea8' ,
'round_pushpin' : '\ud83d\udccd' ,
'rowboat' : '\ud83d\udea3' ,
'rowing_man' : '\ud83d\udea3\u200d\u2642\ufe0f' ,
'rowing_woman' : '\ud83d\udea3\u200d\u2640\ufe0f' ,
'ru' : '\ud83c\uddf7\ud83c\uddfa' ,
'rugby_football' : '\ud83c\udfc9' ,
'runner' : '\ud83c\udfc3' ,
'running' : '\ud83c\udfc3' ,
'running_man' : '\ud83c\udfc3\u200d\u2642\ufe0f' ,
'running_shirt_with_sash' : '\ud83c\udfbd' ,
'running_woman' : '\ud83c\udfc3\u200d\u2640\ufe0f' ,
'rwanda' : '\ud83c\uddf7\ud83c\uddfc' ,
'sa' : '\ud83c\ude02\ufe0f' ,
'safety_pin' : '\ud83e\uddf7' ,
'safety_vest' : '\ud83e\uddba' ,
'sagittarius' : '\u2650' ,
'sailboat' : '\u26f5' ,
'sake' : '\ud83c\udf76' ,
'salt' : '\ud83e\uddc2' ,
'samoa' : '\ud83c\uddfc\ud83c\uddf8' ,
'san_marino' : '\ud83c\uddf8\ud83c\uddf2' ,
'sandal' : '\ud83d\udc61' ,
'sandwich' : '\ud83e\udd6a' ,
'santa' : '\ud83c\udf85' ,
'sao_tome_principe' : '\ud83c\uddf8\ud83c\uddf9' ,
'sari' : '\ud83e\udd7b' ,
'sassy_man' : '\ud83d\udc81\u200d\u2642\ufe0f' ,
'sassy_woman' : '\ud83d\udc81\u200d\u2640\ufe0f' ,
'satellite' : '\ud83d\udce1' ,
'satisfied' : '\ud83d\ude06' ,
'saudi_arabia' : '\ud83c\uddf8\ud83c\udde6' ,
'sauna_man' : '\ud83e\uddd6\u200d\u2642\ufe0f' ,
'sauna_person' : '\ud83e\uddd6' ,
'sauna_woman' : '\ud83e\uddd6\u200d\u2640\ufe0f' ,
'sauropod' : '\ud83e\udd95' ,
'saxophone' : '\ud83c\udfb7' ,
'scarf' : '\ud83e\udde3' ,
'school' : '\ud83c\udfeb' ,
'school_satchel' : '\ud83c\udf92' ,
'scientist' : '\ud83e\uddd1\u200d\ud83d\udd2c' ,
'scissors' : '\u2702\ufe0f' ,
'scorpion' : '\ud83e\udd82' ,
'scorpius' : '\u264f' ,
'scotland' : '\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc73\udb40\udc63\udb40\udc74\udb40\udc7f' ,
'scream' : '\ud83d\ude31' ,
'scream_cat' : '\ud83d\ude40' ,
'scroll' : '\ud83d\udcdc' ,
'seat' : '\ud83d\udcba' ,
'secret' : '\u3299\ufe0f' ,
'see_no_evil' : '\ud83d\ude48' ,
'seedling' : '\ud83c\udf31' ,
'selfie' : '\ud83e\udd33' ,
'senegal' : '\ud83c\uddf8\ud83c\uddf3' ,
'serbia' : '\ud83c\uddf7\ud83c\uddf8' ,
'service_dog' : '\ud83d\udc15\u200d\ud83e\uddba' ,
'seven' : '7\ufe0f\u20e3' ,
'seychelles' : '\ud83c\uddf8\ud83c\udde8' ,
'shallow_pan_of_food' : '\ud83e\udd58' ,
'shamrock' : '\u2618\ufe0f' ,
'shark' : '\ud83e\udd88' ,
'shaved_ice' : '\ud83c\udf67' ,
'sheep' : '\ud83d\udc11' ,
'shell' : '\ud83d\udc1a' ,
'shield' : '\ud83d\udee1\ufe0f' ,
'shinto_shrine' : '\u26e9\ufe0f' ,
'ship' : '\ud83d\udea2' ,
'shirt' : '\ud83d\udc55' ,
'shit' : '\ud83d\udca9' ,
'shoe' : '\ud83d\udc5e' ,
'shopping' : '\ud83d\udecd\ufe0f' ,
'shopping_cart' : '\ud83d\uded2' ,
'shorts' : '\ud83e\ude73' ,
'shower' : '\ud83d\udebf' ,
'shrimp' : '\ud83e\udd90' ,
'shrug' : '\ud83e\udd37' ,
'shushing_face' : '\ud83e\udd2b' ,
'sierra_leone' : '\ud83c\uddf8\ud83c\uddf1' ,
'signal_strength' : '\ud83d\udcf6' ,
'singapore' : '\ud83c\uddf8\ud83c\uddec' ,
'singer' : '\ud83e\uddd1\u200d\ud83c\udfa4' ,
'sint_maarten' : '\ud83c\uddf8\ud83c\uddfd' ,
'six' : '6\ufe0f\u20e3' ,
'six_pointed_star' : '\ud83d\udd2f' ,
'skateboard' : '\ud83d\udef9' ,
'ski' : '\ud83c\udfbf' ,
'skier' : '\u26f7\ufe0f' ,
'skull' : '\ud83d\udc80' ,
'skull_and_crossbones' : '\u2620\ufe0f' ,
'skunk' : '\ud83e\udda8' ,
'sled' : '\ud83d\udef7' ,
'sleeping' : '\ud83d\ude34' ,
'sleeping_bed' : '\ud83d\udecc' ,
'sleepy' : '\ud83d\ude2a' ,
'slightly_frowning_face' : '\ud83d\ude41' ,
'slightly_smiling_face' : '\ud83d\ude42' ,
'slot_machine' : '\ud83c\udfb0' ,
'sloth' : '\ud83e\udda5' ,
'slovakia' : '\ud83c\uddf8\ud83c\uddf0' ,
'slovenia' : '\ud83c\uddf8\ud83c\uddee' ,
'small_airplane' : '\ud83d\udee9\ufe0f' ,
'small_blue_diamond' : '\ud83d\udd39' ,
'small_orange_diamond' : '\ud83d\udd38' ,
'small_red_triangle' : '\ud83d\udd3a' ,
'small_red_triangle_down' : '\ud83d\udd3b' ,
'smile' : '\ud83d\ude04' ,
'smile_cat' : '\ud83d\ude38' ,
'smiley' : '\ud83d\ude03' ,
'smiley_cat' : '\ud83d\ude3a' ,
'smiling_face_with_three_hearts' : '\ud83e\udd70' ,
'smiling_imp' : '\ud83d\ude08' ,
'smirk' : '\ud83d\ude0f' ,
'smirk_cat' : '\ud83d\ude3c' ,
'smoking' : '\ud83d\udeac' ,
'snail' : '\ud83d\udc0c' ,
'snake' : '\ud83d\udc0d' ,
'sneezing_face' : '\ud83e\udd27' ,
'snowboarder' : '\ud83c\udfc2' ,
'snowflake' : '\u2744\ufe0f' ,
'snowman' : '\u26c4' ,
'snowman_with_snow' : '\u2603\ufe0f' ,
'soap' : '\ud83e\uddfc' ,
'sob' : '\ud83d\ude2d' ,
'soccer' : '\u26bd' ,
'socks' : '\ud83e\udde6' ,
'softball' : '\ud83e\udd4e' ,
'solomon_islands' : '\ud83c\uddf8\ud83c\udde7' ,
'somalia' : '\ud83c\uddf8\ud83c\uddf4' ,
'soon' : '\ud83d\udd1c' ,
'sos' : '\ud83c\udd98' ,
'sound' : '\ud83d\udd09' ,
'south_africa' : '\ud83c\uddff\ud83c\udde6' ,
'south_georgia_south_sandwich_islands' : '\ud83c\uddec\ud83c\uddf8' ,
'south_sudan' : '\ud83c\uddf8\ud83c\uddf8' ,
'space_invader' : '\ud83d\udc7e' ,
'spades' : '\u2660\ufe0f' ,
'spaghetti' : '\ud83c\udf5d' ,
'sparkle' : '\u2747\ufe0f' ,
'sparkler' : '\ud83c\udf87' ,
'sparkles' : '\u2728' ,
'sparkling_heart' : '\ud83d\udc96' ,
'speak_no_evil' : '\ud83d\ude4a' ,
'speaker' : '\ud83d\udd08' ,
'speaking_head' : '\ud83d\udde3\ufe0f' ,
'speech_balloon' : '\ud83d\udcac' ,
'speedboat' : '\ud83d\udea4' ,
'spider' : '\ud83d\udd77\ufe0f' ,
'spider_web' : '\ud83d\udd78\ufe0f' ,
'spiral_calendar' : '\ud83d\uddd3\ufe0f' ,
'spiral_notepad' : '\ud83d\uddd2\ufe0f' ,
'sponge' : '\ud83e\uddfd' ,
'spoon' : '\ud83e\udd44' ,
'squid' : '\ud83e\udd91' ,
'sri_lanka' : '\ud83c\uddf1\ud83c\uddf0' ,
'st_barthelemy' : '\ud83c\udde7\ud83c\uddf1' ,
'st_helena' : '\ud83c\uddf8\ud83c\udded' ,
'st_kitts_nevis' : '\ud83c\uddf0\ud83c\uddf3' ,
'st_lucia' : '\ud83c\uddf1\ud83c\udde8' ,
'st_martin' : '\ud83c\uddf2\ud83c\uddeb' ,
'st_pierre_miquelon' : '\ud83c\uddf5\ud83c\uddf2' ,
'st_vincent_grenadines' : '\ud83c\uddfb\ud83c\udde8' ,
'stadium' : '\ud83c\udfdf\ufe0f' ,
'standing_man' : '\ud83e\uddcd\u200d\u2642\ufe0f' ,
'standing_person' : '\ud83e\uddcd' ,
'standing_woman' : '\ud83e\uddcd\u200d\u2640\ufe0f' ,
'star' : '\u2b50' ,
'star2' : '\ud83c\udf1f' ,
'star_and_crescent' : '\u262a\ufe0f' ,
'star_of_david' : '\u2721\ufe0f' ,
'star_struck' : '\ud83e\udd29' ,
'stars' : '\ud83c\udf20' ,
'station' : '\ud83d\ude89' ,
'statue_of_liberty' : '\ud83d\uddfd' ,
'steam_locomotive' : '\ud83d\ude82' ,
'stethoscope' : '\ud83e\ude7a' ,
'stew' : '\ud83c\udf72' ,
'stop_button' : '\u23f9\ufe0f' ,
'stop_sign' : '\ud83d\uded1' ,
'stopwatch' : '\u23f1\ufe0f' ,
'straight_ruler' : '\ud83d\udccf' ,
'strawberry' : '\ud83c\udf53' ,
'stuck_out_tongue' : '\ud83d\ude1b' ,
'stuck_out_tongue_closed_eyes' : '\ud83d\ude1d' ,
'stuck_out_tongue_winking_eye' : '\ud83d\ude1c' ,
'student' : '\ud83e\uddd1\u200d\ud83c\udf93' ,
'studio_microphone' : '\ud83c\udf99\ufe0f' ,
'stuffed_flatbread' : '\ud83e\udd59' ,
'sudan' : '\ud83c\uddf8\ud83c\udde9' ,
'sun_behind_large_cloud' : '\ud83c\udf25\ufe0f' ,
'sun_behind_rain_cloud' : '\ud83c\udf26\ufe0f' ,
'sun_behind_small_cloud' : '\ud83c\udf24\ufe0f' ,
'sun_with_face' : '\ud83c\udf1e' ,
'sunflower' : '\ud83c\udf3b' ,
'sunglasses' : '\ud83d\ude0e' ,
'sunny' : '\u2600\ufe0f' ,
'sunrise' : '\ud83c\udf05' ,
'sunrise_over_mountains' : '\ud83c\udf04' ,
'superhero' : '\ud83e\uddb8' ,
'superhero_man' : '\ud83e\uddb8\u200d\u2642\ufe0f' ,
'superhero_woman' : '\ud83e\uddb8\u200d\u2640\ufe0f' ,
'supervillain' : '\ud83e\uddb9' ,
'supervillain_man' : '\ud83e\uddb9\u200d\u2642\ufe0f' ,
'supervillain_woman' : '\ud83e\uddb9\u200d\u2640\ufe0f' ,
'surfer' : '\ud83c\udfc4' ,
'surfing_man' : '\ud83c\udfc4\u200d\u2642\ufe0f' ,
'surfing_woman' : '\ud83c\udfc4\u200d\u2640\ufe0f' ,
'suriname' : '\ud83c\uddf8\ud83c\uddf7' ,
'sushi' : '\ud83c\udf63' ,
'suspension_railway' : '\ud83d\ude9f' ,
'svalbard_jan_mayen' : '\ud83c\uddf8\ud83c\uddef' ,
'swan' : '\ud83e\udda2' ,
'swaziland' : '\ud83c\uddf8\ud83c\uddff' ,
'sweat' : '\ud83d\ude13' ,
'sweat_drops' : '\ud83d\udca6' ,
'sweat_smile' : '\ud83d\ude05' ,
'sweden' : '\ud83c\uddf8\ud83c\uddea' ,
'sweet_potato' : '\ud83c\udf60' ,
'swim_brief' : '\ud83e\ude72' ,
'swimmer' : '\ud83c\udfca' ,
'swimming_man' : '\ud83c\udfca\u200d\u2642\ufe0f' ,
'swimming_woman' : '\ud83c\udfca\u200d\u2640\ufe0f' ,
'switzerland' : '\ud83c\udde8\ud83c\udded' ,
'symbols' : '\ud83d\udd23' ,
'synagogue' : '\ud83d\udd4d' ,
'syria' : '\ud83c\uddf8\ud83c\uddfe' ,
'syringe' : '\ud83d\udc89' ,
't-rex' : '\ud83e\udd96' ,
'taco' : '\ud83c\udf2e' ,
'tada' : '\ud83c\udf89' ,
'taiwan' : '\ud83c\uddf9\ud83c\uddfc' ,
'tajikistan' : '\ud83c\uddf9\ud83c\uddef' ,
'takeout_box' : '\ud83e\udd61' ,
'tanabata_tree' : '\ud83c\udf8b' ,
'tangerine' : '\ud83c\udf4a' ,
'tanzania' : '\ud83c\uddf9\ud83c\uddff' ,
'taurus' : '\u2649' ,
'taxi' : '\ud83d\ude95' ,
'tea' : '\ud83c\udf75' ,
'teacher' : '\ud83e\uddd1\u200d\ud83c\udfeb' ,
'technologist' : '\ud83e\uddd1\u200d\ud83d\udcbb' ,
'teddy_bear' : '\ud83e\uddf8' ,
'telephone' : '\u260e\ufe0f' ,
'telephone_receiver' : '\ud83d\udcde' ,
'telescope' : '\ud83d\udd2d' ,
'tennis' : '\ud83c\udfbe' ,
'tent' : '\u26fa' ,
'test_tube' : '\ud83e\uddea' ,
'thailand' : '\ud83c\uddf9\ud83c\udded' ,
'thermometer' : '\ud83c\udf21\ufe0f' ,
'thinking' : '\ud83e\udd14' ,
'thought_balloon' : '\ud83d\udcad' ,
'thread' : '\ud83e\uddf5' ,
'three' : '3\ufe0f\u20e3' ,
'thumbsdown' : '\ud83d\udc4e' ,
'thumbsup' : '\ud83d\udc4d' ,
'ticket' : '\ud83c\udfab' ,
'tickets' : '\ud83c\udf9f\ufe0f' ,
'tiger' : '\ud83d\udc2f' ,
'tiger2' : '\ud83d\udc05' ,
'timer_clock' : '\u23f2\ufe0f' ,
'timor_leste' : '\ud83c\uddf9\ud83c\uddf1' ,
'tipping_hand_man' : '\ud83d\udc81\u200d\u2642\ufe0f' ,
'tipping_hand_person' : '\ud83d\udc81' ,
'tipping_hand_woman' : '\ud83d\udc81\u200d\u2640\ufe0f' ,
'tired_face' : '\ud83d\ude2b' ,
'tm' : '\u2122\ufe0f' ,
'togo' : '\ud83c\uddf9\ud83c\uddec' ,
'toilet' : '\ud83d\udebd' ,
'tokelau' : '\ud83c\uddf9\ud83c\uddf0' ,
'tokyo_tower' : '\ud83d\uddfc' ,
'tomato' : '\ud83c\udf45' ,
'tonga' : '\ud83c\uddf9\ud83c\uddf4' ,
'tongue' : '\ud83d\udc45' ,
'toolbox' : '\ud83e\uddf0' ,
'tooth' : '\ud83e\uddb7' ,
'top' : '\ud83d\udd1d' ,
'tophat' : '\ud83c\udfa9' ,
'tornado' : '\ud83c\udf2a\ufe0f' ,
'tr' : '\ud83c\uddf9\ud83c\uddf7' ,
'trackball' : '\ud83d\uddb2\ufe0f' ,
'tractor' : '\ud83d\ude9c' ,
'traffic_light' : '\ud83d\udea5' ,
'train' : '\ud83d\ude8b' ,
'train2' : '\ud83d\ude86' ,
'tram' : '\ud83d\ude8a' ,
'triangular_flag_on_post' : '\ud83d\udea9' ,
'triangular_ruler' : '\ud83d\udcd0' ,
'trident' : '\ud83d\udd31' ,
'trinidad_tobago' : '\ud83c\uddf9\ud83c\uddf9' ,
'tristan_da_cunha' : '\ud83c\uddf9\ud83c\udde6' ,
'triumph' : '\ud83d\ude24' ,
'trolleybus' : '\ud83d\ude8e' ,
'trophy' : '\ud83c\udfc6' ,
'tropical_drink' : '\ud83c\udf79' ,
'tropical_fish' : '\ud83d\udc20' ,
'truck' : '\ud83d\ude9a' ,
'trumpet' : '\ud83c\udfba' ,
'tshirt' : '\ud83d\udc55' ,
'tulip' : '\ud83c\udf37' ,
'tumbler_glass' : '\ud83e\udd43' ,
'tunisia' : '\ud83c\uddf9\ud83c\uddf3' ,
'turkey' : '\ud83e\udd83' ,
'turkmenistan' : '\ud83c\uddf9\ud83c\uddf2' ,
'turks_caicos_islands' : '\ud83c\uddf9\ud83c\udde8' ,
'turtle' : '\ud83d\udc22' ,
'tuvalu' : '\ud83c\uddf9\ud83c\uddfb' ,
'tv' : '\ud83d\udcfa' ,
'twisted_rightwards_arrows' : '\ud83d\udd00' ,
'two' : '2\ufe0f\u20e3' ,
'two_hearts' : '\ud83d\udc95' ,
'two_men_holding_hands' : '\ud83d\udc6c' ,
'two_women_holding_hands' : '\ud83d\udc6d' ,
'u5272' : '\ud83c\ude39' ,
'u5408' : '\ud83c\ude34' ,
'u55b6' : '\ud83c\ude3a' ,
'u6307' : '\ud83c\ude2f' ,
'u6708' : '\ud83c\ude37\ufe0f' ,
'u6709' : '\ud83c\ude36' ,
'u6e80' : '\ud83c\ude35' ,
'u7121' : '\ud83c\ude1a' ,
'u7533' : '\ud83c\ude38' ,
'u7981' : '\ud83c\ude32' ,
'u7a7a' : '\ud83c\ude33' ,
'uganda' : '\ud83c\uddfa\ud83c\uddec' ,
'uk' : '\ud83c\uddec\ud83c\udde7' ,
'ukraine' : '\ud83c\uddfa\ud83c\udde6' ,
'umbrella' : '\u2614' ,
'unamused' : '\ud83d\ude12' ,
'underage' : '\ud83d\udd1e' ,
'unicorn' : '\ud83e\udd84' ,
'united_arab_emirates' : '\ud83c\udde6\ud83c\uddea' ,
'united_nations' : '\ud83c\uddfa\ud83c\uddf3' ,
'unlock' : '\ud83d\udd13' ,
'up' : '\ud83c\udd99' ,
'upside_down_face' : '\ud83d\ude43' ,
'uruguay' : '\ud83c\uddfa\ud83c\uddfe' ,
'us' : '\ud83c\uddfa\ud83c\uddf8' ,
'us_outlying_islands' : '\ud83c\uddfa\ud83c\uddf2' ,
'us_virgin_islands' : '\ud83c\uddfb\ud83c\uddee' ,
'uzbekistan' : '\ud83c\uddfa\ud83c\uddff' ,
'v' : '\u270c\ufe0f' ,
'vampire' : '\ud83e\udddb' ,
'vampire_man' : '\ud83e\udddb\u200d\u2642\ufe0f' ,
'vampire_woman' : '\ud83e\udddb\u200d\u2640\ufe0f' ,
'vanuatu' : '\ud83c\uddfb\ud83c\uddfa' ,
'vatican_city' : '\ud83c\uddfb\ud83c\udde6' ,
'venezuela' : '\ud83c\uddfb\ud83c\uddea' ,
'vertical_traffic_light' : '\ud83d\udea6' ,
'vhs' : '\ud83d\udcfc' ,
'vibration_mode' : '\ud83d\udcf3' ,
'video_camera' : '\ud83d\udcf9' ,
'video_game' : '\ud83c\udfae' ,
'vietnam' : '\ud83c\uddfb\ud83c\uddf3' ,
'violin' : '\ud83c\udfbb' ,
'virgo' : '\u264d' ,
'volcano' : '\ud83c\udf0b' ,
'volleyball' : '\ud83c\udfd0' ,
'vomiting_face' : '\ud83e\udd2e' ,
'vs' : '\ud83c\udd9a' ,
'vulcan_salute' : '\ud83d\udd96' ,
'waffle' : '\ud83e\uddc7' ,
'wales' : '\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc77\udb40\udc6c\udb40\udc73\udb40\udc7f' ,
'walking' : '\ud83d\udeb6' ,
'walking_man' : '\ud83d\udeb6\u200d\u2642\ufe0f' ,
'walking_woman' : '\ud83d\udeb6\u200d\u2640\ufe0f' ,
'wallis_futuna' : '\ud83c\uddfc\ud83c\uddeb' ,
'waning_crescent_moon' : '\ud83c\udf18' ,
'waning_gibbous_moon' : '\ud83c\udf16' ,
'warning' : '\u26a0\ufe0f' ,
'wastebasket' : '\ud83d\uddd1\ufe0f' ,
'watch' : '\u231a' ,
'water_buffalo' : '\ud83d\udc03' ,
'water_polo' : '\ud83e\udd3d' ,
'watermelon' : '\ud83c\udf49' ,
'wave' : '\ud83d\udc4b' ,
'wavy_dash' : '\u3030\ufe0f' ,
'waxing_crescent_moon' : '\ud83c\udf12' ,
'waxing_gibbous_moon' : '\ud83c\udf14' ,
'wc' : '\ud83d\udebe' ,
'weary' : '\ud83d\ude29' ,
'wedding' : '\ud83d\udc92' ,
'weight_lifting' : '\ud83c\udfcb\ufe0f' ,
'weight_lifting_man' : '\ud83c\udfcb\ufe0f\u200d\u2642\ufe0f' ,
'weight_lifting_woman' : '\ud83c\udfcb\ufe0f\u200d\u2640\ufe0f' ,
'western_sahara' : '\ud83c\uddea\ud83c\udded' ,
'whale' : '\ud83d\udc33' ,
'whale2' : '\ud83d\udc0b' ,
'wheel_of_dharma' : '\u2638\ufe0f' ,
'wheelchair' : '\u267f' ,
'white_check_mark' : '\u2705' ,
'white_circle' : '\u26aa' ,
'white_flag' : '\ud83c\udff3\ufe0f' ,
'white_flower' : '\ud83d\udcae' ,
'white_haired_man' : '\ud83d\udc68\u200d\ud83e\uddb3' ,
'white_haired_woman' : '\ud83d\udc69\u200d\ud83e\uddb3' ,
'white_heart' : '\ud83e\udd0d' ,
'white_large_square' : '\u2b1c' ,
'white_medium_small_square' : '\u25fd' ,
'white_medium_square' : '\u25fb\ufe0f' ,
'white_small_square' : '\u25ab\ufe0f' ,
'white_square_button' : '\ud83d\udd33' ,
'wilted_flower' : '\ud83e\udd40' ,
'wind_chime' : '\ud83c\udf90' ,
'wind_face' : '\ud83c\udf2c\ufe0f' ,
'wine_glass' : '\ud83c\udf77' ,
'wink' : '\ud83d\ude09' ,
'wolf' : '\ud83d\udc3a' ,
'woman' : '\ud83d\udc69' ,
'woman_artist' : '\ud83d\udc69\u200d\ud83c\udfa8' ,
'woman_astronaut' : '\ud83d\udc69\u200d\ud83d\ude80' ,
'woman_cartwheeling' : '\ud83e\udd38\u200d\u2640\ufe0f' ,
'woman_cook' : '\ud83d\udc69\u200d\ud83c\udf73' ,
'woman_dancing' : '\ud83d\udc83' ,
'woman_facepalming' : '\ud83e\udd26\u200d\u2640\ufe0f' ,
'woman_factory_worker' : '\ud83d\udc69\u200d\ud83c\udfed' ,
'woman_farmer' : '\ud83d\udc69\u200d\ud83c\udf3e' ,
'woman_firefighter' : '\ud83d\udc69\u200d\ud83d\ude92' ,
'woman_health_worker' : '\ud83d\udc69\u200d\u2695\ufe0f' ,
'woman_in_manual_wheelchair' : '\ud83d\udc69\u200d\ud83e\uddbd' ,
'woman_in_motorized_wheelchair' : '\ud83d\udc69\u200d\ud83e\uddbc' ,
'woman_judge' : '\ud83d\udc69\u200d\u2696\ufe0f' ,
'woman_juggling' : '\ud83e\udd39\u200d\u2640\ufe0f' ,
'woman_mechanic' : '\ud83d\udc69\u200d\ud83d\udd27' ,
'woman_office_worker' : '\ud83d\udc69\u200d\ud83d\udcbc' ,
'woman_pilot' : '\ud83d\udc69\u200d\u2708\ufe0f' ,
'woman_playing_handball' : '\ud83e\udd3e\u200d\u2640\ufe0f' ,
'woman_playing_water_polo' : '\ud83e\udd3d\u200d\u2640\ufe0f' ,
'woman_scientist' : '\ud83d\udc69\u200d\ud83d\udd2c' ,
'woman_shrugging' : '\ud83e\udd37\u200d\u2640\ufe0f' ,
'woman_singer' : '\ud83d\udc69\u200d\ud83c\udfa4' ,
'woman_student' : '\ud83d\udc69\u200d\ud83c\udf93' ,
'woman_teacher' : '\ud83d\udc69\u200d\ud83c\udfeb' ,
'woman_technologist' : '\ud83d\udc69\u200d\ud83d\udcbb' ,
'woman_with_headscarf' : '\ud83e\uddd5' ,
'woman_with_probing_cane' : '\ud83d\udc69\u200d\ud83e\uddaf' ,
'woman_with_turban' : '\ud83d\udc73\u200d\u2640\ufe0f' ,
'womans_clothes' : '\ud83d\udc5a' ,
'womans_hat' : '\ud83d\udc52' ,
'women_wrestling' : '\ud83e\udd3c\u200d\u2640\ufe0f' ,
'womens' : '\ud83d\udeba' ,
'woozy_face' : '\ud83e\udd74' ,
'world_map' : '\ud83d\uddfa\ufe0f' ,
'worried' : '\ud83d\ude1f' ,
'wrench' : '\ud83d\udd27' ,
'wrestling' : '\ud83e\udd3c' ,
'writing_hand' : '\u270d\ufe0f' ,
'x' : '\u274c' ,
'yarn' : '\ud83e\uddf6' ,
'yawning_face' : '\ud83e\udd71' ,
'yellow_circle' : '\ud83d\udfe1' ,
'yellow_heart' : '\ud83d\udc9b' ,
'yellow_square' : '\ud83d\udfe8' ,
'yemen' : '\ud83c\uddfe\ud83c\uddea' ,
'yen' : '\ud83d\udcb4' ,
'yin_yang' : '\u262f\ufe0f' ,
'yo_yo' : '\ud83e\ude80' ,
'yum' : '\ud83d\ude0b' ,
'zambia' : '\ud83c\uddff\ud83c\uddf2' ,
'zany_face' : '\ud83e\udd2a' ,
'zap' : '\u26a1' ,
'zebra' : '\ud83e\udd93' ,
'zero' : '0\ufe0f\u20e3' ,
'zimbabwe' : '\ud83c\uddff\ud83c\uddfc' ,
'zipper_mouth_face' : '\ud83e\udd10' ,
'zombie' : '\ud83e\udddf' ,
'zombie_man' : '\ud83e\udddf\u200d\u2642\ufe0f' ,
'zombie_woman' : '\ud83e\udddf\u200d\u2640\ufe0f' ,
'zzz' : '\ud83d\udca4' ,
/* special emojis :P */
2022-04-28 04:42:24 +08:00
'atom' : '<img alt="atom" width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/atom.png?v8">' ,
'basecamp' : '<img alt="basecamp" width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/basecamp.png?v8">' ,
'basecampy' : '<img alt="basecampy" width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/basecampy.png?v8">' ,
'bowtie' : '<img alt="bowtie" width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/bowtie.png?v8">' ,
'electron' : '<img alt="electron" width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/electron.png?v8">' ,
'feelsgood' : '<img alt="feelsgood" width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/feelsgood.png?v8">' ,
'finnadie' : '<img alt="finnadie" width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/finnadie.png?v8">' ,
'goberserk' : '<img alt="goberserk" width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/goberserk.png?v8">' ,
'godmode' : '<img alt="godmode" width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/godmode.png?v8">' ,
'hurtrealbad' : '<img alt="hurtrealbad" width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/hurtrealbad.png?v8">' ,
'neckbeard' : '<img alt="neckbeard" width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/neckbeard.png?v8">' ,
'octocat' : '<img alt="octocat" width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/octocat.png?v8">' ,
'rage1' : '<img alt="rage1" width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/rage1.png?v8">' ,
'rage2' : '<img alt="rage2" width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/rage2.png?v8">' ,
'rage3' : '<img alt="rage3" width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/rage3.png?v8">' ,
'rage4' : '<img alt="rage4" width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/rage4.png?v8">' ,
'shipit' : '<img alt="shipit" width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/shipit.png?v8">' ,
'suspect' : '<img alt="suspect" width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/suspect.png?v8">' ,
'trollface' : '<img alt="trollface" width="20" height="20" align="absmiddle" src="https://github.githubassets.com/images/icons/emoji/trollface.png?v8">' ,
'showdown' : '<img alt="showdown" width="20" height="20" align="absmiddle" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAS1BMVEX///8jJS0jJS0jJS0jJS0jJS0jJS0jJS0jJS0jJS0jJS0jJS0jJS0jJS0jJS0jJS0jJS3b1q3b1q3b1q3b1q3b1q3b1q3b1q3b1q0565CIAAAAGXRSTlMAQHCAYCCw/+DQwPCQUBAwoHCAEP+wwFBgS2fvBgAAAUZJREFUeAHs1cGy7BAUheFFsEDw/k97VTq3T6ge2EmdM+pvrP6Iwd74XV9Kb52xuMU4/uc1YNgZLFOeV8FGdhGrNk5SEgUyPxAEdj4LlMRDyhVAMVEa2M7TBSeVZAFPdqHgzSZJwPKgcLFLAooHDJo4EDCw4gAtBoJA5UFj4Ng5LOGLwVXZuoIlji/jeQHFk7+baHxrCjeUwB9+s88KndvlhcyBN5BSkYNQIVVb4pV+Npm7hhuKDs/uMP5KxT3WzSNNLIuuoDpMmuAVMruMSeDyQBi24DTr43LAY7ILA1QYaWkgfHzFthYYzg67SQsCbB8GhJUEGCtO9n0rSaCLxgJQjS/JSgMTg2eBDEHAJ+H350AsjYNYscrErgI2e/l+mdR967TCX/v6N0EhPECYCP0i+IAoYQOE8BogNhQMEMdrgAQWHaMAAGi5I5euoY9NAAAAAElFTkSuQmCC">'
2022-02-24 08:23:15 +08:00
} ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
/ * *
2022-04-28 04:42:24 +08:00
* Created by Estevao on 31 - 05 - 2015.
2022-02-24 08:23:15 +08:00
* /
2022-04-28 04:42:24 +08:00
showdown . Event = class {
/ * *
* Creates a new showdown Event object
* @ param { string } name
* @ param { string } input
* @ param { { } } [ params ]
* @ param { string } params . output
* @ param { RegExp } params . regexp
* @ param { { } } params . matches
* @ param { { } } params . attributes
* @ param { { } } params . globals
* @ param { { } } params . options
* @ param { showdown . Converter } params . converter
* /
constructor ( name , input , params ) {
params = params || { } ;
let { output , regexp , matches , attributes , globals , options , converter } = params ;
if ( ! showdown . helper . isString ( name ) ) {
if ( ! showdown . helper . isString ( name ) ) {
throw new TypeError ( 'Event.name must be a string but ' + typeof name + ' given' ) ;
}
}
this . _name = name . toLowerCase ( ) ;
this . input = input ;
this . output = output || input ;
this . regexp = regexp || null ;
this . matches = matches || { } ;
this . attributes = attributes || { } ;
this . _globals = globals || { } ;
this . _options = showdown . helper . cloneObject ( options , true ) || { } ;
this . _converter = converter || undefined ;
}
/** @returns {string} */
get name ( ) {
return this . _name ;
}
/** @returns {string} */
get input ( ) {
return this . _input ;
}
/** @param {string} value */
set input ( value ) {
if ( ! showdown . helper . isString ( value ) ) {
throw new TypeError ( 'Event.input must be a string but ' + typeof value + ' given' ) ;
}
this . _input = value ;
}
/** @returns {string} */
get output ( ) {
return this . _output ;
}
/** @param {string|null} value */
set output ( value ) {
if ( ! showdown . helper . isString ( value ) && value !== null ) {
throw new TypeError ( 'Event.output must be a string but ' + typeof value + ' given' ) ;
}
this . _output = value ;
}
/** @returns {null|RegExp} */
get regexp ( ) {
return this . _regexp ;
}
/** @param {null|RegExp} value */
set regexp ( value ) {
if ( ! ( value instanceof RegExp ) && value !== null ) {
throw new TypeError ( 'Event.regexp must be a RegExp object (or null) but ' + typeof value + ' given' ) ;
}
this . _regexp = value ;
}
/** @returns {{}} */
get matches ( ) {
return this . _matches ;
}
/** @param {{}}value */
set matches ( value ) {
if ( typeof value !== 'object' ) {
throw new TypeError ( 'Event.matches must be an object (or null) but ' + typeof value + ' given' ) ;
}
this . _matches = { } ;
for ( let prop in value ) {
if ( value . hasOwnProperty ( prop ) ) {
let descriptor = { } ;
if ( /^_(.+)/ . test ( prop ) ) {
descriptor = {
enumerable : true ,
configurable : false ,
writable : false ,
value : value [ prop ]
} ;
} else {
descriptor = {
enumerable : true ,
configurable : false ,
writable : true ,
value : value [ prop ]
} ;
}
Object . defineProperty ( this . _matches , prop , descriptor ) ;
}
}
}
/** @returns {{}} */
get attributes ( ) {
return this . _attributes ;
}
/** @param {{}} value */
set attributes ( value ) {
if ( typeof value !== 'object' ) {
throw new TypeError ( 'Event.attributes must be an object (or null) but ' + typeof value + ' given' ) ;
}
this . _attributes = value ;
}
/** @param {showdown.Converter} converter */
set converter ( converter ) {
this . _converter = converter ;
}
/** @returns {showdown.Converter} */
get converter ( ) {
return this . _converter ;
}
get options ( ) {
return this . _options ;
}
get globals ( ) {
return this . _globals ;
}
// FLUID INTERFACE
/ * *
*
* @ param { string } value
* @ returns { showdown . Event }
* /
setInput ( value ) {
this . input = value ;
return this ;
}
/ * *
*
* @ param { string | null } value
* @ returns { showdown . Event }
* /
setOutput ( value ) {
this . output = value ;
return this ;
}
/ * *
*
* @ param { RegExp } value
* @ returns { showdown . Event }
* /
setRegexp ( value ) {
this . regexp = value ;
return this ;
}
/ * *
*
* @ param { { } } value
* @ returns { showdown . Event }
* /
setMatches ( value ) {
this . matches = value ;
return this ;
}
/ * *
*
* @ param { { } } value
* @ returns { showdown . Event }
* /
setAttributes ( value ) {
this . attributes = value ;
return this ;
}
_setOptions ( value ) {
this . _options = value ;
return this ;
}
_setGlobals ( value ) {
this . _globals = value ;
return this ;
}
_setConverter ( value ) {
this . converter = value ;
return this ;
}
/ * *
* Legacy : Return the output text
* @ returns { string }
* /
getText ( ) {
return this . output ;
}
getMatches ( ) {
return this . matches ;
}
} ;
////
// makehtml/blockGamut.js
// Copyright (c) 2018 ShowdownJS
//
// These are all the transformations that form block-level
// tags like paragraphs, headers, and list items.
//
// ***Author:***
// - Estêvão Soares dos Santos (Tivie) <https://github.com/tivie>
////
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makehtml.blockGamut' , function ( text , options , globals ) {
'use strict' ;
2022-04-28 04:42:24 +08:00
let startEvent = new showdown . Event ( 'makehtml.blockGamut.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
2022-02-24 08:23:15 +08:00
// we parse blockquotes first so that we can have headings and hrs
// inside blockquotes
2022-04-28 04:42:24 +08:00
text = showdown . subParser ( 'makehtml.blockquote' ) ( text , options , globals ) ;
text = showdown . subParser ( 'makehtml.heading' ) ( text , options , globals ) ;
2022-02-24 08:23:15 +08:00
// Do Horizontal Rules:
text = showdown . subParser ( 'makehtml.horizontalRule' ) ( text , options , globals ) ;
2022-04-28 04:42:24 +08:00
text = showdown . subParser ( 'makehtml.list' ) ( text , options , globals ) ;
text = showdown . subParser ( 'makehtml.codeBlock' ) ( text , options , globals ) ;
text = showdown . subParser ( 'makehtml.table' ) ( text , options , globals ) ;
2022-02-24 08:23:15 +08:00
// We already ran _HashHTMLBlocks() before, in Markdown(), but that
// was to escape raw HTML in the original Markdown source. This time,
// we're escaping the markup we've just created, so that we don't wrap
// <p> tags around block-level tags.
text = showdown . subParser ( 'makehtml.hashHTMLBlocks' ) ( text , options , globals ) ;
text = showdown . subParser ( 'makehtml.paragraphs' ) ( text , options , globals ) ;
2022-04-28 04:42:24 +08:00
let afterEvent = new showdown . Event ( 'makehtml.blockGamut.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
////
// makehtml/blockquote.js
// Copyright (c) 2018 ShowdownJS
//
// Transforms MD blockquotes into `<blockquote>` html entities
//
// Markdown uses email-style > characters for blockquoting.
// Markdown allows you to be lazy and only put the > before the first line of a hard-wrapped paragraph but
// it looks best if the text is hard wrapped with a > before every line.
//
// ***Author:***
// - Estêvão Soares dos Santos (Tivie) <https://github.com/tivie>
////
2022-03-26 08:31:41 +08:00
2022-04-28 04:42:24 +08:00
showdown . subParser ( 'makehtml.blockquote' , function ( text , options , globals ) {
2022-02-24 08:23:15 +08:00
'use strict' ;
2022-04-28 04:42:24 +08:00
let startEvent = new showdown . Event ( 'makehtml.blockquote.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
2022-02-24 08:23:15 +08:00
// add a couple extra lines after the text and endtext mark
text = text + '\n\n' ;
2022-04-28 04:42:24 +08:00
let pattern = /(^ {0,3}>[ \t]?.+\n(.+\n)*\n*)+/gm ;
2022-02-24 08:23:15 +08:00
if ( options . splitAdjacentBlockquotes ) {
2022-04-28 04:42:24 +08:00
pattern = /^ {0,3}>[\s\S]*?\n\n/gm ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
text = text . replace ( pattern , function ( bq ) {
let otp ,
attributes = { } ,
wholeMatch = bq ;
2022-02-24 08:23:15 +08:00
// attacklab: hack around Konqueror 3.5.4 bug:
// "----------bug".replace(/^-/g,"") == "bug"
bq = bq . replace ( /^[ \t]*>[ \t]?/gm , '' ) ; // trim one level of quoting
// attacklab: clean up hack
bq = bq . replace ( /¨0/g , '' ) ;
bq = bq . replace ( /^[ \t]+$/gm , '' ) ; // trim whitespace-only lines
2022-04-28 04:42:24 +08:00
let captureStartEvent = new showdown . Event ( 'makehtml.blockquote.onCapture' , bq ) ;
captureStartEvent
. setOutput ( null )
. _setGlobals ( globals )
. _setOptions ( options )
. setRegexp ( pattern )
. setMatches ( {
_wholeMatch : wholeMatch ,
blockquote : bq
} )
. setAttributes ( { } ) ;
captureStartEvent = globals . converter . dispatch ( captureStartEvent ) ;
// if something was passed as output, it takes precedence
// and will be used as output
if ( captureStartEvent . output && captureStartEvent . output !== '' ) {
otp = captureStartEvent . output ;
} else {
bq = captureStartEvent . matches . blockquote ;
bq = showdown . subParser ( 'makehtml.githubCodeBlock' ) ( bq , options , globals ) ;
bq = showdown . subParser ( 'makehtml.blockGamut' ) ( bq , options , globals ) ; // recurse
bq = bq . replace ( /(^|\n)/g , '$1 ' ) ;
// These leading spaces screw with <pre> content, so we need to fix that:
bq = bq . replace ( /(\s*<pre>[^\r]+?<\/pre>)/gm , function ( wm , m1 ) {
return m1 . replace ( /^ {2}/mg , '' ) ;
} ) ;
attributes = captureStartEvent . attributes ;
otp = '<blockquote' + showdown . helper . _populateAttributes ( attributes ) + '>\n' + bq + '\n</blockquote>' ;
}
let beforeHashEvent = new showdown . Event ( 'makehtml.blockquote.onHash' , otp ) ;
beforeHashEvent
. setOutput ( otp )
. _setGlobals ( globals )
. _setOptions ( options ) ;
beforeHashEvent = globals . converter . dispatch ( beforeHashEvent ) ;
otp = beforeHashEvent . output ;
return showdown . subParser ( 'makehtml.hashBlock' ) ( otp , options , globals ) ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
let afterEvent = new showdown . Event ( 'makehtml.blockquote.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
////
// makehtml/codeBlock.js
// Copyright (c) 2022 ShowdownJS
//
// Process Markdown `<pre><code>` blocks.
//
// ***Author:***
// - Estêvão Soares dos Santos (Tivie) <https://github.com/tivie>
////
2022-03-26 08:31:41 +08:00
2022-04-28 04:42:24 +08:00
showdown . subParser ( 'makehtml.codeBlock' , function ( text , options , globals ) {
2022-02-24 08:23:15 +08:00
'use strict' ;
2022-04-28 04:42:24 +08:00
let startEvent = new showdown . Event ( 'makehtml.codeBlock.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
2022-02-24 08:23:15 +08:00
// sentinel workarounds for lack of \A and \Z, safari\khtml bug
text += '¨0' ;
2022-04-28 04:42:24 +08:00
let pattern = /(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=¨0))/g ;
2022-02-24 08:23:15 +08:00
text = text . replace ( pattern , function ( wholeMatch , m1 , m2 ) {
2022-04-28 04:42:24 +08:00
let codeblock = m1 ,
2022-02-24 08:23:15 +08:00
nextChar = m2 ,
2022-04-28 04:42:24 +08:00
end = '\n' ,
otp ,
attributes = {
pre : { } ,
code : { }
} ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
let captureStartEvent = new showdown . Event ( 'makehtml.codeBlock.onCapture' , codeblock ) ;
captureStartEvent
. setOutput ( null )
. _setGlobals ( globals )
. _setOptions ( options )
. setRegexp ( pattern )
. setMatches ( {
_wholeMatch : wholeMatch ,
codeblock : codeblock
} )
. setAttributes ( attributes ) ;
captureStartEvent = globals . converter . dispatch ( captureStartEvent ) ;
// if something was passed as output, it takes precedence
// and will be used as output
if ( captureStartEvent . output && captureStartEvent . output !== '' ) {
otp = captureStartEvent . output ;
} else {
codeblock = captureStartEvent . matches . codeblock ;
codeblock = showdown . helper . outdent ( codeblock ) ;
codeblock = showdown . subParser ( 'makehtml.encodeCode' ) ( codeblock , options , globals ) ;
codeblock = showdown . subParser ( 'makehtml.detab' ) ( codeblock , options , globals ) ;
codeblock = codeblock . replace ( /^\n+/g , '' ) ; // trim leading newlines
codeblock = codeblock . replace ( /\n+$/g , '' ) ; // trim trailing newlines
attributes = captureStartEvent . attributes ;
otp = '<pre><code>' ;
if ( ! showdown . helper . isUndefined ( attributes ) ) {
otp = '<pre' + showdown . helper . _populateAttributes ( attributes . pre ) + '>' ;
otp += '<code' + showdown . helper . _populateAttributes ( attributes . code ) + '>' ;
}
if ( options . omitExtraWLInCodeBlocks ) {
end = '' ;
}
otp += codeblock + end + '</code></pre>' ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
let beforeHashEvent = new showdown . Event ( 'makehtml.codeBlock.onHash' , otp ) ;
beforeHashEvent
. setOutput ( otp )
. _setGlobals ( globals )
. _setOptions ( options ) ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
beforeHashEvent = globals . converter . dispatch ( beforeHashEvent ) ;
otp = beforeHashEvent . output ;
return showdown . subParser ( 'makehtml.hashBlock' ) ( otp , options , globals ) + nextChar ;
2022-02-24 08:23:15 +08:00
} ) ;
// strip sentinel
text = text . replace ( /¨0/ , '' ) ;
2022-04-28 04:42:24 +08:00
let afterEvent = new showdown . Event ( 'makehtml.codeBlock.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
////
// makehtml/codeSpan.js
// Copyright (c) 2018 ShowdownJS
//
// Transforms MD code spans into `<code>` html entities
//
// Backtick quotes are used for <code></code> spans.
//
// You can use multiple backticks as the delimiters if you want to
// include literal backticks in the code span. So, this input:
//
// Just type ``foo `bar` baz`` at the prompt.
//
// Will translate to:
//
// <p>Just type <code>foo `bar` baz</code> at the prompt.</p>
//
// There's no arbitrary limit to the number of backticks you
// can use as delimters. If you need three consecutive backticks
// in your code, use four for delimiters, etc.
//
// You can use spaces to get literal backticks at the edges:
// ... type `` `bar` `` ...
//
// Turns to:
// ... type <code>`bar`</code> ...
//
// ***Author:***
// - Estêvão Soares dos Santos (Tivie) <https://github.com/tivie>
////
2022-03-26 08:31:41 +08:00
2022-04-28 04:42:24 +08:00
showdown . subParser ( 'makehtml.codeSpan' , function ( text , options , globals ) {
2022-02-24 08:23:15 +08:00
'use strict' ;
2022-04-28 04:42:24 +08:00
let startEvent = new showdown . Event ( 'makehtml.codeSpan.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
if ( showdown . helper . isUndefined ( ( text ) ) ) {
2022-02-24 08:23:15 +08:00
text = '' ;
}
2022-04-28 04:42:24 +08:00
let pattern = /(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm ;
text = text . replace ( pattern , function ( wholeMatch , m1 , m2 , c ) {
let otp ,
attributes = { } ;
c = c . replace ( /^([ \t]*)/g , '' ) ; // leading whitespace
c = c . replace ( /[ \t]*$/g , '' ) ; // trailing whitespace
let captureStartEvent = new showdown . Event ( 'makehtml.codeSpan.onCapture' , c ) ;
captureStartEvent
. setOutput ( null )
. _setGlobals ( globals )
. _setOptions ( options )
. setRegexp ( pattern )
. setMatches ( {
_wholeMatch : wholeMatch ,
code : c
} )
. setAttributes ( { } ) ;
captureStartEvent = globals . converter . dispatch ( captureStartEvent ) ;
// if something was passed as output, it takes precedence
// and will be used as output
if ( captureStartEvent . output && captureStartEvent . output !== '' ) {
otp = m1 + captureStartEvent . output ;
} else {
c = captureStartEvent . matches . code ;
2022-02-24 08:23:15 +08:00
c = showdown . subParser ( 'makehtml.encodeCode' ) ( c , options , globals ) ;
2022-04-28 04:42:24 +08:00
otp = m1 + '<code' + showdown . helper . _populateAttributes ( attributes ) + '>' + c + '</code>' ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
let beforeHashEvent = new showdown . Event ( 'makehtml.codeSpan.onHash' , otp ) ;
beforeHashEvent
. setOutput ( otp )
. _setGlobals ( globals )
. _setOptions ( options ) ;
beforeHashEvent = globals . converter . dispatch ( beforeHashEvent ) ;
otp = beforeHashEvent . output ;
return showdown . subParser ( 'makehtml.hashHTMLSpans' ) ( otp , options , globals ) ;
}
2022-02-24 08:23:15 +08:00
) ;
2022-04-28 04:42:24 +08:00
let afterEvent = new showdown . Event ( 'makehtml.codeSpan.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
////
// makehtml/completeHTMLDocument.js
// Copyright (c) 2018 ShowdownJS
//
// Create a full HTML document from the processed markdown
//
// ***Author:***
// - Estêvão Soares dos Santos (Tivie) <https://github.com/tivie>
////
2022-03-26 08:31:41 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makehtml.completeHTMLDocument' , function ( text , options , globals ) {
'use strict' ;
if ( ! options . completeHTMLDocument ) {
return text ;
}
2022-04-28 04:42:24 +08:00
let startEvent = new showdown . Event ( 'makehtml.completeHTMLDocument.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
let doctype = 'html' ,
2022-02-24 08:23:15 +08:00
doctypeParsed = '<!DOCTYPE HTML>\n' ,
title = '' ,
charset = '<meta charset="utf-8">\n' ,
lang = '' ,
metadata = '' ;
if ( typeof globals . metadata . parsed . doctype !== 'undefined' ) {
doctypeParsed = '<!DOCTYPE ' + globals . metadata . parsed . doctype + '>\n' ;
doctype = globals . metadata . parsed . doctype . toString ( ) . toLowerCase ( ) ;
if ( doctype === 'html' || doctype === 'html5' ) {
charset = '<meta charset="utf-8">' ;
}
}
2022-04-28 04:42:24 +08:00
for ( let meta in globals . metadata . parsed ) {
2022-02-24 08:23:15 +08:00
if ( globals . metadata . parsed . hasOwnProperty ( meta ) ) {
switch ( meta . toLowerCase ( ) ) {
case 'doctype' :
break ;
case 'title' :
title = '<title>' + globals . metadata . parsed . title + '</title>\n' ;
break ;
case 'charset' :
if ( doctype === 'html' || doctype === 'html5' ) {
charset = '<meta charset="' + globals . metadata . parsed . charset + '">\n' ;
} else {
charset = '<meta name="charset" content="' + globals . metadata . parsed . charset + '">\n' ;
}
break ;
case 'language' :
case 'lang' :
lang = ' lang="' + globals . metadata . parsed [ meta ] + '"' ;
metadata += '<meta name="' + meta + '" content="' + globals . metadata . parsed [ meta ] + '">\n' ;
break ;
default :
metadata += '<meta name="' + meta + '" content="' + globals . metadata . parsed [ meta ] + '">\n' ;
}
}
}
text = doctypeParsed + '<html' + lang + '>\n<head>\n' + title + charset + metadata + '</head>\n<body>\n' + text . trim ( ) + '\n</body>\n</html>' ;
2022-04-28 04:42:24 +08:00
let afterEvent = new showdown . Event ( 'makehtml.completeHTMLDocument.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
////
// makehtml/detab.js
// Copyright (c) 2018 ShowdownJS
//
// Convert all tabs to spaces
//
// ***Author:***
// - Estêvão Soares dos Santos (Tivie) <https://github.com/tivie>
////
2022-03-26 08:31:41 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makehtml.detab' , function ( text , options , globals ) {
'use strict' ;
2022-04-28 04:42:24 +08:00
let startEvent = new showdown . Event ( 'makehtml.detab.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
2022-02-24 08:23:15 +08:00
// expand first n-1 tabs
text = text . replace ( /\t(?=\t)/g , ' ' ) ; // g_tab_width
// replace the nth with two sentinels
text = text . replace ( /\t/g , '¨A¨B' ) ;
// use the sentinel to anchor our regex so it doesn't explode
text = text . replace ( /¨B(.+?)¨A/g , function ( wholeMatch , m1 ) {
var leadingText = m1 ,
numSpaces = 4 - leadingText . length % 4 ; // g_tab_width
// there *must* be a better way to do this:
for ( var i = 0 ; i < numSpaces ; i ++ ) {
leadingText += ' ' ;
}
return leadingText ;
} ) ;
// clean up sentinels
text = text . replace ( /¨A/g , ' ' ) ; // g_tab_width
text = text . replace ( /¨B/g , '' ) ;
2022-04-28 04:42:24 +08:00
let afterEvent = new showdown . Event ( 'makehtml.detab.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
////
// makehtml/ellipsis.js
// Copyright (c) 2018 ShowdownJS
//
// transform three dots (...) into ellipsis (…)
//
// ***Author:***
// - Estêvão Soares dos Santos (Tivie) <https://github.com/tivie>
////
2022-03-26 08:31:41 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makehtml.ellipsis' , function ( text , options , globals ) {
'use strict' ;
if ( ! options . ellipsis ) {
return text ;
}
2022-04-28 04:42:24 +08:00
let startEvent = new showdown . Event ( 'makehtml.ellipsis.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
2022-02-24 08:23:15 +08:00
text = text . replace ( /\.\.\./g , '…' ) ;
2022-04-28 04:42:24 +08:00
let afterEvent = new showdown . Event ( 'makehtml.ellipsis.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
////
// makehtml/emoji.js
// Copyright (c) 2018 ShowdownJS
//
// Turn emoji codes into emojis
// List of supported emojis: https://github.com/showdownjs/showdown/wiki/Emojis
//
// ***Author:***
// - Estêvão Soares dos Santos (Tivie) <https://github.com/tivie>
////
2022-03-26 08:31:41 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makehtml.emoji' , function ( text , options , globals ) {
'use strict' ;
if ( ! options . emoji ) {
return text ;
}
2022-04-28 04:42:24 +08:00
let startEvent = new showdown . Event ( 'makehtml.emoji.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
let pattern = /:(\S+?):/g ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
text = text . replace ( pattern , function ( wholeMatch , emojiCode ) {
if ( ! showdown . helper . emojis . hasOwnProperty ( emojiCode ) ) {
return wholeMatch ;
}
let otp = '' ;
let captureStartEvent = new showdown . Event ( 'makehtml.emoji.onCapture' , emojiCode ) ;
captureStartEvent
. setOutput ( null )
. _setGlobals ( globals )
. _setOptions ( options )
. setRegexp ( pattern )
. setMatches ( {
_wholeMatch : wholeMatch ,
emojiCode : emojiCode
} )
. setAttributes ( { } ) ;
captureStartEvent = globals . converter . dispatch ( captureStartEvent ) ;
// if something was passed as output, it takes precedence and will be used as output
if ( captureStartEvent . output && captureStartEvent . output !== '' ) {
otp = captureStartEvent . output ;
} else {
otp = showdown . helper . emojis [ emojiCode ] ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
let beforeHashEvent = new showdown . Event ( 'makehtml.emoji.onHash' , otp ) ;
beforeHashEvent
. setOutput ( otp )
. _setGlobals ( globals )
. _setOptions ( options ) ;
beforeHashEvent = globals . converter . dispatch ( beforeHashEvent ) ;
return beforeHashEvent . output ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
let afterEvent = new showdown . Event ( 'makehtml.emoji.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
} ) ;
////
// makehtml/emphasisAndStrong.js
// Copyright (c) 2022 ShowdownJS
//
// Transforms MD emphasis and strong into `<em>` and `<strong>` html entities
//
// Markdown treats asterisks (*) and underscores (_) as indicators of emphasis.
// Text wrapped with one * or _ will be wrapped with an HTML <em> tag;
// double *’ s or _’ s will be wrapped with an HTML <strong> tag
//
// ***Author:***
// - Estêvão Soares dos Santos (Tivie) <https://github.com/tivie>
////
showdown . subParser ( 'makehtml.emphasisAndStrong' , function ( text , options , globals ) {
'use strict' ;
let startEvent = new showdown . Event ( 'makehtml.emphasisAndStrong.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
/ * *
* @ param { string } txt
* @ param { string } tags
* @ param { string } wholeMatch
* @ param { RegExp } pattern
* @ returns { string }
* /
function parseInside ( txt , tags , wholeMatch , pattern ) {
let otp = 'ERROR' ,
attributes ,
subEventName ;
switch ( tags ) {
case '<em>' :
attributes = {
em : { }
} ;
subEventName = 'emphasis' ;
break ;
case '<strong>' :
attributes = {
strong : { }
} ;
subEventName = 'strong' ;
break ;
case '<strong><em>' :
attributes = {
em : { } ,
strong : { }
} ;
subEventName = 'emphasisAndStrong' ;
break ;
default :
attributes = { } ;
subEventName = 'emphasisAndStrong' ;
break ;
}
let captureStartEvent = new showdown . Event ( 'makehtml.emphasisAndStrong.' + subEventName + '.onCapture' , txt ) ;
captureStartEvent
. setOutput ( null )
. _setGlobals ( globals )
. _setOptions ( options )
. setRegexp ( pattern )
. setMatches ( {
_wholeMatch : wholeMatch ,
text : txt
} )
. setAttributes ( attributes ) ;
captureStartEvent = globals . converter . dispatch ( captureStartEvent ) ;
// if something was passed as output, it takes precedence
// and will be used as output
if ( captureStartEvent . output && captureStartEvent . output !== '' ) {
otp = captureStartEvent . output ;
} else {
attributes = captureStartEvent . attributes ;
if ( showdown . helper . isUndefined ( attributes . em ) ) {
attributes . em = { } ;
}
if ( showdown . helper . isUndefined ( attributes . strong ) ) {
attributes . strong = { } ;
}
switch ( tags ) {
case '<em>' :
otp = '<em' + showdown . helper . _populateAttributes ( attributes . em ) + '>' + txt + '</em>' ;
break ;
case '<strong>' :
otp = '<strong' + showdown . helper . _populateAttributes ( attributes . strong ) + '>' + txt + '</strong>' ;
break ;
case '<strong><em>' :
otp = '<strong' + showdown . helper . _populateAttributes ( attributes . strong ) + '>' +
'<em' + showdown . helper . _populateAttributes ( attributes . em ) + '>' +
txt +
'</em>' +
'</strong>' ;
break ;
}
}
let beforeHashEvent = new showdown . Event ( 'makehtml.emphasisAndStrong.' + subEventName + '.onHash' , otp ) ;
beforeHashEvent
. setOutput ( otp )
. _setGlobals ( globals )
. _setOptions ( options ) ;
beforeHashEvent = globals . converter . dispatch ( beforeHashEvent ) ;
otp = beforeHashEvent . output ;
return otp ;
}
// it's faster to have 3 separate regexes for each case than have just one
// because of backtracking, in some cases, it could lead to an exponential effect
// called "catastrophic backtrace". Ominous!
const lmwuStrongEmRegex = /\b___(\S[\s\S]*?)___\b/g ,
lmwuStrongRegex = /\b__(\S[\s\S]*?)__\b/g ,
lmwuEmRegex = /\b_(\S[\s\S]*?)_\b/g ,
underscoreStrongEmRegex = /___(\S[\s\S]*?)___/g ,
unserscoreStrongRegex = /__(\S[\s\S]*?)__/g ,
unserscoreEmRegex = /_([^\s_][\s\S]*?)_/g ,
asteriskStrongEm = /\*\*\*(\S[\s\S]*?)\*\*\*/g ,
asteriskStrong = /\*\*(\S[\s\S]*?)\*\*/g ,
asteriskEm = /\*([^\s*][\s\S]*?)\*/g ;
// Parse underscores
if ( options . literalMidWordUnderscores ) {
text = text . replace ( lmwuStrongEmRegex , function ( wm , txt ) {
return parseInside ( txt , '<strong><em>' , wm , lmwuStrongEmRegex ) ;
} ) ;
text = text . replace ( lmwuStrongRegex , function ( wm , txt ) {
return parseInside ( txt , '<strong>' , wm , lmwuStrongRegex ) ;
} ) ;
text = text . replace ( lmwuEmRegex , function ( wm , txt ) {
return parseInside ( txt , '<em>' , wm , lmwuEmRegex ) ;
} ) ;
} else {
text = text . replace ( underscoreStrongEmRegex , function ( wm , m ) {
return ( /\S$/ . test ( m ) ) ? parseInside ( m , '<strong><em>' , wm , underscoreStrongEmRegex ) : wm ;
} ) ;
text = text . replace ( unserscoreStrongRegex , function ( wm , m ) {
return ( /\S$/ . test ( m ) ) ? parseInside ( m , '<strong>' , wm , unserscoreStrongRegex ) : wm ;
} ) ;
text = text . replace ( unserscoreEmRegex , function ( wm , m ) {
// !/^_[^_]/.test(m) - test if it doesn't start with __ (since it seems redundant, we removed it)
return ( /\S$/ . test ( m ) ) ? parseInside ( m , '<em>' , wm , unserscoreEmRegex ) : wm ;
} ) ;
}
// Now parse asterisks
text = text . replace ( asteriskStrongEm , function ( wm , m ) {
return ( /\S$/ . test ( m ) ) ? parseInside ( m , '<strong><em>' , wm , asteriskStrongEm ) : wm ;
} ) ;
text = text . replace ( asteriskStrong , function ( wm , m ) {
return ( /\S$/ . test ( m ) ) ? parseInside ( m , '<strong>' , wm , asteriskStrong ) : wm ;
} ) ;
text = text . replace ( asteriskEm , function ( wm , m ) {
// !/^\*[^*]/.test(m) - test if it doesn't start with ** (since it seems redundant, we removed it)
return ( /\S$/ . test ( m ) ) ? parseInside ( m , '<em>' , wm , asteriskEm ) : wm ;
} ) ;
//}
let afterEvent = new showdown . Event ( 'makehtml.emphasisAndStrong.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
////
// makehtml/encodeAmpsAndAngles.js
// Copyright (c) 2018 ShowdownJS
//
// Smart processing for ampersands and angle brackets that need to be encoded.
//
// ***Author:***
// - Estêvão Soares dos Santos (Tivie) <https://github.com/tivie>
////
2022-03-26 08:31:41 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makehtml.encodeAmpsAndAngles' , function ( text , options , globals ) {
'use strict' ;
2022-04-28 04:42:24 +08:00
let startEvent = new showdown . Event ( 'makehtml.encodeAmpsAndAngles.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
2022-02-24 08:23:15 +08:00
// Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:
// http://bumppo.net/projects/amputator/
2022-04-28 04:42:24 +08:00
text = text . replace ( /&(?!#?[xX]?(?:[\da-fA-F]+|\w+);)/g , '&' ) ;
2022-02-24 08:23:15 +08:00
// Encode naked <'s
text = text . replace ( /<(?![a-z\/?$!])/gi , '<' ) ;
// Encode <
text = text . replace ( /</g , '<' ) ;
// Encode >
text = text . replace ( />/g , '>' ) ;
2022-04-28 04:42:24 +08:00
let afterEvent = new showdown . Event ( 'makehtml.encodeAmpsAndAngles.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
////
// makehtml/encodeBackslashEscapes.js
// Copyright (c) 2018 ShowdownJS
//
// Returns the string, with after processing the following backslash escape sequences.
//
// The polite way to do this is with the new escapeCharacters() function:
//
// text = escapeCharacters(text,"\\",true);
// text = escapeCharacters(text,"`*_{}[]()>#+-.!",true);
//
// ...but we're sidestepping its use of the (slow) RegExp constructor
// as an optimization for Firefox. This function gets called a LOT.
//
// ***Author:***
// - attacklab
// - Estêvão Soares dos Santos (Tivie) <https://github.com/tivie>
////
2022-03-26 08:31:41 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makehtml.encodeBackslashEscapes' , function ( text , options , globals ) {
'use strict' ;
2022-04-28 04:42:24 +08:00
let startEvent = new showdown . Event ( 'makehtml.encodeBackslashEscapes.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
2022-02-24 08:23:15 +08:00
text = text . replace ( /\\(\\)/g , showdown . helper . escapeCharactersCallback ) ;
text = text . replace ( /\\([`*_{}\[\]()>#+.!~=|:-])/g , showdown . helper . escapeCharactersCallback ) ;
2022-04-28 04:42:24 +08:00
let afterEvent = new showdown . Event ( 'makehtml.encodeBackslashEscapes.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
////
// makehtml/emoji.js
// Copyright (c) 2018 ShowdownJS
//
// Encode/escape certain characters inside Markdown code runs.
// The point is that in code, these characters are literals,
// and lose their special Markdown meanings.
//
// ***Author:***
// - Estêvão Soares dos Santos (Tivie) <https://github.com/tivie>
////
2022-03-26 08:31:41 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makehtml.encodeCode' , function ( text , options , globals ) {
'use strict' ;
2022-04-28 04:42:24 +08:00
let startEvent = new showdown . Event ( 'makehtml.encodeCode.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
2022-02-24 08:23:15 +08:00
// Encode all ampersands; HTML entities are not
// entities within a Markdown code span.
text = text
. replace ( /&/g , '&' )
// Do the angle bracket song and dance:
. replace ( /</g , '<' )
. replace ( />/g , '>' )
// Now, escape characters that are magic in Markdown:
. replace ( /([*_{}\[\]\\=~-])/g , showdown . helper . escapeCharactersCallback ) ;
2022-04-28 04:42:24 +08:00
let afterEvent = new showdown . Event ( 'makehtml.encodeCode.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
////
// makehtml/escapeSpecialCharsWithinTagAttributes.js
// Copyright (c) 2018 ShowdownJS
//
// Within tags -- meaning between < and > -- encode [\ ` * _ ~ =] so they
// don't conflict with their use in Markdown for code, italics and strong.
//
// ***Author:***
// - Estêvão Soares dos Santos (Tivie) <https://github.com/tivie>
////
2022-03-26 08:31:41 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makehtml.escapeSpecialCharsWithinTagAttributes' , function ( text , options , globals ) {
'use strict' ;
2022-04-28 04:42:24 +08:00
let startEvent = new showdown . Event ( 'makehtml.escapeSpecialCharsWithinTagAttributes.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
2022-02-24 08:23:15 +08:00
// Build a regex to find HTML tags.
2022-04-28 04:42:24 +08:00
let tags = /<\/?[a-z\d_:-]+(?:[\s]+[\s\S]+?)?>/gi ,
comments = /<!(--(([^>-]|-[^>])([^-]|-[^-])*)--)>/gi ;
2022-02-24 08:23:15 +08:00
text = text . replace ( tags , function ( wholeMatch ) {
return wholeMatch
. replace ( /(.)<\/?code>(?=.)/g , '$1`' )
. replace ( /([\\`*_~=|])/g , showdown . helper . escapeCharactersCallback ) ;
} ) ;
text = text . replace ( comments , function ( wholeMatch ) {
return wholeMatch
. replace ( /([\\`*_~=|])/g , showdown . helper . escapeCharactersCallback ) ;
} ) ;
2022-04-28 04:42:24 +08:00
let afterEvent = new showdown . Event ( 'makehtml.escapeSpecialCharsWithinTagAttributes.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
////
// makehtml/githubCodeBlock.js
// Copyright (c) 2018 ShowdownJS
//
// Handle github codeblocks prior to running HashHTML so that
// HTML contained within the codeblock gets escaped properly
// Example:
// ```ruby
// def hello_world(x)
// puts "Hello, #{x}"
// end
// ```
//
// ***Author:***
// - Estêvão Soares dos Santos (Tivie) <https://github.com/tivie>
////
2022-03-26 08:31:41 +08:00
2022-04-28 04:42:24 +08:00
showdown . subParser ( 'makehtml.githubCodeBlock' , function ( text , options , globals ) {
2022-02-24 08:23:15 +08:00
'use strict' ;
// early exit if option is not enabled
if ( ! options . ghCodeBlocks ) {
return text ;
}
2022-04-28 04:42:24 +08:00
let startEvent = new showdown . Event ( 'makehtml.githubCodeBlock.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output + '¨0' ;
let pattern = /(?:^|\n) {0,3}(```+|~~~+) *([^\n\t`~]*)\n([\s\S]*?)\n {0,3}\1/g ;
text = text . replace ( pattern , function ( wholeMatch , delim , language , codeblock ) {
let end = ( options . omitExtraWLInCodeBlocks ) ? '' : '\n' ,
otp ,
attributes = {
pre : { } ,
code : { } ,
} ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
let captureStartEvent = new showdown . Event ( 'makehtml.githubCodeBlock.onCapture' , codeblock ) ;
captureStartEvent
. setOutput ( null )
. _setGlobals ( globals )
. _setOptions ( options )
. setRegexp ( pattern )
. setMatches ( {
_whoteMatch : wholeMatch ,
codeblock : codeblock ,
infostring : language
} )
. setAttributes ( attributes ) ;
captureStartEvent = globals . converter . dispatch ( captureStartEvent ) ;
// if something was passed as output, it takes precedence
// and will be used as output
if ( captureStartEvent . output && captureStartEvent . output !== '' ) {
otp = captureStartEvent . output ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
} else {
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
// First parse the github code block
let infostring = captureStartEvent . matches . infostring ;
let lang = infostring . trim ( ) . split ( ' ' ) [ 0 ] ;
codeblock = captureStartEvent . matches . codeblock ;
codeblock = showdown . subParser ( 'makehtml.encodeCode' ) ( codeblock , options , globals ) ;
codeblock = showdown . subParser ( 'makehtml.detab' ) ( codeblock , options , globals ) ;
codeblock = codeblock
. replace ( /^\n+/g , '' ) // trim leading newlines
. replace ( /\n+$/g , '' ) ; // trim trailing whitespace
attributes = captureStartEvent . attributes ;
otp = '<pre><code>' ;
if ( ! showdown . helper . isUndefined ( attributes ) ) {
otp = '<pre' + showdown . helper . _populateAttributes ( attributes . pre ) + '>' ;
// if the language has spaces followed by some other chars, according to the spec we should just ignore everything
// after the first space
if ( infostring ) {
if ( ! attributes . code ) {
attributes . code = { } ;
}
if ( ! attributes . code . classes ) {
attributes . code . classes = [ ] ;
}
2022-02-24 09:22:11 +08:00
2022-04-28 04:42:24 +08:00
if ( attributes . code . classes ) {
if ( showdown . helper . isString ( attributes . code . classes ) ) {
attributes . code . classes += ' ' + lang + ' language-' + lang ;
} else if ( showdown . helper . isArray ( attributes . code . classes ) ) {
attributes . code . classes . push ( lang ) ;
attributes . code . classes . push ( 'language-' + lang ) ;
}
}
}
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
otp += '<code' + showdown . helper . _populateAttributes ( attributes . code ) + '>' ;
}
if ( options . omitExtraWLInCodeBlocks ) {
end = '' ;
}
otp += codeblock + end + '</code></pre>' ;
}
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
let beforeHashEvent = new showdown . Event ( 'makehtml.githubCodeBlock.onHash' , otp ) ;
beforeHashEvent
. setOutput ( otp )
. _setGlobals ( globals )
. _setOptions ( options ) ;
beforeHashEvent = globals . converter . dispatch ( beforeHashEvent ) ;
otp = beforeHashEvent . output ;
otp = showdown . subParser ( 'makehtml.hashBlock' ) ( otp , options , globals ) ;
2022-02-24 08:23:15 +08:00
// Since GHCodeblocks can be false positives, we need to
// store the primitive text and the parsed text in a global var,
// and then return a token
2022-04-28 04:42:24 +08:00
return '\n\n¨G' + ( globals . ghCodeBlocks . push ( { text : wholeMatch , codeblock : otp } ) - 1 ) + 'G\n\n' ;
2022-02-24 08:23:15 +08:00
} ) ;
// attacklab: strip sentinel
text = text . replace ( /¨0/ , '' ) ;
2022-04-28 04:42:24 +08:00
let afterEvent = new showdown . Event ( 'makehtml.githubCodeBlock.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
////
// makehtml/hashBlock.js
// Copyright (c) 2018 ShowdownJS
//
//
// ***Author:***
// - Estêvão Soares dos Santos (Tivie) <https://github.com/tivie>
////
2022-03-26 08:31:41 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makehtml.hashBlock' , function ( text , options , globals ) {
'use strict' ;
2022-04-28 04:42:24 +08:00
let startEvent = new showdown . Event ( 'makehtml.hashBlock.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
2022-02-24 08:23:15 +08:00
text = text . replace ( /(^\n+|\n+$)/g , '' ) ;
text = '\n\n¨K' + ( globals . gHtmlBlocks . push ( text ) - 1 ) + 'K\n\n' ;
2022-04-28 04:42:24 +08:00
let afterEvent = new showdown . Event ( 'makehtml.hashBlock.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
////
// makehtml/hashCodeTags.js
// Copyright (c) 2018 ShowdownJS
//
// Hash and escape <code> elements that should not be parsed as markdown
//
// ***Author:***
// - Estêvão Soares dos Santos (Tivie) <https://github.com/tivie>
////
2022-03-26 08:31:41 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makehtml.hashCodeTags' , function ( text , options , globals ) {
'use strict' ;
2022-04-28 04:42:24 +08:00
let startEvent = new showdown . Event ( 'makehtml.hashCodeTags.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
let repFunc = function ( wholeMatch , match , left , right ) {
let codeblock = left + showdown . subParser ( 'makehtml.encodeCode' ) ( match , options , globals ) + right ;
2022-02-24 08:23:15 +08:00
return '¨C' + ( globals . gHtmlSpans . push ( codeblock ) - 1 ) + 'C' ;
} ;
// Hash naked <code>
text = showdown . helper . replaceRecursiveRegExp ( text , repFunc , '<code\\b[^>]*>' , '</code>' , 'gim' ) ;
2022-04-28 04:42:24 +08:00
let afterEvent = new showdown . Event ( 'makehtml.hashCodeTags.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makehtml.hashElement' , function ( text , options , globals ) {
'use strict' ;
return function ( wholeMatch , m1 ) {
2022-04-28 04:42:24 +08:00
let blockText = m1 ;
2022-02-24 08:23:15 +08:00
// Undo double lines
blockText = blockText . replace ( /\n\n/g , '\n' ) ;
blockText = blockText . replace ( /^\n/ , '' ) ;
// strip trailing blank lines
blockText = blockText . replace ( /\n+$/g , '' ) ;
// Replace the element text with a marker ("¨KxK" where x is its key)
blockText = '\n\n¨K' + ( globals . gHtmlBlocks . push ( blockText ) - 1 ) + 'K\n\n' ;
return blockText ;
} ;
} ) ;
2022-04-28 04:42:24 +08:00
////
// makehtml/hashHTMLBlocks.js
// Copyright (c) 2018 ShowdownJS
//
// Hash HTML blocks
//
// ***Author:***
// - Estêvão Soares dos Santos (Tivie) <https://github.com/tivie>
////
2022-03-26 08:31:41 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makehtml.hashHTMLBlocks' , function ( text , options , globals ) {
'use strict' ;
2022-04-28 04:42:24 +08:00
let startEvent = new showdown . Event ( 'makehtml.hashHTMLBlocks.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
let blockTags = [
2022-02-24 08:23:15 +08:00
'pre' ,
'div' ,
'h1' ,
'h2' ,
'h3' ,
'h4' ,
'h5' ,
'h6' ,
'blockquote' ,
'table' ,
'dl' ,
'ol' ,
'ul' ,
'script' ,
'noscript' ,
'form' ,
'fieldset' ,
'iframe' ,
'math' ,
'style' ,
'section' ,
'header' ,
'footer' ,
'nav' ,
'article' ,
'aside' ,
'address' ,
'audio' ,
'canvas' ,
'figure' ,
'hgroup' ,
'output' ,
'video' ,
'details' ,
'p'
] ,
repFunc = function ( wholeMatch , match , left , right ) {
2022-04-28 04:42:24 +08:00
let txt = wholeMatch ;
2022-02-24 08:23:15 +08:00
// check if this html element is marked as markdown
// if so, it's contents should be parsed as markdown
if ( left . search ( /\bmarkdown\b/ ) !== - 1 ) {
txt = left + globals . converter . makeHtml ( match ) + right ;
}
return '\n\n¨K' + ( globals . gHtmlBlocks . push ( txt ) - 1 ) + 'K\n\n' ;
} ;
if ( options . backslashEscapesHTMLTags ) {
// encode backslash escaped HTML tags
text = text . replace ( /\\<(\/?[^>]+?)>/g , function ( wm , inside ) {
return '<' + inside + '>' ;
} ) ;
}
// hash HTML Blocks
2022-04-28 04:42:24 +08:00
for ( let i = 0 ; i < blockTags . length ; ++ i ) {
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
let opTagPos ,
2022-02-24 08:23:15 +08:00
rgx1 = new RegExp ( '^ {0,3}(<' + blockTags [ i ] + '\\b[^>]*>)' , 'im' ) ,
patLeft = '<' + blockTags [ i ] + '\\b[^>]*>' ,
patRight = '</' + blockTags [ i ] + '>' ;
// 1. Look for the first position of the first opening HTML tag in the text
while ( ( opTagPos = showdown . helper . regexIndexOf ( text , rgx1 ) ) !== - 1 ) {
// if the HTML tag is \ escaped, we need to escape it and break
//2. Split the text in that position
2022-04-28 04:42:24 +08:00
let subTexts = showdown . helper . splitAtIndex ( text , opTagPos ) ,
2022-02-24 08:23:15 +08:00
//3. Match recursively
newSubText1 = showdown . helper . replaceRecursiveRegExp ( subTexts [ 1 ] , repFunc , patLeft , patRight , 'im' ) ;
// prevent an infinite loop
if ( newSubText1 === subTexts [ 1 ] ) {
break ;
}
text = subTexts [ 0 ] . concat ( newSubText1 ) ;
}
}
// HR SPECIAL CASE
text = text . replace ( /(\n {0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g ,
showdown . subParser ( 'makehtml.hashElement' ) ( text , options , globals ) ) ;
// Special case for standalone HTML comments
text = showdown . helper . replaceRecursiveRegExp ( text , function ( txt ) {
return '\n\n¨K' + ( globals . gHtmlBlocks . push ( txt ) - 1 ) + 'K\n\n' ;
} , '^ {0,3}<!--' , '-->' , 'gm' ) ;
// PHP and ASP-style processor instructions (<?...?> and <%...%>)
text = text . replace ( /\n\n( {0,3}<([?%])[^\r]*?\2>[ \t]*(?=\n{2,}))/g ,
showdown . subParser ( 'makehtml.hashElement' ) ( text , options , globals ) ) ;
2022-04-28 04:42:24 +08:00
let afterEvent = new showdown . Event ( 'makehtml.hashHTMLBlocks.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
////
// makehtml/hashHTMLSpans.js
// Copyright (c) 2018 ShowdownJS
//
// Hash span elements that should not be parsed as markdown
//
// ***Author:***
// - Estêvão Soares dos Santos (Tivie) <https://github.com/tivie>
////
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makehtml.hashHTMLSpans' , function ( text , options , globals ) {
'use strict' ;
2022-04-28 04:42:24 +08:00
let startEvent = new showdown . Event ( 'makehtml.hashHTMLSpans.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
2022-02-24 08:23:15 +08:00
// Hash Self Closing tags
text = text . replace ( /<[^>]+?\/>/gi , function ( wm ) {
return showdown . helper . _hashHTMLSpan ( wm , globals ) ;
} ) ;
// Hash tags without properties
text = text . replace ( /<([^>]+?)>[\s\S]*?<\/\1>/g , function ( wm ) {
return showdown . helper . _hashHTMLSpan ( wm , globals ) ;
} ) ;
// Hash tags with properties
text = text . replace ( /<([^>]+?)\s[^>]+?>[\s\S]*?<\/\1>/g , function ( wm ) {
return showdown . helper . _hashHTMLSpan ( wm , globals ) ;
} ) ;
// Hash self closing tags without />
text = text . replace ( /<[^>]+?>/gi , function ( wm ) {
return showdown . helper . _hashHTMLSpan ( wm , globals ) ;
} ) ;
2022-04-28 04:42:24 +08:00
let afterEvent = new showdown . Event ( 'makehtml.hashHTMLSpans.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
////
// makehtml/githubCodeBlock.js
// Copyright (c) 2018 ShowdownJS
//
// Hash and escape <pre><code> elements that should not be parsed as markdown
//
// ***Author:***
// - Estêvão Soares dos Santos (Tivie) <https://github.com/tivie>
////
2022-02-24 08:23:15 +08:00
2022-03-26 08:31:41 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makehtml.hashPreCodeTags' , function ( text , options , globals ) {
'use strict' ;
2022-04-28 04:42:24 +08:00
let startEvent = new showdown . Event ( 'makehtml.hashPreCodeTags.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
let repFunc = function ( wholeMatch , match , left , right ) {
2022-02-24 08:23:15 +08:00
// encode html entities
2022-04-28 04:42:24 +08:00
let codeblock = left + showdown . subParser ( 'makehtml.encodeCode' ) ( match , options , globals ) + right ;
2022-02-24 08:23:15 +08:00
return '\n\n¨G' + ( globals . ghCodeBlocks . push ( { text : wholeMatch , codeblock : codeblock } ) - 1 ) + 'G\n\n' ;
} ;
// Hash <pre><code>
text = showdown . helper . replaceRecursiveRegExp ( text , repFunc , '^ {0,3}<pre\\b[^>]*>\\s*<code\\b[^>]*>' , '^ {0,3}</code>\\s*</pre>' , 'gim' ) ;
2022-04-28 04:42:24 +08:00
let afterEvent = new showdown . Event ( 'makehtml.hashPreCodeTags.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
////
// makehtml/blockquote.js
// Copyright (c) 2018 ShowdownJS
//
// Transforms MD headings into `<h#>` html entities
//
// Setext-style headers:
// Header 1
// ========
//
// Header 2
// --------
//
// atx-style headers:
// # Header 1
// ## Header 2
// ## Header 2 with closing hashes ##
// ...
// ###### Header 6
//
// ***Author:***
// - Estêvão Soares dos Santos (Tivie) <https://github.com/tivie>
////
2022-03-26 08:31:41 +08:00
2022-04-28 04:42:24 +08:00
showdown . subParser ( 'makehtml.heading' , function ( text , options , globals ) {
2022-02-24 08:23:15 +08:00
'use strict' ;
2022-04-28 04:42:24 +08:00
function parseHeader ( pattern , wholeMatch , headingText , headingLevel , headingId ) {
let captureStartEvent = new showdown . Event ( 'makehtml.heading.onCapture' , headingText ) ,
otp ;
captureStartEvent
. setOutput ( null )
. _setGlobals ( globals )
. _setOptions ( options )
. setRegexp ( pattern )
. setMatches ( {
_wholeMatch : wholeMatch ,
heading : headingText
} )
. setAttributes ( {
id : headingId
} ) ;
captureStartEvent = globals . converter . dispatch ( captureStartEvent ) ;
// if something was passed as output, it takes precedence
// and will be used as output
if ( captureStartEvent . output && captureStartEvent . output !== '' ) {
otp = captureStartEvent . output ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
} else {
headingText = captureStartEvent . matches . heading ;
let spanGamut = showdown . subParser ( 'makehtml.spanGamut' ) ( headingText , options , globals ) ,
attributes = captureStartEvent . attributes ;
otp = '<h' + headingLevel + showdown . helper . _populateAttributes ( attributes ) + '>' + spanGamut + '</h' + headingLevel + '>' ;
}
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
let beforeHashEvent = new showdown . Event ( 'makehtml.heading.onHash' , otp ) ;
beforeHashEvent
. setOutput ( otp )
. _setGlobals ( globals )
. _setOptions ( options ) ;
beforeHashEvent = globals . converter . dispatch ( beforeHashEvent ) ;
otp = beforeHashEvent . output ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
return showdown . subParser ( 'makehtml.hashBlock' ) ( otp , options , globals ) ;
}
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
let startEvent = new showdown . Event ( 'makehtml.heading.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
let setextRegexH1 = ( options . smoothLivePreview ) ? /^(.+)[ \t]*\n={2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n=+[ \t]*\n+/gm ,
setextRegexH2 = ( options . smoothLivePreview ) ? /^(.+)[ \t]*\n-{2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n-+[ \t]*\n+/gm ,
atxRegex = ( options . requireSpaceBeforeHeadingText ) ? /^(#{1,6})[ \t]+(.+?)[ \t]*#*\n+/gm : /^(#{1,6})[ \t]*(.+?)[ \t]*#*\n+/gm ;
text = text . replace ( setextRegexH1 , function ( wholeMatch , headingText ) {
let id = ( options . noHeaderId ) ? null : showdown . subParser ( 'makehtml.heading.id' ) ( headingText , options , globals ) ;
return parseHeader ( setextRegexH1 , wholeMatch , headingText , options . headerLevelStart , id ) ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
text = text . replace ( setextRegexH2 , function ( wholeMatch , headingText ) {
let id = ( options . noHeaderId ) ? null : showdown . subParser ( 'makehtml.heading.id' ) ( headingText , options , globals ) ;
return parseHeader ( setextRegexH2 , wholeMatch , headingText , options . headerLevelStart + 1 , id ) ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
text = text . replace ( atxRegex , function ( wholeMatch , m1 , m2 ) {
let headingLevel = options . headerLevelStart - 1 + m1 . length ,
headingText = ( options . customizedHeaderId ) ? m2 . replace ( /\s?{([^{]+?)}\s*$/ , '' ) : m2 ,
id = ( options . noHeaderId ) ? null : showdown . subParser ( 'makehtml.heading.id' ) ( m2 , options , globals ) ;
return parseHeader ( setextRegexH2 , wholeMatch , headingText , headingLevel , id ) ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
let afterEvent = new showdown . Event ( 'makehtml.heading.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
} ) ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
showdown . subParser ( 'makehtml.heading.id' , function ( m , options , globals ) {
let title ,
prefix ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
// It is separate from other options to allow combining prefix and customized
if ( options . customizedHeaderId ) {
let match = m . match ( /{([^{]+?)}\s*$/ ) ;
if ( match && match [ 1 ] ) {
m = match [ 1 ] ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
}
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
title = m ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
// Prefix id to prevent causing inadvertent pre-existing style matches.
if ( showdown . helper . isString ( options . prefixHeaderId ) ) {
prefix = options . prefixHeaderId ;
} else if ( options . prefixHeaderId === true ) {
prefix = 'section-' ;
} else {
prefix = '' ;
}
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
if ( ! options . rawPrefixHeaderId ) {
title = prefix + title ;
}
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
if ( options . ghCompatibleHeaderId ) {
title = title
. replace ( / /g , '-' )
// replace previously escaped chars (&, ¨ and $)
. replace ( /&/g , '' )
. replace ( /¨T/g , '' )
. replace ( /¨D/g , '' )
// replace rest of the chars (&~$ are repeated as they might have been escaped)
// borrowed from github's redcarpet (so they should produce similar results)
. replace ( /[&+$,\/:;=?@"#{}|^¨~\[\]`\\*)(%.!'<>]/g , '' )
. toLowerCase ( ) ;
} else if ( options . rawHeaderId ) {
title = title
. replace ( / /g , '-' )
// replace previously escaped chars (&, ¨ and $)
. replace ( /&/g , '&' )
. replace ( /¨T/g , '¨' )
. replace ( /¨D/g , '$' )
// replace " and '
. replace ( /["']/g , '-' )
. toLowerCase ( ) ;
} else {
title = title
. replace ( /[^\w]/g , '' )
. toLowerCase ( ) ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
if ( options . rawPrefixHeaderId ) {
title = prefix + title ;
}
2022-03-26 08:31:41 +08:00
2022-04-28 04:42:24 +08:00
if ( globals . hashLinkCounts [ title ] ) {
title = title + '-' + ( globals . hashLinkCounts [ title ] ++ ) ;
} else {
globals . hashLinkCounts [ title ] = 1 ;
}
return title ;
} ) ;
////
// makehtml/blockquote.js
// Copyright (c) 2018 ShowdownJS
//
// Turn Markdown horizontal rule shortcuts into <hr /> tags.
//
// Any 3 or more unindented consecutive hyphens, asterisks or underscores with or without a space beetween them
// in a single line is considered a horizontal rule
//
// ***Author:***
// - Estêvão Soares dos Santos (Tivie) <https://github.com/tivie>
////
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makehtml.horizontalRule' , function ( text , options , globals ) {
'use strict' ;
2022-04-28 04:42:24 +08:00
let startEvent = new showdown . Event ( 'makehtml.horizontalRule.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
const rgx1 = /^ {0,2}( ?-){3,}[ \t]*$/gm ;
text = text . replace ( /^ {0,2}( ?-){3,}[ \t]*$/gm , function ( wholeMatch ) {
return parse ( rgx1 , wholeMatch ) ;
} ) ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
const rgx2 = /^ {0,2}( ?\*){3,}[ \t]*$/gm ;
text = text . replace ( /^ {0,2}( ?\*){3,}[ \t]*$/gm , function ( wholeMatch ) {
return parse ( rgx2 , wholeMatch ) ;
} ) ;
const rgx3 = /^ {0,2}( ?\*){3,}[ \t]*$/gm ;
text = text . replace ( /^ {0,2}( ?_){3,}[ \t]*$/gm , function ( wholeMatch ) {
return parse ( rgx3 , wholeMatch ) ;
} ) ;
let afterEvent = new showdown . Event ( 'makehtml.horizontalRule.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
/ * *
*
* @ param { RegExp } pattern
* @ param { string } wholeMatch
* @ returns { string }
* /
function parse ( pattern , wholeMatch ) {
let otp ;
let captureStartEvent = new showdown . Event ( 'makehtml.horizontalRule.onCapture' , wholeMatch ) ;
captureStartEvent
. setOutput ( null )
. _setGlobals ( globals )
. _setOptions ( options )
. setRegexp ( pattern )
. setMatches ( {
_whoteMatch : wholeMatch
} )
. setAttributes ( { } ) ;
captureStartEvent = globals . converter . dispatch ( captureStartEvent ) ;
// if something was passed as output, it takes precedence
// and will be used as output
if ( captureStartEvent . output && captureStartEvent . output !== '' ) {
otp = captureStartEvent . output ;
} else {
otp = '<hr' + showdown . helper . _populateAttributes ( captureStartEvent . attributes ) + ' />' ;
}
let beforeHashEvent = new showdown . Event ( 'makehtml.horizontalRule.onHash' , otp ) ;
beforeHashEvent
. setOutput ( otp )
. _setGlobals ( globals )
. _setOptions ( options ) ;
beforeHashEvent = globals . converter . dispatch ( beforeHashEvent ) ;
otp = beforeHashEvent . output ;
otp = showdown . subParser ( 'makehtml.hashBlock' ) ( otp , options , globals ) ;
return otp ;
}
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
////
// makehtml/blockquote.js
// Copyright (c) 2018 ShowdownJS
//
// Turn Markdown image into <img> tags.
//
// ***Author:***
// - Estêvão Soares dos Santos (Tivie) <https://github.com/tivie>
////
2022-03-26 08:31:41 +08:00
2022-04-28 04:42:24 +08:00
showdown . subParser ( 'makehtml.image' , function ( text , options , globals ) {
2022-02-24 08:23:15 +08:00
'use strict' ;
2022-04-28 04:42:24 +08:00
let startEvent = new showdown . Event ( 'makehtml.image.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
let inlineRegExp = /!\[([^\]]*?)][ \t]*\([ \t]?<?(\S+?(?:\(\S*?\)\S*?)?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\5)?[ \t]?\)/g ,
crazyRegExp = /!\[([^\]]*?)][ \t]*\([ \t]?<([^>]*)>(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\5)?[ \t]?\)/g ,
base64RegExp = /!\[([^\]]*?)][ \t]*\([ \t]?<?(data:.+?\/.+?;base64,[A-Za-z\d+/=\n]+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\6)?[ \t]?\)/g ,
referenceRegExp = /!\[([^\]]*?)] ?(?:\n *)?\[([\s\S]*?)]/g ,
refShortcutRegExp = /!\[([^\[\]]+)]/g ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
// First, handle reference-style labeled images: ![alt text][id]
text = text . replace ( referenceRegExp , function ( wholeMatch , altText , linkId ) {
return writeImageTag ( 'reference' , referenceRegExp , wholeMatch , altText , null , linkId ) ;
} ) ;
// Next, handle inline images: ![alt text](url =<width>x<height> "optional title")
// base64 encoded images
text = text . replace ( base64RegExp , function ( wholeMatch , altText , url , width , height , m5 , title ) {
2022-02-24 08:23:15 +08:00
url = url . replace ( /\s/g , '' ) ;
2022-04-28 04:42:24 +08:00
return writeImageTag ( 'inline' , base64RegExp , wholeMatch , altText , url , null , width , height , title ) ;
} ) ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
// cases with crazy urls like ./image/cat1).png
text = text . replace ( crazyRegExp , function ( wholeMatch , altText , url , width , height , m5 , title ) {
2022-02-24 08:23:15 +08:00
url = showdown . helper . applyBaseUrl ( options . relativePathBaseUrl , url ) ;
2022-04-28 04:42:24 +08:00
return writeImageTag ( 'inline' , crazyRegExp , wholeMatch , altText , url , null , width , height , title ) ;
} ) ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
// normal cases
text = text . replace ( inlineRegExp , function ( wholeMatch , altText , url , width , height , m5 , title ) {
url = showdown . helper . applyBaseUrl ( options . relativePathBaseUrl , url ) ;
return writeImageTag ( 'inline' , inlineRegExp , wholeMatch , altText , url , null , width , height , title ) ;
} ) ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
// handle reference-style shortcuts: ![img text]
text = text . replace ( refShortcutRegExp , function ( wholeMatch , altText ) {
return writeImageTag ( 'reference' , refShortcutRegExp , wholeMatch , altText ) ;
} ) ;
let afterEvent = new showdown . Event ( 'makehtml.image.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
/ * *
* @ param { string } subEvtName
* @ param { RegExp } pattern
* @ param { string } wholeMatch
* @ param { string } altText
* @ param { string | null } [ url ]
* @ param { string | null } [ linkId ]
* @ param { string | null } [ width ]
* @ param { string | null } [ height ]
* @ param { string | null } [ title ]
* @ returns { string }
* /
function writeImageTag ( subEvtName , pattern , wholeMatch , altText , url , linkId , width , height , title ) {
let gUrls = globals . gUrls ,
gTitles = globals . gTitles ,
gDims = globals . gDimensions ,
matches = {
_wholeMatch : wholeMatch ,
_altText : altText ,
_linkId : linkId ,
_url : url ,
_width : width ,
_height : height ,
_title : title
} ,
otp ,
attributes = { } ;
linkId = ( linkId ) ? linkId . toLowerCase ( ) : null ;
2022-02-24 08:23:15 +08:00
if ( ! title ) {
2022-04-28 04:42:24 +08:00
title = null ;
2022-02-24 08:23:15 +08:00
}
// Special case for explicit empty url
if ( wholeMatch . search ( /\(<?\s*>? ?(['"].*['"])?\)$/m ) > - 1 ) {
url = '' ;
2022-04-28 04:42:24 +08:00
} else if ( showdown . helper . isUndefined ( url ) || url === '' || url === null ) {
2022-02-24 08:23:15 +08:00
if ( linkId === '' || linkId === null ) {
// lower-case and turn embedded newlines into spaces
linkId = altText . toLowerCase ( ) . replace ( / ?\n/g , ' ' ) ;
}
url = '#' + linkId ;
if ( ! showdown . helper . isUndefined ( gUrls [ linkId ] ) ) {
url = gUrls [ linkId ] ;
if ( ! showdown . helper . isUndefined ( gTitles [ linkId ] ) ) {
title = gTitles [ linkId ] ;
}
if ( ! showdown . helper . isUndefined ( gDims [ linkId ] ) ) {
width = gDims [ linkId ] . width ;
height = gDims [ linkId ] . height ;
}
} else {
return wholeMatch ;
}
}
altText = altText
. replace ( /"/g , '"' )
2022-04-28 04:42:24 +08:00
//altText = showdown.helper.escapeCharacters(altText, '*_', false);
2022-02-24 08:23:15 +08:00
. replace ( showdown . helper . regexes . asteriskDashTildeAndColon , showdown . helper . escapeCharactersCallback ) ;
//url = showdown.helper.escapeCharacters(url, '*_', false);
url = url . replace ( showdown . helper . regexes . asteriskDashTildeAndColon , showdown . helper . escapeCharactersCallback ) ;
if ( title && showdown . helper . isString ( title ) ) {
title = title
. replace ( /"/g , '"' )
. replace ( showdown . helper . regexes . asteriskDashTildeAndColon , showdown . helper . escapeCharactersCallback ) ;
}
2022-04-28 04:42:24 +08:00
if ( width ) {
2022-02-24 08:23:15 +08:00
width = ( width === '*' ) ? 'auto' : width ;
2022-04-28 04:42:24 +08:00
} else {
width = null ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
if ( height ) {
height = ( height === '*' ) ? 'auto' : height ;
} else {
height = null ;
}
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
let captureStartEvent = new showdown . Event ( 'makehtml.image.' + subEvtName + '.onCapture' , wholeMatch ) ;
captureStartEvent
. setOutput ( null )
. _setGlobals ( globals )
. _setOptions ( options )
. setRegexp ( pattern )
. setMatches ( matches )
. setAttributes ( {
src : url ,
alt : altText ,
title : title ,
width : width ,
height : height
} ) ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
captureStartEvent = globals . converter . dispatch ( captureStartEvent ) ;
// if something was passed as output, it takes precedence
// and will be used as output
if ( captureStartEvent . output && captureStartEvent . output !== '' ) {
otp = captureStartEvent . output ;
} else {
attributes = captureStartEvent . attributes ;
otp = '<img' + showdown . helper . _populateAttributes ( attributes ) + ' />' ;
}
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
let beforeHashEvent = new showdown . Event ( 'makehtml.image.' + subEvtName + '.onHash' , otp ) ;
beforeHashEvent
. setOutput ( otp )
. _setGlobals ( globals )
. _setOptions ( options ) ;
beforeHashEvent = globals . converter . dispatch ( beforeHashEvent ) ;
otp = beforeHashEvent . output ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
return otp ;
2022-02-24 08:23:15 +08:00
}
} ) ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
////
// makehtml/links.js
// Copyright (c) 2018 ShowdownJS
//
// Transforms MD links into `<a>` html anchors
//
// A link contains link text (the visible text), a link destination (the URI that is the link destination), and
// optionally a link title. There are two basic kinds of links in Markdown.
// In inline links the destination and title are given immediately after the link text.
// In reference links the destination and title are defined elsewhere in the document.
//
// ***Author:***
// - Estevão Soares dos Santos (Tivie) <https://github.com/tivie>
////
2022-04-28 04:42:24 +08:00
showdown . subParser ( 'makehtml.link' , function ( text , options , globals ) {
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
//
// Parser starts here
//
let startEvent = new showdown . Event ( 'makehtml.link.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
// 1. Handle reference-style links: [link text] [id]
let referenceRegex = /\[((?:\[[^\]]*]|[^\[\]])*)] ?(?:\n *)?\[(.*?)]/g ;
text = text . replace ( referenceRegex , function ( wholeMatch , text , linkId ) {
// bail if we find 2 newlines somewhere
if ( /\n\n/ . test ( wholeMatch ) ) {
return wholeMatch ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
return writeAnchorTag ( 'reference' , referenceRegex , wholeMatch , text , linkId ) ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
// 2. Handle inline-style links: [link text](url "optional title")
// 2.1. Look for empty cases: []() and [empty]() and []("title")
let inlineEmptyRegex = /\[(.*?)]\(<? ?>? ?(["'](.*)["'])?\)/g ;
text = text . replace ( inlineEmptyRegex , function ( wholeMatch , text , m1 , title ) {
return writeAnchorTag ( 'inline' , inlineEmptyRegex , wholeMatch , text , null , null , title , true ) ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
// 2.2. Look for cases with crazy urls like ./image/cat1).png
// the url mus be enclosed in <>
let inlineCrazyRegex = /\[((?:\[[^\]]*]|[^\[\]])*)]\s?\([ \t]?<([^>]*)>(?:[ \t]*((["'])([^"]*?)\4))?[ \t]?\)/g ;
text = text . replace ( inlineCrazyRegex , function ( wholeMatch , text , url , m1 , m2 , title ) {
return writeAnchorTag ( 'inline' , inlineCrazyRegex , wholeMatch , text , null , url , title ) ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
// 2.3. inline links with no title or titles wrapped in ' or ":
// [text](url.com) || [text](<url.com>) || [text](url.com "title") || [text](<url.com> "title")
let inlineNormalRegex1 = /\[([\S ]*?)]\s?\( *<?([^\s'"]*?(?:\(\S*?\)\S*?)?)>?\s*(?:(['"])(.*?)\3)? *\)/g ;
text = text . replace ( inlineNormalRegex1 , function ( wholeMatch , text , url , m1 , title ) {
return writeAnchorTag ( 'inline' , inlineNormalRegex1 , wholeMatch , text , null , url , title ) ;
} ) ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
// 2.4. inline links with titles wrapped in (): [foo](bar.com (title))
let inlineNormalRegex2 = /\[([\S ]*?)]\s?\( *<?([^\s'"]*?(?:\(\S*?\)\S*?)?)>?\s+\((.*?)\) *\)/g ;
text = text . replace ( inlineNormalRegex2 , function ( wholeMatch , text , url , title ) {
return writeAnchorTag ( 'inline' , inlineNormalRegex2 , wholeMatch , text , null , url , title ) ;
} ) ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
// 3. Handle reference-style shortcuts: [link text]
// These must come last in case there's a [link text][1] or [link text](/foo)
let referenceShortcutRegex = /\[([^\[\]]+)]/g ;
text = text . replace ( referenceShortcutRegex , function ( wholeMatch , text ) {
return writeAnchorTag ( 'reference' , referenceShortcutRegex , wholeMatch , text ) ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
// 4. Handle angle brackets links -> `<http://example.com/>`
// Must come after links, because you can use < and > delimiters in inline links like [this](<url>).
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
// 4.1. Handle links first
let angleBracketsLinksRegex = /<(((?:https?|ftp):\/\/|www\.)[^'">\s]+)>/gi ;
text = text . replace ( angleBracketsLinksRegex , function ( wholeMatch , url , urlStart ) {
let text = url ;
url = ( urlStart === 'www.' ) ? 'http://' + url : url ;
return writeAnchorTag ( 'angleBrackets' , angleBracketsLinksRegex , wholeMatch , text , null , url ) ;
} ) ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
// 4.2. Then mail adresses
let angleBracketsMailRegex = /<(?:mailto:)?([-.\w]+@[-a-z\d]+(\.[-a-z\d]+)*\.[a-z]+)>/gi ;
text = text . replace ( angleBracketsMailRegex , function ( wholeMatch , mail ) {
const m = parseMail ( mail ) ;
return writeAnchorTag ( 'angleBrackets' , angleBracketsMailRegex , wholeMatch , m . mail , null , m . url ) ;
} ) ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
// 5. Handle GithubMentions (if option is enabled)
if ( options . ghMentions ) {
let ghMentionsRegex = /(^|\s)(\\)?(@([a-z\d]+(?:[a-z\d._-]+?[a-z\d]+)*))/gi ;
text = text . replace ( ghMentionsRegex , function ( wholeMatch , st , escape , mentions , username ) {
2022-02-24 08:23:15 +08:00
// bail if the mentions was escaped
if ( escape === '\\' ) {
return st + mentions ;
}
// check if options.ghMentionsLink is a string
// TODO Validation should be done at initialization not at runtime
if ( ! showdown . helper . isString ( options . ghMentionsLink ) ) {
throw new Error ( 'ghMentionsLink option must be a string' ) ;
}
2022-04-28 04:42:24 +08:00
let url = options . ghMentionsLink . replace ( /\{u}/g , username ) ;
return st + writeAnchorTag ( 'reference' , ghMentionsRegex , wholeMatch , mentions , null , url ) ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
}
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
// 6 and 7 have to come here to prevent naked links to catch html
// 6. Handle <a> tags
text = text . replace ( /<a\s[^>]*>[\s\S]*<\/a>/g , function ( wholeMatch ) {
return showdown . helper . _hashHTMLSpan ( wholeMatch , globals ) ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
// 7. Handle <img> tags
text = text . replace ( /<img\s[^>]*\/?>/g , function ( wholeMatch ) {
return showdown . helper . _hashHTMLSpan ( wholeMatch , globals ) ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
// 8. Handle naked links (if option is enabled)
if ( options . simplifiedAutoLink ) {
// 8.1. Check for naked URLs
2022-02-24 08:23:15 +08:00
// we also include leading markdown magic chars [_*~] for cases like __https://www.google.com/foobar__
2022-04-28 04:42:24 +08:00
let nakedUrlRegex = /([_*~]*?)(((?:https?|ftp):\/\/|www\.)[^\s<>"'`´ .-][^\s<>"'`´ ]*?\.[a-z\d.]+[^\s<>"']*)\1/gi ;
text = text . replace ( nakedUrlRegex , function ( wholeMatch , leadingMDChars , url , urlPrefix ) {
2022-02-24 08:23:15 +08:00
// we now will start traversing the url from the front to back, looking for punctuation chars [_*~,;:.!?\)\]]
2022-04-28 04:42:24 +08:00
const len = url . length ;
let suffix = '' ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
for ( let i = len - 1 ; i >= 0 ; -- i ) {
let char = url . charAt ( i ) ;
2022-02-24 08:23:15 +08:00
if ( /[_*~,;:.!?]/ . test ( char ) ) {
2022-04-28 04:42:24 +08:00
// it's a punctuation char so we remove it from the url
2022-02-24 08:23:15 +08:00
url = url . slice ( 0 , - 1 ) ;
// and prepend it to the suffix
suffix = char + suffix ;
2022-04-28 04:42:24 +08:00
} else if ( /[)\]]/ . test ( char ) ) {
// it's a parenthesis so we need to check for "balance" (kinda)
let opPar , clPar ;
if ( /\)/ . test ( char ) ) {
// it's a curved parenthesis
opPar = url . match ( /\(/g ) || [ ] ;
clPar = url . match ( /\)/g ) ;
2022-02-24 08:23:15 +08:00
} else {
2022-04-28 04:42:24 +08:00
// it's a squared parenthesis
opPar = url . match ( /\[/g ) || [ ] ;
clPar = url . match ( /]/g ) ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
if ( opPar . length < clPar . length ) {
2022-02-24 08:23:15 +08:00
// there are more closing Parenthesis than opening so chop it!!!!!
url = url . slice ( 0 , - 1 ) ;
// and prepend it to the suffix
suffix = char + suffix ;
} else {
// it's (kinda) balanced so our work is done
break ;
}
} else {
// it's not a punctuation or a parenthesis so our work is done
break ;
}
}
// we copy the treated url to the text variable
2022-04-28 04:42:24 +08:00
let txt = url ;
2022-02-24 08:23:15 +08:00
// finally, if it's a www shortcut, we prepend http
url = ( urlPrefix === 'www.' ) ? 'http://' + url : url ;
// url part is done so let's take care of text now
// we need to escape the text (because of links such as www.example.com/foo__bar__baz)
2022-04-28 04:42:24 +08:00
txt = txt . replace ( showdown . helper . regexes . asteriskDashTildeAndColon , showdown . helper . escapeCharactersCallback ) ;
2022-02-24 08:23:15 +08:00
// and return the link tag, with the leadingMDChars and suffix. The leadingMDChars are added at the end too because
// we consumed those characters in the regexp
2022-04-28 04:42:24 +08:00
return leadingMDChars +
writeAnchorTag ( 'autoLink' , nakedUrlRegex , wholeMatch , txt , null , url ) +
suffix +
leadingMDChars ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
// 8.2. Now check for naked mail
let nakedMailRegex = /(^|\s)(?:mailto:)?([A-Za-z\d!#$%&'*+-/=?^_`{|}~.]+@[-a-z\d]+(\.[-a-z\d]+)*\.[a-z]+)(?=$|\s)/gmi ;
text = text . replace ( nakedMailRegex , function ( wholeMatch , leadingChar , mail ) {
const m = parseMail ( mail ) ;
return leadingChar + writeAnchorTag ( 'autoLink' , nakedMailRegex , wholeMatch , m . mail , null , m . url ) ;
} ) ;
}
let afterEvent = new showdown . Event ( 'makehtml.link.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
/ * *
*
* @ param { string } subEvtName
* @ param { RegExp } pattern
* @ param { string } wholeMatch
* @ param { string } text
* @ param { string | null } [ linkId ]
* @ param { string | null } [ url ]
* @ param { string | null } [ title ]
* @ param { boolean } [ emptyCase ]
* @ returns { string }
* /
function writeAnchorTag ( subEvtName , pattern , wholeMatch , text , linkId , url , title , emptyCase ) {
let matches = {
_wholeMatch : wholeMatch ,
_linkId : linkId ,
_url : url ,
_title : title ,
text : text
} ,
otp ,
attributes = { } ;
title = title || null ;
url = url || null ;
linkId = ( linkId ) ? linkId . toLowerCase ( ) : null ;
emptyCase = ! ! emptyCase ;
if ( emptyCase ) {
url = '' ;
} else if ( ! url ) {
if ( ! linkId ) {
// lower-case and turn embedded newlines into spaces
linkId = text . toLowerCase ( ) . replace ( / ?\n/g , ' ' ) ;
}
url = '#' + linkId ;
if ( ! showdown . helper . isUndefined ( globals . gUrls [ linkId ] ) ) {
url = globals . gUrls [ linkId ] ;
if ( ! showdown . helper . isUndefined ( globals . gTitles [ linkId ] ) ) {
title = globals . gTitles [ linkId ] ;
}
2022-02-24 08:23:15 +08:00
} else {
2022-04-28 04:42:24 +08:00
return wholeMatch ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
}
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
url = showdown . helper . applyBaseUrl ( options . relativePathBaseUrl , url ) ;
url = url . replace ( showdown . helper . regexes . asteriskDashTildeAndColon , showdown . helper . escapeCharactersCallback ) ;
attributes . href = url ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
if ( title && showdown . helper . isString ( title ) ) {
title = title
. replace ( /"/g , '"' )
. replace ( showdown . helper . regexes . asteriskDashTildeAndColon , showdown . helper . escapeCharactersCallback ) ;
attributes . title = title ;
}
2022-03-26 08:31:41 +08:00
2022-04-28 04:42:24 +08:00
// optionLinksInNewWindow only applies
// to external links. Hash links (#) open in same page
if ( options . openLinksInNewWindow && ! /^#/ . test ( url ) ) {
attributes . rel = 'noopener noreferrer' ;
attributes . target = '¨E95Eblank' ; // escaped _
}
let captureStartEvent = new showdown . Event ( 'makehtml.link.' + subEvtName + '.onCapture' , wholeMatch ) ;
captureStartEvent
. setOutput ( null )
. _setGlobals ( globals )
. _setOptions ( options )
. setRegexp ( pattern )
. setMatches ( matches )
. setAttributes ( attributes ) ;
captureStartEvent = globals . converter . dispatch ( captureStartEvent ) ;
// if something was passed as output, it takes precedence
// and will be used as output
if ( captureStartEvent . output && captureStartEvent . output !== '' ) {
otp = captureStartEvent . output ;
} else {
attributes = captureStartEvent . attributes ;
text = captureStartEvent . matches . text || '' ;
// Text can be a markdown element, so we run through the appropriate parsers
text = showdown . subParser ( 'makehtml.codeSpan' ) ( text , options , globals ) ;
text = showdown . subParser ( 'makehtml.emoji' ) ( text , options , globals ) ;
text = showdown . subParser ( 'makehtml.underline' ) ( text , options , globals ) ;
text = showdown . subParser ( 'makehtml.emphasisAndStrong' ) ( text , options , globals ) ;
text = showdown . subParser ( 'makehtml.strikethrough' ) ( text , options , globals ) ;
text = showdown . subParser ( 'makehtml.ellipsis' ) ( text , options , globals ) ;
text = showdown . subParser ( 'makehtml.hashHTMLSpans' ) ( text , options , globals ) ;
otp = '<a' + showdown . helper . _populateAttributes ( attributes ) + '>' + text + '</a>' ;
}
let beforeHashEvent = new showdown . Event ( 'makehtml.link.' + subEvtName + '.onHash' , otp ) ;
beforeHashEvent
. setOutput ( otp )
. _setGlobals ( globals )
. _setOptions ( options ) ;
beforeHashEvent = globals . converter . dispatch ( beforeHashEvent ) ;
otp = beforeHashEvent . output ;
return showdown . subParser ( 'makehtml.hashHTMLSpans' ) ( otp , options , globals ) ;
}
/ * *
* @ param { string } mail
* @ returns { { mail : string , url : string } }
* /
function parseMail ( mail ) {
let url = 'mailto:' ;
mail = showdown . subParser ( 'makehtml.unescapeSpecialChars' ) ( mail , options , globals ) ;
if ( options . encodeEmails ) {
url = showdown . helper . encodeEmailAddress ( url + mail ) ;
mail = showdown . helper . encodeEmailAddress ( mail ) ;
} else {
url = url + mail ;
}
return {
mail : mail ,
url : url
} ;
}
} ) ;
////
// makehtml/list.js
// Copyright (c) 2022 ShowdownJS
//
// Transforms MD lists into `<ul>` or `<ol>` html list
//
// Markdown supports ordered (numbered) and unordered (bulleted) lists.
// Unordered lists use asterisks, pluses, and hyphens - interchangably - as list markers
// Ordered lists use numbers followed by periods.
//
// ***Author:***
// - Estevão Soares dos Santos (Tivie) <https://github.com/tivie>
////
showdown . subParser ( 'makehtml.list' , function ( text , options , globals ) {
2022-02-24 08:23:15 +08:00
'use strict' ;
2022-04-28 04:42:24 +08:00
// Start of list parsing
const subListRgx = /^(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(¨0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm ;
const mainListRgx = /(\n\n|^\n?)(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(¨0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm ;
const listTypeRgx = /[*+-]/g ;
let startEvent = new showdown . Event ( 'makehtml.list.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
// add sentinel to hack around khtml/safari bug:
// http://bugs.webkit.org/show_bug.cgi?id=11231
text += '¨0' ;
if ( globals . gListLevel ) {
text = text . replace ( subListRgx , function ( wholeMatch , list , m2 ) {
return parseConsecutiveLists ( subListRgx , list , ( m2 . search ( listTypeRgx ) > - 1 ) ? 'ul' : 'ol' , true ) ;
} ) ;
} else {
text = text . replace ( mainListRgx , function ( wholeMatch , m1 , list , m3 ) {
return parseConsecutiveLists ( mainListRgx , list , ( m3 . search ( listTypeRgx ) > - 1 ) ? 'ul' : 'ol' , false ) ;
} ) ;
}
// strip sentinel
text = text . replace ( /¨0/ , '' ) ;
let afterEvent = new showdown . Event ( 'makehtml.list.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
/ * *
*
* @ param { RegExp } pattern
* @ param { string } item
* @ param { boolean } checked
* @ returns { string }
* /
function processTaskListItem ( pattern , item , checked ) {
const checkboxRgx = /^[ \t]*\[([xX ])]/m ;
item = item . replace ( checkboxRgx , function ( wm , checkedRaw ) {
let attributes = {
type : 'checkbox' ,
disabled : true ,
style : 'margin: 0px 0.35em 0.25em -1.6em; vertical-align: middle;' ,
checked : ! ! checked
} ;
let captureStartEvent = new showdown . Event ( 'makehtml.list.taskListItem.checkbox.onCapture' , item ) ;
captureStartEvent
. setOutput ( null )
. _setGlobals ( globals )
. _setOptions ( options )
. setRegexp ( pattern )
. setMatches ( {
_wholeMatch : item ,
_tasklistButton : wm ,
_taksListButtonChecked : checkedRaw
} )
. setAttributes ( attributes ) ;
captureStartEvent = globals . converter . dispatch ( captureStartEvent ) ;
let otp ;
if ( captureStartEvent . output && captureStartEvent . output !== '' ) {
otp = captureStartEvent . output ;
} else {
attributes = captureStartEvent . attributes ;
otp = '<input' + showdown . helper . _populateAttributes ( attributes ) + '>' ;
}
let beforeHashEvent = new showdown . Event ( 'makehtml.list.taskListItem.checkbox.onHash' , otp ) ;
beforeHashEvent
. setOutput ( otp )
. _setGlobals ( globals )
. _setOptions ( options ) ;
beforeHashEvent = globals . converter . dispatch ( beforeHashEvent ) ;
otp = beforeHashEvent . output ;
return otp ;
} ) ;
return item ;
}
2022-02-24 08:23:15 +08:00
/ * *
* Process the contents of a single ordered or unordered list , splitting it
* into individual list items .
* @ param { string } listStr
* @ param { boolean } trimTrailing
* @ returns { string }
* /
function processListItems ( listStr , trimTrailing ) {
// The $g_list_level global keeps track of when we're inside a list.
// Each time we enter a list, we increment it; when we leave a list,
// we decrement. If it's zero, we're not in a list anymore.
//
// We do this because when we're not inside a list, we want to treat
// something like this:
//
// I recommend upgrading to version
// 8. Oops, now this line is treated
// as a sub-list.
//
// As a single paragraph, despite the fact that the second line starts
// with a digit-period-space sequence.
//
// Whereas when we're inside a list (or sub-list), that line will be
// treated as the start of a sub-list. What a kludge, huh? This is
// an aspect of Markdown's syntax that's hard to parse perfectly
// without resorting to mind-reading. Perhaps the solution is to
// change the syntax rules such that sub-lists must start with a
// starting cardinal number; e.g. "1." or "a.".
globals . gListLevel ++ ;
// trim trailing blank lines:
listStr = listStr . replace ( /\n{2,}$/ , '\n' ) ;
// attacklab: add sentinel to emulate \z
listStr += '¨0' ;
2022-04-28 04:42:24 +08:00
let rgx = /(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[([xX ])])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(¨0| {0,3}([*+-]|\d+[.])[ \t]+))/gm ,
2022-02-24 08:23:15 +08:00
isParagraphed = ( /\n[ \t]*\n(?!¨0)/ . test ( listStr ) ) ;
// Since version 1.5, nesting sublists requires 4 spaces (or 1 tab) indentation,
// which is a syntax breaking change
// activating this option reverts to old behavior
// This will be removed in version 2.0
if ( options . disableForced4SpacesIndentedSublists ) {
2022-02-24 09:57:08 +08:00
rgx = /(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[([xX ])])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(¨0|\2([*+-]|\d+[.])[ \t]+))/gm ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
listStr = listStr . replace ( rgx , function ( wholeMatch , m1 , m2 , m3 , m4 , taskbtn , checkedRaw ) {
let item = showdown . helper . outdent ( m4 ) ,
attributes = { } ,
checked = ( checkedRaw && checkedRaw . trim ( ) !== '' ) ,
eventName = 'makehtml.list.listItem' ,
captureStartEvent ,
matches = {
_wholeMatch : wholeMatch ,
listItem : item ,
} ;
2022-02-24 08:23:15 +08:00
// Support for github tasklists
if ( taskbtn && options . tasklists ) {
2022-04-28 04:42:24 +08:00
// it's a github tasklist and tasklists are enabled
2022-02-24 09:57:08 +08:00
// Style used for tasklist bullets
2022-04-28 04:42:24 +08:00
attributes . classes = [ 'task-list-item' ] ;
attributes . style = 'list-style-type: none;' ;
if ( options . moreStyling && checked ) {
attributes . classes . push ( 'task-list-item-complete' ) ;
}
eventName = 'makehtml.list.taskListItem' ;
matches . _taskListButton = taskbtn ;
matches . _taskListButtonChecked = checkedRaw ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
captureStartEvent = new showdown . Event ( eventName + '.onCapture' , item ) ;
captureStartEvent
. setOutput ( null )
. _setGlobals ( globals )
. _setOptions ( options )
. setRegexp ( rgx )
. setMatches ( matches )
. setAttributes ( attributes ) ;
captureStartEvent = globals . converter . dispatch ( captureStartEvent ) ;
// if something was passed as output, it takes precedence
// and will be used as output
if ( captureStartEvent . output && captureStartEvent . output !== '' ) {
item = captureStartEvent . output ;
} else {
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
attributes = captureStartEvent . attributes ;
item = captureStartEvent . matches . listItem ;
// even if user there's no tasklist, it's fine because the tasklist handler will bail without raising the event
if ( options . tasklists ) {
item = processTaskListItem ( rgx , item , checked ) ;
2022-02-25 09:06:09 +08:00
}
2022-04-28 04:42:24 +08:00
// ISSUE #312
// This input: - - - a
// causes trouble to the parser, since it interprets it as:
// <ul><li><li><li>a</li></li></li></ul>
// instead of:
// <ul><li>- - a</li></ul>
// So, to prevent it, we will put a marker (¨A)in the beginning of the line
// Kind of hackish/monkey patching, but seems more effective than overcomplicating the list parser
item = item . replace ( /^([-*+]|\d\.)[ \t]+[\S\n ]*/g , function ( wm2 ) {
return '¨A' + wm2 ;
} ) ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
// SPECIAL CASE: a heading followed by a paragraph of text that is not separated by a double newline
// or/nor indented. ex:
//
// - # foo
// bar is great
//
// While this does now follow the spec per se, not allowing for this might cause confusion since
// header blocks don't need double-newlines after
if ( /^#+.+\n.+/ . test ( item ) ) {
item = item . replace ( /^(#+.+)$/m , '$1\n' ) ;
}
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
// m1 - Leading line or
// Has a double return (multi paragraph)
if ( m1 || ( item . search ( /\n{2,}/ ) > - 1 ) ) {
item = showdown . subParser ( 'makehtml.githubCodeBlock' ) ( item , options , globals ) ;
item = showdown . subParser ( 'makehtml.blockquote' ) ( item , options , globals ) ;
item = showdown . subParser ( 'makehtml.heading' ) ( item , options , globals ) ;
item = showdown . subParser ( 'makehtml.list' ) ( item , options , globals ) ;
item = showdown . subParser ( 'makehtml.codeBlock' ) ( item , options , globals ) ;
item = showdown . subParser ( 'makehtml.table' ) ( item , options , globals ) ;
item = showdown . subParser ( 'makehtml.hashHTMLBlocks' ) ( item , options , globals ) ;
//item = showdown.subParser('makehtml.paragraphs')(item, options, globals);
// TODO: This is a copy of the paragraph parser
// This is a provisory fix for issue #494
// For a permanent fix we need to rewrite the paragraph parser, passing the unhashify logic outside
// so that we can call the paragraph parser without accidently unashifying previously parsed blocks
// Strip leading and trailing lines:
item = item . replace ( /^\n+/g , '' ) ;
item = item . replace ( /\n+$/g , '' ) ;
let grafs = item . split ( /\n{2,}/g ) ,
grafsOut = [ ] ,
end = grafs . length ; // Wrap <p> tags
for ( let i = 0 ; i < end ; i ++ ) {
let str = grafs [ i ] ;
// if this is an HTML marker, copy it
if ( str . search ( /¨([KG])(\d+)\1/g ) >= 0 ) {
grafsOut . push ( str ) ;
// test for presence of characters to prevent empty lines being parsed
// as paragraphs (resulting in undesired extra empty paragraphs)
} else if ( str . search ( /\S/ ) >= 0 ) {
str = showdown . subParser ( 'makehtml.spanGamut' ) ( str , options , globals ) ;
str = str . replace ( /^([ \t]*)/g , '<p>' ) ;
str += '</p>' ;
grafsOut . push ( str ) ;
}
}
item = grafsOut . join ( '\n' ) ;
// Strip leading and trailing lines:
item = item . replace ( /^\n+/g , '' ) ;
item = item . replace ( /\n+$/g , '' ) ;
2022-02-24 08:23:15 +08:00
} else {
2022-04-28 04:42:24 +08:00
// Recursion for sub-lists:
item = showdown . subParser ( 'makehtml.list' ) ( item , options , globals ) ;
item = item . replace ( /\n$/ , '' ) ; // chomp(item)
item = showdown . subParser ( 'makehtml.hashHTMLBlocks' ) ( item , options , globals ) ;
// Colapse double linebreaks
item = item . replace ( /\n\n+/g , '\n\n' ) ;
if ( isParagraphed ) {
item = showdown . subParser ( 'makehtml.paragraphs' ) ( item , options , globals ) ;
} else {
item = showdown . subParser ( 'makehtml.spanGamut' ) ( item , options , globals ) ;
}
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
// now we need to remove the marker (¨A)
item = item . replace ( '¨A' , '' ) ;
// we can finally wrap the line in list item tags
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
item = '<li' + showdown . helper . _populateAttributes ( attributes ) + '>' + item + '</li>\n' ;
}
let beforeHashEvent = new showdown . Event ( eventName + '.onHash' , item ) ;
beforeHashEvent
. setOutput ( item )
. _setGlobals ( globals )
. _setOptions ( options ) ;
beforeHashEvent = globals . converter . dispatch ( beforeHashEvent ) ;
return beforeHashEvent . output ;
2022-02-24 08:23:15 +08:00
} ) ;
// attacklab: strip sentinel
listStr = listStr . replace ( /¨0/g , '' ) ;
globals . gListLevel -- ;
if ( trimTrailing ) {
listStr = listStr . replace ( /\s+$/ , '' ) ;
}
return listStr ;
}
2022-04-28 04:42:24 +08:00
/ * *
*
* @ param { string } list
* @ param { string } listType
* @ returns { string | null }
* /
2022-02-24 08:23:15 +08:00
function styleStartNumber ( list , listType ) {
// check if ol and starts by a number different than 1
if ( listType === 'ol' ) {
2022-04-28 04:42:24 +08:00
let res = list . match ( /^ *(\d+)\./ ) ;
2022-02-24 08:23:15 +08:00
if ( res && res [ 1 ] !== '1' ) {
2022-04-28 04:42:24 +08:00
return res [ 1 ] ;
2022-02-24 08:23:15 +08:00
}
}
2022-04-28 04:42:24 +08:00
return null ;
2022-02-24 08:23:15 +08:00
}
/ * *
* Check and parse consecutive lists ( better fix for issue # 142 )
2022-04-28 04:42:24 +08:00
* @ param { RegExp } pattern
2022-02-24 08:23:15 +08:00
* @ param { string } list
* @ param { string } listType
* @ param { boolean } trimTrailing
* @ returns { string }
* /
2022-04-28 04:42:24 +08:00
function parseConsecutiveLists ( pattern , list , listType , trimTrailing ) {
let otp = '' ;
let captureStartEvent = new showdown . Event ( 'makehtml.list.onCapture' , list ) ;
captureStartEvent
. setOutput ( null )
. _setGlobals ( globals )
. _setOptions ( options )
. setRegexp ( pattern )
. setMatches ( {
_wholeMatch : list ,
list : list
} )
. setAttributes ( { } ) ;
captureStartEvent = globals . converter . dispatch ( captureStartEvent ) ;
let attributes = captureStartEvent . attributes ;
// if something was passed as output, it takes precedence
// and will be used as output
if ( captureStartEvent . output && captureStartEvent . output !== '' ) {
otp = captureStartEvent . output ;
2022-02-24 08:23:15 +08:00
} else {
2022-04-28 04:42:24 +08:00
// check if we caught 2 or more consecutive lists by mistake
// we use the counterRgx, meaning if listType is UL we look for OL and vice versa
const olRgx = ( options . disableForced4SpacesIndentedSublists ) ? /^ ?\d+\.[ \t]/gm : /^ {0,3}\d+\.[ \t]/gm ;
const ulRgx = ( options . disableForced4SpacesIndentedSublists ) ? /^ ?[*+-][ \t]/gm : /^ {0,3}[*+-][ \t]/gm ;
let counterRxg = ( listType === 'ul' ) ? olRgx : ulRgx ;
let attrs = showdown . helper . cloneObject ( attributes ) ;
if ( list . search ( counterRxg ) !== - 1 ) {
( function parseCL ( txt ) {
let pos = txt . search ( counterRxg ) ;
attrs . start = styleStartNumber ( list , listType ) ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
if ( pos !== - 1 ) {
// slice
otp += '\n\n<' + listType + showdown . helper . _populateAttributes ( attrs ) + '>\n' + processListItems ( txt . slice ( 0 , pos ) , ! ! trimTrailing ) + '</' + listType + '>\n' ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
// invert counterType and listType
listType = ( listType === 'ul' ) ? 'ol' : 'ul' ;
counterRxg = ( listType === 'ul' ) ? olRgx : ulRgx ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
//recurse
parseCL ( txt . slice ( pos ) , attrs ) ;
} else {
otp += '\n\n<' + listType + showdown . helper . _populateAttributes ( attrs ) + '>\n' + processListItems ( txt , ! ! trimTrailing ) + '</' + listType + '>\n' ;
}
} ) ( list , attributes ) ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
} else {
attrs . start = styleStartNumber ( list , listType ) ;
otp = '\n\n<' + listType + showdown . helper . _populateAttributes ( attrs ) + '>\n' + processListItems ( list , ! ! trimTrailing ) + '</' + listType + '>\n' ;
}
}
return otp ;
}
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
/ * *
* Parse metadata at the top of the document
* /
showdown . subParser ( 'makehtml.metadata' , function ( text , options , globals ) {
'use strict' ;
if ( ! options . metadata ) {
return text ;
}
2022-04-28 04:42:24 +08:00
let startEvent = new showdown . Event ( 'makehtml.metadata.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
/ * *
* @ param { RegExp } pattern
* @ param { string } wholeMatch
* @ param { string } format
* @ param { string } content
* @ returns { string }
* /
function parseMetadataContents ( pattern , wholeMatch , format , content ) {
let otp ;
let captureStartEvent = new showdown . Event ( 'makehtml.metadata.onCapture' , content ) ;
captureStartEvent
. setOutput ( null )
. _setGlobals ( globals )
. _setOptions ( options )
. setRegexp ( pattern )
. setMatches ( {
_wholeMatch : wholeMatch ,
format : format ,
content : content
} )
. setAttributes ( { } ) ;
captureStartEvent = globals . converter . dispatch ( captureStartEvent ) ;
format = captureStartEvent . matches . format ;
content = captureStartEvent . matches . content ;
// if something was passed as output, it will be used as output
if ( captureStartEvent . output && captureStartEvent . output !== '' ) {
otp = captureStartEvent . output ;
} else {
otp = '¨M' ;
}
2022-02-24 08:23:15 +08:00
// raw is raw so it's not changed in any way
globals . metadata . raw = content ;
2022-04-28 04:42:24 +08:00
globals . metadata . format = format ;
2022-02-24 08:23:15 +08:00
// escape chars forbidden in html attributes
// double quotes
content = content
// ampersand first
. replace ( /&/g , '&' )
// double quotes
2022-04-28 04:42:24 +08:00
. replace ( /"/g , '"' )
2022-02-24 08:23:15 +08:00
// Restore dollar signs and tremas
. replace ( /¨D/g , '$$' )
2022-04-28 04:42:24 +08:00
. replace ( /¨T/g , '¨' )
// replace multiple spaces
. replace ( /\n {4}/g , ' ' ) ;
2022-02-24 08:23:15 +08:00
content . replace ( /^([\S ]+): +([\s\S]+?)$/gm , function ( wm , key , value ) {
globals . metadata . parsed [ key ] = value ;
return '' ;
} ) ;
2022-04-28 04:42:24 +08:00
let beforeHashEvent = new showdown . Event ( 'makehtml.metadata.onHash' , otp ) ;
beforeHashEvent
. setOutput ( otp )
. _setGlobals ( globals )
. _setOptions ( options ) ;
beforeHashEvent = globals . converter . dispatch ( beforeHashEvent ) ;
otp = beforeHashEvent . output ;
if ( ! otp ) {
otp = '¨M' ;
}
return otp ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
// 1. Metadata with «««»»» delimiters
const rgx1 = /^\s*«««+\s*(\S*?)\n([\s\S]+?)\n»»»+\s*\n/ ;
text = text . replace ( rgx1 , function ( wholeMatch , format , content ) {
return parseMetadataContents ( rgx1 , wholeMatch , format , content ) ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
// 2. Metadata with YAML delimiters
const rgx2 = /^\s*---+\s*(\S*?)\n([\s\S]+?)\n---+\s*\n/ ;
text = text . replace ( rgx2 , function ( wholeMatch , format , content ) {
return parseMetadataContents ( rgx1 , wholeMatch , format , content ) ;
2022-02-24 08:23:15 +08:00
} ) ;
text = text . replace ( /¨M/g , '' ) ;
2022-04-28 04:42:24 +08:00
let afterEvent = new showdown . Event ( 'makehtml.metadata.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
/ * *
*
* /
showdown . subParser ( 'makehtml.paragraphs' , function ( text , options , globals ) {
'use strict' ;
// Strip leading and trailing lines:
text = text . replace ( /^\n+/g , '' ) ;
text = text . replace ( /\n+$/g , '' ) ;
var grafs = text . split ( /\n{2,}/g ) ,
grafsOut = [ ] ,
end = grafs . length ; // Wrap <p> tags
for ( var i = 0 ; i < end ; i ++ ) {
var str = grafs [ i ] ;
// if this is an HTML marker, copy it
if ( str . search ( /¨(K|G)(\d+)\1/g ) >= 0 ) {
grafsOut . push ( str ) ;
// test for presence of characters to prevent empty lines being parsed
// as paragraphs (resulting in undesired extra empty paragraphs)
} else if ( str . search ( /\S/ ) >= 0 ) {
str = showdown . subParser ( 'makehtml.spanGamut' ) ( str , options , globals ) ;
str = str . replace ( /^([ \t]*)/g , '<p>' ) ;
str += '</p>' ;
grafsOut . push ( str ) ;
}
}
/** Unhashify HTML blocks */
end = grafsOut . length ;
for ( i = 0 ; i < end ; i ++ ) {
var blockText = '' ,
grafsOutIt = grafsOut [ i ] ,
codeFlag = false ;
// if this is a marker for an html block...
// use RegExp.test instead of string.search because of QML bug
2022-04-28 04:42:24 +08:00
while ( /¨([KG])(\d+)\1/ . test ( grafsOutIt ) ) {
2022-02-24 08:23:15 +08:00
var delim = RegExp . $1 ,
num = RegExp . $2 ;
if ( delim === 'K' ) {
blockText = globals . gHtmlBlocks [ num ] ;
} else {
// we need to check if ghBlock is a false positive
if ( codeFlag ) {
// use encoded version of all text
blockText = showdown . subParser ( 'makehtml.encodeCode' ) ( globals . ghCodeBlocks [ num ] . text , options , globals ) ;
} else {
blockText = globals . ghCodeBlocks [ num ] . codeblock ;
}
}
blockText = blockText . replace ( /\$/g , '$$$$' ) ; // Escape any dollar signs
2022-04-28 04:42:24 +08:00
grafsOutIt = grafsOutIt . replace ( /(\n\n)?¨([KG])\d+\2(\n\n)?/ , blockText ) ;
2022-02-24 08:23:15 +08:00
// Check if grafsOutIt is a pre->code
if ( /^<pre\b[^>]*>\s*<code\b[^>]*>/ . test ( grafsOutIt ) ) {
codeFlag = true ;
}
}
grafsOut [ i ] = grafsOutIt ;
}
text = grafsOut . join ( '\n' ) ;
// Strip leading and trailing lines:
text = text . replace ( /^\n+/g , '' ) ;
text = text . replace ( /\n+$/g , '' ) ;
2022-04-28 04:42:24 +08:00
return text ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
/ * *
* Run extension
* /
showdown . subParser ( 'makehtml.runExtension' , function ( ext , text , options , globals ) {
'use strict' ;
if ( ext . filter ) {
text = ext . filter ( text , globals . converter , options ) ;
} else if ( ext . regex ) {
// TODO remove this when old extension loading mechanism is deprecated
2022-04-28 04:42:24 +08:00
let re = ext . regex ;
2022-02-24 08:23:15 +08:00
if ( ! ( re instanceof RegExp ) ) {
re = new RegExp ( re , 'g' ) ;
}
text = text . replace ( re , ext . replace ) ;
}
return text ;
} ) ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
/ * *
* These are all the transformations that occur * within * block - level
* tags like paragraphs , headers , and list items .
* /
showdown . subParser ( 'makehtml.spanGamut' , function ( text , options , globals ) {
'use strict' ;
2022-04-28 04:42:24 +08:00
let startEvent = new showdown . Event ( 'makehtml.spanGamut.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
text = showdown . subParser ( 'makehtml.codeSpan' ) ( text , options , globals ) ;
2022-02-24 08:23:15 +08:00
text = showdown . subParser ( 'makehtml.escapeSpecialCharsWithinTagAttributes' ) ( text , options , globals ) ;
text = showdown . subParser ( 'makehtml.encodeBackslashEscapes' ) ( text , options , globals ) ;
// Process link and image tags. Images must come first,
// because ![foo][f] looks like a link.
2022-04-28 04:42:24 +08:00
text = showdown . subParser ( 'makehtml.image' ) ( text , options , globals ) ;
text = showdown . subParser ( 'makehtml.link' ) ( text , options , globals ) ;
2022-02-24 08:23:15 +08:00
text = showdown . subParser ( 'makehtml.emoji' ) ( text , options , globals ) ;
text = showdown . subParser ( 'makehtml.underline' ) ( text , options , globals ) ;
2022-04-28 04:42:24 +08:00
text = showdown . subParser ( 'makehtml.emphasisAndStrong' ) ( text , options , globals ) ;
2022-02-24 08:23:15 +08:00
text = showdown . subParser ( 'makehtml.strikethrough' ) ( text , options , globals ) ;
text = showdown . subParser ( 'makehtml.ellipsis' ) ( text , options , globals ) ;
// we need to hash HTML tags inside spans
text = showdown . subParser ( 'makehtml.hashHTMLSpans' ) ( text , options , globals ) ;
// now we encode amps and angles
text = showdown . subParser ( 'makehtml.encodeAmpsAndAngles' ) ( text , options , globals ) ;
// Do hard breaks
if ( options . simpleLineBreaks ) {
// GFM style hard breaks
// only add line breaks if the text does not contain a block (special case for lists)
if ( ! /\n\n¨K/ . test ( text ) ) {
text = text . replace ( /\n+/g , '<br />\n' ) ;
}
} else {
// Vanilla hard breaks
text = text . replace ( / +\n/g , '<br />\n' ) ;
}
2022-04-28 04:42:24 +08:00
let afterEvent = new showdown . Event ( 'makehtml.spanGamut.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makehtml.strikethrough' , function ( text , options , globals ) {
'use strict' ;
2022-04-28 04:42:24 +08:00
if ( ! options . strikethrough ) {
return text ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
let startEvent = new showdown . Event ( 'makehtml.strikethrough.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
const strikethroughRegex = /~{2}([\s\S]+?)~{2}/g ;
text = text . replace ( strikethroughRegex , function ( wholeMatch , txt ) {
let otp ;
let captureStartEvent = new showdown . Event ( 'makehtml.strikethrough.onCapture' , txt ) ;
captureStartEvent
. setOutput ( null )
. _setGlobals ( globals )
. _setOptions ( options )
. setRegexp ( strikethroughRegex )
. setMatches ( {
_wholeMatch : wholeMatch ,
strikethrough : txt
} )
. setAttributes ( { } ) ;
captureStartEvent = globals . converter . dispatch ( captureStartEvent ) ;
// if something was passed as output, it takes precedence
// and will be used as output
if ( captureStartEvent . output && captureStartEvent . output !== '' ) {
otp = captureStartEvent . output ;
} else {
otp = '<del' + showdown . helper . _populateAttributes ( captureStartEvent . attributes ) + '>' + txt + '</del>' ;
}
2022-03-26 08:31:41 +08:00
2022-04-28 04:42:24 +08:00
let beforeHashEvent = new showdown . Event ( 'makehtml.strikethrough.onHash' , otp ) ;
beforeHashEvent
. setOutput ( otp )
. _setGlobals ( globals )
. _setOptions ( options ) ;
beforeHashEvent = globals . converter . dispatch ( beforeHashEvent ) ;
return beforeHashEvent . output ;
} ) ;
let afterEvent = new showdown . Event ( 'makehtml.strikethrough.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
} ) ;
2022-02-24 08:23:15 +08:00
/ * *
* Strips link definitions from text , stores the URLs and titles in
* hash references .
* Link defs are in the form : ^ [ id ] : url "optional title"
* /
showdown . subParser ( 'makehtml.stripLinkDefinitions' , function ( text , options , globals ) {
'use strict' ;
2022-04-28 04:42:24 +08:00
const regex = /^ {0,3}\[([^\]]+)]:[ \t]*\n?[ \t]*<?([^>\s]+)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n+|(?=¨0))/gm ,
base64Regex = /^ {0,3}\[([^\]]+)]:[ \t]*\n?[ \t]*<?(data:.+?\/.+?;base64,[A-Za-z\d+/=\n]+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n\n|(?=¨0)|(?=\n\[))/gm ;
2022-02-24 08:23:15 +08:00
// attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug
text += '¨0' ;
2022-04-28 04:42:24 +08:00
let replaceFunc = function ( wholeMatch , linkId , url , width , height , blankLines , title ) {
2022-02-24 08:23:15 +08:00
// if there aren't two instances of linkId it must not be a reference link so back out
linkId = linkId . toLowerCase ( ) ;
if ( text . toLowerCase ( ) . split ( linkId ) . length - 1 < 2 ) {
return wholeMatch ;
}
if ( url . match ( /^data:.+?\/.+?;base64,/ ) ) {
// remove newlines
globals . gUrls [ linkId ] = url . replace ( /\s/g , '' ) ;
} else {
url = showdown . helper . applyBaseUrl ( options . relativePathBaseUrl , url ) ;
globals . gUrls [ linkId ] = showdown . subParser ( 'makehtml.encodeAmpsAndAngles' ) ( url , options , globals ) ; // Link IDs are case-insensitive
}
if ( blankLines ) {
// Oops, found blank lines, so it's not a title.
// Put back the parenthetical statement we stole.
return blankLines + title ;
} else {
if ( title ) {
2022-04-28 04:42:24 +08:00
globals . gTitles [ linkId ] = title . replace ( /["']/g , '"' ) ;
2022-02-24 08:23:15 +08:00
}
if ( options . parseImgDimensions && width && height ) {
globals . gDimensions [ linkId ] = {
width : width ,
height : height
} ;
}
}
// Completely remove the definition from the text
return '' ;
} ;
// first we try to find base64 link references
text = text . replace ( base64Regex , replaceFunc ) ;
text = text . replace ( regex , replaceFunc ) ;
// attacklab: strip sentinel
text = text . replace ( /¨0/ , '' ) ;
return text ;
} ) ;
2022-04-28 04:42:24 +08:00
showdown . subParser ( 'makehtml.table' , function ( text , options , globals ) {
2022-02-24 08:23:15 +08:00
'use strict' ;
if ( ! options . tables ) {
return text ;
}
2022-04-28 04:42:24 +08:00
// find escaped pipe characters
text = text . replace ( /\\(\|)/g , showdown . helper . escapeCharactersCallback ) ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
//
// parser starts here
//
let startEvent = new showdown . Event ( 'makehtml.table.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
// parse multi column tables
const tableRgx = /^ {0,3}\|?.+\|.+\n {0,3}\|?[ \t]*:?[ \t]*[-=]{2,}[ \t]*:?[ \t]*\|[ \t]*:?[ \t]*[-=]{2,}[\s\S]+?(?:\n\n|¨0)/gm ;
text = text . replace ( tableRgx , function ( wholeMatch ) {
return parse ( tableRgx , wholeMatch ) ;
} ) ;
const singeColTblRgx = /^ {0,3}\|.+\|[ \t]*\n {0,3}\|[ \t]*:?[ \t]*[-=]{2,}[ \t]*:?[ \t]*\|[ \t]*\n( {0,3}\|.+\|[ \t]*\n)*(?:\n|¨0)/gm ;
text = text . replace ( singeColTblRgx , function ( wholeMatch ) {
return parse ( singeColTblRgx , wholeMatch ) ;
} ) ;
let afterEvent = new showdown . Event ( 'makehtml.table.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
/ * *
*
* @ param { RegExp } pattern
* @ param { string } wholeMatch
* @ returns { string }
* /
function parse ( pattern , wholeMatch ) {
let tab = preParse ( wholeMatch ) ;
// if parseTable returns null then it's a malformed table so we return what we caught
if ( ! tab ) {
return wholeMatch ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
// only now we consider it to be a markdown table and start doing stuff
let headers = tab . rawHeaders ;
let styles = tab . rawStyles ;
let cells = tab . rawCells ;
let otp ;
let captureStartEvent = new showdown . Event ( 'makehtml.table.onCapture' , wholeMatch ) ;
captureStartEvent
. setOutput ( null )
. _setGlobals ( globals )
. _setOptions ( options )
. setRegexp ( pattern )
. setMatches ( {
_wholeMatch : wholeMatch ,
table : wholeMatch
} )
. setAttributes ( { } ) ;
captureStartEvent = globals . converter . dispatch ( captureStartEvent ) ;
if ( captureStartEvent . output && captureStartEvent . output !== '' ) {
// user provided an otp, so we use it
otp = captureStartEvent . output ;
} else {
// user changed matches.table, so we need to generate headers, styles, and cells again
if ( captureStartEvent . matches . table !== wholeMatch ) {
tab = preParse ( captureStartEvent . matches . table ) ;
// user passed a malformed table, so we bail
if ( ! tab ) {
return wholeMatch ;
}
headers = tab . rawHeaders ;
styles = tab . rawStyles ;
cells = tab . rawCells ;
}
let parsedTab = parseTable ( headers , styles , cells ) ;
let attributes = captureStartEvent . attributes ;
otp = buildTableOtp ( parsedTab . headers , parsedTab . cells , attributes ) ;
}
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
let beforeHashEvent = new showdown . Event ( 'makehtml.table.onHash' , otp ) ;
beforeHashEvent
. setOutput ( otp )
. _setGlobals ( globals )
. _setOptions ( options ) ;
beforeHashEvent = globals . converter . dispatch ( beforeHashEvent ) ;
otp = beforeHashEvent . output ;
return otp ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
/ * *
*
* @ param { string [ ] } headers
* @ param { string [ ] } cells
* @ param { { } } attributes
* @ returns { string }
* /
function buildTableOtp ( headers , cells , attributes ) {
let otp ;
const colCount = headers . length ,
rowCount = cells . length ;
otp = '<table' + showdown . helper . _populateAttributes ( attributes ) + '>\n<thead>\n<tr>\n' ;
for ( let i = 0 ; i < colCount ; ++ i ) {
otp += headers [ i ] ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
otp += '</tr>\n</thead>\n<tbody>\n' ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
for ( let i = 0 ; i < rowCount ; ++ i ) {
otp += '<tr>\n' ;
for ( let ii = 0 ; ii < colCount ; ++ ii ) {
otp += cells [ i ] [ ii ] ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
otp += '</tr>\n' ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
otp += '</tbody>\n</table>\n' ;
return otp ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
/ * *
* @ param { string } rawTable
* @ returns { { rawHeaders : string [ ] , rawStyles : string [ ] , rawCells : * [ ] } | null }
* /
function preParse ( rawTable ) {
let tableLines = rawTable . split ( '\n' ) ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
for ( let i = 0 ; i < tableLines . length ; ++ i ) {
2022-02-24 08:23:15 +08:00
// strip wrong first and last column if wrapped tables are used
if ( /^ {0,3}\|/ . test ( tableLines [ i ] ) ) {
tableLines [ i ] = tableLines [ i ] . replace ( /^ {0,3}\|/ , '' ) ;
}
if ( /\|[ \t]*$/ . test ( tableLines [ i ] ) ) {
tableLines [ i ] = tableLines [ i ] . replace ( /\|[ \t]*$/ , '' ) ;
}
// parse code spans first, but we only support one line code spans
2022-04-28 04:42:24 +08:00
tableLines [ i ] = showdown . subParser ( 'makehtml.codeSpan' ) ( tableLines [ i ] , options , globals ) ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
let rawHeaders = tableLines [ 0 ] . split ( '|' ) . map ( function ( s ) { return s . trim ( ) ; } ) ,
2022-02-24 08:23:15 +08:00
rawStyles = tableLines [ 1 ] . split ( '|' ) . map ( function ( s ) { return s . trim ( ) ; } ) ,
2022-04-28 04:42:24 +08:00
rawCells = [ ] ;
2022-02-24 08:23:15 +08:00
tableLines . shift ( ) ;
tableLines . shift ( ) ;
2022-04-28 04:42:24 +08:00
for ( let i = 0 ; i < tableLines . length ; ++ i ) {
2022-02-24 08:23:15 +08:00
if ( tableLines [ i ] . trim ( ) === '' ) {
continue ;
}
rawCells . push (
tableLines [ i ]
. split ( '|' )
. map ( function ( s ) {
return s . trim ( ) ;
} )
) ;
}
if ( rawHeaders . length < rawStyles . length ) {
2022-04-28 04:42:24 +08:00
return null ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
return {
rawHeaders : rawHeaders ,
rawStyles : rawStyles ,
rawCells : rawCells
} ;
}
/ * *
*
* @ param { string [ ] } rawHeaders
* @ param { string [ ] } rawStyles
* @ param { string [ ] } rawCells
* @ returns { { headers : * , cells : * } }
* /
function parseTable ( rawHeaders , rawStyles , rawCells ) {
const headers = [ ] ,
cells = [ ] ,
styles = [ ] ,
colCount = rawHeaders . length ,
rowCount = rawCells . length ;
for ( let i = 0 ; i < colCount ; ++ i ) {
styles . push ( parseStyle ( rawStyles [ i ] ) ) ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
for ( let i = 0 ; i < colCount ; ++ i ) {
let header = rawHeaders [ i ] ;
let captureStartEvent = new showdown . Event ( 'makehtml.table.header.onCapture' , rawHeaders [ i ] ) ;
captureStartEvent
. setOutput ( null )
. _setGlobals ( globals )
. _setOptions ( options )
. setRegexp ( null )
. setMatches ( {
_wholeMatch : rawHeaders [ i ] ,
header : rawHeaders [ i ]
} )
. setAttributes ( styles [ i ] ) ;
captureStartEvent = globals . converter . dispatch ( captureStartEvent ) ;
if ( captureStartEvent . output && captureStartEvent . output !== '' ) {
// user provided an otp, so we use it
header = captureStartEvent . output ;
} else {
header = parseHeader ( captureStartEvent . matches . header , styles [ i ] ) ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
let beforeHashEvent = new showdown . Event ( 'makehtml.table.header.onHash' , header ) ;
beforeHashEvent
. setOutput ( header )
. _setGlobals ( globals )
. _setOptions ( options ) ;
beforeHashEvent = globals . converter . dispatch ( beforeHashEvent ) ;
header = beforeHashEvent . output ;
headers . push ( header ) ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
for ( let i = 0 ; i < rowCount ; ++ i ) {
let row = [ ] ;
for ( let ii = 0 ; ii < colCount ; ++ ii ) {
let cell = ( ! showdown . helper . isUndefined ( rawCells [ i ] [ ii ] ) ) ? rawCells [ i ] [ ii ] : '' ,
attributes = ( ! showdown . helper . isUndefined ( styles [ ii ] ) ) ? styles [ ii ] : { } ;
// since we're reusing attributes, we might need to remove the id that we previously set for headers
if ( attributes . id ) {
attributes . classes = [ attributes . id ] + '_col' ;
delete attributes . id ;
}
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
let captureStartEvent = new showdown . Event ( 'makehtml.table.cell.onCapture' , cell ) ;
captureStartEvent
. setOutput ( null )
. _setGlobals ( globals )
. _setOptions ( options )
. setRegexp ( null )
. setMatches ( {
_wholeMatch : cell ,
cell : cell
} )
. setAttributes ( attributes ) ;
captureStartEvent = globals . converter . dispatch ( captureStartEvent ) ;
if ( captureStartEvent . output && captureStartEvent . output !== '' ) {
// user provided an otp, so we use it
cell = captureStartEvent . output ;
} else {
attributes = captureStartEvent . attributes ;
cell = parseCell ( captureStartEvent . matches . cell , attributes ) ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
let beforeHashEvent = new showdown . Event ( 'makehtml.table.cell.onHash' , cell ) ;
beforeHashEvent
. setOutput ( cell )
. _setGlobals ( globals )
. _setOptions ( options ) ;
beforeHashEvent = globals . converter . dispatch ( beforeHashEvent ) ;
cell = beforeHashEvent . output ;
row . push ( cell ) ;
2022-02-24 08:23:15 +08:00
}
cells . push ( row ) ;
}
2022-04-28 04:42:24 +08:00
return { headers : headers , cells : cells } ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
/ * *
* @ param { string } sLine
* @ returns { { } | { style : string } }
* /
function parseStyle ( sLine ) {
if ( /^:[ \t]*-+$/ . test ( sLine ) ) {
return { style : 'text-align:left;' } ;
} else if ( /^-+[ \t]*:[ \t]*$/ . test ( sLine ) ) {
return { style : 'text-align:right;' } ;
} else if ( /^:[ \t]*-+[ \t]*:$/ . test ( sLine ) ) {
return { style : 'text-align:center;' } ;
} else {
return { } ;
}
}
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
/ * *
*
* @ param { string } headerText
* @ param { { id : string } } attributes
* @ returns { string }
* /
function parseHeader ( headerText , attributes ) {
headerText = headerText . trim ( ) ;
headerText = showdown . subParser ( 'makehtml.spanGamut' ) ( headerText , options , globals ) ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
// support both tablesHeaderId and tableHeaderId due to error in documentation so we don't break backwards compatibility
// TODO think about this option!!! and remove backwards compatibility
if ( options . tablesHeaderId || options . tableHeaderId ) {
attributes . id = headerText . replace ( / /g , '_' ) . toLowerCase ( ) ;
}
return '<th' + showdown . helper . _populateAttributes ( attributes ) + '>' + headerText + '</th>\n' ;
}
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
/ * *
*
* @ param { string } cellText
* @ param { { } } attributes
* @ returns { string }
* /
function parseCell ( cellText , attributes ) {
cellText = showdown . subParser ( 'makehtml.spanGamut' ) ( cellText , options , globals ) ;
return '<td' + showdown . helper . _populateAttributes ( attributes ) + '>' + cellText + '</td>\n' ;
}
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makehtml.underline' , function ( text , options , globals ) {
'use strict' ;
if ( ! options . underline ) {
return text ;
}
2022-04-28 04:42:24 +08:00
let startEvent = new showdown . Event ( 'makehtml.underline.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
2022-02-24 08:23:15 +08:00
if ( options . literalMidWordUnderscores ) {
2022-04-28 04:42:24 +08:00
const rgx1 = /\b___(\S[\s\S]*?)___\b/g ;
text = text . replace ( rgx1 , function ( wm , txt ) {
return parse ( rgx1 , wm , txt ) ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
const rgx2 = /\b__(\S[\s\S]*?)__\b/g ;
text = text . replace ( rgx2 , function ( wm , txt ) {
return parse ( rgx2 , wm , txt ) ;
2022-02-24 08:23:15 +08:00
} ) ;
} else {
2022-04-28 04:42:24 +08:00
const rgx3 = /___(\S[\s\S]*?)___/g ;
text = text . replace ( rgx3 , function ( wm , txt ) {
if ( ! ( /\S$/ . test ( txt ) ) ) {
return wm ;
}
return parse ( rgx3 , wm , txt ) ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
const rgx4 = /__(\S[\s\S]*?)__/g ;
text = text . replace ( rgx4 , function ( wm , txt ) {
if ( ! ( /\S$/ . test ( txt ) ) ) {
return wm ;
}
return parse ( rgx4 , wm , txt ) ;
2022-02-24 08:23:15 +08:00
} ) ;
}
// escape remaining underscores to prevent them being parsed by italic and bold
text = text . replace ( /(_)/g , showdown . helper . escapeCharactersCallback ) ;
2022-04-28 04:42:24 +08:00
let afterEvent = new showdown . Event ( 'makehtml.underline.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
function parse ( pattern , wholeMatch , txt ) {
let otp ;
let captureStartEvent = new showdown . Event ( 'makehtml.underline.onCapture' , txt ) ;
captureStartEvent
. setOutput ( null )
. _setGlobals ( globals )
. _setOptions ( options )
. setRegexp ( pattern )
. setMatches ( {
_wholeMatch : wholeMatch ,
strikethrough : txt
} )
. setAttributes ( { } ) ;
captureStartEvent = globals . converter . dispatch ( captureStartEvent ) ;
// if something was passed as output, it takes precedence
// and will be used as output
if ( captureStartEvent . output && captureStartEvent . output !== '' ) {
otp = captureStartEvent . output ;
} else {
otp = '<u' + showdown . helper . _populateAttributes ( captureStartEvent . attributes ) + '>' + txt + '</u>' ;
}
let beforeHashEvent = new showdown . Event ( 'makehtml.underline.onHash' , otp ) ;
beforeHashEvent
. setOutput ( otp )
. _setGlobals ( globals )
. _setOptions ( options ) ;
beforeHashEvent = globals . converter . dispatch ( beforeHashEvent ) ;
return beforeHashEvent . output ;
}
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
/ * *
* Swap back in all the special characters we ' ve hidden .
* /
showdown . subParser ( 'makehtml.unescapeSpecialChars' , function ( text , options , globals ) {
'use strict' ;
2022-04-28 04:42:24 +08:00
let startEvent = new showdown . Event ( 'makehtml.unescapeSpecialChars.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
2022-02-24 08:23:15 +08:00
text = text . replace ( /¨E(\d+)E/g , function ( wholeMatch , m1 ) {
2022-04-28 04:42:24 +08:00
let charCodeToReplace = parseInt ( m1 ) ;
2022-02-24 08:23:15 +08:00
return String . fromCharCode ( charCodeToReplace ) ;
} ) ;
2022-04-28 04:42:24 +08:00
let afterEvent = new showdown . Event ( 'makehtml.unescapeSpecialChars.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
2022-02-24 08:23:15 +08:00
} ) ;
2022-04-28 04:42:24 +08:00
////
// makehtml/unhashHTMLSpans.js
// Copyright (c) 2018 ShowdownJS
//
// Unhash HTML spans
//
// ***Author:***
// - Estêvão Soares dos Santos (Tivie) <https://github.com/tivie>
////
showdown . subParser ( 'makehtml.unhashHTMLSpans' , function ( text , options , globals ) {
'use strict' ;
let startEvent = new showdown . Event ( 'makehtml.unhashHTMLSpans.onStart' , text ) ;
startEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
startEvent = globals . converter . dispatch ( startEvent ) ;
text = startEvent . output ;
for ( let i = 0 ; i < globals . gHtmlSpans . length ; ++ i ) {
let repText = globals . gHtmlSpans [ i ] ,
// limiter to prevent infinite loop (assume 20 as limit for recurse)
limit = 0 ;
while ( /¨C(\d+)C/ . test ( repText ) ) {
let num = repText . match ( /¨C(\d+)C/ ) [ 1 ] ;
repText = repText . replace ( '¨C' + num + 'C' , globals . gHtmlSpans [ num ] ) ;
if ( limit === 10 ) {
console . error ( 'maximum nesting of 20 spans reached!!!' ) ;
break ;
}
++ limit ;
}
text = text . replace ( '¨C' + i + 'C' , repText ) ;
}
2022-03-26 08:31:41 +08:00
2022-04-28 04:42:24 +08:00
let afterEvent = new showdown . Event ( 'makehtml.unhashHTMLSpans.onEnd' , text ) ;
afterEvent
. setOutput ( text )
. _setGlobals ( globals )
. _setOptions ( options ) ;
afterEvent = globals . converter . dispatch ( afterEvent ) ;
return afterEvent . output ;
} ) ;
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makeMarkdown.blockquote' , function ( node , globals ) {
'use strict' ;
var txt = '' ;
if ( node . hasChildNodes ( ) ) {
var children = node . childNodes ,
childrenLength = children . length ;
for ( var i = 0 ; i < childrenLength ; ++ i ) {
var innerTxt = showdown . subParser ( 'makeMarkdown.node' ) ( children [ i ] , globals ) ;
if ( innerTxt === '' ) {
continue ;
}
txt += innerTxt ;
}
}
// cleanup
txt = txt . trim ( ) ;
txt = '> ' + txt . split ( '\n' ) . join ( '\n> ' ) ;
return txt ;
} ) ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makeMarkdown.break' , function ( ) {
'use strict' ;
return ' \n' ;
} ) ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makeMarkdown.codeBlock' , function ( node , globals ) {
'use strict' ;
var lang = node . getAttribute ( 'language' ) ,
num = node . getAttribute ( 'precodenum' ) ;
return '```' + lang + '\n' + globals . preList [ num ] + '\n```' ;
} ) ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makeMarkdown.codeSpan' , function ( node ) {
'use strict' ;
return '`' + node . innerHTML + '`' ;
} ) ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makeMarkdown.emphasis' , function ( node , globals ) {
'use strict' ;
var txt = '' ;
if ( node . hasChildNodes ( ) ) {
txt += '*' ;
var children = node . childNodes ,
childrenLength = children . length ;
for ( var i = 0 ; i < childrenLength ; ++ i ) {
txt += showdown . subParser ( 'makeMarkdown.node' ) ( children [ i ] , globals ) ;
}
txt += '*' ;
}
return txt ;
} ) ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makeMarkdown.header' , function ( node , globals , headerLevel ) {
'use strict' ;
var headerMark = new Array ( headerLevel + 1 ) . join ( '#' ) ,
txt = '' ;
if ( node . hasChildNodes ( ) ) {
txt = headerMark + ' ' ;
var children = node . childNodes ,
childrenLength = children . length ;
for ( var i = 0 ; i < childrenLength ; ++ i ) {
txt += showdown . subParser ( 'makeMarkdown.node' ) ( children [ i ] , globals ) ;
}
}
return txt ;
} ) ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makeMarkdown.hr' , function ( ) {
'use strict' ;
return '---' ;
} ) ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makeMarkdown.image' , function ( node ) {
'use strict' ;
var txt = '' ;
if ( node . hasAttribute ( 'src' ) ) {
txt += '![' + node . getAttribute ( 'alt' ) + '](' ;
txt += '<' + node . getAttribute ( 'src' ) + '>' ;
if ( node . hasAttribute ( 'width' ) && node . hasAttribute ( 'height' ) ) {
txt += ' =' + node . getAttribute ( 'width' ) + 'x' + node . getAttribute ( 'height' ) ;
}
if ( node . hasAttribute ( 'title' ) ) {
txt += ' "' + node . getAttribute ( 'title' ) + '"' ;
}
txt += ')' ;
}
return txt ;
} ) ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makeMarkdown.input' , function ( node , globals ) {
'use strict' ;
var txt = '' ;
if ( node . getAttribute ( 'checked' ) !== null ) {
txt += '[x]' ;
} else {
txt += '[ ]' ;
}
var children = node . childNodes ,
childrenLength = children . length ;
for ( var i = 0 ; i < childrenLength ; ++ i ) {
txt += showdown . subParser ( 'makeMarkdown.node' ) ( children [ i ] , globals ) ;
}
return txt ;
} ) ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makeMarkdown.links' , function ( node , globals ) {
'use strict' ;
var txt = '' ;
if ( node . hasChildNodes ( ) && node . hasAttribute ( 'href' ) ) {
var children = node . childNodes ,
childrenLength = children . length ;
txt = '[' ;
for ( var i = 0 ; i < childrenLength ; ++ i ) {
txt += showdown . subParser ( 'makeMarkdown.node' ) ( children [ i ] , globals ) ;
}
txt += '](' ;
txt += '<' + node . getAttribute ( 'href' ) + '>' ;
if ( node . hasAttribute ( 'title' ) ) {
txt += ' "' + node . getAttribute ( 'title' ) + '"' ;
}
txt += ')' ;
}
return txt ;
} ) ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makeMarkdown.list' , function ( node , globals , type ) {
'use strict' ;
var txt = '' ;
if ( ! node . hasChildNodes ( ) ) {
return '' ;
}
var listItems = node . childNodes ,
listItemsLenght = listItems . length ,
listNum = node . getAttribute ( 'start' ) || 1 ;
for ( var i = 0 ; i < listItemsLenght ; ++ i ) {
if ( typeof listItems [ i ] . tagName === 'undefined' || listItems [ i ] . tagName . toLowerCase ( ) !== 'li' ) {
continue ;
}
// define the bullet to use in list
var bullet = '' ;
if ( type === 'ol' ) {
bullet = listNum . toString ( ) + '. ' ;
} else {
bullet = '- ' ;
}
// parse list item
txt += bullet + showdown . subParser ( 'makeMarkdown.listItem' ) ( listItems [ i ] , globals ) ;
++ listNum ;
}
return txt . trim ( ) ;
} ) ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makeMarkdown.listItem' , function ( node , globals ) {
'use strict' ;
var listItemTxt = '' ;
var children = node . childNodes ,
childrenLenght = children . length ;
for ( var i = 0 ; i < childrenLenght ; ++ i ) {
listItemTxt += showdown . subParser ( 'makeMarkdown.node' ) ( children [ i ] , globals ) ;
}
// if it's only one liner, we need to add a newline at the end
if ( ! /\n$/ . test ( listItemTxt ) ) {
listItemTxt += '\n' ;
} else {
// it's multiparagraph, so we need to indent
listItemTxt = listItemTxt
. split ( '\n' )
. join ( '\n ' )
. replace ( /^ {4}$/gm , '' )
. replace ( /\n\n+/g , '\n\n' ) ;
}
return listItemTxt ;
} ) ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makeMarkdown.node' , function ( node , globals , spansOnly ) {
'use strict' ;
spansOnly = spansOnly || false ;
var txt = '' ;
// edge case of text without wrapper paragraph
if ( node . nodeType === 3 ) {
return showdown . subParser ( 'makeMarkdown.txt' ) ( node , globals ) ;
}
// HTML comment
if ( node . nodeType === 8 ) {
return '<!--' + node . data + '-->\n\n' ;
}
// process only node elements
if ( node . nodeType !== 1 ) {
return '' ;
}
var tagName = node . tagName . toLowerCase ( ) ;
switch ( tagName ) {
//
// BLOCKS
//
case 'h1' :
if ( ! spansOnly ) { txt = showdown . subParser ( 'makeMarkdown.header' ) ( node , globals , 1 ) + '\n\n' ; }
break ;
case 'h2' :
if ( ! spansOnly ) { txt = showdown . subParser ( 'makeMarkdown.header' ) ( node , globals , 2 ) + '\n\n' ; }
break ;
case 'h3' :
if ( ! spansOnly ) { txt = showdown . subParser ( 'makeMarkdown.header' ) ( node , globals , 3 ) + '\n\n' ; }
break ;
case 'h4' :
if ( ! spansOnly ) { txt = showdown . subParser ( 'makeMarkdown.header' ) ( node , globals , 4 ) + '\n\n' ; }
break ;
case 'h5' :
if ( ! spansOnly ) { txt = showdown . subParser ( 'makeMarkdown.header' ) ( node , globals , 5 ) + '\n\n' ; }
break ;
case 'h6' :
if ( ! spansOnly ) { txt = showdown . subParser ( 'makeMarkdown.header' ) ( node , globals , 6 ) + '\n\n' ; }
break ;
case 'p' :
if ( ! spansOnly ) { txt = showdown . subParser ( 'makeMarkdown.paragraph' ) ( node , globals ) + '\n\n' ; }
break ;
case 'blockquote' :
if ( ! spansOnly ) { txt = showdown . subParser ( 'makeMarkdown.blockquote' ) ( node , globals ) + '\n\n' ; }
break ;
case 'hr' :
if ( ! spansOnly ) { txt = showdown . subParser ( 'makeMarkdown.hr' ) ( node , globals ) + '\n\n' ; }
break ;
case 'ol' :
if ( ! spansOnly ) { txt = showdown . subParser ( 'makeMarkdown.list' ) ( node , globals , 'ol' ) + '\n\n' ; }
break ;
case 'ul' :
if ( ! spansOnly ) { txt = showdown . subParser ( 'makeMarkdown.list' ) ( node , globals , 'ul' ) + '\n\n' ; }
break ;
case 'precode' :
if ( ! spansOnly ) { txt = showdown . subParser ( 'makeMarkdown.codeBlock' ) ( node , globals ) + '\n\n' ; }
break ;
case 'pre' :
if ( ! spansOnly ) { txt = showdown . subParser ( 'makeMarkdown.pre' ) ( node , globals ) + '\n\n' ; }
break ;
case 'table' :
if ( ! spansOnly ) { txt = showdown . subParser ( 'makeMarkdown.table' ) ( node , globals ) + '\n\n' ; }
break ;
//
// SPANS
//
case 'code' :
txt = showdown . subParser ( 'makeMarkdown.codeSpan' ) ( node , globals ) ;
break ;
case 'em' :
case 'i' :
txt = showdown . subParser ( 'makeMarkdown.emphasis' ) ( node , globals ) ;
break ;
case 'strong' :
case 'b' :
txt = showdown . subParser ( 'makeMarkdown.strong' ) ( node , globals ) ;
break ;
case 'del' :
txt = showdown . subParser ( 'makeMarkdown.strikethrough' ) ( node , globals ) ;
break ;
case 'a' :
txt = showdown . subParser ( 'makeMarkdown.links' ) ( node , globals ) ;
break ;
case 'img' :
txt = showdown . subParser ( 'makeMarkdown.image' ) ( node , globals ) ;
break ;
case 'br' :
txt = showdown . subParser ( 'makeMarkdown.break' ) ( node , globals ) ;
break ;
case 'input' :
txt = showdown . subParser ( 'makeMarkdown.input' ) ( node , globals ) ;
break ;
default :
txt = node . outerHTML + '\n\n' ;
}
// common normalization
// TODO eventually
return txt ;
} ) ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makeMarkdown.paragraph' , function ( node , globals ) {
'use strict' ;
var txt = '' ;
if ( node . hasChildNodes ( ) ) {
var children = node . childNodes ,
childrenLength = children . length ;
for ( var i = 0 ; i < childrenLength ; ++ i ) {
txt += showdown . subParser ( 'makeMarkdown.node' ) ( children [ i ] , globals ) ;
}
}
// some text normalization
txt = txt . trim ( ) ;
return txt ;
} ) ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makeMarkdown.pre' , function ( node , globals ) {
'use strict' ;
var num = node . getAttribute ( 'prenum' ) ;
return '<pre>' + globals . preList [ num ] + '</pre>' ;
} ) ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makeMarkdown.strikethrough' , function ( node , globals ) {
'use strict' ;
var txt = '' ;
if ( node . hasChildNodes ( ) ) {
txt += '~~' ;
var children = node . childNodes ,
childrenLength = children . length ;
for ( var i = 0 ; i < childrenLength ; ++ i ) {
txt += showdown . subParser ( 'makeMarkdown.node' ) ( children [ i ] , globals ) ;
}
txt += '~~' ;
}
return txt ;
} ) ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makeMarkdown.strong' , function ( node , globals ) {
'use strict' ;
var txt = '' ;
if ( node . hasChildNodes ( ) ) {
txt += '**' ;
var children = node . childNodes ,
childrenLength = children . length ;
for ( var i = 0 ; i < childrenLength ; ++ i ) {
txt += showdown . subParser ( 'makeMarkdown.node' ) ( children [ i ] , globals ) ;
}
txt += '**' ;
}
return txt ;
} ) ;
2022-04-28 04:42:24 +08:00
2022-03-26 08:31:41 +08:00
2022-04-28 04:42:24 +08:00
showdown . subParser ( 'makeMarkdown.table' ,
/ * *
*
* @ param { DocumentFragment } node
* @ param { { } } globals
* @ returns { string }
* /
function ( node , globals ) {
'use strict' ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
var txt = '' ,
tableArray = [ [ ] , [ ] ] ,
headings ,
rows = [ ] ,
colCount ,
i ,
ii ;
/ * *
* @ param { Element } tr
* /
function iterateRow ( tr ) {
var children = tr . childNodes ,
cols = [ ] ;
// we need to iterate by order, since td and th can be used interchangeably and in any order
// we will ignore malformed stuff, comments and floating text.
for ( var i = 0 ; i < children . length ; ++ i ) {
var childName = children [ i ] . nodeName . toUpperCase ( ) ;
if ( childName === 'TD' || childName === 'TH' ) {
cols . push ( children [ i ] ) ;
}
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
return cols ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
// first lets look for <thead>
// we will ignore thead without <tr> children
// also, since markdown doesn't support tables with multiple heading rows, only the first one will be transformed
// the rest will count as regular rows
if ( node . querySelectorAll ( ':scope>thead' ) . length !== 0 && node . querySelectorAll ( ':scope>thead>tr' ) . length !== 0 ) {
var thead = node . querySelectorAll ( ':scope>thead>tr' ) ;
// thead>tr can have td and th children
for ( i = 0 ; i < thead . length ; ++ i ) {
rows . push ( iterateRow ( thead [ i ] ) ) ;
2022-02-24 08:23:15 +08:00
}
}
2022-04-28 04:42:24 +08:00
// now let's look for tbody
// we will ignore tbody without <tr> children
if ( node . querySelectorAll ( ':scope>tbody' ) . length !== 0 && node . querySelectorAll ( ':scope>tbody>tr' ) . length !== 0 ) {
var tbody = node . querySelectorAll ( ':scope>tbody>tr' ) ;
// tbody>tr can have td and th children, although th are not very screen reader friendly
for ( i = 0 ; i < tbody . length ; ++ i ) {
rows . push ( iterateRow ( tbody [ i ] ) ) ;
2022-02-24 08:23:15 +08:00
}
}
2022-04-28 04:42:24 +08:00
// now look for tfoot
if ( node . querySelectorAll ( ':scope>tfoot' ) . length !== 0 && node . querySelectorAll ( ':scope>tfoot>tr' ) . length !== 0 ) {
var tfoot = node . querySelectorAll ( ':scope>tfoot>tr' ) ;
// tfoot>tr can have td and th children, although th are not very screen reader friendly
for ( i = 0 ; i < tfoot . length ; ++ i ) {
rows . push ( iterateRow ( tfoot [ i ] ) ) ;
}
}
// lastly look for naked tr
if ( node . querySelectorAll ( ':scope>tr' ) . length !== 0 ) {
var tr = node . querySelectorAll ( ':scope>tr' ) ;
// tfoot>tr can have td and th children, although th are not very screen reader friendly
for ( i = 0 ; i < tr . length ; ++ i ) {
rows . push ( iterateRow ( tr [ i ] ) ) ;
}
}
// TODO: implement <caption> in tables https://developer.mozilla.org/pt-BR/docs/Web/HTML/Element/caption
// note: <colgroup> is ignored, since they are basically styling
// we need now to account for cases of completely empty tables, like <table></table> or equivalent
if ( rows . length === 0 ) {
// table is empty, return empty text
return txt ;
}
// count the first row. We need it to trim the table (if table rows have inconsistent number of columns)
colCount = rows [ 0 ] . length ;
// let's shift the first row as a heading
headings = rows . shift ( ) ;
for ( i = 0 ; i < headings . length ; ++ i ) {
var headContent = showdown . subParser ( 'makeMarkdown.tableCell' ) ( headings [ i ] , globals ) ,
align = '---' ;
if ( headings [ i ] . hasAttribute ( 'style' ) ) {
var style = headings [ i ] . getAttribute ( 'style' ) . toLowerCase ( ) . replace ( /\s/g , '' ) ;
switch ( style ) {
case 'text-align:left;' :
align = ':---' ;
break ;
case 'text-align:right;' :
align = '---:' ;
break ;
case 'text-align:center;' :
align = ':---:' ;
break ;
2022-02-24 08:23:15 +08:00
}
}
2022-04-28 04:42:24 +08:00
tableArray [ 0 ] [ i ] = headContent . trim ( ) ;
tableArray [ 1 ] [ i ] = align ;
2022-02-24 08:23:15 +08:00
}
2022-04-28 04:42:24 +08:00
// now iterate through the rows and create the pseudo output (not pretty yet)
for ( i = 0 ; i < rows . length ; ++ i ) {
var r = tableArray . push ( [ ] ) - 1 ;
for ( ii = 0 ; ii < colCount ; ++ ii ) {
var cellContent = ' ' ;
if ( typeof rows [ i ] [ ii ] !== 'undefined' ) {
// Note: if rows[i][ii] is undefined, it means the row has fewer elements than the header,
// and empty content will be added
cellContent = showdown . subParser ( 'makeMarkdown.tableCell' ) ( rows [ i ] [ ii ] , globals ) ;
}
tableArray [ r ] . push ( cellContent ) ;
}
}
// now tidy up the output, aligning cells and stuff
var cellSpacesCount = 3 ;
for ( i = 0 ; i < tableArray . length ; ++ i ) {
for ( ii = 0 ; ii < tableArray [ i ] . length ; ++ ii ) {
var strLen = tableArray [ i ] [ ii ] . length ;
if ( strLen > cellSpacesCount ) {
cellSpacesCount = strLen ;
}
}
}
for ( i = 0 ; i < tableArray . length ; ++ i ) {
for ( ii = 0 ; ii < tableArray [ i ] . length ; ++ ii ) {
if ( i === 1 ) {
if ( tableArray [ i ] [ ii ] . slice ( - 1 ) === ':' ) {
tableArray [ i ] [ ii ] = showdown . helper . padEnd ( tableArray [ i ] [ ii ] . slice ( 0 , - 1 ) , cellSpacesCount - 1 , '-' ) + ':' ;
} else {
tableArray [ i ] [ ii ] = showdown . helper . padEnd ( tableArray [ i ] [ ii ] , cellSpacesCount , '-' ) ;
}
} else {
tableArray [ i ] [ ii ] = showdown . helper . padEnd ( tableArray [ i ] [ ii ] , cellSpacesCount ) ;
}
}
txt += '| ' + tableArray [ i ] . join ( ' | ' ) + ' |\n' ;
}
2022-03-26 08:31:41 +08:00
2022-04-28 04:42:24 +08:00
return txt . trim ( ) ;
}
) ;
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makeMarkdown.tableCell' , function ( node , globals ) {
'use strict' ;
var txt = '' ;
if ( ! node . hasChildNodes ( ) ) {
return '' ;
}
var children = node . childNodes ,
childrenLength = children . length ;
for ( var i = 0 ; i < childrenLength ; ++ i ) {
txt += showdown . subParser ( 'makeMarkdown.node' ) ( children [ i ] , globals , true ) ;
}
return txt . trim ( ) ;
} ) ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
showdown . subParser ( 'makeMarkdown.txt' , function ( node ) {
'use strict' ;
var txt = node . nodeValue ;
// multiple spaces are collapsed
txt = txt . replace ( / +/g , ' ' ) ;
// replace the custom ¨NBSP; with a space
txt = txt . replace ( /¨NBSP;/g , ' ' ) ;
// ", <, > and & should replace escaped html entities
txt = showdown . helper . unescapeHTMLEntities ( txt ) ;
// escape markdown magic characters
// emphasis, strong and strikethrough - can appear everywhere
// we also escape pipe (|) because of tables
// and escape ` because of code blocks and spans
txt = txt . replace ( /([*_~|`])/g , '\\$1' ) ;
// escape > because of blockquotes
txt = txt . replace ( /^(\s*)>/g , '\\$1>' ) ;
// hash character, only troublesome at the beginning of a line because of headers
txt = txt . replace ( /^#/gm , '\\#' ) ;
// horizontal rules
txt = txt . replace ( /^(\s*)([-=]{3,})(\s*)$/ , '$1\\$2$3' ) ;
// dot, because of ordered lists, only troublesome at the beginning of a line when preceded by an integer
txt = txt . replace ( /^( {0,3}\d+)\./gm , '$1\\.' ) ;
// +, * and -, at the beginning of a line becomes a list, so we need to escape them also (asterisk was already escaped)
txt = txt . replace ( /^( {0,3})([+-])/gm , '$1\\$2' ) ;
// images and links, ] followed by ( is problematic, so we escape it
txt = txt . replace ( /]([\s]*)\(/g , '\\]$1\\(' ) ;
// reference URIs must also be escaped
txt = txt . replace ( /^ {0,3}\[([\S \t]*?)]:/gm , '\\[$1]:' ) ;
return txt ;
} ) ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
/ * *
* Created by Estevao on 31 - 05 - 2015.
* /
/ * *
* Showdown Converter class
* @ class
* @ param { object } [ converterOptions ]
* @ returns { Converter }
* /
showdown . Converter = function ( converterOptions ) {
'use strict' ;
2022-04-28 04:42:24 +08:00
let
2022-02-24 08:23:15 +08:00
/ * *
* Options used by this converter
* @ private
* @ type { { } }
* /
options = { } ,
/ * *
* Language extensions used by this converter
* @ private
* @ type { Array }
* /
langExtensions = [ ] ,
/ * *
* Output modifiers extensions used by this converter
* @ private
* @ type { Array }
* /
outputModifiers = [ ] ,
/ * *
* Event listeners
* @ private
* @ type { { } }
* /
listeners = { } ,
/ * *
* The flavor set in this converter
* /
setConvFlavor = setFlavor ,
/ * *
* Metadata of the document
* @ type { { parsed : { } , raw : string , format : string } }
* /
metadata = {
parsed : { } ,
raw : '' ,
format : ''
} ;
_constructor ( ) ;
/ * *
* Converter constructor
* @ private
* /
function _constructor ( ) {
converterOptions = converterOptions || { } ;
2022-04-28 04:42:24 +08:00
for ( let gOpt in globalOptions ) {
2022-02-24 08:23:15 +08:00
if ( globalOptions . hasOwnProperty ( gOpt ) ) {
options [ gOpt ] = globalOptions [ gOpt ] ;
}
}
// Merge options
if ( typeof converterOptions === 'object' ) {
2022-04-28 04:42:24 +08:00
for ( let opt in converterOptions ) {
2022-02-24 08:23:15 +08:00
if ( converterOptions . hasOwnProperty ( opt ) ) {
options [ opt ] = converterOptions [ opt ] ;
}
}
} else {
throw Error ( 'Converter expects the passed parameter to be an object, but ' + typeof converterOptions +
' was passed instead.' ) ;
}
if ( options . extensions ) {
showdown . helper . forEach ( options . extensions , _parseExtension ) ;
}
2022-04-28 04:42:24 +08:00
options = showdown . helper . validateOptions ( options ) ;
2022-02-24 08:23:15 +08:00
}
/ * *
* Parse extension
* @ param { * } ext
* @ param { string } [ name = '' ]
* @ private
* /
function _parseExtension ( ext , name ) {
name = name || null ;
// If it's a string, the extension was previously loaded
if ( showdown . helper . isString ( ext ) ) {
ext = showdown . helper . stdExtName ( ext ) ;
name = ext ;
// LEGACY_SUPPORT CODE
if ( showdown . extensions [ ext ] ) {
console . warn ( 'DEPRECATION WARNING: ' + ext + ' is an old extension that uses a deprecated loading method.' +
'Please inform the developer that the extension should be updated!' ) ;
legacyExtensionLoading ( showdown . extensions [ ext ] , ext ) ;
return ;
// END LEGACY SUPPORT CODE
} else if ( ! showdown . helper . isUndefined ( extensions [ ext ] ) ) {
ext = extensions [ ext ] ;
} else {
throw Error ( 'Extension "' + ext + '" could not be loaded. It was either not found or is not a valid extension.' ) ;
}
}
if ( typeof ext === 'function' ) {
ext = ext ( ) ;
}
if ( ! showdown . helper . isArray ( ext ) ) {
ext = [ ext ] ;
}
var validExt = validate ( ext , name ) ;
if ( ! validExt . valid ) {
throw Error ( validExt . error ) ;
}
for ( var i = 0 ; i < ext . length ; ++ i ) {
switch ( ext [ i ] . type ) {
case 'lang' :
langExtensions . push ( ext [ i ] ) ;
break ;
case 'output' :
outputModifiers . push ( ext [ i ] ) ;
break ;
}
if ( ext [ i ] . hasOwnProperty ( 'listeners' ) ) {
for ( var ln in ext [ i ] . listeners ) {
if ( ext [ i ] . listeners . hasOwnProperty ( ln ) ) {
listen ( ln , ext [ i ] . listeners [ ln ] ) ;
}
}
}
}
}
/ * *
* LEGACY _SUPPORT
* @ param { * } ext
* @ param { string } name
* /
function legacyExtensionLoading ( ext , name ) {
if ( typeof ext === 'function' ) {
ext = ext ( new showdown . Converter ( ) ) ;
}
if ( ! showdown . helper . isArray ( ext ) ) {
ext = [ ext ] ;
}
var valid = validate ( ext , name ) ;
if ( ! valid . valid ) {
throw Error ( valid . error ) ;
}
for ( var i = 0 ; i < ext . length ; ++ i ) {
switch ( ext [ i ] . type ) {
case 'lang' :
langExtensions . push ( ext [ i ] ) ;
break ;
case 'output' :
outputModifiers . push ( ext [ i ] ) ;
break ;
default : // should never reach here
throw Error ( 'Extension loader error: Type unrecognized!!!' ) ;
}
}
}
/ * *
* Listen to an event
* @ param { string } name
* @ param { function } callback
* /
function listen ( name , callback ) {
if ( ! showdown . helper . isString ( name ) ) {
throw Error ( 'Invalid argument in converter.listen() method: name must be a string, but ' + typeof name + ' given' ) ;
}
if ( typeof callback !== 'function' ) {
throw Error ( 'Invalid argument in converter.listen() method: callback must be a function, but ' + typeof callback + ' given' ) ;
}
name = name . toLowerCase ( ) ;
if ( ! listeners . hasOwnProperty ( name ) ) {
listeners [ name ] = [ ] ;
}
listeners [ name ] . push ( callback ) ;
}
function rTrimInputText ( text ) {
2022-04-28 04:42:24 +08:00
let rsp = text . match ( /^\s*/ ) [ 0 ] . length ,
2022-02-24 08:23:15 +08:00
rgx = new RegExp ( '^\\s{0,' + rsp + '}' , 'gm' ) ;
return text . replace ( rgx , '' ) ;
}
/ * *
*
2022-04-28 04:42:24 +08:00
* @ param { showdown . Event } event
* @ returns showdown . Event
2022-02-24 08:23:15 +08:00
* /
2022-04-28 04:42:24 +08:00
this . dispatch = function ( event ) {
if ( ! ( event instanceof showdown . Event ) ) {
throw new TypeError ( 'dispatch only accepts showdown.Event objects as param, but ' + typeof event + ' given' ) ;
}
event . converter = this ;
if ( listeners . hasOwnProperty ( event . name ) ) {
for ( let i = 0 ; i < listeners [ event . name ] . length ; ++ i ) {
let listRet = listeners [ event . name ] [ i ] ( event ) ;
if ( showdown . helper . isString ( listRet ) ) {
event . output = listRet ;
event . input = listRet ;
} else if ( listRet instanceof showdown . Event && listRet . name === event . name ) {
event = listRet ;
2022-02-24 08:23:15 +08:00
}
}
}
return event ;
} ;
/ * *
* Listen to an event
* @ param { string } name
* @ param { function } callback
* @ returns { showdown . Converter }
* /
this . listen = function ( name , callback ) {
listen ( name , callback ) ;
return this ;
} ;
/ * *
* Converts a markdown string into HTML string
* @ param { string } text
* @ returns { * }
* /
this . makeHtml = function ( text ) {
//check if text is not falsy
if ( ! text ) {
return text ;
}
var globals = {
gHtmlBlocks : [ ] ,
gHtmlMdBlocks : [ ] ,
gHtmlSpans : [ ] ,
gUrls : { } ,
gTitles : { } ,
gDimensions : { } ,
gListLevel : 0 ,
hashLinkCounts : { } ,
langExtensions : langExtensions ,
outputModifiers : outputModifiers ,
converter : this ,
ghCodeBlocks : [ ] ,
metadata : {
parsed : { } ,
raw : '' ,
format : ''
}
} ;
// This lets us use ¨ trema as an escape char to avoid md5 hashes
// The choice of character is arbitrary; anything that isn't
// magic in Markdown will work.
text = text . replace ( /¨/g , '¨T' ) ;
// Replace $ with ¨D
// RegExp interprets $ as a special character
// when it's in a replacement string
text = text . replace ( /\$/g , '¨D' ) ;
// Standardize line endings
text = text . replace ( /\r\n/g , '\n' ) ; // DOS to Unix
text = text . replace ( /\r/g , '\n' ) ; // Mac to Unix
// Stardardize line spaces
text = text . replace ( /\u00A0/g , ' ' ) ;
if ( options . smartIndentationFix ) {
text = rTrimInputText ( text ) ;
}
// Make sure text begins and ends with a couple of newlines:
text = '\n\n' + text + '\n\n' ;
// detab
text = showdown . subParser ( 'makehtml.detab' ) ( text , options , globals ) ;
/ * *
* Strip any lines consisting only of spaces and tabs .
* This makes subsequent regexs easier to write , because we can
* match consecutive blank lines with /\n+/ instead of something
* contorted like / [ \ t ] * \ n + /
* /
text = text . replace ( /^[ \t]+$/mg , '' ) ;
//run languageExtensions
showdown . helper . forEach ( langExtensions , function ( ext ) {
text = showdown . subParser ( 'makehtml.runExtension' ) ( ext , text , options , globals ) ;
} ) ;
// run the sub parsers
text = showdown . subParser ( 'makehtml.metadata' ) ( text , options , globals ) ;
text = showdown . subParser ( 'makehtml.hashPreCodeTags' ) ( text , options , globals ) ;
2022-04-28 04:42:24 +08:00
text = showdown . subParser ( 'makehtml.githubCodeBlock' ) ( text , options , globals ) ;
2022-02-24 08:23:15 +08:00
text = showdown . subParser ( 'makehtml.hashHTMLBlocks' ) ( text , options , globals ) ;
text = showdown . subParser ( 'makehtml.hashCodeTags' ) ( text , options , globals ) ;
text = showdown . subParser ( 'makehtml.stripLinkDefinitions' ) ( text , options , globals ) ;
text = showdown . subParser ( 'makehtml.blockGamut' ) ( text , options , globals ) ;
text = showdown . subParser ( 'makehtml.unhashHTMLSpans' ) ( text , options , globals ) ;
text = showdown . subParser ( 'makehtml.unescapeSpecialChars' ) ( text , options , globals ) ;
// attacklab: Restore dollar signs
text = text . replace ( /¨D/g , '$$' ) ;
// attacklab: Restore tremas
text = text . replace ( /¨T/g , '¨' ) ;
// render a complete html document instead of a partial if the option is enabled
text = showdown . subParser ( 'makehtml.completeHTMLDocument' ) ( text , options , globals ) ;
// Run output modifiers
showdown . helper . forEach ( outputModifiers , function ( ext ) {
text = showdown . subParser ( 'makehtml.runExtension' ) ( ext , text , options , globals ) ;
} ) ;
// update metadata
metadata = globals . metadata ;
return text ;
} ;
/ * *
* Converts an HTML string into a markdown string
* @ param src
* @ returns { string }
* /
this . makeMarkdown = function ( src ) {
// replace \r\n with \n
src = src . replace ( /\r\n/g , '\n' ) ;
src = src . replace ( /\r/g , '\n' ) ; // old macs
// due to an edge case, we need to find this: > <
// to prevent removing of non silent white spaces
// ex: <em>this is</em> <strong>sparta</strong>
src = src . replace ( />[ \t]+</ , '>¨NBSP;<' ) ;
var doc = showdown . helper . document . createElement ( 'div' ) ;
doc . innerHTML = src ;
var globals = {
preList : substitutePreCodeTags ( doc )
} ;
// remove all newlines and collapse spaces
clean ( doc ) ;
// some stuff, like accidental reference links must now be escaped
// TODO
// doc.innerHTML = doc.innerHTML.replace(/\[[\S\t ]]/);
var nodes = doc . childNodes ,
mdDoc = '' ;
for ( var i = 0 ; i < nodes . length ; i ++ ) {
mdDoc += showdown . subParser ( 'makeMarkdown.node' ) ( nodes [ i ] , globals ) ;
}
function clean ( node ) {
for ( var n = 0 ; n < node . childNodes . length ; ++ n ) {
var child = node . childNodes [ n ] ;
if ( child . nodeType === 3 ) {
if ( ! /\S/ . test ( child . nodeValue ) && ! /^[ ]+$/ . test ( child . nodeValue ) ) {
node . removeChild ( child ) ;
-- n ;
} else {
child . nodeValue = child . nodeValue . split ( '\n' ) . join ( ' ' ) ;
child . nodeValue = child . nodeValue . replace ( /(\s)+/g , '$1' ) ;
}
} else if ( child . nodeType === 1 ) {
clean ( child ) ;
}
}
}
// find all pre tags and replace contents with placeholder
// we need this so that we can remove all indentation from html
// to ease up parsing
function substitutePreCodeTags ( doc ) {
var pres = doc . querySelectorAll ( 'pre' ) ,
presPH = [ ] ;
for ( var i = 0 ; i < pres . length ; ++ i ) {
if ( pres [ i ] . childElementCount === 1 && pres [ i ] . firstChild . tagName . toLowerCase ( ) === 'code' ) {
var content = pres [ i ] . firstChild . innerHTML . trim ( ) ,
language = pres [ i ] . firstChild . getAttribute ( 'data-language' ) || '' ;
// if data-language attribute is not defined, then we look for class language-*
if ( language === '' ) {
var classes = pres [ i ] . firstChild . className . split ( ' ' ) ;
for ( var c = 0 ; c < classes . length ; ++ c ) {
var matches = classes [ c ] . match ( /^language-(.+)$/ ) ;
if ( matches !== null ) {
language = matches [ 1 ] ;
break ;
}
}
}
// unescape html entities in content
content = showdown . helper . unescapeHTMLEntities ( content ) ;
presPH . push ( content ) ;
pres [ i ] . outerHTML = '<precode language="' + language + '" precodenum="' + i . toString ( ) + '"></precode>' ;
} else {
presPH . push ( pres [ i ] . innerHTML ) ;
pres [ i ] . innerHTML = '' ;
pres [ i ] . setAttribute ( 'prenum' , i . toString ( ) ) ;
}
}
return presPH ;
}
return mdDoc ;
} ;
/ * *
* Set an option of this Converter instance
* @ param { string } key
* @ param { * } value
* /
this . setOption = function ( key , value ) {
options [ key ] = value ;
} ;
/ * *
* Get the option of this Converter instance
* @ param { string } key
* @ returns { * }
* /
this . getOption = function ( key ) {
return options [ key ] ;
} ;
/ * *
* Get the options of this Converter instance
* @ returns { { } }
* /
this . getOptions = function ( ) {
return options ;
} ;
/ * *
* Add extension to THIS converter
* @ param { { } } extension
* @ param { string } [ name = null ]
* /
this . addExtension = function ( extension , name ) {
name = name || null ;
_parseExtension ( extension , name ) ;
} ;
/ * *
* Use a global registered extension with THIS converter
* @ param { string } extensionName Name of the previously registered extension
* /
this . useExtension = function ( extensionName ) {
_parseExtension ( extensionName ) ;
} ;
/ * *
* Set the flavor THIS converter should use
* @ param { string } name
* /
this . setFlavor = function ( name ) {
if ( ! flavor . hasOwnProperty ( name ) ) {
throw Error ( name + ' flavor was not found' ) ;
}
var preset = flavor [ name ] ;
setConvFlavor = name ;
for ( var option in preset ) {
if ( preset . hasOwnProperty ( option ) ) {
options [ option ] = preset [ option ] ;
}
}
} ;
/ * *
* Get the currently set flavor of this converter
* @ returns { string }
* /
this . getFlavor = function ( ) {
return setConvFlavor ;
} ;
/ * *
* Remove an extension from THIS converter .
* Note : This is a costly operation . It ' s better to initialize a new converter
* and specify the extensions you wish to use
* @ param { Array } extension
* /
this . removeExtension = function ( extension ) {
if ( ! showdown . helper . isArray ( extension ) ) {
extension = [ extension ] ;
}
for ( var a = 0 ; a < extension . length ; ++ a ) {
var ext = extension [ a ] ;
for ( var i = 0 ; i < langExtensions . length ; ++ i ) {
if ( langExtensions [ i ] === ext ) {
langExtensions . splice ( i , 1 ) ;
}
}
for ( var ii = 0 ; ii < outputModifiers . length ; ++ ii ) {
if ( outputModifiers [ ii ] === ext ) {
outputModifiers . splice ( ii , 1 ) ;
}
}
}
} ;
/ * *
* Get all extension of THIS converter
* @ returns { { language : Array , output : Array } }
* /
this . getAllExtensions = function ( ) {
return {
language : langExtensions ,
output : outputModifiers
} ;
} ;
/ * *
* Get the metadata of the previously parsed document
* @ param raw
* @ returns { string | { } }
* /
this . getMetadata = function ( raw ) {
if ( raw ) {
return metadata . raw ;
} else {
return metadata . parsed ;
}
} ;
/ * *
* Get the metadata format of the previously parsed document
* @ returns { string }
* /
this . getMetadataFormat = function ( ) {
return metadata . format ;
} ;
/ * *
* Private : set a single key , value metadata pair
* @ param { string } key
* @ param { string } value
* /
this . _setMetadataPair = function ( key , value ) {
metadata . parsed [ key ] = value ;
} ;
/ * *
* Private : set metadata format
* @ param { string } format
* /
this . _setMetadataFormat = function ( format ) {
metadata . format = format ;
} ;
/ * *
* Private : set metadata raw text
* @ param { string } raw
* /
this . _setMetadataRaw = function ( raw ) {
metadata . raw = raw ;
} ;
} ;
2022-04-28 04:42:24 +08:00
2022-02-24 08:23:15 +08:00
var root = this ;
// AMD Loader
if ( typeof define === 'function' && define . amd ) {
define ( function ( ) {
'use strict' ;
return showdown ;
} ) ;
// CommonJS/nodeJS Loader
} else if ( typeof module !== 'undefined' && module . exports ) {
module . exports = showdown ;
// Regular Browser loader
} else {
root . showdown = showdown ;
}
2022-04-28 04:42:24 +08:00
} ) . call ( this ) ;
2022-02-24 08:23:15 +08:00
2022-04-28 04:42:24 +08:00
//# sourceMappingURL=showdown.js.map