赞
踩
里面的结构是这样:wxParse :{
emojis (文件夹)
html2json.js (文件)
htmlparser.js(文件)
showdown.js (文件)
wxDiscode.js(文件)
wxParse.js (文件)
wxParse.wxml(文件)
wxParse.wxss(文件)
}
- /**
- * 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 element
- var 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 attribute
- if (name == 'style') {
- console.dir(value);
- // value = value.join("")
- node.styleStr = value;
- }
- if (value.match(/ /)) {
- value = value.split(' ');
- }
-
-
- // if attr already exists
- // merge it
- if (pre[name]) {
- if (Array.isArray(pre[name])) {
- // already array, push to last
- pre[name].push(value);
- } else {
- // single value, make it array
- pre[name] = [pre[name], value];
- }
- } else {
- // not exist, put it
- pre[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 parents
- var 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 tag
- var 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 += 1
- results.nodes.push(node);
- } else {
- var parent = bufArray[0];
- if (parent.nodes === undefined) {
- parent.nodes = [];
- }
- node.index = parent.index + '.' + parent.nodes.length
- parent.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
- };
-

- /**
- *
- * 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 element
- if (!stack.last() || !special[stack.last()]) {
-
- // Comment
- if (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 tags
- parseEndTag();
-
- 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 shop
- if (!tagName)
- var pos = 0;
-
- // Find the closest opened tag of the same type
- else {
- 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 stack
- for (var i = stack.length - 1; i >= pos; i--)
- if (handler.end)
- handler.end(stack[i]);
-
- // Remove the open elements from the stack
- stack.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;

- /**
- *
- * 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);
-
- // Getter
- if (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 function
- if (typeof ext === 'function') {
- ext = ext();
- }
-
- // Ensure extension is an array
- if (!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 type
- if (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 them
- var 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 options
- if (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 loaded
- if (showdown.helper.isString(ext)) {
- ext = showdown.helper.stdExtName(ext);
- name = ext;
-
- // LEGACY_SUPPORT CODE
- if (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 here
- throw 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 falsy
- if (!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 string
- text = text.replace(/\$/g, '~D');
-
- // Standardize line endings
- text = text.replace(/\r\n/g, '\n'); // DOS to Unix
- text = text.replace(/\r/g, '\n'); // Mac to Unix
-
- if (options.smartIndentationFix) {
- text = rTrimInputText(text);
- }
-
- // Make sure text begins and ends with a couple of newlines:
- //text = '\n\n' + text + '\n\n';
- text = text;
- // detab
- text = showdown.subParser('detab')(text, options, globals);
-
- // stripBlankLines
- text = showdown.subParser('stripBlankLines')(text, options, globals);
-
- //run languageExtensions
- showdown.helper.forEach(langExtensions, function (ext) {
- text = showdown.subParser('runExtension')(ext, text, options, globals);
- });
-
- // run the sub parsers
- text = 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 signs
- text = text.replace(/~D/g, '$$');
-
- // attacklab: Restore tildes
- text = text.replace(/~T/g, '~');
-
- // Run output modifiers
- showdown.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 spaces
- linkId = 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 url
- url = '';
- } else {
- return wholeMatch;
- }
- }
- }
-
- url = showdown.helper.escapeCharacters(url, '*_', false);
- var result = '<a href="' + url + '"';
-
- if (title !== '' && title !== null) {
- title = title.replace(/"/g, '"');
- 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 blockquotes
- text = 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 hack
- bq = bq.replace(/~0/g, '');
-
- bq = bq.replace(/^[ \t]+$/gm, ''); // trim whitespace-only lines
- bq = showdown.subParser('githubCodeBlocks')(bq, options, globals);
- bq = showdown.subParser('blockGamut')(bq, options, globals); // recurse
-
- bq = 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 bug
- text += '~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 newlines
- codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing newlines
-
- if (options.omitExtraWLInCodeBlocks) {
- end = '';
- }
-
- codeblock = '<pre><code>' + codeblock + end + '</code></pre>';
-
- return showdown.subParser('hashBlock')(codeblock, options, globals) + nextChar;
- });
-
- // attacklab: strip sentinel
- text = 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 whitespace
- c = c.replace(/[ \t]*$/g, ''); // trailing whitespace
- c = 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 tabs
- text = text.replace(/\t(?=\t)/g, ' '); // g_tab_width
-
- // replace the nth with two sentinels
- text = text.replace(/\t/g, '~A~B');
-
- // use the sentinel to anchor our regex so it doesn't explode
- text = 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 sentinels
- text = text.replace(/~A/g, ' '); // g_tab_width
- text = 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, '&');
-
- // Encode naked <'s
- text = text.replace(/<(?![a-z\/?\$!])/gi, '<');
-
- 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, '&');
-
- // Do the angle bracket song and dance:
- text = text.replace(/</g, '<');
- text = text.replace(/>/g, '>');
-
- // 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="mailto:foo@e
- * xample.com">foo
- * @example.com</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% dec
- ch = (
- 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 part
-
- return 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 enabled
- if (!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 block
- codeblock = showdown.subParser('encodeCode')(codeblock);
- codeblock = showdown.subParser('detab')(codeblock);
- codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines
- codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing whitespace
-
- codeblock = '<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 token
- return '\n\n~G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\n\n';
- });
-
- // attacklab: strip sentinel
- text = 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 lines
- blockText = blockText.replace(/\n\n/g, '\n');
- blockText = blockText.replace(/^\n/, '');
-
- // strip trailing blank lines
- blockText = 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 markdown
- if (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 CASE
- text = 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 entities
- var 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 spaces
- linkId = 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, '"');
- 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, '"');
- 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: 
- 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 it
- text = 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>');
- //asterisks
- text = 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 \z
- listStr += '~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 tasklists
- if (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 sublist
- if (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 sentinel
- listStr = 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 versa
- var 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) {
- // slice
- result += '\n\n<' + listType + '>' + processListItems(txt.slice(0, pos), !!trimTrailing) + '</' + listType + '>\n\n';
-
- // invert counterType and listType
- listType = (listType === 'ul') ? 'ol' : 'ul';
- counterRxg = (listType === 'ul') ? /^ {0,2}\d+\.[ \t]/gm : /^ {0,2}[*+-][ \t]/gm;
-
- //recurse
- parseCL(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=11231
- text += '~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 sentinel
- text = 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 hack
- text = 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> tags
-
- for (var i = 0; i < end; i++) {
- var str = grafs[i];
- // if this is an HTML marker, copy it
- if (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 positive
- if (codeFlag) {
- // use encoded version of all text
- blockText = showdown.subParser('encodeCode')(globals.ghCodeBlocks[num].text);
- } else {
- blockText = globals.ghCodeBlocks[num].codeblock;
- }
- }
- blockText = blockText.replace(/\$/g, '$$$$'); // Escape any dollar signs
-
- grafsOutIt = grafsOutIt.replace(/(\n\n)?~(K|G)\d+\2(\n\n)?/, blockText);
- // Check if grafsOutIt is a pre->code
- if (/^<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 deprecated
- var 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 bug
- text += '~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-insensitive
-
- if (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, '"');
- }
- if (options.parseImgDimensions && width && height) {
- globals.gDimensions[linkId] = {
- width: width,
- height: height
- };
- }
- }
- // Completely remove the definition from the text
- return '';
- });
-
- // attacklab: strip sentinel
- text = 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 used
- for (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;

- // HTML 支持的数学符号
- function strNumDiscode(str){
- str = str.replace(/∀/g, '∀');
- str = str.replace(/∂/g, '∂');
- str = str.replace(/&exists;/g, '∃');
- str = str.replace(/∅/g, '∅');
- str = str.replace(/∇/g, '∇');
- str = str.replace(/∈/g, '∈');
- str = str.replace(/∉/g, '∉');
- str = str.replace(/∋/g, '∋');
- str = str.replace(/∏/g, '∏');
- str = str.replace(/∑/g, '∑');
- str = str.replace(/−/g, '−');
- str = str.replace(/∗/g, '∗');
- str = str.replace(/√/g, '√');
- str = str.replace(/∝/g, '∝');
- str = str.replace(/∞/g, '∞');
- str = str.replace(/∠/g, '∠');
- str = str.replace(/∧/g, '∧');
- str = str.replace(/∨/g, '∨');
- str = str.replace(/∩/g, '∩');
- str = str.replace(/∩/g, '∪');
- str = str.replace(/∫/g, '∫');
- str = str.replace(/∴/g, '∴');
- str = str.replace(/∼/g, '∼');
- str = str.replace(/≅/g, '≅');
- str = str.replace(/≈/g, '≈');
- str = str.replace(/≠/g, '≠');
- str = str.replace(/≤/g, '≤');
- str = str.replace(/≥/g, '≥');
- str = str.replace(/⊂/g, '⊂');
- str = str.replace(/⊃/g, '⊃');
- str = str.replace(/⊄/g, '⊄');
- str = str.replace(/⊆/g, '⊆');
- str = str.replace(/⊇/g, '⊇');
- str = str.replace(/⊕/g, '⊕');
- str = str.replace(/⊗/g, '⊗');
- str = str.replace(/⊥/g, '⊥');
- str = str.replace(/⋅/g, '⋅');
- return str;
- }
-
- //HTML 支持的希腊字母
- function strGreeceDiscode(str){
- str = str.replace(/Α/g, 'Α');
- str = str.replace(/Β/g, 'Β');
- str = str.replace(/Γ/g, 'Γ');
- str = str.replace(/Δ/g, 'Δ');
- str = str.replace(/Ε/g, 'Ε');
- str = str.replace(/Ζ/g, 'Ζ');
- str = str.replace(/Η/g, 'Η');
- str = str.replace(/Θ/g, 'Θ');
- str = str.replace(/Ι/g, 'Ι');
- str = str.replace(/Κ/g, 'Κ');
- str = str.replace(/Λ/g, 'Λ');
- str = str.replace(/Μ/g, 'Μ');
- str = str.replace(/Ν/g, 'Ν');
- str = str.replace(/Ξ/g, 'Ν');
- str = str.replace(/Ο/g, 'Ο');
- str = str.replace(/Π/g, 'Π');
- str = str.replace(/Ρ/g, 'Ρ');
- str = str.replace(/Σ/g, 'Σ');
- str = str.replace(/Τ/g, 'Τ');
- str = str.replace(/Υ/g, 'Υ');
- str = str.replace(/Φ/g, 'Φ');
- str = str.replace(/Χ/g, 'Χ');
- str = str.replace(/Ψ/g, 'Ψ');
- str = str.replace(/Ω/g, 'Ω');
-
- str = str.replace(/α/g, 'α');
- str = str.replace(/β/g, 'β');
- str = str.replace(/γ/g, 'γ');
- str = str.replace(/δ/g, 'δ');
- str = str.replace(/ε/g, 'ε');
- str = str.replace(/ζ/g, 'ζ');
- str = str.replace(/η/g, 'η');
- str = str.replace(/θ/g, 'θ');
- str = str.replace(/ι/g, 'ι');
- str = str.replace(/κ/g, 'κ');
- str = str.replace(/λ/g, 'λ');
- str = str.replace(/μ/g, 'μ');
- str = str.replace(/ν/g, 'ν');
- str = str.replace(/ξ/g, 'ξ');
- str = str.replace(/ο/g, 'ο');
- str = str.replace(/π/g, 'π');
- str = str.replace(/ρ/g, 'ρ');
- str = str.replace(/ς/g, 'ς');
- str = str.replace(/σ/g, 'σ');
- str = str.replace(/τ/g, 'τ');
- str = str.replace(/υ/g, 'υ');
- str = str.replace(/φ/g, 'φ');
- str = str.replace(/χ/g, 'χ');
- str = str.replace(/ψ/g, 'ψ');
- str = str.replace(/ω/g, 'ω');
- str = str.replace(/ϑ/g, 'ϑ');
- str = str.replace(/ϒ/g, 'ϒ');
- str = str.replace(/ϖ/g, 'ϖ');
- str = str.replace(/·/g, '·');
- return str;
- }
-
- //
-
- function strcharacterDiscode(str){
- // 加入常用解析
- str = str.replace(/ /g, ' ');
- str = str.replace(/"/g, "'");
- str = str.replace(/&/g, '&');
- // str = str.replace(/</g, '‹');
- // str = str.replace(/>/g, '›');
-
- str = str.replace(/</g, '<');
- str = str.replace(/>/g, '>');
- str = str.replace(/•/g, '•');
-
- return str;
- }
-
- // HTML 支持的其他实体
- function strOtherDiscode(str){
- str = str.replace(/Œ/g, 'Œ');
- str = str.replace(/œ/g, 'œ');
- str = str.replace(/Š/g, 'Š');
- str = str.replace(/š/g, 'š');
- str = str.replace(/Ÿ/g, 'Ÿ');
- str = str.replace(/ƒ/g, 'ƒ');
- str = str.replace(/ˆ/g, 'ˆ');
- str = str.replace(/˜/g, '˜');
- str = str.replace(/ /g, '');
- str = str.replace(/ /g, '');
- str = str.replace(/ /g, '');
- str = str.replace(/‌/g, '');
- str = str.replace(/‍/g, '');
- str = str.replace(/‎/g, '');
- str = str.replace(/‏/g, '');
- str = str.replace(/–/g, '–');
- str = str.replace(/—/g, '—');
- str = str.replace(/‘/g, '‘');
- str = str.replace(/’/g, '’');
- str = str.replace(/‚/g, '‚');
- str = str.replace(/“/g, '“');
- str = str.replace(/”/g, '”');
- str = str.replace(/„/g, '„');
- str = str.replace(/†/g, '†');
- str = str.replace(/‡/g, '‡');
- str = str.replace(/•/g, '•');
- str = str.replace(/…/g, '…');
- str = str.replace(/‰/g, '‰');
- str = str.replace(/′/g, '′');
- str = str.replace(/″/g, '″');
- str = str.replace(/‹/g, '‹');
- str = str.replace(/›/g, '›');
- str = str.replace(/‾/g, '‾');
- str = str.replace(/€/g, '€');
- str = str.replace(/™/g, '™');
-
- str = str.replace(/←/g, '←');
- str = str.replace(/↑/g, '↑');
- str = str.replace(/→/g, '→');
- str = str.replace(/↓/g, '↓');
- str = str.replace(/↔/g, '↔');
- str = str.replace(/↵/g, '↵');
- str = str.replace(/⌈/g, '⌈');
- str = str.replace(/⌉/g, '⌉');
-
- str = str.replace(/⌊/g, '⌊');
- str = str.replace(/⌋/g, '⌋');
- str = str.replace(/◊/g, '◊');
- str = str.replace(/♠/g, '♠');
- str = str.replace(/♣/g, '♣');
- str = str.replace(/♥/g, '♥');
-
- str = str.replace(/♦/g, '♦');
- str = str.replace(/'/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
- }

- /**
- * 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.windowWidth
- realWindowHeight = 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].index
- var 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
- }
-
-

- <!--**
- * 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>

-
- /**
- * 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;
- }

var WxParse = require('../../wxParse/wxParse')
@import "../../wxParse/wxParse.wxss";
<import src="../../wxParse/wxParse.wxml"/>
WxParse.wxParse('parameter', 'html', this.data.parameter, this)
parameter: 字段名
‘html’ 固定
thia.data.parameter 需要转化的内容
this 固定
<template style="float:left" is="wxParse" data="{{ wxParseData:parameter.nodes }}"></template>
nodes 固定
template 只能用这个标签
is="wxParse" 固定滴
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。