/** * @var {boolean} Whether to decode HTML entities when decoding text */ var decodeHtmlEntities = config.decodeHtmlEntities; /** * @var {bool} Whether text contains escape characters */ var hasEscapedChars = false; /** * @var {bool} Whether text contains link references */ var hasReferences = false; /** * @dict */ var linkReferences = {}; if (text.indexOf('\\') >= 0) { hasEscapedChars = true; // Encode escaped literals that have a special meaning otherwise, so that we don't have // to take them into account in regexps text = text.replace( /\\[!"'()*[\\\]^_`~]/g, function (str) { return { '\\!': "\x1B0", '\\"': "\x1B1", "\\'": "\x1B2", '\\(' : "\x1B3", '\\)': "\x1B4", '\\*': "\x1B5", '\\[': "\x1B6", '\\\\': "\x1B7", '\\]': "\x1B8", '\\^': "\x1B9", '\\_': "\x1BA", '\\`' : "\x1BB", '\\~': "\x1BC" }[str]; } ); } // We append a couple of lines and a non-whitespace character at the end of the text in // order to trigger the closure of all open blocks such as quotes and lists text += "\n\n\x17"; /** * Decode a chunk of encoded text to be used as an attribute value * * Decodes escaped literals and removes slashes and 0x1A characters * * @param {string} str Encoded text * @return {string} Decoded text */ function decode(str) { if (HINT.LITEDOWN_DECODE_HTML_ENTITIES && decodeHtmlEntities && str.indexOf('&') > -1) { str = html_entity_decode(str); } str = str.replace(/\x1A/g, ''); if (hasEscapedChars) { str = str.replace( /\x1B./g, function (seq) { return { "\x1B0": '!', "\x1B1": '"', "\x1B2": "'", "\x1B3": '(', "\x1B4": ')', "\x1B5": '*', "\x1B6": '[', "\x1B7": '\\', "\x1B8": ']', "\x1B9": '^', "\x1BA": '_', "\x1BB": '`', "\x1BC": '~' }[seq]; } ); } return str; } /** * Test whether given position is preceded by whitespace * * @param {number} pos * @return {boolean} */ function isAfterWhitespace(pos) { return (pos > 0 && isWhitespace(text.charAt(pos - 1))); } /** * Test whether given character is alphanumeric * * @param {string} chr * @return {boolean} */ function isAlnum(chr) { return (' abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'.indexOf(chr) > 0); } /** * Test whether given position is followed by whitespace * * @param {number} pos * @return {boolean} */ function isBeforeWhitespace(pos) { return isWhitespace(text[pos + 1]); } /** * Test whether a length of text is surrounded by alphanumeric characters * * @param {number} pos Start of the text * @param {number} len Length of the text * @return {boolean} */ function isSurroundedByAlnum(pos, len) { return (pos > 0 && isAlnum(text[pos - 1]) && isAlnum(text[pos + len])); } /** * Test whether given character is an ASCII whitespace character * * NOTE: newlines are normalized to LF before parsing so we don't have to check for CR * * @param {string} chr * @return {boolean} */ function isWhitespace(chr) { return (" \n\t".indexOf(chr) > -1); } /** * Mark the boundary of a block in the original text * * @param {number} pos */ function markBoundary(pos) { text = text.substr(0, pos) + "\x17" + text.substr(pos + 1); } /** * Overwrite part of the text with substitution characters ^Z (0x1A) * * @param {number} pos Start of the range * @param {number} len Length of text to overwrite */ function overwrite(pos, len) { if (len > 0) { text = text.substr(0, pos) + new Array(1 + len).join("\x1A") + text.substr(pos + len); } }