From 868889d08df7855ab092f95923670e951c4f8500 Mon Sep 17 00:00:00 2001 From: Jesper Wrang Date: Sun, 3 Sep 2017 22:51:25 +0200 Subject: [PATCH] Updated references to Rawgit --- static/snuownd.js | 3950 ----------------------------------------- templates/header.html | 5 +- templates/thread.html | 5 +- 3 files changed, 4 insertions(+), 3956 deletions(-) delete mode 100644 static/snuownd.js diff --git a/static/snuownd.js b/static/snuownd.js deleted file mode 100644 index 1fcccd5..0000000 --- a/static/snuownd.js +++ /dev/null @@ -1,3950 +0,0 @@ -/** - @preserve snuownd.js - javascript port of reddit's "snudown" markdown parser - https://github.com/gamefreak/snuownd - */ -/** - * @license Copyright (c) 2009, Natacha Porté - * Copyright (c) 2011, Vicent Marti - * Copyright (c) 2012, Scott McClaugherty - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -// up to date with commit e518f5077b072599dea87596f4ce3c1d03e443c0 - -/** -@module SnuOwnd -*/ -(function(exports){ - function _isspace(c) {return c == ' ' || c == '\n';} - function isspace(c) {return /[\x09-\x0d ]/.test(c);} - function isalnum(c) { return /[A-Za-z0-9]/.test(c); } - function isalpha(c) { return /[A-Za-z]/.test(c); } - function isdigit(c) { return /[0-9]/.test(c); } - function isxdigit(c) { return /[0-9a-fA-F]/.test(c); } - function ispunct(c) {return /[\x20-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]/.test(c); } - - function urlHexCode(number) { - var hex_str = '0123456789ABCDEF'; - return '%'+hex_str[(number&0xf0)>>4]+hex_str[(number&0x0f)>>0]; - } - - function escapeUTF8Char(char) { - var code = char.charCodeAt(0); - if (code < 0x80) { - return urlHexCode(code); - } else if((code > 0x7f) && (code < 0x0800)) { - var seq = urlHexCode(code >> 6 & 0xff | 0xc0); - seq += urlHexCode(code >> 0 & 0x3f | 0x80); - return seq; - } else { - var seq = urlHexCode(code >> 12 & 0xff | 0xe0); - seq += urlHexCode(code >> 6 & 0x3f | 0x80); - seq += urlHexCode(code >> 0 & 0x3f | 0x80); - return seq; - } - } - - function find_block_tag (str) { - var wordList = [ - 'p', 'dl', 'div', 'math', - 'table', 'ul', 'del', 'form', - 'blockquote', 'figure', 'ol', 'fieldset', - 'h1', 'h6', 'pre', 'script', - 'h5', 'noscript', 'style', 'iframe', - 'h4', 'ins', 'h3', 'h2' - ]; - if (wordList.indexOf(str.toLowerCase()) != -1) { - return str.toLowerCase(); - } - return ''; - } - - function sdhtml_is_tag(tag_data, tagname) { - var i; - var closed = 0; - var tag_size = tag_data.length; - - if (tag_size < 3 || tag_data[0] != '<') return HTML_TAG_NONE; - - i = 1; - - if (tag_data[i] == '/') { - closed = 1; - i++; - } - - var tagname_c = 0; - for (; i < tag_size; ++i, ++tagname_c) { - if (tagname_c >= tagname.length) break; - - if (tag_data[i] != tagname[tagname_c]) return HTML_TAG_NONE; - } - - if (i == tag_size) return HTML_TAG_NONE; - - if (isspace(tag_data[i]) || tag_data[i] == '>') - return closed ? HTML_TAG_CLOSE : HTML_TAG_OPEN; - - return HTML_TAG_NONE; - } - - function unscape_text(out, src) { - var i = 0, org; - while (i < src.s.length) { - org = i; - while (i < src.s.length && src.s[i] != '\\') i++; - - if (i > org) out.s += src.s.slice(org, i); - - if (i + 1 >= src.s.length) break; - - out.s += src.s[i + 1]; - i += 2; - } - } - - - // Parsers tend to choke on entities with values greater than this - var MAX_NUM_ENTITY_VAL = 0x10ffff; - - function is_valid_numeric_entity(entity_val) { - /* Some XML parsers will choke on entities with certain - * values (mostly control characters.) - * - * According to lxml these are all problematic: - * - * [xrange(0, 8), - * xrange(11, 12), - * xrange(14, 31), - * xrange(55296, 57343), - * xrange(65534, 65535)] - */ - return (entity_val > 8 - && (entity_val !== 11 && entity_val > 12) - && (entity_val < 14 || entity_val > 31) - && (entity_val < 55296 || entity_val > 57343) - && (entity_val !== 65534 && entity_val !== 65535) - && entity_val <= MAX_NUM_ENTITY_VAL); - } - // Any numeric entity longer than this is obviously above MAX_ENTITY_CHAR - // used to avoid dealing with overflows. - var MAX_NUM_ENTITY_LEN = 7; - var VALID_ENTITIES = [ - 'Æ', 'Á', 'Â', 'À', 'Α', 'Å', - 'Ã', 'Ä', 'Β', 'Ç', 'Χ', '‡', 'Δ', - 'Ð', 'É', 'Ê', 'È', 'Ε', 'Η', 'Ë', - 'Γ', 'Í', 'Î', 'Ì', 'Ι', 'Ï', 'Κ', - 'Λ', 'Μ', 'Ñ', 'Ν', 'Œ', 'Ó', 'Ô', - 'Ò', 'Ω', 'Ο', 'Ø', 'Õ', 'Ö', 'Φ', - 'Π', '″', 'Ψ', 'Ρ', 'Š', 'Σ', 'Þ', 'Τ', - 'Θ', 'Ú', 'Û', 'Ù', 'Υ', 'Ü', 'Ξ', - 'Ý', 'Ÿ', 'Ζ', 'á', 'â', '´', 'æ', - 'à', 'ℵ', 'α', '&', '∧', '∠', ''', - 'å', '≈', 'ã', 'ä', '„', 'β', '¦', - '•', '∩', 'ç', '¸', '¢', 'χ', 'ˆ', - '♣', '≅', '©', '↵', '∪', '¤', '⇓', - '†', '↓', '°', 'δ', '♦', '÷', - - 'é', 'ê', 'è', '∅', ' ', ' ', - 'ε', '≡', 'η', 'ð', 'ë', '€', '∃', - 'ƒ', '∀', '½', '¼', '¾', '⁄', - 'γ','≥', '>', '⇔', '↔', '♥', '…', - 'í', 'î', '¡', 'ì', 'ℑ', - - '∞', - '∫', 'ι', '¿', '∈', 'ï', 'κ', '⇐', - 'λ', '⟨', '«', '←', '⌈', '“', '≤', - '⌊', '∗', '◊', '‎', '‹', '‘', '<', - '¯', '—', 'µ', '·', '−', 'μ', '∇', - ' ', '–', '≠', '∋', '¬', '∉', '⊄', 'ñ', - 'ν', 'ó', 'ô', 'œ', 'ò', '‾', 'ω', - 'ο', '⊕', '∨', 'ª', 'º', 'ø', 'õ', - '⊗', 'ö', '¶', '∂', '‰', '⊥', 'φ', - 'π', 'ϖ', '±', '£', '′', '∏', '∝', - 'ψ', '"', '⇒', '√', '⟩', '»', '→', - '⌉', '”', 'ℜ', '®', '⌋', 'ρ', '‏', - '›', '’', '‚', 'š', '⋅', '§', '­', - 'σ', 'ς', '∼', '♠', '⊂', '⊆', '∑', - '¹', '²', '³', '⊃', '⊇', 'ß', 'τ', - '∴', 'θ', 'ϑ', ' ', 'þ', '˜', - '×', '™', '⇑', 'ú', '↑', 'û', 'ù', - '¨', 'ϒ', 'υ', 'ü', '℘', 'ξ', 'ý', -'¥', 'ÿ', 'ζ', '‍', '‌', -]; - - /** - * According to the OWASP rules: - * - * & --> & - * < --> < - * > --> > - * " --> " - * ' --> ' ' is not recommended - * / --> / forward slash is included as it helps end an HTML entity - * - */ - var HTML_ESCAPE_TABLE = [ - 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 7, 7, 0, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 0, 0, 1, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 4, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 6, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ]; - - var HTML_ESCAPES = ["", """, "&", "'", "/", "<", ">", "" /* throw out control characters */ ]; - - function escape_html(out, src, secure) { - var i = 0, org, esc = 0; - while (i < src.length) { - org = i; - while (i < src.length && !(esc = HTML_ESCAPE_TABLE[src.charCodeAt(i)])) - i++; - - if (i > org) out.s += src.slice(org, i); - - /* escaping */ - if (i >= src.length) break; - - /* The forward slash is only escaped in secure mode */ - if (src[i] == '/' && !secure) { - out.s += '/'; - } else if (HTML_ESCAPE_TABLE[src.charCodeAt(i)] == 7) { - /* skip control characters */ - } else { - out.s += HTML_ESCAPES[esc]; - } - - i++; - } - } - - - /* - * The following characters will not be escaped: - * - * -_.+!*'(),%#@?=;:/,+&$ alphanum - * - * Note that this character set is the addition of: - * - * - The characters which are safe to be in an URL - * - The characters which are *not* safe to be in - * an URL because they are RESERVED characters. - * - * We asume (lazily) that any RESERVED char that - * appears inside an URL is actually meant to - * have its native function (i.e. as an URL - * component/separator) and hence needs no escaping. - * - * There are two exceptions: the chacters & (amp) - * and ' (single quote) do not appear in the table. - * They are meant to appear in the URL as components, - * yet they require special HTML-entity escaping - * to generate valid HTML markup. - * - * All other characters will be escaped to %XX. - * - */ - var HREF_SAFE = [ - 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 0, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ]; - - function escape_href(out, src) { - var i = 0, org; - - - while (i < src.length) { - org = i; - /* Skip by characters that don't need special processing */ - while (i < src.length && HREF_SAFE[src.charCodeAt(i)] === 1) i++; - - if (i > org) out.s += src.slice(org, i); - - /* escaping */ - if (i >= src.length) break; - - /* throw out control characters */ - if (HREF_SAFE[src.charCodeAt(i)] == 2) { - i++; - continue; - } - - switch (src[i]) { - /* amp appears all the time in URLs, but needs - * HTML-entity escaping to be inside an href */ - case '&': - out.s += '&'; - break; - - /* the single quote is a valid URL character - * according to the standard; it needs HTML - * entity escaping too */ - case '\'': - out.s += '''; - break; - - /* the space can be escaped to %20 or a plus - * sign. we're going with the generic escape - * for now. the plus thing is more commonly seen - * when building GET strings */ - /* - //This was disabled - case ' ': - out.s += '+' - break; - //*/ - - /* every other character goes with a %XX escaping */ - default: - out.s += escapeUTF8Char(src[i]); - /* - var cc = src.charCodeAt(i); - hex_str[1] = hex_chars[(cc >> 4) & 0xF]; - hex_str[2] = hex_chars[cc & 0xF]; - out.s += hex_str.join(''); - */ - } - - i++; - } - } - - - // function autolink_delim(uint8_t *data, size_t link_end, size_t offset, size_t size) - function autolink_delim(data_, link_end, offset, size) { - var data = data_.slice(offset) - var cclose, copen = 0; - var i; - - for (i = 0; i < link_end; ++i) - if (data[i] == '<') { - link_end = i; - break; - } - - while (link_end > 0) { - var c = data[link_end - 1]; - if (c === "\0") break; - - if ("?!.,".indexOf(c) !== -1) { - link_end--; - } else if (c === ';') { - var new_end = link_end - 2; - - while (new_end > 0 && isalpha(data[new_end])) new_end--; - - if (new_end < link_end - 2 && data[new_end] == '&') - link_end = new_end; - else link_end--; - } - else break; - } - - if (link_end == 0) return 0; - - cclose = data[link_end - 1]; - - switch (cclose) { - case '"': copen = '"'; break; - case '\'': copen = '\''; break; - case ')': copen = '('; break; - case ']': copen = '['; break; - case '}': copen = '{'; break; - } - - if (copen != 0) { - var closing = 0; - var opening = 0; - var j = 0; - - /* Try to close the final punctuation sign in this same line; - * if we managed to close it outside of the URL, that means that it's - * not part of the URL. If it closes inside the URL, that means it - * is part of the URL. - * - * Examples: - * - * foo http://www.pokemon.com/Pikachu_(Electric) bar - * => http://www.pokemon.com/Pikachu_(Electric) - * - * foo (http://www.pokemon.com/Pikachu_(Electric)) bar - * => http://www.pokemon.com/Pikachu_(Electric) - * - * foo http://www.pokemon.com/Pikachu_(Electric)) bar - * => http://www.pokemon.com/Pikachu_(Electric)) - * - * (foo http://www.pokemon.com/Pikachu_(Electric)) bar - * => foo http://www.pokemon.com/Pikachu_(Electric) - */ - - while (j < link_end) { - if (data[j] == copen) opening++; - else if (data[j] == cclose) closing++; - - j++; - } - - if (closing != opening) link_end--; - } - - return link_end; - } - - function check_domain(data, allow_short) { - var i, np = 0; - - if (!isalnum(data[0])) return 0; - - for (i = 1; i < data.length - 1; ++i) { - if (data[i] == '.') np++; - else if (!isalnum(data[i]) && data[i] != '-') break; - } - - /* a valid domain needs to have at least a dot. - * that's as far as we get */ - if (allow_short) { - /* We don't need a valid domain in the strict sence (with - * at least one dot; so just make sure it's composed of valid - * domain characters and return the length of the valid - * sequence. */ - return i; - } else { - return np ? i : 0; - } - } - - function sd_autolink_issafe(link) { - var valid_uris = [ - "http://", "https://", "ftp://", "mailto://", - "/", "git://", "steam://", "irc://", "news://", "mumble://", - "ssh://", "ircs://", "ts3server://", "#"]; - - var i; - - for (i = 0; i < valid_uris.length; ++i) { - var len = valid_uris[i].length; - - if (link.length > len && - link.toLowerCase().indexOf(valid_uris[i]) == 0 && - /[A-Za-z0-9#\/?]/.test(link[len])) - return 1; - } - - return 0; - } - - - function sd_autolink__url(rewind_p, link, data_, offset, size, flags) { - var data = data_.slice(offset); - var link_end, rewind = 0, domain_len; - - if (size < 4 || data_[offset+1] != '/' || data_[offset+2] != '/') return 0; - - while (rewind < offset && isalpha(data_[offset-rewind - 1])) rewind++; - - if (!sd_autolink_issafe(data_.substr(offset-rewind, size+rewind))) return 0; - link_end = "://".length; - - domain_len = check_domain(data.slice(link_end), flags & SD_AUTOLINK_SHORT_DOMAINS); - if (domain_len == 0) return 0; - - link_end += domain_len; - while (link_end < size && !isspace(data_[offset+link_end])) link_end++; - - link_end = autolink_delim(data_, link_end, offset, size); - - if (link_end == 0) return 0; - - //TODO - link.s += data_.substr(offset-rewind, link_end+rewind); - rewind_p.p = rewind; - - return link_end; - } - - function sd_autolink__subreddit(rewind_p, link, data_, offset, size) { - var data = data_.slice(offset); - var link_end; - var allMinus = false; - - if (size < 3) return 0; - - /* make sure this / is part of /r/ */ - if (data.indexOf('/r/') != 0) return 0; - - link_end = "/r/".length; - if (data.substr(link_end-1, 4).toLowerCase() == "all-") { - allMinus = true; - } - do { - var start = link_end; - var max_length = 24; - /* special case: /r/reddit.com (the only subreddit with a '.') */ - if ( size >= link_end+10 && data.substr(link_end, 10).toLowerCase() == 'reddit.com') { - link_end += 10; - max_length = 10; - } else { - /* If not the special case make sure it starts with (t:)?[A-Za-z0-9] */ - /* support autolinking to timereddits, /r/t:when (1 April 2012) */ - if ( size > link_end+2 && data.substr(link_end, 2) == 't:') - link_end += 2; /* Jump over the 't:' */ - - /* the first character of a subreddit name must be a letter or digit */ - if (!isalnum(data[link_end])) - return 0; - link_end += 1; - } - - /* consume valid characters ([A-Za-z0-9_]) until we run out */ - while (link_end < size && (isalnum(data[link_end]) || - data[link_end] == '_')) - link_end++; - - /* valid subreddit names are between 3 and 21 characters, with - * some subreddits having 2-character names. Don't bother with - * autolinking for anything outside this length range. - * (chksrname function in reddit/.../validator.py) */ - if ( link_end-start < 2 || link_end-start > max_length ) - return 0; - - /* If we are linking to a multireddit, continue */ - } while ( link_end < size && (data[link_end] == '+' || (allMinus && data[link_end] == '-')) && link_end++ ); - if (link_end < size && data[link_end] == '/') { - while (link_end < size && (isalnum(data[link_end]) || - data[link_end] == '_' || - data[link_end] == '/' || - data[link_end] == '-')) { - link_end++; - } - } - /* make the link */ - link.s += data.slice(0, link_end); - rewind_p.p = 0; - - return link_end; - } - - function sd_autolink__username(rewind_p, link, data_, offset, size) { - var data = data_.slice(offset); - var link_end; - - if (size < 6) return 0; - - /* make sure this / is part of /u/ */ - if (data.indexOf('/u/') != 0) return 0; - - /* the first letter of a username must... well, be valid, we don't care otherwise */ - link_end = "/u/".length; - if (!isalnum(data[link_end]) && data[link_end] != '_' && data[link_end] != '-') - return 0; - link_end += 1; - - /* consume valid characters ([A-Za-z0-9_-/]) until we run out */ - while (link_end < size && (isalnum(data[link_end]) || - data[link_end] == '_' || - data[link_end] == '/' || - data[link_end] == '-')) - link_end++; - - /* make the link */ - link.s += data.slice(0, link_end); - rewind_p.p = 0; - - return link_end; - } - - function sd_autolink__email(rewind_p, link, data_, offset, size, flags) { - var data = data_.slice(offset); - var link_end, rewind; - var nb = 0, np = 0; - - for (rewind = 0; rewind < offset; ++rewind) { - var c = data_[offset-rewind - 1]; - - if (c == '\0') break; - - if (isalnum(c)) continue; - if (".+-_".indexOf(c) != -1) continue; - break; - } - - if (rewind == 0) return 0; - - for (link_end = 0; link_end < size; ++link_end) { - var c = data_[offset+link_end]; - - if (isalnum(c)) continue; - - if (c == '@') nb++; - else if (c == '.' && link_end < size - 1) np++; - else if (c != '-' && c != '_') break; - } - - if (link_end < 2 || nb != 1 || np == 0) return 0; - - //TODO - link_end = autolink_delim(data_, link_end, offset, size); - - if (link_end == 0) return 0; - - // link.s += data_.slice(offset - rewind, link_end + rewind - link.s += data_.substr(offset - rewind, link_end + rewind); - rewind_p.p = rewind; - - return link_end; - } - - function sd_autolink__www(rewind_p, link, data_, offset, size, flags) { - var data = data_.slice(offset); - var link_end; - - if (offset > 0 && !ispunct(data_[offset-1]) && !isspace(data_[offset-1])) - return 0; - - // if (size < 4 || memcmp(data, "www.", strlen("www.")) != 0) - if (size < 4 || (data.slice(0,4) != 'www.')) return 0; - - link_end = check_domain(data, 0); - - if (link_end == 0) - return 0; - - while (link_end < size && !isspace(data[link_end])) link_end++; - - link_end = autolink_delim(data_, link_end, offset, size); - - if (link_end == 0) return 0; - - link.s += data.slice(0, link_end); - rewind_p.p = 0; - - return link_end; - } - - /** - Initialize a Callbacks object. - - @constructor - @param {Object.} callbacks A set of callbacks to use as the methods on this object. - */ - function Callbacks(callbacks) { - if (callbacks) { - for (var name in callbacks) { - if (name in this) this[name] = callbacks[name]; - } - } - } - - Callbacks.prototype = { - /** - Renders a code block. - - Syntax highlighting specific to lanugage may be performed here. - - @method - @param {Buffer} out The output string buffer to append to. - @param {Buffer} text The input text. - @param {Buffer} language The name of the code langage. - @param {?Object} context A renderer specific context object. - */ - blockcode: null, - /** - Renders a blockquote. - - @method - @param {Buffer} out The output string buffer to append to. - @param {Buffer} text The input text. - @param {?Object} context A renderer specific context object. - */ - blockquote: null, - /** - Renders a block of HTML code. - - @method - @param {Buffer} out The output string buffer to append to. - @param {Buffer} text The input text. - @param {?Object} context A renderer specific context object. - */ - blockhtml: null, - /** - Renders a header. - - @method - @param {Buffer} out The output string buffer to append to. - @param {Buffer} text The input text. - @param {Number} level The header level. - @param {?Object} context A renderer specific context object. - */ - header: null, - /** - Renders a horizontal rule. - - @method - @param {Buffer} out The output string buffer to append to. - @param {?Object} context A renderer specific context object. - */ - hrule: null, - /** - Renders a list. -

- This method handles the list wrapper, which in terms of HTML would be <ol> or <ul>. - This method is not responsible for handling list elements, all such processing should - already have occured on text pased to the method . All that it is intended - to do is to wrap the text parameter in anything needed. -

- - @example - out.s += "<ul>" + text.s + "</ul>" - - - @method - @param {Buffer} out The output string buffer to append to. - @param {Buffer} text The input that goes inside the list. - @param {Number} flags A bitfield holding a portion of the render state. The only bit that this should be concerned with is MKD_LIST_ORDERED - @param {?Object} context A renderer specific context object. - */ - list: null, - /** - Renders a list. -

- Wraps the text in a list element. -

- - @example - out.s += "<li>" + text.s + "</li>" - - - @method - @param {Buffer} out The output string buffer to append to. - @param {Buffer} text The contents of the list element. - @param {Number} flags A bitfield holding a portion of the render state. The only bit that this should be concerned with is MKD_LI_BLOCK. - @param {?Object} context A renderer specific context object. - */ - listitem: null, - /** - Renders a paragraph. - - @example - - out.s += "<p>" + text.s + "</p>"; - - @method - @param {Buffer} out The output string buffer to append to. - @param {Buffer} text The input text. - @param {?Object} context A renderer specific context object. - */ - paragraph: null, - /** - Renders a table. - - @example - - out.s += ""; - out.s += header.s; - out.s += ""; - out.s += body.s; - out.s += "
"; - - @method - @param {Buffer} out The output string buffer to append to. - @param {Buffer} head The table header. - @param {Buffer} body The table body. - @param {?Object} context A renderer specific context object. - */ - table: null, - /** - Renders a table row. - - @example - - out.s += "<tr>" + text.s + "</tr>"; - - @method - @param {Buffer} out The output string buffer to append to. - @param {Buffer} text The input text. - @param {?Object} context A renderer specific context object. - */ - table_row: null, - /** - Renders a table cell. - - @example - - out.s += "<td>" + text.s + "</td>"; - - @method - @param {Buffer} out The output string buffer to append to. - @param {Buffer} text The input text. - @param {Number} flags A bit filed indicating a portion of the output state. Relevant bits are: MKD_TABLE_HEADER, MKD_TABLE_ALIGN_CENTER. MKD_TABLE_ALIGN_L, and MKD_TABLE_ALIGN_R. - @param {?Object} context A renderer specific context object. - */ - table_cell: null, - /** - Renders a link that was autodetected. - - @example - - out.s += "<a href=\""+ text.s + "\">" + text.s + "</a>"; - - @method - @param {Buffer} out The output string buffer to append to. - @param {Buffer} text The address being linked to. - @param {Number} type Equal to MKDA_NORMAL or MKDA_EMAIL - @param {?Object} context A renderer specific context object. - @returns {Boolean} Whether or not the tag was rendered. - */ - autolink: null, - /** - Renders inline code. - - @method - @param {Buffer} out The output string buffer to append to. - @param {Buffer} text The text being wrapped. - @param {?Object} context A renderer specific context object. - @returns {Boolean} Whether or not the tag was rendered. - */ - codespan: null, - /** - Renders text with double emphasis. Default is equivalent to the HTML <strong> tag. - - @method - @param {Buffer} out The output string buffer to append to. - @param {Buffer} text The text being wrapped. - @param {?Object} context A renderer specific context object. - @returns {Boolean} Whether or not the tag was rendered. - */ - double_emphasis: null, - /** - Renders text with single emphasis. Default is equivalent to the HTML <em> tag. - - @method - @param {Buffer} out The output string buffer to append to. - @param {Buffer} text The text being wrapped. - @param {?Object} context A renderer specific context object. - @returns {Boolean} Whether or not the tag was rendered. - */ - emphasis: null, - /** - Renders an image. - - @example - - out.s = "<img src=\"" + link.s + "\" title=\"" + title.s + "\" alt=\"" + alt.s + "\"/>";" - - @method - @param {Buffer} out The output string buffer to append to. - @param {Buffer} link The address of the image. - @param {Buffer} title Title text for the image - @param {Buffer} alt Alt text for the image - @param {?Object} context A renderer specific context object. - @returns {Boolean} Whether or not the tag was rendered. - */ - image: null, - /** - Renders line break. - - @example - - out.s += "<br/>"; - - @method - @param {Buffer} out The output string buffer to append to. - @param {?Object} context A renderer specific context object. - @returns {Boolean} Whether or not the tag was rendered. - */ - linebreak: null, - /** - Renders a link. - - @example - - out.s = "<a href=\"" + link.s + "\" title=\"" + title.s + "\">" + content.s + "</a>"; - - @method - @param {Buffer} out The output string buffer to append to. - @param {Buffer} link The link address. - @param {Buffer} title Title text for the link. - @param {Buffer} content Link text. - @param {?Object} context A renderer specific context object. - @returns {Boolean} Whether or not the tag was rendered. - */ - link: null, - /** - Copies and potentially escapes some HTML. - - @method - @param {Buffer} out The output string buffer to append to. - @param {Buffer} text The input text. - @param {?Object} context A renderer specific context object. - @returns {Boolean} Whether or not the tag was rendered. - */ - raw_html_tag: null, - /** - Renders text with triple emphasis. Default is equivalent to both the <em> and <strong> HTML tags. - - @method - @param {Buffer} out The output string buffer to append to. - @param {Buffer} text The text being wrapped. - @param {?Object} context A renderer specific context object. - @returns {Boolean} Whether or not the tag was rendered. - */ - triple_emphasis: null, - /** - Renders text crossd out. - - @method - @param {Buffer} out The output string buffer to append to. - @param {Buffer} text The text being wrapped. - @param {?Object} context A renderer specific context object. - @returns {Boolean} Whether or not the tag was rendered. - */ - strikethrough: null, - /** - Renders text as superscript. - - @method - @param {Buffer} out The output string buffer to append to. - @param {Buffer} text The text being wrapped. - @param {?Object} context A renderer specific context object. - @returns {Boolean} Whether or not the tag was rendered. - */ - superscript: null, - /** - Escapes an HTML entity. - - @method - @param {Buffer} out The output string buffer to append to. - @param {Buffer} text The text being wrapped. - @param {?Object} context A renderer specific context object. - */ - entity: null, - /** - Renders plain text. - - @method - @param {Buffer} out The output string buffer to append to. - @param {Buffer} text The text being rendered. - @param {?Object} context A renderer specific context object. - */ - normal_text: null, - /** - Creates opening boilerplate for a table of contents. - - @method - @param {Buffer} out The output string buffer to append to. - @param {?Object} context A renderer specific context object. - */ - doc_header: null, - /** - Creates closing boilerplate for a table of contents. - - @method - @param {Buffer} out The output string buffer to append to. - @param {?Object} context A renderer specific context object. - */ - doc_footer: null - }; - - - /** - A renderer object - - @constructor - @param {Callbacks} callbacks The callbacks object to use for the renderer. - @param {?Callbacks} context Renderer specific context information. - */ - function Renderer(callbacks, context) { - this.callbacks = callbacks; - this.context = context; - } - - /** - Instantiates a custom Renderer object. - - @param {Callbacks} callbacks The callbacks object to use for the renderer. - @param {?Callbacks} context Renderer specific context information. - @returns {Renderer} - */ - function createCustomRenderer(callbacks, context) { - return new Renderer(callbacks, context) - } - exports.createCustomRenderer = createCustomRenderer; - - function defaultRenderState() { - return { - nofollow: 0, - target: null, - tocData: { - headerCount: 0, - currentLevel: 0, - levelOffset: 0 - }, - toc_id_prefix: null, - html_element_whitelist: DEFAULT_HTML_ELEMENT_WHITELIST, - html_attr_whitelist: DEFAULT_HTML_ATTR_WHITELIST, - flags: 0, - //(flags != undefined?flags:HTML_SKIP_HTML | HTML_SKIP_IMAGES | HTML_SAFELINK | HTML_ESCAPE | HTML_USE_XHTML), - /* extra callbacks */ - // void (*link_attributes)(struct buf *ob, const struct buf *url, void *self); - link_attributes: function link_attributes(out, url, options) { - - if (options.nofollow) out.s += ' rel="nofollow"'; - - if (options.target != null) { - out.s += ' target="' + options.target + '"'; - } - } - }; - } - exports.defaultRenderState = defaultRenderState; - /** - Produces a renderer object that will match Reddit's output. - @param {?Number=} flags A bitfield containing flags specific to the reddit HTML renderer. Passing undefined, null, or null value will produce reddit exact output. - @returns {Renderer} A renderer object that will match Reddit's output. - */ - function getRedditRenderer(flags) { - var state =defaultRenderState(); - if (flags == null) { - state.flags = DEFAULT_BODY_FLAGS; - } else { - state.flags = flags; - } - - var renderer = new Renderer(getRedditCallbacks() , state); - if (renderer.context.flags & HTML_SKIP_IMAGES) - renderer.callbacks.image = null; - - if (renderer.context.flags & HTML_SKIP_LINKS) { - renderer.callbacks.link = null; - renderer.callbacks.autolink = null; - } - - if (renderer.context.flags & HTML_SKIP_HTML || renderer.context.flags & HTML_ESCAPE) - renderer.callbacks.blockhtml = null; - return renderer; - } - exports.getRedditRenderer = getRedditRenderer; - - /** - Produces a renderer object that will match Reddit's for a table of contents. - @returns {Renderer} A renderer object that will match Reddit's output. - */ - function getTocRenderer() { - var state = defaultRenderState(); - state.flags = HTML_TOC | HTML_SKIP_HTML; - var renderer = new Renderer(getTocCallbacks(), state); - return renderer; - } - exports.getTocRenderer = getTocRenderer; - - /** - Create a Callbacks object with the given callback table. - - @param {Object.} callbacks A table of callbacks to place int a callbacks object. - @returns {Callbacks} A callbacks object holding the provided callbacks. - */ - function createCustomCallbacks(callbacks) { - return new Callbacks(callbacks); - } - exports.createCustomCallbacks = createCustomCallbacks; - - /** - Produce a callbacks object that matches Reddit's output. - @returns {Callbacks} A callbacks object that matches Reddit's output. - */ - function getRedditCallbacks(){ - return new Callbacks({ - blockcode: cb_blockcode, - blockquote: cb_blockquote, - blockhtml: cb_blockhtml, - header: cb_header, - hrule: cb_hrule, - list: cb_list, - listitem: cb_listitem, - paragraph: cb_paragraph, - table: cb_table, - table_row: cb_table_row, - table_cell: cb_table_cell, - autolink: cb_autolink, - codespan: cb_codespan, - double_emphasis: cb_double_emphasis, - emphasis: cb_emphasis, - image: cb_image, - linebreak: cb_linebreak, - link: cb_link, - raw_html_tag: cb_raw_html_tag, - triple_emphasis: cb_triple_emphasis, - strikethrough: cb_strikethrough, - superscript: cb_superscript, - entity: null, - normal_text: cb_normal_text, - doc_header: null, - doc_footer: cb_reset_toc - }); - } - exports.getRedditCallbacks = getRedditCallbacks; - - /** - Produce a callbacks object for rendering a table of contents. - @returns {Callbacks} A callbacks object for rendering a table of contents. - */ - function getTocCallbacks() { - return new Callbacks({ - blockcode: null, - blockquote: null, - blockhtml: null, - header: cb_toc_header, - hrule: null, - list: null, - listitem: null, - paragraph: null, - table: null, - table_row: null, - table_cell: null, - autolink: null, - codespan: cb_codespan, - double_emphasis: cb_double_emphasis, - emphasis: cb_emphasis, - image: null, - linebreak: null, - link: cb_toc_link, - raw_html_tag: null, - triple_emphasis: cb_triple_emphasis, - strikethrough: cb_strikethrough, - superscript: cb_superscript, - entity: null, - normal_text: null, - doc_header: null, - doc_footer: cb_toc_finalize - }); - } - exports.getTocCallbacks = getTocCallbacks; - - /* block level callbacks - NULL skips the block */ - // void (*blockcode)(struct buf *ob, const struct buf *text, const struct buf *lang, void *opaque); - function cb_blockcode(out, text, lang, options) { - if (out.s.length) out.s += '\n'; - - if (lang && lang.s.length) { - var i, cls; - out.s += '
';
-		} else
-			out.s += '
';
-
-		if (text) escape_html(out, text.s, false);
-
-		out.s += '
\n'; - } - - // void (*blockquote)(struct buf *ob, const struct buf *text, void *opaque); - function cb_blockquote(out, text, options) { - if (out.s.length) out.s += '\n'; - out.s += '
\n'; - if (text) out.s += text.s; - out.s += '
\n'; - } - - // void (*blockhtml)(struct buf *ob,const struct buf *text, void *opaque); - function cb_blockhtml(out, text, options) { - var org, sz; - if (!text) return; - sz = text.s.length; - while (sz > 0 && text.s[sz - 1] == '\n') sz--; - org = 0; - while (org < sz && text.s[org] == '\n') org++; - if (org >= sz) return; - if (out.s.length) out.s += '\n'; - out.s += text.s.slice(org, sz); - out.s += '\n'; - } - - // header(Buffer out, Buffer text, int level, void *opaque); - function cb_header(out, text, level, options) { - if (out.s.length) out.s += '\n'; - - if (options.flags & HTML_TOC) { - out.s += ''; - } else { - out.s += ''; - } - - if (text) out.s += text.s; - out.s += '\n'; - } - - // void (*hrule)(struct buf *ob, void *opaque); - function cb_hrule(out, options) { - if (out.s.length) out.s += '\n'; - out.s += (options.flags & HTML_USE_XHTML) ? '
\n' : '
\n'; - } - - // void (*list)(struct buf *ob, const struct buf *text, int flags, void *opaque); - function cb_list(out, text, flags, options) { - if (out.s.length) out.s += '\n'; - out.s += (flags&MKD_LIST_ORDERED?'
    \n':'
      \n'); - if (text) out.s += text.s; - out.s += (flags&MKD_LIST_ORDERED?'
\n':'\n'); - } - - // void (*listitem)(struct buf *ob, const struct buf *text, int flags, void *opaque); - function cb_listitem(out, text, flags, options) { - out.s += '
  • '; - if (text) { - var size = text.s.length; - while (size && text.s[size - 1] == '\n') size--; - out.s += text.s.slice(0, size); - } - out.s += '
  • \n'; - } - - // void (*paragraph)(struct buf *ob, const struct buf *text, void *opaque); - function cb_paragraph(out, text, options) { - var i = 0; - - if (out.s.length) out.s += '\n'; - - if (!text || !text.s.length) return; - - while (i < text.s.length && isspace(text.s[i])) i++; - - if (i == text.s.length) return; - - out.s += '

    '; - if (options.flags & HTML_HARD_WRAP) { - var org; - while (i < text.s.length) { - org = i; - while (i < text.s.length && text.data[i] != '\n') - i++; - - if (i > org) out.s += text.s.slice(org, i); - - /* - * do not insert a line break if this newline - * is the last character on the paragraph - */ - if (i >= text.s.length - 1) break; - - cb_linebreak(out, options); - i++; - } - } else { - out.s += text.s.slice(i); - } - out.s += '

    \n'; - } - - // void (*table)(struct buf *ob, const struct buf *header, const struct buf *body, void *opaque); - function cb_table(out, header, body, options) { - if (out.s.length) out.s += '\n'; - out.s += '\n'; - if (header) out.s += header.s; - out.s += '\n'; - if (body) out.s += body.s; - out.s += '
    \n'; - } - - // void (*table_row)(struct buf *ob, const struct buf *text, void *opaque); - function cb_table_row(out, text, options) { - out.s += '\n'; - if (text) out.s += text.s; - out.s += '\n'; - } - - // void (*table_cell)(struct buf *ob, const struct buf *text, int flags, void *opaque); - function cb_table_cell(out, text, flags, options, col_span) { - if (flags & MKD_TABLE_HEADER) { - out.s += ' 1) { - out.s += " colspan=\"" + col_span + "\" "; - } - switch (flags & MKD_TABLE_ALIGNMASK) { - case MKD_TABLE_ALIGN_CENTER: - out.s += ' align="center">'; - break; - - case MKD_TABLE_ALIGN_L: - out.s += ' align="left">'; - break; - - case MKD_TABLE_ALIGN_R: - out.s += ' align="right">'; - break; - default: - out.s += '>'; - } - - if (text) out.s += text.s; - - if (flags & MKD_TABLE_HEADER) { - out.s += '\n'; - } else { - out.s += '\n'; - } - } - - /* span level callbacks - NULL or return 0 prints the span verbatim */ - // int (*autolink)(struct buf *ob, const struct buf *link, enum mkd_autolink type, void *opaque); - function cb_autolink(out, link, type, options) { - var offset = 0; - - if (!link || !link.s.length) return 0; - - if ((options.flags & HTML_SAFELINK) != 0 && - !sd_autolink_issafe(link.s) && type != MKDA_EMAIL) - return 0; - - out.s += ''; - return 1; - } - - // int (*emphasis)(struct buf *ob, const struct buf *text, void *opaque); - function cb_emphasis(out, text, options) { - if (!text || !text.s.length) return 0; - out.s += '' + text.s + ''; - return 1; - } - - // int (*image)(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *alt, void *opaque); - function cb_image(out, link, title, alt, options) { - if (!link || !link.s.length) return 0; - - out.s += '';
