showdown

Showdown.js 是一个基于 JavaScript 开发环境的 MarkDown 语法解释工具,能够支持服务端 Node.js 和客户端各大主流浏览器。

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.cn-greasyfork.org/scripts/488179/1413254/showdown.js

  1. /*! showdown v 2.1.0 - 21-04-2022 */
  2. // @ts-nocheck
  3. (function (global, factory) {
  4. if (typeof exports === "object" && typeof module !== "undefined") {
  5. module.exports = factory();
  6. } else {
  7. global = typeof globalThis !== "undefined" ? globalThis : global || self;
  8. global.showdown = factory();
  9. }
  10. })(typeof window !== "undefined" ? window : this, function () {
  11. /**
  12. * Created by Tivie on 13-07-2015.
  13. */
  14.  
  15. function getDefaultOpts(simple) {
  16. "use strict";
  17.  
  18. var defaultOptions = {
  19. omitExtraWLInCodeBlocks: {
  20. defaultValue: false,
  21. describe: "Omit the default extra whiteline added to code blocks",
  22. type: "boolean",
  23. },
  24. noHeaderId: {
  25. defaultValue: false,
  26. describe: "Turn on/off generated header id",
  27. type: "boolean",
  28. },
  29. prefixHeaderId: {
  30. defaultValue: false,
  31. describe:
  32. "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",
  33. type: "string",
  34. },
  35. rawPrefixHeaderId: {
  36. defaultValue: false,
  37. describe:
  38. '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)',
  39. type: "boolean",
  40. },
  41. ghCompatibleHeaderId: {
  42. defaultValue: false,
  43. describe:
  44. "Generate header ids compatible with github style (spaces are replaced with dashes, a bunch of non alphanumeric chars are removed)",
  45. type: "boolean",
  46. },
  47. rawHeaderId: {
  48. defaultValue: false,
  49. describe:
  50. "Remove only spaces, ' and \" from generated header ids (including prefixes), replacing them with dashes (-). WARNING: This might result in malformed ids",
  51. type: "boolean",
  52. },
  53. headerLevelStart: {
  54. defaultValue: false,
  55. describe: "The header blocks level start",
  56. type: "integer",
  57. },
  58. parseImgDimensions: {
  59. defaultValue: false,
  60. describe: "Turn on/off image dimension parsing",
  61. type: "boolean",
  62. },
  63. simplifiedAutoLink: {
  64. defaultValue: false,
  65. describe: "Turn on/off GFM autolink style",
  66. type: "boolean",
  67. },
  68. excludeTrailingPunctuationFromURLs: {
  69. defaultValue: false,
  70. describe:
  71. "Excludes trailing punctuation from links generated with autoLinking",
  72. type: "boolean",
  73. },
  74. literalMidWordUnderscores: {
  75. defaultValue: false,
  76. describe: "Parse midword underscores as literal underscores",
  77. type: "boolean",
  78. },
  79. literalMidWordAsterisks: {
  80. defaultValue: false,
  81. describe: "Parse midword asterisks as literal asterisks",
  82. type: "boolean",
  83. },
  84. strikethrough: {
  85. defaultValue: false,
  86. describe: "Turn on/off strikethrough support",
  87. type: "boolean",
  88. },
  89. tables: {
  90. defaultValue: false,
  91. describe: "Turn on/off tables support",
  92. type: "boolean",
  93. },
  94. tablesHeaderId: {
  95. defaultValue: false,
  96. describe: "Add an id to table headers",
  97. type: "boolean",
  98. },
  99. ghCodeBlocks: {
  100. defaultValue: true,
  101. describe: "Turn on/off GFM fenced code blocks support",
  102. type: "boolean",
  103. },
  104. tasklists: {
  105. defaultValue: false,
  106. describe: "Turn on/off GFM tasklist support",
  107. type: "boolean",
  108. },
  109. smoothLivePreview: {
  110. defaultValue: false,
  111. describe:
  112. "Prevents weird effects in live previews due to incomplete input",
  113. type: "boolean",
  114. },
  115. smartIndentationFix: {
  116. defaultValue: false,
  117. describe: "Tries to smartly fix indentation in es6 strings",
  118. type: "boolean",
  119. },
  120. disableForced4SpacesIndentedSublists: {
  121. defaultValue: false,
  122. describe:
  123. "Disables the requirement of indenting nested sublists by 4 spaces",
  124. type: "boolean",
  125. },
  126. simpleLineBreaks: {
  127. defaultValue: false,
  128. describe: "Parses simple line breaks as <br> (GFM Style)",
  129. type: "boolean",
  130. },
  131. requireSpaceBeforeHeadingText: {
  132. defaultValue: false,
  133. describe:
  134. "Makes adding a space between `#` and the header text mandatory (GFM Style)",
  135. type: "boolean",
  136. },
  137. ghMentions: {
  138. defaultValue: false,
  139. describe: "Enables github @mentions",
  140. type: "boolean",
  141. },
  142. ghMentionsLink: {
  143. defaultValue: "https://github.com/{u}",
  144. describe:
  145. "Changes the link generated by @mentions. Only applies if ghMentions option is enabled.",
  146. type: "string",
  147. },
  148. encodeEmails: {
  149. defaultValue: true,
  150. describe:
  151. "Encode e-mail addresses through the use of Character Entities, transforming ASCII e-mail addresses into its equivalent decimal entities",
  152. type: "boolean",
  153. },
  154. openLinksInNewWindow: {
  155. defaultValue: false,
  156. describe: "Open all links in new windows",
  157. type: "boolean",
  158. },
  159. backslashEscapesHTMLTags: {
  160. defaultValue: false,
  161. describe: "Support for HTML Tag escaping. ex: <div>foo</div>",
  162. type: "boolean",
  163. },
  164. emoji: {
  165. defaultValue: false,
  166. describe: "Enable emoji support. Ex: `this is a :smile: emoji`",
  167. type: "boolean",
  168. },
  169. underline: {
  170. defaultValue: false,
  171. describe:
  172. "Enable support for underline. Syntax is double or triple underscores: `__underline word__`. With this option enabled, underscores no longer parses into `<em>` and `<strong>`",
  173. type: "boolean",
  174. },
  175. ellipsis: {
  176. defaultValue: true,
  177. describe: "Replaces three dots with the ellipsis unicode character",
  178. type: "boolean",
  179. },
  180. completeHTMLDocument: {
  181. defaultValue: false,
  182. describe:
  183. "Outputs a complete html document, including `<html>`, `<head>` and `<body>` tags",
  184. type: "boolean",
  185. },
  186. metadata: {
  187. defaultValue: false,
  188. describe:
  189. "Enable support for document metadata (defined at the top of the document between `«««` and `»»»` or between `---` and `---`).",
  190. type: "boolean",
  191. },
  192. splitAdjacentBlockquotes: {
  193. defaultValue: false,
  194. describe: "Split adjacent blockquote blocks",
  195. type: "boolean",
  196. },
  197. };
  198. if (simple === false) {
  199. return JSON.parse(JSON.stringify(defaultOptions));
  200. }
  201. var ret = {};
  202. for (var opt in defaultOptions) {
  203. if (defaultOptions.hasOwnProperty(opt)) {
  204. ret[opt] = defaultOptions[opt].defaultValue;
  205. }
  206. }
  207. return ret;
  208. }
  209.  
  210. function allOptionsOn() {
  211. "use strict";
  212. var options = getDefaultOpts(true),
  213. ret = {};
  214. for (var opt in options) {
  215. if (options.hasOwnProperty(opt)) {
  216. ret[opt] = true;
  217. }
  218. }
  219. return ret;
  220. }
  221.  
  222. /**
  223. * Created by Tivie on 06-01-2015.
  224. */
  225.  
  226. // Private properties
  227. var showdown = {},
  228. parsers = {},
  229. extensions = {},
  230. globalOptions = getDefaultOpts(true),
  231. setFlavor = "vanilla",
  232. flavor = {
  233. github: {
  234. omitExtraWLInCodeBlocks: true,
  235. simplifiedAutoLink: true,
  236. excludeTrailingPunctuationFromURLs: true,
  237. literalMidWordUnderscores: true,
  238. strikethrough: true,
  239. tables: true,
  240. tablesHeaderId: true,
  241. ghCodeBlocks: true,
  242. tasklists: true,
  243. disableForced4SpacesIndentedSublists: true,
  244. simpleLineBreaks: true,
  245. requireSpaceBeforeHeadingText: true,
  246. ghCompatibleHeaderId: true,
  247. ghMentions: true,
  248. backslashEscapesHTMLTags: true,
  249. emoji: true,
  250. splitAdjacentBlockquotes: true,
  251. },
  252. original: {
  253. noHeaderId: true,
  254. ghCodeBlocks: false,
  255. },
  256. ghost: {
  257. omitExtraWLInCodeBlocks: true,
  258. parseImgDimensions: true,
  259. simplifiedAutoLink: true,
  260. excludeTrailingPunctuationFromURLs: true,
  261. literalMidWordUnderscores: true,
  262. strikethrough: true,
  263. tables: true,
  264. tablesHeaderId: true,
  265. ghCodeBlocks: true,
  266. tasklists: true,
  267. smoothLivePreview: true,
  268. simpleLineBreaks: true,
  269. requireSpaceBeforeHeadingText: true,
  270. ghMentions: false,
  271. encodeEmails: true,
  272. },
  273. vanilla: getDefaultOpts(true),
  274. allOn: allOptionsOn(),
  275. };
  276.  
  277. /**
  278. * helper namespace
  279. * @type {{}}
  280. */
  281. showdown.helper = {};
  282.  
  283. /**
  284. * TODO LEGACY SUPPORT CODE
  285. * @type {{}}
  286. */
  287. showdown.extensions = {};
  288.  
  289. /**
  290. * Set a global option
  291. * @static
  292. * @param {string} key
  293. * @param {*} value
  294. * @returns {showdown}
  295. */
  296. showdown.setOption = function (key, value) {
  297. "use strict";
  298. globalOptions[key] = value;
  299. return this;
  300. };
  301.  
  302. /**
  303. * Get a global option
  304. * @static
  305. * @param {string} key
  306. * @returns {*}
  307. */
  308. showdown.getOption = function (key) {
  309. "use strict";
  310. return globalOptions[key];
  311. };
  312.  
  313. /**
  314. * Get the global options
  315. * @static
  316. * @returns {{}}
  317. */
  318. showdown.getOptions = function () {
  319. "use strict";
  320. return globalOptions;
  321. };
  322.  
  323. /**
  324. * Reset global options to the default values
  325. * @static
  326. */
  327. showdown.resetOptions = function () {
  328. "use strict";
  329. globalOptions = getDefaultOpts(true);
  330. };
  331.  
  332. /**
  333. * Set the flavor showdown should use as default
  334. * @param {string} name
  335. */
  336. showdown.setFlavor = function (name) {
  337. "use strict";
  338. if (!flavor.hasOwnProperty(name)) {
  339. throw Error(name + " flavor was not found");
  340. }
  341. showdown.resetOptions();
  342. var preset = flavor[name];
  343. setFlavor = name;
  344. for (var option in preset) {
  345. if (preset.hasOwnProperty(option)) {
  346. globalOptions[option] = preset[option];
  347. }
  348. }
  349. };
  350.  
  351. /**
  352. * Get the currently set flavor
  353. * @returns {string}
  354. */
  355. showdown.getFlavor = function () {
  356. "use strict";
  357. return setFlavor;
  358. };
  359.  
  360. /**
  361. * Get the options of a specified flavor. Returns undefined if the flavor was not found
  362. * @param {string} name Name of the flavor
  363. * @returns {{}|undefined}
  364. */
  365. showdown.getFlavorOptions = function (name) {
  366. "use strict";
  367. if (flavor.hasOwnProperty(name)) {
  368. return flavor[name];
  369. }
  370. };
  371.  
  372. /**
  373. * Get the default options
  374. * @static
  375. * @param {boolean} [simple=true]
  376. * @returns {{}}
  377. */
  378. showdown.getDefaultOptions = function (simple) {
  379. "use strict";
  380. return getDefaultOpts(simple);
  381. };
  382.  
  383. /**
  384. * Get or set a subParser
  385. *
  386. * subParser(name) - Get a registered subParser
  387. * subParser(name, func) - Register a subParser
  388. * @static
  389. * @param {string} name
  390. * @param {function} [func]
  391. * @returns {*}
  392. */
  393. showdown.subParser = function (name, func) {
  394. "use strict";
  395. if (showdown.helper.isString(name)) {
  396. if (typeof func !== "undefined") {
  397. parsers[name] = func;
  398. } else {
  399. if (parsers.hasOwnProperty(name)) {
  400. return parsers[name];
  401. } else {
  402. throw Error("SubParser named " + name + " not registered!");
  403. }
  404. }
  405. }
  406. };
  407.  
  408. /**
  409. * Gets or registers an extension
  410. * @static
  411. * @param {string} name
  412. * @param {object|object[]|function=} ext
  413. * @returns {*}
  414. */
  415. showdown.extension = function (name, ext) {
  416. "use strict";
  417.  
  418. if (!showdown.helper.isString(name)) {
  419. throw Error("Extension 'name' must be a string");
  420. }
  421.  
  422. name = showdown.helper.stdExtName(name);
  423.  
  424. // Getter
  425. if (showdown.helper.isUndefined(ext)) {
  426. if (!extensions.hasOwnProperty(name)) {
  427. throw Error("Extension named " + name + " is not registered!");
  428. }
  429. return extensions[name];
  430.  
  431. // Setter
  432. } else {
  433. // Expand extension if it's wrapped in a function
  434. if (typeof ext === "function") {
  435. ext = ext();
  436. }
  437.  
  438. // Ensure extension is an array
  439. if (!showdown.helper.isArray(ext)) {
  440. ext = [ext];
  441. }
  442.  
  443. var validExtension = validate(ext, name);
  444.  
  445. if (validExtension.valid) {
  446. extensions[name] = ext;
  447. } else {
  448. throw Error(validExtension.error);
  449. }
  450. }
  451. };
  452.  
  453. /**
  454. * Gets all extensions registered
  455. * @returns {{}}
  456. */
  457. showdown.getAllExtensions = function () {
  458. "use strict";
  459. return extensions;
  460. };
  461.  
  462. /**
  463. * Remove an extension
  464. * @param {string} name
  465. */
  466. showdown.removeExtension = function (name) {
  467. "use strict";
  468. delete extensions[name];
  469. };
  470.  
  471. /**
  472. * Removes all extensions
  473. */
  474. showdown.resetExtensions = function () {
  475. "use strict";
  476. extensions = {};
  477. };
  478.  
  479. /**
  480. * Validate extension
  481. * @param {array} extension
  482. * @param {string} name
  483. * @returns {{valid: boolean, error: string}}
  484. */
  485. function validate(extension, name) {
  486. "use strict";
  487.  
  488. var errMsg = name
  489. ? "Error in " + name + " extension->"
  490. : "Error in unnamed extension",
  491. ret = {
  492. valid: true,
  493. error: "",
  494. };
  495.  
  496. if (!showdown.helper.isArray(extension)) {
  497. extension = [extension];
  498. }
  499.  
  500. for (var i = 0; i < extension.length; ++i) {
  501. var baseMsg = errMsg + " sub-extension " + i + ": ",
  502. ext = extension[i];
  503. if (typeof ext !== "object") {
  504. ret.valid = false;
  505. ret.error = baseMsg + "must be an object, but " + typeof ext + " given";
  506. return ret;
  507. }
  508.  
  509. if (!showdown.helper.isString(ext.type)) {
  510. ret.valid = false;
  511. ret.error =
  512. baseMsg +
  513. 'property "type" must be a string, but ' +
  514. typeof ext.type +
  515. " given";
  516. return ret;
  517. }
  518.  
  519. var type = (ext.type = ext.type.toLowerCase());
  520.  
  521. // normalize extension type
  522. if (type === "language") {
  523. type = ext.type = "lang";
  524. }
  525.  
  526. if (type === "html") {
  527. type = ext.type = "output";
  528. }
  529.  
  530. if (type !== "lang" && type !== "output" && type !== "listener") {
  531. ret.valid = false;
  532. ret.error =
  533. baseMsg +
  534. "type " +
  535. type +
  536. ' is not recognized. Valid values: "lang/language", "output/html" or "listener"';
  537. return ret;
  538. }
  539.  
  540. if (type === "listener") {
  541. if (showdown.helper.isUndefined(ext.listeners)) {
  542. ret.valid = false;
  543. ret.error =
  544. baseMsg +
  545. '. Extensions of type "listener" must have a property called "listeners"';
  546. return ret;
  547. }
  548. } else {
  549. if (
  550. showdown.helper.isUndefined(ext.filter) &&
  551. showdown.helper.isUndefined(ext.regex)
  552. ) {
  553. ret.valid = false;
  554. ret.error =
  555. baseMsg +
  556. type +
  557. ' extensions must define either a "regex" property or a "filter" method';
  558. return ret;
  559. }
  560. }
  561.  
  562. if (ext.listeners) {
  563. if (typeof ext.listeners !== "object") {
  564. ret.valid = false;
  565. ret.error =
  566. baseMsg +
  567. '"listeners" property must be an object but ' +
  568. typeof ext.listeners +
  569. " given";
  570. return ret;
  571. }
  572. for (var ln in ext.listeners) {
  573. if (ext.listeners.hasOwnProperty(ln)) {
  574. if (typeof ext.listeners[ln] !== "function") {
  575. ret.valid = false;
  576. ret.error =
  577. baseMsg +
  578. '"listeners" property must be an hash of [event name]: [callback]. listeners.' +
  579. ln +
  580. " must be a function but " +
  581. typeof ext.listeners[ln] +
  582. " given";
  583. return ret;
  584. }
  585. }
  586. }
  587. }
  588.  
  589. if (ext.filter) {
  590. if (typeof ext.filter !== "function") {
  591. ret.valid = false;
  592. ret.error =
  593. baseMsg +
  594. '"filter" must be a function, but ' +
  595. typeof ext.filter +
  596. " given";
  597. return ret;
  598. }
  599. } else if (ext.regex) {
  600. if (showdown.helper.isString(ext.regex)) {
  601. ext.regex = new RegExp(ext.regex, "g");
  602. }
  603. if (!(ext.regex instanceof RegExp)) {
  604. ret.valid = false;
  605. ret.error =
  606. baseMsg +
  607. '"regex" property must either be a string or a RegExp object, but ' +
  608. typeof ext.regex +
  609. " given";
  610. return ret;
  611. }
  612. if (showdown.helper.isUndefined(ext.replace)) {
  613. ret.valid = false;
  614. ret.error =
  615. baseMsg +
  616. '"regex" extensions must implement a replace string or function';
  617. return ret;
  618. }
  619. }
  620. }
  621. return ret;
  622. }
  623.  
  624. /**
  625. * Validate extension
  626. * @param {object} ext
  627. * @returns {boolean}
  628. */
  629. showdown.validateExtension = function (ext) {
  630. "use strict";
  631.  
  632. var validateExtension = validate(ext, null);
  633. if (!validateExtension.valid) {
  634. console.warn(validateExtension.error);
  635. return false;
  636. }
  637. return true;
  638. };
  639.  
  640. /**
  641. * showdownjs helper functions
  642. */
  643.  
  644. if (!showdown.hasOwnProperty("helper")) {
  645. showdown.helper = {};
  646. }
  647.  
  648. /**
  649. * Check if var is string
  650. * @static
  651. * @param {string} a
  652. * @returns {boolean}
  653. */
  654. showdown.helper.isString = function (a) {
  655. "use strict";
  656. return typeof a === "string" || a instanceof String;
  657. };
  658.  
  659. /**
  660. * Check if var is a function
  661. * @static
  662. * @param {*} a
  663. * @returns {boolean}
  664. */
  665. showdown.helper.isFunction = function (a) {
  666. "use strict";
  667. var getType = {};
  668. return a && getType.toString.call(a) === "[object Function]";
  669. };
  670.  
  671. /**
  672. * isArray helper function
  673. * @static
  674. * @param {*} a
  675. * @returns {boolean}
  676. */
  677. showdown.helper.isArray = function (a) {
  678. "use strict";
  679. return Array.isArray(a);
  680. };
  681.  
  682. /**
  683. * Check if value is undefined
  684. * @static
  685. * @param {*} value The value to check.
  686. * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.
  687. */
  688. showdown.helper.isUndefined = function (value) {
  689. "use strict";
  690. return typeof value === "undefined";
  691. };
  692.  
  693. /**
  694. * ForEach helper function
  695. * Iterates over Arrays and Objects (own properties only)
  696. * @static
  697. * @param {*} obj
  698. * @param {function} callback Accepts 3 params: 1. value, 2. key, 3. the original array/object
  699. */
  700. showdown.helper.forEach = function (obj, callback) {
  701. "use strict";
  702. // check if obj is defined
  703. if (showdown.helper.isUndefined(obj)) {
  704. throw new Error("obj param is required");
  705. }
  706.  
  707. if (showdown.helper.isUndefined(callback)) {
  708. throw new Error("callback param is required");
  709. }
  710.  
  711. if (!showdown.helper.isFunction(callback)) {
  712. throw new Error("callback param must be a function/closure");
  713. }
  714.  
  715. if (typeof obj.forEach === "function") {
  716. obj.forEach(callback);
  717. } else if (showdown.helper.isArray(obj)) {
  718. for (var i = 0; i < obj.length; i++) {
  719. callback(obj[i], i, obj);
  720. }
  721. } else if (typeof obj === "object") {
  722. for (var prop in obj) {
  723. if (obj.hasOwnProperty(prop)) {
  724. callback(obj[prop], prop, obj);
  725. }
  726. }
  727. } else {
  728. throw new Error("obj does not seem to be an array or an iterable object");
  729. }
  730. };
  731.  
  732. /**
  733. * Standardidize extension name
  734. * @static
  735. * @param {string} s extension name
  736. * @returns {string}
  737. */
  738. showdown.helper.stdExtName = function (s) {
  739. "use strict";
  740. return s
  741. .replace(/[_?*+\/\\.^-]/g, "")
  742. .replace(/\s/g, "")
  743. .toLowerCase();
  744. };
  745.  
  746. function escapeCharactersCallback(wholeMatch, m1) {
  747. "use strict";
  748. var charCodeToEscape = m1.charCodeAt(0);
  749. return "¨E" + charCodeToEscape + "E";
  750. }
  751.  
  752. /**
  753. * Callback used to escape characters when passing through String.replace
  754. * @static
  755. * @param {string} wholeMatch
  756. * @param {string} m1
  757. * @returns {string}
  758. */
  759. showdown.helper.escapeCharactersCallback = escapeCharactersCallback;
  760.  
  761. /**
  762. * Escape characters in a string
  763. * @static
  764. * @param {string} text
  765. * @param {string} charsToEscape
  766. * @param {boolean} afterBackslash
  767. * @returns {XML|string|void|*}
  768. */
  769. showdown.helper.escapeCharacters = function (
  770. text,
  771. charsToEscape,
  772. afterBackslash
  773. ) {
  774. "use strict";
  775. // First we have to escape the escape characters so that
  776. // we can build a character class out of them
  777. var regexString =
  778. "([" + charsToEscape.replace(/([\[\]\\])/g, "\\$1") + "])";
  779.  
  780. if (afterBackslash) {
  781. regexString = "\\\\" + regexString;
  782. }
  783.  
  784. var regex = new RegExp(regexString, "g");
  785. text = text.replace(regex, escapeCharactersCallback);
  786.  
  787. return text;
  788. };
  789.  
  790. /**
  791. * Unescape HTML entities
  792. * @param txt
  793. * @returns {string}
  794. */
  795. showdown.helper.unescapeHTMLEntities = function (txt) {
  796. "use strict";
  797.  
  798. return txt
  799. .replace(/&quot;/g, '"')
  800. .replace(/&lt;/g, "<")
  801. .replace(/&gt;/g, ">")
  802. .replace(/&amp;/g, "&");
  803. };
  804.  
  805. var rgxFindMatchPos = function (str, left, right, flags) {
  806. "use strict";
  807. var f = flags || "",
  808. g = f.indexOf("g") > -1,
  809. x = new RegExp(left + "|" + right, "g" + f.replace(/g/g, "")),
  810. l = new RegExp(left, f.replace(/g/g, "")),
  811. pos = [],
  812. t,
  813. s,
  814. m,
  815. start,
  816. end;
  817.  
  818. do {
  819. t = 0;
  820. while ((m = x.exec(str))) {
  821. if (l.test(m[0])) {
  822. if (!t++) {
  823. s = x.lastIndex;
  824. start = s - m[0].length;
  825. }
  826. } else if (t) {
  827. if (!--t) {
  828. end = m.index + m[0].length;
  829. var obj = {
  830. left: { start: start, end: s },
  831. match: { start: s, end: m.index },
  832. right: { start: m.index, end: end },
  833. wholeMatch: { start: start, end: end },
  834. };
  835. pos.push(obj);
  836. if (!g) {
  837. return pos;
  838. }
  839. }
  840. }
  841. }
  842. } while (t && (x.lastIndex = s));
  843.  
  844. return pos;
  845. };
  846.  
  847. /**
  848. * matchRecursiveRegExp
  849. *
  850. * (c) 2007 Steven Levithan <stevenlevithan.com>
  851. * MIT License
  852. *
  853. * Accepts a string to search, a left and right format delimiter
  854. * as regex patterns, and optional regex flags. Returns an array
  855. * of matches, allowing nested instances of left/right delimiters.
  856. * Use the "g" flag to return all matches, otherwise only the
  857. * first is returned. Be careful to ensure that the left and
  858. * right format delimiters produce mutually exclusive matches.
  859. * Backreferences are not supported within the right delimiter
  860. * due to how it is internally combined with the left delimiter.
  861. * When matching strings whose format delimiters are unbalanced
  862. * to the left or right, the output is intentionally as a
  863. * conventional regex library with recursion support would
  864. * produce, e.g. "<<x>" and "<x>>" both produce ["x"] when using
  865. * "<" and ">" as the delimiters (both strings contain a single,
  866. * balanced instance of "<x>").
  867. *
  868. * examples:
  869. * matchRecursiveRegExp("test", "\\(", "\\)")
  870. * returns: []
  871. * matchRecursiveRegExp("<t<<e>><s>>t<>", "<", ">", "g")
  872. * returns: ["t<<e>><s>", ""]
  873. * matchRecursiveRegExp("<div id=\"x\">test</div>", "<div\\b[^>]*>", "</div>", "gi")
  874. * returns: ["test"]
  875. */
  876. showdown.helper.matchRecursiveRegExp = function (str, left, right, flags) {
  877. "use strict";
  878.  
  879. var matchPos = rgxFindMatchPos(str, left, right, flags),
  880. results = [];
  881.  
  882. for (var i = 0; i < matchPos.length; ++i) {
  883. results.push([
  884. str.slice(matchPos[i].wholeMatch.start, matchPos[i].wholeMatch.end),
  885. str.slice(matchPos[i].match.start, matchPos[i].match.end),
  886. str.slice(matchPos[i].left.start, matchPos[i].left.end),
  887. str.slice(matchPos[i].right.start, matchPos[i].right.end),
  888. ]);
  889. }
  890. return results;
  891. };
  892.  
  893. /**
  894. *
  895. * @param {string} str
  896. * @param {string|function} replacement
  897. * @param {string} left
  898. * @param {string} right
  899. * @param {string} flags
  900. * @returns {string}
  901. */
  902. showdown.helper.replaceRecursiveRegExp = function (
  903. str,
  904. replacement,
  905. left,
  906. right,
  907. flags
  908. ) {
  909. "use strict";
  910.  
  911. if (!showdown.helper.isFunction(replacement)) {
  912. var repStr = replacement;
  913. replacement = function () {
  914. return repStr;
  915. };
  916. }
  917.  
  918. var matchPos = rgxFindMatchPos(str, left, right, flags),
  919. finalStr = str,
  920. lng = matchPos.length;
  921.  
  922. if (lng > 0) {
  923. var bits = [];
  924. if (matchPos[0].wholeMatch.start !== 0) {
  925. bits.push(str.slice(0, matchPos[0].wholeMatch.start));
  926. }
  927. for (var i = 0; i < lng; ++i) {
  928. bits.push(
  929. replacement(
  930. str.slice(matchPos[i].wholeMatch.start, matchPos[i].wholeMatch.end),
  931. str.slice(matchPos[i].match.start, matchPos[i].match.end),
  932. str.slice(matchPos[i].left.start, matchPos[i].left.end),
  933. str.slice(matchPos[i].right.start, matchPos[i].right.end)
  934. )
  935. );
  936. if (i < lng - 1) {
  937. bits.push(
  938. str.slice(
  939. matchPos[i].wholeMatch.end,
  940. matchPos[i + 1].wholeMatch.start
  941. )
  942. );
  943. }
  944. }
  945. if (matchPos[lng - 1].wholeMatch.end < str.length) {
  946. bits.push(str.slice(matchPos[lng - 1].wholeMatch.end));
  947. }
  948. finalStr = bits.join("");
  949. }
  950. return finalStr;
  951. };
  952.  
  953. /**
  954. * Returns the index within the passed String object of the first occurrence of the specified regex,
  955. * starting the search at fromIndex. Returns -1 if the value is not found.
  956. *
  957. * @param {string} str string to search
  958. * @param {RegExp} regex Regular expression to search
  959. * @param {int} [fromIndex = 0] Index to start the search
  960. * @returns {Number}
  961. * @throws InvalidArgumentError
  962. */
  963. showdown.helper.regexIndexOf = function (str, regex, fromIndex) {
  964. "use strict";
  965. if (!showdown.helper.isString(str)) {
  966. throw "InvalidArgumentError: first parameter of showdown.helper.regexIndexOf function must be a string";
  967. }
  968. if (regex instanceof RegExp === false) {
  969. throw "InvalidArgumentError: second parameter of showdown.helper.regexIndexOf function must be an instance of RegExp";
  970. }
  971. var indexOf = str.substring(fromIndex || 0).search(regex);
  972. return indexOf >= 0 ? indexOf + (fromIndex || 0) : indexOf;
  973. };
  974.  
  975. /**
  976. * Splits the passed string object at the defined index, and returns an array composed of the two substrings
  977. * @param {string} str string to split
  978. * @param {int} index index to split string at
  979. * @returns {[string,string]}
  980. * @throws InvalidArgumentError
  981. */
  982. showdown.helper.splitAtIndex = function (str, index) {
  983. "use strict";
  984. if (!showdown.helper.isString(str)) {
  985. throw "InvalidArgumentError: first parameter of showdown.helper.regexIndexOf function must be a string";
  986. }
  987. return [str.substring(0, index), str.substring(index)];
  988. };
  989.  
  990. /**
  991. * Obfuscate an e-mail address through the use of Character Entities,
  992. * transforming ASCII characters into their equivalent decimal or hex entities.
  993. *
  994. * Since it has a random component, subsequent calls to this function produce different results
  995. *
  996. * @param {string} mail
  997. * @returns {string}
  998. */
  999. showdown.helper.encodeEmailAddress = function (mail) {
  1000. "use strict";
  1001. var encode = [
  1002. function (ch) {
  1003. return "&#" + ch.charCodeAt(0) + ";";
  1004. },
  1005. function (ch) {
  1006. return "&#x" + ch.charCodeAt(0).toString(16) + ";";
  1007. },
  1008. function (ch) {
  1009. return ch;
  1010. },
  1011. ];
  1012.  
  1013. mail = mail.replace(/./g, function (ch) {
  1014. if (ch === "@") {
  1015. // this *must* be encoded. I insist.
  1016. ch = encode[Math.floor(Math.random() * 2)](ch);
  1017. } else {
  1018. var r = Math.random();
  1019. // roughly 10% raw, 45% hex, 45% dec
  1020. ch = r > 0.9 ? encode[2](ch) : r > 0.45 ? encode[1](ch) : encode[0](ch);
  1021. }
  1022. return ch;
  1023. });
  1024.  
  1025. return mail;
  1026. };
  1027.  
  1028. /**
  1029. *
  1030. * @param str
  1031. * @param targetLength
  1032. * @param padString
  1033. * @returns {string}
  1034. */
  1035. showdown.helper.padEnd = function padEnd(str, targetLength, padString) {
  1036. "use strict";
  1037. /*jshint bitwise: false*/
  1038. // eslint-disable-next-line space-infix-ops
  1039. targetLength = targetLength >> 0; //floor if number or convert non-number to 0;
  1040. /*jshint bitwise: true*/
  1041. padString = String(padString || " ");
  1042. if (str.length > targetLength) {
  1043. return String(str);
  1044. } else {
  1045. targetLength = targetLength - str.length;
  1046. if (targetLength > padString.length) {
  1047. padString += padString.repeat(targetLength / padString.length); //append to original to ensure we are longer than needed
  1048. }
  1049. return String(str) + padString.slice(0, targetLength);
  1050. }
  1051. };
  1052.  
  1053. /**
  1054. * POLYFILLS
  1055. */
  1056. // use this instead of builtin is undefined for IE8 compatibility
  1057. if (typeof console === "undefined") {
  1058. console = {
  1059. warn: function (msg) {
  1060. "use strict";
  1061. alert(msg);
  1062. },
  1063. log: function (msg) {
  1064. "use strict";
  1065. alert(msg);
  1066. },
  1067. error: function (msg) {
  1068. "use strict";
  1069. throw msg;
  1070. },
  1071. };
  1072. }
  1073.  
  1074. /**
  1075. * Common regexes.
  1076. * We declare some common regexes to improve performance
  1077. */
  1078. showdown.helper.regexes = {
  1079. asteriskDashAndColon: /([*_:~])/g,
  1080. };
  1081.  
  1082. /**
  1083. * EMOJIS LIST
  1084. */
  1085. showdown.helper.emojis = {
  1086. "+1": "\ud83d\udc4d",
  1087. "-1": "\ud83d\udc4e",
  1088. 100: "\ud83d\udcaf",
  1089. 1234: "\ud83d\udd22",
  1090. "1st_place_medal": "\ud83e\udd47",
  1091. "2nd_place_medal": "\ud83e\udd48",
  1092. "3rd_place_medal": "\ud83e\udd49",
  1093. "8ball": "\ud83c\udfb1",
  1094. a: "\ud83c\udd70\ufe0f",
  1095. ab: "\ud83c\udd8e",
  1096. abc: "\ud83d\udd24",
  1097. abcd: "\ud83d\udd21",
  1098. accept: "\ud83c\ude51",
  1099. aerial_tramway: "\ud83d\udea1",
  1100. airplane: "\u2708\ufe0f",
  1101. alarm_clock: "\u23f0",
  1102. alembic: "\u2697\ufe0f",
  1103. alien: "\ud83d\udc7d",
  1104. ambulance: "\ud83d\ude91",
  1105. amphora: "\ud83c\udffa",
  1106. anchor: "\u2693\ufe0f",
  1107. angel: "\ud83d\udc7c",
  1108. anger: "\ud83d\udca2",
  1109. angry: "\ud83d\ude20",
  1110. anguished: "\ud83d\ude27",
  1111. ant: "\ud83d\udc1c",
  1112. apple: "\ud83c\udf4e",
  1113. aquarius: "\u2652\ufe0f",
  1114. aries: "\u2648\ufe0f",
  1115. arrow_backward: "\u25c0\ufe0f",
  1116. arrow_double_down: "\u23ec",
  1117. arrow_double_up: "\u23eb",
  1118. arrow_down: "\u2b07\ufe0f",
  1119. arrow_down_small: "\ud83d\udd3d",
  1120. arrow_forward: "\u25b6\ufe0f",
  1121. arrow_heading_down: "\u2935\ufe0f",
  1122. arrow_heading_up: "\u2934\ufe0f",
  1123. arrow_left: "\u2b05\ufe0f",
  1124. arrow_lower_left: "\u2199\ufe0f",
  1125. arrow_lower_right: "\u2198\ufe0f",
  1126. arrow_right: "\u27a1\ufe0f",
  1127. arrow_right_hook: "\u21aa\ufe0f",
  1128. arrow_up: "\u2b06\ufe0f",
  1129. arrow_up_down: "\u2195\ufe0f",
  1130. arrow_up_small: "\ud83d\udd3c",
  1131. arrow_upper_left: "\u2196\ufe0f",
  1132. arrow_upper_right: "\u2197\ufe0f",
  1133. arrows_clockwise: "\ud83d\udd03",
  1134. arrows_counterclockwise: "\ud83d\udd04",
  1135. art: "\ud83c\udfa8",
  1136. articulated_lorry: "\ud83d\ude9b",
  1137. artificial_satellite: "\ud83d\udef0",
  1138. astonished: "\ud83d\ude32",
  1139. athletic_shoe: "\ud83d\udc5f",
  1140. atm: "\ud83c\udfe7",
  1141. atom_symbol: "\u269b\ufe0f",
  1142. avocado: "\ud83e\udd51",
  1143. b: "\ud83c\udd71\ufe0f",
  1144. baby: "\ud83d\udc76",
  1145. baby_bottle: "\ud83c\udf7c",
  1146. baby_chick: "\ud83d\udc24",
  1147. baby_symbol: "\ud83d\udebc",
  1148. back: "\ud83d\udd19",
  1149. bacon: "\ud83e\udd53",
  1150. badminton: "\ud83c\udff8",
  1151. baggage_claim: "\ud83d\udec4",
  1152. baguette_bread: "\ud83e\udd56",
  1153. balance_scale: "\u2696\ufe0f",
  1154. balloon: "\ud83c\udf88",
  1155. ballot_box: "\ud83d\uddf3",
  1156. ballot_box_with_check: "\u2611\ufe0f",
  1157. bamboo: "\ud83c\udf8d",
  1158. banana: "\ud83c\udf4c",
  1159. bangbang: "\u203c\ufe0f",
  1160. bank: "\ud83c\udfe6",
  1161. bar_chart: "\ud83d\udcca",
  1162. barber: "\ud83d\udc88",
  1163. baseball: "\u26be\ufe0f",
  1164. basketball: "\ud83c\udfc0",
  1165. basketball_man: "\u26f9\ufe0f",
  1166. basketball_woman: "\u26f9\ufe0f&zwj;\u2640\ufe0f",
  1167. bat: "\ud83e\udd87",
  1168. bath: "\ud83d\udec0",
  1169. bathtub: "\ud83d\udec1",
  1170. battery: "\ud83d\udd0b",
  1171. beach_umbrella: "\ud83c\udfd6",
  1172. bear: "\ud83d\udc3b",
  1173. bed: "\ud83d\udecf",
  1174. bee: "\ud83d\udc1d",
  1175. beer: "\ud83c\udf7a",
  1176. beers: "\ud83c\udf7b",
  1177. beetle: "\ud83d\udc1e",
  1178. beginner: "\ud83d\udd30",
  1179. bell: "\ud83d\udd14",
  1180. bellhop_bell: "\ud83d\udece",
  1181. bento: "\ud83c\udf71",
  1182. biking_man: "\ud83d\udeb4",
  1183. bike: "\ud83d\udeb2",
  1184. biking_woman: "\ud83d\udeb4&zwj;\u2640\ufe0f",
  1185. bikini: "\ud83d\udc59",
  1186. biohazard: "\u2623\ufe0f",
  1187. bird: "\ud83d\udc26",
  1188. birthday: "\ud83c\udf82",
  1189. black_circle: "\u26ab\ufe0f",
  1190. black_flag: "\ud83c\udff4",
  1191. black_heart: "\ud83d\udda4",
  1192. black_joker: "\ud83c\udccf",
  1193. black_large_square: "\u2b1b\ufe0f",
  1194. black_medium_small_square: "\u25fe\ufe0f",
  1195. black_medium_square: "\u25fc\ufe0f",
  1196. black_nib: "\u2712\ufe0f",
  1197. black_small_square: "\u25aa\ufe0f",
  1198. black_square_button: "\ud83d\udd32",
  1199. blonde_man: "\ud83d\udc71",
  1200. blonde_woman: "\ud83d\udc71&zwj;\u2640\ufe0f",
  1201. blossom: "\ud83c\udf3c",
  1202. blowfish: "\ud83d\udc21",
  1203. blue_book: "\ud83d\udcd8",
  1204. blue_car: "\ud83d\ude99",
  1205. blue_heart: "\ud83d\udc99",
  1206. blush: "\ud83d\ude0a",
  1207. boar: "\ud83d\udc17",
  1208. boat: "\u26f5\ufe0f",
  1209. bomb: "\ud83d\udca3",
  1210. book: "\ud83d\udcd6",
  1211. bookmark: "\ud83d\udd16",
  1212. bookmark_tabs: "\ud83d\udcd1",
  1213. books: "\ud83d\udcda",
  1214. boom: "\ud83d\udca5",
  1215. boot: "\ud83d\udc62",
  1216. bouquet: "\ud83d\udc90",
  1217. bowing_man: "\ud83d\ude47",
  1218. bow_and_arrow: "\ud83c\udff9",
  1219. bowing_woman: "\ud83d\ude47&zwj;\u2640\ufe0f",
  1220. bowling: "\ud83c\udfb3",
  1221. boxing_glove: "\ud83e\udd4a",
  1222. boy: "\ud83d\udc66",
  1223. bread: "\ud83c\udf5e",
  1224. bride_with_veil: "\ud83d\udc70",
  1225. bridge_at_night: "\ud83c\udf09",
  1226. briefcase: "\ud83d\udcbc",
  1227. broken_heart: "\ud83d\udc94",
  1228. bug: "\ud83d\udc1b",
  1229. building_construction: "\ud83c\udfd7",
  1230. bulb: "\ud83d\udca1",
  1231. bullettrain_front: "\ud83d\ude85",
  1232. bullettrain_side: "\ud83d\ude84",
  1233. burrito: "\ud83c\udf2f",
  1234. bus: "\ud83d\ude8c",
  1235. business_suit_levitating: "\ud83d\udd74",
  1236. busstop: "\ud83d\ude8f",
  1237. bust_in_silhouette: "\ud83d\udc64",
  1238. busts_in_silhouette: "\ud83d\udc65",
  1239. butterfly: "\ud83e\udd8b",
  1240. cactus: "\ud83c\udf35",
  1241. cake: "\ud83c\udf70",
  1242. calendar: "\ud83d\udcc6",
  1243. call_me_hand: "\ud83e\udd19",
  1244. calling: "\ud83d\udcf2",
  1245. camel: "\ud83d\udc2b",
  1246. camera: "\ud83d\udcf7",
  1247. camera_flash: "\ud83d\udcf8",
  1248. camping: "\ud83c\udfd5",
  1249. cancer: "\u264b\ufe0f",
  1250. candle: "\ud83d\udd6f",
  1251. candy: "\ud83c\udf6c",
  1252. canoe: "\ud83d\udef6",
  1253. capital_abcd: "\ud83d\udd20",
  1254. capricorn: "\u2651\ufe0f",
  1255. car: "\ud83d\ude97",
  1256. card_file_box: "\ud83d\uddc3",
  1257. card_index: "\ud83d\udcc7",
  1258. card_index_dividers: "\ud83d\uddc2",
  1259. carousel_horse: "\ud83c\udfa0",
  1260. carrot: "\ud83e\udd55",
  1261. cat: "\ud83d\udc31",
  1262. cat2: "\ud83d\udc08",
  1263. cd: "\ud83d\udcbf",
  1264. chains: "\u26d3",
  1265. champagne: "\ud83c\udf7e",
  1266. chart: "\ud83d\udcb9",
  1267. chart_with_downwards_trend: "\ud83d\udcc9",
  1268. chart_with_upwards_trend: "\ud83d\udcc8",
  1269. checkered_flag: "\ud83c\udfc1",
  1270. cheese: "\ud83e\uddc0",
  1271. cherries: "\ud83c\udf52",
  1272. cherry_blossom: "\ud83c\udf38",
  1273. chestnut: "\ud83c\udf30",
  1274. chicken: "\ud83d\udc14",
  1275. children_crossing: "\ud83d\udeb8",
  1276. chipmunk: "\ud83d\udc3f",
  1277. chocolate_bar: "\ud83c\udf6b",
  1278. christmas_tree: "\ud83c\udf84",
  1279. church: "\u26ea\ufe0f",
  1280. cinema: "\ud83c\udfa6",
  1281. circus_tent: "\ud83c\udfaa",
  1282. city_sunrise: "\ud83c\udf07",
  1283. city_sunset: "\ud83c\udf06",
  1284. cityscape: "\ud83c\udfd9",
  1285. cl: "\ud83c\udd91",
  1286. clamp: "\ud83d\udddc",
  1287. clap: "\ud83d\udc4f",
  1288. clapper: "\ud83c\udfac",
  1289. classical_building: "\ud83c\udfdb",
  1290. clinking_glasses: "\ud83e\udd42",
  1291. clipboard: "\ud83d\udccb",
  1292. clock1: "\ud83d\udd50",
  1293. clock10: "\ud83d\udd59",
  1294. clock1030: "\ud83d\udd65",
  1295. clock11: "\ud83d\udd5a",
  1296. clock1130: "\ud83d\udd66",
  1297. clock12: "\ud83d\udd5b",
  1298. clock1230: "\ud83d\udd67",
  1299. clock130: "\ud83d\udd5c",
  1300. clock2: "\ud83d\udd51",
  1301. clock230: "\ud83d\udd5d",
  1302. clock3: "\ud83d\udd52",
  1303. clock330: "\ud83d\udd5e",
  1304. clock4: "\ud83d\udd53",
  1305. clock430: "\ud83d\udd5f",
  1306. clock5: "\ud83d\udd54",
  1307. clock530: "\ud83d\udd60",
  1308. clock6: "\ud83d\udd55",
  1309. clock630: "\ud83d\udd61",
  1310. clock7: "\ud83d\udd56",
  1311. clock730: "\ud83d\udd62",
  1312. clock8: "\ud83d\udd57",
  1313. clock830: "\ud83d\udd63",
  1314. clock9: "\ud83d\udd58",
  1315. clock930: "\ud83d\udd64",
  1316. closed_book: "\ud83d\udcd5",
  1317. closed_lock_with_key: "\ud83d\udd10",
  1318. closed_umbrella: "\ud83c\udf02",
  1319. cloud: "\u2601\ufe0f",
  1320. cloud_with_lightning: "\ud83c\udf29",
  1321. cloud_with_lightning_and_rain: "\u26c8",
  1322. cloud_with_rain: "\ud83c\udf27",
  1323. cloud_with_snow: "\ud83c\udf28",
  1324. clown_face: "\ud83e\udd21",
  1325. clubs: "\u2663\ufe0f",
  1326. cocktail: "\ud83c\udf78",
  1327. coffee: "\u2615\ufe0f",
  1328. coffin: "\u26b0\ufe0f",
  1329. cold_sweat: "\ud83d\ude30",
  1330. comet: "\u2604\ufe0f",
  1331. computer: "\ud83d\udcbb",
  1332. computer_mouse: "\ud83d\uddb1",
  1333. confetti_ball: "\ud83c\udf8a",
  1334. confounded: "\ud83d\ude16",
  1335. confused: "\ud83d\ude15",
  1336. congratulations: "\u3297\ufe0f",
  1337. construction: "\ud83d\udea7",
  1338. construction_worker_man: "\ud83d\udc77",
  1339. construction_worker_woman: "\ud83d\udc77&zwj;\u2640\ufe0f",
  1340. control_knobs: "\ud83c\udf9b",
  1341. convenience_store: "\ud83c\udfea",
  1342. cookie: "\ud83c\udf6a",
  1343. cool: "\ud83c\udd92",
  1344. policeman: "\ud83d\udc6e",
  1345. copyright: "\u00a9\ufe0f",
  1346. corn: "\ud83c\udf3d",
  1347. couch_and_lamp: "\ud83d\udecb",
  1348. couple: "\ud83d\udc6b",
  1349. couple_with_heart_woman_man: "\ud83d\udc91",
  1350. couple_with_heart_man_man: "\ud83d\udc68&zwj;\u2764\ufe0f&zwj;\ud83d\udc68",
  1351. couple_with_heart_woman_woman:
  1352. "\ud83d\udc69&zwj;\u2764\ufe0f&zwj;\ud83d\udc69",
  1353. couplekiss_man_man:
  1354. "\ud83d\udc68&zwj;\u2764\ufe0f&zwj;\ud83d\udc8b&zwj;\ud83d\udc68",
  1355. couplekiss_man_woman: "\ud83d\udc8f",
  1356. couplekiss_woman_woman:
  1357. "\ud83d\udc69&zwj;\u2764\ufe0f&zwj;\ud83d\udc8b&zwj;\ud83d\udc69",
  1358. cow: "\ud83d\udc2e",
  1359. cow2: "\ud83d\udc04",
  1360. cowboy_hat_face: "\ud83e\udd20",
  1361. crab: "\ud83e\udd80",
  1362. crayon: "\ud83d\udd8d",
  1363. credit_card: "\ud83d\udcb3",
  1364. crescent_moon: "\ud83c\udf19",
  1365. cricket: "\ud83c\udfcf",
  1366. crocodile: "\ud83d\udc0a",
  1367. croissant: "\ud83e\udd50",
  1368. crossed_fingers: "\ud83e\udd1e",
  1369. crossed_flags: "\ud83c\udf8c",
  1370. crossed_swords: "\u2694\ufe0f",
  1371. crown: "\ud83d\udc51",
  1372. cry: "\ud83d\ude22",
  1373. crying_cat_face: "\ud83d\ude3f",
  1374. crystal_ball: "\ud83d\udd2e",
  1375. cucumber: "\ud83e\udd52",
  1376. cupid: "\ud83d\udc98",
  1377. curly_loop: "\u27b0",
  1378. currency_exchange: "\ud83d\udcb1",
  1379. curry: "\ud83c\udf5b",
  1380. custard: "\ud83c\udf6e",
  1381. customs: "\ud83d\udec3",
  1382. cyclone: "\ud83c\udf00",
  1383. dagger: "\ud83d\udde1",
  1384. dancer: "\ud83d\udc83",
  1385. dancing_women: "\ud83d\udc6f",
  1386. dancing_men: "\ud83d\udc6f&zwj;\u2642\ufe0f",
  1387. dango: "\ud83c\udf61",
  1388. dark_sunglasses: "\ud83d\udd76",
  1389. dart: "\ud83c\udfaf",
  1390. dash: "\ud83d\udca8",
  1391. date: "\ud83d\udcc5",
  1392. deciduous_tree: "\ud83c\udf33",
  1393. deer: "\ud83e\udd8c",
  1394. department_store: "\ud83c\udfec",
  1395. derelict_house: "\ud83c\udfda",
  1396. desert: "\ud83c\udfdc",
  1397. desert_island: "\ud83c\udfdd",
  1398. desktop_computer: "\ud83d\udda5",
  1399. male_detective: "\ud83d\udd75\ufe0f",
  1400. diamond_shape_with_a_dot_inside: "\ud83d\udca0",
  1401. diamonds: "\u2666\ufe0f",
  1402. disappointed: "\ud83d\ude1e",
  1403. disappointed_relieved: "\ud83d\ude25",
  1404. dizzy: "\ud83d\udcab",
  1405. dizzy_face: "\ud83d\ude35",
  1406. do_not_litter: "\ud83d\udeaf",
  1407. dog: "\ud83d\udc36",
  1408. dog2: "\ud83d\udc15",
  1409. dollar: "\ud83d\udcb5",
  1410. dolls: "\ud83c\udf8e",
  1411. dolphin: "\ud83d\udc2c",
  1412. door: "\ud83d\udeaa",
  1413. doughnut: "\ud83c\udf69",
  1414. dove: "\ud83d\udd4a",
  1415. dragon: "\ud83d\udc09",
  1416. dragon_face: "\ud83d\udc32",
  1417. dress: "\ud83d\udc57",
  1418. dromedary_camel: "\ud83d\udc2a",
  1419. drooling_face: "\ud83e\udd24",
  1420. droplet: "\ud83d\udca7",
  1421. drum: "\ud83e\udd41",
  1422. duck: "\ud83e\udd86",
  1423. dvd: "\ud83d\udcc0",
  1424. "e-mail": "\ud83d\udce7",
  1425. eagle: "\ud83e\udd85",
  1426. ear: "\ud83d\udc42",
  1427. ear_of_rice: "\ud83c\udf3e",
  1428. earth_africa: "\ud83c\udf0d",
  1429. earth_americas: "\ud83c\udf0e",
  1430. earth_asia: "\ud83c\udf0f",
  1431. egg: "\ud83e\udd5a",
  1432. eggplant: "\ud83c\udf46",
  1433. eight_pointed_black_star: "\u2734\ufe0f",
  1434. eight_spoked_asterisk: "\u2733\ufe0f",
  1435. electric_plug: "\ud83d\udd0c",
  1436. elephant: "\ud83d\udc18",
  1437. email: "\u2709\ufe0f",
  1438. end: "\ud83d\udd1a",
  1439. envelope_with_arrow: "\ud83d\udce9",
  1440. euro: "\ud83d\udcb6",
  1441. european_castle: "\ud83c\udff0",
  1442. european_post_office: "\ud83c\udfe4",
  1443. evergreen_tree: "\ud83c\udf32",
  1444. exclamation: "\u2757\ufe0f",
  1445. expressionless: "\ud83d\ude11",
  1446. eye: "\ud83d\udc41",
  1447. eye_speech_bubble: "\ud83d\udc41&zwj;\ud83d\udde8",
  1448. eyeglasses: "\ud83d\udc53",
  1449. eyes: "\ud83d\udc40",
  1450. face_with_head_bandage: "\ud83e\udd15",
  1451. face_with_thermometer: "\ud83e\udd12",
  1452. fist_oncoming: "\ud83d\udc4a",
  1453. factory: "\ud83c\udfed",
  1454. fallen_leaf: "\ud83c\udf42",
  1455. family_man_woman_boy: "\ud83d\udc6a",
  1456. family_man_boy: "\ud83d\udc68&zwj;\ud83d\udc66",
  1457. family_man_boy_boy: "\ud83d\udc68&zwj;\ud83d\udc66&zwj;\ud83d\udc66",
  1458. family_man_girl: "\ud83d\udc68&zwj;\ud83d\udc67",
  1459. family_man_girl_boy: "\ud83d\udc68&zwj;\ud83d\udc67&zwj;\ud83d\udc66",
  1460. family_man_girl_girl: "\ud83d\udc68&zwj;\ud83d\udc67&zwj;\ud83d\udc67",
  1461. family_man_man_boy: "\ud83d\udc68&zwj;\ud83d\udc68&zwj;\ud83d\udc66",
  1462. family_man_man_boy_boy:
  1463. "\ud83d\udc68&zwj;\ud83d\udc68&zwj;\ud83d\udc66&zwj;\ud83d\udc66",
  1464. family_man_man_girl: "\ud83d\udc68&zwj;\ud83d\udc68&zwj;\ud83d\udc67",
  1465. family_man_man_girl_boy:
  1466. "\ud83d\udc68&zwj;\ud83d\udc68&zwj;\ud83d\udc67&zwj;\ud83d\udc66",
  1467. family_man_man_girl_girl:
  1468. "\ud83d\udc68&zwj;\ud83d\udc68&zwj;\ud83d\udc67&zwj;\ud83d\udc67",
  1469. family_man_woman_boy_boy:
  1470. "\ud83d\udc68&zwj;\ud83d\udc69&zwj;\ud83d\udc66&zwj;\ud83d\udc66",
  1471. family_man_woman_girl: "\ud83d\udc68&zwj;\ud83d\udc69&zwj;\ud83d\udc67",
  1472. family_man_woman_girl_boy:
  1473. "\ud83d\udc68&zwj;\ud83d\udc69&zwj;\ud83d\udc67&zwj;\ud83d\udc66",
  1474. family_man_woman_girl_girl:
  1475. "\ud83d\udc68&zwj;\ud83d\udc69&zwj;\ud83d\udc67&zwj;\ud83d\udc67",
  1476. family_woman_boy: "\ud83d\udc69&zwj;\ud83d\udc66",
  1477. family_woman_boy_boy: "\ud83d\udc69&zwj;\ud83d\udc66&zwj;\ud83d\udc66",
  1478. family_woman_girl: "\ud83d\udc69&zwj;\ud83d\udc67",
  1479. family_woman_girl_boy: "\ud83d\udc69&zwj;\ud83d\udc67&zwj;\ud83d\udc66",
  1480. family_woman_girl_girl: "\ud83d\udc69&zwj;\ud83d\udc67&zwj;\ud83d\udc67",
  1481. family_woman_woman_boy: "\ud83d\udc69&zwj;\ud83d\udc69&zwj;\ud83d\udc66",
  1482. family_woman_woman_boy_boy:
  1483. "\ud83d\udc69&zwj;\ud83d\udc69&zwj;\ud83d\udc66&zwj;\ud83d\udc66",
  1484. family_woman_woman_girl: "\ud83d\udc69&zwj;\ud83d\udc69&zwj;\ud83d\udc67",
  1485. family_woman_woman_girl_boy:
  1486. "\ud83d\udc69&zwj;\ud83d\udc69&zwj;\ud83d\udc67&zwj;\ud83d\udc66",
  1487. family_woman_woman_girl_girl:
  1488. "\ud83d\udc69&zwj;\ud83d\udc69&zwj;\ud83d\udc67&zwj;\ud83d\udc67",
  1489. fast_forward: "\u23e9",
  1490. fax: "\ud83d\udce0",
  1491. fearful: "\ud83d\ude28",
  1492. feet: "\ud83d\udc3e",
  1493. female_detective: "\ud83d\udd75\ufe0f&zwj;\u2640\ufe0f",
  1494. ferris_wheel: "\ud83c\udfa1",
  1495. ferry: "\u26f4",
  1496. field_hockey: "\ud83c\udfd1",
  1497. file_cabinet: "\ud83d\uddc4",
  1498. file_folder: "\ud83d\udcc1",
  1499. film_projector: "\ud83d\udcfd",
  1500. film_strip: "\ud83c\udf9e",
  1501. fire: "\ud83d\udd25",
  1502. fire_engine: "\ud83d\ude92",
  1503. fireworks: "\ud83c\udf86",
  1504. first_quarter_moon: "\ud83c\udf13",
  1505. first_quarter_moon_with_face: "\ud83c\udf1b",
  1506. fish: "\ud83d\udc1f",
  1507. fish_cake: "\ud83c\udf65",
  1508. fishing_pole_and_fish: "\ud83c\udfa3",
  1509. fist_raised: "\u270a",
  1510. fist_left: "\ud83e\udd1b",
  1511. fist_right: "\ud83e\udd1c",
  1512. flags: "\ud83c\udf8f",
  1513. flashlight: "\ud83d\udd26",
  1514. fleur_de_lis: "\u269c\ufe0f",
  1515. flight_arrival: "\ud83d\udeec",
  1516. flight_departure: "\ud83d\udeeb",
  1517. floppy_disk: "\ud83d\udcbe",
  1518. flower_playing_cards: "\ud83c\udfb4",
  1519. flushed: "\ud83d\ude33",
  1520. fog: "\ud83c\udf2b",
  1521. foggy: "\ud83c\udf01",
  1522. football: "\ud83c\udfc8",
  1523. footprints: "\ud83d\udc63",
  1524. fork_and_knife: "\ud83c\udf74",
  1525. fountain: "\u26f2\ufe0f",
  1526. fountain_pen: "\ud83d\udd8b",
  1527. four_leaf_clover: "\ud83c\udf40",
  1528. fox_face: "\ud83e\udd8a",
  1529. framed_picture: "\ud83d\uddbc",
  1530. free: "\ud83c\udd93",
  1531. fried_egg: "\ud83c\udf73",
  1532. fried_shrimp: "\ud83c\udf64",
  1533. fries: "\ud83c\udf5f",
  1534. frog: "\ud83d\udc38",
  1535. frowning: "\ud83d\ude26",
  1536. frowning_face: "\u2639\ufe0f",
  1537. frowning_man: "\ud83d\ude4d&zwj;\u2642\ufe0f",
  1538. frowning_woman: "\ud83d\ude4d",
  1539. middle_finger: "\ud83d\udd95",
  1540. fuelpump: "\u26fd\ufe0f",
  1541. full_moon: "\ud83c\udf15",
  1542. full_moon_with_face: "\ud83c\udf1d",
  1543. funeral_urn: "\u26b1\ufe0f",
  1544. game_die: "\ud83c\udfb2",
  1545. gear: "\u2699\ufe0f",
  1546. gem: "\ud83d\udc8e",
  1547. gemini: "\u264a\ufe0f",
  1548. ghost: "\ud83d\udc7b",
  1549. gift: "\ud83c\udf81",
  1550. gift_heart: "\ud83d\udc9d",
  1551. girl: "\ud83d\udc67",
  1552. globe_with_meridians: "\ud83c\udf10",
  1553. goal_net: "\ud83e\udd45",
  1554. goat: "\ud83d\udc10",
  1555. golf: "\u26f3\ufe0f",
  1556. golfing_man: "\ud83c\udfcc\ufe0f",
  1557. golfing_woman: "\ud83c\udfcc\ufe0f&zwj;\u2640\ufe0f",
  1558. gorilla: "\ud83e\udd8d",
  1559. grapes: "\ud83c\udf47",
  1560. green_apple: "\ud83c\udf4f",
  1561. green_book: "\ud83d\udcd7",
  1562. green_heart: "\ud83d\udc9a",
  1563. green_salad: "\ud83e\udd57",
  1564. grey_exclamation: "\u2755",
  1565. grey_question: "\u2754",
  1566. grimacing: "\ud83d\ude2c",
  1567. grin: "\ud83d\ude01",
  1568. grinning: "\ud83d\ude00",
  1569. guardsman: "\ud83d\udc82",
  1570. guardswoman: "\ud83d\udc82&zwj;\u2640\ufe0f",
  1571. guitar: "\ud83c\udfb8",
  1572. gun: "\ud83d\udd2b",
  1573. haircut_woman: "\ud83d\udc87",
  1574. haircut_man: "\ud83d\udc87&zwj;\u2642\ufe0f",
  1575. hamburger: "\ud83c\udf54",
  1576. hammer: "\ud83d\udd28",
  1577. hammer_and_pick: "\u2692",
  1578. hammer_and_wrench: "\ud83d\udee0",
  1579. hamster: "\ud83d\udc39",
  1580. hand: "\u270b",
  1581. handbag: "\ud83d\udc5c",
  1582. handshake: "\ud83e\udd1d",
  1583. hankey: "\ud83d\udca9",
  1584. hatched_chick: "\ud83d\udc25",
  1585. hatching_chick: "\ud83d\udc23",
  1586. headphones: "\ud83c\udfa7",
  1587. hear_no_evil: "\ud83d\ude49",
  1588. heart: "\u2764\ufe0f",
  1589. heart_decoration: "\ud83d\udc9f",
  1590. heart_eyes: "\ud83d\ude0d",
  1591. heart_eyes_cat: "\ud83d\ude3b",
  1592. heartbeat: "\ud83d\udc93",
  1593. heartpulse: "\ud83d\udc97",
  1594. hearts: "\u2665\ufe0f",
  1595. heavy_check_mark: "\u2714\ufe0f",
  1596. heavy_division_sign: "\u2797",
  1597. heavy_dollar_sign: "\ud83d\udcb2",
  1598. heavy_heart_exclamation: "\u2763\ufe0f",
  1599. heavy_minus_sign: "\u2796",
  1600. heavy_multiplication_x: "\u2716\ufe0f",
  1601. heavy_plus_sign: "\u2795",
  1602. helicopter: "\ud83d\ude81",
  1603. herb: "\ud83c\udf3f",
  1604. hibiscus: "\ud83c\udf3a",
  1605. high_brightness: "\ud83d\udd06",
  1606. high_heel: "\ud83d\udc60",
  1607. hocho: "\ud83d\udd2a",
  1608. hole: "\ud83d\udd73",
  1609. honey_pot: "\ud83c\udf6f",
  1610. horse: "\ud83d\udc34",
  1611. horse_racing: "\ud83c\udfc7",
  1612. hospital: "\ud83c\udfe5",
  1613. hot_pepper: "\ud83c\udf36",
  1614. hotdog: "\ud83c\udf2d",
  1615. hotel: "\ud83c\udfe8",
  1616. hotsprings: "\u2668\ufe0f",
  1617. hourglass: "\u231b\ufe0f",
  1618. hourglass_flowing_sand: "\u23f3",
  1619. house: "\ud83c\udfe0",
  1620. house_with_garden: "\ud83c\udfe1",
  1621. houses: "\ud83c\udfd8",
  1622. hugs: "\ud83e\udd17",
  1623. hushed: "\ud83d\ude2f",
  1624. ice_cream: "\ud83c\udf68",
  1625. ice_hockey: "\ud83c\udfd2",
  1626. ice_skate: "\u26f8",
  1627. icecream: "\ud83c\udf66",
  1628. id: "\ud83c\udd94",
  1629. ideograph_advantage: "\ud83c\ude50",
  1630. imp: "\ud83d\udc7f",
  1631. inbox_tray: "\ud83d\udce5",
  1632. incoming_envelope: "\ud83d\udce8",
  1633. tipping_hand_woman: "\ud83d\udc81",
  1634. information_source: "\u2139\ufe0f",
  1635. innocent: "\ud83d\ude07",
  1636. interrobang: "\u2049\ufe0f",
  1637. iphone: "\ud83d\udcf1",
  1638. izakaya_lantern: "\ud83c\udfee",
  1639. jack_o_lantern: "\ud83c\udf83",
  1640. japan: "\ud83d\uddfe",
  1641. japanese_castle: "\ud83c\udfef",
  1642. japanese_goblin: "\ud83d\udc7a",
  1643. japanese_ogre: "\ud83d\udc79",
  1644. jeans: "\ud83d\udc56",
  1645. joy: "\ud83d\ude02",
  1646. joy_cat: "\ud83d\ude39",
  1647. joystick: "\ud83d\udd79",
  1648. kaaba: "\ud83d\udd4b",
  1649. key: "\ud83d\udd11",
  1650. keyboard: "\u2328\ufe0f",
  1651. keycap_ten: "\ud83d\udd1f",
  1652. kick_scooter: "\ud83d\udef4",
  1653. kimono: "\ud83d\udc58",
  1654. kiss: "\ud83d\udc8b",
  1655. kissing: "\ud83d\ude17",
  1656. kissing_cat: "\ud83d\ude3d",
  1657. kissing_closed_eyes: "\ud83d\ude1a",
  1658. kissing_heart: "\ud83d\ude18",
  1659. kissing_smiling_eyes: "\ud83d\ude19",
  1660. kiwi_fruit: "\ud83e\udd5d",
  1661. koala: "\ud83d\udc28",
  1662. koko: "\ud83c\ude01",
  1663. label: "\ud83c\udff7",
  1664. large_blue_circle: "\ud83d\udd35",
  1665. large_blue_diamond: "\ud83d\udd37",
  1666. large_orange_diamond: "\ud83d\udd36",
  1667. last_quarter_moon: "\ud83c\udf17",
  1668. last_quarter_moon_with_face: "\ud83c\udf1c",
  1669. latin_cross: "\u271d\ufe0f",
  1670. laughing: "\ud83d\ude06",
  1671. leaves: "\ud83c\udf43",
  1672. ledger: "\ud83d\udcd2",
  1673. left_luggage: "\ud83d\udec5",
  1674. left_right_arrow: "\u2194\ufe0f",
  1675. leftwards_arrow_with_hook: "\u21a9\ufe0f",
  1676. lemon: "\ud83c\udf4b",
  1677. leo: "\u264c\ufe0f",
  1678. leopard: "\ud83d\udc06",
  1679. level_slider: "\ud83c\udf9a",
  1680. libra: "\u264e\ufe0f",
  1681. light_rail: "\ud83d\ude88",
  1682. link: "\ud83d\udd17",
  1683. lion: "\ud83e\udd81",
  1684. lips: "\ud83d\udc44",
  1685. lipstick: "\ud83d\udc84",
  1686. lizard: "\ud83e\udd8e",
  1687. lock: "\ud83d\udd12",
  1688. lock_with_ink_pen: "\ud83d\udd0f",
  1689. lollipop: "\ud83c\udf6d",
  1690. loop: "\u27bf",
  1691. loud_sound: "\ud83d\udd0a",
  1692. loudspeaker: "\ud83d\udce2",
  1693. love_hotel: "\ud83c\udfe9",
  1694. love_letter: "\ud83d\udc8c",
  1695. low_brightness: "\ud83d\udd05",
  1696. lying_face: "\ud83e\udd25",
  1697. m: "\u24c2\ufe0f",
  1698. mag: "\ud83d\udd0d",
  1699. mag_right: "\ud83d\udd0e",
  1700. mahjong: "\ud83c\udc04\ufe0f",
  1701. mailbox: "\ud83d\udceb",
  1702. mailbox_closed: "\ud83d\udcea",
  1703. mailbox_with_mail: "\ud83d\udcec",
  1704. mailbox_with_no_mail: "\ud83d\udced",
  1705. man: "\ud83d\udc68",
  1706. man_artist: "\ud83d\udc68&zwj;\ud83c\udfa8",
  1707. man_astronaut: "\ud83d\udc68&zwj;\ud83d\ude80",
  1708. man_cartwheeling: "\ud83e\udd38&zwj;\u2642\ufe0f",
  1709. man_cook: "\ud83d\udc68&zwj;\ud83c\udf73",
  1710. man_dancing: "\ud83d\udd7a",
  1711. man_facepalming: "\ud83e\udd26&zwj;\u2642\ufe0f",
  1712. man_factory_worker: "\ud83d\udc68&zwj;\ud83c\udfed",
  1713. man_farmer: "\ud83d\udc68&zwj;\ud83c\udf3e",
  1714. man_firefighter: "\ud83d\udc68&zwj;\ud83d\ude92",
  1715. man_health_worker: "\ud83d\udc68&zwj;\u2695\ufe0f",
  1716. man_in_tuxedo: "\ud83e\udd35",
  1717. man_judge: "\ud83d\udc68&zwj;\u2696\ufe0f",
  1718. man_juggling: "\ud83e\udd39&zwj;\u2642\ufe0f",
  1719. man_mechanic: "\ud83d\udc68&zwj;\ud83d\udd27",
  1720. man_office_worker: "\ud83d\udc68&zwj;\ud83d\udcbc",
  1721. man_pilot: "\ud83d\udc68&zwj;\u2708\ufe0f",
  1722. man_playing_handball: "\ud83e\udd3e&zwj;\u2642\ufe0f",
  1723. man_playing_water_polo: "\ud83e\udd3d&zwj;\u2642\ufe0f",
  1724. man_scientist: "\ud83d\udc68&zwj;\ud83d\udd2c",
  1725. man_shrugging: "\ud83e\udd37&zwj;\u2642\ufe0f",
  1726. man_singer: "\ud83d\udc68&zwj;\ud83c\udfa4",
  1727. man_student: "\ud83d\udc68&zwj;\ud83c\udf93",
  1728. man_teacher: "\ud83d\udc68&zwj;\ud83c\udfeb",
  1729. man_technologist: "\ud83d\udc68&zwj;\ud83d\udcbb",
  1730. man_with_gua_pi_mao: "\ud83d\udc72",
  1731. man_with_turban: "\ud83d\udc73",
  1732. tangerine: "\ud83c\udf4a",
  1733. mans_shoe: "\ud83d\udc5e",
  1734. mantelpiece_clock: "\ud83d\udd70",
  1735. maple_leaf: "\ud83c\udf41",
  1736. martial_arts_uniform: "\ud83e\udd4b",
  1737. mask: "\ud83d\ude37",
  1738. massage_woman: "\ud83d\udc86",
  1739. massage_man: "\ud83d\udc86&zwj;\u2642\ufe0f",
  1740. meat_on_bone: "\ud83c\udf56",
  1741. medal_military: "\ud83c\udf96",
  1742. medal_sports: "\ud83c\udfc5",
  1743. mega: "\ud83d\udce3",
  1744. melon: "\ud83c\udf48",
  1745. memo: "\ud83d\udcdd",
  1746. men_wrestling: "\ud83e\udd3c&zwj;\u2642\ufe0f",
  1747. menorah: "\ud83d\udd4e",
  1748. mens: "\ud83d\udeb9",
  1749. metal: "\ud83e\udd18",
  1750. metro: "\ud83d\ude87",
  1751. microphone: "\ud83c\udfa4",
  1752. microscope: "\ud83d\udd2c",
  1753. milk_glass: "\ud83e\udd5b",
  1754. milky_way: "\ud83c\udf0c",
  1755. minibus: "\ud83d\ude90",
  1756. minidisc: "\ud83d\udcbd",
  1757. mobile_phone_off: "\ud83d\udcf4",
  1758. money_mouth_face: "\ud83e\udd11",
  1759. money_with_wings: "\ud83d\udcb8",
  1760. moneybag: "\ud83d\udcb0",
  1761. monkey: "\ud83d\udc12",
  1762. monkey_face: "\ud83d\udc35",
  1763. monorail: "\ud83d\ude9d",
  1764. moon: "\ud83c\udf14",
  1765. mortar_board: "\ud83c\udf93",
  1766. mosque: "\ud83d\udd4c",
  1767. motor_boat: "\ud83d\udee5",
  1768. motor_scooter: "\ud83d\udef5",
  1769. motorcycle: "\ud83c\udfcd",
  1770. motorway: "\ud83d\udee3",
  1771. mount_fuji: "\ud83d\uddfb",
  1772. mountain: "\u26f0",
  1773. mountain_biking_man: "\ud83d\udeb5",
  1774. mountain_biking_woman: "\ud83d\udeb5&zwj;\u2640\ufe0f",
  1775. mountain_cableway: "\ud83d\udea0",
  1776. mountain_railway: "\ud83d\ude9e",
  1777. mountain_snow: "\ud83c\udfd4",
  1778. mouse: "\ud83d\udc2d",
  1779. mouse2: "\ud83d\udc01",
  1780. movie_camera: "\ud83c\udfa5",
  1781. moyai: "\ud83d\uddff",
  1782. mrs_claus: "\ud83e\udd36",
  1783. muscle: "\ud83d\udcaa",
  1784. mushroom: "\ud83c\udf44",
  1785. musical_keyboard: "\ud83c\udfb9",
  1786. musical_note: "\ud83c\udfb5",
  1787. musical_score: "\ud83c\udfbc",
  1788. mute: "\ud83d\udd07",
  1789. nail_care: "\ud83d\udc85",
  1790. name_badge: "\ud83d\udcdb",
  1791. national_park: "\ud83c\udfde",
  1792. nauseated_face: "\ud83e\udd22",
  1793. necktie: "\ud83d\udc54",
  1794. negative_squared_cross_mark: "\u274e",
  1795. nerd_face: "\ud83e\udd13",
  1796. neutral_face: "\ud83d\ude10",
  1797. new: "\ud83c\udd95",
  1798. new_moon: "\ud83c\udf11",
  1799. new_moon_with_face: "\ud83c\udf1a",
  1800. newspaper: "\ud83d\udcf0",
  1801. newspaper_roll: "\ud83d\uddde",
  1802. next_track_button: "\u23ed",
  1803. ng: "\ud83c\udd96",
  1804. no_good_man: "\ud83d\ude45&zwj;\u2642\ufe0f",
  1805. no_good_woman: "\ud83d\ude45",
  1806. night_with_stars: "\ud83c\udf03",
  1807. no_bell: "\ud83d\udd15",
  1808. no_bicycles: "\ud83d\udeb3",
  1809. no_entry: "\u26d4\ufe0f",
  1810. no_entry_sign: "\ud83d\udeab",
  1811. no_mobile_phones: "\ud83d\udcf5",
  1812. no_mouth: "\ud83d\ude36",
  1813. no_pedestrians: "\ud83d\udeb7",
  1814. no_smoking: "\ud83d\udead",
  1815. "non-potable_water": "\ud83d\udeb1",
  1816. nose: "\ud83d\udc43",
  1817. notebook: "\ud83d\udcd3",
  1818. notebook_with_decorative_cover: "\ud83d\udcd4",
  1819. notes: "\ud83c\udfb6",
  1820. nut_and_bolt: "\ud83d\udd29",
  1821. o: "\u2b55\ufe0f",
  1822. o2: "\ud83c\udd7e\ufe0f",
  1823. ocean: "\ud83c\udf0a",
  1824. octopus: "\ud83d\udc19",
  1825. oden: "\ud83c\udf62",
  1826. office: "\ud83c\udfe2",
  1827. oil_drum: "\ud83d\udee2",
  1828. ok: "\ud83c\udd97",
  1829. ok_hand: "\ud83d\udc4c",
  1830. ok_man: "\ud83d\ude46&zwj;\u2642\ufe0f",
  1831. ok_woman: "\ud83d\ude46",
  1832. old_key: "\ud83d\udddd",
  1833. older_man: "\ud83d\udc74",
  1834. older_woman: "\ud83d\udc75",
  1835. om: "\ud83d\udd49",
  1836. on: "\ud83d\udd1b",
  1837. oncoming_automobile: "\ud83d\ude98",
  1838. oncoming_bus: "\ud83d\ude8d",
  1839. oncoming_police_car: "\ud83d\ude94",
  1840. oncoming_taxi: "\ud83d\ude96",
  1841. open_file_folder: "\ud83d\udcc2",
  1842. open_hands: "\ud83d\udc50",
  1843. open_mouth: "\ud83d\ude2e",
  1844. open_umbrella: "\u2602\ufe0f",
  1845. ophiuchus: "\u26ce",
  1846. orange_book: "\ud83d\udcd9",
  1847. orthodox_cross: "\u2626\ufe0f",
  1848. outbox_tray: "\ud83d\udce4",
  1849. owl: "\ud83e\udd89",
  1850. ox: "\ud83d\udc02",
  1851. package: "\ud83d\udce6",
  1852. page_facing_up: "\ud83d\udcc4",
  1853. page_with_curl: "\ud83d\udcc3",
  1854. pager: "\ud83d\udcdf",
  1855. paintbrush: "\ud83d\udd8c",
  1856. palm_tree: "\ud83c\udf34",
  1857. pancakes: "\ud83e\udd5e",
  1858. panda_face: "\ud83d\udc3c",
  1859. paperclip: "\ud83d\udcce",
  1860. paperclips: "\ud83d\udd87",
  1861. parasol_on_ground: "\u26f1",
  1862. parking: "\ud83c\udd7f\ufe0f",
  1863. part_alternation_mark: "\u303d\ufe0f",
  1864. partly_sunny: "\u26c5\ufe0f",
  1865. passenger_ship: "\ud83d\udef3",
  1866. passport_control: "\ud83d\udec2",
  1867. pause_button: "\u23f8",
  1868. peace_symbol: "\u262e\ufe0f",
  1869. peach: "\ud83c\udf51",
  1870. peanuts: "\ud83e\udd5c",
  1871. pear: "\ud83c\udf50",
  1872. pen: "\ud83d\udd8a",
  1873. pencil2: "\u270f\ufe0f",
  1874. penguin: "\ud83d\udc27",
  1875. pensive: "\ud83d\ude14",
  1876. performing_arts: "\ud83c\udfad",
  1877. persevere: "\ud83d\ude23",
  1878. person_fencing: "\ud83e\udd3a",
  1879. pouting_woman: "\ud83d\ude4e",
  1880. phone: "\u260e\ufe0f",
  1881. pick: "\u26cf",
  1882. pig: "\ud83d\udc37",
  1883. pig2: "\ud83d\udc16",
  1884. pig_nose: "\ud83d\udc3d",
  1885. pill: "\ud83d\udc8a",
  1886. pineapple: "\ud83c\udf4d",
  1887. ping_pong: "\ud83c\udfd3",
  1888. pisces: "\u2653\ufe0f",
  1889. pizza: "\ud83c\udf55",
  1890. place_of_worship: "\ud83d\uded0",
  1891. plate_with_cutlery: "\ud83c\udf7d",
  1892. play_or_pause_button: "\u23ef",
  1893. point_down: "\ud83d\udc47",
  1894. point_left: "\ud83d\udc48",
  1895. point_right: "\ud83d\udc49",
  1896. point_up: "\u261d\ufe0f",
  1897. point_up_2: "\ud83d\udc46",
  1898. police_car: "\ud83d\ude93",
  1899. policewoman: "\ud83d\udc6e&zwj;\u2640\ufe0f",
  1900. poodle: "\ud83d\udc29",
  1901. popcorn: "\ud83c\udf7f",
  1902. post_office: "\ud83c\udfe3",
  1903. postal_horn: "\ud83d\udcef",
  1904. postbox: "\ud83d\udcee",
  1905. potable_water: "\ud83d\udeb0",
  1906. potato: "\ud83e\udd54",
  1907. pouch: "\ud83d\udc5d",
  1908. poultry_leg: "\ud83c\udf57",
  1909. pound: "\ud83d\udcb7",
  1910. rage: "\ud83d\ude21",
  1911. pouting_cat: "\ud83d\ude3e",
  1912. pouting_man: "\ud83d\ude4e&zwj;\u2642\ufe0f",
  1913. pray: "\ud83d\ude4f",
  1914. prayer_beads: "\ud83d\udcff",
  1915. pregnant_woman: "\ud83e\udd30",
  1916. previous_track_button: "\u23ee",
  1917. prince: "\ud83e\udd34",
  1918. princess: "\ud83d\udc78",
  1919. printer: "\ud83d\udda8",
  1920. purple_heart: "\ud83d\udc9c",
  1921. purse: "\ud83d\udc5b",
  1922. pushpin: "\ud83d\udccc",
  1923. put_litter_in_its_place: "\ud83d\udeae",
  1924. question: "\u2753",
  1925. rabbit: "\ud83d\udc30",
  1926. rabbit2: "\ud83d\udc07",
  1927. racehorse: "\ud83d\udc0e",
  1928. racing_car: "\ud83c\udfce",
  1929. radio: "\ud83d\udcfb",
  1930. radio_button: "\ud83d\udd18",
  1931. radioactive: "\u2622\ufe0f",
  1932. railway_car: "\ud83d\ude83",
  1933. railway_track: "\ud83d\udee4",
  1934. rainbow: "\ud83c\udf08",
  1935. rainbow_flag: "\ud83c\udff3\ufe0f&zwj;\ud83c\udf08",
  1936. raised_back_of_hand: "\ud83e\udd1a",
  1937. raised_hand_with_fingers_splayed: "\ud83d\udd90",
  1938. raised_hands: "\ud83d\ude4c",
  1939. raising_hand_woman: "\ud83d\ude4b",
  1940. raising_hand_man: "\ud83d\ude4b&zwj;\u2642\ufe0f",
  1941. ram: "\ud83d\udc0f",
  1942. ramen: "\ud83c\udf5c",
  1943. rat: "\ud83d\udc00",
  1944. record_button: "\u23fa",
  1945. recycle: "\u267b\ufe0f",
  1946. red_circle: "\ud83d\udd34",
  1947. registered: "\u00ae\ufe0f",
  1948. relaxed: "\u263a\ufe0f",
  1949. relieved: "\ud83d\ude0c",
  1950. reminder_ribbon: "\ud83c\udf97",
  1951. repeat: "\ud83d\udd01",
  1952. repeat_one: "\ud83d\udd02",
  1953. rescue_worker_helmet: "\u26d1",
  1954. restroom: "\ud83d\udebb",
  1955. revolving_hearts: "\ud83d\udc9e",
  1956. rewind: "\u23ea",
  1957. rhinoceros: "\ud83e\udd8f",
  1958. ribbon: "\ud83c\udf80",
  1959. rice: "\ud83c\udf5a",
  1960. rice_ball: "\ud83c\udf59",
  1961. rice_cracker: "\ud83c\udf58",
  1962. rice_scene: "\ud83c\udf91",
  1963. right_anger_bubble: "\ud83d\uddef",
  1964. ring: "\ud83d\udc8d",
  1965. robot: "\ud83e\udd16",
  1966. rocket: "\ud83d\ude80",
  1967. rofl: "\ud83e\udd23",
  1968. roll_eyes: "\ud83d\ude44",
  1969. roller_coaster: "\ud83c\udfa2",
  1970. rooster: "\ud83d\udc13",
  1971. rose: "\ud83c\udf39",
  1972. rosette: "\ud83c\udff5",
  1973. rotating_light: "\ud83d\udea8",
  1974. round_pushpin: "\ud83d\udccd",
  1975. rowing_man: "\ud83d\udea3",
  1976. rowing_woman: "\ud83d\udea3&zwj;\u2640\ufe0f",
  1977. rugby_football: "\ud83c\udfc9",
  1978. running_man: "\ud83c\udfc3",
  1979. running_shirt_with_sash: "\ud83c\udfbd",
  1980. running_woman: "\ud83c\udfc3&zwj;\u2640\ufe0f",
  1981. sa: "\ud83c\ude02\ufe0f",
  1982. sagittarius: "\u2650\ufe0f",
  1983. sake: "\ud83c\udf76",
  1984. sandal: "\ud83d\udc61",
  1985. santa: "\ud83c\udf85",
  1986. satellite: "\ud83d\udce1",
  1987. saxophone: "\ud83c\udfb7",
  1988. school: "\ud83c\udfeb",
  1989. school_satchel: "\ud83c\udf92",
  1990. scissors: "\u2702\ufe0f",
  1991. scorpion: "\ud83e\udd82",
  1992. scorpius: "\u264f\ufe0f",
  1993. scream: "\ud83d\ude31",
  1994. scream_cat: "\ud83d\ude40",
  1995. scroll: "\ud83d\udcdc",
  1996. seat: "\ud83d\udcba",
  1997. secret: "\u3299\ufe0f",
  1998. see_no_evil: "\ud83d\ude48",
  1999. seedling: "\ud83c\udf31",
  2000. selfie: "\ud83e\udd33",
  2001. shallow_pan_of_food: "\ud83e\udd58",
  2002. shamrock: "\u2618\ufe0f",
  2003. shark: "\ud83e\udd88",
  2004. shaved_ice: "\ud83c\udf67",
  2005. sheep: "\ud83d\udc11",
  2006. shell: "\ud83d\udc1a",
  2007. shield: "\ud83d\udee1",
  2008. shinto_shrine: "\u26e9",
  2009. ship: "\ud83d\udea2",
  2010. shirt: "\ud83d\udc55",
  2011. shopping: "\ud83d\udecd",
  2012. shopping_cart: "\ud83d\uded2",
  2013. shower: "\ud83d\udebf",
  2014. shrimp: "\ud83e\udd90",
  2015. signal_strength: "\ud83d\udcf6",
  2016. six_pointed_star: "\ud83d\udd2f",
  2017. ski: "\ud83c\udfbf",
  2018. skier: "\u26f7",
  2019. skull: "\ud83d\udc80",
  2020. skull_and_crossbones: "\u2620\ufe0f",
  2021. sleeping: "\ud83d\ude34",
  2022. sleeping_bed: "\ud83d\udecc",
  2023. sleepy: "\ud83d\ude2a",
  2024. slightly_frowning_face: "\ud83d\ude41",
  2025. slightly_smiling_face: "\ud83d\ude42",
  2026. slot_machine: "\ud83c\udfb0",
  2027. small_airplane: "\ud83d\udee9",
  2028. small_blue_diamond: "\ud83d\udd39",
  2029. small_orange_diamond: "\ud83d\udd38",
  2030. small_red_triangle: "\ud83d\udd3a",
  2031. small_red_triangle_down: "\ud83d\udd3b",
  2032. smile: "\ud83d\ude04",
  2033. smile_cat: "\ud83d\ude38",
  2034. smiley: "\ud83d\ude03",
  2035. smiley_cat: "\ud83d\ude3a",
  2036. smiling_imp: "\ud83d\ude08",
  2037. smirk: "\ud83d\ude0f",
  2038. smirk_cat: "\ud83d\ude3c",
  2039. smoking: "\ud83d\udeac",
  2040. snail: "\ud83d\udc0c",
  2041. snake: "\ud83d\udc0d",
  2042. sneezing_face: "\ud83e\udd27",
  2043. snowboarder: "\ud83c\udfc2",
  2044. snowflake: "\u2744\ufe0f",
  2045. snowman: "\u26c4\ufe0f",
  2046. snowman_with_snow: "\u2603\ufe0f",
  2047. sob: "\ud83d\ude2d",
  2048. soccer: "\u26bd\ufe0f",
  2049. soon: "\ud83d\udd1c",
  2050. sos: "\ud83c\udd98",
  2051. sound: "\ud83d\udd09",
  2052. space_invader: "\ud83d\udc7e",
  2053. spades: "\u2660\ufe0f",
  2054. spaghetti: "\ud83c\udf5d",
  2055. sparkle: "\u2747\ufe0f",
  2056. sparkler: "\ud83c\udf87",
  2057. sparkles: "\u2728",
  2058. sparkling_heart: "\ud83d\udc96",
  2059. speak_no_evil: "\ud83d\ude4a",
  2060. speaker: "\ud83d\udd08",
  2061. speaking_head: "\ud83d\udde3",
  2062. speech_balloon: "\ud83d\udcac",
  2063. speedboat: "\ud83d\udea4",
  2064. spider: "\ud83d\udd77",
  2065. spider_web: "\ud83d\udd78",
  2066. spiral_calendar: "\ud83d\uddd3",
  2067. spiral_notepad: "\ud83d\uddd2",
  2068. spoon: "\ud83e\udd44",
  2069. squid: "\ud83e\udd91",
  2070. stadium: "\ud83c\udfdf",
  2071. star: "\u2b50\ufe0f",
  2072. star2: "\ud83c\udf1f",
  2073. star_and_crescent: "\u262a\ufe0f",
  2074. star_of_david: "\u2721\ufe0f",
  2075. stars: "\ud83c\udf20",
  2076. station: "\ud83d\ude89",
  2077. statue_of_liberty: "\ud83d\uddfd",
  2078. steam_locomotive: "\ud83d\ude82",
  2079. stew: "\ud83c\udf72",
  2080. stop_button: "\u23f9",
  2081. stop_sign: "\ud83d\uded1",
  2082. stopwatch: "\u23f1",
  2083. straight_ruler: "\ud83d\udccf",
  2084. strawberry: "\ud83c\udf53",
  2085. stuck_out_tongue: "\ud83d\ude1b",
  2086. stuck_out_tongue_closed_eyes: "\ud83d\ude1d",
  2087. stuck_out_tongue_winking_eye: "\ud83d\ude1c",
  2088. studio_microphone: "\ud83c\udf99",
  2089. stuffed_flatbread: "\ud83e\udd59",
  2090. sun_behind_large_cloud: "\ud83c\udf25",
  2091. sun_behind_rain_cloud: "\ud83c\udf26",
  2092. sun_behind_small_cloud: "\ud83c\udf24",
  2093. sun_with_face: "\ud83c\udf1e",
  2094. sunflower: "\ud83c\udf3b",
  2095. sunglasses: "\ud83d\ude0e",
  2096. sunny: "\u2600\ufe0f",
  2097. sunrise: "\ud83c\udf05",
  2098. sunrise_over_mountains: "\ud83c\udf04",
  2099. surfing_man: "\ud83c\udfc4",
  2100. surfing_woman: "\ud83c\udfc4&zwj;\u2640\ufe0f",
  2101. sushi: "\ud83c\udf63",
  2102. suspension_railway: "\ud83d\ude9f",
  2103. sweat: "\ud83d\ude13",
  2104. sweat_drops: "\ud83d\udca6",
  2105. sweat_smile: "\ud83d\ude05",
  2106. sweet_potato: "\ud83c\udf60",
  2107. swimming_man: "\ud83c\udfca",
  2108. swimming_woman: "\ud83c\udfca&zwj;\u2640\ufe0f",
  2109. symbols: "\ud83d\udd23",
  2110. synagogue: "\ud83d\udd4d",
  2111. syringe: "\ud83d\udc89",
  2112. taco: "\ud83c\udf2e",
  2113. tada: "\ud83c\udf89",
  2114. tanabata_tree: "\ud83c\udf8b",
  2115. taurus: "\u2649\ufe0f",
  2116. taxi: "\ud83d\ude95",
  2117. tea: "\ud83c\udf75",
  2118. telephone_receiver: "\ud83d\udcde",
  2119. telescope: "\ud83d\udd2d",
  2120. tennis: "\ud83c\udfbe",
  2121. tent: "\u26fa\ufe0f",
  2122. thermometer: "\ud83c\udf21",
  2123. thinking: "\ud83e\udd14",
  2124. thought_balloon: "\ud83d\udcad",
  2125. ticket: "\ud83c\udfab",
  2126. tickets: "\ud83c\udf9f",
  2127. tiger: "\ud83d\udc2f",
  2128. tiger2: "\ud83d\udc05",
  2129. timer_clock: "\u23f2",
  2130. tipping_hand_man: "\ud83d\udc81&zwj;\u2642\ufe0f",
  2131. tired_face: "\ud83d\ude2b",
  2132. tm: "\u2122\ufe0f",
  2133. toilet: "\ud83d\udebd",
  2134. tokyo_tower: "\ud83d\uddfc",
  2135. tomato: "\ud83c\udf45",
  2136. tongue: "\ud83d\udc45",
  2137. top: "\ud83d\udd1d",
  2138. tophat: "\ud83c\udfa9",
  2139. tornado: "\ud83c\udf2a",
  2140. trackball: "\ud83d\uddb2",
  2141. tractor: "\ud83d\ude9c",
  2142. traffic_light: "\ud83d\udea5",
  2143. train: "\ud83d\ude8b",
  2144. train2: "\ud83d\ude86",
  2145. tram: "\ud83d\ude8a",
  2146. triangular_flag_on_post: "\ud83d\udea9",
  2147. triangular_ruler: "\ud83d\udcd0",
  2148. trident: "\ud83d\udd31",
  2149. triumph: "\ud83d\ude24",
  2150. trolleybus: "\ud83d\ude8e",
  2151. trophy: "\ud83c\udfc6",
  2152. tropical_drink: "\ud83c\udf79",
  2153. tropical_fish: "\ud83d\udc20",
  2154. truck: "\ud83d\ude9a",
  2155. trumpet: "\ud83c\udfba",
  2156. tulip: "\ud83c\udf37",
  2157. tumbler_glass: "\ud83e\udd43",
  2158. turkey: "\ud83e\udd83",
  2159. turtle: "\ud83d\udc22",
  2160. tv: "\ud83d\udcfa",
  2161. twisted_rightwards_arrows: "\ud83d\udd00",
  2162. two_hearts: "\ud83d\udc95",
  2163. two_men_holding_hands: "\ud83d\udc6c",
  2164. two_women_holding_hands: "\ud83d\udc6d",
  2165. u5272: "\ud83c\ude39",
  2166. u5408: "\ud83c\ude34",
  2167. u55b6: "\ud83c\ude3a",
  2168. u6307: "\ud83c\ude2f\ufe0f",
  2169. u6708: "\ud83c\ude37\ufe0f",
  2170. u6709: "\ud83c\ude36",
  2171. u6e80: "\ud83c\ude35",
  2172. u7121: "\ud83c\ude1a\ufe0f",
  2173. u7533: "\ud83c\ude38",
  2174. u7981: "\ud83c\ude32",
  2175. u7a7a: "\ud83c\ude33",
  2176. umbrella: "\u2614\ufe0f",
  2177. unamused: "\ud83d\ude12",
  2178. underage: "\ud83d\udd1e",
  2179. unicorn: "\ud83e\udd84",
  2180. unlock: "\ud83d\udd13",
  2181. up: "\ud83c\udd99",
  2182. upside_down_face: "\ud83d\ude43",
  2183. v: "\u270c\ufe0f",
  2184. vertical_traffic_light: "\ud83d\udea6",
  2185. vhs: "\ud83d\udcfc",
  2186. vibration_mode: "\ud83d\udcf3",
  2187. video_camera: "\ud83d\udcf9",
  2188. video_game: "\ud83c\udfae",
  2189. violin: "\ud83c\udfbb",
  2190. virgo: "\u264d\ufe0f",
  2191. volcano: "\ud83c\udf0b",
  2192. volleyball: "\ud83c\udfd0",
  2193. vs: "\ud83c\udd9a",
  2194. vulcan_salute: "\ud83d\udd96",
  2195. walking_man: "\ud83d\udeb6",
  2196. walking_woman: "\ud83d\udeb6&zwj;\u2640\ufe0f",
  2197. waning_crescent_moon: "\ud83c\udf18",
  2198. waning_gibbous_moon: "\ud83c\udf16",
  2199. warning: "\u26a0\ufe0f",
  2200. wastebasket: "\ud83d\uddd1",
  2201. watch: "\u231a\ufe0f",
  2202. water_buffalo: "\ud83d\udc03",
  2203. watermelon: "\ud83c\udf49",
  2204. wave: "\ud83d\udc4b",
  2205. wavy_dash: "\u3030\ufe0f",
  2206. waxing_crescent_moon: "\ud83c\udf12",
  2207. wc: "\ud83d\udebe",
  2208. weary: "\ud83d\ude29",
  2209. wedding: "\ud83d\udc92",
  2210. weight_lifting_man: "\ud83c\udfcb\ufe0f",
  2211. weight_lifting_woman: "\ud83c\udfcb\ufe0f&zwj;\u2640\ufe0f",
  2212. whale: "\ud83d\udc33",
  2213. whale2: "\ud83d\udc0b",
  2214. wheel_of_dharma: "\u2638\ufe0f",
  2215. wheelchair: "\u267f\ufe0f",
  2216. white_check_mark: "\u2705",
  2217. white_circle: "\u26aa\ufe0f",
  2218. white_flag: "\ud83c\udff3\ufe0f",
  2219. white_flower: "\ud83d\udcae",
  2220. white_large_square: "\u2b1c\ufe0f",
  2221. white_medium_small_square: "\u25fd\ufe0f",
  2222. white_medium_square: "\u25fb\ufe0f",
  2223. white_small_square: "\u25ab\ufe0f",
  2224. white_square_button: "\ud83d\udd33",
  2225. wilted_flower: "\ud83e\udd40",
  2226. wind_chime: "\ud83c\udf90",
  2227. wind_face: "\ud83c\udf2c",
  2228. wine_glass: "\ud83c\udf77",
  2229. wink: "\ud83d\ude09",
  2230. wolf: "\ud83d\udc3a",
  2231. woman: "\ud83d\udc69",
  2232. woman_artist: "\ud83d\udc69&zwj;\ud83c\udfa8",
  2233. woman_astronaut: "\ud83d\udc69&zwj;\ud83d\ude80",
  2234. woman_cartwheeling: "\ud83e\udd38&zwj;\u2640\ufe0f",
  2235. woman_cook: "\ud83d\udc69&zwj;\ud83c\udf73",
  2236. woman_facepalming: "\ud83e\udd26&zwj;\u2640\ufe0f",
  2237. woman_factory_worker: "\ud83d\udc69&zwj;\ud83c\udfed",
  2238. woman_farmer: "\ud83d\udc69&zwj;\ud83c\udf3e",
  2239. woman_firefighter: "\ud83d\udc69&zwj;\ud83d\ude92",
  2240. woman_health_worker: "\ud83d\udc69&zwj;\u2695\ufe0f",
  2241. woman_judge: "\ud83d\udc69&zwj;\u2696\ufe0f",
  2242. woman_juggling: "\ud83e\udd39&zwj;\u2640\ufe0f",
  2243. woman_mechanic: "\ud83d\udc69&zwj;\ud83d\udd27",
  2244. woman_office_worker: "\ud83d\udc69&zwj;\ud83d\udcbc",
  2245. woman_pilot: "\ud83d\udc69&zwj;\u2708\ufe0f",
  2246. woman_playing_handball: "\ud83e\udd3e&zwj;\u2640\ufe0f",
  2247. woman_playing_water_polo: "\ud83e\udd3d&zwj;\u2640\ufe0f",
  2248. woman_scientist: "\ud83d\udc69&zwj;\ud83d\udd2c",
  2249. woman_shrugging: "\ud83e\udd37&zwj;\u2640\ufe0f",
  2250. woman_singer: "\ud83d\udc69&zwj;\ud83c\udfa4",
  2251. woman_student: "\ud83d\udc69&zwj;\ud83c\udf93",
  2252. woman_teacher: "\ud83d\udc69&zwj;\ud83c\udfeb",
  2253. woman_technologist: "\ud83d\udc69&zwj;\ud83d\udcbb",
  2254. woman_with_turban: "\ud83d\udc73&zwj;\u2640\ufe0f",
  2255. womans_clothes: "\ud83d\udc5a",
  2256. womans_hat: "\ud83d\udc52",
  2257. women_wrestling: "\ud83e\udd3c&zwj;\u2640\ufe0f",
  2258. womens: "\ud83d\udeba",
  2259. world_map: "\ud83d\uddfa",
  2260. worried: "\ud83d\ude1f",
  2261. wrench: "\ud83d\udd27",
  2262. writing_hand: "\u270d\ufe0f",
  2263. x: "\u274c",
  2264. yellow_heart: "\ud83d\udc9b",
  2265. yen: "\ud83d\udcb4",
  2266. yin_yang: "\u262f\ufe0f",
  2267. yum: "\ud83d\ude0b",
  2268. zap: "\u26a1\ufe0f",
  2269. zipper_mouth_face: "\ud83e\udd10",
  2270. zzz: "\ud83d\udca4",
  2271.  
  2272. /* special emojis :P */
  2273. octocat:
  2274. '<img alt=":octocat:" height="20" width="20" align="absmiddle" src="https://assets-cdn.github.com/images/icons/emoji/octocat.png">',
  2275. showdown:
  2276. "<span style=\"font-family: 'Anonymous Pro', monospace; text-decoration: underline; text-decoration-style: dashed; text-decoration-color: #3e8b8a;text-underline-position: under;\">S</span>",
  2277. };
  2278.  
  2279. /**
  2280. * Created by Estevao on 31-05-2015.
  2281. */
  2282.  
  2283. /**
  2284. * Showdown Converter class
  2285. * @class
  2286. * @param {object} [converterOptions]
  2287. * @returns {Converter}
  2288. */
  2289. showdown.Converter = function (converterOptions) {
  2290. "use strict";
  2291.  
  2292. var /**
  2293. * Options used by this converter
  2294. * @private
  2295. * @type {{}}
  2296. */
  2297. options = {},
  2298. /**
  2299. * Language extensions used by this converter
  2300. * @private
  2301. * @type {Array}
  2302. */
  2303. langExtensions = [],
  2304. /**
  2305. * Output modifiers extensions used by this converter
  2306. * @private
  2307. * @type {Array}
  2308. */
  2309. outputModifiers = [],
  2310. /**
  2311. * Event listeners
  2312. * @private
  2313. * @type {{}}
  2314. */
  2315. listeners = {},
  2316. /**
  2317. * The flavor set in this converter
  2318. */
  2319. setConvFlavor = setFlavor,
  2320. /**
  2321. * Metadata of the document
  2322. * @type {{parsed: {}, raw: string, format: string}}
  2323. */
  2324. metadata = {
  2325. parsed: {},
  2326. raw: "",
  2327. format: "",
  2328. };
  2329.  
  2330. _constructor();
  2331.  
  2332. /**
  2333. * Converter constructor
  2334. * @private
  2335. */
  2336. function _constructor() {
  2337. converterOptions = converterOptions || {};
  2338.  
  2339. for (var gOpt in globalOptions) {
  2340. if (globalOptions.hasOwnProperty(gOpt)) {
  2341. options[gOpt] = globalOptions[gOpt];
  2342. }
  2343. }
  2344.  
  2345. // Merge options
  2346. if (typeof converterOptions === "object") {
  2347. for (var opt in converterOptions) {
  2348. if (converterOptions.hasOwnProperty(opt)) {
  2349. options[opt] = converterOptions[opt];
  2350. }
  2351. }
  2352. } else {
  2353. throw Error(
  2354. "Converter expects the passed parameter to be an object, but " +
  2355. typeof converterOptions +
  2356. " was passed instead."
  2357. );
  2358. }
  2359.  
  2360. if (options.extensions) {
  2361. showdown.helper.forEach(options.extensions, _parseExtension);
  2362. }
  2363. }
  2364.  
  2365. /**
  2366. * Parse extension
  2367. * @param {*} ext
  2368. * @param {string} [name='']
  2369. * @private
  2370. */
  2371. function _parseExtension(ext, name) {
  2372. name = name || null;
  2373. // If it's a string, the extension was previously loaded
  2374. if (showdown.helper.isString(ext)) {
  2375. ext = showdown.helper.stdExtName(ext);
  2376. name = ext;
  2377.  
  2378. // LEGACY_SUPPORT CODE
  2379. if (showdown.extensions[ext]) {
  2380. console.warn(
  2381. "DEPRECATION WARNING: " +
  2382. ext +
  2383. " is an old extension that uses a deprecated loading method." +
  2384. "Please inform the developer that the extension should be updated!"
  2385. );
  2386. legacyExtensionLoading(showdown.extensions[ext], ext);
  2387. return;
  2388. // END LEGACY SUPPORT CODE
  2389. } else if (!showdown.helper.isUndefined(extensions[ext])) {
  2390. ext = extensions[ext];
  2391. } else {
  2392. throw Error(
  2393. 'Extension "' +
  2394. ext +
  2395. '" could not be loaded. It was either not found or is not a valid extension.'
  2396. );
  2397. }
  2398. }
  2399.  
  2400. if (typeof ext === "function") {
  2401. ext = ext();
  2402. }
  2403.  
  2404. if (!showdown.helper.isArray(ext)) {
  2405. ext = [ext];
  2406. }
  2407.  
  2408. var validExt = validate(ext, name);
  2409. if (!validExt.valid) {
  2410. throw Error(validExt.error);
  2411. }
  2412.  
  2413. for (var i = 0; i < ext.length; ++i) {
  2414. switch (ext[i].type) {
  2415. case "lang":
  2416. langExtensions.push(ext[i]);
  2417. break;
  2418.  
  2419. case "output":
  2420. outputModifiers.push(ext[i]);
  2421. break;
  2422. }
  2423. if (ext[i].hasOwnProperty("listeners")) {
  2424. for (var ln in ext[i].listeners) {
  2425. if (ext[i].listeners.hasOwnProperty(ln)) {
  2426. listen(ln, ext[i].listeners[ln]);
  2427. }
  2428. }
  2429. }
  2430. }
  2431. }
  2432.  
  2433. /**
  2434. * LEGACY_SUPPORT
  2435. * @param {*} ext
  2436. * @param {string} name
  2437. */
  2438. function legacyExtensionLoading(ext, name) {
  2439. if (typeof ext === "function") {
  2440. ext = ext(new showdown.Converter());
  2441. }
  2442. if (!showdown.helper.isArray(ext)) {
  2443. ext = [ext];
  2444. }
  2445. var valid = validate(ext, name);
  2446.  
  2447. if (!valid.valid) {
  2448. throw Error(valid.error);
  2449. }
  2450.  
  2451. for (var i = 0; i < ext.length; ++i) {
  2452. switch (ext[i].type) {
  2453. case "lang":
  2454. langExtensions.push(ext[i]);
  2455. break;
  2456. case "output":
  2457. outputModifiers.push(ext[i]);
  2458. break;
  2459. default: // should never reach here
  2460. throw Error("Extension loader error: Type unrecognized!!!");
  2461. }
  2462. }
  2463. }
  2464.  
  2465. /**
  2466. * Listen to an event
  2467. * @param {string} name
  2468. * @param {function} callback
  2469. */
  2470. function listen(name, callback) {
  2471. if (!showdown.helper.isString(name)) {
  2472. throw Error(
  2473. "Invalid argument in converter.listen() method: name must be a string, but " +
  2474. typeof name +
  2475. " given"
  2476. );
  2477. }
  2478.  
  2479. if (typeof callback !== "function") {
  2480. throw Error(
  2481. "Invalid argument in converter.listen() method: callback must be a function, but " +
  2482. typeof callback +
  2483. " given"
  2484. );
  2485. }
  2486.  
  2487. if (!listeners.hasOwnProperty(name)) {
  2488. listeners[name] = [];
  2489. }
  2490. listeners[name].push(callback);
  2491. }
  2492.  
  2493. function rTrimInputText(text) {
  2494. var rsp = text.match(/^\s*/)[0].length,
  2495. rgx = new RegExp("^\\s{0," + rsp + "}", "gm");
  2496. return text.replace(rgx, "");
  2497. }
  2498.  
  2499. /**
  2500. * Dispatch an event
  2501. * @private
  2502. * @param {string} evtName Event name
  2503. * @param {string} text Text
  2504. * @param {{}} options Converter Options
  2505. * @param {{}} globals
  2506. * @returns {string}
  2507. */
  2508. this._dispatch = function dispatch(evtName, text, options, globals) {
  2509. if (listeners.hasOwnProperty(evtName)) {
  2510. for (var ei = 0; ei < listeners[evtName].length; ++ei) {
  2511. var nText = listeners[evtName][ei](
  2512. evtName,
  2513. text,
  2514. this,
  2515. options,
  2516. globals
  2517. );
  2518. if (nText && typeof nText !== "undefined") {
  2519. text = nText;
  2520. }
  2521. }
  2522. }
  2523. return text;
  2524. };
  2525.  
  2526. /**
  2527. * Listen to an event
  2528. * @param {string} name
  2529. * @param {function} callback
  2530. * @returns {showdown.Converter}
  2531. */
  2532. this.listen = function (name, callback) {
  2533. listen(name, callback);
  2534. return this;
  2535. };
  2536.  
  2537. /**
  2538. * Converts a markdown string into HTML
  2539. * @param {string} text
  2540. * @returns {*}
  2541. */
  2542. this.makeHtml = function (text) {
  2543. //check if text is not falsy
  2544. if (!text) {
  2545. return text;
  2546. }
  2547.  
  2548. var globals = {
  2549. gHtmlBlocks: [],
  2550. gHtmlMdBlocks: [],
  2551. gHtmlSpans: [],
  2552. gUrls: {},
  2553. gTitles: {},
  2554. gDimensions: {},
  2555. gListLevel: 0,
  2556. hashLinkCounts: {},
  2557. langExtensions: langExtensions,
  2558. outputModifiers: outputModifiers,
  2559. converter: this,
  2560. ghCodeBlocks: [],
  2561. metadata: {
  2562. parsed: {},
  2563. raw: "",
  2564. format: "",
  2565. },
  2566. };
  2567.  
  2568. // This lets us use ¨ trema as an escape char to avoid md5 hashes
  2569. // The choice of character is arbitrary; anything that isn't
  2570. // magic in Markdown will work.
  2571. text = text.replace(/¨/g, "¨T");
  2572.  
  2573. // Replace $ with ¨D
  2574. // RegExp interprets $ as a special character
  2575. // when it's in a replacement string
  2576. text = text.replace(/\$/g, "¨D");
  2577.  
  2578. // Standardize line endings
  2579. text = text.replace(/\r\n/g, "\n"); // DOS to Unix
  2580. text = text.replace(/\r/g, "\n"); // Mac to Unix
  2581.  
  2582. // Stardardize line spaces
  2583. text = text.replace(/\u00A0/g, "&nbsp;");
  2584.  
  2585. if (options.smartIndentationFix) {
  2586. text = rTrimInputText(text);
  2587. }
  2588.  
  2589. // Make sure text begins and ends with a couple of newlines:
  2590. text = "\n\n" + text + "\n\n";
  2591.  
  2592. // detab
  2593. text = showdown.subParser("detab")(text, options, globals);
  2594.  
  2595. /**
  2596. * Strip any lines consisting only of spaces and tabs.
  2597. * This makes subsequent regexs easier to write, because we can
  2598. * match consecutive blank lines with /\n+/ instead of something
  2599. * contorted like /[ \t]*\n+/
  2600. */
  2601. text = text.replace(/^[ \t]+$/gm, "");
  2602.  
  2603. //run languageExtensions
  2604. showdown.helper.forEach(langExtensions, function (ext) {
  2605. text = showdown.subParser("runExtension")(ext, text, options, globals);
  2606. });
  2607.  
  2608. // run the sub parsers
  2609. text = showdown.subParser("metadata")(text, options, globals);
  2610. text = showdown.subParser("hashPreCodeTags")(text, options, globals);
  2611. text = showdown.subParser("githubCodeBlocks")(text, options, globals);
  2612. text = showdown.subParser("hashHTMLBlocks")(text, options, globals);
  2613. text = showdown.subParser("hashCodeTags")(text, options, globals);
  2614. text = showdown.subParser("stripLinkDefinitions")(text, options, globals);
  2615. text = showdown.subParser("blockGamut")(text, options, globals);
  2616. text = showdown.subParser("unhashHTMLSpans")(text, options, globals);
  2617. text = showdown.subParser("unescapeSpecialChars")(text, options, globals);
  2618.  
  2619. // attacklab: Restore dollar signs
  2620. text = text.replace(/¨D/g, "$$");
  2621.  
  2622. // attacklab: Restore tremas
  2623. text = text.replace(/¨T/g, "¨");
  2624.  
  2625. // render a complete html document instead of a partial if the option is enabled
  2626. text = showdown.subParser("completeHTMLDocument")(text, options, globals);
  2627.  
  2628. // Run output modifiers
  2629. showdown.helper.forEach(outputModifiers, function (ext) {
  2630. text = showdown.subParser("runExtension")(ext, text, options, globals);
  2631. });
  2632.  
  2633. // update metadata
  2634. metadata = globals.metadata;
  2635. return text;
  2636. };
  2637.  
  2638. /**
  2639. * Converts an HTML string into a markdown string
  2640. * @param src
  2641. * @param [HTMLParser] A WHATWG DOM and HTML parser, such as JSDOM. If none is supplied, window.document will be used.
  2642. * @returns {string}
  2643. */
  2644. this.makeMarkdown = this.makeMd = function (src, HTMLParser) {
  2645. // replace \r\n with \n
  2646. src = src.replace(/\r\n/g, "\n");
  2647. src = src.replace(/\r/g, "\n"); // old macs
  2648.  
  2649. // due to an edge case, we need to find this: > <
  2650. // to prevent removing of non silent white spaces
  2651. // ex: <em>this is</em> <strong>sparta</strong>
  2652. src = src.replace(/>[ \t]+</, ">¨NBSP;<");
  2653.  
  2654. if (!HTMLParser) {
  2655. if (window && window.document) {
  2656. HTMLParser = window.document;
  2657. } else {
  2658. throw new Error(
  2659. "HTMLParser is undefined. If in a webworker or nodejs environment, you need to provide a WHATWG DOM and HTML such as JSDOM"
  2660. );
  2661. }
  2662. }
  2663.  
  2664. var doc = HTMLParser.createElement("div");
  2665. doc.innerHTML = src;
  2666.  
  2667. var globals = {
  2668. preList: substitutePreCodeTags(doc),
  2669. };
  2670.  
  2671. // remove all newlines and collapse spaces
  2672. clean(doc);
  2673.  
  2674. // some stuff, like accidental reference links must now be escaped
  2675. // TODO
  2676. // doc.innerHTML = doc.innerHTML.replace(/\[[\S\t ]]/);
  2677.  
  2678. var nodes = doc.childNodes,
  2679. mdDoc = "";
  2680.  
  2681. for (var i = 0; i < nodes.length; i++) {
  2682. mdDoc += showdown.subParser("makeMarkdown.node")(nodes[i], globals);
  2683. }
  2684.  
  2685. function clean(node) {
  2686. for (var n = 0; n < node.childNodes.length; ++n) {
  2687. var child = node.childNodes[n];
  2688. if (child.nodeType === 3) {
  2689. if (
  2690. !/\S/.test(child.nodeValue) &&
  2691. !/^[ ]+$/.test(child.nodeValue)
  2692. ) {
  2693. node.removeChild(child);
  2694. --n;
  2695. } else {
  2696. child.nodeValue = child.nodeValue.split("\n").join(" ");
  2697. child.nodeValue = child.nodeValue.replace(/(\s)+/g, "$1");
  2698. }
  2699. } else if (child.nodeType === 1) {
  2700. clean(child);
  2701. }
  2702. }
  2703. }
  2704.  
  2705. // find all pre tags and replace contents with placeholder
  2706. // we need this so that we can remove all indentation from html
  2707. // to ease up parsing
  2708. function substitutePreCodeTags(doc) {
  2709. var pres = doc.querySelectorAll("pre"),
  2710. presPH = [];
  2711.  
  2712. for (var i = 0; i < pres.length; ++i) {
  2713. if (
  2714. pres[i].childElementCount === 1 &&
  2715. pres[i].firstChild.tagName.toLowerCase() === "code"
  2716. ) {
  2717. var content = pres[i].firstChild.innerHTML.trim(),
  2718. language = pres[i].firstChild.getAttribute("data-language") || "";
  2719.  
  2720. // if data-language attribute is not defined, then we look for class language-*
  2721. if (language === "") {
  2722. var classes = pres[i].firstChild.className.split(" ");
  2723. for (var c = 0; c < classes.length; ++c) {
  2724. var matches = classes[c].match(/^language-(.+)$/);
  2725. if (matches !== null) {
  2726. language = matches[1];
  2727. break;
  2728. }
  2729. }
  2730. }
  2731.  
  2732. // unescape html entities in content
  2733. content = showdown.helper.unescapeHTMLEntities(content);
  2734.  
  2735. presPH.push(content);
  2736. pres[i].outerHTML =
  2737. '<precode language="' +
  2738. language +
  2739. '" precodenum="' +
  2740. i.toString() +
  2741. '"></precode>';
  2742. } else {
  2743. presPH.push(pres[i].innerHTML);
  2744. pres[i].innerHTML = "";
  2745. pres[i].setAttribute("prenum", i.toString());
  2746. }
  2747. }
  2748. return presPH;
  2749. }
  2750.  
  2751. return mdDoc;
  2752. };
  2753.  
  2754. /**
  2755. * Set an option of this Converter instance
  2756. * @param {string} key
  2757. * @param {*} value
  2758. */
  2759. this.setOption = function (key, value) {
  2760. options[key] = value;
  2761. };
  2762.  
  2763. /**
  2764. * Get the option of this Converter instance
  2765. * @param {string} key
  2766. * @returns {*}
  2767. */
  2768. this.getOption = function (key) {
  2769. return options[key];
  2770. };
  2771.  
  2772. /**
  2773. * Get the options of this Converter instance
  2774. * @returns {{}}
  2775. */
  2776. this.getOptions = function () {
  2777. return options;
  2778. };
  2779.  
  2780. /**
  2781. * Add extension to THIS converter
  2782. * @param {{}} extension
  2783. * @param {string} [name=null]
  2784. */
  2785. this.addExtension = function (extension, name) {
  2786. name = name || null;
  2787. _parseExtension(extension, name);
  2788. };
  2789.  
  2790. /**
  2791. * Use a global registered extension with THIS converter
  2792. * @param {string} extensionName Name of the previously registered extension
  2793. */
  2794. this.useExtension = function (extensionName) {
  2795. _parseExtension(extensionName);
  2796. };
  2797.  
  2798. /**
  2799. * Set the flavor THIS converter should use
  2800. * @param {string} name
  2801. */
  2802. this.setFlavor = function (name) {
  2803. if (!flavor.hasOwnProperty(name)) {
  2804. throw Error(name + " flavor was not found");
  2805. }
  2806. var preset = flavor[name];
  2807. setConvFlavor = name;
  2808. for (var option in preset) {
  2809. if (preset.hasOwnProperty(option)) {
  2810. options[option] = preset[option];
  2811. }
  2812. }
  2813. };
  2814.  
  2815. /**
  2816. * Get the currently set flavor of this converter
  2817. * @returns {string}
  2818. */
  2819. this.getFlavor = function () {
  2820. return setConvFlavor;
  2821. };
  2822.  
  2823. /**
  2824. * Remove an extension from THIS converter.
  2825. * Note: This is a costly operation. It's better to initialize a new converter
  2826. * and specify the extensions you wish to use
  2827. * @param {Array} extension
  2828. */
  2829. this.removeExtension = function (extension) {
  2830. if (!showdown.helper.isArray(extension)) {
  2831. extension = [extension];
  2832. }
  2833. for (var a = 0; a < extension.length; ++a) {
  2834. var ext = extension[a];
  2835. for (var i = 0; i < langExtensions.length; ++i) {
  2836. if (langExtensions[i] === ext) {
  2837. langExtensions.splice(i, 1);
  2838. }
  2839. }
  2840. for (var ii = 0; ii < outputModifiers.length; ++ii) {
  2841. if (outputModifiers[ii] === ext) {
  2842. outputModifiers.splice(ii, 1);
  2843. }
  2844. }
  2845. }
  2846. };
  2847.  
  2848. /**
  2849. * Get all extension of THIS converter
  2850. * @returns {{language: Array, output: Array}}
  2851. */
  2852. this.getAllExtensions = function () {
  2853. return {
  2854. language: langExtensions,
  2855. output: outputModifiers,
  2856. };
  2857. };
  2858.  
  2859. /**
  2860. * Get the metadata of the previously parsed document
  2861. * @param raw
  2862. * @returns {string|{}}
  2863. */
  2864. this.getMetadata = function (raw) {
  2865. if (raw) {
  2866. return metadata.raw;
  2867. } else {
  2868. return metadata.parsed;
  2869. }
  2870. };
  2871.  
  2872. /**
  2873. * Get the metadata format of the previously parsed document
  2874. * @returns {string}
  2875. */
  2876. this.getMetadataFormat = function () {
  2877. return metadata.format;
  2878. };
  2879.  
  2880. /**
  2881. * Private: set a single key, value metadata pair
  2882. * @param {string} key
  2883. * @param {string} value
  2884. */
  2885. this._setMetadataPair = function (key, value) {
  2886. metadata.parsed[key] = value;
  2887. };
  2888.  
  2889. /**
  2890. * Private: set metadata format
  2891. * @param {string} format
  2892. */
  2893. this._setMetadataFormat = function (format) {
  2894. metadata.format = format;
  2895. };
  2896.  
  2897. /**
  2898. * Private: set metadata raw text
  2899. * @param {string} raw
  2900. */
  2901. this._setMetadataRaw = function (raw) {
  2902. metadata.raw = raw;
  2903. };
  2904. };
  2905.  
  2906. /**
  2907. * Turn Markdown link shortcuts into XHTML <a> tags.
  2908. */
  2909. showdown.subParser("anchors", function (text, options, globals) {
  2910. "use strict";
  2911.  
  2912. text = globals.converter._dispatch(
  2913. "anchors.before",
  2914. text,
  2915. options,
  2916. globals
  2917. );
  2918.  
  2919. var writeAnchorTag = function (
  2920. wholeMatch,
  2921. linkText,
  2922. linkId,
  2923. url,
  2924. m5,
  2925. m6,
  2926. title
  2927. ) {
  2928. if (showdown.helper.isUndefined(title)) {
  2929. title = "";
  2930. }
  2931. linkId = linkId.toLowerCase();
  2932.  
  2933. // Special case for explicit empty url
  2934. if (wholeMatch.search(/\(<?\s*>? ?(['"].*['"])?\)$/m) > -1) {
  2935. url = "";
  2936. } else if (!url) {
  2937. if (!linkId) {
  2938. // lower-case and turn embedded newlines into spaces
  2939. linkId = linkText.toLowerCase().replace(/ ?\n/g, " ");
  2940. }
  2941. url = "#" + linkId;
  2942.  
  2943. if (!showdown.helper.isUndefined(globals.gUrls[linkId])) {
  2944. url = globals.gUrls[linkId];
  2945. if (!showdown.helper.isUndefined(globals.gTitles[linkId])) {
  2946. title = globals.gTitles[linkId];
  2947. }
  2948. } else {
  2949. return wholeMatch;
  2950. }
  2951. }
  2952.  
  2953. //url = showdown.helper.escapeCharacters(url, '*_', false); // replaced line to improve performance
  2954. url = url.replace(
  2955. showdown.helper.regexes.asteriskDashAndColon,
  2956. showdown.helper.escapeCharactersCallback
  2957. );
  2958.  
  2959. var result = '<a href="' + url + '"';
  2960.  
  2961. if (title !== "" && title !== null) {
  2962. title = title.replace(/"/g, "&quot;");
  2963. //title = showdown.helper.escapeCharacters(title, '*_', false); // replaced line to improve performance
  2964. title = title.replace(
  2965. showdown.helper.regexes.asteriskDashAndColon,
  2966. showdown.helper.escapeCharactersCallback
  2967. );
  2968. result += ' title="' + title + '"';
  2969. }
  2970.  
  2971. // optionLinksInNewWindow only applies
  2972. // to external links. Hash links (#) open in same page
  2973. if (options.openLinksInNewWindow && !/^#/.test(url)) {
  2974. // escaped _
  2975. result += ' rel="noopener noreferrer" target="¨E95Eblank"';
  2976. }
  2977.  
  2978. result += ">" + linkText + "</a>";
  2979.  
  2980. return result;
  2981. };
  2982.  
  2983. // First, handle reference-style links: [link text] [id]
  2984. text = text.replace(
  2985. /\[((?:\[[^\]]*]|[^\[\]])*)] ?(?:\n *)?\[(.*?)]()()()()/g,
  2986. writeAnchorTag
  2987. );
  2988.  
  2989. // Next, inline-style links: [link text](url "optional title")
  2990. // cases with crazy urls like ./image/cat1).png
  2991. text = text.replace(
  2992. /\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]?<([^>]*)>(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g,
  2993. writeAnchorTag
  2994. );
  2995.  
  2996. // normal cases
  2997. text = text.replace(
  2998. /\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]?<?([\S]+?(?:\([\S]*?\)[\S]*?)?)>?(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g,
  2999. writeAnchorTag
  3000. );
  3001.  
  3002. // handle reference-style shortcuts: [link text]
  3003. // These must come last in case you've also got [link test][1]
  3004. // or [link test](/foo)
  3005. text = text.replace(/\[([^\[\]]+)]()()()()()/g, writeAnchorTag);
  3006.  
  3007. // Lastly handle GithubMentions if option is enabled
  3008. if (options.ghMentions) {
  3009. text = text.replace(
  3010. /(^|\s)(\\)?(@([a-z\d]+(?:[a-z\d.-]+?[a-z\d]+)*))/gim,
  3011. function (wm, st, escape, mentions, username) {
  3012. if (escape === "\\") {
  3013. return st + mentions;
  3014. }
  3015.  
  3016. //check if options.ghMentionsLink is a string
  3017. if (!showdown.helper.isString(options.ghMentionsLink)) {
  3018. throw new Error("ghMentionsLink option must be a string");
  3019. }
  3020. var lnk = options.ghMentionsLink.replace(/\{u}/g, username),
  3021. target = "";
  3022. if (options.openLinksInNewWindow) {
  3023. target = ' rel="noopener noreferrer" target="¨E95Eblank"';
  3024. }
  3025. return (
  3026. st + '<a href="' + lnk + '"' + target + ">" + mentions + "</a>"
  3027. );
  3028. }
  3029. );
  3030. }
  3031.  
  3032. text = globals.converter._dispatch("anchors.after", text, options, globals);
  3033. return text;
  3034. });
  3035.  
  3036. // url allowed chars [a-z\d_.~:/?#[]@!$&'()*+,;=-]
  3037.  
  3038. var simpleURLRegex =
  3039. /([*~_]+|\b)(((https?|ftp|dict):\/\/|www\.)[^'">\s]+?\.[^'">\s]+?)()(\1)?(?=\s|$)(?!["<>])/gi,
  3040. simpleURLRegex2 =
  3041. /([*~_]+|\b)(((https?|ftp|dict):\/\/|www\.)[^'">\s]+\.[^'">\s]+?)([.!?,()\[\]])?(\1)?(?=\s|$)(?!["<>])/gi,
  3042. delimUrlRegex = /()<(((https?|ftp|dict):\/\/|www\.)[^'">\s]+)()>()/gi,
  3043. simpleMailRegex =
  3044. /(^|\s)(?:mailto:)?([A-Za-z0-9!#$%&'*+-/=?^_`{|}~.]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)(?=$|\s)/gim,
  3045. delimMailRegex =
  3046. /<()(?:mailto:)?([-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi,
  3047. replaceLink = function (options) {
  3048. "use strict";
  3049. return function (
  3050. wm,
  3051. leadingMagicChars,
  3052. link,
  3053. m2,
  3054. m3,
  3055. trailingPunctuation,
  3056. trailingMagicChars
  3057. ) {
  3058. link = link.replace(
  3059. showdown.helper.regexes.asteriskDashAndColon,
  3060. showdown.helper.escapeCharactersCallback
  3061. );
  3062. var lnkTxt = link,
  3063. append = "",
  3064. target = "",
  3065. lmc = leadingMagicChars || "",
  3066. tmc = trailingMagicChars || "";
  3067. if (/^www\./i.test(link)) {
  3068. link = link.replace(/^www\./i, "http://www.");
  3069. }
  3070. if (options.excludeTrailingPunctuationFromURLs && trailingPunctuation) {
  3071. append = trailingPunctuation;
  3072. }
  3073. if (options.openLinksInNewWindow) {
  3074. target = ' rel="noopener noreferrer" target="¨E95Eblank"';
  3075. }
  3076. return (
  3077. lmc +
  3078. '<a href="' +
  3079. link +
  3080. '"' +
  3081. target +
  3082. ">" +
  3083. lnkTxt +
  3084. "</a>" +
  3085. append +
  3086. tmc
  3087. );
  3088. };
  3089. },
  3090. replaceMail = function (options, globals) {
  3091. "use strict";
  3092. return function (wholeMatch, b, mail) {
  3093. var href = "mailto:";
  3094. b = b || "";
  3095. mail = showdown.subParser("unescapeSpecialChars")(
  3096. mail,
  3097. options,
  3098. globals
  3099. );
  3100. if (options.encodeEmails) {
  3101. href = showdown.helper.encodeEmailAddress(href + mail);
  3102. mail = showdown.helper.encodeEmailAddress(mail);
  3103. } else {
  3104. href = href + mail;
  3105. }
  3106. return b + '<a href="' + href + '">' + mail + "</a>";
  3107. };
  3108. };
  3109.  
  3110. showdown.subParser("autoLinks", function (text, options, globals) {
  3111. "use strict";
  3112.  
  3113. text = globals.converter._dispatch(
  3114. "autoLinks.before",
  3115. text,
  3116. options,
  3117. globals
  3118. );
  3119.  
  3120. text = text.replace(delimUrlRegex, replaceLink(options));
  3121. text = text.replace(delimMailRegex, replaceMail(options, globals));
  3122.  
  3123. text = globals.converter._dispatch(
  3124. "autoLinks.after",
  3125. text,
  3126. options,
  3127. globals
  3128. );
  3129.  
  3130. return text;
  3131. });
  3132.  
  3133. showdown.subParser("simplifiedAutoLinks", function (text, options, globals) {
  3134. "use strict";
  3135.  
  3136. if (!options.simplifiedAutoLink) {
  3137. return text;
  3138. }
  3139.  
  3140. text = globals.converter._dispatch(
  3141. "simplifiedAutoLinks.before",
  3142. text,
  3143. options,
  3144. globals
  3145. );
  3146.  
  3147. if (options.excludeTrailingPunctuationFromURLs) {
  3148. text = text.replace(simpleURLRegex2, replaceLink(options));
  3149. } else {
  3150. text = text.replace(simpleURLRegex, replaceLink(options));
  3151. }
  3152. text = text.replace(simpleMailRegex, replaceMail(options, globals));
  3153.  
  3154. text = globals.converter._dispatch(
  3155. "simplifiedAutoLinks.after",
  3156. text,
  3157. options,
  3158. globals
  3159. );
  3160.  
  3161. return text;
  3162. });
  3163.  
  3164. /**
  3165. * These are all the transformations that form block-level
  3166. * tags like paragraphs, headers, and list items.
  3167. */
  3168. showdown.subParser("blockGamut", function (text, options, globals) {
  3169. "use strict";
  3170.  
  3171. text = globals.converter._dispatch(
  3172. "blockGamut.before",
  3173. text,
  3174. options,
  3175. globals
  3176. );
  3177.  
  3178. // we parse blockquotes first so that we can have headings and hrs
  3179. // inside blockquotes
  3180. text = showdown.subParser("blockQuotes")(text, options, globals);
  3181. text = showdown.subParser("headers")(text, options, globals);
  3182.  
  3183. // Do Horizontal Rules:
  3184. text = showdown.subParser("horizontalRule")(text, options, globals);
  3185.  
  3186. text = showdown.subParser("lists")(text, options, globals);
  3187. text = showdown.subParser("codeBlocks")(text, options, globals);
  3188. text = showdown.subParser("tables")(text, options, globals);
  3189.  
  3190. // We already ran _HashHTMLBlocks() before, in Markdown(), but that
  3191. // was to escape raw HTML in the original Markdown source. This time,
  3192. // we're escaping the markup we've just created, so that we don't wrap
  3193. // <p> tags around block-level tags.
  3194. text = showdown.subParser("hashHTMLBlocks")(text, options, globals);
  3195. text = showdown.subParser("paragraphs")(text, options, globals);
  3196.  
  3197. text = globals.converter._dispatch(
  3198. "blockGamut.after",
  3199. text,
  3200. options,
  3201. globals
  3202. );
  3203.  
  3204. return text;
  3205. });
  3206.  
  3207. showdown.subParser("blockQuotes", function (text, options, globals) {
  3208. "use strict";
  3209.  
  3210. text = globals.converter._dispatch(
  3211. "blockQuotes.before",
  3212. text,
  3213. options,
  3214. globals
  3215. );
  3216.  
  3217. // add a couple extra lines after the text and endtext mark
  3218. text = text + "\n\n";
  3219.  
  3220. var rgx = /(^ {0,3}>[ \t]?.+\n(.+\n)*\n*)+/gm;
  3221.  
  3222. if (options.splitAdjacentBlockquotes) {
  3223. rgx = /^ {0,3}>[\s\S]*?(?:\n\n)/gm;
  3224. }
  3225.  
  3226. text = text.replace(rgx, function (bq) {
  3227. // attacklab: hack around Konqueror 3.5.4 bug:
  3228. // "----------bug".replace(/^-/g,"") == "bug"
  3229. bq = bq.replace(/^[ \t]*>[ \t]?/gm, ""); // trim one level of quoting
  3230.  
  3231. // attacklab: clean up hack
  3232. bq = bq.replace(/¨0/g, "");
  3233.  
  3234. bq = bq.replace(/^[ \t]+$/gm, ""); // trim whitespace-only lines
  3235. bq = showdown.subParser("githubCodeBlocks")(bq, options, globals);
  3236. bq = showdown.subParser("blockGamut")(bq, options, globals); // recurse
  3237.  
  3238. bq = bq.replace(/(^|\n)/g, "$1 ");
  3239. // These leading spaces screw with <pre> content, so we need to fix that:
  3240. bq = bq.replace(/(\s*<pre>[^\r]+?<\/pre>)/gm, function (wholeMatch, m1) {
  3241. var pre = m1;
  3242. // attacklab: hack around Konqueror 3.5.4 bug:
  3243. pre = pre.replace(/^ /gm, "¨0");
  3244. pre = pre.replace(/¨0/g, "");
  3245. return pre;
  3246. });
  3247.  
  3248. return showdown.subParser("hashBlock")(
  3249. "<blockquote>\n" + bq + "\n</blockquote>",
  3250. options,
  3251. globals
  3252. );
  3253. });
  3254.  
  3255. text = globals.converter._dispatch(
  3256. "blockQuotes.after",
  3257. text,
  3258. options,
  3259. globals
  3260. );
  3261. return text;
  3262. });
  3263.  
  3264. /**
  3265. * Process Markdown `<pre><code>` blocks.
  3266. */
  3267. showdown.subParser("codeBlocks", function (text, options, globals) {
  3268. "use strict";
  3269.  
  3270. text = globals.converter._dispatch(
  3271. "codeBlocks.before",
  3272. text,
  3273. options,
  3274. globals
  3275. );
  3276.  
  3277. // sentinel workarounds for lack of \A and \Z, safari\khtml bug
  3278. text += "¨0";
  3279.  
  3280. var pattern =
  3281. /(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=¨0))/g;
  3282. text = text.replace(pattern, function (wholeMatch, m1, m2) {
  3283. var codeblock = m1,
  3284. nextChar = m2,
  3285. end = "\n";
  3286.  
  3287. codeblock = showdown.subParser("outdent")(codeblock, options, globals);
  3288. codeblock = showdown.subParser("encodeCode")(codeblock, options, globals);
  3289. codeblock = showdown.subParser("detab")(codeblock, options, globals);
  3290. codeblock = codeblock.replace(/^\n+/g, ""); // trim leading newlines
  3291. codeblock = codeblock.replace(/\n+$/g, ""); // trim trailing newlines
  3292.  
  3293. if (options.omitExtraWLInCodeBlocks) {
  3294. end = "";
  3295. }
  3296.  
  3297. codeblock = "<pre><code>" + codeblock + end + "</code></pre>";
  3298.  
  3299. return (
  3300. showdown.subParser("hashBlock")(codeblock, options, globals) + nextChar
  3301. );
  3302. });
  3303.  
  3304. // strip sentinel
  3305. text = text.replace(/¨0/, "");
  3306.  
  3307. text = globals.converter._dispatch(
  3308. "codeBlocks.after",
  3309. text,
  3310. options,
  3311. globals
  3312. );
  3313. return text;
  3314. });
  3315.  
  3316. /**
  3317. *
  3318. * * Backtick quotes are used for <code></code> spans.
  3319. *
  3320. * * You can use multiple backticks as the delimiters if you want to
  3321. * include literal backticks in the code span. So, this input:
  3322. *
  3323. * Just type ``foo `bar` baz`` at the prompt.
  3324. *
  3325. * Will translate to:
  3326. *
  3327. * <p>Just type <code>foo `bar` baz</code> at the prompt.</p>
  3328. *
  3329. * There's no arbitrary limit to the number of backticks you
  3330. * can use as delimters. If you need three consecutive backticks
  3331. * in your code, use four for delimiters, etc.
  3332. *
  3333. * * You can use spaces to get literal backticks at the edges:
  3334. *
  3335. * ... type `` `bar` `` ...
  3336. *
  3337. * Turns to:
  3338. *
  3339. * ... type <code>`bar`</code> ...
  3340. */
  3341. showdown.subParser("codeSpans", function (text, options, globals) {
  3342. "use strict";
  3343.  
  3344. text = globals.converter._dispatch(
  3345. "codeSpans.before",
  3346. text,
  3347. options,
  3348. globals
  3349. );
  3350.  
  3351. if (typeof text === "undefined") {
  3352. text = "";
  3353. }
  3354. text = text.replace(
  3355. /(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,
  3356. function (wholeMatch, m1, m2, m3) {
  3357. var c = m3;
  3358. c = c.replace(/^([ \t]*)/g, ""); // leading whitespace
  3359. c = c.replace(/[ \t]*$/g, ""); // trailing whitespace
  3360. c = showdown.subParser("encodeCode")(c, options, globals);
  3361. c = m1 + "<code>" + c + "</code>";
  3362. c = showdown.subParser("hashHTMLSpans")(c, options, globals);
  3363. return c;
  3364. }
  3365. );
  3366.  
  3367. text = globals.converter._dispatch(
  3368. "codeSpans.after",
  3369. text,
  3370. options,
  3371. globals
  3372. );
  3373. return text;
  3374. });
  3375.  
  3376. /**
  3377. * Create a full HTML document from the processed markdown
  3378. */
  3379. showdown.subParser("completeHTMLDocument", function (text, options, globals) {
  3380. "use strict";
  3381.  
  3382. if (!options.completeHTMLDocument) {
  3383. return text;
  3384. }
  3385.  
  3386. text = globals.converter._dispatch(
  3387. "completeHTMLDocument.before",
  3388. text,
  3389. options,
  3390. globals
  3391. );
  3392.  
  3393. var doctype = "html",
  3394. doctypeParsed = "<!DOCTYPE HTML>\n",
  3395. title = "",
  3396. charset = '<meta charset="utf-8">\n',
  3397. lang = "",
  3398. metadata = "";
  3399.  
  3400. if (typeof globals.metadata.parsed.doctype !== "undefined") {
  3401. doctypeParsed = "<!DOCTYPE " + globals.metadata.parsed.doctype + ">\n";
  3402. doctype = globals.metadata.parsed.doctype.toString().toLowerCase();
  3403. if (doctype === "html" || doctype === "html5") {
  3404. charset = '<meta charset="utf-8">';
  3405. }
  3406. }
  3407.  
  3408. for (var meta in globals.metadata.parsed) {
  3409. if (globals.metadata.parsed.hasOwnProperty(meta)) {
  3410. switch (meta.toLowerCase()) {
  3411. case "doctype":
  3412. break;
  3413.  
  3414. case "title":
  3415. title = "<title>" + globals.metadata.parsed.title + "</title>\n";
  3416. break;
  3417.  
  3418. case "charset":
  3419. if (doctype === "html" || doctype === "html5") {
  3420. charset =
  3421. '<meta charset="' + globals.metadata.parsed.charset + '">\n';
  3422. } else {
  3423. charset =
  3424. '<meta name="charset" content="' +
  3425. globals.metadata.parsed.charset +
  3426. '">\n';
  3427. }
  3428. break;
  3429.  
  3430. case "language":
  3431. case "lang":
  3432. lang = ' lang="' + globals.metadata.parsed[meta] + '"';
  3433. metadata +=
  3434. '<meta name="' +
  3435. meta +
  3436. '" content="' +
  3437. globals.metadata.parsed[meta] +
  3438. '">\n';
  3439. break;
  3440.  
  3441. default:
  3442. metadata +=
  3443. '<meta name="' +
  3444. meta +
  3445. '" content="' +
  3446. globals.metadata.parsed[meta] +
  3447. '">\n';
  3448. }
  3449. }
  3450. }
  3451.  
  3452. text =
  3453. doctypeParsed +
  3454. "<html" +
  3455. lang +
  3456. ">\n<head>\n" +
  3457. title +
  3458. charset +
  3459. metadata +
  3460. "</head>\n<body>\n" +
  3461. text.trim() +
  3462. "\n</body>\n</html>";
  3463.  
  3464. text = globals.converter._dispatch(
  3465. "completeHTMLDocument.after",
  3466. text,
  3467. options,
  3468. globals
  3469. );
  3470. return text;
  3471. });
  3472.  
  3473. /**
  3474. * Convert all tabs to spaces
  3475. */
  3476. showdown.subParser("detab", function (text, options, globals) {
  3477. "use strict";
  3478. text = globals.converter._dispatch("detab.before", text, options, globals);
  3479.  
  3480. // expand first n-1 tabs
  3481. text = text.replace(/\t(?=\t)/g, " "); // g_tab_width
  3482.  
  3483. // replace the nth with two sentinels
  3484. text = text.replace(/\t/g, "¨A¨B");
  3485.  
  3486. // use the sentinel to anchor our regex so it doesn't explode
  3487. text = text.replace(/¨B(.+?)¨A/g, function (wholeMatch, m1) {
  3488. var leadingText = m1,
  3489. numSpaces = 4 - (leadingText.length % 4); // g_tab_width
  3490.  
  3491. // there *must* be a better way to do this:
  3492. for (var i = 0; i < numSpaces; i++) {
  3493. leadingText += " ";
  3494. }
  3495.  
  3496. return leadingText;
  3497. });
  3498.  
  3499. // clean up sentinels
  3500. text = text.replace(/¨A/g, " "); // g_tab_width
  3501. text = text.replace(/¨B/g, "");
  3502.  
  3503. text = globals.converter._dispatch("detab.after", text, options, globals);
  3504. return text;
  3505. });
  3506.  
  3507. showdown.subParser("ellipsis", function (text, options, globals) {
  3508. "use strict";
  3509.  
  3510. if (!options.ellipsis) {
  3511. return text;
  3512. }
  3513.  
  3514. text = globals.converter._dispatch(
  3515. "ellipsis.before",
  3516. text,
  3517. options,
  3518. globals
  3519. );
  3520.  
  3521. text = text.replace(/\.\.\./g, "…");
  3522.  
  3523. text = globals.converter._dispatch(
  3524. "ellipsis.after",
  3525. text,
  3526. options,
  3527. globals
  3528. );
  3529.  
  3530. return text;
  3531. });
  3532.  
  3533. /**
  3534. * Turn emoji codes into emojis
  3535. *
  3536. * List of supported emojis: https://github.com/showdownjs/showdown/wiki/Emojis
  3537. */
  3538. showdown.subParser("emoji", function (text, options, globals) {
  3539. "use strict";
  3540.  
  3541. if (!options.emoji) {
  3542. return text;
  3543. }
  3544.  
  3545. text = globals.converter._dispatch("emoji.before", text, options, globals);
  3546.  
  3547. var emojiRgx = /:([\S]+?):/g;
  3548.  
  3549. text = text.replace(emojiRgx, function (wm, emojiCode) {
  3550. if (showdown.helper.emojis.hasOwnProperty(emojiCode)) {
  3551. return showdown.helper.emojis[emojiCode];
  3552. }
  3553. return wm;
  3554. });
  3555.  
  3556. text = globals.converter._dispatch("emoji.after", text, options, globals);
  3557.  
  3558. return text;
  3559. });
  3560.  
  3561. /**
  3562. * Smart processing for ampersands and angle brackets that need to be encoded.
  3563. */
  3564. showdown.subParser("encodeAmpsAndAngles", function (text, options, globals) {
  3565. "use strict";
  3566. text = globals.converter._dispatch(
  3567. "encodeAmpsAndAngles.before",
  3568. text,
  3569. options,
  3570. globals
  3571. );
  3572.  
  3573. // Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:
  3574. // http://bumppo.net/projects/amputator/
  3575. text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g, "&amp;");
  3576.  
  3577. // Encode naked <'s
  3578. text = text.replace(/<(?![a-z\/?$!])/gi, "&lt;");
  3579.  
  3580. // Encode <
  3581. text = text.replace(/</g, "&lt;");
  3582.  
  3583. // Encode >
  3584. text = text.replace(/>/g, "&gt;");
  3585.  
  3586. text = globals.converter._dispatch(
  3587. "encodeAmpsAndAngles.after",
  3588. text,
  3589. options,
  3590. globals
  3591. );
  3592. return text;
  3593. });
  3594.  
  3595. /**
  3596. * Returns the string, with after processing the following backslash escape sequences.
  3597. *
  3598. * attacklab: The polite way to do this is with the new escapeCharacters() function:
  3599. *
  3600. * text = escapeCharacters(text,"\\",true);
  3601. * text = escapeCharacters(text,"`*_{}[]()>#+-.!",true);
  3602. *
  3603. * ...but we're sidestepping its use of the (slow) RegExp constructor
  3604. * as an optimization for Firefox. This function gets called a LOT.
  3605. */
  3606. showdown.subParser(
  3607. "encodeBackslashEscapes",
  3608. function (text, options, globals) {
  3609. "use strict";
  3610. text = globals.converter._dispatch(
  3611. "encodeBackslashEscapes.before",
  3612. text,
  3613. options,
  3614. globals
  3615. );
  3616.  
  3617. text = text.replace(/\\(\\)/g, showdown.helper.escapeCharactersCallback);
  3618. text = text.replace(
  3619. /\\([`*_{}\[\]()>#+.!~=|:-])/g,
  3620. showdown.helper.escapeCharactersCallback
  3621. );
  3622.  
  3623. text = globals.converter._dispatch(
  3624. "encodeBackslashEscapes.after",
  3625. text,
  3626. options,
  3627. globals
  3628. );
  3629. return text;
  3630. }
  3631. );
  3632.  
  3633. /**
  3634. * Encode/escape certain characters inside Markdown code runs.
  3635. * The point is that in code, these characters are literals,
  3636. * and lose their special Markdown meanings.
  3637. */
  3638. showdown.subParser("encodeCode", function (text, options, globals) {
  3639. "use strict";
  3640.  
  3641. text = globals.converter._dispatch(
  3642. "encodeCode.before",
  3643. text,
  3644. options,
  3645. globals
  3646. );
  3647.  
  3648. // Encode all ampersands; HTML entities are not
  3649. // entities within a Markdown code span.
  3650. text = text
  3651. .replace(/&/g, "&amp;")
  3652. // Do the angle bracket song and dance:
  3653. .replace(/</g, "&lt;")
  3654. .replace(/>/g, "&gt;")
  3655. // Now, escape characters that are magic in Markdown:
  3656. .replace(/([*_{}\[\]\\=~-])/g, showdown.helper.escapeCharactersCallback);
  3657.  
  3658. text = globals.converter._dispatch(
  3659. "encodeCode.after",
  3660. text,
  3661. options,
  3662. globals
  3663. );
  3664. return text;
  3665. });
  3666.  
  3667. /**
  3668. * Within tags -- meaning between < and > -- encode [\ ` * _ ~ =] so they
  3669. * don't conflict with their use in Markdown for code, italics and strong.
  3670. */
  3671. showdown.subParser(
  3672. "escapeSpecialCharsWithinTagAttributes",
  3673. function (text, options, globals) {
  3674. "use strict";
  3675. text = globals.converter._dispatch(
  3676. "escapeSpecialCharsWithinTagAttributes.before",
  3677. text,
  3678. options,
  3679. globals
  3680. );
  3681.  
  3682. // Build a regex to find HTML tags.
  3683. var tags = /<\/?[a-z\d_:-]+(?:[\s]+[\s\S]+?)?>/gi,
  3684. comments = /<!(--(?:(?:[^>-]|-[^>])(?:[^-]|-[^-])*)--)>/gi;
  3685.  
  3686. text = text.replace(tags, function (wholeMatch) {
  3687. return wholeMatch
  3688. .replace(/(.)<\/?code>(?=.)/g, "$1`")
  3689. .replace(/([\\`*_~=|])/g, showdown.helper.escapeCharactersCallback);
  3690. });
  3691.  
  3692. text = text.replace(comments, function (wholeMatch) {
  3693. return wholeMatch.replace(
  3694. /([\\`*_~=|])/g,
  3695. showdown.helper.escapeCharactersCallback
  3696. );
  3697. });
  3698.  
  3699. text = globals.converter._dispatch(
  3700. "escapeSpecialCharsWithinTagAttributes.after",
  3701. text,
  3702. options,
  3703. globals
  3704. );
  3705. return text;
  3706. }
  3707. );
  3708.  
  3709. /**
  3710. * Handle github codeblocks prior to running HashHTML so that
  3711. * HTML contained within the codeblock gets escaped properly
  3712. * Example:
  3713. * ```ruby
  3714. * def hello_world(x)
  3715. * puts "Hello, #{x}"
  3716. * end
  3717. * ```
  3718. */
  3719. showdown.subParser("githubCodeBlocks", function (text, options, globals) {
  3720. "use strict";
  3721.  
  3722. // early exit if option is not enabled
  3723. if (!options.ghCodeBlocks) {
  3724. return text;
  3725. }
  3726.  
  3727. text = globals.converter._dispatch(
  3728. "githubCodeBlocks.before",
  3729. text,
  3730. options,
  3731. globals
  3732. );
  3733.  
  3734. text += "¨0";
  3735.  
  3736. text = text.replace(
  3737. /(?:^|\n)(?: {0,3})(```+|~~~+)(?: *)([^\s`~]*)\n([\s\S]*?)\n(?: {0,3})\1/g,
  3738. function (wholeMatch, delim, language, codeblock) {
  3739. var end = options.omitExtraWLInCodeBlocks ? "" : "\n";
  3740.  
  3741. // First parse the github code block
  3742. codeblock = showdown.subParser("encodeCode")(
  3743. codeblock,
  3744. options,
  3745. globals
  3746. );
  3747. codeblock = showdown.subParser("detab")(codeblock, options, globals);
  3748. codeblock = codeblock.replace(/^\n+/g, ""); // trim leading newlines
  3749. codeblock = codeblock.replace(/\n+$/g, ""); // trim trailing whitespace
  3750.  
  3751. codeblock =
  3752. "<pre><code" +
  3753. (language
  3754. ? ' class="' + language + " language-" + language + '"'
  3755. : "") +
  3756. ">" +
  3757. codeblock +
  3758. end +
  3759. "</code></pre>";
  3760.  
  3761. codeblock = showdown.subParser("hashBlock")(
  3762. codeblock,
  3763. options,
  3764. globals
  3765. );
  3766.  
  3767. // Since GHCodeblocks can be false positives, we need to
  3768. // store the primitive text and the parsed text in a global var,
  3769. // and then return a token
  3770. return (
  3771. "\n\n¨G" +
  3772. (globals.ghCodeBlocks.push({
  3773. text: wholeMatch,
  3774. codeblock: codeblock,
  3775. }) -
  3776. 1) +
  3777. "G\n\n"
  3778. );
  3779. }
  3780. );
  3781.  
  3782. // attacklab: strip sentinel
  3783. text = text.replace(/¨0/, "");
  3784.  
  3785. return globals.converter._dispatch(
  3786. "githubCodeBlocks.after",
  3787. text,
  3788. options,
  3789. globals
  3790. );
  3791. });
  3792.  
  3793. showdown.subParser("hashBlock", function (text, options, globals) {
  3794. "use strict";
  3795. text = globals.converter._dispatch(
  3796. "hashBlock.before",
  3797. text,
  3798. options,
  3799. globals
  3800. );
  3801. text = text.replace(/(^\n+|\n+$)/g, "");
  3802. text = "\n\n¨K" + (globals.gHtmlBlocks.push(text) - 1) + "K\n\n";
  3803. text = globals.converter._dispatch(
  3804. "hashBlock.after",
  3805. text,
  3806. options,
  3807. globals
  3808. );
  3809. return text;
  3810. });
  3811.  
  3812. /**
  3813. * Hash and escape <code> elements that should not be parsed as markdown
  3814. */
  3815. showdown.subParser("hashCodeTags", function (text, options, globals) {
  3816. "use strict";
  3817. text = globals.converter._dispatch(
  3818. "hashCodeTags.before",
  3819. text,
  3820. options,
  3821. globals
  3822. );
  3823.  
  3824. var repFunc = function (wholeMatch, match, left, right) {
  3825. var codeblock =
  3826. left +
  3827. showdown.subParser("encodeCode")(match, options, globals) +
  3828. right;
  3829. return "¨C" + (globals.gHtmlSpans.push(codeblock) - 1) + "C";
  3830. };
  3831.  
  3832. // Hash naked <code>
  3833. text = showdown.helper.replaceRecursiveRegExp(
  3834. text,
  3835. repFunc,
  3836. "<code\\b[^>]*>",
  3837. "</code>",
  3838. "gim"
  3839. );
  3840.  
  3841. text = globals.converter._dispatch(
  3842. "hashCodeTags.after",
  3843. text,
  3844. options,
  3845. globals
  3846. );
  3847. return text;
  3848. });
  3849.  
  3850. showdown.subParser("hashElement", function (text, options, globals) {
  3851. "use strict";
  3852.  
  3853. return function (wholeMatch, m1) {
  3854. var blockText = m1;
  3855.  
  3856. // Undo double lines
  3857. blockText = blockText.replace(/\n\n/g, "\n");
  3858. blockText = blockText.replace(/^\n/, "");
  3859.  
  3860. // strip trailing blank lines
  3861. blockText = blockText.replace(/\n+$/g, "");
  3862.  
  3863. // Replace the element text with a marker ("¨KxK" where x is its key)
  3864. blockText =
  3865. "\n\n¨K" + (globals.gHtmlBlocks.push(blockText) - 1) + "K\n\n";
  3866.  
  3867. return blockText;
  3868. };
  3869. });
  3870.  
  3871. showdown.subParser("hashHTMLBlocks", function (text, options, globals) {
  3872. "use strict";
  3873. text = globals.converter._dispatch(
  3874. "hashHTMLBlocks.before",
  3875. text,
  3876. options,
  3877. globals
  3878. );
  3879.  
  3880. var blockTags = [
  3881. "pre",
  3882. "div",
  3883. "h1",
  3884. "h2",
  3885. "h3",
  3886. "h4",
  3887. "h5",
  3888. "h6",
  3889. "blockquote",
  3890. "table",
  3891. "dl",
  3892. "ol",
  3893. "ul",
  3894. "script",
  3895. "noscript",
  3896. "form",
  3897. "fieldset",
  3898. "iframe",
  3899. "math",
  3900. "style",
  3901. "section",
  3902. "header",
  3903. "footer",
  3904. "nav",
  3905. "article",
  3906. "aside",
  3907. "address",
  3908. "audio",
  3909. "canvas",
  3910. "figure",
  3911. "hgroup",
  3912. "output",
  3913. "video",
  3914. "p",
  3915. ],
  3916. repFunc = function (wholeMatch, match, left, right) {
  3917. var txt = wholeMatch;
  3918. // check if this html element is marked as markdown
  3919. // if so, it's contents should be parsed as markdown
  3920. if (left.search(/\bmarkdown\b/) !== -1) {
  3921. txt = left + globals.converter.makeHtml(match) + right;
  3922. }
  3923. return "\n\n¨K" + (globals.gHtmlBlocks.push(txt) - 1) + "K\n\n";
  3924. };
  3925.  
  3926. if (options.backslashEscapesHTMLTags) {
  3927. // encode backslash escaped HTML tags
  3928. text = text.replace(/\\<(\/?[^>]+?)>/g, function (wm, inside) {
  3929. return "&lt;" + inside + "&gt;";
  3930. });
  3931. }
  3932.  
  3933. // hash HTML Blocks
  3934. for (var i = 0; i < blockTags.length; ++i) {
  3935. var opTagPos,
  3936. rgx1 = new RegExp("^ {0,3}(<" + blockTags[i] + "\\b[^>]*>)", "im"),
  3937. patLeft = "<" + blockTags[i] + "\\b[^>]*>",
  3938. patRight = "</" + blockTags[i] + ">";
  3939. // 1. Look for the first position of the first opening HTML tag in the text
  3940. while ((opTagPos = showdown.helper.regexIndexOf(text, rgx1)) !== -1) {
  3941. // if the HTML tag is \ escaped, we need to escape it and break
  3942.  
  3943. //2. Split the text in that position
  3944. var subTexts = showdown.helper.splitAtIndex(text, opTagPos),
  3945. //3. Match recursively
  3946. newSubText1 = showdown.helper.replaceRecursiveRegExp(
  3947. subTexts[1],
  3948. repFunc,
  3949. patLeft,
  3950. patRight,
  3951. "im"
  3952. );
  3953.  
  3954. // prevent an infinite loop
  3955. if (newSubText1 === subTexts[1]) {
  3956. break;
  3957. }
  3958. text = subTexts[0].concat(newSubText1);
  3959. }
  3960. }
  3961. // HR SPECIAL CASE
  3962. text = text.replace(
  3963. /(\n {0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,
  3964. showdown.subParser("hashElement")(text, options, globals)
  3965. );
  3966.  
  3967. // Special case for standalone HTML comments
  3968. text = showdown.helper.replaceRecursiveRegExp(
  3969. text,
  3970. function (txt) {
  3971. return "\n\n¨K" + (globals.gHtmlBlocks.push(txt) - 1) + "K\n\n";
  3972. },
  3973. "^ {0,3}<!--",
  3974. "-->",
  3975. "gm"
  3976. );
  3977.  
  3978. // PHP and ASP-style processor instructions (<?...?> and <%...%>)
  3979. text = text.replace(
  3980. /(?:\n\n)( {0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,
  3981. showdown.subParser("hashElement")(text, options, globals)
  3982. );
  3983.  
  3984. text = globals.converter._dispatch(
  3985. "hashHTMLBlocks.after",
  3986. text,
  3987. options,
  3988. globals
  3989. );
  3990. return text;
  3991. });
  3992.  
  3993. /**
  3994. * Hash span elements that should not be parsed as markdown
  3995. */
  3996. showdown.subParser("hashHTMLSpans", function (text, options, globals) {
  3997. "use strict";
  3998. text = globals.converter._dispatch(
  3999. "hashHTMLSpans.before",
  4000. text,
  4001. options,
  4002. globals
  4003. );
  4004.  
  4005. function hashHTMLSpan(html) {
  4006. return "¨C" + (globals.gHtmlSpans.push(html) - 1) + "C";
  4007. }
  4008.  
  4009. // Hash Self Closing tags
  4010. text = text.replace(/<[^>]+?\/>/gi, function (wm) {
  4011. return hashHTMLSpan(wm);
  4012. });
  4013.  
  4014. // Hash tags without properties
  4015. text = text.replace(/<([^>]+?)>[\s\S]*?<\/\1>/g, function (wm) {
  4016. return hashHTMLSpan(wm);
  4017. });
  4018.  
  4019. // Hash tags with properties
  4020. text = text.replace(/<([^>]+?)\s[^>]+?>[\s\S]*?<\/\1>/g, function (wm) {
  4021. return hashHTMLSpan(wm);
  4022. });
  4023.  
  4024. // Hash self closing tags without />
  4025. text = text.replace(/<[^>]+?>/gi, function (wm) {
  4026. return hashHTMLSpan(wm);
  4027. });
  4028.  
  4029. /*showdown.helper.matchRecursiveRegExp(text, '<code\\b[^>]*>', '</code>', 'gi');*/
  4030.  
  4031. text = globals.converter._dispatch(
  4032. "hashHTMLSpans.after",
  4033. text,
  4034. options,
  4035. globals
  4036. );
  4037. return text;
  4038. });
  4039.  
  4040. /**
  4041. * Unhash HTML spans
  4042. */
  4043. showdown.subParser("unhashHTMLSpans", function (text, options, globals) {
  4044. "use strict";
  4045. text = globals.converter._dispatch(
  4046. "unhashHTMLSpans.before",
  4047. text,
  4048. options,
  4049. globals
  4050. );
  4051.  
  4052. for (var i = 0; i < globals.gHtmlSpans.length; ++i) {
  4053. var repText = globals.gHtmlSpans[i],
  4054. // limiter to prevent infinite loop (assume 10 as limit for recurse)
  4055. limit = 0;
  4056.  
  4057. while (/¨C(\d+)C/.test(repText)) {
  4058. var num = RegExp.$1;
  4059. repText = repText.replace("¨C" + num + "C", globals.gHtmlSpans[num]);
  4060. if (limit === 10) {
  4061. console.error("maximum nesting of 10 spans reached!!!");
  4062. break;
  4063. }
  4064. ++limit;
  4065. }
  4066. text = text.replace("¨C" + i + "C", repText);
  4067. }
  4068.  
  4069. text = globals.converter._dispatch(
  4070. "unhashHTMLSpans.after",
  4071. text,
  4072. options,
  4073. globals
  4074. );
  4075. return text;
  4076. });
  4077.  
  4078. /**
  4079. * Hash and escape <pre><code> elements that should not be parsed as markdown
  4080. */
  4081. showdown.subParser("hashPreCodeTags", function (text, options, globals) {
  4082. "use strict";
  4083. text = globals.converter._dispatch(
  4084. "hashPreCodeTags.before",
  4085. text,
  4086. options,
  4087. globals
  4088. );
  4089.  
  4090. var repFunc = function (wholeMatch, match, left, right) {
  4091. // encode html entities
  4092. var codeblock =
  4093. left +
  4094. showdown.subParser("encodeCode")(match, options, globals) +
  4095. right;
  4096. return (
  4097. "\n\n¨G" +
  4098. (globals.ghCodeBlocks.push({ text: wholeMatch, codeblock: codeblock }) -
  4099. 1) +
  4100. "G\n\n"
  4101. );
  4102. };
  4103.  
  4104. // Hash <pre><code>
  4105. text = showdown.helper.replaceRecursiveRegExp(
  4106. text,
  4107. repFunc,
  4108. "^ {0,3}<pre\\b[^>]*>\\s*<code\\b[^>]*>",
  4109. "^ {0,3}</code>\\s*</pre>",
  4110. "gim"
  4111. );
  4112.  
  4113. text = globals.converter._dispatch(
  4114. "hashPreCodeTags.after",
  4115. text,
  4116. options,
  4117. globals
  4118. );
  4119. return text;
  4120. });
  4121.  
  4122. showdown.subParser("headers", function (text, options, globals) {
  4123. "use strict";
  4124.  
  4125. text = globals.converter._dispatch(
  4126. "headers.before",
  4127. text,
  4128. options,
  4129. globals
  4130. );
  4131.  
  4132. var headerLevelStart = isNaN(parseInt(options.headerLevelStart))
  4133. ? 1
  4134. : parseInt(options.headerLevelStart),
  4135. // Set text-style headers:
  4136. // Header 1
  4137. // ========
  4138. //
  4139. // Header 2
  4140. // --------
  4141. //
  4142. setextRegexH1 = options.smoothLivePreview
  4143. ? /^(.+)[ \t]*\n={2,}[ \t]*\n+/gm
  4144. : /^(.+)[ \t]*\n=+[ \t]*\n+/gm,
  4145. setextRegexH2 = options.smoothLivePreview
  4146. ? /^(.+)[ \t]*\n-{2,}[ \t]*\n+/gm
  4147. : /^(.+)[ \t]*\n-+[ \t]*\n+/gm;
  4148.  
  4149. text = text.replace(setextRegexH1, function (wholeMatch, m1) {
  4150. var spanGamut = showdown.subParser("spanGamut")(m1, options, globals),
  4151. hID = options.noHeaderId ? "" : ' id="' + headerId(m1) + '"',
  4152. hLevel = headerLevelStart,
  4153. hashBlock =
  4154. "<h" + hLevel + hID + ">" + spanGamut + "</h" + hLevel + ">";
  4155. return showdown.subParser("hashBlock")(hashBlock, options, globals);
  4156. });
  4157.  
  4158. text = text.replace(setextRegexH2, function (matchFound, m1) {
  4159. var spanGamut = showdown.subParser("spanGamut")(m1, options, globals),
  4160. hID = options.noHeaderId ? "" : ' id="' + headerId(m1) + '"',
  4161. hLevel = headerLevelStart + 1,
  4162. hashBlock =
  4163. "<h" + hLevel + hID + ">" + spanGamut + "</h" + hLevel + ">";
  4164. return showdown.subParser("hashBlock")(hashBlock, options, globals);
  4165. });
  4166.  
  4167. // atx-style headers:
  4168. // # Header 1
  4169. // ## Header 2
  4170. // ## Header 2 with closing hashes ##
  4171. // ...
  4172. // ###### Header 6
  4173. //
  4174. var atxStyle = options.requireSpaceBeforeHeadingText
  4175. ? /^(#{1,6})[ \t]+(.+?)[ \t]*#*\n+/gm
  4176. : /^(#{1,6})[ \t]*(.+?)[ \t]*#*\n+/gm;
  4177.  
  4178. text = text.replace(atxStyle, function (wholeMatch, m1, m2) {
  4179. var hText = m2;
  4180. if (options.customizedHeaderId) {
  4181. hText = m2.replace(/\s?\{([^{]+?)}\s*$/, "");
  4182. }
  4183.  
  4184. var span = showdown.subParser("spanGamut")(hText, options, globals),
  4185. hID = options.noHeaderId ? "" : ' id="' + headerId(m2) + '"',
  4186. hLevel = headerLevelStart - 1 + m1.length,
  4187. header = "<h" + hLevel + hID + ">" + span + "</h" + hLevel + ">";
  4188.  
  4189. return showdown.subParser("hashBlock")(header, options, globals);
  4190. });
  4191.  
  4192. function headerId(m) {
  4193. var title, prefix;
  4194.  
  4195. // It is separate from other options to allow combining prefix and customized
  4196. if (options.customizedHeaderId) {
  4197. var match = m.match(/\{([^{]+?)}\s*$/);
  4198. if (match && match[1]) {
  4199. m = match[1];
  4200. }
  4201. }
  4202.  
  4203. title = m;
  4204.  
  4205. // Prefix id to prevent causing inadvertent pre-existing style matches.
  4206. if (showdown.helper.isString(options.prefixHeaderId)) {
  4207. prefix = options.prefixHeaderId;
  4208. } else if (options.prefixHeaderId === true) {
  4209. prefix = "section-";
  4210. } else {
  4211. prefix = "";
  4212. }
  4213.  
  4214. if (!options.rawPrefixHeaderId) {
  4215. title = prefix + title;
  4216. }
  4217.  
  4218. if (options.ghCompatibleHeaderId) {
  4219. title = title
  4220. .replace(/ /g, "-")
  4221. // replace previously escaped chars (&, ¨ and $)
  4222. .replace(/&amp;/g, "")
  4223. .replace(/¨T/g, "")
  4224. .replace(/¨D/g, "")
  4225. // replace rest of the chars (&~$ are repeated as they might have been escaped)
  4226. // borrowed from github's redcarpet (some they should produce similar results)
  4227. .replace(/[&+$,\/:;=?@"#{}|^¨~\[\]`\\*)(%.!'<>]/g, "")
  4228. .toLowerCase();
  4229. } else if (options.rawHeaderId) {
  4230. title = title
  4231. .replace(/ /g, "-")
  4232. // replace previously escaped chars (&, ¨ and $)
  4233. .replace(/&amp;/g, "&")
  4234. .replace(/¨T/g, "¨")
  4235. .replace(/¨D/g, "$")
  4236. // replace " and '
  4237. .replace(/["']/g, "-")
  4238. .toLowerCase();
  4239. } else {
  4240. title = title.replace(/[^\w]/g, "").toLowerCase();
  4241. }
  4242.  
  4243. if (options.rawPrefixHeaderId) {
  4244. title = prefix + title;
  4245. }
  4246.  
  4247. if (globals.hashLinkCounts[title]) {
  4248. title = title + "-" + globals.hashLinkCounts[title]++;
  4249. } else {
  4250. globals.hashLinkCounts[title] = 1;
  4251. }
  4252. return title;
  4253. }
  4254.  
  4255. text = globals.converter._dispatch("headers.after", text, options, globals);
  4256. return text;
  4257. });
  4258.  
  4259. /**
  4260. * Turn Markdown link shortcuts into XHTML <a> tags.
  4261. */
  4262. showdown.subParser("horizontalRule", function (text, options, globals) {
  4263. "use strict";
  4264. text = globals.converter._dispatch(
  4265. "horizontalRule.before",
  4266. text,
  4267. options,
  4268. globals
  4269. );
  4270.  
  4271. var key = showdown.subParser("hashBlock")("<hr />", options, globals);
  4272. text = text.replace(/^ {0,2}( ?-){3,}[ \t]*$/gm, key);
  4273. text = text.replace(/^ {0,2}( ?\*){3,}[ \t]*$/gm, key);
  4274. text = text.replace(/^ {0,2}( ?_){3,}[ \t]*$/gm, key);
  4275.  
  4276. text = globals.converter._dispatch(
  4277. "horizontalRule.after",
  4278. text,
  4279. options,
  4280. globals
  4281. );
  4282. return text;
  4283. });
  4284.  
  4285. /**
  4286. * Turn Markdown image shortcuts into <img> tags.
  4287. */
  4288. showdown.subParser("images", function (text, options, globals) {
  4289. "use strict";
  4290.  
  4291. text = globals.converter._dispatch("images.before", text, options, globals);
  4292.  
  4293. var inlineRegExp =
  4294. /!\[([^\]]*?)][ \t]*()\([ \t]?<?([\S]+?(?:\([\S]*?\)[\S]*?)?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\6)?[ \t]?\)/g,
  4295. crazyRegExp =
  4296. /!\[([^\]]*?)][ \t]*()\([ \t]?<([^>]*)>(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(?:(["'])([^"]*?)\6))?[ \t]?\)/g,
  4297. base64RegExp =
  4298. /!\[([^\]]*?)][ \t]*()\([ \t]?<?(data:.+?\/.+?;base64,[A-Za-z0-9+/=\n]+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\6)?[ \t]?\)/g,
  4299. referenceRegExp = /!\[([^\]]*?)] ?(?:\n *)?\[([\s\S]*?)]()()()()()/g,
  4300. refShortcutRegExp = /!\[([^\[\]]+)]()()()()()/g;
  4301.  
  4302. function writeImageTagBase64(
  4303. wholeMatch,
  4304. altText,
  4305. linkId,
  4306. url,
  4307. width,
  4308. height,
  4309. m5,
  4310. title
  4311. ) {
  4312. url = url.replace(/\s/g, "");
  4313. return writeImageTag(
  4314. wholeMatch,
  4315. altText,
  4316. linkId,
  4317. url,
  4318. width,
  4319. height,
  4320. m5,
  4321. title
  4322. );
  4323. }
  4324.  
  4325. function writeImageTag(
  4326. wholeMatch,
  4327. altText,
  4328. linkId,
  4329. url,
  4330. width,
  4331. height,
  4332. m5,
  4333. title
  4334. ) {
  4335. var gUrls = globals.gUrls,
  4336. gTitles = globals.gTitles,
  4337. gDims = globals.gDimensions;
  4338.  
  4339. linkId = linkId.toLowerCase();
  4340.  
  4341. if (!title) {
  4342. title = "";
  4343. }
  4344. // Special case for explicit empty url
  4345. if (wholeMatch.search(/\(<?\s*>? ?(['"].*['"])?\)$/m) > -1) {
  4346. url = "";
  4347. } else if (url === "" || url === null) {
  4348. if (linkId === "" || linkId === null) {
  4349. // lower-case and turn embedded newlines into spaces
  4350. linkId = altText.toLowerCase().replace(/ ?\n/g, " ");
  4351. }
  4352. url = "#" + linkId;
  4353.  
  4354. if (!showdown.helper.isUndefined(gUrls[linkId])) {
  4355. url = gUrls[linkId];
  4356. if (!showdown.helper.isUndefined(gTitles[linkId])) {
  4357. title = gTitles[linkId];
  4358. }
  4359. if (!showdown.helper.isUndefined(gDims[linkId])) {
  4360. width = gDims[linkId].width;
  4361. height = gDims[linkId].height;
  4362. }
  4363. } else {
  4364. return wholeMatch;
  4365. }
  4366. }
  4367.  
  4368. altText = altText
  4369. .replace(/"/g, "&quot;")
  4370. //altText = showdown.helper.escapeCharacters(altText, '*_', false);
  4371. .replace(
  4372. showdown.helper.regexes.asteriskDashAndColon,
  4373. showdown.helper.escapeCharactersCallback
  4374. );
  4375. //url = showdown.helper.escapeCharacters(url, '*_', false);
  4376. url = url.replace(
  4377. showdown.helper.regexes.asteriskDashAndColon,
  4378. showdown.helper.escapeCharactersCallback
  4379. );
  4380. var result = '<img src="' + url + '" alt="' + altText + '"';
  4381.  
  4382. if (title && showdown.helper.isString(title)) {
  4383. title = title
  4384. .replace(/"/g, "&quot;")
  4385. //title = showdown.helper.escapeCharacters(title, '*_', false);
  4386. .replace(
  4387. showdown.helper.regexes.asteriskDashAndColon,
  4388. showdown.helper.escapeCharactersCallback
  4389. );
  4390. result += ' title="' + title + '"';
  4391. }
  4392.  
  4393. if (width && height) {
  4394. width = width === "*" ? "auto" : width;
  4395. height = height === "*" ? "auto" : height;
  4396.  
  4397. result += ' width="' + width + '"';
  4398. result += ' height="' + height + '"';
  4399. }
  4400.  
  4401. result += " />";
  4402.  
  4403. return result;
  4404. }
  4405.  
  4406. // First, handle reference-style labeled images: ![alt text][id]
  4407. text = text.replace(referenceRegExp, writeImageTag);
  4408.  
  4409. // Next, handle inline images: ![alt text](url =<width>x<height> "optional title")
  4410.  
  4411. // base64 encoded images
  4412. text = text.replace(base64RegExp, writeImageTagBase64);
  4413.  
  4414. // cases with crazy urls like ./image/cat1).png
  4415. text = text.replace(crazyRegExp, writeImageTag);
  4416.  
  4417. // normal cases
  4418. text = text.replace(inlineRegExp, writeImageTag);
  4419.  
  4420. // handle reference-style shortcuts: ![img text]
  4421. text = text.replace(refShortcutRegExp, writeImageTag);
  4422.  
  4423. text = globals.converter._dispatch("images.after", text, options, globals);
  4424. return text;
  4425. });
  4426.  
  4427. showdown.subParser("italicsAndBold", function (text, options, globals) {
  4428. "use strict";
  4429.  
  4430. text = globals.converter._dispatch(
  4431. "italicsAndBold.before",
  4432. text,
  4433. options,
  4434. globals
  4435. );
  4436.  
  4437. // it's faster to have 3 separate regexes for each case than have just one
  4438. // because of backtracing, in some cases, it could lead to an exponential effect
  4439. // called "catastrophic backtrace". Ominous!
  4440.  
  4441. function parseInside(txt, left, right) {
  4442. /*
  4443. if (options.simplifiedAutoLink) {
  4444. txt = showdown.subParser('simplifiedAutoLinks')(txt, options, globals);
  4445. }
  4446. */
  4447. return left + txt + right;
  4448. }
  4449.  
  4450. // Parse underscores
  4451. if (options.literalMidWordUnderscores) {
  4452. text = text.replace(/\b___(\S[\s\S]*?)___\b/g, function (wm, txt) {
  4453. return parseInside(txt, "<strong><em>", "</em></strong>");
  4454. });
  4455. text = text.replace(/\b__(\S[\s\S]*?)__\b/g, function (wm, txt) {
  4456. return parseInside(txt, "<strong>", "</strong>");
  4457. });
  4458. text = text.replace(/\b_(\S[\s\S]*?)_\b/g, function (wm, txt) {
  4459. return parseInside(txt, "<em>", "</em>");
  4460. });
  4461. } else {
  4462. text = text.replace(/___(\S[\s\S]*?)___/g, function (wm, m) {
  4463. return /\S$/.test(m)
  4464. ? parseInside(m, "<strong><em>", "</em></strong>")
  4465. : wm;
  4466. });
  4467. text = text.replace(/__(\S[\s\S]*?)__/g, function (wm, m) {
  4468. return /\S$/.test(m) ? parseInside(m, "<strong>", "</strong>") : wm;
  4469. });
  4470. text = text.replace(/_([^\s_][\s\S]*?)_/g, function (wm, m) {
  4471. // !/^_[^_]/.test(m) - test if it doesn't start with __ (since it seems redundant, we removed it)
  4472. return /\S$/.test(m) ? parseInside(m, "<em>", "</em>") : wm;
  4473. });
  4474. }
  4475.  
  4476. // Now parse asterisks
  4477. if (options.literalMidWordAsterisks) {
  4478. text = text.replace(
  4479. /([^*]|^)\B\*\*\*(\S[\s\S]*?)\*\*\*\B(?!\*)/g,
  4480. function (wm, lead, txt) {
  4481. return parseInside(txt, lead + "<strong><em>", "</em></strong>");
  4482. }
  4483. );
  4484. text = text.replace(
  4485. /([^*]|^)\B\*\*(\S[\s\S]*?)\*\*\B(?!\*)/g,
  4486. function (wm, lead, txt) {
  4487. return parseInside(txt, lead + "<strong>", "</strong>");
  4488. }
  4489. );
  4490. text = text.replace(
  4491. /([^*]|^)\B\*(\S[\s\S]*?)\*\B(?!\*)/g,
  4492. function (wm, lead, txt) {
  4493. return parseInside(txt, lead + "<em>", "</em>");
  4494. }
  4495. );
  4496. } else {
  4497. text = text.replace(/\*\*\*(\S[\s\S]*?)\*\*\*/g, function (wm, m) {
  4498. return /\S$/.test(m)
  4499. ? parseInside(m, "<strong><em>", "</em></strong>")
  4500. : wm;
  4501. });
  4502. text = text.replace(/\*\*(\S[\s\S]*?)\*\*/g, function (wm, m) {
  4503. return /\S$/.test(m) ? parseInside(m, "<strong>", "</strong>") : wm;
  4504. });
  4505. text = text.replace(/\*([^\s*][\s\S]*?)\*/g, function (wm, m) {
  4506. // !/^\*[^*]/.test(m) - test if it doesn't start with ** (since it seems redundant, we removed it)
  4507. return /\S$/.test(m) ? parseInside(m, "<em>", "</em>") : wm;
  4508. });
  4509. }
  4510.  
  4511. text = globals.converter._dispatch(
  4512. "italicsAndBold.after",
  4513. text,
  4514. options,
  4515. globals
  4516. );
  4517. return text;
  4518. });
  4519.  
  4520. /**
  4521. * Form HTML ordered (numbered) and unordered (bulleted) lists.
  4522. */
  4523. showdown.subParser("lists", function (text, options, globals) {
  4524. "use strict";
  4525.  
  4526. /**
  4527. * Process the contents of a single ordered or unordered list, splitting it
  4528. * into individual list items.
  4529. * @param {string} listStr
  4530. * @param {boolean} trimTrailing
  4531. * @returns {string}
  4532. */
  4533. function processListItems(listStr, trimTrailing) {
  4534. // The $g_list_level global keeps track of when we're inside a list.
  4535. // Each time we enter a list, we increment it; when we leave a list,
  4536. // we decrement. If it's zero, we're not in a list anymore.
  4537. //
  4538. // We do this because when we're not inside a list, we want to treat
  4539. // something like this:
  4540. //
  4541. // I recommend upgrading to version
  4542. // 8. Oops, now this line is treated
  4543. // as a sub-list.
  4544. //
  4545. // As a single paragraph, despite the fact that the second line starts
  4546. // with a digit-period-space sequence.
  4547. //
  4548. // Whereas when we're inside a list (or sub-list), that line will be
  4549. // treated as the start of a sub-list. What a kludge, huh? This is
  4550. // an aspect of Markdown's syntax that's hard to parse perfectly
  4551. // without resorting to mind-reading. Perhaps the solution is to
  4552. // change the syntax rules such that sub-lists must start with a
  4553. // starting cardinal number; e.g. "1." or "a.".
  4554. globals.gListLevel++;
  4555.  
  4556. // trim trailing blank lines:
  4557. listStr = listStr.replace(/\n{2,}$/, "\n");
  4558.  
  4559. // attacklab: add sentinel to emulate \z
  4560. listStr += "¨0";
  4561.  
  4562. var rgx =
  4563. /(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(¨0| {0,3}([*+-]|\d+[.])[ \t]+))/gm,
  4564. isParagraphed = /\n[ \t]*\n(?!¨0)/.test(listStr);
  4565.  
  4566. // Since version 1.5, nesting sublists requires 4 spaces (or 1 tab) indentation,
  4567. // which is a syntax breaking change
  4568. // activating this option reverts to old behavior
  4569. if (options.disableForced4SpacesIndentedSublists) {
  4570. rgx =
  4571. /(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(¨0|\2([*+-]|\d+[.])[ \t]+))/gm;
  4572. }
  4573.  
  4574. listStr = listStr.replace(
  4575. rgx,
  4576. function (wholeMatch, m1, m2, m3, m4, taskbtn, checked) {
  4577. checked = checked && checked.trim() !== "";
  4578.  
  4579. var item = showdown.subParser("outdent")(m4, options, globals),
  4580. bulletStyle = "";
  4581.  
  4582. // Support for github tasklists
  4583. if (taskbtn && options.tasklists) {
  4584. bulletStyle =
  4585. ' class="task-list-item" style="list-style-type: none;"';
  4586. item = item.replace(/^[ \t]*\[(x|X| )?]/m, function () {
  4587. var otp =
  4588. '<input type="checkbox" disabled style="margin: 0px 0.35em 0.25em -1.6em; vertical-align: middle;"';
  4589. if (checked) {
  4590. otp += " checked";
  4591. }
  4592. otp += ">";
  4593. return otp;
  4594. });
  4595. }
  4596.  
  4597. // ISSUE #312
  4598. // This input: - - - a
  4599. // causes trouble to the parser, since it interprets it as:
  4600. // <ul><li><li><li>a</li></li></li></ul>
  4601. // instead of:
  4602. // <ul><li>- - a</li></ul>
  4603. // So, to prevent it, we will put a marker (¨A)in the beginning of the line
  4604. // Kind of hackish/monkey patching, but seems more effective than overcomplicating the list parser
  4605. item = item.replace(/^([-*+]|\d\.)[ \t]+[\S\n ]*/g, function (wm2) {
  4606. return "¨A" + wm2;
  4607. });
  4608.  
  4609. // m1 - Leading line or
  4610. // Has a double return (multi paragraph) or
  4611. // Has sublist
  4612. if (m1 || item.search(/\n{2,}/) > -1) {
  4613. item = showdown.subParser("githubCodeBlocks")(
  4614. item,
  4615. options,
  4616. globals
  4617. );
  4618. item = showdown.subParser("blockGamut")(item, options, globals);
  4619. } else {
  4620. // Recursion for sub-lists:
  4621. item = showdown.subParser("lists")(item, options, globals);
  4622. item = item.replace(/\n$/, ""); // chomp(item)
  4623. item = showdown.subParser("hashHTMLBlocks")(item, options, globals);
  4624.  
  4625. // Colapse double linebreaks
  4626. item = item.replace(/\n\n+/g, "\n\n");
  4627. if (isParagraphed) {
  4628. item = showdown.subParser("paragraphs")(item, options, globals);
  4629. } else {
  4630. item = showdown.subParser("spanGamut")(item, options, globals);
  4631. }
  4632. }
  4633.  
  4634. // now we need to remove the marker (¨A)
  4635. item = item.replace("¨A", "");
  4636. // we can finally wrap the line in list item tags
  4637. item = "<li" + bulletStyle + ">" + item + "</li>\n";
  4638.  
  4639. return item;
  4640. }
  4641. );
  4642.  
  4643. // attacklab: strip sentinel
  4644. listStr = listStr.replace(/¨0/g, "");
  4645.  
  4646. globals.gListLevel--;
  4647.  
  4648. if (trimTrailing) {
  4649. listStr = listStr.replace(/\s+$/, "");
  4650. }
  4651.  
  4652. return listStr;
  4653. }
  4654.  
  4655. function styleStartNumber(list, listType) {
  4656. // check if ol and starts by a number different than 1
  4657. if (listType === "ol") {
  4658. var res = list.match(/^ *(\d+)\./);
  4659. if (res && res[1] !== "1") {
  4660. return ' start="' + res[1] + '"';
  4661. }
  4662. }
  4663. return "";
  4664. }
  4665.  
  4666. /**
  4667. * Check and parse consecutive lists (better fix for issue #142)
  4668. * @param {string} list
  4669. * @param {string} listType
  4670. * @param {boolean} trimTrailing
  4671. * @returns {string}
  4672. */
  4673. function parseConsecutiveLists(list, listType, trimTrailing) {
  4674. // check if we caught 2 or more consecutive lists by mistake
  4675. // we use the counterRgx, meaning if listType is UL we look for OL and vice versa
  4676. var olRgx = options.disableForced4SpacesIndentedSublists
  4677. ? /^ ?\d+\.[ \t]/gm
  4678. : /^ {0,3}\d+\.[ \t]/gm,
  4679. ulRgx = options.disableForced4SpacesIndentedSublists
  4680. ? /^ ?[*+-][ \t]/gm
  4681. : /^ {0,3}[*+-][ \t]/gm,
  4682. counterRxg = listType === "ul" ? olRgx : ulRgx,
  4683. result = "";
  4684.  
  4685. if (list.search(counterRxg) !== -1) {
  4686. (function parseCL(txt) {
  4687. var pos = txt.search(counterRxg),
  4688. style = styleStartNumber(list, listType);
  4689. if (pos !== -1) {
  4690. // slice
  4691. result +=
  4692. "\n\n<" +
  4693. listType +
  4694. style +
  4695. ">\n" +
  4696. processListItems(txt.slice(0, pos), !!trimTrailing) +
  4697. "</" +
  4698. listType +
  4699. ">\n";
  4700.  
  4701. // invert counterType and listType
  4702. listType = listType === "ul" ? "ol" : "ul";
  4703. counterRxg = listType === "ul" ? olRgx : ulRgx;
  4704.  
  4705. //recurse
  4706. parseCL(txt.slice(pos));
  4707. } else {
  4708. result +=
  4709. "\n\n<" +
  4710. listType +
  4711. style +
  4712. ">\n" +
  4713. processListItems(txt, !!trimTrailing) +
  4714. "</" +
  4715. listType +
  4716. ">\n";
  4717. }
  4718. })(list);
  4719. } else {
  4720. var style = styleStartNumber(list, listType);
  4721. result =
  4722. "\n\n<" +
  4723. listType +
  4724. style +
  4725. ">\n" +
  4726. processListItems(list, !!trimTrailing) +
  4727. "</" +
  4728. listType +
  4729. ">\n";
  4730. }
  4731.  
  4732. return result;
  4733. }
  4734.  
  4735. /** Start of list parsing **/
  4736. text = globals.converter._dispatch("lists.before", text, options, globals);
  4737. // add sentinel to hack around khtml/safari bug:
  4738. // http://bugs.webkit.org/show_bug.cgi?id=11231
  4739. text += "¨0";
  4740.  
  4741. if (globals.gListLevel) {
  4742. text = text.replace(
  4743. /^(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(¨0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm,
  4744. function (wholeMatch, list, m2) {
  4745. var listType = m2.search(/[*+-]/g) > -1 ? "ul" : "ol";
  4746. return parseConsecutiveLists(list, listType, true);
  4747. }
  4748. );
  4749. } else {
  4750. text = text.replace(
  4751. /(\n\n|^\n?)(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(¨0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm,
  4752. function (wholeMatch, m1, list, m3) {
  4753. var listType = m3.search(/[*+-]/g) > -1 ? "ul" : "ol";
  4754. return parseConsecutiveLists(list, listType, false);
  4755. }
  4756. );
  4757. }
  4758.  
  4759. // strip sentinel
  4760. text = text.replace(/¨0/, "");
  4761. text = globals.converter._dispatch("lists.after", text, options, globals);
  4762. return text;
  4763. });
  4764.  
  4765. /**
  4766. * Parse metadata at the top of the document
  4767. */
  4768. showdown.subParser("metadata", function (text, options, globals) {
  4769. "use strict";
  4770.  
  4771. if (!options.metadata) {
  4772. return text;
  4773. }
  4774.  
  4775. text = globals.converter._dispatch(
  4776. "metadata.before",
  4777. text,
  4778. options,
  4779. globals
  4780. );
  4781.  
  4782. function parseMetadataContents(content) {
  4783. // raw is raw so it's not changed in any way
  4784. globals.metadata.raw = content;
  4785.  
  4786. // escape chars forbidden in html attributes
  4787. // double quotes
  4788. content = content
  4789. // ampersand first
  4790. .replace(/&/g, "&amp;")
  4791. // double quotes
  4792. .replace(/"/g, "&quot;");
  4793.  
  4794. content = content.replace(/\n {4}/g, " ");
  4795. content.replace(/^([\S ]+): +([\s\S]+?)$/gm, function (wm, key, value) {
  4796. globals.metadata.parsed[key] = value;
  4797. return "";
  4798. });
  4799. }
  4800.  
  4801. text = text.replace(
  4802. /^\s*«««+(\S*?)\n([\s\S]+?)\n»»»+\n/,
  4803. function (wholematch, format, content) {
  4804. parseMetadataContents(content);
  4805. return "¨M";
  4806. }
  4807. );
  4808.  
  4809. text = text.replace(
  4810. /^\s*---+(\S*?)\n([\s\S]+?)\n---+\n/,
  4811. function (wholematch, format, content) {
  4812. if (format) {
  4813. globals.metadata.format = format;
  4814. }
  4815. parseMetadataContents(content);
  4816. return "¨M";
  4817. }
  4818. );
  4819.  
  4820. text = text.replace(/¨M/g, "");
  4821.  
  4822. text = globals.converter._dispatch(
  4823. "metadata.after",
  4824. text,
  4825. options,
  4826. globals
  4827. );
  4828. return text;
  4829. });
  4830.  
  4831. /**
  4832. * Remove one level of line-leading tabs or spaces
  4833. */
  4834. showdown.subParser("outdent", function (text, options, globals) {
  4835. "use strict";
  4836. text = globals.converter._dispatch(
  4837. "outdent.before",
  4838. text,
  4839. options,
  4840. globals
  4841. );
  4842.  
  4843. // attacklab: hack around Konqueror 3.5.4 bug:
  4844. // "----------bug".replace(/^-/g,"") == "bug"
  4845. text = text.replace(/^(\t|[ ]{1,4})/gm, "¨0"); // attacklab: g_tab_width
  4846.  
  4847. // attacklab: clean up hack
  4848. text = text.replace(/¨0/g, "");
  4849.  
  4850. text = globals.converter._dispatch("outdent.after", text, options, globals);
  4851. return text;
  4852. });
  4853.  
  4854. /**
  4855. *
  4856. */
  4857. showdown.subParser("paragraphs", function (text, options, globals) {
  4858. "use strict";
  4859.  
  4860. text = globals.converter._dispatch(
  4861. "paragraphs.before",
  4862. text,
  4863. options,
  4864. globals
  4865. );
  4866. // Strip leading and trailing lines:
  4867. text = text.replace(/^\n+/g, "");
  4868. text = text.replace(/\n+$/g, "");
  4869.  
  4870. var grafs = text.split(/\n{2,}/g),
  4871. grafsOut = [],
  4872. end = grafs.length; // Wrap <p> tags
  4873.  
  4874. for (var i = 0; i < end; i++) {
  4875. var str = grafs[i];
  4876. // if this is an HTML marker, copy it
  4877. if (str.search(/¨(K|G)(\d+)\1/g) >= 0) {
  4878. grafsOut.push(str);
  4879.  
  4880. // test for presence of characters to prevent empty lines being parsed
  4881. // as paragraphs (resulting in undesired extra empty paragraphs)
  4882. } else if (str.search(/\S/) >= 0) {
  4883. str = showdown.subParser("spanGamut")(str, options, globals);
  4884. str = str.replace(/^([ \t]*)/g, "<p>");
  4885. str += "</p>";
  4886. grafsOut.push(str);
  4887. }
  4888. }
  4889.  
  4890. /** Unhashify HTML blocks */
  4891. end = grafsOut.length;
  4892. for (i = 0; i < end; i++) {
  4893. var blockText = "",
  4894. grafsOutIt = grafsOut[i],
  4895. codeFlag = false;
  4896. // if this is a marker for an html block...
  4897. // use RegExp.test instead of string.search because of QML bug
  4898. while (/¨(K|G)(\d+)\1/.test(grafsOutIt)) {
  4899. var delim = RegExp.$1,
  4900. num = RegExp.$2;
  4901.  
  4902. if (delim === "K") {
  4903. blockText = globals.gHtmlBlocks[num];
  4904. } else {
  4905. // we need to check if ghBlock is a false positive
  4906. if (codeFlag) {
  4907. // use encoded version of all text
  4908. blockText = showdown.subParser("encodeCode")(
  4909. globals.ghCodeBlocks[num].text,
  4910. options,
  4911. globals
  4912. );
  4913. } else {
  4914. blockText = globals.ghCodeBlocks[num].codeblock;
  4915. }
  4916. }
  4917. blockText = blockText.replace(/\$/g, "$$$$"); // Escape any dollar signs
  4918.  
  4919. grafsOutIt = grafsOutIt.replace(/(\n\n)?¨(K|G)\d+\2(\n\n)?/, blockText);
  4920. // Check if grafsOutIt is a pre->code
  4921. if (/^<pre\b[^>]*>\s*<code\b[^>]*>/.test(grafsOutIt)) {
  4922. codeFlag = true;
  4923. }
  4924. }
  4925. grafsOut[i] = grafsOutIt;
  4926. }
  4927. text = grafsOut.join("\n");
  4928. // Strip leading and trailing lines:
  4929. text = text.replace(/^\n+/g, "");
  4930. text = text.replace(/\n+$/g, "");
  4931. return globals.converter._dispatch(
  4932. "paragraphs.after",
  4933. text,
  4934. options,
  4935. globals
  4936. );
  4937. });
  4938.  
  4939. /**
  4940. * Run extension
  4941. */
  4942. showdown.subParser("runExtension", function (ext, text, options, globals) {
  4943. "use strict";
  4944.  
  4945. if (ext.filter) {
  4946. text = ext.filter(text, globals.converter, options);
  4947. } else if (ext.regex) {
  4948. // TODO remove this when old extension loading mechanism is deprecated
  4949. var re = ext.regex;
  4950. if (!(re instanceof RegExp)) {
  4951. re = new RegExp(re, "g");
  4952. }
  4953. text = text.replace(re, ext.replace);
  4954. }
  4955.  
  4956. return text;
  4957. });
  4958.  
  4959. /**
  4960. * These are all the transformations that occur *within* block-level
  4961. * tags like paragraphs, headers, and list items.
  4962. */
  4963. showdown.subParser("spanGamut", function (text, options, globals) {
  4964. "use strict";
  4965.  
  4966. text = globals.converter._dispatch(
  4967. "spanGamut.before",
  4968. text,
  4969. options,
  4970. globals
  4971. );
  4972. text = showdown.subParser("codeSpans")(text, options, globals);
  4973. text = showdown.subParser("escapeSpecialCharsWithinTagAttributes")(
  4974. text,
  4975. options,
  4976. globals
  4977. );
  4978. text = showdown.subParser("encodeBackslashEscapes")(text, options, globals);
  4979.  
  4980. // Process anchor and image tags. Images must come first,
  4981. // because ![foo][f] looks like an anchor.
  4982. text = showdown.subParser("images")(text, options, globals);
  4983. text = showdown.subParser("anchors")(text, options, globals);
  4984.  
  4985. // Make links out of things like `<http://example.com/>`
  4986. // Must come after anchors, because you can use < and >
  4987. // delimiters in inline links like [this](<url>).
  4988. text = showdown.subParser("autoLinks")(text, options, globals);
  4989. text = showdown.subParser("simplifiedAutoLinks")(text, options, globals);
  4990. text = showdown.subParser("emoji")(text, options, globals);
  4991. text = showdown.subParser("underline")(text, options, globals);
  4992. text = showdown.subParser("italicsAndBold")(text, options, globals);
  4993. text = showdown.subParser("strikethrough")(text, options, globals);
  4994. text = showdown.subParser("ellipsis")(text, options, globals);
  4995.  
  4996. // we need to hash HTML tags inside spans
  4997. text = showdown.subParser("hashHTMLSpans")(text, options, globals);
  4998.  
  4999. // now we encode amps and angles
  5000. text = showdown.subParser("encodeAmpsAndAngles")(text, options, globals);
  5001.  
  5002. // Do hard breaks
  5003. if (options.simpleLineBreaks) {
  5004. // GFM style hard breaks
  5005. // only add line breaks if the text does not contain a block (special case for lists)
  5006. if (!/\n\n¨K/.test(text)) {
  5007. text = text.replace(/\n+/g, "<br />\n");
  5008. }
  5009. } else {
  5010. // Vanilla hard breaks
  5011. text = text.replace(/ +\n/g, "<br />\n");
  5012. }
  5013.  
  5014. text = globals.converter._dispatch(
  5015. "spanGamut.after",
  5016. text,
  5017. options,
  5018. globals
  5019. );
  5020. return text;
  5021. });
  5022.  
  5023. showdown.subParser("strikethrough", function (text, options, globals) {
  5024. "use strict";
  5025.  
  5026. function parseInside(txt) {
  5027. if (options.simplifiedAutoLink) {
  5028. txt = showdown.subParser("simplifiedAutoLinks")(txt, options, globals);
  5029. }
  5030. return "<del>" + txt + "</del>";
  5031. }
  5032.  
  5033. if (options.strikethrough) {
  5034. text = globals.converter._dispatch(
  5035. "strikethrough.before",
  5036. text,
  5037. options,
  5038. globals
  5039. );
  5040. text = text.replace(/(?:~){2}([\s\S]+?)(?:~){2}/g, function (wm, txt) {
  5041. return parseInside(txt);
  5042. });
  5043. text = globals.converter._dispatch(
  5044. "strikethrough.after",
  5045. text,
  5046. options,
  5047. globals
  5048. );
  5049. }
  5050.  
  5051. return text;
  5052. });
  5053.  
  5054. /**
  5055. * Strips link definitions from text, stores the URLs and titles in
  5056. * hash references.
  5057. * Link defs are in the form: ^[id]: url "optional title"
  5058. */
  5059. showdown.subParser("stripLinkDefinitions", function (text, options, globals) {
  5060. "use strict";
  5061.  
  5062. var regex =
  5063. /^ {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,
  5064. base64Regex =
  5065. /^ {0,3}\[([^\]]+)]:[ \t]*\n?[ \t]*<?(data:.+?\/.+?;base64,[A-Za-z0-9+/=\n]+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n\n|(?=¨0)|(?=\n\[))/gm;
  5066.  
  5067. // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug
  5068. text += "¨0";
  5069.  
  5070. var replaceFunc = function (
  5071. wholeMatch,
  5072. linkId,
  5073. url,
  5074. width,
  5075. height,
  5076. blankLines,
  5077. title
  5078. ) {
  5079. // if there aren't two instances of linkId it must not be a reference link so back out
  5080. linkId = linkId.toLowerCase();
  5081. if (text.toLowerCase().split(linkId).length - 1 < 2) {
  5082. return wholeMatch;
  5083. }
  5084. if (url.match(/^data:.+?\/.+?;base64,/)) {
  5085. // remove newlines
  5086. globals.gUrls[linkId] = url.replace(/\s/g, "");
  5087. } else {
  5088. globals.gUrls[linkId] = showdown.subParser("encodeAmpsAndAngles")(
  5089. url,
  5090. options,
  5091. globals
  5092. ); // Link IDs are case-insensitive
  5093. }
  5094.  
  5095. if (blankLines) {
  5096. // Oops, found blank lines, so it's not a title.
  5097. // Put back the parenthetical statement we stole.
  5098. return blankLines + title;
  5099. } else {
  5100. if (title) {
  5101. globals.gTitles[linkId] = title.replace(/"|'/g, "&quot;");
  5102. }
  5103. if (options.parseImgDimensions && width && height) {
  5104. globals.gDimensions[linkId] = {
  5105. width: width,
  5106. height: height,
  5107. };
  5108. }
  5109. }
  5110. // Completely remove the definition from the text
  5111. return "";
  5112. };
  5113.  
  5114. // first we try to find base64 link references
  5115. text = text.replace(base64Regex, replaceFunc);
  5116.  
  5117. text = text.replace(regex, replaceFunc);
  5118.  
  5119. // attacklab: strip sentinel
  5120. text = text.replace(/¨0/, "");
  5121.  
  5122. return text;
  5123. });
  5124.  
  5125. showdown.subParser("tables", function (text, options, globals) {
  5126. "use strict";
  5127.  
  5128. if (!options.tables) {
  5129. return text;
  5130. }
  5131.  
  5132. var tableRgx =
  5133. /^ {0,3}\|?.+\|.+\n {0,3}\|?[ \t]*:?[ \t]*(?:[-=]){2,}[ \t]*:?[ \t]*\|[ \t]*:?[ \t]*(?:[-=]){2,}[\s\S]+?(?:\n\n|¨0)/gm,
  5134. //singeColTblRgx = /^ {0,3}\|.+\|\n {0,3}\|[ \t]*:?[ \t]*(?:[-=]){2,}[ \t]*:?[ \t]*\|[ \t]*\n(?: {0,3}\|.+\|\n)+(?:\n\n|¨0)/gm;
  5135. singeColTblRgx =
  5136. /^ {0,3}\|.+\|[ \t]*\n {0,3}\|[ \t]*:?[ \t]*(?:[-=]){2,}[ \t]*:?[ \t]*\|[ \t]*\n( {0,3}\|.+\|[ \t]*\n)*(?:\n|¨0)/gm;
  5137.  
  5138. function parseStyles(sLine) {
  5139. if (/^:[ \t]*--*$/.test(sLine)) {
  5140. return ' style="text-align:left;"';
  5141. } else if (/^--*[ \t]*:[ \t]*$/.test(sLine)) {
  5142. return ' style="text-align:right;"';
  5143. } else if (/^:[ \t]*--*[ \t]*:$/.test(sLine)) {
  5144. return ' style="text-align:center;"';
  5145. } else {
  5146. return "";
  5147. }
  5148. }
  5149.  
  5150. function parseHeaders(header, style) {
  5151. var id = "";
  5152. header = header.trim();
  5153. // support both tablesHeaderId and tableHeaderId due to error in documentation so we don't break backwards compatibility
  5154. if (options.tablesHeaderId || options.tableHeaderId) {
  5155. id = ' id="' + header.replace(/ /g, "_").toLowerCase() + '"';
  5156. }
  5157. header = showdown.subParser("spanGamut")(header, options, globals);
  5158.  
  5159. return "<th" + id + style + ">" + header + "</th>\n";
  5160. }
  5161.  
  5162. function parseCells(cell, style) {
  5163. var subText = showdown.subParser("spanGamut")(cell, options, globals);
  5164. return "<td" + style + ">" + subText + "</td>\n";
  5165. }
  5166.  
  5167. function buildTable(headers, cells) {
  5168. var tb = "<table>\n<thead>\n<tr>\n",
  5169. tblLgn = headers.length;
  5170.  
  5171. for (var i = 0; i < tblLgn; ++i) {
  5172. tb += headers[i];
  5173. }
  5174. tb += "</tr>\n</thead>\n<tbody>\n";
  5175.  
  5176. for (i = 0; i < cells.length; ++i) {
  5177. tb += "<tr>\n";
  5178. for (var ii = 0; ii < tblLgn; ++ii) {
  5179. tb += cells[i][ii];
  5180. }
  5181. tb += "</tr>\n";
  5182. }
  5183. tb += "</tbody>\n</table>\n";
  5184. return tb;
  5185. }
  5186.  
  5187. function parseTable(rawTable) {
  5188. var i,
  5189. tableLines = rawTable.split("\n");
  5190.  
  5191. for (i = 0; i < tableLines.length; ++i) {
  5192. // strip wrong first and last column if wrapped tables are used
  5193. if (/^ {0,3}\|/.test(tableLines[i])) {
  5194. tableLines[i] = tableLines[i].replace(/^ {0,3}\|/, "");
  5195. }
  5196. if (/\|[ \t]*$/.test(tableLines[i])) {
  5197. tableLines[i] = tableLines[i].replace(/\|[ \t]*$/, "");
  5198. }
  5199. // parse code spans first, but we only support one line code spans
  5200. tableLines[i] = showdown.subParser("codeSpans")(
  5201. tableLines[i],
  5202. options,
  5203. globals
  5204. );
  5205. }
  5206.  
  5207. var rawHeaders = tableLines[0].split("|").map(function (s) {
  5208. return s.trim();
  5209. }),
  5210. rawStyles = tableLines[1].split("|").map(function (s) {
  5211. return s.trim();
  5212. }),
  5213. rawCells = [],
  5214. headers = [],
  5215. styles = [],
  5216. cells = [];
  5217.  
  5218. tableLines.shift();
  5219. tableLines.shift();
  5220.  
  5221. for (i = 0; i < tableLines.length; ++i) {
  5222. if (tableLines[i].trim() === "") {
  5223. continue;
  5224. }
  5225. rawCells.push(
  5226. tableLines[i].split("|").map(function (s) {
  5227. return s.trim();
  5228. })
  5229. );
  5230. }
  5231.  
  5232. if (rawHeaders.length < rawStyles.length) {
  5233. return rawTable;
  5234. }
  5235.  
  5236. for (i = 0; i < rawStyles.length; ++i) {
  5237. styles.push(parseStyles(rawStyles[i]));
  5238. }
  5239.  
  5240. for (i = 0; i < rawHeaders.length; ++i) {
  5241. if (showdown.helper.isUndefined(styles[i])) {
  5242. styles[i] = "";
  5243. }
  5244. headers.push(parseHeaders(rawHeaders[i], styles[i]));
  5245. }
  5246.  
  5247. for (i = 0; i < rawCells.length; ++i) {
  5248. var row = [];
  5249. for (var ii = 0; ii < headers.length; ++ii) {
  5250. if (showdown.helper.isUndefined(rawCells[i][ii])) {
  5251. }
  5252. row.push(parseCells(rawCells[i][ii], styles[ii]));
  5253. }
  5254. cells.push(row);
  5255. }
  5256.  
  5257. return buildTable(headers, cells);
  5258. }
  5259.  
  5260. text = globals.converter._dispatch("tables.before", text, options, globals);
  5261.  
  5262. // find escaped pipe characters
  5263. text = text.replace(/\\(\|)/g, showdown.helper.escapeCharactersCallback);
  5264.  
  5265. // parse multi column tables
  5266. text = text.replace(tableRgx, parseTable);
  5267.  
  5268. // parse one column tables
  5269. text = text.replace(singeColTblRgx, parseTable);
  5270.  
  5271. text = globals.converter._dispatch("tables.after", text, options, globals);
  5272.  
  5273. return text;
  5274. });
  5275.  
  5276. showdown.subParser("underline", function (text, options, globals) {
  5277. "use strict";
  5278.  
  5279. if (!options.underline) {
  5280. return text;
  5281. }
  5282.  
  5283. text = globals.converter._dispatch(
  5284. "underline.before",
  5285. text,
  5286. options,
  5287. globals
  5288. );
  5289.  
  5290. if (options.literalMidWordUnderscores) {
  5291. text = text.replace(/\b___(\S[\s\S]*?)___\b/g, function (wm, txt) {
  5292. return "<u>" + txt + "</u>";
  5293. });
  5294. text = text.replace(/\b__(\S[\s\S]*?)__\b/g, function (wm, txt) {
  5295. return "<u>" + txt + "</u>";
  5296. });
  5297. } else {
  5298. text = text.replace(/___(\S[\s\S]*?)___/g, function (wm, m) {
  5299. return /\S$/.test(m) ? "<u>" + m + "</u>" : wm;
  5300. });
  5301. text = text.replace(/__(\S[\s\S]*?)__/g, function (wm, m) {
  5302. return /\S$/.test(m) ? "<u>" + m + "</u>" : wm;
  5303. });
  5304. }
  5305.  
  5306. // escape remaining underscores to prevent them being parsed by italic and bold
  5307. text = text.replace(/(_)/g, showdown.helper.escapeCharactersCallback);
  5308.  
  5309. text = globals.converter._dispatch(
  5310. "underline.after",
  5311. text,
  5312. options,
  5313. globals
  5314. );
  5315.  
  5316. return text;
  5317. });
  5318.  
  5319. /**
  5320. * Swap back in all the special characters we've hidden.
  5321. */
  5322. showdown.subParser("unescapeSpecialChars", function (text, options, globals) {
  5323. "use strict";
  5324. text = globals.converter._dispatch(
  5325. "unescapeSpecialChars.before",
  5326. text,
  5327. options,
  5328. globals
  5329. );
  5330.  
  5331. text = text.replace(/¨E(\d+)E/g, function (wholeMatch, m1) {
  5332. var charCodeToReplace = parseInt(m1);
  5333. return String.fromCharCode(charCodeToReplace);
  5334. });
  5335.  
  5336. text = globals.converter._dispatch(
  5337. "unescapeSpecialChars.after",
  5338. text,
  5339. options,
  5340. globals
  5341. );
  5342. return text;
  5343. });
  5344.  
  5345. showdown.subParser("makeMarkdown.blockquote", function (node, globals) {
  5346. "use strict";
  5347.  
  5348. var txt = "";
  5349. if (node.hasChildNodes()) {
  5350. var children = node.childNodes,
  5351. childrenLength = children.length;
  5352.  
  5353. for (var i = 0; i < childrenLength; ++i) {
  5354. var innerTxt = showdown.subParser("makeMarkdown.node")(
  5355. children[i],
  5356. globals
  5357. );
  5358.  
  5359. if (innerTxt === "") {
  5360. continue;
  5361. }
  5362. txt += innerTxt;
  5363. }
  5364. }
  5365. // cleanup
  5366. txt = txt.trim();
  5367. txt = "> " + txt.split("\n").join("\n> ");
  5368. return txt;
  5369. });
  5370.  
  5371. showdown.subParser("makeMarkdown.codeBlock", function (node, globals) {
  5372. "use strict";
  5373.  
  5374. var lang = node.getAttribute("language"),
  5375. num = node.getAttribute("precodenum");
  5376. return "```" + lang + "\n" + globals.preList[num] + "\n```";
  5377. });
  5378.  
  5379. showdown.subParser("makeMarkdown.codeSpan", function (node) {
  5380. "use strict";
  5381.  
  5382. return "`" + node.innerHTML + "`";
  5383. });
  5384.  
  5385. showdown.subParser("makeMarkdown.emphasis", function (node, globals) {
  5386. "use strict";
  5387.  
  5388. var txt = "";
  5389. if (node.hasChildNodes()) {
  5390. txt += "*";
  5391. var children = node.childNodes,
  5392. childrenLength = children.length;
  5393. for (var i = 0; i < childrenLength; ++i) {
  5394. txt += showdown.subParser("makeMarkdown.node")(children[i], globals);
  5395. }
  5396. txt += "*";
  5397. }
  5398. return txt;
  5399. });
  5400.  
  5401. showdown.subParser(
  5402. "makeMarkdown.header",
  5403. function (node, globals, headerLevel) {
  5404. "use strict";
  5405.  
  5406. var headerMark = new Array(headerLevel + 1).join("#"),
  5407. txt = "";
  5408.  
  5409. if (node.hasChildNodes()) {
  5410. txt = headerMark + " ";
  5411. var children = node.childNodes,
  5412. childrenLength = children.length;
  5413.  
  5414. for (var i = 0; i < childrenLength; ++i) {
  5415. txt += showdown.subParser("makeMarkdown.node")(children[i], globals);
  5416. }
  5417. }
  5418. return txt;
  5419. }
  5420. );
  5421.  
  5422. showdown.subParser("makeMarkdown.hr", function () {
  5423. "use strict";
  5424.  
  5425. return "---";
  5426. });
  5427.  
  5428. showdown.subParser("makeMarkdown.image", function (node) {
  5429. "use strict";
  5430.  
  5431. var txt = "";
  5432. if (node.hasAttribute("src")) {
  5433. txt += "![" + node.getAttribute("alt") + "](";
  5434. txt += "<" + node.getAttribute("src") + ">";
  5435. if (node.hasAttribute("width") && node.hasAttribute("height")) {
  5436. txt +=
  5437. " =" + node.getAttribute("width") + "x" + node.getAttribute("height");
  5438. }
  5439.  
  5440. if (node.hasAttribute("title")) {
  5441. txt += ' "' + node.getAttribute("title") + '"';
  5442. }
  5443. txt += ")";
  5444. }
  5445. return txt;
  5446. });
  5447.  
  5448. showdown.subParser("makeMarkdown.links", function (node, globals) {
  5449. "use strict";
  5450.  
  5451. var txt = "";
  5452. if (node.hasChildNodes() && node.hasAttribute("href")) {
  5453. var children = node.childNodes,
  5454. childrenLength = children.length;
  5455. txt = "[";
  5456. for (var i = 0; i < childrenLength; ++i) {
  5457. txt += showdown.subParser("makeMarkdown.node")(children[i], globals);
  5458. }
  5459. txt += "](";
  5460. txt += "<" + node.getAttribute("href") + ">";
  5461. if (node.hasAttribute("title")) {
  5462. txt += ' "' + node.getAttribute("title") + '"';
  5463. }
  5464. txt += ")";
  5465. }
  5466. return txt;
  5467. });
  5468.  
  5469. showdown.subParser("makeMarkdown.list", function (node, globals, type) {
  5470. "use strict";
  5471.  
  5472. var txt = "";
  5473. if (!node.hasChildNodes()) {
  5474. return "";
  5475. }
  5476. var listItems = node.childNodes,
  5477. listItemsLenght = listItems.length,
  5478. listNum = node.getAttribute("start") || 1;
  5479.  
  5480. for (var i = 0; i < listItemsLenght; ++i) {
  5481. if (
  5482. typeof listItems[i].tagName === "undefined" ||
  5483. listItems[i].tagName.toLowerCase() !== "li"
  5484. ) {
  5485. continue;
  5486. }
  5487.  
  5488. // define the bullet to use in list
  5489. var bullet = "";
  5490. if (type === "ol") {
  5491. bullet = listNum.toString() + ". ";
  5492. } else {
  5493. bullet = "- ";
  5494. }
  5495.  
  5496. // parse list item
  5497. txt +=
  5498. bullet +
  5499. showdown.subParser("makeMarkdown.listItem")(listItems[i], globals);
  5500. ++listNum;
  5501. }
  5502.  
  5503. // add comment at the end to prevent consecutive lists to be parsed as one
  5504. txt += "\n<!-- -->\n";
  5505. return txt.trim();
  5506. });
  5507.  
  5508. showdown.subParser("makeMarkdown.listItem", function (node, globals) {
  5509. "use strict";
  5510.  
  5511. var listItemTxt = "";
  5512.  
  5513. var children = node.childNodes,
  5514. childrenLenght = children.length;
  5515.  
  5516. for (var i = 0; i < childrenLenght; ++i) {
  5517. listItemTxt += showdown.subParser("makeMarkdown.node")(
  5518. children[i],
  5519. globals
  5520. );
  5521. }
  5522. // if it's only one liner, we need to add a newline at the end
  5523. if (!/\n$/.test(listItemTxt)) {
  5524. listItemTxt += "\n";
  5525. } else {
  5526. // it's multiparagraph, so we need to indent
  5527. listItemTxt = listItemTxt
  5528. .split("\n")
  5529. .join("\n ")
  5530. .replace(/^ {4}$/gm, "")
  5531. .replace(/\n\n+/g, "\n\n");
  5532. }
  5533.  
  5534. return listItemTxt;
  5535. });
  5536.  
  5537. showdown.subParser("makeMarkdown.node", function (node, globals, spansOnly) {
  5538. "use strict";
  5539.  
  5540. spansOnly = spansOnly || false;
  5541.  
  5542. var txt = "";
  5543.  
  5544. // edge case of text without wrapper paragraph
  5545. if (node.nodeType === 3) {
  5546. return showdown.subParser("makeMarkdown.txt")(node, globals);
  5547. }
  5548.  
  5549. // HTML comment
  5550. if (node.nodeType === 8) {
  5551. return "<!--" + node.data + "-->\n\n";
  5552. }
  5553.  
  5554. // process only node elements
  5555. if (node.nodeType !== 1) {
  5556. return "";
  5557. }
  5558.  
  5559. var tagName = node.tagName.toLowerCase();
  5560.  
  5561. switch (tagName) {
  5562. //
  5563. // BLOCKS
  5564. //
  5565. case "h1":
  5566. if (!spansOnly) {
  5567. txt =
  5568. showdown.subParser("makeMarkdown.header")(node, globals, 1) +
  5569. "\n\n";
  5570. }
  5571. break;
  5572. case "h2":
  5573. if (!spansOnly) {
  5574. txt =
  5575. showdown.subParser("makeMarkdown.header")(node, globals, 2) +
  5576. "\n\n";
  5577. }
  5578. break;
  5579. case "h3":
  5580. if (!spansOnly) {
  5581. txt =
  5582. showdown.subParser("makeMarkdown.header")(node, globals, 3) +
  5583. "\n\n";
  5584. }
  5585. break;
  5586. case "h4":
  5587. if (!spansOnly) {
  5588. txt =
  5589. showdown.subParser("makeMarkdown.header")(node, globals, 4) +
  5590. "\n\n";
  5591. }
  5592. break;
  5593. case "h5":
  5594. if (!spansOnly) {
  5595. txt =
  5596. showdown.subParser("makeMarkdown.header")(node, globals, 5) +
  5597. "\n\n";
  5598. }
  5599. break;
  5600. case "h6":
  5601. if (!spansOnly) {
  5602. txt =
  5603. showdown.subParser("makeMarkdown.header")(node, globals, 6) +
  5604. "\n\n";
  5605. }
  5606. break;
  5607.  
  5608. case "p":
  5609. if (!spansOnly) {
  5610. txt =
  5611. showdown.subParser("makeMarkdown.paragraph")(node, globals) +
  5612. "\n\n";
  5613. }
  5614. break;
  5615.  
  5616. case "blockquote":
  5617. if (!spansOnly) {
  5618. txt =
  5619. showdown.subParser("makeMarkdown.blockquote")(node, globals) +
  5620. "\n\n";
  5621. }
  5622. break;
  5623.  
  5624. case "hr":
  5625. if (!spansOnly) {
  5626. txt = showdown.subParser("makeMarkdown.hr")(node, globals) + "\n\n";
  5627. }
  5628. break;
  5629.  
  5630. case "ol":
  5631. if (!spansOnly) {
  5632. txt =
  5633. showdown.subParser("makeMarkdown.list")(node, globals, "ol") +
  5634. "\n\n";
  5635. }
  5636. break;
  5637.  
  5638. case "ul":
  5639. if (!spansOnly) {
  5640. txt =
  5641. showdown.subParser("makeMarkdown.list")(node, globals, "ul") +
  5642. "\n\n";
  5643. }
  5644. break;
  5645.  
  5646. case "precode":
  5647. if (!spansOnly) {
  5648. txt =
  5649. showdown.subParser("makeMarkdown.codeBlock")(node, globals) +
  5650. "\n\n";
  5651. }
  5652. break;
  5653.  
  5654. case "pre":
  5655. if (!spansOnly) {
  5656. txt = showdown.subParser("makeMarkdown.pre")(node, globals) + "\n\n";
  5657. }
  5658. break;
  5659.  
  5660. case "table":
  5661. if (!spansOnly) {
  5662. txt =
  5663. showdown.subParser("makeMarkdown.table")(node, globals) + "\n\n";
  5664. }
  5665. break;
  5666.  
  5667. //
  5668. // SPANS
  5669. //
  5670. case "code":
  5671. txt = showdown.subParser("makeMarkdown.codeSpan")(node, globals);
  5672. break;
  5673.  
  5674. case "em":
  5675. case "i":
  5676. txt = showdown.subParser("makeMarkdown.emphasis")(node, globals);
  5677. break;
  5678.  
  5679. case "strong":
  5680. case "b":
  5681. txt = showdown.subParser("makeMarkdown.strong")(node, globals);
  5682. break;
  5683.  
  5684. case "del":
  5685. txt = showdown.subParser("makeMarkdown.strikethrough")(node, globals);
  5686. break;
  5687.  
  5688. case "a":
  5689. txt = showdown.subParser("makeMarkdown.links")(node, globals);
  5690. break;
  5691.  
  5692. case "img":
  5693. txt = showdown.subParser("makeMarkdown.image")(node, globals);
  5694. break;
  5695.  
  5696. default:
  5697. txt = node.outerHTML + "\n\n";
  5698. }
  5699.  
  5700. // common normalization
  5701. // TODO eventually
  5702.  
  5703. return txt;
  5704. });
  5705.  
  5706. showdown.subParser("makeMarkdown.paragraph", function (node, globals) {
  5707. "use strict";
  5708.  
  5709. var txt = "";
  5710. if (node.hasChildNodes()) {
  5711. var children = node.childNodes,
  5712. childrenLength = children.length;
  5713. for (var i = 0; i < childrenLength; ++i) {
  5714. txt += showdown.subParser("makeMarkdown.node")(children[i], globals);
  5715. }
  5716. }
  5717.  
  5718. // some text normalization
  5719. txt = txt.trim();
  5720.  
  5721. return txt;
  5722. });
  5723.  
  5724. showdown.subParser("makeMarkdown.pre", function (node, globals) {
  5725. "use strict";
  5726.  
  5727. var num = node.getAttribute("prenum");
  5728. return "<pre>" + globals.preList[num] + "</pre>";
  5729. });
  5730.  
  5731. showdown.subParser("makeMarkdown.strikethrough", function (node, globals) {
  5732. "use strict";
  5733.  
  5734. var txt = "";
  5735. if (node.hasChildNodes()) {
  5736. txt += "~~";
  5737. var children = node.childNodes,
  5738. childrenLength = children.length;
  5739. for (var i = 0; i < childrenLength; ++i) {
  5740. txt += showdown.subParser("makeMarkdown.node")(children[i], globals);
  5741. }
  5742. txt += "~~";
  5743. }
  5744. return txt;
  5745. });
  5746.  
  5747. showdown.subParser("makeMarkdown.strong", function (node, globals) {
  5748. "use strict";
  5749.  
  5750. var txt = "";
  5751. if (node.hasChildNodes()) {
  5752. txt += "**";
  5753. var children = node.childNodes,
  5754. childrenLength = children.length;
  5755. for (var i = 0; i < childrenLength; ++i) {
  5756. txt += showdown.subParser("makeMarkdown.node")(children[i], globals);
  5757. }
  5758. txt += "**";
  5759. }
  5760. return txt;
  5761. });
  5762.  
  5763. showdown.subParser("makeMarkdown.table", function (node, globals) {
  5764. "use strict";
  5765.  
  5766. var txt = "",
  5767. tableArray = [[], []],
  5768. headings = node.querySelectorAll("thead>tr>th"),
  5769. rows = node.querySelectorAll("tbody>tr"),
  5770. i,
  5771. ii;
  5772. for (i = 0; i < headings.length; ++i) {
  5773. var headContent = showdown.subParser("makeMarkdown.tableCell")(
  5774. headings[i],
  5775. globals
  5776. ),
  5777. allign = "---";
  5778.  
  5779. if (headings[i].hasAttribute("style")) {
  5780. var style = headings[i]
  5781. .getAttribute("style")
  5782. .toLowerCase()
  5783. .replace(/\s/g, "");
  5784. switch (style) {
  5785. case "text-align:left;":
  5786. allign = ":---";
  5787. break;
  5788. case "text-align:right;":
  5789. allign = "---:";
  5790. break;
  5791. case "text-align:center;":
  5792. allign = ":---:";
  5793. break;
  5794. }
  5795. }
  5796. tableArray[0][i] = headContent.trim();
  5797. tableArray[1][i] = allign;
  5798. }
  5799.  
  5800. for (i = 0; i < rows.length; ++i) {
  5801. var r = tableArray.push([]) - 1,
  5802. cols = rows[i].getElementsByTagName("td");
  5803.  
  5804. for (ii = 0; ii < headings.length; ++ii) {
  5805. var cellContent = " ";
  5806. if (typeof cols[ii] !== "undefined") {
  5807. cellContent = showdown.subParser("makeMarkdown.tableCell")(
  5808. cols[ii],
  5809. globals
  5810. );
  5811. }
  5812. tableArray[r].push(cellContent);
  5813. }
  5814. }
  5815.  
  5816. var cellSpacesCount = 3;
  5817. for (i = 0; i < tableArray.length; ++i) {
  5818. for (ii = 0; ii < tableArray[i].length; ++ii) {
  5819. var strLen = tableArray[i][ii].length;
  5820. if (strLen > cellSpacesCount) {
  5821. cellSpacesCount = strLen;
  5822. }
  5823. }
  5824. }
  5825.  
  5826. for (i = 0; i < tableArray.length; ++i) {
  5827. for (ii = 0; ii < tableArray[i].length; ++ii) {
  5828. if (i === 1) {
  5829. if (tableArray[i][ii].slice(-1) === ":") {
  5830. tableArray[i][ii] =
  5831. showdown.helper.padEnd(
  5832. tableArray[i][ii].slice(-1),
  5833. cellSpacesCount - 1,
  5834. "-"
  5835. ) + ":";
  5836. } else {
  5837. tableArray[i][ii] = showdown.helper.padEnd(
  5838. tableArray[i][ii],
  5839. cellSpacesCount,
  5840. "-"
  5841. );
  5842. }
  5843. } else {
  5844. tableArray[i][ii] = showdown.helper.padEnd(
  5845. tableArray[i][ii],
  5846. cellSpacesCount
  5847. );
  5848. }
  5849. }
  5850. txt += "| " + tableArray[i].join(" | ") + " |\n";
  5851. }
  5852.  
  5853. return txt.trim();
  5854. });
  5855.  
  5856. showdown.subParser("makeMarkdown.tableCell", function (node, globals) {
  5857. "use strict";
  5858.  
  5859. var txt = "";
  5860. if (!node.hasChildNodes()) {
  5861. return "";
  5862. }
  5863. var children = node.childNodes,
  5864. childrenLength = children.length;
  5865.  
  5866. for (var i = 0; i < childrenLength; ++i) {
  5867. txt += showdown.subParser("makeMarkdown.node")(
  5868. children[i],
  5869. globals,
  5870. true
  5871. );
  5872. }
  5873. return txt.trim();
  5874. });
  5875.  
  5876. showdown.subParser("makeMarkdown.txt", function (node) {
  5877. "use strict";
  5878.  
  5879. var txt = node.nodeValue;
  5880.  
  5881. // multiple spaces are collapsed
  5882. txt = txt.replace(/ +/g, " ");
  5883.  
  5884. // replace the custom ¨NBSP; with a space
  5885. txt = txt.replace(/¨NBSP;/g, " ");
  5886.  
  5887. // ", <, > and & should replace escaped html entities
  5888. txt = showdown.helper.unescapeHTMLEntities(txt);
  5889.  
  5890. // escape markdown magic characters
  5891. // emphasis, strong and strikethrough - can appear everywhere
  5892. // we also escape pipe (|) because of tables
  5893. // and escape ` because of code blocks and spans
  5894. txt = txt.replace(/([*_~|`])/g, "\\$1");
  5895.  
  5896. // escape > because of blockquotes
  5897. txt = txt.replace(/^(\s*)>/g, "\\$1>");
  5898.  
  5899. // hash character, only troublesome at the beginning of a line because of headers
  5900. txt = txt.replace(/^#/gm, "\\#");
  5901.  
  5902. // horizontal rules
  5903. txt = txt.replace(/^(\s*)([-=]{3,})(\s*)$/, "$1\\$2$3");
  5904.  
  5905. // dot, because of ordered lists, only troublesome at the beginning of a line when preceded by an integer
  5906. txt = txt.replace(/^( {0,3}\d+)\./gm, "$1\\.");
  5907.  
  5908. // +, * and -, at the beginning of a line becomes a list, so we need to escape them also (asterisk was already escaped)
  5909. txt = txt.replace(/^( {0,3})([+-])/gm, "$1\\$2");
  5910.  
  5911. // images and links, ] followed by ( is problematic, so we escape it
  5912. txt = txt.replace(/]([\s]*)\(/g, "\\]$1\\(");
  5913.  
  5914. // reference URIs must also be escaped
  5915. txt = txt.replace(/^ {0,3}\[([\S \t]*?)]:/gm, "\\[$1]:");
  5916.  
  5917. return txt;
  5918. });
  5919.  
  5920. return showdown;
  5921. });
  5922.  
  5923. //# sourceMappingURL=showdown.js.map