1、新建wxParse文件夹

里面的结构是这样:wxParse :{

emojis (文件夹)

html2json.js (文件)

htmlparser.js(文件)

showdown.js (文件)

wxDiscode.js(文件)

wxParse.js (文件)

wxParse.wxml(文件)

wxParse.wxss(文件)

}

2、html2json.js

/*** html2Json 改造来自: https://github.com/Jxck/html2json* * * author: Di (微信小程序开发工程师)* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)*               垂直微信小程序开发交流社区* * github地址: https://github.com/icindy/wxParse* * for: 微信小程序富文本解析* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184*/var __placeImgeUrlHttps = "https";
var __emojisReg = '';
var __emojisBaseSrc = '';
var __emojis = {};
var wxDiscode = require('./wxDiscode.js');
var HTMLParser = require('./htmlparser.js');
// Empty Elements - HTML 5
var empty = makeMap("area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr");
// Block Elements - HTML 5
var block = makeMap("br,a,code,address,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video");// Inline Elements - HTML 5
var inline = makeMap("abbr,acronym,applet,b,basefont,bdo,big,button,cite,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var");// Elements that you can, intentionally, leave open
// (and which close themselves)
var closeSelf = makeMap("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr");// Attributes that have their values filled in disabled="disabled"
var fillAttrs = makeMap("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected");// Special Elements (can contain anything)
var special = makeMap("wxxxcode-style,script,style,view,scroll-view,block");
function makeMap(str) {var obj = {}, items = str.split(",");for (var i = 0; i < items.length; i++)obj[items[i]] = true;return obj;
}function q(v) {return '"' + v + '"';
}function removeDOCTYPE(html) {return html.replace(/<\?xml.*\?>\n/, '').replace(/<.*!doctype.*\>\n/, '').replace(/<.*!DOCTYPE.*\>\n/, '');
}function trimHtml(html) {return html.replace(/\r?\n+/g, '').replace(/<!--.*?-->/ig, '').replace(/\/\*.*?\*\//ig, '').replace(/[ ]+</ig, '<')
}function html2json(html, bindName) {//处理字符串html = removeDOCTYPE(html);html = trimHtml(html);html = wxDiscode.strDiscode(html);//生成node节点var bufArray = [];var results = {node: bindName,nodes: [],images:[],imageUrls:[]};var index = 0;HTMLParser(html, {start: function (tag, attrs, unary) {//debug(tag, attrs, unary);// node for this elementvar node = {node: 'element',tag: tag,};if (bufArray.length === 0) {node.index = index.toString()index += 1} else {var parent = bufArray[0];if (parent.nodes === undefined) {parent.nodes = [];}node.index = parent.index + '.' + parent.nodes.length}if (block[tag]) {node.tagType = "block";} else if (inline[tag]) {node.tagType = "inline";} else if (closeSelf[tag]) {node.tagType = "closeSelf";}if (attrs.length !== 0) {node.attr = attrs.reduce(function (pre, attr) {var name = attr.name;var value = attr.value;if (name == 'class') {console.dir(value);//  value = value.join("")node.classStr = value;}// has multi attibutes// make it array of attributeif (name == 'style') {console.dir(value);//  value = value.join("")node.styleStr = value;}if (value.match(/ /)) {value = value.split(' ');}// if attr already exists// merge itif (pre[name]) {if (Array.isArray(pre[name])) {// already array, push to lastpre[name].push(value);} else {// single value, make it arraypre[name] = [pre[name], value];}} else {// not exist, put itpre[name] = value;}return pre;}, {});}//对img添加额外数据if (node.tag === 'img') {node.imgIndex = results.images.length;var imgUrl = node.attr.src;if (imgUrl[0] == '') {imgUrl.splice(0, 1);}imgUrl = wxDiscode.urlToHttpUrl(imgUrl, __placeImgeUrlHttps);node.attr.src = imgUrl;node.from = bindName;results.images.push(node);results.imageUrls.push(imgUrl);}// 处理font标签样式属性if (node.tag === 'font') {var fontSize = ['x-small', 'small', 'medium', 'large', 'x-large', 'xx-large', '-webkit-xxx-large'];var styleAttrs = {'color': 'color','face': 'font-family','size': 'font-size'};if (!node.attr.style) node.attr.style = [];if (!node.styleStr) node.styleStr = '';for (var key in styleAttrs) {if (node.attr[key]) {var value = key === 'size' ? fontSize[node.attr[key]-1] : node.attr[key];node.attr.style.push(styleAttrs[key]);node.attr.style.push(value);node.styleStr += styleAttrs[key] + ': ' + value + ';';}}}//临时记录source资源if(node.tag === 'source'){results.source = node.attr.src;}if (unary) {// if this tag doesn't have end tag// like <img src="hoge.png"/>// add to parentsvar parent = bufArray[0] || results;if (parent.nodes === undefined) {parent.nodes = [];}parent.nodes.push(node);} else {bufArray.unshift(node);}},end: function (tag) {//debug(tag);// merge into parent tagvar node = bufArray.shift();if (node.tag !== tag) console.error('invalid state: mismatch end tag');//当有缓存source资源时于于video补上src资源if(node.tag === 'video' && results.source){node.attr.src = results.source;delete results.source;}if (bufArray.length === 0) {results.nodes.push(node);} else {var parent = bufArray[0];if (parent.nodes === undefined) {parent.nodes = [];}parent.nodes.push(node);}},chars: function (text) {//debug(text);var node = {node: 'text',text: text,textArray:transEmojiStr(text)};if (bufArray.length === 0) {node.index = index.toString()index += 1results.nodes.push(node);} else {var parent = bufArray[0];if (parent.nodes === undefined) {parent.nodes = [];}node.index = parent.index + '.' + parent.nodes.lengthparent.nodes.push(node);}},comment: function (text) {//debug(text);// var node = {//     node: 'comment',//     text: text,// };// var parent = bufArray[0];// if (parent.nodes === undefined) {//     parent.nodes = [];// }// parent.nodes.push(node);},});return results;
};function transEmojiStr(str){// var eReg = new RegExp("["+__reg+' '+"]");
//   str = str.replace(/\[([^\[\]]+)\]/g,':$1:')var emojiObjs = [];//如果正则表达式为空if(__emojisReg.length == 0 || !__emojis){var emojiObj = {}emojiObj.node = "text";emojiObj.text = str;array = [emojiObj];return array;}//这个地方需要调整str = str.replace(/\[([^\[\]]+)\]/g,':$1:')var eReg = new RegExp("[:]");var array = str.split(eReg);for(var i = 0; i < array.length; i++){var ele = array[i];var emojiObj = {};if(__emojis[ele]){emojiObj.node = "element";emojiObj.tag = "emoji";emojiObj.text = __emojis[ele];emojiObj.baseSrc= __emojisBaseSrc;}else{emojiObj.node = "text";emojiObj.text = ele;}emojiObjs.push(emojiObj);}return emojiObjs;
}function emojisInit(reg='',baseSrc="/wxParse/emojis/",emojis){__emojisReg = reg;__emojisBaseSrc=baseSrc;__emojis=emojis;
}module.exports = {html2json: html2json,emojisInit:emojisInit
};

3、htmlparser.js

/*** * htmlParser改造自: https://github.com/blowsie/Pure-JavaScript-HTML5-Parser* * author: Di (微信小程序开发工程师)* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)*               垂直微信小程序开发交流社区* * github地址: https://github.com/icindy/wxParse* * for: 微信小程序富文本解析* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184*/
// Regular Expressions for parsing tags and attributes
var startTag = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/,endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/,attr = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g;// Empty Elements - HTML 5
var empty = makeMap("area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr");// Block Elements - HTML 5
var block = makeMap("a,address,code,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video");// Inline Elements - HTML 5
var inline = makeMap("abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var");// Elements that you can, intentionally, leave open
// (and which close themselves)
var closeSelf = makeMap("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr");// Attributes that have their values filled in disabled="disabled"
var fillAttrs = makeMap("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected");// Special Elements (can contain anything)
var special = makeMap("wxxxcode-style,script,style,view,scroll-view,block");function HTMLParser(html, handler) {var index, chars, match, stack = [], last = html;stack.last = function () {return this[this.length - 1];};while (html) {chars = true;// Make sure we're not in a script or style elementif (!stack.last() || !special[stack.last()]) {// Commentif (html.indexOf("<!--") == 0) {index = html.indexOf("-->");if (index >= 0) {if (handler.comment)handler.comment(html.substring(4, index));html = html.substring(index + 3);chars = false;}// end tag} else if (html.indexOf("</") == 0) {match = html.match(endTag);if (match) {html = html.substring(match[0].length);match[0].replace(endTag, parseEndTag);chars = false;}// start tag} else if (html.indexOf("<") == 0) {match = html.match(startTag);if (match) {html = html.substring(match[0].length);match[0].replace(startTag, parseStartTag);chars = false;}}if (chars) {index = html.indexOf("<");var text = ''while (index === 0) {text += "<";html = html.substring(1);index = html.indexOf("<");}text += index < 0 ? html : html.substring(0, index);html = index < 0 ? "" : html.substring(index);if (handler.chars)handler.chars(text);}} else {html = html.replace(new RegExp("([\\s\\S]*?)<\/" + stack.last() + "[^>]*>"), function (all, text) {text = text.replace(/<!--([\s\S]*?)-->|<!\[CDATA\[([\s\S]*?)]]>/g, "$1$2");if (handler.chars)handler.chars(text);return "";});parseEndTag("", stack.last());}if (html == last)throw "Parse Error: " + html;last = html;}// Clean up any remaining tagsparseEndTag();function parseStartTag(tag, tagName, rest, unary) {tagName = tagName.toLowerCase();if (block[tagName]) {while (stack.last() && inline[stack.last()]) {parseEndTag("", stack.last());}}if (closeSelf[tagName] && stack.last() == tagName) {parseEndTag("", tagName);}unary = empty[tagName] || !!unary;if (!unary)stack.push(tagName);if (handler.start) {var attrs = [];rest.replace(attr, function (match, name) {var value = arguments[2] ? arguments[2] :arguments[3] ? arguments[3] :arguments[4] ? arguments[4] :fillAttrs[name] ? name : "";attrs.push({name: name,value: value,escaped: value.replace(/(^|[^\\])"/g, '$1\\\"') //"});});if (handler.start) {handler.start(tagName, attrs, unary);}}}function parseEndTag(tag, tagName) {// If no tag name is provided, clean shopif (!tagName)var pos = 0;// Find the closest opened tag of the same typeelse {tagName = tagName.toLowerCase();for (var pos = stack.length - 1; pos >= 0; pos--)if (stack[pos] == tagName)break;}if (pos >= 0) {// Close all the open elements, up the stackfor (var i = stack.length - 1; i >= pos; i--)if (handler.end)handler.end(stack[i]);// Remove the open elements from the stackstack.length = pos;}}
};function makeMap(str) {var obj = {}, items = str.split(",");for (var i = 0; i < items.length; i++)obj[items[i]] = true;return obj;
}module.exports = HTMLParser;

4、showdown.js

/*** * showdown: https://github.com/showdownjs/showdown* * author: Di (微信小程序开发工程师)* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)*               垂直微信小程序开发交流社区* * github地址: https://github.com/icindy/wxParse* * for: 微信小程序富文本解析* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184*/function getDefaultOpts(simple) {'use strict';var defaultOptions = {omitExtraWLInCodeBlocks: {defaultValue: false,describe: 'Omit the default extra whiteline added to code blocks',type: 'boolean'},noHeaderId: {defaultValue: false,describe: 'Turn on/off generated header id',type: 'boolean'},prefixHeaderId: {defaultValue: false,describe: 'Specify a prefix to generated header ids',type: 'string'},headerLevelStart: {defaultValue: false,describe: 'The header blocks level start',type: 'integer'},parseImgDimensions: {defaultValue: false,describe: 'Turn on/off image dimension parsing',type: 'boolean'},simplifiedAutoLink: {defaultValue: false,describe: 'Turn on/off GFM autolink style',type: 'boolean'},literalMidWordUnderscores: {defaultValue: false,describe: 'Parse midword underscores as literal underscores',type: 'boolean'},strikethrough: {defaultValue: false,describe: 'Turn on/off strikethrough support',type: 'boolean'},tables: {defaultValue: false,describe: 'Turn on/off tables support',type: 'boolean'},tablesHeaderId: {defaultValue: false,describe: 'Add an id to table headers',type: 'boolean'},ghCodeBlocks: {defaultValue: true,describe: 'Turn on/off GFM fenced code blocks support',type: 'boolean'},tasklists: {defaultValue: false,describe: 'Turn on/off GFM tasklist support',type: 'boolean'},smoothLivePreview: {defaultValue: false,describe: 'Prevents weird effects in live previews due to incomplete input',type: 'boolean'},smartIndentationFix: {defaultValue: false,description: 'Tries to smartly fix identation in es6 strings',type: 'boolean'}};if (simple === false) {return JSON.parse(JSON.stringify(defaultOptions));}var ret = {};for (var opt in defaultOptions) {if (defaultOptions.hasOwnProperty(opt)) {ret[opt] = defaultOptions[opt].defaultValue;}}return ret;
}/*** Created by Tivie on 06-01-2015.*/// Private properties
var showdown = {},parsers = {},extensions = {},globalOptions = getDefaultOpts(true),flavor = {github: {omitExtraWLInCodeBlocks:   true,prefixHeaderId:            'user-content-',simplifiedAutoLink:        true,literalMidWordUnderscores: true,strikethrough:             true,tables:                    true,tablesHeaderId:            true,ghCodeBlocks:              true,tasklists:                 true},vanilla: getDefaultOpts(true)};/*** helper namespace* @type {{}}*/
showdown.helper = {};/*** TODO LEGACY SUPPORT CODE* @type {{}}*/
showdown.extensions = {};/*** Set a global option* @static* @param {string} key* @param {*} value* @returns {showdown}*/
showdown.setOption = function (key, value) {'use strict';globalOptions[key] = value;return this;
};/*** Get a global option* @static* @param {string} key* @returns {*}*/
showdown.getOption = function (key) {'use strict';return globalOptions[key];
};/*** Get the global options* @static* @returns {{}}*/
showdown.getOptions = function () {'use strict';return globalOptions;
};/*** Reset global options to the default values* @static*/
showdown.resetOptions = function () {'use strict';globalOptions = getDefaultOpts(true);
};/*** Set the flavor showdown should use as default* @param {string} name*/
showdown.setFlavor = function (name) {'use strict';if (flavor.hasOwnProperty(name)) {var preset = flavor[name];for (var option in preset) {if (preset.hasOwnProperty(option)) {globalOptions[option] = preset[option];}}}
};/*** Get the default options* @static* @param {boolean} [simple=true]* @returns {{}}*/
showdown.getDefaultOptions = function (simple) {'use strict';return getDefaultOpts(simple);
};/*** Get or set a subParser** subParser(name)       - Get a registered subParser* subParser(name, func) - Register a subParser* @static* @param {string} name* @param {function} [func]* @returns {*}*/
showdown.subParser = function (name, func) {'use strict';if (showdown.helper.isString(name)) {if (typeof func !== 'undefined') {parsers[name] = func;} else {if (parsers.hasOwnProperty(name)) {return parsers[name];} else {throw Error('SubParser named ' + name + ' not registered!');}}}
};/*** Gets or registers an extension* @static* @param {string} name* @param {object|function=} ext* @returns {*}*/
showdown.extension = function (name, ext) {'use strict';if (!showdown.helper.isString(name)) {throw Error('Extension \'name\' must be a string');}name = showdown.helper.stdExtName(name);// Getterif (showdown.helper.isUndefined(ext)) {if (!extensions.hasOwnProperty(name)) {throw Error('Extension named ' + name + ' is not registered!');}return extensions[name];// Setter} else {// Expand extension if it's wrapped in a functionif (typeof ext === 'function') {ext = ext();}// Ensure extension is an arrayif (!showdown.helper.isArray(ext)) {ext = [ext];}var validExtension = validate(ext, name);if (validExtension.valid) {extensions[name] = ext;} else {throw Error(validExtension.error);}}
};/*** Gets all extensions registered* @returns {{}}*/
showdown.getAllExtensions = function () {'use strict';return extensions;
};/*** Remove an extension* @param {string} name*/
showdown.removeExtension = function (name) {'use strict';delete extensions[name];
};/*** Removes all extensions*/
showdown.resetExtensions = function () {'use strict';extensions = {};
};/*** Validate extension* @param {array} extension* @param {string} name* @returns {{valid: boolean, error: string}}*/
function validate(extension, name) {'use strict';var errMsg = (name) ? 'Error in ' + name + ' extension->' : 'Error in unnamed extension',ret = {valid: true,error: ''};if (!showdown.helper.isArray(extension)) {extension = [extension];}for (var i = 0; i < extension.length; ++i) {var baseMsg = errMsg + ' sub-extension ' + i + ': ',ext = extension[i];if (typeof ext !== 'object') {ret.valid = false;ret.error = baseMsg + 'must be an object, but ' + typeof ext + ' given';return ret;}if (!showdown.helper.isString(ext.type)) {ret.valid = false;ret.error = baseMsg + 'property "type" must be a string, but ' + typeof ext.type + ' given';return ret;}var type = ext.type = ext.type.toLowerCase();// normalize extension typeif (type === 'language') {type = ext.type = 'lang';}if (type === 'html') {type = ext.type = 'output';}if (type !== 'lang' && type !== 'output' && type !== 'listener') {ret.valid = false;ret.error = baseMsg + 'type ' + type + ' is not recognized. Valid values: "lang/language", "output/html" or "listener"';return ret;}if (type === 'listener') {if (showdown.helper.isUndefined(ext.listeners)) {ret.valid = false;ret.error = baseMsg + '. Extensions of type "listener" must have a property called "listeners"';return ret;}} else {if (showdown.helper.isUndefined(ext.filter) && showdown.helper.isUndefined(ext.regex)) {ret.valid = false;ret.error = baseMsg + type + ' extensions must define either a "regex" property or a "filter" method';return ret;}}if (ext.listeners) {if (typeof ext.listeners !== 'object') {ret.valid = false;ret.error = baseMsg + '"listeners" property must be an object but ' + typeof ext.listeners + ' given';return ret;}for (var ln in ext.listeners) {if (ext.listeners.hasOwnProperty(ln)) {if (typeof ext.listeners[ln] !== 'function') {ret.valid = false;ret.error = baseMsg + '"listeners" property must be an hash of [event name]: [callback]. listeners.' + ln +' must be a function but ' + typeof ext.listeners[ln] + ' given';return ret;}}}}if (ext.filter) {if (typeof ext.filter !== 'function') {ret.valid = false;ret.error = baseMsg + '"filter" must be a function, but ' + typeof ext.filter + ' given';return ret;}} else if (ext.regex) {if (showdown.helper.isString(ext.regex)) {ext.regex = new RegExp(ext.regex, 'g');}if (!ext.regex instanceof RegExp) {ret.valid = false;ret.error = baseMsg + '"regex" property must either be a string or a RegExp object, but ' + typeof ext.regex + ' given';return ret;}if (showdown.helper.isUndefined(ext.replace)) {ret.valid = false;ret.error = baseMsg + '"regex" extensions must implement a replace string or function';return ret;}}}return ret;
}/*** Validate extension* @param {object} ext* @returns {boolean}*/
showdown.validateExtension = function (ext) {'use strict';var validateExtension = validate(ext, null);if (!validateExtension.valid) {console.warn(validateExtension.error);return false;}return true;
};/*** showdownjs helper functions*/if (!showdown.hasOwnProperty('helper')) {showdown.helper = {};
}/*** Check if var is string* @static* @param {string} a* @returns {boolean}*/
showdown.helper.isString = function isString(a) {'use strict';return (typeof a === 'string' || a instanceof String);
};/*** Check if var is a function* @static* @param {string} a* @returns {boolean}*/
showdown.helper.isFunction = function isFunction(a) {'use strict';var getType = {};return a && getType.toString.call(a) === '[object Function]';
};/*** ForEach helper function* @static* @param {*} obj* @param {function} callback*/
showdown.helper.forEach = function forEach(obj, callback) {'use strict';if (typeof obj.forEach === 'function') {obj.forEach(callback);} else {for (var i = 0; i < obj.length; i++) {callback(obj[i], i, obj);}}
};/*** isArray helper function* @static* @param {*} a* @returns {boolean}*/
showdown.helper.isArray = function isArray(a) {'use strict';return a.constructor === Array;
};/*** Check if value is undefined* @static* @param {*} value The value to check.* @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.*/
showdown.helper.isUndefined = function isUndefined(value) {'use strict';return typeof value === 'undefined';
};/*** Standardidize extension name* @static* @param {string} s extension name* @returns {string}*/
showdown.helper.stdExtName = function (s) {'use strict';return s.replace(/[_-]||\s/g, '').toLowerCase();
};function escapeCharactersCallback(wholeMatch, m1) {'use strict';var charCodeToEscape = m1.charCodeAt(0);return '~E' + charCodeToEscape + 'E';
}/*** Callback used to escape characters when passing through String.replace* @static* @param {string} wholeMatch* @param {string} m1* @returns {string}*/
showdown.helper.escapeCharactersCallback = escapeCharactersCallback;/*** Escape characters in a string* @static* @param {string} text* @param {string} charsToEscape* @param {boolean} afterBackslash* @returns {XML|string|void|*}*/
showdown.helper.escapeCharacters = function escapeCharacters(text, charsToEscape, afterBackslash) {'use strict';// First we have to escape the escape characters so that// we can build a character class out of themvar regexString = '([' + charsToEscape.replace(/([\[\]\\])/g, '\\$1') + '])';if (afterBackslash) {regexString = '\\\\' + regexString;}var regex = new RegExp(regexString, 'g');text = text.replace(regex, escapeCharactersCallback);return text;
};var rgxFindMatchPos = function (str, left, right, flags) {'use strict';var f = flags || '',g = f.indexOf('g') > -1,x = new RegExp(left + '|' + right, 'g' + f.replace(/g/g, '')),l = new RegExp(left, f.replace(/g/g, '')),pos = [],t, s, m, start, end;do {t = 0;while ((m = x.exec(str))) {if (l.test(m[0])) {if (!(t++)) {s = x.lastIndex;start = s - m[0].length;}} else if (t) {if (!--t) {end = m.index + m[0].length;var obj = {left: {start: start, end: s},match: {start: s, end: m.index},right: {start: m.index, end: end},wholeMatch: {start: start, end: end}};pos.push(obj);if (!g) {return pos;}}}}} while (t && (x.lastIndex = s));return pos;
};/*** matchRecursiveRegExp** (c) 2007 Steven Levithan <stevenlevithan.com>* MIT License** Accepts a string to search, a left and right format delimiter* as regex patterns, and optional regex flags. Returns an array* of matches, allowing nested instances of left/right delimiters.* Use the "g" flag to return all matches, otherwise only the* first is returned. Be careful to ensure that the left and* right format delimiters produce mutually exclusive matches.* Backreferences are not supported within the right delimiter* due to how it is internally combined with the left delimiter.* When matching strings whose format delimiters are unbalanced* to the left or right, the output is intentionally as a* conventional regex library with recursion support would* produce, e.g. "<<x>" and "<x>>" both produce ["x"] when using* "<" and ">" as the delimiters (both strings contain a single,* balanced instance of "<x>").** examples:* matchRecursiveRegExp("test", "\\(", "\\)")* returns: []* matchRecursiveRegExp("<t<<e>><s>>t<>", "<", ">", "g")* returns: ["t<<e>><s>", ""]* matchRecursiveRegExp("<div id=\"x\">test</div>", "<div\\b[^>]*>", "</div>", "gi")* returns: ["test"]*/
showdown.helper.matchRecursiveRegExp = function (str, left, right, flags) {'use strict';var matchPos = rgxFindMatchPos (str, left, right, flags),results = [];for (var i = 0; i < matchPos.length; ++i) {results.push([str.slice(matchPos[i].wholeMatch.start, matchPos[i].wholeMatch.end),str.slice(matchPos[i].match.start, matchPos[i].match.end),str.slice(matchPos[i].left.start, matchPos[i].left.end),str.slice(matchPos[i].right.start, matchPos[i].right.end)]);}return results;
};/**** @param {string} str* @param {string|function} replacement* @param {string} left* @param {string} right* @param {string} flags* @returns {string}*/
showdown.helper.replaceRecursiveRegExp = function (str, replacement, left, right, flags) {'use strict';if (!showdown.helper.isFunction(replacement)) {var repStr = replacement;replacement = function () {return repStr;};}var matchPos = rgxFindMatchPos(str, left, right, flags),finalStr = str,lng = matchPos.length;if (lng > 0) {var bits = [];if (matchPos[0].wholeMatch.start !== 0) {bits.push(str.slice(0, matchPos[0].wholeMatch.start));}for (var i = 0; i < lng; ++i) {bits.push(replacement(str.slice(matchPos[i].wholeMatch.start, matchPos[i].wholeMatch.end),str.slice(matchPos[i].match.start, matchPos[i].match.end),str.slice(matchPos[i].left.start, matchPos[i].left.end),str.slice(matchPos[i].right.start, matchPos[i].right.end)));if (i < lng - 1) {bits.push(str.slice(matchPos[i].wholeMatch.end, matchPos[i + 1].wholeMatch.start));}}if (matchPos[lng - 1].wholeMatch.end < str.length) {bits.push(str.slice(matchPos[lng - 1].wholeMatch.end));}finalStr = bits.join('');}return finalStr;
};/*** POLYFILLS*/
if (showdown.helper.isUndefined(console)) {console = {warn: function (msg) {'use strict';alert(msg);},log: function (msg) {'use strict';alert(msg);},error: function (msg) {'use strict';throw msg;}};
}/*** Created by Estevao on 31-05-2015.*//*** Showdown Converter class* @class* @param {object} [converterOptions]* @returns {Converter}*/
showdown.Converter = function (converterOptions) {'use strict';var/*** Options used by this converter* @private* @type {{}}*/options = {},/*** Language extensions used by this converter* @private* @type {Array}*/langExtensions = [],/*** Output modifiers extensions used by this converter* @private* @type {Array}*/outputModifiers = [],/*** Event listeners* @private* @type {{}}*/listeners = {};_constructor();/*** Converter constructor* @private*/function _constructor() {converterOptions = converterOptions || {};for (var gOpt in globalOptions) {if (globalOptions.hasOwnProperty(gOpt)) {options[gOpt] = globalOptions[gOpt];}}// Merge optionsif (typeof converterOptions === 'object') {for (var opt in converterOptions) {if (converterOptions.hasOwnProperty(opt)) {options[opt] = converterOptions[opt];}}} else {throw Error('Converter expects the passed parameter to be an object, but ' + typeof converterOptions +' was passed instead.');}if (options.extensions) {showdown.helper.forEach(options.extensions, _parseExtension);}}/*** Parse extension* @param {*} ext* @param {string} [name='']* @private*/function _parseExtension(ext, name) {name = name || null;// If it's a string, the extension was previously loadedif (showdown.helper.isString(ext)) {ext = showdown.helper.stdExtName(ext);name = ext;// LEGACY_SUPPORT CODEif (showdown.extensions[ext]) {console.warn('DEPRECATION WARNING: ' + ext + ' is an old extension that uses a deprecated loading method.' +'Please inform the developer that the extension should be updated!');legacyExtensionLoading(showdown.extensions[ext], ext);return;// END LEGACY SUPPORT CODE} else if (!showdown.helper.isUndefined(extensions[ext])) {ext = extensions[ext];} else {throw Error('Extension "' + ext + '" could not be loaded. It was either not found or is not a valid extension.');}}if (typeof ext === 'function') {ext = ext();}if (!showdown.helper.isArray(ext)) {ext = [ext];}var validExt = validate(ext, name);if (!validExt.valid) {throw Error(validExt.error);}for (var i = 0; i < ext.length; ++i) {switch (ext[i].type) {case 'lang':langExtensions.push(ext[i]);break;case 'output':outputModifiers.push(ext[i]);break;}if (ext[i].hasOwnProperty(listeners)) {for (var ln in ext[i].listeners) {if (ext[i].listeners.hasOwnProperty(ln)) {listen(ln, ext[i].listeners[ln]);}}}}}/*** LEGACY_SUPPORT* @param {*} ext* @param {string} name*/function legacyExtensionLoading(ext, name) {if (typeof ext === 'function') {ext = ext(new showdown.Converter());}if (!showdown.helper.isArray(ext)) {ext = [ext];}var valid = validate(ext, name);if (!valid.valid) {throw Error(valid.error);}for (var i = 0; i < ext.length; ++i) {switch (ext[i].type) {case 'lang':langExtensions.push(ext[i]);break;case 'output':outputModifiers.push(ext[i]);break;default:// should never reach herethrow Error('Extension loader error: Type unrecognized!!!');}}}/*** Listen to an event* @param {string} name* @param {function} callback*/function listen(name, callback) {if (!showdown.helper.isString(name)) {throw Error('Invalid argument in converter.listen() method: name must be a string, but ' + typeof name + ' given');}if (typeof callback !== 'function') {throw Error('Invalid argument in converter.listen() method: callback must be a function, but ' + typeof callback + ' given');}if (!listeners.hasOwnProperty(name)) {listeners[name] = [];}listeners[name].push(callback);}function rTrimInputText(text) {var rsp = text.match(/^\s*/)[0].length,rgx = new RegExp('^\\s{0,' + rsp + '}', 'gm');return text.replace(rgx, '');}/*** Dispatch an event* @private* @param {string} evtName Event name* @param {string} text Text* @param {{}} options Converter Options* @param {{}} globals* @returns {string}*/this._dispatch = function dispatch (evtName, text, options, globals) {if (listeners.hasOwnProperty(evtName)) {for (var ei = 0; ei < listeners[evtName].length; ++ei) {var nText = listeners[evtName][ei](evtName, text, this, options, globals);if (nText && typeof nText !== 'undefined') {text = nText;}}}return text;};/*** Listen to an event* @param {string} name* @param {function} callback* @returns {showdown.Converter}*/this.listen = function (name, callback) {listen(name, callback);return this;};/*** Converts a markdown string into HTML* @param {string} text* @returns {*}*/this.makeHtml = function (text) {//check if text is not falsyif (!text) {return text;}var globals = {gHtmlBlocks:     [],gHtmlMdBlocks:   [],gHtmlSpans:      [],gUrls:           {},gTitles:         {},gDimensions:     {},gListLevel:      0,hashLinkCounts:  {},langExtensions:  langExtensions,outputModifiers: outputModifiers,converter:       this,ghCodeBlocks:    []};// attacklab: Replace ~ with ~T// This lets us use tilde as an escape char to avoid md5 hashes// The choice of character is arbitrary; anything that isn't// magic in Markdown will work.text = text.replace(/~/g, '~T');// attacklab: Replace $ with ~D// RegExp interprets $ as a special character// when it's in a replacement stringtext = text.replace(/\$/g, '~D');// Standardize line endingstext = text.replace(/\r\n/g, '\n'); // DOS to Unixtext = text.replace(/\r/g, '\n'); // Mac to Unixif (options.smartIndentationFix) {text = rTrimInputText(text);}// Make sure text begins and ends with a couple of newlines://text = '\n\n' + text + '\n\n';text = text;// detabtext = showdown.subParser('detab')(text, options, globals);// stripBlankLinestext = showdown.subParser('stripBlankLines')(text, options, globals);//run languageExtensionsshowdown.helper.forEach(langExtensions, function (ext) {text = showdown.subParser('runExtension')(ext, text, options, globals);});// run the sub parserstext = showdown.subParser('hashPreCodeTags')(text, options, globals);text = showdown.subParser('githubCodeBlocks')(text, options, globals);text = showdown.subParser('hashHTMLBlocks')(text, options, globals);text = showdown.subParser('hashHTMLSpans')(text, options, globals);text = showdown.subParser('stripLinkDefinitions')(text, options, globals);text = showdown.subParser('blockGamut')(text, options, globals);text = showdown.subParser('unhashHTMLSpans')(text, options, globals);text = showdown.subParser('unescapeSpecialChars')(text, options, globals);// attacklab: Restore dollar signstext = text.replace(/~D/g, '$$');// attacklab: Restore tildestext = text.replace(/~T/g, '~');// Run output modifiersshowdown.helper.forEach(outputModifiers, function (ext) {text = showdown.subParser('runExtension')(ext, text, options, globals);});return text;};/*** Set an option of this Converter instance* @param {string} key* @param {*} value*/this.setOption = function (key, value) {options[key] = value;};/*** Get the option of this Converter instance* @param {string} key* @returns {*}*/this.getOption = function (key) {return options[key];};/*** Get the options of this Converter instance* @returns {{}}*/this.getOptions = function () {return options;};/*** Add extension to THIS converter* @param {{}} extension* @param {string} [name=null]*/this.addExtension = function (extension, name) {name = name || null;_parseExtension(extension, name);};/*** Use a global registered extension with THIS converter* @param {string} extensionName Name of the previously registered extension*/this.useExtension = function (extensionName) {_parseExtension(extensionName);};/*** Set the flavor THIS converter should use* @param {string} name*/this.setFlavor = function (name) {if (flavor.hasOwnProperty(name)) {var preset = flavor[name];for (var option in preset) {if (preset.hasOwnProperty(option)) {options[option] = preset[option];}}}};/*** Remove an extension from THIS converter.* Note: This is a costly operation. It's better to initialize a new converter* and specify the extensions you wish to use* @param {Array} extension*/this.removeExtension = function (extension) {if (!showdown.helper.isArray(extension)) {extension = [extension];}for (var a = 0; a < extension.length; ++a) {var ext = extension[a];for (var i = 0; i < langExtensions.length; ++i) {if (langExtensions[i] === ext) {langExtensions[i].splice(i, 1);}}for (var ii = 0; ii < outputModifiers.length; ++i) {if (outputModifiers[ii] === ext) {outputModifiers[ii].splice(i, 1);}}}};/*** Get all extension of THIS converter* @returns {{language: Array, output: Array}}*/this.getAllExtensions = function () {return {language: langExtensions,output: outputModifiers};};
};/*** Turn Markdown link shortcuts into XHTML <a> tags.*/
showdown.subParser('anchors', function (text, options, globals) {'use strict';text = globals.converter._dispatch('anchors.before', text, options, globals);var writeAnchorTag = function (wholeMatch, m1, m2, m3, m4, m5, m6, m7) {if (showdown.helper.isUndefined(m7)) {m7 = '';}wholeMatch = m1;var linkText = m2,linkId = m3.toLowerCase(),url = m4,title = m7;if (!url) {if (!linkId) {// lower-case and turn embedded newlines into spaceslinkId = linkText.toLowerCase().replace(/ ?\n/g, ' ');}url = '#' + linkId;if (!showdown.helper.isUndefined(globals.gUrls[linkId])) {url = globals.gUrls[linkId];if (!showdown.helper.isUndefined(globals.gTitles[linkId])) {title = globals.gTitles[linkId];}} else {if (wholeMatch.search(/\(\s*\)$/m) > -1) {// Special case for explicit empty urlurl = '';} else {return wholeMatch;}}}url = showdown.helper.escapeCharacters(url, '*_', false);var result = '<a href="' + url + '"';if (title !== '' && title !== null) {title = title.replace(/"/g, '&quot;');title = showdown.helper.escapeCharacters(title, '*_', false);result += ' title="' + title + '"';}result += '>' + linkText + '</a>';return result;};// First, handle reference-style links: [link text] [id]/*text = text.replace(/(                           // wrap whole match in $1\[((?:\[[^\]]*\]       // allow brackets nested one level|[^\[]            // or anything else)*)\][ ]?                    // one optional space(?:\n[ ]*)?                // one optional newline followed by spaces\[(.*?)                   // id = $3\])()()()()                   // pad remaining backreferences/g,_DoAnchors_callback);*/text = text.replace(/(\[((?:\[[^\]]*]|[^\[\]])*)][ ]?(?:\n[ ]*)?\[(.*?)])()()()()/g, writeAnchorTag);//// Next, inline-style links: [link text](url "optional title")///*text = text.replace(/(                        // wrap whole match in $1\[((?:\[[^\]]*\]   // allow brackets nested one level|[^\[\]]          // or anything else))\]\(                       // literal paren[ \t]*()                        // no id, so leave $3 empty<?(.*?)>?              // href = $4[ \t]*(                     // $5(['"])             // quote char = $6(.*?)             // Title = $7\6                 // matching quote[ \t]*             // ignore any spaces/tabs between closing quote and ))?                     // title is optional\))/g,writeAnchorTag);*/text = text.replace(/(\[((?:\[[^\]]*]|[^\[\]])*)]\([ \t]*()<?(.*?(?:\(.*?\).*?)?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,writeAnchorTag);//// Last, handle reference-style shortcuts: [link text]// These must come last in case you've also got [link test][1]// or [link test](/foo)///*text = text.replace(/(                // wrap whole match in $1\[([^\[\]]+)       // link text = $2; can't contain '[' or ']'\])()()()()()      // pad rest of backreferences/g, writeAnchorTag);*/text = text.replace(/(\[([^\[\]]+)])()()()()()/g, writeAnchorTag);text = globals.converter._dispatch('anchors.after', text, options, globals);return text;
});showdown.subParser('autoLinks', function (text, options, globals) {'use strict';text = globals.converter._dispatch('autoLinks.before', text, options, globals);var simpleURLRegex  = /\b(((https?|ftp|dict):\/\/|www\.)[^'">\s]+\.[^'">\s]+)(?=\s|$)(?!["<>])/gi,delimUrlRegex   = /<(((https?|ftp|dict):\/\/|www\.)[^'">\s]+)>/gi,simpleMailRegex = /(?:^|[ \n\t])([A-Za-z0-9!#$%&'*+-/=?^_`\{|}~\.]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)(?:$|[ \n\t])/gi,delimMailRegex  = /<(?:mailto:)?([-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi;text = text.replace(delimUrlRegex, replaceLink);text = text.replace(delimMailRegex, replaceMail);// simpleURLRegex  = /\b(((https?|ftp|dict):\/\/|www\.)[-.+~:?#@!$&'()*,;=[\]\w]+)\b/gi,// Email addresses: <address@domain.foo>if (options.simplifiedAutoLink) {text = text.replace(simpleURLRegex, replaceLink);text = text.replace(simpleMailRegex, replaceMail);}function replaceLink(wm, link) {var lnkTxt = link;if (/^www\./i.test(link)) {link = link.replace(/^www\./i, 'http://www.');}return '<a href="' + link + '">' + lnkTxt + '</a>';}function replaceMail(wholeMatch, m1) {var unescapedStr = showdown.subParser('unescapeSpecialChars')(m1);return showdown.subParser('encodeEmailAddress')(unescapedStr);}text = globals.converter._dispatch('autoLinks.after', text, options, globals);return text;
});/*** These are all the transformations that form block-level* tags like paragraphs, headers, and list items.*/
showdown.subParser('blockGamut', function (text, options, globals) {'use strict';text = globals.converter._dispatch('blockGamut.before', text, options, globals);// we parse blockquotes first so that we can have headings and hrs// inside blockquotestext = showdown.subParser('blockQuotes')(text, options, globals);text = showdown.subParser('headers')(text, options, globals);// Do Horizontal Rules:var key = showdown.subParser('hashBlock')('<hr />', options, globals);text = text.replace(/^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$/gm, key);text = text.replace(/^[ ]{0,2}([ ]?\-[ ]?){3,}[ \t]*$/gm, key);text = text.replace(/^[ ]{0,2}([ ]?_[ ]?){3,}[ \t]*$/gm, key);text = showdown.subParser('lists')(text, options, globals);text = showdown.subParser('codeBlocks')(text, options, globals);text = showdown.subParser('tables')(text, options, globals);// We already ran _HashHTMLBlocks() before, in Markdown(), but that// was to escape raw HTML in the original Markdown source. This time,// we're escaping the markup we've just created, so that we don't wrap// <p> tags around block-level tags.text = showdown.subParser('hashHTMLBlocks')(text, options, globals);text = showdown.subParser('paragraphs')(text, options, globals);text = globals.converter._dispatch('blockGamut.after', text, options, globals);return text;
});showdown.subParser('blockQuotes', function (text, options, globals) {'use strict';text = globals.converter._dispatch('blockQuotes.before', text, options, globals);/*text = text.replace(/(                              // Wrap whole match in $1(^[ \t]*>[ \t]?         // '>' at the start of a line.+\n                    // rest of the first line(.+\n)*                    // subsequent consecutive lines\n*                      // blanks)+)/gm, function(){...});*/text = text.replace(/((^[ \t]{0,3}>[ \t]?.+\n(.+\n)*\n*)+)/gm, function (wholeMatch, m1) {var bq = m1;// attacklab: hack around Konqueror 3.5.4 bug:// "----------bug".replace(/^-/g,"") == "bug"bq = bq.replace(/^[ \t]*>[ \t]?/gm, '~0'); // trim one level of quoting// attacklab: clean up hackbq = bq.replace(/~0/g, '');bq = bq.replace(/^[ \t]+$/gm, ''); // trim whitespace-only linesbq = showdown.subParser('githubCodeBlocks')(bq, options, globals);bq = showdown.subParser('blockGamut')(bq, options, globals); // recursebq = bq.replace(/(^|\n)/g, '$1  ');// These leading spaces screw with <pre> content, so we need to fix that:bq = bq.replace(/(\s*<pre>[^\r]+?<\/pre>)/gm, function (wholeMatch, m1) {var pre = m1;// attacklab: hack around Konqueror 3.5.4 bug:pre = pre.replace(/^  /mg, '~0');pre = pre.replace(/~0/g, '');return pre;});return showdown.subParser('hashBlock')('<blockquote>\n' + bq + '\n</blockquote>', options, globals);});text = globals.converter._dispatch('blockQuotes.after', text, options, globals);return text;
});/*** Process Markdown `<pre><code>` blocks.*/
showdown.subParser('codeBlocks', function (text, options, globals) {'use strict';text = globals.converter._dispatch('codeBlocks.before', text, options, globals);/*text = text.replace(text,/(?:\n\n|^)(                                // $1 = the code block -- one or more lines, starting with a space/tab(?:(?:[ ]{4}|\t)          // Lines must start with a tab or a tab-width of spaces - attacklab: g_tab_width.*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))    // attacklab: g_tab_width/g,function(){...});*/// attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bugtext += '~0';var pattern = /(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g;text = text.replace(pattern, function (wholeMatch, m1, m2) {var codeblock = m1,nextChar = m2,end = '\n';codeblock = showdown.subParser('outdent')(codeblock);codeblock = showdown.subParser('encodeCode')(codeblock);codeblock = showdown.subParser('detab')(codeblock);codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlinescodeblock = codeblock.replace(/\n+$/g, ''); // trim trailing newlinesif (options.omitExtraWLInCodeBlocks) {end = '';}codeblock = '<pre><code>' + codeblock + end + '</code></pre>';return showdown.subParser('hashBlock')(codeblock, options, globals) + nextChar;});// attacklab: strip sentineltext = text.replace(/~0/, '');text = globals.converter._dispatch('codeBlocks.after', text, options, globals);return text;
});/****   *  Backtick quotes are used for <code></code> spans.**   *  You can use multiple backticks as the delimiters if you want to*     include literal backticks in the code span. So, this input:**         Just type ``foo `bar` baz`` at the prompt.**       Will translate to:**         <p>Just type <code>foo `bar` baz</code> at the prompt.</p>**    There's no arbitrary limit to the number of backticks you*    can use as delimters. If you need three consecutive backticks*    in your code, use four for delimiters, etc.**  *  You can use spaces to get literal backticks at the edges:**         ... type `` `bar` `` ...**       Turns to:**         ... type <code>`bar`</code> ...*/
showdown.subParser('codeSpans', function (text, options, globals) {'use strict';text = globals.converter._dispatch('codeSpans.before', text, options, globals);/*text = text.replace(/(^|[^\\])                 // Character before opening ` can't be a backslash(`+)                      // $2 = Opening run of `(                           // $3 = The code block[^\r]*?[^`]                   // attacklab: work around lack of lookbehind)\2                         // Matching closer(?!`)/gm, function(){...});*/if (typeof(text) === 'undefined') {text = '';}text = text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,function (wholeMatch, m1, m2, m3) {var c = m3;c = c.replace(/^([ \t]*)/g, '');   // leading whitespacec = c.replace(/[ \t]*$/g, ''); // trailing whitespacec = showdown.subParser('encodeCode')(c);return m1 + '<code>' + c + '</code>';});text = globals.converter._dispatch('codeSpans.after', text, options, globals);return text;
});/*** Convert all tabs to spaces*/
showdown.subParser('detab', function (text) {'use strict';// expand first n-1 tabstext = text.replace(/\t(?=\t)/g, '    '); // g_tab_width// replace the nth with two sentinelstext = text.replace(/\t/g, '~A~B');// use the sentinel to anchor our regex so it doesn't explodetext = text.replace(/~B(.+?)~A/g, function (wholeMatch, m1) {var leadingText = m1,numSpaces = 4 - leadingText.length % 4;  // g_tab_width// there *must* be a better way to do this:for (var i = 0; i < numSpaces; i++) {leadingText += ' ';}return leadingText;});// clean up sentinelstext = text.replace(/~A/g, '    ');  // g_tab_widthtext = text.replace(/~B/g, '');return text;});/*** Smart processing for ampersands and angle brackets that need to be encoded.*/
showdown.subParser('encodeAmpsAndAngles', function (text) {'use strict';// Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:// http://bumppo.net/projects/amputator/text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g, '&amp;');// Encode naked <'stext = text.replace(/<(?![a-z\/?\$!])/gi, '&lt;');return text;
});/*** Returns the string, with after processing the following backslash escape sequences.** attacklab: The polite way to do this is with the new escapeCharacters() function:**    text = escapeCharacters(text,"\\",true);*    text = escapeCharacters(text,"`*_{}[]()>#+-.!",true);** ...but we're sidestepping its use of the (slow) RegExp constructor* as an optimization for Firefox.  This function gets called a LOT.*/
showdown.subParser('encodeBackslashEscapes', function (text) {'use strict';text = text.replace(/\\(\\)/g, showdown.helper.escapeCharactersCallback);text = text.replace(/\\([`*_{}\[\]()>#+-.!])/g, showdown.helper.escapeCharactersCallback);return text;
});/*** Encode/escape certain characters inside Markdown code runs.* The point is that in code, these characters are literals,* and lose their special Markdown meanings.*/
showdown.subParser('encodeCode', function (text) {'use strict';// Encode all ampersands; HTML entities are not// entities within a Markdown code span.text = text.replace(/&/g, '&amp;');// Do the angle bracket song and dance:text = text.replace(/</g, '&lt;');text = text.replace(/>/g, '&gt;');// Now, escape characters that are magic in Markdown:text = showdown.helper.escapeCharacters(text, '*_{}[]\\', false);// jj the line above breaks this://---//* Item//   1. Subitem//            special char: *// ---return text;
});/***  Input: an email address, e.g. "foo@example.com"**  Output: the email address as a mailto link, with each character*    of the address encoded as either a decimal or hex entity, in*    the hopes of foiling most address harvesting spam bots. E.g.:**    <a href="&#x6D;&#97;&#105;&#108;&#x74;&#111;:&#102;&#111;&#111;&#64;&#101;*       x&#x61;&#109;&#x70;&#108;&#x65;&#x2E;&#99;&#111;&#109;">&#102;&#111;&#111;*       &#64;&#101;x&#x61;&#109;&#x70;&#108;&#x65;&#x2E;&#99;&#111;&#109;</a>**  Based on a filter by Matthew Wickline, posted to the BBEdit-Talk*  mailing list: <http://tinyurl.com/yu7ue>**/
showdown.subParser('encodeEmailAddress', function (addr) {'use strict';var encode = [function (ch) {return '&#' + ch.charCodeAt(0) + ';';},function (ch) {return '&#x' + ch.charCodeAt(0).toString(16) + ';';},function (ch) {return ch;}];addr = 'mailto:' + addr;addr = addr.replace(/./g, function (ch) {if (ch === '@') {// this *must* be encoded. I insist.ch = encode[Math.floor(Math.random() * 2)](ch);} else if (ch !== ':') {// leave ':' alone (to spot mailto: later)var r = Math.random();// roughly 10% raw, 45% hex, 45% decch = (r > 0.9 ? encode[2](ch) : r > 0.45 ? encode[1](ch) : encode[0](ch));}return ch;});addr = '<a href="' + addr + '">' + addr + '</a>';addr = addr.replace(/">.+:/g, '">'); // strip the mailto: from the visible partreturn addr;
});/*** Within tags -- meaning between < and > -- encode [\ ` * _] so they* don't conflict with their use in Markdown for code, italics and strong.*/
showdown.subParser('escapeSpecialCharsWithinTagAttributes', function (text) {'use strict';// Build a regex to find HTML tags and comments.  See Friedl's// "Mastering Regular Expressions", 2nd Ed., pp. 200-201.var regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|<!(--.*?--\s*)+>)/gi;text = text.replace(regex, function (wholeMatch) {var tag = wholeMatch.replace(/(.)<\/?code>(?=.)/g, '$1`');tag = showdown.helper.escapeCharacters(tag, '\\`*_', false);return tag;});return text;
});/*** Handle github codeblocks prior to running HashHTML so that* HTML contained within the codeblock gets escaped properly* Example:* ```ruby*     def hello_world(x)*       puts "Hello, #{x}"*     end* ```*/
showdown.subParser('githubCodeBlocks', function (text, options, globals) {'use strict';// early exit if option is not enabledif (!options.ghCodeBlocks) {return text;}text = globals.converter._dispatch('githubCodeBlocks.before', text, options, globals);text += '~0';text = text.replace(/(?:^|\n)```(.*)\n([\s\S]*?)\n```/g, function (wholeMatch, language, codeblock) {var end = (options.omitExtraWLInCodeBlocks) ? '' : '\n';// First parse the github code blockcodeblock = showdown.subParser('encodeCode')(codeblock);codeblock = showdown.subParser('detab')(codeblock);codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlinescodeblock = codeblock.replace(/\n+$/g, ''); // trim trailing whitespacecodeblock = '<pre><code' + (language ? ' class="' + language + ' language-' + language + '"' : '') + '>' + codeblock + end + '</code></pre>';codeblock = showdown.subParser('hashBlock')(codeblock, options, globals);// Since GHCodeblocks can be false positives, we need to// store the primitive text and the parsed text in a global var,// and then return a tokenreturn '\n\n~G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\n\n';});// attacklab: strip sentineltext = text.replace(/~0/, '');return globals.converter._dispatch('githubCodeBlocks.after', text, options, globals);
});showdown.subParser('hashBlock', function (text, options, globals) {'use strict';text = text.replace(/(^\n+|\n+$)/g, '');return '\n\n~K' + (globals.gHtmlBlocks.push(text) - 1) + 'K\n\n';
});showdown.subParser('hashElement', function (text, options, globals) {'use strict';return function (wholeMatch, m1) {var blockText = m1;// Undo double linesblockText = blockText.replace(/\n\n/g, '\n');blockText = blockText.replace(/^\n/, '');// strip trailing blank linesblockText = blockText.replace(/\n+$/g, '');// Replace the element text with a marker ("~KxK" where x is its key)blockText = '\n\n~K' + (globals.gHtmlBlocks.push(blockText) - 1) + 'K\n\n';return blockText;};
});showdown.subParser('hashHTMLBlocks', function (text, options, globals) {'use strict';var blockTags = ['pre','div','h1','h2','h3','h4','h5','h6','blockquote','table','dl','ol','ul','script','noscript','form','fieldset','iframe','math','style','section','header','footer','nav','article','aside','address','audio','canvas','figure','hgroup','output','video','p'],repFunc = function (wholeMatch, match, left, right) {var txt = wholeMatch;// check if this html element is marked as markdown// if so, it's contents should be parsed as markdownif (left.search(/\bmarkdown\b/) !== -1) {txt = left + globals.converter.makeHtml(match) + right;}return '\n\n~K' + (globals.gHtmlBlocks.push(txt) - 1) + 'K\n\n';};for (var i = 0; i < blockTags.length; ++i) {text = showdown.helper.replaceRecursiveRegExp(text, repFunc, '^(?: |\\t){0,3}<' + blockTags[i] + '\\b[^>]*>', '</' + blockTags[i] + '>', 'gim');}// HR SPECIAL CASEtext = text.replace(/(\n[ ]{0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,showdown.subParser('hashElement')(text, options, globals));// Special case for standalone HTML comments:text = text.replace(/(<!--[\s\S]*?-->)/g,showdown.subParser('hashElement')(text, options, globals));// PHP and ASP-style processor instructions (<?...?> and <%...%>)text = text.replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,showdown.subParser('hashElement')(text, options, globals));return text;
});/*** Hash span elements that should not be parsed as markdown*/
showdown.subParser('hashHTMLSpans', function (text, config, globals) {'use strict';var matches = showdown.helper.matchRecursiveRegExp(text, '<code\\b[^>]*>', '</code>', 'gi');for (var i = 0; i < matches.length; ++i) {text = text.replace(matches[i][0], '~L' + (globals.gHtmlSpans.push(matches[i][0]) - 1) + 'L');}return text;
});/*** Unhash HTML spans*/
showdown.subParser('unhashHTMLSpans', function (text, config, globals) {'use strict';for (var i = 0; i < globals.gHtmlSpans.length; ++i) {text = text.replace('~L' + i + 'L', globals.gHtmlSpans[i]);}return text;
});/*** Hash span elements that should not be parsed as markdown*/
showdown.subParser('hashPreCodeTags', function (text, config, globals) {'use strict';var repFunc = function (wholeMatch, match, left, right) {// encode html entitiesvar codeblock = left + showdown.subParser('encodeCode')(match) + right;return '\n\n~G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\n\n';};text = showdown.helper.replaceRecursiveRegExp(text, repFunc, '^(?: |\\t){0,3}<pre\\b[^>]*>\\s*<code\\b[^>]*>', '^(?: |\\t){0,3}</code>\\s*</pre>', 'gim');return text;
});showdown.subParser('headers', function (text, options, globals) {'use strict';text = globals.converter._dispatch('headers.before', text, options, globals);var prefixHeader = options.prefixHeaderId,headerLevelStart = (isNaN(parseInt(options.headerLevelStart))) ? 1 : parseInt(options.headerLevelStart),// Set text-style headers://    Header 1//  ========////    Header 2//  --------//setextRegexH1 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n={2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n=+[ \t]*\n+/gm,setextRegexH2 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n-{2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n-+[ \t]*\n+/gm;text = text.replace(setextRegexH1, function (wholeMatch, m1) {var spanGamut = showdown.subParser('spanGamut')(m1, options, globals),hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"',hLevel = headerLevelStart,hashBlock = '<h' + hLevel + hID + '>' + spanGamut + '</h' + hLevel + '>';return showdown.subParser('hashBlock')(hashBlock, options, globals);});text = text.replace(setextRegexH2, function (matchFound, m1) {var spanGamut = showdown.subParser('spanGamut')(m1, options, globals),hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"',hLevel = headerLevelStart + 1,hashBlock = '<h' + hLevel + hID + '>' + spanGamut + '</h' + hLevel + '>';return showdown.subParser('hashBlock')(hashBlock, options, globals);});// atx-style headers://  # Header 1//  ## Header 2//  ## Header 2 with closing hashes ##//  ...//  ###### Header 6//text = text.replace(/^(#{1,6})[ \t]*(.+?)[ \t]*#*\n+/gm, function (wholeMatch, m1, m2) {var span = showdown.subParser('spanGamut')(m2, options, globals),hID = (options.noHeaderId) ? '' : ' id="' + headerId(m2) + '"',hLevel = headerLevelStart - 1 + m1.length,header = '<h' + hLevel + hID + '>' + span + '</h' + hLevel + '>';return showdown.subParser('hashBlock')(header, options, globals);});function headerId(m) {var title, escapedId = m.replace(/[^\w]/g, '').toLowerCase();if (globals.hashLinkCounts[escapedId]) {title = escapedId + '-' + (globals.hashLinkCounts[escapedId]++);} else {title = escapedId;globals.hashLinkCounts[escapedId] = 1;}// Prefix id to prevent causing inadvertent pre-existing style matches.if (prefixHeader === true) {prefixHeader = 'section';}if (showdown.helper.isString(prefixHeader)) {return prefixHeader + title;}return title;}text = globals.converter._dispatch('headers.after', text, options, globals);return text;
});/*** Turn Markdown image shortcuts into <img> tags.*/
showdown.subParser('images', function (text, options, globals) {'use strict';text = globals.converter._dispatch('images.before', text, options, globals);var inlineRegExp    = /!\[(.*?)]\s?\([ \t]*()<?(\S+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(['"])(.*?)\6[ \t]*)?\)/g,referenceRegExp = /!\[([^\]]*?)] ?(?:\n *)?\[(.*?)]()()()()()/g;function writeImageTag (wholeMatch, altText, linkId, url, width, height, m5, title) {var gUrls   = globals.gUrls,gTitles = globals.gTitles,gDims   = globals.gDimensions;linkId = linkId.toLowerCase();if (!title) {title = '';}if (url === '' || url === null) {if (linkId === '' || linkId === null) {// lower-case and turn embedded newlines into spaceslinkId = altText.toLowerCase().replace(/ ?\n/g, ' ');}url = '#' + linkId;if (!showdown.helper.isUndefined(gUrls[linkId])) {url = gUrls[linkId];if (!showdown.helper.isUndefined(gTitles[linkId])) {title = gTitles[linkId];}if (!showdown.helper.isUndefined(gDims[linkId])) {width = gDims[linkId].width;height = gDims[linkId].height;}} else {return wholeMatch;}}altText = altText.replace(/"/g, '&quot;');altText = showdown.helper.escapeCharacters(altText, '*_', false);url = showdown.helper.escapeCharacters(url, '*_', false);var result = '<img src="' + url + '" alt="' + altText + '"';if (title) {title = title.replace(/"/g, '&quot;');title = showdown.helper.escapeCharacters(title, '*_', false);result += ' title="' + title + '"';}if (width && height) {width  = (width === '*') ? 'auto' : width;height = (height === '*') ? 'auto' : height;result += ' width="' + width + '"';result += ' height="' + height + '"';}result += ' />';return result;}// First, handle reference-style labeled images: ![alt text][id]text = text.replace(referenceRegExp, writeImageTag);// Next, handle inline images:  ![alt text](url =<width>x<height> "optional title")text = text.replace(inlineRegExp, writeImageTag);text = globals.converter._dispatch('images.after', text, options, globals);return text;
});showdown.subParser('italicsAndBold', function (text, options, globals) {'use strict';text = globals.converter._dispatch('italicsAndBold.before', text, options, globals);if (options.literalMidWordUnderscores) {//underscores// Since we are consuming a \s character, we need to add ittext = text.replace(/(^|\s|>|\b)__(?=\S)([\s\S]+?)__(?=\b|<|\s|$)/gm, '$1<strong>$2</strong>');text = text.replace(/(^|\s|>|\b)_(?=\S)([\s\S]+?)_(?=\b|<|\s|$)/gm, '$1<em>$2</em>');//asteriskstext = text.replace(/(\*\*)(?=\S)([^\r]*?\S[*]*)\1/g, '<strong>$2</strong>');text = text.replace(/(\*)(?=\S)([^\r]*?\S)\1/g, '<em>$2</em>');} else {// <strong> must go first:text = text.replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g, '<strong>$2</strong>');text = text.replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g, '<em>$2</em>');}text = globals.converter._dispatch('italicsAndBold.after', text, options, globals);return text;
});/*** Form HTML ordered (numbered) and unordered (bulleted) lists.*/
showdown.subParser('lists', function (text, options, globals) {'use strict';text = globals.converter._dispatch('lists.before', text, options, globals);/*** Process the contents of a single ordered or unordered list, splitting it* into individual list items.* @param {string} listStr* @param {boolean} trimTrailing* @returns {string}*/function processListItems (listStr, trimTrailing) {// The $g_list_level global keeps track of when we're inside a list.// Each time we enter a list, we increment it; when we leave a list,// we decrement. If it's zero, we're not in a list anymore.//// We do this because when we're not inside a list, we want to treat// something like this:////    I recommend upgrading to version//    8. Oops, now this line is treated//    as a sub-list.//// As a single paragraph, despite the fact that the second line starts// with a digit-period-space sequence.//// Whereas when we're inside a list (or sub-list), that line will be// treated as the start of a sub-list. What a kludge, huh? This is// an aspect of Markdown's syntax that's hard to parse perfectly// without resorting to mind-reading. Perhaps the solution is to// change the syntax rules such that sub-lists must start with a// starting cardinal number; e.g. "1." or "a.".globals.gListLevel++;// trim trailing blank lines:listStr = listStr.replace(/\n{2,}$/, '\n');// attacklab: add sentinel to emulate \zlistStr += '~0';var rgx = /(\n)?(^[ \t]*)([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(~0|\2([*+-]|\d+[.])[ \t]+))/gm,isParagraphed = (/\n[ \t]*\n(?!~0)/.test(listStr));listStr = listStr.replace(rgx, function (wholeMatch, m1, m2, m3, m4, taskbtn, checked) {checked = (checked && checked.trim() !== '');var item = showdown.subParser('outdent')(m4, options, globals),bulletStyle = '';// Support for github tasklistsif (taskbtn && options.tasklists) {bulletStyle = ' class="task-list-item" style="list-style-type: none;"';item = item.replace(/^[ \t]*\[(x|X| )?]/m, function () {var otp = '<input type="checkbox" disabled style="margin: 0px 0.35em 0.25em -1.6em; vertical-align: middle;"';if (checked) {otp += ' checked';}otp += '>';return otp;});}// m1 - Leading line or// Has a double return (multi paragraph) or// Has sublistif (m1 || (item.search(/\n{2,}/) > -1)) {item = showdown.subParser('githubCodeBlocks')(item, options, globals);item = showdown.subParser('blockGamut')(item, options, globals);} else {// Recursion for sub-lists:item = showdown.subParser('lists')(item, options, globals);item = item.replace(/\n$/, ''); // chomp(item)if (isParagraphed) {item = showdown.subParser('paragraphs')(item, options, globals);} else {item = showdown.subParser('spanGamut')(item, options, globals);}}item =  '\n<li' + bulletStyle + '>' + item + '</li>\n';return item;});// attacklab: strip sentinellistStr = listStr.replace(/~0/g, '');globals.gListLevel--;if (trimTrailing) {listStr = listStr.replace(/\s+$/, '');}return listStr;}/*** Check and parse consecutive lists (better fix for issue #142)* @param {string} list* @param {string} listType* @param {boolean} trimTrailing* @returns {string}*/function parseConsecutiveLists(list, listType, trimTrailing) {// check if we caught 2 or more consecutive lists by mistake// we use the counterRgx, meaning if listType is UL we look for UL and vice versavar counterRxg = (listType === 'ul') ? /^ {0,2}\d+\.[ \t]/gm : /^ {0,2}[*+-][ \t]/gm,subLists = [],result = '';if (list.search(counterRxg) !== -1) {(function parseCL(txt) {var pos = txt.search(counterRxg);if (pos !== -1) {// sliceresult += '\n\n<' + listType + '>' + processListItems(txt.slice(0, pos), !!trimTrailing) + '</' + listType + '>\n\n';// invert counterType and listTypelistType = (listType === 'ul') ? 'ol' : 'ul';counterRxg = (listType === 'ul') ? /^ {0,2}\d+\.[ \t]/gm : /^ {0,2}[*+-][ \t]/gm;//recurseparseCL(txt.slice(pos));} else {result += '\n\n<' + listType + '>' + processListItems(txt, !!trimTrailing) + '</' + listType + '>\n\n';}})(list);for (var i = 0; i < subLists.length; ++i) {}} else {result = '\n\n<' + listType + '>' + processListItems(list, !!trimTrailing) + '</' + listType + '>\n\n';}return result;}// attacklab: add sentinel to hack around khtml/safari bug:// http://bugs.webkit.org/show_bug.cgi?id=11231text += '~0';// Re-usable pattern to match any entire ul or ol list:var wholeList = /^(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;if (globals.gListLevel) {text = text.replace(wholeList, function (wholeMatch, list, m2) {var listType = (m2.search(/[*+-]/g) > -1) ? 'ul' : 'ol';return parseConsecutiveLists(list, listType, true);});} else {wholeList = /(\n\n|^\n?)(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;//wholeList = /(\n\n|^\n?)( {0,3}([*+-]|\d+\.)[ \t]+[\s\S]+?)(?=(~0)|(\n\n(?!\t| {2,}| {0,3}([*+-]|\d+\.)[ \t])))/g;text = text.replace(wholeList, function (wholeMatch, m1, list, m3) {var listType = (m3.search(/[*+-]/g) > -1) ? 'ul' : 'ol';return parseConsecutiveLists(list, listType);});}// attacklab: strip sentineltext = text.replace(/~0/, '');text = globals.converter._dispatch('lists.after', text, options, globals);return text;
});/*** Remove one level of line-leading tabs or spaces*/
showdown.subParser('outdent', function (text) {'use strict';// attacklab: hack around Konqueror 3.5.4 bug:// "----------bug".replace(/^-/g,"") == "bug"text = text.replace(/^(\t|[ ]{1,4})/gm, '~0'); // attacklab: g_tab_width// attacklab: clean up hacktext = text.replace(/~0/g, '');return text;
});/****/
showdown.subParser('paragraphs', function (text, options, globals) {'use strict';text = globals.converter._dispatch('paragraphs.before', text, options, globals);// Strip leading and trailing lines:text = text.replace(/^\n+/g, '');text = text.replace(/\n+$/g, '');var grafs = text.split(/\n{2,}/g),grafsOut = [],end = grafs.length; // Wrap <p> tagsfor (var i = 0; i < end; i++) {var str = grafs[i];// if this is an HTML marker, copy itif (str.search(/~(K|G)(\d+)\1/g) >= 0) {grafsOut.push(str);} else {str = showdown.subParser('spanGamut')(str, options, globals);str = str.replace(/^([ \t]*)/g, '<p>');str += '</p>';grafsOut.push(str);}}/** Unhashify HTML blocks */end = grafsOut.length;for (i = 0; i < end; i++) {var blockText = '',grafsOutIt = grafsOut[i],codeFlag = false;// if this is a marker for an html block...while (grafsOutIt.search(/~(K|G)(\d+)\1/) >= 0) {var delim = RegExp.$1,num   = RegExp.$2;if (delim === 'K') {blockText = globals.gHtmlBlocks[num];} else {// we need to check if ghBlock is a false positiveif (codeFlag) {// use encoded version of all textblockText = showdown.subParser('encodeCode')(globals.ghCodeBlocks[num].text);} else {blockText = globals.ghCodeBlocks[num].codeblock;}}blockText = blockText.replace(/\$/g, '$$$$'); // Escape any dollar signsgrafsOutIt = grafsOutIt.replace(/(\n\n)?~(K|G)\d+\2(\n\n)?/, blockText);// Check if grafsOutIt is a pre->codeif (/^<pre\b[^>]*>\s*<code\b[^>]*>/.test(grafsOutIt)) {codeFlag = true;}}grafsOut[i] = grafsOutIt;}text = grafsOut.join('\n\n');// Strip leading and trailing lines:text = text.replace(/^\n+/g, '');text = text.replace(/\n+$/g, '');return globals.converter._dispatch('paragraphs.after', text, options, globals);
});/*** Run extension*/
showdown.subParser('runExtension', function (ext, text, options, globals) {'use strict';if (ext.filter) {text = ext.filter(text, globals.converter, options);} else if (ext.regex) {// TODO remove this when old extension loading mechanism is deprecatedvar re = ext.regex;if (!re instanceof RegExp) {re = new RegExp(re, 'g');}text = text.replace(re, ext.replace);}return text;
});/*** These are all the transformations that occur *within* block-level* tags like paragraphs, headers, and list items.*/
showdown.subParser('spanGamut', function (text, options, globals) {'use strict';text = globals.converter._dispatch('spanGamut.before', text, options, globals);text = showdown.subParser('codeSpans')(text, options, globals);text = showdown.subParser('escapeSpecialCharsWithinTagAttributes')(text, options, globals);text = showdown.subParser('encodeBackslashEscapes')(text, options, globals);// Process anchor and image tags. Images must come first,// because ![foo][f] looks like an anchor.text = showdown.subParser('images')(text, options, globals);text = showdown.subParser('anchors')(text, options, globals);// Make links out of things like `<http://example.com/>`// Must come after _DoAnchors(), because you can use < and >// delimiters in inline links like [this](<url>).text = showdown.subParser('autoLinks')(text, options, globals);text = showdown.subParser('encodeAmpsAndAngles')(text, options, globals);text = showdown.subParser('italicsAndBold')(text, options, globals);text = showdown.subParser('strikethrough')(text, options, globals);// Do hard breaks:text = text.replace(/  +\n/g, ' <br />\n');text = globals.converter._dispatch('spanGamut.after', text, options, globals);return text;
});showdown.subParser('strikethrough', function (text, options, globals) {'use strict';if (options.strikethrough) {text = globals.converter._dispatch('strikethrough.before', text, options, globals);text = text.replace(/(?:~T){2}([\s\S]+?)(?:~T){2}/g, '<del>$1</del>');text = globals.converter._dispatch('strikethrough.after', text, options, globals);}return text;
});/*** Strip any lines consisting only of spaces and tabs.* This makes subsequent regexs easier to write, because we can* match consecutive blank lines with /\n+/ instead of something* contorted like /[ \t]*\n+/*/
showdown.subParser('stripBlankLines', function (text) {'use strict';return text.replace(/^[ \t]+$/mg, '');
});/*** Strips link definitions from text, stores the URLs and titles in* hash references.* Link defs are in the form: ^[id]: url "optional title"** ^[ ]{0,3}\[(.+)\]: // id = $1  attacklab: g_tab_width - 1* [ \t]** \n?                  // maybe *one* newline* [ \t]** <?(\S+?)>?          // url = $2* [ \t]** \n?                // maybe one newline* [ \t]** (?:* (\n*)              // any lines skipped = $3 attacklab: lookbehind removed* ["(]* (.+?)              // title = $4* [")]* [ \t]** )?                 // title is optional* (?:\n+|$)* /gm,* function(){...});**/
showdown.subParser('stripLinkDefinitions', function (text, options, globals) {'use strict';var regex = /^ {0,3}\[(.+)]:[ \t]*\n?[ \t]*<?(\S+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n+|(?=~0))/gm;// attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bugtext += '~0';text = text.replace(regex, function (wholeMatch, linkId, url, width, height, blankLines, title) {linkId = linkId.toLowerCase();globals.gUrls[linkId] = showdown.subParser('encodeAmpsAndAngles')(url);  // Link IDs are case-insensitiveif (blankLines) {// Oops, found blank lines, so it's not a title.// Put back the parenthetical statement we stole.return blankLines + title;} else {if (title) {globals.gTitles[linkId] = title.replace(/"|'/g, '&quot;');}if (options.parseImgDimensions && width && height) {globals.gDimensions[linkId] = {width:  width,height: height};}}// Completely remove the definition from the textreturn '';});// attacklab: strip sentineltext = text.replace(/~0/, '');return text;
});showdown.subParser('tables', function (text, options, globals) {'use strict';if (!options.tables) {return text;}var tableRgx = /^[ \t]{0,3}\|?.+\|.+\n[ \t]{0,3}\|?[ \t]*:?[ \t]*(?:-|=){2,}[ \t]*:?[ \t]*\|[ \t]*:?[ \t]*(?:-|=){2,}[\s\S]+?(?:\n\n|~0)/gm;function parseStyles(sLine) {if (/^:[ \t]*--*$/.test(sLine)) {return ' style="text-align:left;"';} else if (/^--*[ \t]*:[ \t]*$/.test(sLine)) {return ' style="text-align:right;"';} else if (/^:[ \t]*--*[ \t]*:$/.test(sLine)) {return ' style="text-align:center;"';} else {return '';}}function parseHeaders(header, style) {var id = '';header = header.trim();if (options.tableHeaderId) {id = ' id="' + header.replace(/ /g, '_').toLowerCase() + '"';}header = showdown.subParser('spanGamut')(header, options, globals);return '<th' + id + style + '>' + header + '</th>\n';}function parseCells(cell, style) {var subText = showdown.subParser('spanGamut')(cell, options, globals);return '<td' + style + '>' + subText + '</td>\n';}function buildTable(headers, cells) {var tb = '<table>\n<thead>\n<tr>\n',tblLgn = headers.length;for (var i = 0; i < tblLgn; ++i) {tb += headers[i];}tb += '</tr>\n</thead>\n<tbody>\n';for (i = 0; i < cells.length; ++i) {tb += '<tr>\n';for (var ii = 0; ii < tblLgn; ++ii) {tb += cells[i][ii];}tb += '</tr>\n';}tb += '</tbody>\n</table>\n';return tb;}text = globals.converter._dispatch('tables.before', text, options, globals);text = text.replace(tableRgx, function (rawTable) {var i, tableLines = rawTable.split('\n');// strip wrong first and last column if wrapped tables are usedfor (i = 0; i < tableLines.length; ++i) {if (/^[ \t]{0,3}\|/.test(tableLines[i])) {tableLines[i] = tableLines[i].replace(/^[ \t]{0,3}\|/, '');}if (/\|[ \t]*$/.test(tableLines[i])) {tableLines[i] = tableLines[i].replace(/\|[ \t]*$/, '');}}var rawHeaders = tableLines[0].split('|').map(function (s) { return s.trim();}),rawStyles = tableLines[1].split('|').map(function (s) { return s.trim();}),rawCells = [],headers = [],styles = [],cells = [];tableLines.shift();tableLines.shift();for (i = 0; i < tableLines.length; ++i) {if (tableLines[i].trim() === '') {continue;}rawCells.push(tableLines[i].split('|').map(function (s) {return s.trim();}));}if (rawHeaders.length < rawStyles.length) {return rawTable;}for (i = 0; i < rawStyles.length; ++i) {styles.push(parseStyles(rawStyles[i]));}for (i = 0; i < rawHeaders.length; ++i) {if (showdown.helper.isUndefined(styles[i])) {styles[i] = '';}headers.push(parseHeaders(rawHeaders[i], styles[i]));}for (i = 0; i < rawCells.length; ++i) {var row = [];for (var ii = 0; ii < headers.length; ++ii) {if (showdown.helper.isUndefined(rawCells[i][ii])) {}row.push(parseCells(rawCells[i][ii], styles[ii]));}cells.push(row);}return buildTable(headers, cells);});text = globals.converter._dispatch('tables.after', text, options, globals);return text;
});/*** Swap back in all the special characters we've hidden.*/
showdown.subParser('unescapeSpecialChars', function (text) {'use strict';text = text.replace(/~E(\d+)E/g, function (wholeMatch, m1) {var charCodeToReplace = parseInt(m1);return String.fromCharCode(charCodeToReplace);});return text;
});
module.exports = showdown;

5、wxDiscode.js

// HTML 支持的数学符号
function strNumDiscode(str){str = str.replace(/&forall;/g, '∀');str = str.replace(/&part;/g, '∂');str = str.replace(/&exists;/g, '∃');str = str.replace(/&empty;/g, '∅');str = str.replace(/&nabla;/g, '∇');str = str.replace(/&isin;/g, '∈');str = str.replace(/&notin;/g, '∉');str = str.replace(/&ni;/g, '∋');str = str.replace(/&prod;/g, '∏');str = str.replace(/&sum;/g, '∑');str = str.replace(/&minus;/g, '−');str = str.replace(/&lowast;/g, '∗');str = str.replace(/&radic;/g, '√');str = str.replace(/&prop;/g, '∝');str = str.replace(/&infin;/g, '∞');str = str.replace(/&ang;/g, '∠');str = str.replace(/&and;/g, '∧');str = str.replace(/&or;/g, '∨');str = str.replace(/&cap;/g, '∩');str = str.replace(/&cap;/g, '∪');str = str.replace(/&int;/g, '∫');str = str.replace(/&there4;/g, '∴');str = str.replace(/&sim;/g, '∼');str = str.replace(/&cong;/g, '≅');str = str.replace(/&asymp;/g, '≈');str = str.replace(/&ne;/g, '≠');str = str.replace(/&le;/g, '≤');str = str.replace(/&ge;/g, '≥');str = str.replace(/&sub;/g, '⊂');str = str.replace(/&sup;/g, '⊃');str = str.replace(/&nsub;/g, '⊄');str = str.replace(/&sube;/g, '⊆');str = str.replace(/&supe;/g, '⊇');str = str.replace(/&oplus;/g, '⊕');str = str.replace(/&otimes;/g, '⊗');str = str.replace(/&perp;/g, '⊥');str = str.replace(/&sdot;/g, '⋅');return str;
}//HTML 支持的希腊字母
function strGreeceDiscode(str){str = str.replace(/&Alpha;/g, 'Α');str = str.replace(/&Beta;/g, 'Β');str = str.replace(/&Gamma;/g, 'Γ');str = str.replace(/&Delta;/g, 'Δ');str = str.replace(/&Epsilon;/g, 'Ε');str = str.replace(/&Zeta;/g, 'Ζ');str = str.replace(/&Eta;/g, 'Η');str = str.replace(/&Theta;/g, 'Θ');str = str.replace(/&Iota;/g, 'Ι');str = str.replace(/&Kappa;/g, 'Κ');str = str.replace(/&Lambda;/g, 'Λ');str = str.replace(/&Mu;/g, 'Μ');str = str.replace(/&Nu;/g, 'Ν');str = str.replace(/&Xi;/g, 'Ν');str = str.replace(/&Omicron;/g, 'Ο');str = str.replace(/&Pi;/g, 'Π');str = str.replace(/&Rho;/g, 'Ρ');str = str.replace(/&Sigma;/g, 'Σ');str = str.replace(/&Tau;/g, 'Τ');str = str.replace(/&Upsilon;/g, 'Υ');str = str.replace(/&Phi;/g, 'Φ');str = str.replace(/&Chi;/g, 'Χ');str = str.replace(/&Psi;/g, 'Ψ');str = str.replace(/&Omega;/g, 'Ω');str = str.replace(/&alpha;/g, 'α');str = str.replace(/&beta;/g, 'β');str = str.replace(/&gamma;/g, 'γ');str = str.replace(/&delta;/g, 'δ');str = str.replace(/&epsilon;/g, 'ε');str = str.replace(/&zeta;/g, 'ζ');str = str.replace(/&eta;/g, 'η');str = str.replace(/&theta;/g, 'θ');str = str.replace(/&iota;/g, 'ι');str = str.replace(/&kappa;/g, 'κ');str = str.replace(/&lambda;/g, 'λ');str = str.replace(/&mu;/g, 'μ');str = str.replace(/&nu;/g, 'ν');str = str.replace(/&xi;/g, 'ξ');str = str.replace(/&omicron;/g, 'ο');str = str.replace(/&pi;/g, 'π');str = str.replace(/&rho;/g, 'ρ');str = str.replace(/&sigmaf;/g, 'ς');str = str.replace(/&sigma;/g, 'σ');str = str.replace(/&tau;/g, 'τ');str = str.replace(/&upsilon;/g, 'υ');str = str.replace(/&phi;/g, 'φ');str = str.replace(/&chi;/g, 'χ');str = str.replace(/&psi;/g, 'ψ');str = str.replace(/&omega;/g, 'ω');str = str.replace(/&thetasym;/g, 'ϑ');str = str.replace(/&upsih;/g, 'ϒ');str = str.replace(/&piv;/g, 'ϖ');str = str.replace(/&middot;/g, '·');return str;
}// function strcharacterDiscode(str){// 加入常用解析str = str.replace(/&nbsp;/g, ' ');str = str.replace(/&quot;/g, "'");str = str.replace(/&amp;/g, '&');// str = str.replace(/&lt;/g, '‹');// str = str.replace(/&gt;/g, '›');str = str.replace(/&lt;/g, '<');str = str.replace(/&gt;/g, '>');str = str.replace(/&#8226;/g, '•');return str;
}// HTML 支持的其他实体
function strOtherDiscode(str){str = str.replace(/&OElig;/g, 'Œ');str = str.replace(/&oelig;/g, 'œ');str = str.replace(/&Scaron;/g, 'Š');str = str.replace(/&scaron;/g, 'š');str = str.replace(/&Yuml;/g, 'Ÿ');str = str.replace(/&fnof;/g, 'ƒ');str = str.replace(/&circ;/g, 'ˆ');str = str.replace(/&tilde;/g, '˜');str = str.replace(/&ensp;/g, '');str = str.replace(/&emsp;/g, '');str = str.replace(/&thinsp;/g, '');str = str.replace(/&zwnj;/g, '');str = str.replace(/&zwj;/g, '');str = str.replace(/&lrm;/g, '');str = str.replace(/&rlm;/g, '');str = str.replace(/&ndash;/g, '–');str = str.replace(/&mdash;/g, '—');str = str.replace(/&lsquo;/g, '‘');str = str.replace(/&rsquo;/g, '’');str = str.replace(/&sbquo;/g, '‚');str = str.replace(/&ldquo;/g, '“');str = str.replace(/&rdquo;/g, '”');str = str.replace(/&bdquo;/g, '„');str = str.replace(/&dagger;/g, '†');str = str.replace(/&Dagger;/g, '‡');str = str.replace(/&bull;/g, '•');str = str.replace(/&hellip;/g, '…');str = str.replace(/&permil;/g, '‰');str = str.replace(/&prime;/g, '′');str = str.replace(/&Prime;/g, '″');str = str.replace(/&lsaquo;/g, '‹');str = str.replace(/&rsaquo;/g, '›');str = str.replace(/&oline;/g, '‾');str = str.replace(/&euro;/g, '€');str = str.replace(/&trade;/g, '™');str = str.replace(/&larr;/g, '←');str = str.replace(/&uarr;/g, '↑');str = str.replace(/&rarr;/g, '→');str = str.replace(/&darr;/g, '↓');str = str.replace(/&harr;/g, '↔');str = str.replace(/&crarr;/g, '↵');str = str.replace(/&lceil;/g, '⌈');str = str.replace(/&rceil;/g, '⌉');str = str.replace(/&lfloor;/g, '⌊');str = str.replace(/&rfloor;/g, '⌋');str = str.replace(/&loz;/g, '◊');str = str.replace(/&spades;/g, '♠');str = str.replace(/&clubs;/g, '♣');str = str.replace(/&hearts;/g, '♥');str = str.replace(/&diams;/g, '♦');str = str.replace(/&#39;/g, '\'');return str;
}function strMoreDiscode(str){str = str.replace(/\r\n/g,"");  str = str.replace(/\n/g,"");str = str.replace(/code/g,"wxxxcode-style");return str;
}function strDiscode(str){str = strNumDiscode(str);str = strGreeceDiscode(str);str = strcharacterDiscode(str);str = strOtherDiscode(str);str = strMoreDiscode(str);return str;
}
function urlToHttpUrl(url,rep){var patt1 = new RegExp("^//");var result = patt1.test(url);if(result){url = rep+":"+url;}return  url;
}module.exports = {strDiscode:strDiscode,urlToHttpUrl:urlToHttpUrl
}

6、wxParse.js

/*** author: Di (微信小程序开发工程师)* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)*               垂直微信小程序开发交流社区* * github地址: https://github.com/icindy/wxParse* * for: 微信小程序富文本解析* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184*//*** utils函数引入**/
import showdown from './showdown.js';
import HtmlToJson from './html2json.js';
/*** 配置及公有属性**/
var realWindowWidth = 0;
var realWindowHeight = 0;
wx.getSystemInfo({success: function (res) {realWindowWidth = res.windowWidthrealWindowHeight = res.windowHeight}
})
/*** 主函数入口区**/
function wxParse(bindName = 'wxParseData', type='html', data='<div class="color:red;">数据不能为空</div>', target,imagePadding) {var that = target;var transData = {};//存放转化后的数据if (type == 'html') {transData = HtmlToJson.html2json(data, bindName);// console.log(JSON.stringify(transData, ' ', ' '));} else if (type == 'md' || type == 'markdown') {var converter = new showdown.Converter();var html = converter.makeHtml(data);transData = HtmlToJson.html2json(html, bindName);console.log(JSON.stringify(transData, ' ', ' '));}transData.view = {};transData.view.imagePadding = 0;if(typeof(imagePadding) != 'undefined'){transData.view.imagePadding = imagePadding}var bindData = {};bindData[bindName] = transData;that.setData(bindData)that.wxParseImgLoad = wxParseImgLoad;that.wxParseImgTap = wxParseImgTap;
}
// 图片点击事件
function wxParseImgTap(e) {var that = this;var nowImgUrl = e.target.dataset.src;var tagFrom = e.target.dataset.from;if (typeof (tagFrom) != 'undefined' && tagFrom.length > 0) {wx.previewImage({current: nowImgUrl, // 当前显示图片的http链接urls: that.data[tagFrom].imageUrls // 需要预览的图片http链接列表})}
}/*** 图片视觉宽高计算函数区 **/
function wxParseImgLoad(e) {var that = this;var tagFrom = e.target.dataset.from;var idx = e.target.dataset.idx;if (typeof (tagFrom) != 'undefined' && tagFrom.length > 0) {calMoreImageInfo(e, idx, that, tagFrom)}
}
// 假循环获取计算图片视觉最佳宽高
function calMoreImageInfo(e, idx, that, bindName) {var temData = that.data[bindName];if (!temData || temData.images.length == 0) {return;}var temImages = temData.images;//因为无法获取view宽度 需要自定义padding进行计算,稍后处理var recal = wxAutoImageCal(e.detail.width, e.detail.height,that,bindName); // temImages[idx].width = recal.imageWidth;// temImages[idx].height = recal.imageheight; // temData.images = temImages;// var bindData = {};// bindData[bindName] = temData;// that.setData(bindData);var index = temImages[idx].indexvar key = `${bindName}`for (var i of index.split('.')) key+=`.nodes[${i}]`var keyW = key + '.width'var keyH = key + '.height'that.setData({[keyW]: recal.imageWidth,[keyH]: recal.imageheight,})
}// 计算视觉优先的图片宽高
function wxAutoImageCal(originalWidth, originalHeight,that,bindName) {//获取图片的原始长宽var windowWidth = 0, windowHeight = 0;var autoWidth = 0, autoHeight = 0;var results = {};var padding = that.data[bindName].view.imagePadding;windowWidth = realWindowWidth-2*padding;windowHeight = realWindowHeight;//判断按照那种方式进行缩放// console.log("windowWidth" + windowWidth);if (originalWidth > windowWidth) {//在图片width大于手机屏幕width时候autoWidth = windowWidth;// console.log("autoWidth" + autoWidth);autoHeight = (autoWidth * originalHeight) / originalWidth;// console.log("autoHeight" + autoHeight);results.imageWidth = autoWidth;results.imageheight = autoHeight;} else {//否则展示原来的数据results.imageWidth = originalWidth;results.imageheight = originalHeight;}return results;
}function wxParseTemArray(temArrayName,bindNameReg,total,that){var array = [];var temData = that.data;var obj = null;for(var i = 0; i < total; i++){var simArr = temData[bindNameReg+i].nodes;array.push(simArr);}temArrayName = temArrayName || 'wxParseTemArray';obj = JSON.parse('{"'+ temArrayName +'":""}');obj[temArrayName] = array;that.setData(obj);
}/*** 配置emojis* */function emojisInit(reg='',baseSrc="/wxParse/emojis/",emojis){HtmlToJson.emojisInit(reg,baseSrc,emojis);
}module.exports = {wxParse: wxParse,wxParseTemArray:wxParseTemArray,emojisInit:emojisInit
}

7、wxParse.wxml

<!--*** author: Di (微信小程序开发工程师)* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)*               垂直微信小程序开发交流社区* * github地址: https://github.com/icindy/wxParse* * for: 微信小程序富文本解析* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184*/--><!--基础元素-->
<template name="wxParseVideo"><!--增加video标签支持,并循环添加--><view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"><video class="{{item.classStr}} wxParse-{{item.tag}}-video" src="{{item.attr.src}}"></video></view>
</template><template name="wxParseImg"><image class="{{item.classStr}} wxParse-{{item.tag}}" data-from="{{item.from}}" data-src="{{item.attr.src}}" data-idx="{{item.imgIndex}}" src="{{item.attr.src}}" mode="aspectFit" bindload="wxParseImgLoad" bindtap="wxParseImgTap" mode="widthFix" style="width:{{item.width}}px;"/>
</template><template name="WxEmojiView"><view class="WxEmojiView wxParse-inline" style="{{item.styleStr}}"><block wx:for="{{item.textArray}}" wx:key="id"><block class="{{item.text == '\\n' ? 'wxParse-hide':''}}" wx:if="{{item.node == 'text'}}">{{item.text}}</block><block wx:elif="{{item.node == 'element'}}"><image class="wxEmoji" src="{{item.baseSrc}}{{item.text}}" /></block></block></view>
</template><template name="WxParseBr"><text>\n</text>
</template>
<!--入口模版--><template name="wxParse"><block wx:for="{{wxParseData}}" wx:key="id"><template is="wxParse0" data="{{item}}" /></block>
</template><!--循环模版-->
<template name="wxParse0"><!--<template is="wxParse1" data="{{item}}" />--><!--判断是否是标签节点--><block wx:if="{{item.node == 'element'}}"><block wx:if="{{item.tag == 'button'}}"><button type="default" size="mini"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse1" data="{{item}}" /></block></button></block><!--li类型--><block wx:elif="{{item.tag == 'li'}}"><view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}"><view class="{{item.classStr}} wxParse-li-inner"><view class="{{item.classStr}} wxParse-li-text"><view class="{{item.classStr}} wxParse-li-circle"></view></view><view class="{{item.classStr}} wxParse-li-text"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse1" data="{{item}}" /></block></view></view></view></block><!--video类型--><block wx:elif="{{item.tag == 'video'}}"><template is="wxParseVideo" data="{{item}}" /></block><!--img类型--><block wx:elif="{{item.tag == 'img'}}"><template is="wxParseImg" data="{{item}}" /></block><!--a类型--><block wx:elif="{{item.tag == 'a'}}"><view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse1" data="{{item}}" /></block></view></block><block wx:elif="{{item.tag == 'table'}}"><view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse1" data="{{item}}" /></block></view></block><block wx:elif="{{item.tag == 'br'}}"><template is="WxParseBr"></template></block><!--其他块级标签--><block wx:elif="{{item.tagType == 'block'}}"><view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse1" data="{{item}}" /></block></view></block><!--内联标签--><view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse1" data="{{item}}" /></block></view></block><!--判断是否是文本节点--><block wx:elif="{{item.node == 'text'}}"><!--如果是,直接进行--><template is="WxEmojiView" data="{{item}}" /></block></template><!--循环模版-->
<template name="wxParse1"><!--<template is="wxParse2" data="{{item}}" />--><!--判断是否是标签节点--><block wx:if="{{item.node == 'element'}}"><block wx:if="{{item.tag == 'button'}}"><button type="default" size="mini"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse2" data="{{item}}" /></block></button></block><!--li类型--><block wx:elif="{{item.tag == 'li'}}"><view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}"><view class="{{item.classStr}} wxParse-li-inner"><view class="{{item.classStr}} wxParse-li-text"><view class="{{item.classStr}} wxParse-li-circle"></view></view><view class="{{item.classStr}} wxParse-li-text"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse2" data="{{item}}" /></block></view></view></view></block><!--video类型--><block wx:elif="{{item.tag == 'video'}}"><template is="wxParseVideo" data="{{item}}" /></block><!--img类型--><block wx:elif="{{item.tag == 'img'}}"><template is="wxParseImg" data="{{item}}" /></block><!--a类型--><block wx:elif="{{item.tag == 'a'}}"><view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse2" data="{{item}}" /></block></view></block><block wx:elif="{{item.tag == 'br'}}"><template is="WxParseBr"></template></block><!--其他块级标签--><block wx:elif="{{item.tagType == 'block'}}"><view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse2" data="{{item}}" /></block></view></block><!--内联标签--><view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse2" data="{{item}}" /></block></view></block><!--判断是否是文本节点--><block wx:elif="{{item.node == 'text'}}"><!--如果是,直接进行--><template is="WxEmojiView" data="{{item}}" /></block></template><!--循环模版-->
<template name="wxParse2"><!--<template is="wxParse3" data="{{item}}" />--><!--判断是否是标签节点--><block wx:if="{{item.node == 'element'}}"><block wx:if="{{item.tag == 'button'}}"><button type="default" size="mini"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse3" data="{{item}}" /></block></button></block><!--li类型--><block wx:elif="{{item.tag == 'li'}}"><view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}"><view class="{{item.classStr}} wxParse-li-inner"><view class="{{item.classStr}} wxParse-li-text"><view class="{{item.classStr}} wxParse-li-circle"></view></view><view class="{{item.classStr}} wxParse-li-text"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse3" data="{{item}}" /></block></view></view></view></block><!--video类型--><block wx:elif="{{item.tag == 'video'}}"><template is="wxParseVideo" data="{{item}}" /></block><!--img类型--><block wx:elif="{{item.tag == 'img'}}"><template is="wxParseImg" data="{{item}}" /></block><!--a类型--><block wx:elif="{{item.tag == 'a'}}"><view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse3" data="{{item}}" /></block></view></block><block wx:elif="{{item.tag == 'br'}}"><template is="WxParseBr"></template></block><!--其他块级标签--><block wx:elif="{{item.tagType == 'block'}}"><view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse3" data="{{item}}" /></block></view></block><!--内联标签--><view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse3" data="{{item}}" /></block></view></block><!--判断是否是文本节点--><block wx:elif="{{item.node == 'text'}}"><!--如果是,直接进行--><template is="WxEmojiView" data="{{item}}" /></block></template><!--循环模版-->
<template name="wxParse3"><!--<template is="wxParse4" data="{{item}}" />--><!--判断是否是标签节点--><block wx:if="{{item.node == 'element'}}"><block wx:if="{{item.tag == 'button'}}"><button type="default" size="mini"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse4" data="{{item}}" /></block></button></block><!--li类型--><block wx:elif="{{item.tag == 'li'}}"><view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}"><view class="{{item.classStr}} wxParse-li-inner"><view class="{{item.classStr}} wxParse-li-text"><view class="{{item.classStr}} wxParse-li-circle"></view></view><view class="{{item.classStr}} wxParse-li-text"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse4" data="{{item}}" /></block></view></view></view></block><!--video类型--><block wx:elif="{{item.tag == 'video'}}"><template is="wxParseVideo" data="{{item}}" /></block><!--img类型--><block wx:elif="{{item.tag == 'img'}}"><template is="wxParseImg" data="{{item}}" /></block><!--a类型--><block wx:elif="{{item.tag == 'a'}}"><view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse4" data="{{item}}" /></block></view></block><block wx:elif="{{item.tag == 'br'}}"><template is="WxParseBr"></template></block><!--其他块级标签--><block wx:elif="{{item.tagType == 'block'}}"><view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse4" data="{{item}}" /></block></view></block><!--内联标签--><view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse4" data="{{item}}" /></block></view></block><!--判断是否是文本节点--><block wx:elif="{{item.node == 'text'}}"><!--如果是,直接进行--><template is="WxEmojiView" data="{{item}}" /></block></template><!--循环模版-->
<template name="wxParse4"><!--<template is="wxParse5" data="{{item}}" />--><!--判断是否是标签节点--><block wx:if="{{item.node == 'element'}}"><block wx:if="{{item.tag == 'button'}}"><button type="default" size="mini"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse5" data="{{item}}" /></block></button></block><!--li类型--><block wx:elif="{{item.tag == 'li'}}"><view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}"><view class="{{item.classStr}} wxParse-li-inner"><view class="{{item.classStr}} wxParse-li-text"><view class="{{item.classStr}} wxParse-li-circle"></view></view><view class="{{item.classStr}} wxParse-li-text"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse5" data="{{item}}" /></block></view></view></view></block><!--video类型--><block wx:elif="{{item.tag == 'video'}}"><template is="wxParseVideo" data="{{item}}" /></block><!--img类型--><block wx:elif="{{item.tag == 'img'}}"><template is="wxParseImg" data="{{item}}" /></block><!--a类型--><block wx:elif="{{item.tag == 'a'}}"><view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse5" data="{{item}}" /></block></view></block><block wx:elif="{{item.tag == 'br'}}"><template is="WxParseBr"></template></block><!--其他块级标签--><block wx:elif="{{item.tagType == 'block'}}"><view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse5" data="{{item}}" /></block></view></block><!--内联标签--><view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse5" data="{{item}}" /></block></view></block><!--判断是否是文本节点--><block wx:elif="{{item.node == 'text'}}"><!--如果是,直接进行--><template is="WxEmojiView" data="{{item}}" /></block></template><!--循环模版-->
<template name="wxParse5"><!--<template is="wxParse6" data="{{item}}" />--><!--判断是否是标签节点--><block wx:if="{{item.node == 'element'}}"><block wx:if="{{item.tag == 'button'}}"><button type="default" size="mini"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""><template is="wxParse6" data="{{item}}" /></block></button></block><!--li类型--><block wx:elif="{{item.tag == 'li'}}"><view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}"><view class="{{item.classStr}} wxParse-li-inner"><view class="{{item.classStr}} wxParse-li-text"><view class="{{item.classStr}} wxParse-li-circle"></view></view><view class="{{item.classStr}} wxParse-li-text"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse6" data="{{item}}" /></block></view></view></view></block><!--video类型--><block wx:elif="{{item.tag == 'video'}}"><template is="wxParseVideo" data="{{item}}" /></block><!--img类型--><block wx:elif="{{item.tag == 'img'}}"><template is="wxParseImg" data="{{item}}" /></block><!--a类型--><block wx:elif="{{item.tag == 'a'}}"><view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse6" data="{{item}}" /></block></view></block><block wx:elif="{{item.tag == 'br'}}"><template is="WxParseBr"></template></block><!--其他块级标签--><block wx:elif="{{item.tagType == 'block'}}"><view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse6" data="{{item}}" /></block></view></block><!--内联标签--><view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse6" data="{{item}}" /></block></view></block><!--判断是否是文本节点--><block wx:elif="{{item.node == 'text'}}"><!--如果是,直接进行--><template is="WxEmojiView" data="{{item}}" /></block></template><!--循环模版-->
<template name="wxParse6"><!--<template is="wxParse7" data="{{item}}" />--><!--判断是否是标签节点--><block wx:if="{{item.node == 'element'}}"><block wx:if="{{item.tag == 'button'}}"><button type="default" size="mini"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse7" data="{{item}}" /></block></button></block><!--li类型--><block wx:elif="{{item.tag == 'li'}}"><view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}"><view class="{{item.classStr}} wxParse-li-inner"><view class="{{item.classStr}} wxParse-li-text"><view class="{{item.classStr}} wxParse-li-circle"></view></view><view class="{{item.classStr}} wxParse-li-text"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse7" data="{{item}}" /></block></view></view></view></block><!--video类型--><block wx:elif="{{item.tag == 'video'}}"><template is="wxParseVideo" data="{{item}}" /></block><!--img类型--><block wx:elif="{{item.tag == 'img'}}"><template is="wxParseImg" data="{{item}}" /></block><!--a类型--><block wx:elif="{{item.tag == 'a'}}"><view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse7" data="{{item}}" /></block></view></block><block wx:elif="{{item.tag == 'br'}}"><template is="WxParseBr"></template></block><!--其他块级标签--><block wx:elif="{{item.tagType == 'block'}}"><view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse7" data="{{item}}" /></block></view></block><!--内联标签--><view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse7" data="{{item}}" /></block></view></block><!--判断是否是文本节点--><block wx:elif="{{item.node == 'text'}}"><!--如果是,直接进行--><template is="WxEmojiView" data="{{item}}" /></block></template>
<!--循环模版-->
<template name="wxParse7"><!--<template is="wxParse8" data="{{item}}" />--><!--判断是否是标签节点--><block wx:if="{{item.node == 'element'}}"><block wx:if="{{item.tag == 'button'}}"><button type="default" size="mini"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse8" data="{{item}}" /></block></button></block><!--li类型--><block wx:elif="{{item.tag == 'li'}}"><view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}"><view class="{{item.classStr}} wxParse-li-inner"><view class="{{item.classStr}} wxParse-li-text"><view class="{{item.classStr}} wxParse-li-circle"></view></view><view class="{{item.classStr}} wxParse-li-text"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse8" data="{{item}}" /></block></view></view></view></block><!--video类型--><block wx:elif="{{item.tag == 'video'}}"><template is="wxParseVideo" data="{{item}}" /></block><!--img类型--><block wx:elif="{{item.tag == 'img'}}"><template is="wxParseImg" data="{{item}}" /></block><!--a类型--><block wx:elif="{{item.tag == 'a'}}"><view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse8" data="{{item}}" /></block></view></block><block wx:elif="{{item.tag == 'br'}}"><template is="WxParseBr"></template></block><!--其他块级标签--><block wx:elif="{{item.tagType == 'block'}}"><view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse8" data="{{item}}" /></block></view></block><!--内联标签--><view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse8" data="{{item}}" /></block></view></block><!--判断是否是文本节点--><block wx:elif="{{item.node == 'text'}}"><!--如果是,直接进行--><template is="WxEmojiView" data="{{item}}" /></block></template><!--循环模版-->
<template name="wxParse8"><!--<template is="wxParse9" data="{{item}}" />--><!--判断是否是标签节点--><block wx:if="{{item.node == 'element'}}"><block wx:if="{{item.tag == 'button'}}"><button type="default" size="mini"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse9" data="{{item}}" /></block></button></block><!--li类型--><block wx:elif="{{item.tag == 'li'}}"><view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}"><view class="{{item.classStr}} wxParse-li-inner"><view class="{{item.classStr}} wxParse-li-text"><view class="{{item.classStr}} wxParse-li-circle"></view></view><view class="{{item.classStr}} wxParse-li-text"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse9" data="{{item}}" /></block></view></view></view></block><!--video类型--><block wx:elif="{{item.tag == 'video'}}"><template is="wxParseVideo" data="{{item}}" /></block><!--img类型--><block wx:elif="{{item.tag == 'img'}}"><template is="wxParseImg" data="{{item}}" /></block><!--a类型--><block wx:elif="{{item.tag == 'a'}}"><view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse9" data="{{item}}" /></block></view></block><block wx:elif="{{item.tag == 'br'}}"><template is="WxParseBr"></template></block><!--其他块级标签--><block wx:elif="{{item.tagType == 'block'}}"><view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse9" data="{{item}}" /></block></view></block><!--内联标签--><view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse9" data="{{item}}" /></block></view></block><!--判断是否是文本节点--><block wx:elif="{{item.node == 'text'}}"><!--如果是,直接进行--><template is="WxEmojiView" data="{{item}}" /></block></template><!--循环模版-->
<template name="wxParse9"><!--<template is="wxParse10" data="{{item}}" />--><!--判断是否是标签节点--><block wx:if="{{item.node == 'element'}}"><block wx:if="{{item.tag == 'button'}}"><button type="default" size="mini"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse10" data="{{item}}" /></block></button></block><!--li类型--><block wx:elif="{{item.tag == 'li'}}"><view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}"><view class="{{item.classStr}} wxParse-li-inner"><view class="{{item.classStr}} wxParse-li-text"><view class="{{item.classStr}} wxParse-li-circle"></view></view><view class="{{item.classStr}} wxParse-li-text"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse10" data="{{item}}" /></block></view></view></view></block><!--video类型--><block wx:elif="{{item.tag == 'video'}}"><template is="wxParseVideo" data="{{item}}" /></block><!--img类型--><block wx:elif="{{item.tag == 'img'}}"><template is="wxParseImg" data="{{item}}" /></block><!--a类型--><block wx:elif="{{item.tag == 'a'}}"><view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse10" data="{{item}}" /></block></view></block><block wx:elif="{{item.tag == 'br'}}"><template is="WxParseBr"></template></block><!--其他块级标签--><block wx:elif="{{item.tagType == 'block'}}"><view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse10" data="{{item}}" /></block></view></block><!--内联标签--><view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse10" data="{{item}}" /></block></view></block><!--判断是否是文本节点--><block wx:elif="{{item.node == 'text'}}"><!--如果是,直接进行--><template is="WxEmojiView" data="{{item}}" /></block></template><!--循环模版-->
<template name="wxParse10"><!--<template is="wxParse11" data="{{item}}" />--><!--判断是否是标签节点--><block wx:if="{{item.node == 'element'}}"><block wx:if="{{item.tag == 'button'}}"><button type="default" size="mini"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse11" data="{{item}}" /></block></button></block><!--li类型--><block wx:elif="{{item.tag == 'li'}}"><view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}"><view class="{{item.classStr}} wxParse-li-inner"><view class="{{item.classStr}} wxParse-li-text"><view class="{{item.classStr}} wxParse-li-circle"></view></view><view class="{{item.classStr}} wxParse-li-text"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse11" data="{{item}}" /></block></view></view></view></block><!--video类型--><block wx:elif="{{item.tag == 'video'}}"><template is="wxParseVideo" data="{{item}}" /></block><!--img类型--><block wx:elif="{{item.tag == 'img'}}"><template is="wxParseImg" data="{{item}}" /></block><!--a类型--><block wx:elif="{{item.tag == 'a'}}"><view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse11" data="{{item}}" /></block></view></block><block wx:elif="{{item.tag == 'br'}}"><template is="WxParseBr"></template></block><!--其他块级标签--><block wx:elif="{{item.tagType == 'block'}}"><view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse11" data="{{item}}" /></block></view></block><!--内联标签--><view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse11" data="{{item}}" /></block></view></block><!--判断是否是文本节点--><block wx:elif="{{item.node == 'text'}}"><!--如果是,直接进行--><template is="WxEmojiView" data="{{item}}" /></block></template><!--循环模版-->
<template name="wxParse11"><!--<template is="wxParse12" data="{{item}}" />--><!--判断是否是标签节点--><block wx:if="{{item.node == 'element'}}"><block wx:if="{{item.tag == 'button'}}"><button type="default" size="mini"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse12" data="{{item}}" /></block></button></block><!--li类型--><block wx:elif="{{item.tag == 'li'}}"><view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}"><view class="{{item.classStr}} wxParse-li-inner"><view class="{{item.classStr}} wxParse-li-text"><view class="{{item.classStr}} wxParse-li-circle"></view></view><view class="{{item.classStr}} wxParse-li-text"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse12" data="{{item}}" /></block></view></view></view></block><!--video类型--><block wx:elif="{{item.tag == 'video'}}"><template is="wxParseVideo" data="{{item}}" /></block><!--img类型--><block wx:elif="{{item.tag == 'img'}}"><template is="wxParseImg" data="{{item}}" /></block><!--a类型--><block wx:elif="{{item.tag == 'a'}}"><view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse12" data="{{item}}" /></block></view></block><block wx:elif="{{item.tag == 'br'}}"><template is="WxParseBr"></template></block><!--其他块级标签--><block wx:elif="{{item.tagType == 'block'}}"><view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="id"><template is="wxParse12" data="{{item}}" /></block></view></block><!--内联标签--><view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}"><block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""><template is="wxParse12" data="{{item}}" /></block></view></block><!--判断是否是文本节点--><block wx:elif="{{item.node == 'text'}}"><!--如果是,直接进行--><template is="WxEmojiView" data="{{item}}" /></block></template>

8、wxParse.wxss


/*** author: Di (微信小程序开发工程师)* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)*               垂直微信小程序开发交流社区* * github地址: https://github.com/icindy/wxParse* * for: 微信小程序富文本解析* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184*/.wxParse{margin: 0 5px;font-family: Helvetica,sans-serif;font-size: 28rpx;color: #666;line-height: 1.8;
}
view{word-break:break-all; overflow:auto;
}
.wxParse-inline{display: inline;margin: 0;padding: 0;
}
/*//标题 */
.wxParse-div{margin: 0;padding: 0;}
.wxParse-h1{ font-size:2em; margin: .67em 0 }
.wxParse-h2{ font-size:1.5em; margin: .75em 0 }
.wxParse-h3{ font-size:1.17em; margin: .83em 0 }
.wxParse-h4{ margin: 1.12em 0}
.wxParse-h5 { font-size:.83em; margin: 1.5em 0 }
.wxParse-h6{ font-size:.75em; margin: 1.67em 0 }.wxParse-h1 {font-size: 18px;font-weight: 400;margin-bottom: .9em;
}
.wxParse-h2 {font-size: 16px;font-weight: 400;margin-bottom: .34em;
}
.wxParse-h3 {font-weight: 400;font-size: 15px;margin-bottom: .34em;
}
.wxParse-h4 {font-weight: 400;font-size: 14px;margin-bottom: .24em;
}
.wxParse-h5 {font-weight: 400;font-size: 13px;margin-bottom: .14em;
}
.wxParse-h6 {font-weight: 400;font-size: 12px;margin-bottom: .04em;
}.wxParse-h1, .wxParse-h2, .wxParse-h3, .wxParse-h4, .wxParse-h5, .wxParse-h6, .wxParse-b, .wxParse-strong  { font-weight: bolder }.wxParse-i,.wxParse-cite,.wxParse-em,.wxParse-var,.wxParse-address{font-style:italic}
.wxParse-pre,.wxParse-tt,.wxParse-code,.wxParse-kbd,.wxParse-samp{font-family:monospace}
.wxParse-pre{white-space:pre}
.wxParse-big{font-size:1.17em}
.wxParse-small,.wxParse-sub,.wxParse-sup{font-size:.83em}
.wxParse-sub{vertical-align:sub}
.wxParse-sup{vertical-align:super}
.wxParse-s,.wxParse-strike,.wxParse-del{text-decoration:line-through}
/*wxparse-自定义个性化的css样式*/
/*增加video的css样式*/
.wxParse-strong,.wxParse-s{display: inline}
.wxParse-a{color: deepskyblue;word-break:break-all;overflow:auto;
}.wxParse-video{text-align: center;margin: 10px 0;
}.wxParse-video-video{width:100%;
}.wxParse-img{/*background-color: #efefef;*/overflow: hidden;
}.wxParse-blockquote {margin: 0;padding:10px 0 10px 5px;font-family:Courier, Calibri,"宋体";background:#f5f5f5;border-left: 3px solid #dbdbdb;
}.wxParse-code,.wxParse-wxxxcode-style{display: inline;background:#f5f5f5;
}
.wxParse-ul{margin: 20rpx 10rpx;
}.wxParse-li,.wxParse-li-inner{display: flex;align-items: baseline;margin: 10rpx 0;
}
.wxParse-li-text{align-items: center;line-height: 20px;
}.wxParse-li-circle{display: inline-flex;width: 5px;height: 5px;background-color: #333;margin-right: 5px;
}.wxParse-li-square{display: inline-flex;width: 10rpx;height: 10rpx;background-color: #333;margin-right: 5px;
}
.wxParse-li-ring{display: inline-flex;width: 10rpx;height: 10rpx;border: 2rpx solid #333;border-radius: 50%;background-color: #fff;margin-right: 5px;
}/*.wxParse-table{width: 100%;height: 400px;
}
.wxParse-thead,.wxParse-tfoot,.wxParse-tr{display: flex;flex-direction: row;
}
.wxParse-th,.wxParse-td{display: flex;width: 580px;overflow: auto;
}*/.wxParse-u {text-decoration: underline;
}
.wxParse-hide{display: none;
}
.WxEmojiView{align-items: center;
}
.wxEmoji{width: 16px;height:16px;
}
.wxParse-tr{display: flex;border-right:1px solid #e0e0e0;border-bottom:1px solid #e0e0e0;border-top:1px solid #e0e0e0;
}
.wxParse-th,
.wxParse-td{flex:1;padding:5px;font-size:28rpx;border-left:1px solid #e0e0e0;word-break: break-all;
}
.wxParse-td:last{border-top:1px solid #e0e0e0;
}
.wxParse-th{background:#f0f0f0;border-top:1px solid #e0e0e0;
}
.wxParse-del{display: inline;
}
.wxParse-figure {overflow: hidden;
}

9、在引入的界面还要分别引入

var WxParse = require('../../wxParse/wxParse')
@import "../../wxParse/wxParse.wxss";
<import src="../../wxParse/wxParse.wxml"/>

10、在对应文件的js里

WxParse.wxParse('parameter', 'html', this.data.parameter, this)

parameter: 字段名

‘html’ 固定

thia.data.parameter 需要转化的内容

this 固定

11、在对应文件的wxml里

 <template style="float:left" is="wxParse" data="{{ wxParseData:parameter.nodes }}"></template>

nodes 固定

template 只能用这个标签

is="wxParse" 固定滴

微信小程序富文本编辑器获取内容相关推荐

  1. 微信小程序 富文本编辑器组件 editor

    微信小程序 富文本编辑器组件 editor <view class="container"><view class="titlebox"> ...

  2. 微信小程序富文本编辑器editor初体验-图片上传

    https://developers.weixin.qq.com/miniprogram/dev/component/editor.html 以前没有小程序富文本编辑器,只能输入文字,图片上传后,在服 ...

  3. 小程序开发笔记(二):微信小程序富文本编辑器editor的使用

      小程序在去年5月的 v2.7.0 版本新增了组件editor富文本编辑器,但对于像我这种开发新手,要熟练使用还是有一定难度.所以记录一下我的学习过程,希望对大家有帮助.   小程序有详细的微信开发 ...

  4. 【愚公系列】2022年03月 微信小程序-富文本编辑器

    文章目录 前言 一.富文本编辑器的使用 1.富文本编辑器属性 2.富文本编辑器使用 3.实际效果 前言 富文本编辑器,可以对图片.文字进行编辑. 编辑器导出内容支持带标签的 html和纯文本的 tex ...

  5. 关于微信小程序富文本编辑器回显数据初始化editor的时候,页面滑动到最底部了

    ** 一个页面高度超出一屏时,底部使用了富文本编辑器组件editor之后,如果在进入页面时对editor进行了赋值,页面会滚动到底部 控制页面不滚动到底部?** 这个问题的关键是进入页面给富文本赋值造 ...

  6. uniapp微信小程序富文本编辑器组件

    前言 最近需要实现一个微信小程序的富文本编辑器,由于使用的是uniapp框架开发的小程序,因此就改造了一下微信小程序官方案例,并封装成了一个组件. uniapp-editor gitee仓库 实现效果 ...

  7. 微信小程序富文本编辑器editor+rich-text(附源码)

    之前小程序一直都是使用自己写的接口,小程序远程获取使用富文本编辑器的内容,比如UEditor,wangEditor等.我们可以选择插件wxparse和自带的rich-text,但是这些并不能完全转义他 ...

  8. 小程序(二十五)微信小程序富文本编辑器editor上传图片

    官方给出的示例代码中图片上传功能是将图片上传至小程序的缓存中,代码如下所示: insertImage(e) {console.log(e);const that = thiswx.chooseImag ...

  9. 使用微信小程序 富文本编辑器组件 editor

    先看下官方文档 https://developers.weixin.qq.com/miniprogram/dev/component/editor.html 富文本组件文档 文档上的代码比较少建议在开 ...

最新文章

  1. 2018-2019-2 20165315 《网络对抗技术》Exp2+ 后门进阶
  2. HPC China2016全国高性能计算学术年会即将举行
  3. 电脑文件系统的管理总结
  4. mysql字符集修改保存_mysql更改已有数据表的字符集,保留原有数据内容
  5. 如何实现按钮水平居中
  6. swagger中参数为数组dataType的设置
  7. javaScript的Math和Date对象
  8. paip.java 多线程参数以及返回值Future FutureTask 的使用.
  9. IE7pro v0.9.8已经发布(已经有中文包)
  10. 系统集成项目管理工程师思维导图
  11. Tabular Editor学习笔记_3:警告标志及解决办法
  12. Tomcat安装步骤及详细配置教程(2022最新版)
  13. Scrapy框架:Request和Response对象,使用Request发送get请求、FormRequest发送post请求
  14. ios兼容iphonex刘海屏解决方案
  15. SQL语法之PRIMARY KEY 约束
  16. MySQL8免安装版下载安装与配置(windows)
  17. 闲人闲谈PS之三十二——业务工程预算和PS成本计划
  18. e讯丨美国政府问责局(GAO)发布网安审计报告 提出美应对网安挑战的十条行动
  19. ERP销售人员快速上手
  20. CSDN 写博客 word文档复制粘贴 图片粘贴 加载失败问题解决

热门文章

  1. 计算机毕业设计JavaWeb美食网站设计(源码+系统+mysql数据库+lw文档)
  2. 罗技k380键盘-数字键上的字符对不上怎么办?
  3. 小猿圈python之python期末考试测试题(二)_小猿圈Python开发面试题(一)
  4. windows11文件夹共享设置 如何共享 如何访问
  5. java实现记账本功能_java基础实战项目一:实现家庭记账本的简易记账功能
  6. C语言学习(2):enum枚举时出现的问题:
  7. 全国青少年编程等级考试scratch三级真题2021年9月(含题库答题软件账号)
  8. swing hacks_这些firefox hacks和扩展程序增强了您的隐私
  9. 武田以3.22亿美元剥离中国大陆非核心业务至海森
  10. 阿里云专有网络VPC学习笔记