-
-		if (alt && alt.s.length) escape_html(out, alt.s, false);
-
-		if (title && title.s.length) {
-			out.s += '':'">'); - return 1; - } - - - // int (*linebreak)(struct buf *ob, void *opaque); - function cb_linebreak(out, options) { - out.s += (options.flags&HTML_USE_XHTML?'
    \n':'
    \n'); - return 1; - } - - // int (*link)(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *content, void *opaque); - function cb_link(out, link, title, content, options) { - if (link != null && (options.flags & HTML_SAFELINK) != 0 && !sd_autolink_issafe(link.s)) return 0; - - out.s += '
    "; - return; - } - - out.s += tagname; - var i = 1 + tagname.length; - - attr = new Buffer; - value = new Buffer; - - for(;i < text.s.length && !done; i++) { - c = text.s[i]; - done = 0; - reset = 0; - done_attr = 0; - - switch(c) { - case '>': - done = 1; - break; - case '\'': - case '"': - if (!seen_equals) { - reset = 1; - } else if(!in_str) { - in_str = c; - } else if(in_str == c) { - in_str = 0; - done_attr = 1; - } else { - value.s += c; - } - break; - case ' ': - if (in_str) { - value.s += ' '; - } else { - reset = 1; - } - break; - case '=': - if (seen_equals) { - reset = 1; - break; - } - seen_equals = 1; - break; - default: - if (seen_equals && in_str || !seen_equals) { - if (seen_equals) { - value.s += c; - } else { - attr.s += c; - } - } - break; - } - - if (done_attr) { - var valid = 0; - for (z = 0; whitelist[z]; z++) { - if (whitelist[z].length != attr.s.length) { - continue; - } - for (x = 0; x < attr.s.length; x++) { - if (whitelist[z][x].toLowerCase() != attr.s[x].toLowerCase()) { - break; - } - } - if (x == attr.s.length) { - valid = 1; - break; - } - } - if (valid && value.s.length && attr.s.length) { - // console.log("VALD", value.s.length, attr.s.length); - out.s += ' '; - escape_html(out, attr.s, false); - out.s += '="'; - escape_html(out, value.s, false) - out.s += '"'; - } - reset = 1; - } - if (reset) { - seen_equals = 0; - in_str = 0; - attr = new Buffer; - value = new Buffer; - } - } - out.s += '>'; - } - - // int (*raw_html_tag)(struct buf *ob, const struct buf *tag, void *opaque); - function cb_raw_html_tag(out, text, options) { - var whitelist = options.html_element_whitelist; - - /* Items on the whitelist ignore all other flags and just output */ - if (((options.flags & HTML_ALLOW_ELEMENT_WHITELIST) != 0) && whitelist) { - for(var i = 0; whitelist[i]; i++) { - var tagtype = sdhtml_is_tag(text.s, whitelist[i]); - if(tagtype != HTML_TAG_NONE) { - rndr_html_tag(out, text, options, whitelist[i], options.html_attr_whitelist, tagtype); - return 1; - } - } - } - - /* HTML_ESCAPE overrides SKIP_HTML, SKIP_STYLE, SKIP_LINKS and SKIP_IMAGES - * It doens't see if there are any valid tags, just escape all of them. */ - if((options.flags & HTML_ESCAPE) != 0) { - escape_html(out, text.s, false); - return 1; - } - - if ((options.flags & HTML_SKIP_HTML) != 0) return 1; - - if ((options.flags & HTML_SKIP_STYLE) != 0 && - sdhtml_is_tag(text.s, "style")) - return 1; - - if ((options.flags & HTML_SKIP_LINKS) != 0 && - sdhtml_is_tag(text.s, "a")) - return 1; - - if ((options.flags & HTML_SKIP_IMAGES) != 0 && - sdhtml_is_tag(text.s, "img")) - return 1; - - out.s += text.s; - return 1; - } - - // int (*triple_emphasis)(struct buf *ob, const struct buf *text, void *opaque); - function cb_triple_emphasis(out, text, options) { - if (!text || !text.s.length) return 0; - out.s += '' + text.s + ''; - return 1; - } - - // int (*strikethrough)(struct buf *ob, const struct buf *text, void *opaque); - function cb_strikethrough(out, text, options) { - if (!text || !text.s.length) return 0; - out.s += '' + text.s + ''; - return 1; - } - - // int (*superscript)(struct buf *ob, const struct buf *text, void *opaque); - function cb_superscript(out, text, options) { - if (!text || !text.s.length) return 0; - out.s += '' + text.s + ''; - return 1; - } - - /* low level callbacks - NULL copies input directly into the output */ - //do not use - // void (*entity)(struct buf *ob, const struct buf *entity, void *opaque); - // function cb_entity(out, entity, options) {} - - // void (*normal_text)(struct buf *ob, const struct buf *text, void *opaque); - function cb_normal_text(out, text, options) { - if (text) escape_html(out, text.s, false); - } - - // toc_header(struct buf *ob, const struct buf *text, int level, void *opaque) - function cb_toc_header(out, text, level, options) { - /* set the level offset if this is the first header - * we're parsing for the document */ - if (options.tocData.currentLevel== 0) { - out.s += '
    \n'; - options.tocData.levelOffset = level - 1; - } - level -= options.tocData.levelOffset; - - if (level > options.tocData.currentLevel) { - while (level > options.tocData.currentLevel) { - out.s += '
      \n
    • \n'; - options.tocData.currentLevel++; - } - } else if (level < options.tocData.currentLevel) { - out.s += '
    • \n'; - while (level < options.tocData.currentLevel) { - out.s += '
    \n\n'; - options.tocData.currentLevel--; - } - out.s += '
  • \n'; - } else { - out.s += '
  • \n
  • \n'; - } - - out.s += ''; - if (text) escape_html(out, text.s, false); - out.s += '\n'; - } - - //toc_link(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *content, void *opaque) - function cb_toc_link(out, link, title, content, options) { - if (content && content.s) - out.s += content.s; - return 1; - } - - - // reset_toc(struct buf *ob, void *opaque) - function cb_reset_toc(out, options) { - options.tocData = { - headerCount: 0, - currentLevel: 0, - levelOffset: 0 - }; - } - - //toc_finalize(struct buf *ob, void *opaque) - function cb_toc_finalize(out, options) { - var hasToc = false; - while (options.tocData.currentLevel > 0) { - out.s += '
  • \n\n'; - options.tocData.currentLevel--; - hasToc = true; - } - if (hasToc) { - out.s += '
    \n'; - } - cb_reset_toc(out, options); - } - - /* header and footer */ - // doc_header(Buffer out}, context); - // doc_header: null, - // doc_footer(Buffer out, context); - // doc_footer: null - - - /* char_emphasis • single and double emphasis parsing */ - //Buffer, md, str, int - function char_emphasis(out, md, data_, offset) { - var data = data_.slice(offset); - var size = data.length; - var c = data[0]; - var ret; - - if (size > 2 && data[1] != c) { - /* whitespace cannot follow an opening emphasis; - * strikethrough only takes two characters '~~' */ - if (c == '~' || _isspace(data[1]) || (ret = parse_emph1(out, md, data, c)) == 0) - return 0; - - return ret + 1; - } - - if (data.length > 3 && data[1] == c && data[2] != c) { - if (_isspace(data[2]) || (ret = parse_emph2(out, md, data, c)) == 0) - return 0; - - return ret + 2; - } - - if (data.length > 4 && data[1] == c && data[2] == c && data[3] != c) { - if (c == '~' || _isspace(data[3]) || (ret = parse_emph3(out, md, data, c)) == 0) - return 0; - - return ret + 3; - } - - return 0; - } - - /* char_codespan - '`' parsing a code span (assuming codespan != 0) */ - function char_codespan(out, md, data_, offset) { - var data = data_.slice(offset); - var end, nb = 0, i, f_begin, f_end; - - /* counting the number of backticks in the delimiter */ - while (nb < data.length && data[nb] == '`') - nb++; - - /* finding the next delimiter */ - i = 0; - for (end = nb; end < data.length && i < nb; end++) { - if (data[end] == '`') i++; - else i = 0; - } - - if (i < nb && end >= data.length) - return 0; /* no matching delimiter */ - - /* trimming outside whitespaces */ - f_begin = nb; - while (f_begin < end && data[f_begin] == ' ') f_begin++; - - f_end = end - nb; - while (f_end > nb && data[f_end-1] == ' ') f_end--; - - /* real code span */ - if (f_begin < f_end) { - var work = new Buffer(data.slice(f_begin, f_end)); - if (!md.callbacks.codespan(out, work, md.context)) - end = 0; - } else { - if (!md.callbacks.codespan(out, null, md.context)) - end = 0; - } - - return end; - } - - /* char_linebreak - '\n' preceded by two spaces (assuming linebreak != 0) */ - function char_linebreak(out, md, data_, offset) { - var data = data_.slice(offset); - if (offset < 2 || data_[offset-1] != ' ' || data_[offset-2] != ' ') - return 0; - - /* removing the last space from ob and rendering */ - var len = out.s.length; - while (len && out.s[len - 1] == ' ') len--; - out.s = out.s.slice(0, len); - - return md.callbacks.linebreak(out, md.context) ? 1 : 0; - } - - /* char_link - '[': parsing a link or an image */ - function char_link(out, md, data_, offset) { - var data = data_.slice(offset); - var is_img = (offset && data_[offset - 1] == '!'), level; - var i = 1, txt_e, link_b = 0, link_e = 0, title_b = 0, title_e = 0; - //4 bufs - var content = null; - var link = null; - var title = null; - var u_link = null; - var org_work_size = md.spanStack.length; - var text_has_nl = 0, ret = 0; - var in_title = 0, qtype = 0; - - function cleanup() { - md.spanStack.length = org_work_size; - return ret ? i : 0; - } - - /* checking whether the correct renderer exists */ - if ((is_img && !md.callbacks.image) || (!is_img && !md.callbacks.link)) - return cleanup(); - /* looking for the matching closing bracket */ - for (level = 1; i < data.length; i++) { - if (data[i] == '\n') text_has_nl = 1; - else if (data[i - 1] == '\\') continue; - else if (data[i] == '[') level++; - else if (data[i] == ']') { - level--; - if (level <= 0) break; - } - } - - if (i >= data.length) return cleanup(); - - txt_e = i; - i++; - - /* skip any amount of whitespace or newline */ - /* (this is much more laxist than original markdown syntax) */ - while (i < data.length && _isspace(data[i])) i++; - - /* inline style link */ - if (i < data.length && data[i] == '(') { - /* skipping initial whitespace */ - i++; - - while (i < data.length && _isspace(data[i])) i++; - - link_b = i; - - /* looking for link end: ' " ) */ - while (i < data.length) { - if (data[i] == '\\') i += 2; - else if (data[i] == ')') break; - else if (i >= 1 && _isspace(data[i-1]) && (data[i] == '\'' || data[i] == '"')) break; - else i++; - } - - if (i >= data.length) return cleanup(); - link_e = i; - - /* looking for title end if present */ - if (data[i] == '\'' || data[i] == '"') { - qtype = data[i]; - in_title = 1; - i++; - title_b = i; - - while (i < data.length) { - if (data[i] == '\\') i += 2; - else if (data[i] == qtype) {in_title = 0; i++;} - else if ((data[i] == ')') && !in_title) break; - else i++; - } - - if (i >= data.length) return cleanup(); - - /* skipping whitespaces after title */ - title_e = i - 1; - while (title_e > title_b && _isspace(data[title_e])) title_e--; - - /* checking for closing quote presence */ - if (data[title_e] != '\'' && data[title_e] != '"') { - title_b = title_e = 0; - link_e = i; - } - } - - /* remove whitespace at the end of the link */ - while (link_e > link_b && _isspace(data[link_e - 1])) link_e--; - - /* remove optional angle brackets around the link */ - if (data[link_b] == '<') link_b++; - if (data[link_e - 1] == '>') link_e--; - - /* building escaped link and title */ - if (link_e > link_b) { - link = new Buffer(); - md.spanStack.push(link); - link.s += data.slice(link_b, link_e); - } - - if (title_e > title_b) { - title = new Buffer(); - md.spanStack.push(title); - title.s += data.slice(title_b, title_e); - } - - i++; - } - - /* reference style link */ - else if (i < data.length && data[i] == '[') { - var id = new Buffer(); - var lr = null; - - /* looking for the id */ - i++; - link_b = i; - while (i < data.length && data[i] != ']') i++; - if (i >= data.length) return cleanup(); - link_e = i; - - /* finding the link_ref */ - if (link_b == link_e) { - if (text_has_nl) { - var b = new Buffer(); - md.spanStack.push(b); - var j; - - for (j = 1; j < txt_e; j++) { - if (data[j] != '\n') - b.s += data[j]; - else if (data[j - 1] != ' ') - b.s += ' '; - } - - id.s = b.s; - } else { - id.s = data.slice(1); - } - } else { - id.s = data.slice(link_b, link_e); - } - - //TODO - lr = md.refs[id.s]; - if (!lr) return cleanup(); - - /* keeping link and title from link_ref */ - link = lr.link; - title = lr.title; - i++; - } - - /* shortcut reference style link */ - else { - var id = new Buffer(); - var lr = null; - - /* crafting the id */ - if (text_has_nl) { - var b = new Buffer(); - md.spanStack.push(b); - - var j; - for (j = 1; j < txt_e; j++) { - if (data[j] != '\n') b.s += data[j]; - else if (data[j - 1] != ' ') b.s += ' '; - } - - id.s = b.s; - } else { - id.s = data.slice(1, txt_e); - } - - /* finding the link_ref */ - lr = md.refs[id.s]; - if (!lr) return cleanup(); - - /* keeping link and title from link_ref */ - link = lr.link; - title = lr.title; - - /* rewinding the whitespace */ - i = txt_e + 1; - } - - /* building content: img alt is escaped, link content is parsed */ - if (txt_e > 1) { - content = new Buffer(); - md.spanStack.push(content); - if (is_img) { - content.s += data.slice(1, txt_e); - } else { - /* disable autolinking when parsing inline the - * content of a link */ - md.inLinkBody = 1; - parse_inline(content, md, data.slice(1, txt_e)); - md.inLinkBody = 0; - } - } - - if (link) { - u_link = new Buffer(); - md.spanStack.push(u_link); - unscape_text(u_link, link); - } else { - return cleanup(); - } - - /* calling the relevant rendering function */ - if (is_img) { - if (out.s.length && out.s[out.s.length - 1] == '!') - out.s = out.s.slice(0, -1); - - ret = md.callbacks.image(out, u_link, title, content, md.context); - } else { - ret = md.callbacks.link(out, u_link, title, content, md.context); - } - - /* cleanup */ - // cleanup: - // rndr->work_bufs[BUFFER_SPAN].size = (int)org_work_size; - // return ret ? i : 0; - return cleanup(); - } - - - /* char_langle_tag - '<' when tags or autolinks are allowed */ - function char_langle_tag(out, md, data_, offset) { - var data = data_.slice(offset); - var altype = {p:MKDA_NOT_AUTOLINK}; - var end = tag_length(data, altype); - var work = new Buffer(data.slice(0, end)); - var ret = 0; - - if (end > 2) { - if (md.callbacks.autolink && altype.p != MKDA_NOT_AUTOLINK) { - var u_link = new Buffer(); - md.spanStack.push(u_link); - work.s = data.substr(1 , end - 2); - unscape_text(u_link, work); - ret = md.callbacks.autolink(out, u_link, altype.p, md.context); - md.spanStack.pop(); - } - else if (md.callbacks.raw_html_tag) - ret = md.callbacks.raw_html_tag(out, work, md.context); - } - - if (!ret) return 0; - else return end; - } - - - /* char_escape - '\\' backslash escape */ - function char_escape(out, md, data_, offset) { - var data = data_.slice(offset); - var escape_chars = "\\`*_{}[]()#+-.!:|&<>/^~"; - var work = new Buffer(); - - if (data.length > 1) { - if (escape_chars.indexOf(data[1]) == -1) return 0; - - if (md.callbacks.normal_text) { - work.s = data[1]; - md.callbacks.normal_text(out, work, md.context); - } - else out.s += data[1]; - } else if (data.length == 1) { - out.s += data[0]; - } - - return 2; - } - - - - /* char_entity - '&' escaped when it doesn't belong to an entity */ - //-/* valid entities are assumed to be anything matching &#?[A-Za-z0-9]+; */ - function char_entity(out, md, data_, offset) { - var data = data_.slice(offset); - var end = 1, content_start, content_end; - var numeric = false, hex = false, entity_base, entity_val; - var work = new Buffer(); - - if (end < data.length && data[end] === '#') { - numeric = true; - end++; - } - - if (end < data.length && numeric && data[end].toLowerCase() === 'x') { - hex = true; - end++; - } - - content_start = end; - while (end < data.length) { - var c = data[end]; - if (hex) { - if (!isxdigit(c)) break; - } else if (numeric) { - if (!isdigit(c)) break; - } else if (!isalnum(c)) { - break; - } - end++; - } - - - if (end > content_start && end < data.length && data[end] === ';') { - /* well formed entity */ - end++; - } else { - return 0; /* not an entity */ - } - - /* way too long to be a valid numeric entity */ - if (numeric && content_end - content_start > MAX_NUM_ENTITY_LEN) { - return 0; - } - - /* Validate the entity's contents */ - if (numeric) { - if (hex) entity_base = 16; - else entity_base = 10; - entity_val = parseInt(data.slice(content_start), entity_base); - if (!is_valid_numeric_entity(entity_val)) return 0; - } else { - if (VALID_ENTITIES.indexOf(data.slice(0, end)) === -1) return 0; - } - - if (md.callbacks.entity) { - work.s = data.slice(0, end); - md.callbacks.entity(out, work, md.context); - } - else out.s += data.slice(0, end); - - return end; - } - - function char_autolink_url(out, md, data_, offset) { - var data = data_.slice(offset); - var link = null; - var link_len, rewind = {p: null}; - - if (!md.callbacks.autolink || md.inLinkBody) return 0; - - link = new Buffer(); - md.spanStack.push(link); - - if ((link_len = sd_autolink__url(rewind, link, data_, offset, data.length, 0)) > 0) { - if (rewind.p > 0) out.truncate(out.s.length - rewind.p); - md.callbacks.autolink(out, link, MKDA_NORMAL, md.context); - } - - md.spanStack.pop(); - return link_len; - } - - - function char_autolink_email(out, md, data_, offset) { - var data = data_.slice(offset); - var link = null; - var link_len, rewind = {p: null}; - - if (!md.callbacks.autolink || md.inLinkBody) return 0; - - link = new Buffer(); - md.spanStack.push(link); - - if ((link_len = sd_autolink__email(rewind, link, data_, offset, data.length, 0)) > 0) { - if (rewind.p > 0) out.truncate(out.s.length - rewind.p); - md.callbacks.autolink(out, link, MKDA_EMAIL, md.context); - } - - md.spanStack.pop(); - return link_len; - } - - - function char_autolink_www(out, md, data_, offset) { - var data = data_.slice(offset); - var link = null, link_url = null, link_text = null; - var link_len, rewind = {p: null}; - - if (!md.callbacks.link || md.inLinkBody) return 0; - - link = new Buffer(); - md.spanStack.push(link); - - if ((link_len = sd_autolink__www(rewind, link, data_, offset, data.length, 0)) > 0) { - link_url = new Buffer(); - md.spanStack.push(link_url); - link_url.s += 'http://'; - link_url.s += link.s; - - if (rewind.p > 0) out.truncate(out.s.length - rewind.p); - - if (md.callbacks.normal_text) { - link_text = new Buffer(); - md.spanStack.push(link_text); - md.callbacks.normal_text(link_text, link, md.context); - md.callbacks.link(out, link_url, null, link_text, md.context); - md.spanStack.pop(); - } else { - md.callbacks.link(out, link_url, null, link, md.context); - } - md.spanStack.pop(); - } - - md.spanStack.pop(); - return link_len; - } - - function char_autolink_subreddit_or_username(out, md, data_, offset) { - var data = data_.slice(offset); - var link = null; - var link_len, rewind = {p: null}; - - if (!md.callbacks.autolink || md.inLinkBody) return 0; - - link = new Buffer(); - md.spanStack.push(link); - if ((link_len = sd_autolink__subreddit(rewind, link, data_, offset, data.length)) > 0) { - //don't slice because the rewind pointer will always be 0 - if (rewind.p > 0) out.truncate(out.s.length - rewind.p); - md.callbacks.autolink(out, link, MKDA_NORMAL, md.context); - } else if ((link_len = sd_autolink__username(rewind, link, data_, offset, data.length)) > 0) { - //don't slice because the rewind pointer will always be 0 - if (rewind.p > 0) out.truncate(out.s.length - rewind.p); - md.callbacks.autolink(out, link, MKDA_NORMAL, md.context); - } - md.spanStack.pop(); - - return link_len; - } - - function char_superscript(out, md, data_, offset) { - var data = data_.slice(offset); - var size = data.length; - var sup_start, sup_len; - var sup = null; - - if (!md.callbacks.superscript) return 0; - - if (size < 2) return 0; - - if (data[1] == '(') { - sup_start = sup_len = 2; - - while (sup_len < size && data[sup_len] != ')' && data[sup_len - 1] != '\\') sup_len++; - - if (sup_len == size) return 0; - } else { - sup_start = sup_len = 1; - - while (sup_len < size && !_isspace(data[sup_len])) sup_len++; - } - - if (sup_len - sup_start == 0) return (sup_start == 2) ? 3 : 0; - - sup = new Buffer(); - md.spanStack.push(sup); - parse_inline(sup, md, data.slice(sup_start, sup_len)); - md.callbacks.superscript(out, sup, md.context); - md.spanStack.pop(); - - return (sup_start == 2) ? sup_len + 1 : sup_len; - } - - - var markdown_char_ptrs = [ - null, - char_emphasis, - char_codespan, - char_linebreak, - char_link, - char_langle_tag, - char_escape, - char_entity, - char_autolink_url, - char_autolink_email, - char_autolink_www, - char_autolink_subreddit_or_username, - char_superscript - ]; - - var MKD_LIST_ORDERED = 1; - var MKD_LI_BLOCK = 2; /*
  • containing block data */ - var MKD_LI_END = 8; /* internal list flag */ - - var enumCounter = 0; - var MD_CHAR_NONE = enumCounter++; - var MD_CHAR_EMPHASIS = enumCounter++; - var MD_CHAR_CODESPAN = enumCounter++; - var MD_CHAR_LINEBREAK = enumCounter++; - var MD_CHAR_LINK = enumCounter++; - var MD_CHAR_LANGLE = enumCounter++; - var MD_CHAR_ESCAPE = enumCounter++; - var MD_CHAR_ENTITITY = enumCounter++; - var MD_CHAR_AUTOLINK_URL = enumCounter++; - var MD_CHAR_AUTOLINK_EMAIL = enumCounter++; - var MD_CHAR_AUTOLINK_WWW = enumCounter++; - var MD_CHAR_AUTOLINK_SUBREDDIT_OR_USERNAME = enumCounter++; - var MD_CHAR_SUPERSCRIPT = enumCounter++; - - var SD_AUTOLINK_SHORT_DOMAINS = (1 << 0); - - enumCounter = 0; - var MKDA_NOT_AUTOLINK = enumCounter++; /* used internally when it is not an autolink*/ - var MKDA_NORMAL = enumCounter++; /* normal http/http/ftp/mailto/etc link */ - var MKDA_EMAIL = enumCounter++; /* e-mail link without explit mailto: */ - - var MKDEXT_NO_INTRA_EMPHASIS = (1 << 0); - var MKDEXT_TABLES = (1 << 1); - var MKDEXT_FENCED_CODE = (1 << 2); - var MKDEXT_AUTOLINK = (1 << 3); - var MKDEXT_STRIKETHROUGH = (1 << 4); - // var MKDEXT_LAX_HTML_BLOCKS = (1 << 5); - var MKDEXT_SPACE_HEADERS = (1 << 6); - var MKDEXT_SUPERSCRIPT = (1 << 7); - var MKDEXT_LAX_SPACING = (1 << 8) - var MKDEXT_NO_EMAIL_AUTOLINK = (1 << 9) - - var HTML_SKIP_HTML = (1 << 0); - var HTML_SKIP_STYLE = (1 << 1); - var HTML_SKIP_IMAGES = (1 << 2); - var HTML_SKIP_LINKS = (1 << 3); - var HTML_EXPAND_TABS = (1 << 4); - var HTML_SAFELINK = (1 << 5); - var HTML_TOC = (1 << 6); - var HTML_HARD_WRAP = (1 << 7); - var HTML_USE_XHTML = (1 << 8); - var HTML_ESCAPE = (1 << 9); - var HTML_ALLOW_ELEMENT_WHITELIST = (1 << 10); - - var MKD_TABLE_ALIGN_L = 1; - var MKD_TABLE_ALIGN_R = 2; - var MKD_TABLE_ALIGN_CENTER = 3; - var MKD_TABLE_ALIGNMASK = 3; - var MKD_TABLE_HEADER = 4 - - var HTML_TAG_NONE = 0; - var HTML_TAG_OPEN = 1; - var HTML_TAG_CLOSE = 2; - - - /** - * A string buffer wrapper because JavaScript doesn't have mutable strings. - * @constructor - * @param {string=} str Optional string to initialize the Buffer with. - */ - function Buffer(str) { - this.s = str || ""; - }; - - /** - */ - Buffer.prototype.truncate = function(size) { - if (this.s.length < size) throw new RangeError("Buffer smaller than desired size"); - if (size < 0) throw new RangeError("Size argument is negative"); - this.s = this.s.slice(0, size); - } - - - /** - * A Markdown parser object. - * @constructor - */ - function Markdown() { - - //Becase javascript strings are immutable they must be wrapped with Buffer() - this.spanStack = []; - this.blockStack = []; - this.extensions = MKDEXT_NO_INTRA_EMPHASIS | MKDEXT_SUPERSCRIPT | MKDEXT_AUTOLINK | MKDEXT_STRIKETHROUGH | MKDEXT_TABLES | MKDEXT_TABLES; - var renderer = getRedditRenderer(); - this.context = renderer.context; - this.callbacks = renderer.callbacks; - this.inLinkBody = 0; - this.activeChars = {}; - this.refs = {}; - this.nestingLimit = 16; - this.maxTableCols = 64; - }; - - - /* is_empty - returns the line length when it is empty, 0 otherwise */ - function is_empty(data) { - var i; - for (i = 0; i < data.length && data[i] != '\n'; i++) - if (data[i] != ' ') return 0; - - return i + 1; - } - - - /* is_hrule - returns whether a line is a horizontal rule */ - function is_hrule(data) { - var i = 0, n = 0; - var c; - - /* skipping initial spaces */ - if (data.length < 3) return 0; - if (data[0] == ' ') { i++; - if (data[1] == ' ') { i++; - if (data[2] == ' ') { i++; } } } - - /* looking at the hrule uint8_t */ - if (i + 2 >= data.length - || (data[i] != '*' && data[i] != '-' && data[i] != '_')) - return 0; - c = data[i]; - - /* the whole line must be the char or whitespace */ - while (i < data.length && data[i] != '\n') { - if (data[i] == c) n++; - else if (data[i] != ' ') - return 0; - - i++; - } - - return n >= 3; - } - - - /* check if a line begins with a code fence; return the - * width if it is */ - function prefix_codefence(data) { - var i = 0, n = 0; - var c; - - /* skipping initial spaces */ - if (data.length < 3) return 0; - if (data[0] == ' ') { i++; - if (data[1] == ' ') { i++; - if (data[2] == ' ') { i++; } } } - - /* looking at the hrule uint8_t */ - if (i + 2 >= data.length || !(data[i] == '~' || data[i] == '`')) - return 0; - - c = data[i]; - - /* the whole line must be the uint8_t or whitespace */ - while (i < data.length && data[i] == c) { - n++; i++; - } - - if (n < 3) return 0; - - return i; - } - - /* check if a line is a code fence; return its size if it */ - function is_codefence(data, syntax) { - var i = 0, syn_len = 0; - i = prefix_codefence(data); - if (i == 0) return 0; - - - while (i < data.length && data[i] == ' ') i++; - - var syn_start; - //syn_start = data + i; - syn_start = i; - - if (i < data.length && data[i] == '{') { - i++; syn_start++; - - while (i < data.length && data[i] != '}' && data[i] != '\n') { - syn_len++; i++; - } - - if (i == data.length || data[i] != '}') - return 0; - - /* strip all whitespace at the beginning and the end - * of the {} block */ - /*remember not to remove the +0, it helps me keep syncronised with snudown*/ - while (syn_len > 0 && _isspace(data[syn_start+0])) { - syn_start++; syn_len--; - } - - // while (syn_len > 0 && _isspace(syn_start[syn_len - 1])) - while (syn_len > 0 && _isspace(data[syn_start+syn_len - 1])) - syn_len--; - - i++; - } else { - while (i < data.length && !_isspace(data[i])) { - syn_len++; i++; - } - } - - if (syntax) syntax.s = data.substr(syn_start, syn_len); - // syntax->size = syn; - - while (i < data.length && data[i] != '\n') { - if (!_isspace(data[i])) return 0; - - i++; - } - - return i + 1; - } - - /* find_emph_char - looks for the next emph uint8_t, skipping other constructs */ - function find_emph_char(data, c) { - var i = 1; - while (i < data.length) { - while (i < data.length && data[i] != c && data[i] != '`' && data[i] != '[') - i++; - - if (i == data.length) return 0; - - if (data[i] == c) - return i; - - /* not counting escaped chars */ - if (i && data[i - 1] == '\\') { - i++; continue; - } - - if (data[i] == '`') { - var span_nb = 0, bt; - var tmp_i = 0; - - /* counting the number of opening backticks */ - while (i < data.length && data[i] == '`') { - i++; span_nb++; - } - - if (i >= data.length) return 0; - - /* finding the matching closing sequence */ - bt = 0; - while (i < data.length && bt < span_nb) { - if (!tmp_i && data[i] == c) tmp_i = i; - if (data[i] == '`') bt++; - else bt = 0; - i++; - } - - if (i >= data.length) return tmp_i; - } - /* skipping a link */ - else if (data[i] == '[') { - var tmp_i = 0; - var cc; - - i++; - while (i < data.length && data[i] != ']') { - if (!tmp_i && data[i] == c) tmp_i = i; - i++; - } - - i++; - while (i < data.length && (data[i] == ' ' || data[i] == '\n')) - i++; - - if (i >= data.length) return tmp_i; - - switch (data[i]) { - case '[': - cc = ']'; break; - - case '(': - cc = ')'; break; - - default: - if (tmp_i) - return tmp_i; - else - continue; - } - - i++; - while (i < data.length && data[i] != cc) { - if (!tmp_i && data[i] == c) tmp_i = i; - i++; - } - - if (i >= data.length) return tmp_i; - i++; - } - } - - return 0; - } - - /* parse_emph1 - parsing single emphase */ - /* closed by a symbol not preceded by whitespace and not followed by symbol */ - function parse_emph1(out, md, data_, c) { - var data = data_.slice(1); - var i = 0, len; - var r; - - if (!md.callbacks.emphasis) return 0; - - /* skipping one symbol if coming from emph3 */ - if (data.length > 1 && data[0] == c && data[1] == c) i = 1; - - while (i < data.length) { - len = find_emph_char(data.slice(i), c); - if (!len) return 0; - i += len; - if (i >= data.length) return 0; - - if (data[i] == c && !_isspace(data[i - 1])) { - if ((md.extensions & MKDEXT_NO_INTRA_EMPHASIS) && (c == '_')) { - if (!(i + 1 == data.length || _isspace(data[i + 1]) || ispunct(data[i + 1]))) - continue; - } - - var work = new Buffer(); - md.spanStack.push(work); - parse_inline(work, md, data.slice(0, i)); - r = md.callbacks.emphasis(out, work, md.context); - md.spanStack.pop(); - return r ? i + 1 : 0; - } - } - - return 0; - } - - /* parse_emph2 - parsing single emphase */ - function parse_emph2(out, md, data_, c) { - var data = data_.slice(2); - var i = 0, len; - var r; - - var render_method = (c == '~') ? md.callbacks.strikethrough : md.callbacks.double_emphasis; - - if (!render_method) return 0; - - while (i < data.length) { - len = find_emph_char(data.slice(i), c); - if (!len) return 0; - i += len; - - if (i + 1 < data.length && data[i] == c && data[i + 1] == c && i && !_isspace(data[i - 1])) { - var work = new Buffer(); - md.spanStack.push(work); - parse_inline(work, md, data.slice(0, i)); - r = render_method(out, work, md.context); - md.spanStack.pop(); - return r ? i + 2 : 0; - } - i++; - } - return 0; - } - - /* parse_emph3 • parsing single emphase */ - /* finds the first closing tag, and delegates to the other emph */ - function parse_emph3(out, md, data_, c) { - var data = data_.slice(3); - var i = 0, len; - var r; - - while (i < data.length) { - len = find_emph_char(data.slice(i), c); - if (!len) return 0; - i += len; - - /* skip whitespace preceded symbols */ - if (data[i] != c || _isspace(data[i - 1])) continue; - - if (i + 2 < data.length && data[i + 1] == c && data[i + 2] == c && md.callbacks.triple_emphasis) { - /* triple symbol found */ - var work = new Buffer(); - md.spanStack.push(work); - parse_inline(work, md, data.slice(0, i)); - r = md.callbacks.triple_emphasis(out, work, md.context); - md.spanStack.pop(); - return r ? i + 3 : 0; - - } else if (i + 1 < data.length && data[i + 1] == c) { - /* double symbol found, handing over to emph1 */ - len = parse_emph1(out, md, data_, c); - if (!len) return 0; - else return len - 2; - - } else { - /* single symbol found, handing over to emph2 */ - len = parse_emph2(out, md, data_, c); - if (!len) return 0; - else return len - 1; - } - } - return 0; - } - - function is_atxheader(md, data) { - if (data[0] != '#') return false; - - if (md.extensions & MKDEXT_SPACE_HEADERS) { - var level = 0; - - while (level < data.length && level < 6 && data[level] == '#') - level++; - - if (level < data.length && data[level] != ' ') - return false; - } - - return true; - } - - - /* is_headerline . returns whether the line is a setext-style hdr underline */ - function is_headerline(data) { - var i = 0; - var size = data.length; - - /* test of level 1 header */ - if (data[i] == '=') { - for (i = 1; i < size && data[i] == '='; i++) {} - while (i < size && data[i] == ' ') i++; - return (i >= size || data[i] == '\n') ? 1 : 0; } - - /* test of level 2 header */ - if (data[i] == '-') { - for (i = 1; i < size && data[i] == '-'; i++) {} - while (i < size && data[i] == ' ') i++; - return (i >= size || data[i] == '\n') ? 2 : 0; } - - return 0; - } - - function is_next_headerline(data) { - var size = data.length; - var i = 0; - - while (i < size && data[i] != '\n') i++; - - if (++i >= size) return 0; - - return is_headerline(data.slice(i)); - } - - /* prefix_quote - returns blockquote prefix length */ - function prefix_quote(data) { - var i = 0; - var size = data.length; - if (i < size && data[i] == ' ') i++; - if (i < size && data[i] == ' ') i++; - if (i < size && data[i] == ' ') i++; - - if (i < size && data[i] == '>') { - if (i + 1 < size && data[i + 1] == ' ') - return i + 2; - - return i + 1; - } - - return 0; - } - - /* prefix_code • returns prefix length for block code*/ - function prefix_code(data) { - if (data.length > 3 && data[0] == ' ' && data[1] == ' ' - && data[2] == ' ' && data[3] == ' ') return 4; - - return 0; - } - - /* prefix_oli - returns ordered list item prefix */ - function prefix_oli(data) { - var size = data.length; - var i = 0; - - if (i < size && data[i] == ' ') i++; - if (i < size && data[i] == ' ') i++; - if (i < size && data[i] == ' ') i++; - - if (i >= size || data[i] < '0' || data[i] > '9') return 0; - - while (i < size && data[i] >= '0' && data[i] <= '9') i++; - - if (i + 1 >= size || data[i] != '.' || data[i + 1] != ' ') return 0; - - if (is_next_headerline(data.slice(i))) return 0; - - return i + 2; - } - - /* prefix_uli - returns ordered list item prefix */ - function prefix_uli(data) { - var size = data.length; - var i = 0; - - if (i < size && data[i] == ' ') i++; - if (i < size && data[i] == ' ') i++; - if (i < size && data[i] == ' ') i++; - - if (i + 1 >= size || - (data[i] != '*' && data[i] != '+' && data[i] != '-') || - data[i + 1] != ' ') - return 0; - - if (is_next_headerline(data.slice(i))) return 0; - - return i + 2; - } - - /* is_mail_autolink - looks for the address part of a mail autolink and '>' */ - /* this is less strict than the original markdown e-mail address matching */ - function is_mail_autolink(data) { - var i = 0, nb = 0; - - /* address is assumed to be: [-@._a-zA-Z0-9]+ with exactly one '@' */ - for (i = 0; i < data.length; ++i) { - if (isalnum(data[i])) - continue; - - switch (data[i]) { - case '@': - nb++; - - case '-': - case '.': - case '_': - break; - - case '>': - return (nb == 1) ? i + 1 : 0; - - default: - return 0; - } - } - - return 0; - } - - /* tag_length - returns the length of the given tag, or 0 is it's not valid */ - function tag_length(data, autolink) { - var i, j; - - /* a valid tag can't be shorter than 3 chars */ - if (data.length < 3) return 0; - - /* begins with a '<' optionally followed by '/', followed by letter or number */ - if (data[0] != '<') return 0; - i = (data[1] == '/') ? 2 : 1; - - if (!isalnum(data[i])) return 0; - - /* scheme test */ - autolink.p = MKDA_NOT_AUTOLINK; - - /* try to find the beginning of an URI */ - while (i < data.length && (isalnum(data[i]) || data[i] == '.' || data[i] == '+' || data[i] == '-')) i++; - - if (i > 1 && data[i] == '@') { - if ((j = is_mail_autolink(data.slice(i))) != 0) { - autolink.p = MKDA_EMAIL; - return i + j; - } - } - - if (i > 2 && data[i] == ':') { - autolink.p = MKDA_NORMAL; - i++; - } - - /* completing autolink test: no whitespace or ' or " */ - if (i >= data.length) autolink.p = MKDA_NOT_AUTOLINK; - else if (autolink.p) { - j = i; - - while (i < data.length) { - if (data[i] == '\\') i += 2; - else if (data[i] == '>' || data[i] == '\'' || - data[i] == '"' || data[i] == ' ' || data[i] == '\n') - break; - else i++; - } - - if (i >= data.length) return 0; - if (i > j && data[i] == '>') return i + 1; - /* one of the forbidden chars has been found */ - autolink.p = MKDA_NOT_AUTOLINK; - } - - /* looking for sometinhg looking like a tag end */ - while (i < data.length && data[i] != '>') i++; - if (i >= data.length) return 0; - return i + 1; - } - - // parse_inline - parses inline markdown elements - //Buffer, md, String - function parse_inline(out, md, data) { - var i = 0, end = 0; - var action = 0; - var work = new Buffer(); - - if (md.spanStack.length + md.blockStack.length > md.nestingLimit) - return; - - while (i < data.length) { - /* copying inactive chars into the output */ - while (end < data.length && !(action = md.activeChars[data[end]])) { - end++; - } - - if (md.callbacks.normal_text) { - work.s = data.slice(i, end); - md.callbacks.normal_text(out, work, md.context); - } - else - out.s += data.slice(i, end); - - if (end >= data.length) break; - i = end; - - end = markdown_char_ptrs[action](out, md, data, i); - if (!end) /* no action from the callback */ - end = i + 1; - else { - i += end; - end = i; - } - } - } - - /* parse_atxheader - parsing of atx-style headers */ - function parse_atxheader(out, md, data) { - var level = 0; - var i, end, skip; - - while (level < data.length && level < 6 && data[level] == '#') level++; - - for (i = level; i < data.length && data[i] == ' '; i++) {} - - for (end = i; end < data.length && data[end] != '\n'; end++) {} - skip = end; - - while (end && data[end - 1] == '#') end--; - - while (end && data[end - 1] == ' ') end--; - - if (end > i) { - var work = new Buffer(); - md.spanStack.push(work); - - parse_inline(work, md, data.slice(i, end)); - - if (md.callbacks.header) - md.callbacks.header(out, work, level, md.context); - - md.spanStack.pop(); - } - - return skip; - } - - /* htmlblock_end - checking end of HTML block : [ \t]*\n[ \t*]\n */ - /* returns the length on match, 0 otherwise */ - // htmlblock_end(const char *tag, size_t tag_len, struct sd_markdown *rndr, uint8_t *data, size_t size) - function htmlblock_end(tag, md, data) { - var i, w; - - /* checking if tag is a match */ - //tag should already be lowercase - if (tag.length + 3 >= data.length || - data.slice(2).toLowerCase() != tag || - data[tag.length + 2] != '>') - return 0; - - /* checking white lines */ - i = tag.length + 3; - w = 0; - if (i < data.length && (w = is_empty(data.slice(i))) == 0) - return 0; /* non-blank after tag */ - i += w; - w = 0; - - if (i < data.length) w = is_empty(data.slice(i)); - - return i + w; - } - - /* parse_htmlblock - parsing of inline HTML block */ - //TODO - function parse_htmlblock(out, md, data, do_render) { - var i, j = 0; - var curtag = null; - var found; - var work = new Buffer(data); - - /* identification of the opening tag */ - if (data.length < 2 || data[0] != '<') return 0; - - i = 1; - while (i < data.length && data[i] != '>' && data[i] != ' ') i++; - - if (i < data.length) curtag = find_block_tag(data.slice(1)); - - /* handling of special cases */ - if (!curtag) { - - /* HTML comment, laxist form */ - if (data.length > 5 && data[1] == '!' && data[2] == '-' && data[3] == '-') { - i = 5; - - while (i < data.length && !(data[i - 2] == '-' && data[i - 1] == '-' && data[i] == '>')) i++; - - i++; - - if (i < size) - j = is_empty(data.slice(i)); - - if (j) { - //TODO: HANDLE WORK!!! - // work.size = i + j; - work.s = data.slice(0, i + j); - if (do_render && md.callbacks.blockhtml) - md.callbacks.blockhtml(out, work, md.context); - return work.s.length; - } - } - - /* HR, which is the only self-closing block tag considered */ - if (data.length > 4 && (data[1] == 'h' || data[1] == 'H') && (data[2] == 'r' || data[2] == 'R')) { - i = 3; - while (i < data.length && data[i] != '>') i++; - - if (i + 1 < data.length) { - i++; - j = is_empty(data.slice(i)); - if (j) { - work.s = data.slice(0, i + j); - if (do_render && md.callbacks.blockhtml) - md.callbacks.blockhtml(out, work, md.context); - return work.s.length; - } - } - } - - /* no special case recognised */ - return 0; - } - - /* looking for an unindented matching closing tag */ - /* followed by a blank line */ - i = 1; - found = 0; - - /* if not found, trying a second pass looking for indented match */ - /* but not if tag is "ins" or "del" (following original Markdown.pl) */ - if (curtag != 'ins' && curtag != 'del') { - var tag_size = curtag.length; - i = 1; - while (i < data.length) { - i++; - while (i < data.length && !(data[i - 1] == '<' && data[i] == '/')) - i++; - - if (i + 2 + tag_size >= data.length) - break; - - // j = htmlblock_end(tag, md, data + i - 1, size - i + 1); - //TODO - j = htmlblock_end(tag, md, data.slice(i - 1)); - - if (j) { - i += j - 1; - found = 1; - break; - } - } - } - - if (!found) return 0; - - /* the end of the block has been found */ - //TODO: - work.s = work.s.slice(0, i); - if (do_render && md.callbacks.blockhtml) - md.callbacks.blockhtml(out, work, md.context); - - return i; - } - - /* parse_blockquote - handles parsing of a blockquote fragment */ - function parse_blockquote(out, md, data) { - var size = data.length; - var beg, end = 0, pre, work_size = 0; - // uint8_t *work_data = 0; - var work_data = ""; - var work_data_cursor = 0; - - var out_ = new Buffer(); - md.blockStack.push(out_); - - beg = 0; - while (beg < size) { - for (end = beg + 1; end < size && data[end - 1] != '\n'; end++) {} - - pre = prefix_quote(data.slice(beg, end)); - - if (pre) beg += pre; /* skipping prefix */ - - /* empty line followed by non-quote line */ - else if (is_empty(data.slice(beg, end)) && - (end >= size || (prefix_quote(data.slice(end)) == 0 && - !is_empty(data.slice(end))))) - break; - - if (beg < end) { /* copy into the in-place working buffer */ - /* bufput(work, data + beg, end - beg); */ - //TODO:!!! FIX THIS!!! - // if (!work_data) work_data = data.slice(beg, end); - // work_data = data + beg; - work_data += data.slice(beg, end); - /* - if (!work_data) work_data_cursor = beg; - else if (beg != work_data_cursor + work_size) - work_data += data.slice(beg, end); - */ - // memmove(work_data + work_size, data + beg, end - beg); - work_size += end - beg; - } - beg = end; - } - - parse_block(out_, md, work_data); - if (md.callbacks.blockquote) - md.callbacks.blockquote(out, out_, md.context); - md.blockStack.pop(); - return end; - } - - /* parse_paragraph - handles parsing of a regular paragraph */ - function parse_paragraph(out, md, data) { - var i = 0, end = 0; - var level = 0; - var size = data.length; - var work = new Buffer(data); - - while (i < size) { - for (end = i + 1; end < size && data[end - 1] != '\n'; end++) {/* empty */} - - if (prefix_quote(data.slice(i, end)) != 0) { - end = i; - break; - } - - var tempdata = data.slice(i); - if (is_empty(tempdata) || (level = is_headerline(tempdata)) != 0) break; - if (is_empty(tempdata)) break; - if ((level = is_headerline(tempdata)) != 0) break; - - if (is_atxheader(md, tempdata) - || is_hrule(tempdata) - || prefix_quote(tempdata)) { - end = i; - break; - } - - /* - * Early termination of a paragraph with the same logic - * as markdown 1.0.0. If this logic is applied, the - * Markdown 1.0.3 test suite wont pass cleanly. - * - * :: If the first character in a new line is not a letter - * lets check to see if there's some kind of block starting here - */ - if ((md.extensions & MKDEXT_LAX_SPACING) && !isalnum(data[i])) { - if (prefix_oli(tempdata) - || prefix_uli(tempdata)) { - end = i; - break; - } - /* see if an html block starts here */ - if (data[i] == '<' && md.callbacks.blockhtml - && parse_htmlblock(out, md, tempdata, 0)) { - end = i; - break - } - - /* see if a code fence starts here */ - if ((md.extensions && MKDEXT_FENCED_CODE) != 0 - && is_codefence(tempdata, null) != 0) { - end = i; - break; - } - } - - i = end; - } - - var work_size = i; - while (work_size && data[work_size - 1] == '\n') work_size--; - work.s = work.s.slice(0, work_size); - - if (!level) { - var tmp = new Buffer(); - md.blockStack.push(tmp); - parse_inline(tmp, md, work.s); - if (md.callbacks.paragraph) - md.callbacks.paragraph(out, tmp, md.context); - md.blockStack.pop(); - } else { - var header_work = null; - - if (work.size) { - var beg; - i = work.s.length; - // var work_size = work.s.length - 1; - // work.size -= 1; - - while (work_size && data[work_size] != '\n') - work_size -= 1; - - beg = work_size + 1; - while (work_size && data[work_size - 1] == '\n') - work_size -= 1; - - work.s = work.s.slice(0, work_size); - if (work_size > 0) { - var tmp = new Buffer(); - md.blockStack.push(tmp); - parse_inline(tmp, md, work.s); - - if (md.callbacks.paragraph) - md.callbacks.paragraph(out, tmp, md.context); - - md.blockStack.pop(); - work.s = work.s.slice(beg, i); - } - else work.s = work.s.slice(0, i); - } - - header_work = new Buffer(); - md.spanStack.push(header_work); - parse_inline(header_work, md, work.s); - - if (md.callbacks.header) - md.callbacks.header(out, header_work, level, md.context); - - md.spanStack.pop(); - } - - return end; - } - - /* parse_fencedcode - handles parsing of a block-level code fragment */ - function parse_fencedcode(out, md, data) { - var beg, end; - var work = null; - var lang = new Buffer(); - - beg = is_codefence(data, lang); - if (beg == 0) return 0; - - work = new Buffer(); - md.blockStack.push(work); - - while (beg < data.length) { - var fence_end; - var fence_trail = new Buffer(); - - fence_end = is_codefence(data.slice(beg), fence_trail); - if (fence_end != 0 && fence_trail.s.length == 0) { - beg += fence_end; - break; - } - - for (end = beg + 1; end < data.length && data[end - 1] != '\n'; end++) {} - - if (beg < end) { - /* verbatim copy to the working buffer, - escaping entities */ - var tempData = data.slice(beg, end); - if (is_empty(tempData)) work.s += '\n'; - else work.s += tempData; - } - beg = end; - } - - if (work.s.length && work.s[work.s.length - 1] != '\n') - work.s += '\n'; - - if (md.callbacks.blockcode) - md.callbacks.blockcode(out, work, lang.s.length ? lang : null, md.context); - - md.blockStack.pop(); - return beg; - } - - function parse_blockcode(out, md, data) { - var size = data.length; - var beg, end, pre; - - var work = null; - md.blockStack.push(work = new Buffer()); - - beg = 0; - while (beg < size) { - for (end = beg + 1; end < size && data[end - 1] != '\n'; end++) {}; - pre = prefix_code(data.slice(beg, end)); - - if (pre) beg += pre; /* skipping prefix */ - else if (!is_empty(data.slice(beg, end))) - /* non-empty non-prefixed line breaks the pre */ - break; - - if (beg < end) { - /* verbatim copy to the working buffer, - escaping entities */ - if (is_empty(data.slice(beg, end))) work.s += '\n'; - else work.s += data.slice(beg, end); - } - beg = end; - } - - var work_size = work.s.length; - while (work_size && work.s[work_size - 1] == '\n') work_size -= 1; - work.s = work.s.slice(0, work_size); - - work.s += '\n'; - - if (md.callbacks.blockcode) - md.callbacks.blockcode(out, work, null, md.context); - - md.blockStack.pop(); - return beg; - } - - /* parse_listitem - parsing of a single list item */ - /* assuming initial prefix is already removed */ - //FLAGS is pointer - function parse_listitem(out, md, data, flags) { - var size = data.length; - var work = null, inter = null; - var beg = 0, end, pre, sublist = 0, orgpre = 0, i; - var in_empty = 0, has_inside_empty = 0, in_fence = 0; - - /* keeping track of the first indentation prefix */ - while (orgpre < 3 && orgpre < size && data[orgpre] == ' ') - orgpre++; - - //TODO - beg = prefix_uli(data); - if (!beg) beg = prefix_oli(data); - - if (!beg) return 0; - - /* skipping to the beginning of the following line */ - end = beg; - while (end < size && data[end - 1] != '\n') end++; - - /* getting working buffers */ - md.spanStack.push(work = new Buffer()); - md.spanStack.push(inter = new Buffer()); - - /* putting the first line into the working buffer */ - work.s += data.slice(beg, end); - beg = end; - - /* process the following lines */ - while (beg < size) { - var has_next_uli, has_next_oli; - end++; - - while (end < size && data[end - 1] != '\n') end++; - - /* process an empty line */ - if (is_empty(data.slice(beg, end))) { - in_empty = 1; - beg = end; - continue; - } - - /* calculating the indentation */ - i = 0; - while (i < 4 && beg + i < end && data[beg + i] == ' ') i++; - - pre = i; - - //TODO: Cache this slice? - if (md.flags & MKDEXT_FENCED_CODE) { - if (is_codefence(data.slice(beg+i, end), null) != 0) { - in_fence = !in_fence; - } - } - - /* only check for new list items if we are **not** in a fenced code block */ - if (!in_fence) { - has_next_uli = prefix_uli(data.slice(beg+i, end)); - has_next_oli = prefix_oli(data.slice(beg+i, end)); - } - - /* checking for ul/ol switch */ - if (in_empty && ( - ((flags.p & MKD_LIST_ORDERED) && has_next_uli) || - (!(flags.p & MKD_LIST_ORDERED) && has_next_oli))){ - flags.p |= MKD_LI_END; - break; /* the following item must have same list type */ - } - - /* checking for a new item */ - if ((has_next_uli && !is_hrule(data.slice(beg+i, end))) || has_next_oli) { - if (in_empty) has_inside_empty = 1; - - if (pre == orgpre) /* the following item must have */ - break; /* the same indentation */ - - if (!sublist) sublist = work.s.length; - } - /* joining only indented stuff after empty lines; - * note that now we only require 1 space of indentation - * to continue list */ - else if (in_empty && pre == 0) { - flags.p |= MKD_LI_END; - break; - } - else if (in_empty) { - work.s += '\n'; - has_inside_empty = 1; - } - - in_empty = 0; - - /* adding the line without prefix into the working buffer */ - work.s += data.slice(beg + i, end); - beg = end; - } - - /* render of li contents */ - if (has_inside_empty) flags.p |= MKD_LI_BLOCK; - - if (flags.p & MKD_LI_BLOCK) { - /* intermediate render of block li */ - if (sublist && sublist < work.s.length) { - parse_block(inter, md, work.s.slice(0, sublist)); - parse_block(inter, md, work.s.slice(sublist)); - } - else - parse_block(inter, md, work.s); - } else { - //TODO: - /* intermediate render of inline li */ - if (sublist && sublist < work.s.length) { - parse_inline(inter, md, work.s.slice(0, sublist)); - parse_block(inter, md, work.s.slice(sublist)); - } - else - parse_inline(inter, md, work.s); - } - - /* render of li itself */ - if (md.callbacks.listitem) - md.callbacks.listitem(out, inter, flags.p, md.context); - - md.spanStack.pop(); - md.spanStack.pop(); - return beg; - } - - - /* parse_list - parsing ordered or unordered list block */ - function parse_list(out, md, data, flags) { - var size = data.length; - var i = 0, j; - - var work = null; - md.blockStack.push(work = new Buffer()); - - while (i < size) { - var flag_p = {p: flags}; - j = parse_listitem(work, md, data.slice(i), flag_p); - flags = flag_p.p; - i += j; - - if (!j || (flags & MKD_LI_END)) break; - } - - if (md.callbacks.list) - md.callbacks.list(out, work, flags, md.context); - md.blockStack.pop(); - return i; - } - - function parse_table_row(out, md, data, columns, header_flag) { - var i = 0, col, cols_left; - var row_work = null; - - if (!md.callbacks.table_cell || !md.callbacks.table_row) return; - - md.spanStack.push(row_work = new Buffer()); - - if (i < data.length && data[i] == '|') i++; - - for (col = 0; col < columns.length && i < data.length; ++col) { - var cell_start, cell_end; - var cell_work; - - md.spanStack.push(cell_work = new Buffer()); - - while (i < data.length && _isspace(data[i])) i++; - - cell_start = i; - - while (i < data.length && data[i] != '|') i++; - - cell_end = i - 1; - - while (cell_end > cell_start && _isspace(data[cell_end])) cell_end--; - - // parse_inline(cell_work, rndr, data + cell_start, 1 + cell_end - cell_start); - parse_inline(cell_work, md, data.slice(cell_start, 1 + cell_end)); - md.callbacks.table_cell(row_work, cell_work, columns[col] | header_flag, md.context, 0); - - md.spanStack.pop(); - i++; - } - - cols_left = columns.length - col; - // for (; col < columns.length; ++col) { - if (cols_left > 0) { - var empty_cell = null; - md.callbacks.table_cell(row_work, empty_cell, columns[col] | header_flag, md.context, cols_left); - } - - md.callbacks.table_row(out, row_work, md.context); - - md.spanStack.pop(); - } - - function parse_table_header(out, md, data, columns) { - var i = 0, col, header_end, under_end; - - var pipes = 0; - while (i < data.length && data[i] != '\n') - if (data[i++] == '|') pipes++; - - if (i == data.length || pipes == 0) - return 0; - - header_end = i; - - while (header_end > 0 && _isspace(data[header_end - 1])) header_end--; - - if (data[0] == '|') pipes--; - - if (header_end && data[header_end - 1] == '|') pipes--; - - if (pipes + 1 > md.maxTableCols) return 0; - // columns.p = pipes + 1; - // column_data.p = new Array(columns.p); - columns.p = new Array(pipes + 1); - for (var k = 0; k < columns.p.length; k++) columns.p[k] = 0; - - /* Parse the header underline */ - i++; - if (i < data.length && data[i] == '|') i++; - - under_end = i; - while (under_end < data.length && data[under_end] != '\n') under_end++; - - for (col = 0; col < columns.p.length && i < under_end; ++col) { - var dashes = 0; - - while (i < under_end && data[i] == ' ') i++; - - if (data[i] == ':') { - i++; - columns.p[col] |= MKD_TABLE_ALIGN_L; - dashes++; - } - - while (i < under_end && data[i] == '-') { - i++; dashes++; - } - - if (i < under_end && data[i] == ':') { - i++; columns.p[col] |= MKD_TABLE_ALIGN_R; - dashes++; - } - - while (i < under_end && data[i] == ' ') i++; - - if (i < under_end && data[i] != '|') break; - - if (dashes < 1) break; - - i++; - } - - if (col < columns.p.length) return 0; - - parse_table_row(out, md, data.slice(0, header_end), columns.p, MKD_TABLE_HEADER); - - return under_end + 1; - } - - function parse_table(out, md, data) { - var i; - var header_work, body_work; - - var columns = {p: null}; - - md.spanStack.push(header_work = new Buffer()); - md.blockStack.push(body_work = new Buffer()); - - i = parse_table_header(header_work, md, data, columns); - if (i > 0) { - - while (i < data.length) { - var row_start; - var pipes = 0; - - row_start = i; - - while (i < data.length && data[i] != '\n') - if (data[i++] == '|') - pipes++; - - if (pipes == 0 || i == data.length) { - i = row_start; - break; - } - - parse_table_row(body_work, md, data.slice(row_start, i), columns.p, 0); - - i++; - } - - if (md.callbacks.table) - md.callbacks.table(out, header_work, body_work, md.context); - } - - md.spanStack.pop(); - md.blockStack.pop(); - return i; - } - - function parse_block(out, md, data) { - var beg = 0, end, i; - var textData; - - if (md.spanStack.length + - md.blockStack.length > md.nestingLimit) - return; - - while (beg < data.length) { - textData = data.slice(beg); - end = data.length - beg; - - if (is_atxheader(md, textData)) - beg += parse_atxheader(out, md, textData); - - else if (data[beg] == '<' && md.callbacks.blockhtml && - (i = parse_htmlblock(out, md, textData, 1)) != 0) - beg += i; - else if ((i = is_empty(textData)) != 0) - beg += i; - else if (is_hrule(textData)) { - if (md.callbacks.hrule) - md.callbacks.hrule(out, md.context); - - while (beg < data.length && data[beg] != '\n') beg++; - - beg++; - } - - else if ((md.extensions & MKDEXT_FENCED_CODE) != 0 && - (i = parse_fencedcode(out, md, textData)) != 0) - beg += i; - - else if ((md.extensions & MKDEXT_TABLES) != 0 && - (i = parse_table(out, md, textData)) != 0) - beg += i; - - else if (prefix_quote(textData)) - beg += parse_blockquote(out, md, textData); - - else if (prefix_code(textData)) - beg += parse_blockcode(out, md, textData); - - else if (prefix_uli(textData)) - beg += parse_list(out, md, textData, 0); - - else if (prefix_oli(textData)) - beg += parse_list(out, md, textData, MKD_LIST_ORDERED); - - else { - beg += parse_paragraph(out, md, textData); - } - } - } - - function is_ref(data, beg, end, md) { - /* int n; */ - var i = 0; - var idOffset, idEnd; - var linkOffset, linkEnd; - var titleOffset, titleEnd; - var lineEnd; - - /* up to 3 optional leading spaces */ - if (beg + 3 >= end) return 0; - if (data[beg] == ' ') { i = 1; - if (data[beg + 1] == ' ') { i = 2; - if (data[beg + 2] == ' ') { i = 3; - if (data[beg + 3] == ' ') return 0; } } } - i += beg; - - /* id part: anything but a newline between brackets */ - if (data[i] != '[') return 0; - i++; - idOffset = i; - while (i < end && data[i] != '\n' && data[i] != '\r' && data[i] != ']') i++; - if (i >= end || data[i] != ']') return 0; - idEnd = i; - - /* spacer: colon (space | tab)* newline? (space | tab)* */ - i++; - if (i >= end || data[i] != ':') return 0; - i++; - while (i < end && data[i] == ' ') i++; - if (i < end && (data[i] == '\n' || data[i] == '\r')) { - i++; - if (i < end && data[i] == '\r' && data[i - 1] == '\n') i++; } - while (i < end && data[i] == ' ') i++; - if (i >= end) return 0; - - /* link: whitespace-free sequence, optionally between angle brackets */ - if (data[i] == '<') i++; - - linkOffset = i; - while (i < end && data[i] != ' ' && data[i] != '\n' && data[i] != '\r') i++; - - if (data[i - 1] == '>') linkEnd = i - 1; else linkEnd = i; - - /* optional spacer: (space | tab)* (newline | '\'' | '"' | '(' ) */ - while (i < end && data[i] == ' ') i++; - if (i < end && data[i] != '\n' && data[i] != '\r' - && data[i] != '\'' && data[i] != '"' && data[i] != '(') - return 0; - lineEnd = 0; - /* computing end-of-line */ - if (i >= end || data[i] == '\r' || data[i] == '\n') lineEnd = i; - if (i + 1 < end && data[i] == '\n' && data[i + 1] == '\r') - lineEnd = i + 1; - - /* optional (space|tab)* spacer after a newline */ - if (lineEnd) { - i = lineEnd + 1; - while (i < end && data[i] == ' ') i++; - } - - /* optional title: any non-newline sequence enclosed in '"() - alone on its line */ - titleOffset = titleEnd = 0; - if (i + 1 < end && (data[i] == '\'' || data[i] == '"' || data[i] == '(')) { - i++; - titleOffset = i; - /* looking for EOL */ - while (i < end && data[i] != '\n' && data[i] != '\r') i++; - if (i + 1 < end && data[i] == '\n' && data[i + 1] == '\r') - titleEnd = i + 1; - else titleEnd = i; - /* stepping back */ - i -= 1; - while (i > titleOffset && data[i] == ' ') - i -= 1; - if (i > titleOffset && (data[i] == '\'' || data[i] == '"' || data[i] == ')')) { - lineEnd = titleEnd; - titleEnd = i; - } - } - - if (!lineEnd || linkEnd == linkOffset) - return 0; /* garbage after the link empty link */ - - var id = data.slice(idOffset, idEnd); - var link = data.slice(linkOffset, linkEnd); - var title = null; - if (titleEnd > titleOffset) title = data.slice(titleOffset, titleEnd); - md.refs[id] = { - id: id, - link: new Buffer(link), - title: new Buffer(title) - }; - return lineEnd; - } - - function expand_tabs(out, line) { - var i = 0, tab = 0; - - while (i < line.length) { - var org = i; - - while (i < line.length && line[i] != '\t') { - i++; tab++; - } - - if (i > org) out.s += line.slice(org, i); - - if (i >= line.length) break; - - do { - out.s += ' '; - tab++; - } while (tab % 4); - - i++; - } - } - - /** - Render markdown code to HTML. - - @param {string} source Markdown code. - @returns {string} HTML code. - */ - function render(source) { - var text = new Buffer(); - var beg = 0, end; - this.refs = {}; - - while (beg < source.length) { /* iterating over lines */ - if (end = is_ref(source, beg, source.length, this)) - beg = end; - else { /* skipping to the next line */ - end = beg; - while (end < source.length && source[end] != '\n' && source[end] != '\r') end++; - - /* adding the line body if present */ - if (end > beg) expand_tabs(text, source.slice(beg, end)); - - while (end < source.length && (source[end] == '\n' || source[end] == '\r')) { - /* add one \n per newline */ - if (source[end] == '\n' || (end + 1 < source.length && source[end + 1] != '\n')) - text.s += '\n'; - end++; - } - - beg = end; - } - } - - var out = new Buffer(); - - /* second pass: actual rendering */ - if (this.callbacks.doc_header) - this.callbacks.doc_header(out, this.context); - - if (text.s.length) { - /* adding a final newline if not already present */ - if (text.s[text.s.length - 1] != '\n' && text.s[text.s.length - 1] != '\r') - text.s += '\n'; - parse_block(out, this, text.s); - } - - if (this.callbacks.doc_footer) - this.callbacks.doc_footer(out, this.context); - - return out.s; - } - Markdown.prototype['render'] = render; - - /** - Create a parser object using the given configuration parameters. - - To get a Reddit equivelent configuration, pass no arguments. - - @param {?Renderer=} renderer A renderer object. - @param {?Number=} extensions A series of OR'd extension flags. (Extension flags start with MKDEXT_) - @param {?Number=} nestingLimit The maximum depth to which inline elements can be nested. - @return {Markdown} A configured markdown object. - */ - exports.getParser = function getParser(renderer, extensions, nestingLimit, columnLimit) { - var md = new Markdown(); - if (renderer) md.callbacks = renderer.callbacks; - if (nestingLimit) md.nestingLimit = nestingLimit; - if (nestingLimit) md.maxTableCols = columnLimit; - if (renderer) md.context = renderer.context; - if (extensions != undefined && extensions != null) md.extensions = extensions; - - // if (!(nestingLimit > 0 && columnLimit > 0 && callbacks)) throw new Error; - var cb = md.callbacks; - if (cb.emphasis || cb.double_emphasis || cb.triple_emphasis) { - md.activeChars['*'] = MD_CHAR_EMPHASIS; - md.activeChars['_'] = MD_CHAR_EMPHASIS; - if (md.extensions & MKDEXT_STRIKETHROUGH) md.activeChars['~'] = MD_CHAR_EMPHASIS; - } - - if (cb.codespan) md.activeChars['`'] = MD_CHAR_CODESPAN; - if (cb.linebreak) md.activeChars['\n'] = MD_CHAR_LINEBREAK; - if (cb.image || cb.link) md.activeChars['['] = MD_CHAR_LINK; - - md.activeChars['<'] = MD_CHAR_LANGLE; - md.activeChars['\\'] = MD_CHAR_ESCAPE; - md.activeChars['&'] = MD_CHAR_ENTITITY; - - if (md.extensions & MKDEXT_AUTOLINK) { - if (!(md.extensions & MKDEXT_NO_EMAIL_AUTOLINK)) { - md.activeChars['@'] = MD_CHAR_AUTOLINK_EMAIL; - } - md.activeChars[':'] = MD_CHAR_AUTOLINK_URL; - md.activeChars['w'] = MD_CHAR_AUTOLINK_WWW; - md.activeChars['/'] = MD_CHAR_AUTOLINK_SUBREDDIT_OR_USERNAME; - } - if (md.extensions & MKDEXT_SUPERSCRIPT) md.activeChars['^'] = MD_CHAR_SUPERSCRIPT; - - return md; - } - - var DEFAULT_BODY_FLAGS = HTML_SKIP_HTML | HTML_SKIP_IMAGES | HTML_SAFELINK | HTML_ESCAPE | HTML_USE_XHTML; - var DEFAULT_WIKI_FLAGS = HTML_SKIP_HTML | HTML_SAFELINK | HTML_ALLOW_ELEMENT_WHITELIST | HTML_ESCAPE | HTML_USE_XHTML; - var DEFAULT_HTML_ATTR_WHITELIST = ['colspan', 'rowspan', 'cellspacing', 'cellpadding', 'scope']; - var DEFAULT_HTML_ELEMENT_WHITELIST = ['tr', 'th', 'td', 'table', 'tbody', 'thead', 'tfoot', 'caption']; - exports.DEFAULT_HTML_ELEMENT_WHITELIST = DEFAULT_HTML_ELEMENT_WHITELIST; - exports.DEFAULT_HTML_ATTR_WHITELIST = DEFAULT_HTML_ATTR_WHITELIST; - exports.DEFAULT_BODY_FLAGS = DEFAULT_BODY_FLAGS; - exports.DEFAULT_WIKI_FLAGS = DEFAULT_WIKI_FLAGS; - - exports.HTML_SKIP_HTML = HTML_SKIP_HTML; - exports.HTML_SKIP_STYLE = HTML_SKIP_STYLE; - exports.HTML_SKIP_IMAGES = HTML_SKIP_IMAGES; - exports.HTML_SKIP_LINKS = HTML_SKIP_LINKS; - exports.HTML_EXPAND_TABS = HTML_EXPAND_TABS; - exports.HTML_SAFELINK = HTML_SAFELINK; - exports.HTML_TOC = HTML_TOC; - exports.HTML_HARD_WRAP = HTML_HARD_WRAP; - exports.HTML_USE_XHTML = HTML_USE_XHTML; - exports.HTML_ESCAPE = HTML_ESCAPE; - exports.HTML_ALLOW_ELEMENT_WHITELIST = HTML_ALLOW_ELEMENT_WHITELIST; - - exports.MKDEXT_NO_INTRA_EMPHASIS = MKDEXT_NO_INTRA_EMPHASIS; - exports.MKDEXT_TABLES = MKDEXT_TABLES; - exports.MKDEXT_FENCED_CODE = MKDEXT_FENCED_CODE; - exports.MKDEXT_AUTOLINK = MKDEXT_AUTOLINK; - exports.MKDEXT_STRIKETHROUGH = MKDEXT_STRIKETHROUGH; - exports.MKDEXT_SPACE_HEADERS = MKDEXT_SPACE_HEADERS; - exports.MKDEXT_SUPERSCRIPT = MKDEXT_SUPERSCRIPT; - exports.MKDEXT_LAX_SPACING = MKDEXT_LAX_SPACING; - exports.MKDEXT_NO_EMAIL_AUTOLINK = MKDEXT_NO_EMAIL_AUTOLINK; - - exports['SD_AUTOLINK_SHORT_DOMAINS'] = SD_AUTOLINK_SHORT_DOMAINS; - - exports.MKDA_NOT_AUTOLINK = MKDA_NOT_AUTOLINK; - exports.MKDA_NORMAL = MKDA_NORMAL; - exports.MKDA_EMAIL = MKDA_EMAIL; - - if (typeof define === 'function') { - define('snuownd', [], exports); - } -})(typeof(exports)!=='undefined'?exports:typeof(window)!=='undefined'?window.SnuOwnd={}:{}); - diff --git a/templates/header.html b/templates/header.html index ccfff2c..33e0144 100644 --- a/templates/header.html +++ b/templates/header.html @@ -3,9 +3,8 @@ Removeddit - - - + +