/** * @type {boolean} Whether to decode HTML entities when decoding text */ var decodeHtmlEntities = config.decodeHtmlEntities; /** * @type {boolean} Whether text contains escape characters */ var hasEscapedChars = false; /** * @type {boolean} 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", '\\`' : "\x1BD", '\\~': "\x1BE" }[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": '_', "\x1BD": '`', "\x1BE": '~' }[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.substring(0, pos) + "\x17" + text.substring(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.substring(0, pos) + new Array(1 + len).join("\x1A") + text.substring(pos + len); } }