作者 吴孟雨

commit

1 -var _createClass=function(){function a(e,c){for(var b=0;b<c.length;b++){var d=c[b];d.enumerable=d.enumerable||false;d.configurable=true;if("value" in d){d.writable=true}Object.defineProperty(e,d.key,d)}}return function(d,b,c){if(b){a(d.prototype,b)}if(c){a(d,c)}return d}}();function _classCallCheck(a,b){if(!(a instanceof b)){throw new TypeError("Cannot call a class as a function")}}var ERROR_CONF={KEY_ERR:311,KEY_ERR_MSG:"key格式错误",PARAM_ERR:310,PARAM_ERR_MSG:"请求参数信息有误",SYSTEM_ERR:600,SYSTEM_ERR_MSG:"系统错误",WX_ERR_CODE:1000,WX_OK_CODE:200};var BASE_URL="https://apis.map.qq.com/ws/";var URL_SEARCH=BASE_URL+"place/v1/search";var URL_SUGGESTION=BASE_URL+"place/v1/suggestion";var URL_GET_GEOCODER=BASE_URL+"geocoder/v1/";var URL_CITY_LIST=BASE_URL+"district/v1/list";var URL_AREA_LIST=BASE_URL+"district/v1/getchildren";var URL_DISTANCE=BASE_URL+"distance/v1/";var Utils={location2query:function location2query(c){if(typeof c=="string"){return c}var b="";for(var a=0;a<c.length;a++){var e=c[a];if(!!b){b+=";"}if(e.location){b=b+e.location.lat+","+e.location.lng}if(e.latitude&&e.longitude){b=b+e.latitude+","+e.longitude}}return b},getWXLocation:function getWXLocation(c,b,a){wx.getLocation({type:"gcj02",success:c,fail:b,complete:a})},getLocationParam:function getLocationParam(b){if(typeof b=="string"){var a=b.split(",");if(a.length===2){b={latitude:b.split(",")[0],longitude:b.split(",")[1]}}else{b={}}}return b},polyfillParam:function polyfillParam(a){a.success=a.success||function(){};a.fail=a.fail||function(){};a.complete=a.complete||function(){}},checkParamKeyEmpty:function checkParamKeyEmpty(c,b){if(!c[b]){var a=this.buildErrorConfig(ERROR_CONF.PARAM_ERR,ERROR_CONF.PARAM_ERR_MSG+b+"参数格式有误");c.fail(a);c.complete(a);return true}return false},checkKeyword:function checkKeyword(a){return !this.checkParamKeyEmpty(a,"keyword")},checkLocation:function checkLocation(c){var a=this.getLocationParam(c.location);if(!a||!a.latitude||!a.longitude){var b=this.buildErrorConfig(ERROR_CONF.PARAM_ERR,ERROR_CONF.PARAM_ERR_MSG+" location参数格式有误");c.fail(b);c.complete(b);return false}return true},buildErrorConfig:function buildErrorConfig(a,b){return{status:a,message:b}},buildWxRequestConfig:function buildWxRequestConfig(c,a){var b=this;a.header={"content-type":"application/json"};a.method="GET";a.success=function(d){var e=d.data;if(e.status===0){c.success(e)}else{c.fail(e)}};a.fail=function(d){d.statusCode=ERROR_CONF.WX_ERR_CODE;c.fail(b.buildErrorConfig(ERROR_CONF.WX_ERR_CODE,result.errMsg))};a.complete=function(d){var e=+d.statusCode;switch(e){case ERROR_CONF.WX_ERR_CODE:c.complete(b.buildErrorConfig(ERROR_CONF.WX_ERR_CODE,d.errMsg));break;case ERROR_CONF.WX_OK_CODE:var f=d.data;if(f.status===0){c.complete(f)}else{c.complete(b.buildErrorConfig(f.status,f.message))}break;default:c.complete(b.buildErrorConfig(ERROR_CONF.SYSTEM_ERR,ERROR_CONF.SYSTEM_ERR_MSG))}};return a},locationProcess:function locationProcess(f,e,c,a){var d=this;c=c||function(g){g.statusCode=ERROR_CONF.WX_ERR_CODE;f.fail(d.buildErrorConfig(ERROR_CONF.WX_ERR_CODE,g.errMsg))};a=a||function(g){if(g.statusCode==ERROR_CONF.WX_ERR_CODE){f.complete(d.buildErrorConfig(ERROR_CONF.WX_ERR_CODE,g.errMsg))}};if(!f.location){d.getWXLocation(e,c,a)}else{if(d.checkLocation(f)){var b=Utils.getLocationParam(f.location);e(b)}}}};var QQMapWX=function(){function b(i){_classCallCheck(this,b);if(!i.key){throw Error("key值不能为空")}this.key=i.key}_createClass(b,[{key:"search",value:function f(i){var l=this;i=i||{};Utils.polyfillParam(i);if(!Utils.checkKeyword(i)){return}var k={keyword:i.keyword,orderby:i.orderby||"_distance",page_size:i.page_size||10,page_index:i.page_index||1,output:"json",key:l.key};if(i.address_format){k.address_format=i.address_format}if(i.filter){k.filter=i.filter}var n=i.distance||"1000";var j=i.auto_extend||1;var m=function m(o){k.boundary="nearby("+o.latitude+","+o.longitude+","+n+","+j+")";wx.request(Utils.buildWxRequestConfig(i,{url:URL_SEARCH,data:k}))};Utils.locationProcess(i,m)}},{key:"getSuggestion",value:function h(i){var k=this;i=i||{};Utils.polyfillParam(i);if(!Utils.checkKeyword(i)){return}var j={keyword:i.keyword,region:i.region||"全国",region_fix:i.region_fix||0,policy:i.policy||0,output:"json",key:k.key};wx.request(Utils.buildWxRequestConfig(i,{url:URL_SUGGESTION,data:j}))}},{key:"reverseGeocoder",value:function a(i){var k=this;i=i||{};Utils.polyfillParam(i);var j={coord_type:i.coord_type||5,get_poi:i.get_poi||0,output:"json",key:k.key};if(i.poi_options){j.poi_options=i.poi_options}var l=function l(m){j.location=m.latitude+","+m.longitude;wx.request(Utils.buildWxRequestConfig(i,{url:URL_GET_GEOCODER,data:j}))};Utils.locationProcess(i,l)}},{key:"geocoder",value:function g(i){var k=this;i=i||{};Utils.polyfillParam(i);if(Utils.checkParamKeyEmpty(i,"address")){return}var j={address:i.address,output:"json",key:k.key};wx.request(Utils.buildWxRequestConfig(i,{url:URL_GET_GEOCODER,data:j}))}},{key:"getCityList",value:function c(i){var k=this;i=i||{};Utils.polyfillParam(i);var j={output:"json",key:k.key};  
2 -wx.request(Utils.buildWxRequestConfig(i,{url:URL_CITY_LIST,data:j}))}},{key:"getDistrictByCityId",value:function d(i){var k=this;i=i||{};Utils.polyfillParam(i);if(Utils.checkParamKeyEmpty(i,"id")){return}var j={id:i.id||"",output:"json",key:k.key};wx.request(Utils.buildWxRequestConfig(i,{url:URL_AREA_LIST,data:j}))}},{key:"calculateDistance",value:function e(i){var k=this;i=i||{};Utils.polyfillParam(i);if(Utils.checkParamKeyEmpty(i,"to")){return}var j={mode:i.mode||"walking",to:Utils.location2query(i.to),output:"json",key:k.key};var l=function l(m){j.from=m.latitude+","+m.longitude;wx.request(Utils.buildWxRequestConfig(i,{url:URL_DISTANCE,data:j}))};if(i.from){i.location=i.from}Utils.locationProcess(i,l)}}]);return b}();module.exports=QQMapWX;  
1 -/**  
2 - * html2Json 改造来自: https://github.com/Jxck/html2json  
3 - *  
4 - *  
5 - * author: Di (微信小程序开发工程师)  
6 - * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)  
7 - * 垂直微信小程序开发交流社区  
8 - *  
9 - * github地址: https://github.com/icindy/wxParse  
10 - *  
11 - * for: 微信小程序富文本解析  
12 - * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184  
13 - */  
14 -  
15 -var __placeImgeUrlHttps = "https";  
16 -var __emojisReg = '';  
17 -var __emojisBaseSrc = '';  
18 -var __emojis = {};  
19 -var wxDiscode = require('./wxDiscode.js');  
20 -var HTMLParser = require('./htmlparser.js');  
21 -// Empty Elements - HTML 5  
22 -var empty = makeMap("area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr");  
23 -// Block Elements - HTML 5  
24 -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");  
25 -  
26 -// Inline Elements - HTML 5  
27 -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");  
28 -  
29 -// Elements that you can, intentionally, leave open  
30 -// (and which close themselves)  
31 -var closeSelf = makeMap("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr");  
32 -  
33 -// Attributes that have their values filled in disabled="disabled"  
34 -var fillAttrs = makeMap("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected");  
35 -  
36 -// Special Elements (can contain anything)  
37 -var special = makeMap("wxxxcode-style,script,style,view,scroll-view,block");  
38 -function makeMap(str) {  
39 - var obj = {}, items = str.split(",");  
40 - for (var i = 0; i < items.length; i++)  
41 - obj[items[i]] = true;  
42 - return obj;  
43 -}  
44 -  
45 -function q(v) {  
46 - return '"' + v + '"';  
47 -}  
48 -  
49 -function removeDOCTYPE(html) {  
50 - return html  
51 - .replace(/<\?xml.*\?>\n/, '')  
52 - .replace(/<.*!doctype.*\>\n/, '')  
53 - .replace(/<.*!DOCTYPE.*\>\n/, '');  
54 -}  
55 -  
56 -function trimHtml(html) {  
57 - return html  
58 - .replace(/\r?\n+/g, '')  
59 - .replace(/<!--.*?-->/ig, '')  
60 - .replace(/\/\*.*?\*\//ig, '')  
61 - .replace(/[ ]+</ig, '<')  
62 -}  
63 -  
64 -  
65 -function html2json(html, bindName) {  
66 - //处理字符串  
67 - html = removeDOCTYPE(html);  
68 - html = trimHtml(html);  
69 - html = wxDiscode.strDiscode(html);  
70 - //生成node节点  
71 - var bufArray = [];  
72 - var results = {  
73 - node: bindName,  
74 - nodes: [],  
75 - images:[],  
76 - imageUrls:[]  
77 - };  
78 - var index = 0;  
79 - HTMLParser(html, {  
80 - start: function (tag, attrs, unary) {  
81 - //debug(tag, attrs, unary);  
82 - // node for this element  
83 - var node = {  
84 - node: 'element',  
85 - tag: tag,  
86 - };  
87 -  
88 - if (bufArray.length === 0) {  
89 - node.index = index.toString()  
90 - index += 1  
91 - } else {  
92 - var parent = bufArray[0];  
93 - if (parent.nodes === undefined) {  
94 - parent.nodes = [];  
95 - }  
96 - node.index = parent.index + '.' + parent.nodes.length  
97 - }  
98 -  
99 - if (block[tag]) {  
100 - node.tagType = "block";  
101 - } else if (inline[tag]) {  
102 - node.tagType = "inline";  
103 - } else if (closeSelf[tag]) {  
104 - node.tagType = "closeSelf";  
105 - }  
106 -  
107 - if (attrs.length !== 0) {  
108 - node.attr = attrs.reduce(function (pre, attr) {  
109 - var name = attr.name;  
110 - var value = attr.value;  
111 - if (name == 'class') {  
112 - // console.dir(value);  
113 - // value = value.join("")  
114 - node.classStr = value;  
115 - }  
116 - // has multi attibutes  
117 - // make it array of attribute  
118 - if (name == 'style') {  
119 - console.dir(value);  
120 - // value = value.join("")  
121 - node.styleStr = value;  
122 - }  
123 - if (value.match(/ /)) {  
124 - value = value.split(' ');  
125 - }  
126 -  
127 -  
128 - // if attr already exists  
129 - // merge it  
130 - if (pre[name]) {  
131 - if (Array.isArray(pre[name])) {  
132 - // already array, push to last  
133 - pre[name].push(value);  
134 - } else {  
135 - // single value, make it array  
136 - pre[name] = [pre[name], value];  
137 - }  
138 - } else {  
139 - // not exist, put it  
140 - pre[name] = value;  
141 - }  
142 -  
143 - return pre;  
144 - }, {});  
145 - }  
146 -  
147 - //对img添加额外数据  
148 - if (node.tag === 'img') {  
149 - node.imgIndex = results.images.length;  
150 - var imgUrl = node.attr.src;  
151 - if (imgUrl[0] == '') {  
152 - imgUrl.splice(0, 1);  
153 - }  
154 - imgUrl = wxDiscode.urlToHttpUrl(imgUrl, __placeImgeUrlHttps);  
155 - node.attr.src = imgUrl;  
156 - node.from = bindName;  
157 - results.images.push(node);  
158 - results.imageUrls.push(imgUrl);  
159 - }  
160 -  
161 - // 处理font标签样式属性  
162 - if (node.tag === 'font') {  
163 - var fontSize = ['x-small', 'small', 'medium', 'large', 'x-large', 'xx-large', '-webkit-xxx-large'];  
164 - var styleAttrs = {  
165 - 'color': 'color',  
166 - 'face': 'font-family',  
167 - 'size': 'font-size'  
168 - };  
169 - if (!node.attr.style) node.attr.style = [];  
170 - if (!node.styleStr) node.styleStr = '';  
171 - for (var key in styleAttrs) {  
172 - if (node.attr[key]) {  
173 - var value = key === 'size' ? fontSize[node.attr[key]-1] : node.attr[key];  
174 - node.attr.style.push(styleAttrs[key]);  
175 - node.attr.style.push(value);  
176 - node.styleStr += styleAttrs[key] + ': ' + value + ';';  
177 - }  
178 - }  
179 - }  
180 -  
181 - //临时记录source资源  
182 - if(node.tag === 'source'){  
183 - results.source = node.attr.src;  
184 - }  
185 -  
186 - if (unary) {  
187 - // if this tag doesn't have end tag  
188 - // like <img src="hoge.png"/>  
189 - // add to parents  
190 - var parent = bufArray[0] || results;  
191 - if (parent.nodes === undefined) {  
192 - parent.nodes = [];  
193 - }  
194 - parent.nodes.push(node);  
195 - } else {  
196 - bufArray.unshift(node);  
197 - }  
198 - },  
199 - end: function (tag) {  
200 - //debug(tag);  
201 - // merge into parent tag  
202 - var node = bufArray.shift();  
203 - if (node.tag !== tag) console.error('invalid state: mismatch end tag');  
204 -  
205 - //当有缓存source资源时于于video补上src资源  
206 - if(node.tag === 'video' && results.source){  
207 - node.attr.src = results.source;  
208 - delete results.source;  
209 - }  
210 -  
211 - if (bufArray.length === 0) {  
212 - results.nodes.push(node);  
213 - } else {  
214 - var parent = bufArray[0];  
215 - if (parent.nodes === undefined) {  
216 - parent.nodes = [];  
217 - }  
218 - parent.nodes.push(node);  
219 - }  
220 - },  
221 - chars: function (text) {  
222 - //debug(text);  
223 - var node = {  
224 - node: 'text',  
225 - text: text,  
226 - textArray:transEmojiStr(text)  
227 - };  
228 -  
229 - if (bufArray.length === 0) {  
230 - node.index = index.toString()  
231 - index += 1  
232 - results.nodes.push(node);  
233 - } else {  
234 - var parent = bufArray[0];  
235 - if (parent.nodes === undefined) {  
236 - parent.nodes = [];  
237 - }  
238 - node.index = parent.index + '.' + parent.nodes.length  
239 - parent.nodes.push(node);  
240 - }  
241 - },  
242 - comment: function (text) {  
243 - //debug(text);  
244 - // var node = {  
245 - // node: 'comment',  
246 - // text: text,  
247 - // };  
248 - // var parent = bufArray[0];  
249 - // if (parent.nodes === undefined) {  
250 - // parent.nodes = [];  
251 - // }  
252 - // parent.nodes.push(node);  
253 - },  
254 - });  
255 - return results;  
256 -};  
257 -  
258 -function transEmojiStr(str){  
259 - // var eReg = new RegExp("["+__reg+' '+"]");  
260 -// str = str.replace(/\[([^\[\]]+)\]/g,':$1:')  
261 -  
262 - var emojiObjs = [];  
263 - //如果正则表达式为空  
264 - if(__emojisReg.length == 0 || !__emojis){  
265 - var emojiObj = {}  
266 - emojiObj.node = "text";  
267 - emojiObj.text = str;  
268 - array = [emojiObj];  
269 - return array;  
270 - }  
271 - //这个地方需要调整  
272 - str = str.replace(/\[([^\[\]]+)\]/g,':$1:')  
273 - var eReg = new RegExp("[:]");  
274 - var array = str.split(eReg);  
275 - for(var i = 0; i < array.length; i++){  
276 - var ele = array[i];  
277 - var emojiObj = {};  
278 - if(__emojis[ele]){  
279 - emojiObj.node = "element";  
280 - emojiObj.tag = "emoji";  
281 - emojiObj.text = __emojis[ele];  
282 - emojiObj.baseSrc= __emojisBaseSrc;  
283 - }else{  
284 - emojiObj.node = "text";  
285 - emojiObj.text = ele;  
286 - }  
287 - emojiObjs.push(emojiObj);  
288 - }  
289 -  
290 - return emojiObjs;  
291 -}  
292 -  
293 -function emojisInit(reg='',baseSrc="/wxParse/emojis/",emojis){  
294 - __emojisReg = reg;  
295 - __emojisBaseSrc=baseSrc;  
296 - __emojis=emojis;  
297 -}  
298 -  
299 -module.exports = {  
300 - html2json: html2json,  
301 - emojisInit:emojisInit  
302 -};  
303 -  
1 -/**  
2 - *  
3 - * htmlParser改造自: https://github.com/blowsie/Pure-JavaScript-HTML5-Parser  
4 - *  
5 - * author: Di (微信小程序开发工程师)  
6 - * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)  
7 - * 垂直微信小程序开发交流社区  
8 - *  
9 - * github地址: https://github.com/icindy/wxParse  
10 - *  
11 - * for: 微信小程序富文本解析  
12 - * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184  
13 - */  
14 -// Regular Expressions for parsing tags and attributes  
15 -var startTag = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/,  
16 - endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/,  
17 - attr = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g;  
18 -  
19 -// Empty Elements - HTML 5  
20 -var empty = makeMap("area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr");  
21 -  
22 -// Block Elements - HTML 5  
23 -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");  
24 -  
25 -// Inline Elements - HTML 5  
26 -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");  
27 -  
28 -// Elements that you can, intentionally, leave open  
29 -// (and which close themselves)  
30 -var closeSelf = makeMap("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr");  
31 -  
32 -// Attributes that have their values filled in disabled="disabled"  
33 -var fillAttrs = makeMap("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected");  
34 -  
35 -// Special Elements (can contain anything)  
36 -var special = makeMap("wxxxcode-style,script,style,view,scroll-view,block");  
37 -  
38 -function HTMLParser(html, handler) {  
39 - var index, chars, match, stack = [], last = html;  
40 - stack.last = function () {  
41 - return this[this.length - 1];  
42 - };  
43 -  
44 - while (html) {  
45 - chars = true;  
46 -  
47 - // Make sure we're not in a script or style element  
48 - if (!stack.last() || !special[stack.last()]) {  
49 -  
50 - // Comment  
51 - if (html.indexOf("<!--") == 0) {  
52 - index = html.indexOf("-->");  
53 -  
54 - if (index >= 0) {  
55 - if (handler.comment)  
56 - handler.comment(html.substring(4, index));  
57 - html = html.substring(index + 3);  
58 - chars = false;  
59 - }  
60 -  
61 - // end tag  
62 - } else if (html.indexOf("</") == 0) {  
63 - match = html.match(endTag);  
64 -  
65 - if (match) {  
66 - html = html.substring(match[0].length);  
67 - match[0].replace(endTag, parseEndTag);  
68 - chars = false;  
69 - }  
70 -  
71 - // start tag  
72 - } else if (html.indexOf("<") == 0) {  
73 - match = html.match(startTag);  
74 -  
75 - if (match) {  
76 - html = html.substring(match[0].length);  
77 - match[0].replace(startTag, parseStartTag);  
78 - chars = false;  
79 - }  
80 - }  
81 -  
82 - if (chars) {  
83 - index = html.indexOf("<");  
84 - var text = ''  
85 - while (index === 0) {  
86 - text += "<";  
87 - html = html.substring(1);  
88 - index = html.indexOf("<");  
89 - }  
90 - text += index < 0 ? html : html.substring(0, index);  
91 - html = index < 0 ? "" : html.substring(index);  
92 -  
93 - if (handler.chars)  
94 - handler.chars(text);  
95 - }  
96 -  
97 - } else {  
98 -  
99 - html = html.replace(new RegExp("([\\s\\S]*?)<\/" + stack.last() + "[^>]*>"), function (all, text) {  
100 - text = text.replace(/<!--([\s\S]*?)-->|<!\[CDATA\[([\s\S]*?)]]>/g, "$1$2");  
101 - if (handler.chars)  
102 - handler.chars(text);  
103 -  
104 - return "";  
105 - });  
106 -  
107 -  
108 - parseEndTag("", stack.last());  
109 - }  
110 -  
111 - if (html == last)  
112 - throw "Parse Error: " + html;  
113 - last = html;  
114 - }  
115 -  
116 - // Clean up any remaining tags  
117 - parseEndTag();  
118 -  
119 - function parseStartTag(tag, tagName, rest, unary) {  
120 - tagName = tagName.toLowerCase();  
121 -  
122 - if (block[tagName]) {  
123 - while (stack.last() && inline[stack.last()]) {  
124 - parseEndTag("", stack.last());  
125 - }  
126 - }  
127 -  
128 - if (closeSelf[tagName] && stack.last() == tagName) {  
129 - parseEndTag("", tagName);  
130 - }  
131 -  
132 - unary = empty[tagName] || !!unary;  
133 -  
134 - if (!unary)  
135 - stack.push(tagName);  
136 -  
137 - if (handler.start) {  
138 - var attrs = [];  
139 -  
140 - rest.replace(attr, function (match, name) {  
141 - var value = arguments[2] ? arguments[2] :  
142 - arguments[3] ? arguments[3] :  
143 - arguments[4] ? arguments[4] :  
144 - fillAttrs[name] ? name : "";  
145 -  
146 - attrs.push({  
147 - name: name,  
148 - value: value,  
149 - escaped: value.replace(/(^|[^\\])"/g, '$1\\\"') //"  
150 - });  
151 - });  
152 -  
153 - if (handler.start) {  
154 - handler.start(tagName, attrs, unary);  
155 - }  
156 -  
157 - }  
158 - }  
159 -  
160 - function parseEndTag(tag, tagName) {  
161 - // If no tag name is provided, clean shop  
162 - if (!tagName)  
163 - var pos = 0;  
164 -  
165 - // Find the closest opened tag of the same type  
166 - else {  
167 - tagName = tagName.toLowerCase();  
168 - for (var pos = stack.length - 1; pos >= 0; pos--)  
169 - if (stack[pos] == tagName)  
170 - break;  
171 - }  
172 - if (pos >= 0) {  
173 - // Close all the open elements, up the stack  
174 - for (var i = stack.length - 1; i >= pos; i--)  
175 - if (handler.end)  
176 - handler.end(stack[i]);  
177 -  
178 - // Remove the open elements from the stack  
179 - stack.length = pos;  
180 - }  
181 - }  
182 -};  
183 -  
184 -  
185 -function makeMap(str) {  
186 - var obj = {}, items = str.split(",");  
187 - for (var i = 0; i < items.length; i++)  
188 - obj[items[i]] = true;  
189 - return obj;  
190 -}  
191 -  
192 -module.exports = HTMLParser;  
1 -/**  
2 - *  
3 - * showdown: https://github.com/showdownjs/showdown  
4 - *  
5 - * author: Di (微信小程序开发工程师)  
6 - * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)  
7 - * 垂直微信小程序开发交流社区  
8 - *  
9 - * github地址: https://github.com/icindy/wxParse  
10 - *  
11 - * for: 微信小程序富文本解析  
12 - * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184  
13 - */  
14 -  
15 -function getDefaultOpts(simple) {  
16 - 'use strict';  
17 -  
18 - var defaultOptions = {  
19 - omitExtraWLInCodeBlocks: {  
20 - defaultValue: false,  
21 - describe: 'Omit the default extra whiteline added to code blocks',  
22 - type: 'boolean'  
23 - },  
24 - noHeaderId: {  
25 - defaultValue: false,  
26 - describe: 'Turn on/off generated header id',  
27 - type: 'boolean'  
28 - },  
29 - prefixHeaderId: {  
30 - defaultValue: false,  
31 - describe: 'Specify a prefix to generated header ids',  
32 - type: 'string'  
33 - },  
34 - headerLevelStart: {  
35 - defaultValue: false,  
36 - describe: 'The header blocks level start',  
37 - type: 'integer'  
38 - },  
39 - parseImgDimensions: {  
40 - defaultValue: false,  
41 - describe: 'Turn on/off image dimension parsing',  
42 - type: 'boolean'  
43 - },  
44 - simplifiedAutoLink: {  
45 - defaultValue: false,  
46 - describe: 'Turn on/off GFM autolink style',  
47 - type: 'boolean'  
48 - },  
49 - literalMidWordUnderscores: {  
50 - defaultValue: false,  
51 - describe: 'Parse midword underscores as literal underscores',  
52 - type: 'boolean'  
53 - },  
54 - strikethrough: {  
55 - defaultValue: false,  
56 - describe: 'Turn on/off strikethrough support',  
57 - type: 'boolean'  
58 - },  
59 - tables: {  
60 - defaultValue: false,  
61 - describe: 'Turn on/off tables support',  
62 - type: 'boolean'  
63 - },  
64 - tablesHeaderId: {  
65 - defaultValue: false,  
66 - describe: 'Add an id to table headers',  
67 - type: 'boolean'  
68 - },  
69 - ghCodeBlocks: {  
70 - defaultValue: true,  
71 - describe: 'Turn on/off GFM fenced code blocks support',  
72 - type: 'boolean'  
73 - },  
74 - tasklists: {  
75 - defaultValue: false,  
76 - describe: 'Turn on/off GFM tasklist support',  
77 - type: 'boolean'  
78 - },  
79 - smoothLivePreview: {  
80 - defaultValue: false,  
81 - describe: 'Prevents weird effects in live previews due to incomplete input',  
82 - type: 'boolean'  
83 - },  
84 - smartIndentationFix: {  
85 - defaultValue: false,  
86 - description: 'Tries to smartly fix identation in es6 strings',  
87 - type: 'boolean'  
88 - }  
89 - };  
90 - if (simple === false) {  
91 - return JSON.parse(JSON.stringify(defaultOptions));  
92 - }  
93 - var ret = {};  
94 - for (var opt in defaultOptions) {  
95 - if (defaultOptions.hasOwnProperty(opt)) {  
96 - ret[opt] = defaultOptions[opt].defaultValue;  
97 - }  
98 - }  
99 - return ret;  
100 -}  
101 -  
102 -/**  
103 - * Created by Tivie on 06-01-2015.  
104 - */  
105 -  
106 -// Private properties  
107 -var showdown = {},  
108 - parsers = {},  
109 - extensions = {},  
110 - globalOptions = getDefaultOpts(true),  
111 - flavor = {  
112 - github: {  
113 - omitExtraWLInCodeBlocks: true,  
114 - prefixHeaderId: 'user-content-',  
115 - simplifiedAutoLink: true,  
116 - literalMidWordUnderscores: true,  
117 - strikethrough: true,  
118 - tables: true,  
119 - tablesHeaderId: true,  
120 - ghCodeBlocks: true,  
121 - tasklists: true  
122 - },  
123 - vanilla: getDefaultOpts(true)  
124 - };  
125 -  
126 -/**  
127 - * helper namespace  
128 - * @type {{}}  
129 - */  
130 -showdown.helper = {};  
131 -  
132 -/**  
133 - * TODO LEGACY SUPPORT CODE  
134 - * @type {{}}  
135 - */  
136 -showdown.extensions = {};  
137 -  
138 -/**  
139 - * Set a global option  
140 - * @static  
141 - * @param {string} key  
142 - * @param {*} value  
143 - * @returns {showdown}  
144 - */  
145 -showdown.setOption = function (key, value) {  
146 - 'use strict';  
147 - globalOptions[key] = value;  
148 - return this;  
149 -};  
150 -  
151 -/**  
152 - * Get a global option  
153 - * @static  
154 - * @param {string} key  
155 - * @returns {*}  
156 - */  
157 -showdown.getOption = function (key) {  
158 - 'use strict';  
159 - return globalOptions[key];  
160 -};  
161 -  
162 -/**  
163 - * Get the global options  
164 - * @static  
165 - * @returns {{}}  
166 - */  
167 -showdown.getOptions = function () {  
168 - 'use strict';  
169 - return globalOptions;  
170 -};  
171 -  
172 -/**  
173 - * Reset global options to the default values  
174 - * @static  
175 - */  
176 -showdown.resetOptions = function () {  
177 - 'use strict';  
178 - globalOptions = getDefaultOpts(true);  
179 -};  
180 -  
181 -/**  
182 - * Set the flavor showdown should use as default  
183 - * @param {string} name  
184 - */  
185 -showdown.setFlavor = function (name) {  
186 - 'use strict';  
187 - if (flavor.hasOwnProperty(name)) {  
188 - var preset = flavor[name];  
189 - for (var option in preset) {  
190 - if (preset.hasOwnProperty(option)) {  
191 - globalOptions[option] = preset[option];  
192 - }  
193 - }  
194 - }  
195 -};  
196 -  
197 -/**  
198 - * Get the default options  
199 - * @static  
200 - * @param {boolean} [simple=true]  
201 - * @returns {{}}  
202 - */  
203 -showdown.getDefaultOptions = function (simple) {  
204 - 'use strict';  
205 - return getDefaultOpts(simple);  
206 -};  
207 -  
208 -/**  
209 - * Get or set a subParser  
210 - *  
211 - * subParser(name) - Get a registered subParser  
212 - * subParser(name, func) - Register a subParser  
213 - * @static  
214 - * @param {string} name  
215 - * @param {function} [func]  
216 - * @returns {*}  
217 - */  
218 -showdown.subParser = function (name, func) {  
219 - 'use strict';  
220 - if (showdown.helper.isString(name)) {  
221 - if (typeof func !== 'undefined') {  
222 - parsers[name] = func;  
223 - } else {  
224 - if (parsers.hasOwnProperty(name)) {  
225 - return parsers[name];  
226 - } else {  
227 - throw Error('SubParser named ' + name + ' not registered!');  
228 - }  
229 - }  
230 - }  
231 -};  
232 -  
233 -/**  
234 - * Gets or registers an extension  
235 - * @static  
236 - * @param {string} name  
237 - * @param {object|function=} ext  
238 - * @returns {*}  
239 - */  
240 -showdown.extension = function (name, ext) {  
241 - 'use strict';  
242 -  
243 - if (!showdown.helper.isString(name)) {  
244 - throw Error('Extension \'name\' must be a string');  
245 - }  
246 -  
247 - name = showdown.helper.stdExtName(name);  
248 -  
249 - // Getter  
250 - if (showdown.helper.isUndefined(ext)) {  
251 - if (!extensions.hasOwnProperty(name)) {  
252 - throw Error('Extension named ' + name + ' is not registered!');  
253 - }  
254 - return extensions[name];  
255 -  
256 - // Setter  
257 - } else {  
258 - // Expand extension if it's wrapped in a function  
259 - if (typeof ext === 'function') {  
260 - ext = ext();  
261 - }  
262 -  
263 - // Ensure extension is an array  
264 - if (!showdown.helper.isArray(ext)) {  
265 - ext = [ext];  
266 - }  
267 -  
268 - var validExtension = validate(ext, name);  
269 -  
270 - if (validExtension.valid) {  
271 - extensions[name] = ext;  
272 - } else {  
273 - throw Error(validExtension.error);  
274 - }  
275 - }  
276 -};  
277 -  
278 -/**  
279 - * Gets all extensions registered  
280 - * @returns {{}}  
281 - */  
282 -showdown.getAllExtensions = function () {  
283 - 'use strict';  
284 - return extensions;  
285 -};  
286 -  
287 -/**  
288 - * Remove an extension  
289 - * @param {string} name  
290 - */  
291 -showdown.removeExtension = function (name) {  
292 - 'use strict';  
293 - delete extensions[name];  
294 -};  
295 -  
296 -/**  
297 - * Removes all extensions  
298 - */  
299 -showdown.resetExtensions = function () {  
300 - 'use strict';  
301 - extensions = {};  
302 -};  
303 -  
304 -/**  
305 - * Validate extension  
306 - * @param {array} extension  
307 - * @param {string} name  
308 - * @returns {{valid: boolean, error: string}}  
309 - */  
310 -function validate(extension, name) {  
311 - 'use strict';  
312 -  
313 - var errMsg = (name) ? 'Error in ' + name + ' extension->' : 'Error in unnamed extension',  
314 - ret = {  
315 - valid: true,  
316 - error: ''  
317 - };  
318 -  
319 - if (!showdown.helper.isArray(extension)) {  
320 - extension = [extension];  
321 - }  
322 -  
323 - for (var i = 0; i < extension.length; ++i) {  
324 - var baseMsg = errMsg + ' sub-extension ' + i + ': ',  
325 - ext = extension[i];  
326 - if (typeof ext !== 'object') {  
327 - ret.valid = false;  
328 - ret.error = baseMsg + 'must be an object, but ' + typeof ext + ' given';  
329 - return ret;  
330 - }  
331 -  
332 - if (!showdown.helper.isString(ext.type)) {  
333 - ret.valid = false;  
334 - ret.error = baseMsg + 'property "type" must be a string, but ' + typeof ext.type + ' given';  
335 - return ret;  
336 - }  
337 -  
338 - var type = ext.type = ext.type.toLowerCase();  
339 -  
340 - // normalize extension type  
341 - if (type === 'language') {  
342 - type = ext.type = 'lang';  
343 - }  
344 -  
345 - if (type === 'html') {  
346 - type = ext.type = 'output';  
347 - }  
348 -  
349 - if (type !== 'lang' && type !== 'output' && type !== 'listener') {  
350 - ret.valid = false;  
351 - ret.error = baseMsg + 'type ' + type + ' is not recognized. Valid values: "lang/language", "output/html" or "listener"';  
352 - return ret;  
353 - }  
354 -  
355 - if (type === 'listener') {  
356 - if (showdown.helper.isUndefined(ext.listeners)) {  
357 - ret.valid = false;  
358 - ret.error = baseMsg + '. Extensions of type "listener" must have a property called "listeners"';  
359 - return ret;  
360 - }  
361 - } else {  
362 - if (showdown.helper.isUndefined(ext.filter) && showdown.helper.isUndefined(ext.regex)) {  
363 - ret.valid = false;  
364 - ret.error = baseMsg + type + ' extensions must define either a "regex" property or a "filter" method';  
365 - return ret;  
366 - }  
367 - }  
368 -  
369 - if (ext.listeners) {  
370 - if (typeof ext.listeners !== 'object') {  
371 - ret.valid = false;  
372 - ret.error = baseMsg + '"listeners" property must be an object but ' + typeof ext.listeners + ' given';  
373 - return ret;  
374 - }  
375 - for (var ln in ext.listeners) {  
376 - if (ext.listeners.hasOwnProperty(ln)) {  
377 - if (typeof ext.listeners[ln] !== 'function') {  
378 - ret.valid = false;  
379 - ret.error = baseMsg + '"listeners" property must be an hash of [event name]: [callback]. listeners.' + ln +  
380 - ' must be a function but ' + typeof ext.listeners[ln] + ' given';  
381 - return ret;  
382 - }  
383 - }  
384 - }  
385 - }  
386 -  
387 - if (ext.filter) {  
388 - if (typeof ext.filter !== 'function') {  
389 - ret.valid = false;  
390 - ret.error = baseMsg + '"filter" must be a function, but ' + typeof ext.filter + ' given';  
391 - return ret;  
392 - }  
393 - } else if (ext.regex) {  
394 - if (showdown.helper.isString(ext.regex)) {  
395 - ext.regex = new RegExp(ext.regex, 'g');  
396 - }  
397 - if (!ext.regex instanceof RegExp) {  
398 - ret.valid = false;  
399 - ret.error = baseMsg + '"regex" property must either be a string or a RegExp object, but ' + typeof ext.regex + ' given';  
400 - return ret;  
401 - }  
402 - if (showdown.helper.isUndefined(ext.replace)) {  
403 - ret.valid = false;  
404 - ret.error = baseMsg + '"regex" extensions must implement a replace string or function';  
405 - return ret;  
406 - }  
407 - }  
408 - }  
409 - return ret;  
410 -}  
411 -  
412 -/**  
413 - * Validate extension  
414 - * @param {object} ext  
415 - * @returns {boolean}  
416 - */  
417 -showdown.validateExtension = function (ext) {  
418 - 'use strict';  
419 -  
420 - var validateExtension = validate(ext, null);  
421 - if (!validateExtension.valid) {  
422 - console.warn(validateExtension.error);  
423 - return false;  
424 - }  
425 - return true;  
426 -};  
427 -  
428 -/**  
429 - * showdownjs helper functions  
430 - */  
431 -  
432 -if (!showdown.hasOwnProperty('helper')) {  
433 - showdown.helper = {};  
434 -}  
435 -  
436 -/**  
437 - * Check if var is string  
438 - * @static  
439 - * @param {string} a  
440 - * @returns {boolean}  
441 - */  
442 -showdown.helper.isString = function isString(a) {  
443 - 'use strict';  
444 - return (typeof a === 'string' || a instanceof String);  
445 -};  
446 -  
447 -/**  
448 - * Check if var is a function  
449 - * @static  
450 - * @param {string} a  
451 - * @returns {boolean}  
452 - */  
453 -showdown.helper.isFunction = function isFunction(a) {  
454 - 'use strict';  
455 - var getType = {};  
456 - return a && getType.toString.call(a) === '[object Function]';  
457 -};  
458 -  
459 -/**  
460 - * ForEach helper function  
461 - * @static  
462 - * @param {*} obj  
463 - * @param {function} callback  
464 - */  
465 -showdown.helper.forEach = function forEach(obj, callback) {  
466 - 'use strict';  
467 - if (typeof obj.forEach === 'function') {  
468 - obj.forEach(callback);  
469 - } else {  
470 - for (var i = 0; i < obj.length; i++) {  
471 - callback(obj[i], i, obj);  
472 - }  
473 - }  
474 -};  
475 -  
476 -/**  
477 - * isArray helper function  
478 - * @static  
479 - * @param {*} a  
480 - * @returns {boolean}  
481 - */  
482 -showdown.helper.isArray = function isArray(a) {  
483 - 'use strict';  
484 - return a.constructor === Array;  
485 -};  
486 -  
487 -/**  
488 - * Check if value is undefined  
489 - * @static  
490 - * @param {*} value The value to check.  
491 - * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.  
492 - */  
493 -showdown.helper.isUndefined = function isUndefined(value) {  
494 - 'use strict';  
495 - return typeof value === 'undefined';  
496 -};  
497 -  
498 -/**  
499 - * Standardidize extension name  
500 - * @static  
501 - * @param {string} s extension name  
502 - * @returns {string}  
503 - */  
504 -showdown.helper.stdExtName = function (s) {  
505 - 'use strict';  
506 - return s.replace(/[_-]||\s/g, '').toLowerCase();  
507 -};  
508 -  
509 -function escapeCharactersCallback(wholeMatch, m1) {  
510 - 'use strict';  
511 - var charCodeToEscape = m1.charCodeAt(0);  
512 - return '~E' + charCodeToEscape + 'E';  
513 -}  
514 -  
515 -/**  
516 - * Callback used to escape characters when passing through String.replace  
517 - * @static  
518 - * @param {string} wholeMatch  
519 - * @param {string} m1  
520 - * @returns {string}  
521 - */  
522 -showdown.helper.escapeCharactersCallback = escapeCharactersCallback;  
523 -  
524 -/**  
525 - * Escape characters in a string  
526 - * @static  
527 - * @param {string} text  
528 - * @param {string} charsToEscape  
529 - * @param {boolean} afterBackslash  
530 - * @returns {XML|string|void|*}  
531 - */  
532 -showdown.helper.escapeCharacters = function escapeCharacters(text, charsToEscape, afterBackslash) {  
533 - 'use strict';  
534 - // First we have to escape the escape characters so that  
535 - // we can build a character class out of them  
536 - var regexString = '([' + charsToEscape.replace(/([\[\]\\])/g, '\\$1') + '])';  
537 -  
538 - if (afterBackslash) {  
539 - regexString = '\\\\' + regexString;  
540 - }  
541 -  
542 - var regex = new RegExp(regexString, 'g');  
543 - text = text.replace(regex, escapeCharactersCallback);  
544 -  
545 - return text;  
546 -};  
547 -  
548 -var rgxFindMatchPos = function (str, left, right, flags) {  
549 - 'use strict';  
550 - var f = flags || '',  
551 - g = f.indexOf('g') > -1,  
552 - x = new RegExp(left + '|' + right, 'g' + f.replace(/g/g, '')),  
553 - l = new RegExp(left, f.replace(/g/g, '')),  
554 - pos = [],  
555 - t, s, m, start, end;  
556 -  
557 - do {  
558 - t = 0;  
559 - while ((m = x.exec(str))) {  
560 - if (l.test(m[0])) {  
561 - if (!(t++)) {  
562 - s = x.lastIndex;  
563 - start = s - m[0].length;  
564 - }  
565 - } else if (t) {  
566 - if (!--t) {  
567 - end = m.index + m[0].length;  
568 - var obj = {  
569 - left: {start: start, end: s},  
570 - match: {start: s, end: m.index},  
571 - right: {start: m.index, end: end},  
572 - wholeMatch: {start: start, end: end}  
573 - };  
574 - pos.push(obj);  
575 - if (!g) {  
576 - return pos;  
577 - }  
578 - }  
579 - }  
580 - }  
581 - } while (t && (x.lastIndex = s));  
582 -  
583 - return pos;  
584 -};  
585 -  
586 -/**  
587 - * matchRecursiveRegExp  
588 - *  
589 - * (c) 2007 Steven Levithan <stevenlevithan.com>  
590 - * MIT License  
591 - *  
592 - * Accepts a string to search, a left and right format delimiter  
593 - * as regex patterns, and optional regex flags. Returns an array  
594 - * of matches, allowing nested instances of left/right delimiters.  
595 - * Use the "g" flag to return all matches, otherwise only the  
596 - * first is returned. Be careful to ensure that the left and  
597 - * right format delimiters produce mutually exclusive matches.  
598 - * Backreferences are not supported within the right delimiter  
599 - * due to how it is internally combined with the left delimiter.  
600 - * When matching strings whose format delimiters are unbalanced  
601 - * to the left or right, the output is intentionally as a  
602 - * conventional regex library with recursion support would  
603 - * produce, e.g. "<<x>" and "<x>>" both produce ["x"] when using  
604 - * "<" and ">" as the delimiters (both strings contain a single,  
605 - * balanced instance of "<x>").  
606 - *  
607 - * examples:  
608 - * matchRecursiveRegExp("test", "\\(", "\\)")  
609 - * returns: []  
610 - * matchRecursiveRegExp("<t<<e>><s>>t<>", "<", ">", "g")  
611 - * returns: ["t<<e>><s>", ""]  
612 - * matchRecursiveRegExp("<div id=\"x\">test</div>", "<div\\b[^>]*>", "</div>", "gi")  
613 - * returns: ["test"]  
614 - */  
615 -showdown.helper.matchRecursiveRegExp = function (str, left, right, flags) {  
616 - 'use strict';  
617 -  
618 - var matchPos = rgxFindMatchPos (str, left, right, flags),  
619 - results = [];  
620 -  
621 - for (var i = 0; i < matchPos.length; ++i) {  
622 - results.push([  
623 - str.slice(matchPos[i].wholeMatch.start, matchPos[i].wholeMatch.end),  
624 - str.slice(matchPos[i].match.start, matchPos[i].match.end),  
625 - str.slice(matchPos[i].left.start, matchPos[i].left.end),  
626 - str.slice(matchPos[i].right.start, matchPos[i].right.end)  
627 - ]);  
628 - }  
629 - return results;  
630 -};  
631 -  
632 -/**  
633 - *  
634 - * @param {string} str  
635 - * @param {string|function} replacement  
636 - * @param {string} left  
637 - * @param {string} right  
638 - * @param {string} flags  
639 - * @returns {string}  
640 - */  
641 -showdown.helper.replaceRecursiveRegExp = function (str, replacement, left, right, flags) {  
642 - 'use strict';  
643 -  
644 - if (!showdown.helper.isFunction(replacement)) {  
645 - var repStr = replacement;  
646 - replacement = function () {  
647 - return repStr;  
648 - };  
649 - }  
650 -  
651 - var matchPos = rgxFindMatchPos(str, left, right, flags),  
652 - finalStr = str,  
653 - lng = matchPos.length;  
654 -  
655 - if (lng > 0) {  
656 - var bits = [];  
657 - if (matchPos[0].wholeMatch.start !== 0) {  
658 - bits.push(str.slice(0, matchPos[0].wholeMatch.start));  
659 - }  
660 - for (var i = 0; i < lng; ++i) {  
661 - bits.push(  
662 - replacement(  
663 - str.slice(matchPos[i].wholeMatch.start, matchPos[i].wholeMatch.end),  
664 - str.slice(matchPos[i].match.start, matchPos[i].match.end),  
665 - str.slice(matchPos[i].left.start, matchPos[i].left.end),  
666 - str.slice(matchPos[i].right.start, matchPos[i].right.end)  
667 - )  
668 - );  
669 - if (i < lng - 1) {  
670 - bits.push(str.slice(matchPos[i].wholeMatch.end, matchPos[i + 1].wholeMatch.start));  
671 - }  
672 - }  
673 - if (matchPos[lng - 1].wholeMatch.end < str.length) {  
674 - bits.push(str.slice(matchPos[lng - 1].wholeMatch.end));  
675 - }  
676 - finalStr = bits.join('');  
677 - }  
678 - return finalStr;  
679 -};  
680 -  
681 -/**  
682 - * POLYFILLS  
683 - */  
684 -if (showdown.helper.isUndefined(console)) {  
685 - console = {  
686 - warn: function (msg) {  
687 - 'use strict';  
688 - alert(msg);  
689 - },  
690 - log: function (msg) {  
691 - 'use strict';  
692 - alert(msg);  
693 - },  
694 - error: function (msg) {  
695 - 'use strict';  
696 - throw msg;  
697 - }  
698 - };  
699 -}  
700 -  
701 -/**  
702 - * Created by Estevao on 31-05-2015.  
703 - */  
704 -  
705 -/**  
706 - * Showdown Converter class  
707 - * @class  
708 - * @param {object} [converterOptions]  
709 - * @returns {Converter}  
710 - */  
711 -showdown.Converter = function (converterOptions) {  
712 - 'use strict';  
713 -  
714 - var  
715 - /**  
716 - * Options used by this converter  
717 - * @private  
718 - * @type {{}}  
719 - */  
720 - options = {},  
721 -  
722 - /**  
723 - * Language extensions used by this converter  
724 - * @private  
725 - * @type {Array}  
726 - */  
727 - langExtensions = [],  
728 -  
729 - /**  
730 - * Output modifiers extensions used by this converter  
731 - * @private  
732 - * @type {Array}  
733 - */  
734 - outputModifiers = [],  
735 -  
736 - /**  
737 - * Event listeners  
738 - * @private  
739 - * @type {{}}  
740 - */  
741 - listeners = {};  
742 -  
743 - _constructor();  
744 -  
745 - /**  
746 - * Converter constructor  
747 - * @private  
748 - */  
749 - function _constructor() {  
750 - converterOptions = converterOptions || {};  
751 -  
752 - for (var gOpt in globalOptions) {  
753 - if (globalOptions.hasOwnProperty(gOpt)) {  
754 - options[gOpt] = globalOptions[gOpt];  
755 - }  
756 - }  
757 -  
758 - // Merge options  
759 - if (typeof converterOptions === 'object') {  
760 - for (var opt in converterOptions) {  
761 - if (converterOptions.hasOwnProperty(opt)) {  
762 - options[opt] = converterOptions[opt];  
763 - }  
764 - }  
765 - } else {  
766 - throw Error('Converter expects the passed parameter to be an object, but ' + typeof converterOptions +  
767 - ' was passed instead.');  
768 - }  
769 -  
770 - if (options.extensions) {  
771 - showdown.helper.forEach(options.extensions, _parseExtension);  
772 - }  
773 - }  
774 -  
775 - /**  
776 - * Parse extension  
777 - * @param {*} ext  
778 - * @param {string} [name='']  
779 - * @private  
780 - */  
781 - function _parseExtension(ext, name) {  
782 -  
783 - name = name || null;  
784 - // If it's a string, the extension was previously loaded  
785 - if (showdown.helper.isString(ext)) {  
786 - ext = showdown.helper.stdExtName(ext);  
787 - name = ext;  
788 -  
789 - // LEGACY_SUPPORT CODE  
790 - if (showdown.extensions[ext]) {  
791 - console.warn('DEPRECATION WARNING: ' + ext + ' is an old extension that uses a deprecated loading method.' +  
792 - 'Please inform the developer that the extension should be updated!');  
793 - legacyExtensionLoading(showdown.extensions[ext], ext);  
794 - return;  
795 - // END LEGACY SUPPORT CODE  
796 -  
797 - } else if (!showdown.helper.isUndefined(extensions[ext])) {  
798 - ext = extensions[ext];  
799 -  
800 - } else {  
801 - throw Error('Extension "' + ext + '" could not be loaded. It was either not found or is not a valid extension.');  
802 - }  
803 - }  
804 -  
805 - if (typeof ext === 'function') {  
806 - ext = ext();  
807 - }  
808 -  
809 - if (!showdown.helper.isArray(ext)) {  
810 - ext = [ext];  
811 - }  
812 -  
813 - var validExt = validate(ext, name);  
814 - if (!validExt.valid) {  
815 - throw Error(validExt.error);  
816 - }  
817 -  
818 - for (var i = 0; i < ext.length; ++i) {  
819 - switch (ext[i].type) {  
820 -  
821 - case 'lang':  
822 - langExtensions.push(ext[i]);  
823 - break;  
824 -  
825 - case 'output':  
826 - outputModifiers.push(ext[i]);  
827 - break;  
828 - }  
829 - if (ext[i].hasOwnProperty(listeners)) {  
830 - for (var ln in ext[i].listeners) {  
831 - if (ext[i].listeners.hasOwnProperty(ln)) {  
832 - listen(ln, ext[i].listeners[ln]);  
833 - }  
834 - }  
835 - }  
836 - }  
837 -  
838 - }  
839 -  
840 - /**  
841 - * LEGACY_SUPPORT  
842 - * @param {*} ext  
843 - * @param {string} name  
844 - */  
845 - function legacyExtensionLoading(ext, name) {  
846 - if (typeof ext === 'function') {  
847 - ext = ext(new showdown.Converter());  
848 - }  
849 - if (!showdown.helper.isArray(ext)) {  
850 - ext = [ext];  
851 - }  
852 - var valid = validate(ext, name);  
853 -  
854 - if (!valid.valid) {  
855 - throw Error(valid.error);  
856 - }  
857 -  
858 - for (var i = 0; i < ext.length; ++i) {  
859 - switch (ext[i].type) {  
860 - case 'lang':  
861 - langExtensions.push(ext[i]);  
862 - break;  
863 - case 'output':  
864 - outputModifiers.push(ext[i]);  
865 - break;  
866 - default:// should never reach here  
867 - throw Error('Extension loader error: Type unrecognized!!!');  
868 - }  
869 - }  
870 - }  
871 -  
872 - /**  
873 - * Listen to an event  
874 - * @param {string} name  
875 - * @param {function} callback  
876 - */  
877 - function listen(name, callback) {  
878 - if (!showdown.helper.isString(name)) {  
879 - throw Error('Invalid argument in converter.listen() method: name must be a string, but ' + typeof name + ' given');  
880 - }  
881 -  
882 - if (typeof callback !== 'function') {  
883 - throw Error('Invalid argument in converter.listen() method: callback must be a function, but ' + typeof callback + ' given');  
884 - }  
885 -  
886 - if (!listeners.hasOwnProperty(name)) {  
887 - listeners[name] = [];  
888 - }  
889 - listeners[name].push(callback);  
890 - }  
891 -  
892 - function rTrimInputText(text) {  
893 - var rsp = text.match(/^\s*/)[0].length,  
894 - rgx = new RegExp('^\\s{0,' + rsp + '}', 'gm');  
895 - return text.replace(rgx, '');  
896 - }  
897 -  
898 - /**  
899 - * Dispatch an event  
900 - * @private  
901 - * @param {string} evtName Event name  
902 - * @param {string} text Text  
903 - * @param {{}} options Converter Options  
904 - * @param {{}} globals  
905 - * @returns {string}  
906 - */  
907 - this._dispatch = function dispatch (evtName, text, options, globals) {  
908 - if (listeners.hasOwnProperty(evtName)) {  
909 - for (var ei = 0; ei < listeners[evtName].length; ++ei) {  
910 - var nText = listeners[evtName][ei](evtName, text, this, options, globals);  
911 - if (nText && typeof nText !== 'undefined') {  
912 - text = nText;  
913 - }  
914 - }  
915 - }  
916 - return text;  
917 - };  
918 -  
919 - /**  
920 - * Listen to an event  
921 - * @param {string} name  
922 - * @param {function} callback  
923 - * @returns {showdown.Converter}  
924 - */  
925 - this.listen = function (name, callback) {  
926 - listen(name, callback);  
927 - return this;  
928 - };  
929 -  
930 - /**  
931 - * Converts a markdown string into HTML  
932 - * @param {string} text  
933 - * @returns {*}  
934 - */  
935 - this.makeHtml = function (text) {  
936 - //check if text is not falsy  
937 - if (!text) {  
938 - return text;  
939 - }  
940 -  
941 - var globals = {  
942 - gHtmlBlocks: [],  
943 - gHtmlMdBlocks: [],  
944 - gHtmlSpans: [],  
945 - gUrls: {},  
946 - gTitles: {},  
947 - gDimensions: {},  
948 - gListLevel: 0,  
949 - hashLinkCounts: {},  
950 - langExtensions: langExtensions,  
951 - outputModifiers: outputModifiers,  
952 - converter: this,  
953 - ghCodeBlocks: []  
954 - };  
955 -  
956 - // attacklab: Replace ~ with ~T  
957 - // This lets us use tilde as an escape char to avoid md5 hashes  
958 - // The choice of character is arbitrary; anything that isn't  
959 - // magic in Markdown will work.  
960 - text = text.replace(/~/g, '~T');  
961 -  
962 - // attacklab: Replace $ with ~D  
963 - // RegExp interprets $ as a special character  
964 - // when it's in a replacement string  
965 - text = text.replace(/\$/g, '~D');  
966 -  
967 - // Standardize line endings  
968 - text = text.replace(/\r\n/g, '\n'); // DOS to Unix  
969 - text = text.replace(/\r/g, '\n'); // Mac to Unix  
970 -  
971 - if (options.smartIndentationFix) {  
972 - text = rTrimInputText(text);  
973 - }  
974 -  
975 - // Make sure text begins and ends with a couple of newlines:  
976 - //text = '\n\n' + text + '\n\n';  
977 - text = text;  
978 - // detab  
979 - text = showdown.subParser('detab')(text, options, globals);  
980 -  
981 - // stripBlankLines  
982 - text = showdown.subParser('stripBlankLines')(text, options, globals);  
983 -  
984 - //run languageExtensions  
985 - showdown.helper.forEach(langExtensions, function (ext) {  
986 - text = showdown.subParser('runExtension')(ext, text, options, globals);  
987 - });  
988 -  
989 - // run the sub parsers  
990 - text = showdown.subParser('hashPreCodeTags')(text, options, globals);  
991 - text = showdown.subParser('githubCodeBlocks')(text, options, globals);  
992 - text = showdown.subParser('hashHTMLBlocks')(text, options, globals);  
993 - text = showdown.subParser('hashHTMLSpans')(text, options, globals);  
994 - text = showdown.subParser('stripLinkDefinitions')(text, options, globals);  
995 - text = showdown.subParser('blockGamut')(text, options, globals);  
996 - text = showdown.subParser('unhashHTMLSpans')(text, options, globals);  
997 - text = showdown.subParser('unescapeSpecialChars')(text, options, globals);  
998 -  
999 - // attacklab: Restore dollar signs  
1000 - text = text.replace(/~D/g, '$$');  
1001 -  
1002 - // attacklab: Restore tildes  
1003 - text = text.replace(/~T/g, '~');  
1004 -  
1005 - // Run output modifiers  
1006 - showdown.helper.forEach(outputModifiers, function (ext) {  
1007 - text = showdown.subParser('runExtension')(ext, text, options, globals);  
1008 - });  
1009 - return text;  
1010 - };  
1011 -  
1012 - /**  
1013 - * Set an option of this Converter instance  
1014 - * @param {string} key  
1015 - * @param {*} value  
1016 - */  
1017 - this.setOption = function (key, value) {  
1018 - options[key] = value;  
1019 - };  
1020 -  
1021 - /**  
1022 - * Get the option of this Converter instance  
1023 - * @param {string} key  
1024 - * @returns {*}  
1025 - */  
1026 - this.getOption = function (key) {  
1027 - return options[key];  
1028 - };  
1029 -  
1030 - /**  
1031 - * Get the options of this Converter instance  
1032 - * @returns {{}}  
1033 - */  
1034 - this.getOptions = function () {  
1035 - return options;  
1036 - };  
1037 -  
1038 - /**  
1039 - * Add extension to THIS converter  
1040 - * @param {{}} extension  
1041 - * @param {string} [name=null]  
1042 - */  
1043 - this.addExtension = function (extension, name) {  
1044 - name = name || null;  
1045 - _parseExtension(extension, name);  
1046 - };  
1047 -  
1048 - /**  
1049 - * Use a global registered extension with THIS converter  
1050 - * @param {string} extensionName Name of the previously registered extension  
1051 - */  
1052 - this.useExtension = function (extensionName) {  
1053 - _parseExtension(extensionName);  
1054 - };  
1055 -  
1056 - /**  
1057 - * Set the flavor THIS converter should use  
1058 - * @param {string} name  
1059 - */  
1060 - this.setFlavor = function (name) {  
1061 - if (flavor.hasOwnProperty(name)) {  
1062 - var preset = flavor[name];  
1063 - for (var option in preset) {  
1064 - if (preset.hasOwnProperty(option)) {  
1065 - options[option] = preset[option];  
1066 - }  
1067 - }  
1068 - }  
1069 - };  
1070 -  
1071 - /**  
1072 - * Remove an extension from THIS converter.  
1073 - * Note: This is a costly operation. It's better to initialize a new converter  
1074 - * and specify the extensions you wish to use  
1075 - * @param {Array} extension  
1076 - */  
1077 - this.removeExtension = function (extension) {  
1078 - if (!showdown.helper.isArray(extension)) {  
1079 - extension = [extension];  
1080 - }  
1081 - for (var a = 0; a < extension.length; ++a) {  
1082 - var ext = extension[a];  
1083 - for (var i = 0; i < langExtensions.length; ++i) {  
1084 - if (langExtensions[i] === ext) {  
1085 - langExtensions[i].splice(i, 1);  
1086 - }  
1087 - }  
1088 - for (var ii = 0; ii < outputModifiers.length; ++i) {  
1089 - if (outputModifiers[ii] === ext) {  
1090 - outputModifiers[ii].splice(i, 1);  
1091 - }  
1092 - }  
1093 - }  
1094 - };  
1095 -  
1096 - /**  
1097 - * Get all extension of THIS converter  
1098 - * @returns {{language: Array, output: Array}}  
1099 - */  
1100 - this.getAllExtensions = function () {  
1101 - return {  
1102 - language: langExtensions,  
1103 - output: outputModifiers  
1104 - };  
1105 - };  
1106 -};  
1107 -  
1108 -/**  
1109 - * Turn Markdown link shortcuts into XHTML <a> tags.  
1110 - */  
1111 -showdown.subParser('anchors', function (text, options, globals) {  
1112 - 'use strict';  
1113 -  
1114 - text = globals.converter._dispatch('anchors.before', text, options, globals);  
1115 -  
1116 - var writeAnchorTag = function (wholeMatch, m1, m2, m3, m4, m5, m6, m7) {  
1117 - if (showdown.helper.isUndefined(m7)) {  
1118 - m7 = '';  
1119 - }  
1120 - wholeMatch = m1;  
1121 - var linkText = m2,  
1122 - linkId = m3.toLowerCase(),  
1123 - url = m4,  
1124 - title = m7;  
1125 -  
1126 - if (!url) {  
1127 - if (!linkId) {  
1128 - // lower-case and turn embedded newlines into spaces  
1129 - linkId = linkText.toLowerCase().replace(/ ?\n/g, ' ');  
1130 - }  
1131 - url = '#' + linkId;  
1132 -  
1133 - if (!showdown.helper.isUndefined(globals.gUrls[linkId])) {  
1134 - url = globals.gUrls[linkId];  
1135 - if (!showdown.helper.isUndefined(globals.gTitles[linkId])) {  
1136 - title = globals.gTitles[linkId];  
1137 - }  
1138 - } else {  
1139 - if (wholeMatch.search(/\(\s*\)$/m) > -1) {  
1140 - // Special case for explicit empty url  
1141 - url = '';  
1142 - } else {  
1143 - return wholeMatch;  
1144 - }  
1145 - }  
1146 - }  
1147 -  
1148 - url = showdown.helper.escapeCharacters(url, '*_', false);  
1149 - var result = '<a href="' + url + '"';  
1150 -  
1151 - if (title !== '' && title !== null) {  
1152 - title = title.replace(/"/g, '&quot;');  
1153 - title = showdown.helper.escapeCharacters(title, '*_', false);  
1154 - result += ' title="' + title + '"';  
1155 - }  
1156 -  
1157 - result += '>' + linkText + '</a>';  
1158 -  
1159 - return result;  
1160 - };  
1161 -  
1162 - // First, handle reference-style links: [link text] [id]  
1163 - /*  
1164 - text = text.replace(/  
1165 - ( // wrap whole match in $1  
1166 - \[  
1167 - (  
1168 - (?:  
1169 - \[[^\]]*\] // allow brackets nested one level  
1170 - |  
1171 - [^\[] // or anything else  
1172 - )*  
1173 - )  
1174 - \]  
1175 -  
1176 - [ ]? // one optional space  
1177 - (?:\n[ ]*)? // one optional newline followed by spaces  
1178 -  
1179 - \[  
1180 - (.*?) // id = $3  
1181 - \]  
1182 - )()()()() // pad remaining backreferences  
1183 - /g,_DoAnchors_callback);  
1184 - */  
1185 - text = text.replace(/(\[((?:\[[^\]]*]|[^\[\]])*)][ ]?(?:\n[ ]*)?\[(.*?)])()()()()/g, writeAnchorTag);  
1186 -  
1187 - //  
1188 - // Next, inline-style links: [link text](url "optional title")  
1189 - //  
1190 -  
1191 - /*  
1192 - text = text.replace(/  
1193 - ( // wrap whole match in $1  
1194 - \[  
1195 - (  
1196 - (?:  
1197 - \[[^\]]*\] // allow brackets nested one level  
1198 - |  
1199 - [^\[\]] // or anything else  
1200 - )  
1201 - )  
1202 - \]  
1203 - \( // literal paren  
1204 - [ \t]*  
1205 - () // no id, so leave $3 empty  
1206 - <?(.*?)>? // href = $4  
1207 - [ \t]*  
1208 - ( // $5  
1209 - (['"]) // quote char = $6  
1210 - (.*?) // Title = $7  
1211 - \6 // matching quote  
1212 - [ \t]* // ignore any spaces/tabs between closing quote and )  
1213 - )? // title is optional  
1214 - \)  
1215 - )  
1216 - /g,writeAnchorTag);  
1217 - */  
1218 - text = text.replace(/(\[((?:\[[^\]]*]|[^\[\]])*)]\([ \t]*()<?(.*?(?:\(.*?\).*?)?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,  
1219 - writeAnchorTag);  
1220 -  
1221 - //  
1222 - // Last, handle reference-style shortcuts: [link text]  
1223 - // These must come last in case you've also got [link test][1]  
1224 - // or [link test](/foo)  
1225 - //  
1226 -  
1227 - /*  
1228 - text = text.replace(/  
1229 - ( // wrap whole match in $1  
1230 - \[  
1231 - ([^\[\]]+) // link text = $2; can't contain '[' or ']'  
1232 - \]  
1233 - )()()()()() // pad rest of backreferences  
1234 - /g, writeAnchorTag);  
1235 - */  
1236 - text = text.replace(/(\[([^\[\]]+)])()()()()()/g, writeAnchorTag);  
1237 -  
1238 - text = globals.converter._dispatch('anchors.after', text, options, globals);  
1239 - return text;  
1240 -});  
1241 -  
1242 -showdown.subParser('autoLinks', function (text, options, globals) {  
1243 - 'use strict';  
1244 -  
1245 - text = globals.converter._dispatch('autoLinks.before', text, options, globals);  
1246 -  
1247 - var simpleURLRegex = /\b(((https?|ftp|dict):\/\/|www\.)[^'">\s]+\.[^'">\s]+)(?=\s|$)(?!["<>])/gi,  
1248 - delimUrlRegex = /<(((https?|ftp|dict):\/\/|www\.)[^'">\s]+)>/gi,  
1249 - simpleMailRegex = /(?:^|[ \n\t])([A-Za-z0-9!#$%&'*+-/=?^_`\{|}~\.]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)(?:$|[ \n\t])/gi,  
1250 - delimMailRegex = /<(?:mailto:)?([-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi;  
1251 -  
1252 - text = text.replace(delimUrlRegex, replaceLink);  
1253 - text = text.replace(delimMailRegex, replaceMail);  
1254 - // simpleURLRegex = /\b(((https?|ftp|dict):\/\/|www\.)[-.+~:?#@!$&'()*,;=[\]\w]+)\b/gi,  
1255 - // Email addresses: <address@domain.foo>  
1256 -  
1257 - if (options.simplifiedAutoLink) {  
1258 - text = text.replace(simpleURLRegex, replaceLink);  
1259 - text = text.replace(simpleMailRegex, replaceMail);  
1260 - }  
1261 -  
1262 - function replaceLink(wm, link) {  
1263 - var lnkTxt = link;  
1264 - if (/^www\./i.test(link)) {  
1265 - link = link.replace(/^www\./i, 'http://www.');  
1266 - }  
1267 - return '<a href="' + link + '">' + lnkTxt + '</a>';  
1268 - }  
1269 -  
1270 - function replaceMail(wholeMatch, m1) {  
1271 - var unescapedStr = showdown.subParser('unescapeSpecialChars')(m1);  
1272 - return showdown.subParser('encodeEmailAddress')(unescapedStr);  
1273 - }  
1274 -  
1275 - text = globals.converter._dispatch('autoLinks.after', text, options, globals);  
1276 -  
1277 - return text;  
1278 -});  
1279 -  
1280 -/**  
1281 - * These are all the transformations that form block-level  
1282 - * tags like paragraphs, headers, and list items.  
1283 - */  
1284 -showdown.subParser('blockGamut', function (text, options, globals) {  
1285 - 'use strict';  
1286 -  
1287 - text = globals.converter._dispatch('blockGamut.before', text, options, globals);  
1288 -  
1289 - // we parse blockquotes first so that we can have headings and hrs  
1290 - // inside blockquotes  
1291 - text = showdown.subParser('blockQuotes')(text, options, globals);  
1292 - text = showdown.subParser('headers')(text, options, globals);  
1293 -  
1294 - // Do Horizontal Rules:  
1295 - var key = showdown.subParser('hashBlock')('<hr />', options, globals);  
1296 - text = text.replace(/^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$/gm, key);  
1297 - text = text.replace(/^[ ]{0,2}([ ]?\-[ ]?){3,}[ \t]*$/gm, key);  
1298 - text = text.replace(/^[ ]{0,2}([ ]?_[ ]?){3,}[ \t]*$/gm, key);  
1299 -  
1300 - text = showdown.subParser('lists')(text, options, globals);  
1301 - text = showdown.subParser('codeBlocks')(text, options, globals);  
1302 - text = showdown.subParser('tables')(text, options, globals);  
1303 -  
1304 - // We already ran _HashHTMLBlocks() before, in Markdown(), but that  
1305 - // was to escape raw HTML in the original Markdown source. This time,  
1306 - // we're escaping the markup we've just created, so that we don't wrap  
1307 - // <p> tags around block-level tags.  
1308 - text = showdown.subParser('hashHTMLBlocks')(text, options, globals);  
1309 - text = showdown.subParser('paragraphs')(text, options, globals);  
1310 -  
1311 - text = globals.converter._dispatch('blockGamut.after', text, options, globals);  
1312 -  
1313 - return text;  
1314 -});  
1315 -  
1316 -showdown.subParser('blockQuotes', function (text, options, globals) {  
1317 - 'use strict';  
1318 -  
1319 - text = globals.converter._dispatch('blockQuotes.before', text, options, globals);  
1320 - /*  
1321 - text = text.replace(/  
1322 - ( // Wrap whole match in $1  
1323 - (  
1324 - ^[ \t]*>[ \t]? // '>' at the start of a line  
1325 - .+\n // rest of the first line  
1326 - (.+\n)* // subsequent consecutive lines  
1327 - \n* // blanks  
1328 - )+  
1329 - )  
1330 - /gm, function(){...});  
1331 - */  
1332 -  
1333 - text = text.replace(/((^[ \t]{0,3}>[ \t]?.+\n(.+\n)*\n*)+)/gm, function (wholeMatch, m1) {  
1334 - var bq = m1;  
1335 -  
1336 - // attacklab: hack around Konqueror 3.5.4 bug:  
1337 - // "----------bug".replace(/^-/g,"") == "bug"  
1338 - bq = bq.replace(/^[ \t]*>[ \t]?/gm, '~0'); // trim one level of quoting  
1339 -  
1340 - // attacklab: clean up hack  
1341 - bq = bq.replace(/~0/g, '');  
1342 -  
1343 - bq = bq.replace(/^[ \t]+$/gm, ''); // trim whitespace-only lines  
1344 - bq = showdown.subParser('githubCodeBlocks')(bq, options, globals);  
1345 - bq = showdown.subParser('blockGamut')(bq, options, globals); // recurse  
1346 -  
1347 - bq = bq.replace(/(^|\n)/g, '$1 ');  
1348 - // These leading spaces screw with <pre> content, so we need to fix that:  
1349 - bq = bq.replace(/(\s*<pre>[^\r]+?<\/pre>)/gm, function (wholeMatch, m1) {  
1350 - var pre = m1;  
1351 - // attacklab: hack around Konqueror 3.5.4 bug:  
1352 - pre = pre.replace(/^ /mg, '~0');  
1353 - pre = pre.replace(/~0/g, '');  
1354 - return pre;  
1355 - });  
1356 -  
1357 - return showdown.subParser('hashBlock')('<blockquote>\n' + bq + '\n</blockquote>', options, globals);  
1358 - });  
1359 -  
1360 - text = globals.converter._dispatch('blockQuotes.after', text, options, globals);  
1361 - return text;  
1362 -});  
1363 -  
1364 -/**  
1365 - * Process Markdown `<pre><code>` blocks.  
1366 - */  
1367 -showdown.subParser('codeBlocks', function (text, options, globals) {  
1368 - 'use strict';  
1369 -  
1370 - text = globals.converter._dispatch('codeBlocks.before', text, options, globals);  
1371 - /*  
1372 - text = text.replace(text,  
1373 - /(?:\n\n|^)  
1374 - ( // $1 = the code block -- one or more lines, starting with a space/tab  
1375 - (?:  
1376 - (?:[ ]{4}|\t) // Lines must start with a tab or a tab-width of spaces - attacklab: g_tab_width  
1377 - .*\n+  
1378 - )+  
1379 - )  
1380 - (\n*[ ]{0,3}[^ \t\n]|(?=~0)) // attacklab: g_tab_width  
1381 - /g,function(){...});  
1382 - */  
1383 -  
1384 - // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug  
1385 - text += '~0';  
1386 -  
1387 - var pattern = /(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g;  
1388 - text = text.replace(pattern, function (wholeMatch, m1, m2) {  
1389 - var codeblock = m1,  
1390 - nextChar = m2,  
1391 - end = '\n';  
1392 -  
1393 - codeblock = showdown.subParser('outdent')(codeblock);  
1394 - codeblock = showdown.subParser('encodeCode')(codeblock);  
1395 - codeblock = showdown.subParser('detab')(codeblock);  
1396 - codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines  
1397 - codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing newlines  
1398 -  
1399 - if (options.omitExtraWLInCodeBlocks) {  
1400 - end = '';  
1401 - }  
1402 -  
1403 - codeblock = '<pre><code>' + codeblock + end + '</code></pre>';  
1404 -  
1405 - return showdown.subParser('hashBlock')(codeblock, options, globals) + nextChar;  
1406 - });  
1407 -  
1408 - // attacklab: strip sentinel  
1409 - text = text.replace(/~0/, '');  
1410 -  
1411 - text = globals.converter._dispatch('codeBlocks.after', text, options, globals);  
1412 - return text;  
1413 -});  
1414 -  
1415 -/**  
1416 - *  
1417 - * * Backtick quotes are used for <code></code> spans.  
1418 - *  
1419 - * * You can use multiple backticks as the delimiters if you want to  
1420 - * include literal backticks in the code span. So, this input:  
1421 - *  
1422 - * Just type ``foo `bar` baz`` at the prompt.  
1423 - *  
1424 - * Will translate to:  
1425 - *  
1426 - * <p>Just type <code>foo `bar` baz</code> at the prompt.</p>  
1427 - *  
1428 - * There's no arbitrary limit to the number of backticks you  
1429 - * can use as delimters. If you need three consecutive backticks  
1430 - * in your code, use four for delimiters, etc.  
1431 - *  
1432 - * * You can use spaces to get literal backticks at the edges:  
1433 - *  
1434 - * ... type `` `bar` `` ...  
1435 - *  
1436 - * Turns to:  
1437 - *  
1438 - * ... type <code>`bar`</code> ...  
1439 - */  
1440 -showdown.subParser('codeSpans', function (text, options, globals) {  
1441 - 'use strict';  
1442 -  
1443 - text = globals.converter._dispatch('codeSpans.before', text, options, globals);  
1444 -  
1445 - /*  
1446 - text = text.replace(/  
1447 - (^|[^\\]) // Character before opening ` can't be a backslash  
1448 - (`+) // $2 = Opening run of `  
1449 - ( // $3 = The code block  
1450 - [^\r]*?  
1451 - [^`] // attacklab: work around lack of lookbehind  
1452 - )  
1453 - \2 // Matching closer  
1454 - (?!`)  
1455 - /gm, function(){...});  
1456 - */  
1457 -  
1458 - if (typeof(text) === 'undefined') {  
1459 - text = '';  
1460 - }  
1461 - text = text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,  
1462 - function (wholeMatch, m1, m2, m3) {  
1463 - var c = m3;  
1464 - c = c.replace(/^([ \t]*)/g, ''); // leading whitespace  
1465 - c = c.replace(/[ \t]*$/g, ''); // trailing whitespace  
1466 - c = showdown.subParser('encodeCode')(c);  
1467 - return m1 + '<code>' + c + '</code>';  
1468 - }  
1469 - );  
1470 -  
1471 - text = globals.converter._dispatch('codeSpans.after', text, options, globals);  
1472 - return text;  
1473 -});  
1474 -  
1475 -/**  
1476 - * Convert all tabs to spaces  
1477 - */  
1478 -showdown.subParser('detab', function (text) {  
1479 - 'use strict';  
1480 -  
1481 - // expand first n-1 tabs  
1482 - text = text.replace(/\t(?=\t)/g, ' '); // g_tab_width  
1483 -  
1484 - // replace the nth with two sentinels  
1485 - text = text.replace(/\t/g, '~A~B');  
1486 -  
1487 - // use the sentinel to anchor our regex so it doesn't explode  
1488 - text = text.replace(/~B(.+?)~A/g, function (wholeMatch, m1) {  
1489 - var leadingText = m1,  
1490 - numSpaces = 4 - leadingText.length % 4; // g_tab_width  
1491 -  
1492 - // there *must* be a better way to do this:  
1493 - for (var i = 0; i < numSpaces; i++) {  
1494 - leadingText += ' ';  
1495 - }  
1496 -  
1497 - return leadingText;  
1498 - });  
1499 -  
1500 - // clean up sentinels  
1501 - text = text.replace(/~A/g, ' '); // g_tab_width  
1502 - text = text.replace(/~B/g, '');  
1503 -  
1504 - return text;  
1505 -  
1506 -});  
1507 -  
1508 -/**  
1509 - * Smart processing for ampersands and angle brackets that need to be encoded.  
1510 - */  
1511 -showdown.subParser('encodeAmpsAndAngles', function (text) {  
1512 - 'use strict';  
1513 - // Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:  
1514 - // http://bumppo.net/projects/amputator/  
1515 - text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g, '&amp;');  
1516 -  
1517 - // Encode naked <'s  
1518 - text = text.replace(/<(?![a-z\/?\$!])/gi, '&lt;');  
1519 -  
1520 - return text;  
1521 -});  
1522 -  
1523 -/**  
1524 - * Returns the string, with after processing the following backslash escape sequences.  
1525 - *  
1526 - * attacklab: The polite way to do this is with the new escapeCharacters() function:  
1527 - *  
1528 - * text = escapeCharacters(text,"\\",true);  
1529 - * text = escapeCharacters(text,"`*_{}[]()>#+-.!",true);  
1530 - *  
1531 - * ...but we're sidestepping its use of the (slow) RegExp constructor  
1532 - * as an optimization for Firefox. This function gets called a LOT.  
1533 - */  
1534 -showdown.subParser('encodeBackslashEscapes', function (text) {  
1535 - 'use strict';  
1536 - text = text.replace(/\\(\\)/g, showdown.helper.escapeCharactersCallback);  
1537 - text = text.replace(/\\([`*_{}\[\]()>#+-.!])/g, showdown.helper.escapeCharactersCallback);  
1538 - return text;  
1539 -});  
1540 -  
1541 -/**  
1542 - * Encode/escape certain characters inside Markdown code runs.  
1543 - * The point is that in code, these characters are literals,  
1544 - * and lose their special Markdown meanings.  
1545 - */  
1546 -showdown.subParser('encodeCode', function (text) {  
1547 - 'use strict';  
1548 -  
1549 - // Encode all ampersands; HTML entities are not  
1550 - // entities within a Markdown code span.  
1551 - text = text.replace(/&/g, '&amp;');  
1552 -  
1553 - // Do the angle bracket song and dance:  
1554 - text = text.replace(/</g, '&lt;');  
1555 - text = text.replace(/>/g, '&gt;');  
1556 -  
1557 - // Now, escape characters that are magic in Markdown:  
1558 - text = showdown.helper.escapeCharacters(text, '*_{}[]\\', false);  
1559 -  
1560 - // jj the line above breaks this:  
1561 - //---  
1562 - //* Item  
1563 - // 1. Subitem  
1564 - // special char: *  
1565 - // ---  
1566 -  
1567 - return text;  
1568 -});  
1569 -  
1570 -/**  
1571 - * Input: an email address, e.g. "foo@example.com"  
1572 - *  
1573 - * Output: the email address as a mailto link, with each character  
1574 - * of the address encoded as either a decimal or hex entity, in  
1575 - * the hopes of foiling most address harvesting spam bots. E.g.:  
1576 - *  
1577 - * <a href="&#x6D;&#97;&#105;&#108;&#x74;&#111;:&#102;&#111;&#111;&#64;&#101;  
1578 - * x&#x61;&#109;&#x70;&#108;&#x65;&#x2E;&#99;&#111;&#109;">&#102;&#111;&#111;  
1579 - * &#64;&#101;x&#x61;&#109;&#x70;&#108;&#x65;&#x2E;&#99;&#111;&#109;</a>  
1580 - *  
1581 - * Based on a filter by Matthew Wickline, posted to the BBEdit-Talk  
1582 - * mailing list: <http://tinyurl.com/yu7ue>  
1583 - *  
1584 - */  
1585 -showdown.subParser('encodeEmailAddress', function (addr) {  
1586 - 'use strict';  
1587 -  
1588 - var encode = [  
1589 - function (ch) {  
1590 - return '&#' + ch.charCodeAt(0) + ';';  
1591 - },  
1592 - function (ch) {  
1593 - return '&#x' + ch.charCodeAt(0).toString(16) + ';';  
1594 - },  
1595 - function (ch) {  
1596 - return ch;  
1597 - }  
1598 - ];  
1599 -  
1600 - addr = 'mailto:' + addr;  
1601 -  
1602 - addr = addr.replace(/./g, function (ch) {  
1603 - if (ch === '@') {  
1604 - // this *must* be encoded. I insist.  
1605 - ch = encode[Math.floor(Math.random() * 2)](ch);  
1606 - } else if (ch !== ':') {  
1607 - // leave ':' alone (to spot mailto: later)  
1608 - var r = Math.random();  
1609 - // roughly 10% raw, 45% hex, 45% dec  
1610 - ch = (  
1611 - r > 0.9 ? encode[2](ch) : r > 0.45 ? encode[1](ch) : encode[0](ch)  
1612 - );  
1613 - }  
1614 - return ch;  
1615 - });  
1616 -  
1617 - addr = '<a href="' + addr + '">' + addr + '</a>';  
1618 - addr = addr.replace(/">.+:/g, '">'); // strip the mailto: from the visible part  
1619 -  
1620 - return addr;  
1621 -});  
1622 -  
1623 -/**  
1624 - * Within tags -- meaning between < and > -- encode [\ ` * _] so they  
1625 - * don't conflict with their use in Markdown for code, italics and strong.  
1626 - */  
1627 -showdown.subParser('escapeSpecialCharsWithinTagAttributes', function (text) {  
1628 - 'use strict';  
1629 -  
1630 - // Build a regex to find HTML tags and comments. See Friedl's  
1631 - // "Mastering Regular Expressions", 2nd Ed., pp. 200-201.  
1632 - var regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|<!(--.*?--\s*)+>)/gi;  
1633 -  
1634 - text = text.replace(regex, function (wholeMatch) {  
1635 - var tag = wholeMatch.replace(/(.)<\/?code>(?=.)/g, '$1`');  
1636 - tag = showdown.helper.escapeCharacters(tag, '\\`*_', false);  
1637 - return tag;  
1638 - });  
1639 -  
1640 - return text;  
1641 -});  
1642 -  
1643 -/**  
1644 - * Handle github codeblocks prior to running HashHTML so that  
1645 - * HTML contained within the codeblock gets escaped properly  
1646 - * Example:  
1647 - * ```ruby  
1648 - * def hello_world(x)  
1649 - * puts "Hello, #{x}"  
1650 - * end  
1651 - * ```  
1652 - */  
1653 -showdown.subParser('githubCodeBlocks', function (text, options, globals) {  
1654 - 'use strict';  
1655 -  
1656 - // early exit if option is not enabled  
1657 - if (!options.ghCodeBlocks) {  
1658 - return text;  
1659 - }  
1660 -  
1661 - text = globals.converter._dispatch('githubCodeBlocks.before', text, options, globals);  
1662 -  
1663 - text += '~0';  
1664 -  
1665 - text = text.replace(/(?:^|\n)```(.*)\n([\s\S]*?)\n```/g, function (wholeMatch, language, codeblock) {  
1666 - var end = (options.omitExtraWLInCodeBlocks) ? '' : '\n';  
1667 -  
1668 - // First parse the github code block  
1669 - codeblock = showdown.subParser('encodeCode')(codeblock);  
1670 - codeblock = showdown.subParser('detab')(codeblock);  
1671 - codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines  
1672 - codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing whitespace  
1673 -  
1674 - codeblock = '<pre><code' + (language ? ' class="' + language + ' language-' + language + '"' : '') + '>' + codeblock + end + '</code></pre>';  
1675 -  
1676 - codeblock = showdown.subParser('hashBlock')(codeblock, options, globals);  
1677 -  
1678 - // Since GHCodeblocks can be false positives, we need to  
1679 - // store the primitive text and the parsed text in a global var,  
1680 - // and then return a token  
1681 - return '\n\n~G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\n\n';  
1682 - });  
1683 -  
1684 - // attacklab: strip sentinel  
1685 - text = text.replace(/~0/, '');  
1686 -  
1687 - return globals.converter._dispatch('githubCodeBlocks.after', text, options, globals);  
1688 -});  
1689 -  
1690 -showdown.subParser('hashBlock', function (text, options, globals) {  
1691 - 'use strict';  
1692 - text = text.replace(/(^\n+|\n+$)/g, '');  
1693 - return '\n\n~K' + (globals.gHtmlBlocks.push(text) - 1) + 'K\n\n';  
1694 -});  
1695 -  
1696 -showdown.subParser('hashElement', function (text, options, globals) {  
1697 - 'use strict';  
1698 -  
1699 - return function (wholeMatch, m1) {  
1700 - var blockText = m1;  
1701 -  
1702 - // Undo double lines  
1703 - blockText = blockText.replace(/\n\n/g, '\n');  
1704 - blockText = blockText.replace(/^\n/, '');  
1705 -  
1706 - // strip trailing blank lines  
1707 - blockText = blockText.replace(/\n+$/g, '');  
1708 -  
1709 - // Replace the element text with a marker ("~KxK" where x is its key)  
1710 - blockText = '\n\n~K' + (globals.gHtmlBlocks.push(blockText) - 1) + 'K\n\n';  
1711 -  
1712 - return blockText;  
1713 - };  
1714 -});  
1715 -  
1716 -showdown.subParser('hashHTMLBlocks', function (text, options, globals) {  
1717 - 'use strict';  
1718 -  
1719 - var blockTags = [  
1720 - 'pre',  
1721 - 'div',  
1722 - 'h1',  
1723 - 'h2',  
1724 - 'h3',  
1725 - 'h4',  
1726 - 'h5',  
1727 - 'h6',  
1728 - 'blockquote',  
1729 - 'table',  
1730 - 'dl',  
1731 - 'ol',  
1732 - 'ul',  
1733 - 'script',  
1734 - 'noscript',  
1735 - 'form',  
1736 - 'fieldset',  
1737 - 'iframe',  
1738 - 'math',  
1739 - 'style',  
1740 - 'section',  
1741 - 'header',  
1742 - 'footer',  
1743 - 'nav',  
1744 - 'article',  
1745 - 'aside',  
1746 - 'address',  
1747 - 'audio',  
1748 - 'canvas',  
1749 - 'figure',  
1750 - 'hgroup',  
1751 - 'output',  
1752 - 'video',  
1753 - 'p'  
1754 - ],  
1755 - repFunc = function (wholeMatch, match, left, right) {  
1756 - var txt = wholeMatch;  
1757 - // check if this html element is marked as markdown  
1758 - // if so, it's contents should be parsed as markdown  
1759 - if (left.search(/\bmarkdown\b/) !== -1) {  
1760 - txt = left + globals.converter.makeHtml(match) + right;  
1761 - }  
1762 - return '\n\n~K' + (globals.gHtmlBlocks.push(txt) - 1) + 'K\n\n';  
1763 - };  
1764 -  
1765 - for (var i = 0; i < blockTags.length; ++i) {  
1766 - text = showdown.helper.replaceRecursiveRegExp(text, repFunc, '^(?: |\\t){0,3}<' + blockTags[i] + '\\b[^>]*>', '</' + blockTags[i] + '>', 'gim');  
1767 - }  
1768 -  
1769 - // HR SPECIAL CASE  
1770 - text = text.replace(/(\n[ ]{0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,  
1771 - showdown.subParser('hashElement')(text, options, globals));  
1772 -  
1773 - // Special case for standalone HTML comments:  
1774 - text = text.replace(/(<!--[\s\S]*?-->)/g,  
1775 - showdown.subParser('hashElement')(text, options, globals));  
1776 -  
1777 - // PHP and ASP-style processor instructions (<?...?> and <%...%>)  
1778 - text = text.replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,  
1779 - showdown.subParser('hashElement')(text, options, globals));  
1780 - return text;  
1781 -});  
1782 -  
1783 -/**  
1784 - * Hash span elements that should not be parsed as markdown  
1785 - */  
1786 -showdown.subParser('hashHTMLSpans', function (text, config, globals) {  
1787 - 'use strict';  
1788 -  
1789 - var matches = showdown.helper.matchRecursiveRegExp(text, '<code\\b[^>]*>', '</code>', 'gi');  
1790 -  
1791 - for (var i = 0; i < matches.length; ++i) {  
1792 - text = text.replace(matches[i][0], '~L' + (globals.gHtmlSpans.push(matches[i][0]) - 1) + 'L');  
1793 - }  
1794 - return text;  
1795 -});  
1796 -  
1797 -/**  
1798 - * Unhash HTML spans  
1799 - */  
1800 -showdown.subParser('unhashHTMLSpans', function (text, config, globals) {  
1801 - 'use strict';  
1802 -  
1803 - for (var i = 0; i < globals.gHtmlSpans.length; ++i) {  
1804 - text = text.replace('~L' + i + 'L', globals.gHtmlSpans[i]);  
1805 - }  
1806 -  
1807 - return text;  
1808 -});  
1809 -  
1810 -/**  
1811 - * Hash span elements that should not be parsed as markdown  
1812 - */  
1813 -showdown.subParser('hashPreCodeTags', function (text, config, globals) {  
1814 - 'use strict';  
1815 -  
1816 - var repFunc = function (wholeMatch, match, left, right) {  
1817 - // encode html entities  
1818 - var codeblock = left + showdown.subParser('encodeCode')(match) + right;  
1819 - return '\n\n~G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\n\n';  
1820 - };  
1821 -  
1822 - text = showdown.helper.replaceRecursiveRegExp(text, repFunc, '^(?: |\\t){0,3}<pre\\b[^>]*>\\s*<code\\b[^>]*>', '^(?: |\\t){0,3}</code>\\s*</pre>', 'gim');  
1823 - return text;  
1824 -});  
1825 -  
1826 -showdown.subParser('headers', function (text, options, globals) {  
1827 - 'use strict';  
1828 -  
1829 - text = globals.converter._dispatch('headers.before', text, options, globals);  
1830 -  
1831 - var prefixHeader = options.prefixHeaderId,  
1832 - headerLevelStart = (isNaN(parseInt(options.headerLevelStart))) ? 1 : parseInt(options.headerLevelStart),  
1833 -  
1834 - // Set text-style headers:  
1835 - // Header 1  
1836 - // ========  
1837 - //  
1838 - // Header 2  
1839 - // --------  
1840 - //  
1841 - setextRegexH1 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n={2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n=+[ \t]*\n+/gm,  
1842 - setextRegexH2 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n-{2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n-+[ \t]*\n+/gm;  
1843 -  
1844 - text = text.replace(setextRegexH1, function (wholeMatch, m1) {  
1845 -  
1846 - var spanGamut = showdown.subParser('spanGamut')(m1, options, globals),  
1847 - hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"',  
1848 - hLevel = headerLevelStart,  
1849 - hashBlock = '<h' + hLevel + hID + '>' + spanGamut + '</h' + hLevel + '>';  
1850 - return showdown.subParser('hashBlock')(hashBlock, options, globals);  
1851 - });  
1852 -  
1853 - text = text.replace(setextRegexH2, function (matchFound, m1) {  
1854 - var spanGamut = showdown.subParser('spanGamut')(m1, options, globals),  
1855 - hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"',  
1856 - hLevel = headerLevelStart + 1,  
1857 - hashBlock = '<h' + hLevel + hID + '>' + spanGamut + '</h' + hLevel + '>';  
1858 - return showdown.subParser('hashBlock')(hashBlock, options, globals);  
1859 - });  
1860 -  
1861 - // atx-style headers:  
1862 - // # Header 1  
1863 - // ## Header 2  
1864 - // ## Header 2 with closing hashes ##  
1865 - // ...  
1866 - // ###### Header 6  
1867 - //  
1868 - text = text.replace(/^(#{1,6})[ \t]*(.+?)[ \t]*#*\n+/gm, function (wholeMatch, m1, m2) {  
1869 - var span = showdown.subParser('spanGamut')(m2, options, globals),  
1870 - hID = (options.noHeaderId) ? '' : ' id="' + headerId(m2) + '"',  
1871 - hLevel = headerLevelStart - 1 + m1.length,  
1872 - header = '<h' + hLevel + hID + '>' + span + '</h' + hLevel + '>';  
1873 -  
1874 - return showdown.subParser('hashBlock')(header, options, globals);  
1875 - });  
1876 -  
1877 - function headerId(m) {  
1878 - var title, escapedId = m.replace(/[^\w]/g, '').toLowerCase();  
1879 -  
1880 - if (globals.hashLinkCounts[escapedId]) {  
1881 - title = escapedId + '-' + (globals.hashLinkCounts[escapedId]++);  
1882 - } else {  
1883 - title = escapedId;  
1884 - globals.hashLinkCounts[escapedId] = 1;  
1885 - }  
1886 -  
1887 - // Prefix id to prevent causing inadvertent pre-existing style matches.  
1888 - if (prefixHeader === true) {  
1889 - prefixHeader = 'section';  
1890 - }  
1891 -  
1892 - if (showdown.helper.isString(prefixHeader)) {  
1893 - return prefixHeader + title;  
1894 - }  
1895 - return title;  
1896 - }  
1897 -  
1898 - text = globals.converter._dispatch('headers.after', text, options, globals);  
1899 - return text;  
1900 -});  
1901 -  
1902 -/**  
1903 - * Turn Markdown image shortcuts into <img> tags.  
1904 - */  
1905 -showdown.subParser('images', function (text, options, globals) {  
1906 - 'use strict';  
1907 -  
1908 - text = globals.converter._dispatch('images.before', text, options, globals);  
1909 -  
1910 - var inlineRegExp = /!\[(.*?)]\s?\([ \t]*()<?(\S+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(['"])(.*?)\6[ \t]*)?\)/g,  
1911 - referenceRegExp = /!\[([^\]]*?)] ?(?:\n *)?\[(.*?)]()()()()()/g;  
1912 -  
1913 - function writeImageTag (wholeMatch, altText, linkId, url, width, height, m5, title) {  
1914 -  
1915 - var gUrls = globals.gUrls,  
1916 - gTitles = globals.gTitles,  
1917 - gDims = globals.gDimensions;  
1918 -  
1919 - linkId = linkId.toLowerCase();  
1920 -  
1921 - if (!title) {  
1922 - title = '';  
1923 - }  
1924 -  
1925 - if (url === '' || url === null) {  
1926 - if (linkId === '' || linkId === null) {  
1927 - // lower-case and turn embedded newlines into spaces  
1928 - linkId = altText.toLowerCase().replace(/ ?\n/g, ' ');  
1929 - }  
1930 - url = '#' + linkId;  
1931 -  
1932 - if (!showdown.helper.isUndefined(gUrls[linkId])) {  
1933 - url = gUrls[linkId];  
1934 - if (!showdown.helper.isUndefined(gTitles[linkId])) {  
1935 - title = gTitles[linkId];  
1936 - }  
1937 - if (!showdown.helper.isUndefined(gDims[linkId])) {  
1938 - width = gDims[linkId].width;  
1939 - height = gDims[linkId].height;  
1940 - }  
1941 - } else {  
1942 - return wholeMatch;  
1943 - }  
1944 - }  
1945 -  
1946 - altText = altText.replace(/"/g, '&quot;');  
1947 - altText = showdown.helper.escapeCharacters(altText, '*_', false);  
1948 - url = showdown.helper.escapeCharacters(url, '*_', false);  
1949 - var result = '<img src="' + url + '" alt="' + altText + '"';  
1950 -  
1951 - if (title) {  
1952 - title = title.replace(/"/g, '&quot;');  
1953 - title = showdown.helper.escapeCharacters(title, '*_', false);  
1954 - result += ' title="' + title + '"';  
1955 - }  
1956 -  
1957 - if (width && height) {  
1958 - width = (width === '*') ? 'auto' : width;  
1959 - height = (height === '*') ? 'auto' : height;  
1960 -  
1961 - result += ' width="' + width + '"';  
1962 - result += ' height="' + height + '"';  
1963 - }  
1964 -  
1965 - result += ' />';  
1966 - return result;  
1967 - }  
1968 -  
1969 - // First, handle reference-style labeled images: ![alt text][id]  
1970 - text = text.replace(referenceRegExp, writeImageTag);  
1971 -  
1972 - // Next, handle inline images: ![alt text](url =<width>x<height> "optional title")  
1973 - text = text.replace(inlineRegExp, writeImageTag);  
1974 -  
1975 - text = globals.converter._dispatch('images.after', text, options, globals);  
1976 - return text;  
1977 -});  
1978 -  
1979 -showdown.subParser('italicsAndBold', function (text, options, globals) {  
1980 - 'use strict';  
1981 -  
1982 - text = globals.converter._dispatch('italicsAndBold.before', text, options, globals);  
1983 -  
1984 - if (options.literalMidWordUnderscores) {  
1985 - //underscores  
1986 - // Since we are consuming a \s character, we need to add it  
1987 - text = text.replace(/(^|\s|>|\b)__(?=\S)([\s\S]+?)__(?=\b|<|\s|$)/gm, '$1<strong>$2</strong>');  
1988 - text = text.replace(/(^|\s|>|\b)_(?=\S)([\s\S]+?)_(?=\b|<|\s|$)/gm, '$1<em>$2</em>');  
1989 - //asterisks  
1990 - text = text.replace(/(\*\*)(?=\S)([^\r]*?\S[*]*)\1/g, '<strong>$2</strong>');  
1991 - text = text.replace(/(\*)(?=\S)([^\r]*?\S)\1/g, '<em>$2</em>');  
1992 -  
1993 - } else {  
1994 - // <strong> must go first:  
1995 - text = text.replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g, '<strong>$2</strong>');  
1996 - text = text.replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g, '<em>$2</em>');  
1997 - }  
1998 -  
1999 - text = globals.converter._dispatch('italicsAndBold.after', text, options, globals);  
2000 - return text;  
2001 -});  
2002 -  
2003 -/**  
2004 - * Form HTML ordered (numbered) and unordered (bulleted) lists.  
2005 - */  
2006 -showdown.subParser('lists', function (text, options, globals) {  
2007 - 'use strict';  
2008 -  
2009 - text = globals.converter._dispatch('lists.before', text, options, globals);  
2010 - /**  
2011 - * Process the contents of a single ordered or unordered list, splitting it  
2012 - * into individual list items.  
2013 - * @param {string} listStr  
2014 - * @param {boolean} trimTrailing  
2015 - * @returns {string}  
2016 - */  
2017 - function processListItems (listStr, trimTrailing) {  
2018 - // The $g_list_level global keeps track of when we're inside a list.  
2019 - // Each time we enter a list, we increment it; when we leave a list,  
2020 - // we decrement. If it's zero, we're not in a list anymore.  
2021 - //  
2022 - // We do this because when we're not inside a list, we want to treat  
2023 - // something like this:  
2024 - //  
2025 - // I recommend upgrading to version  
2026 - // 8. Oops, now this line is treated  
2027 - // as a sub-list.  
2028 - //  
2029 - // As a single paragraph, despite the fact that the second line starts  
2030 - // with a digit-period-space sequence.  
2031 - //  
2032 - // Whereas when we're inside a list (or sub-list), that line will be  
2033 - // treated as the start of a sub-list. What a kludge, huh? This is  
2034 - // an aspect of Markdown's syntax that's hard to parse perfectly  
2035 - // without resorting to mind-reading. Perhaps the solution is to  
2036 - // change the syntax rules such that sub-lists must start with a  
2037 - // starting cardinal number; e.g. "1." or "a.".  
2038 - globals.gListLevel++;  
2039 -  
2040 - // trim trailing blank lines:  
2041 - listStr = listStr.replace(/\n{2,}$/, '\n');  
2042 -  
2043 - // attacklab: add sentinel to emulate \z  
2044 - listStr += '~0';  
2045 -  
2046 - var rgx = /(\n)?(^[ \t]*)([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(~0|\2([*+-]|\d+[.])[ \t]+))/gm,  
2047 - isParagraphed = (/\n[ \t]*\n(?!~0)/.test(listStr));  
2048 -  
2049 - listStr = listStr.replace(rgx, function (wholeMatch, m1, m2, m3, m4, taskbtn, checked) {  
2050 - checked = (checked && checked.trim() !== '');  
2051 - var item = showdown.subParser('outdent')(m4, options, globals),  
2052 - bulletStyle = '';  
2053 -  
2054 - // Support for github tasklists  
2055 - if (taskbtn && options.tasklists) {  
2056 - bulletStyle = ' class="task-list-item" style="list-style-type: none;"';  
2057 - item = item.replace(/^[ \t]*\[(x|X| )?]/m, function () {  
2058 - var otp = '<input type="checkbox" disabled style="margin: 0px 0.35em 0.25em -1.6em; vertical-align: middle;"';  
2059 - if (checked) {  
2060 - otp += ' checked';  
2061 - }  
2062 - otp += '>';  
2063 - return otp;  
2064 - });  
2065 - }  
2066 - // m1 - Leading line or  
2067 - // Has a double return (multi paragraph) or  
2068 - // Has sublist  
2069 - if (m1 || (item.search(/\n{2,}/) > -1)) {  
2070 - item = showdown.subParser('githubCodeBlocks')(item, options, globals);  
2071 - item = showdown.subParser('blockGamut')(item, options, globals);  
2072 - } else {  
2073 - // Recursion for sub-lists:  
2074 - item = showdown.subParser('lists')(item, options, globals);  
2075 - item = item.replace(/\n$/, ''); // chomp(item)  
2076 - if (isParagraphed) {  
2077 - item = showdown.subParser('paragraphs')(item, options, globals);  
2078 - } else {  
2079 - item = showdown.subParser('spanGamut')(item, options, globals);  
2080 - }  
2081 - }  
2082 - item = '\n<li' + bulletStyle + '>' + item + '</li>\n';  
2083 - return item;  
2084 - });  
2085 -  
2086 - // attacklab: strip sentinel  
2087 - listStr = listStr.replace(/~0/g, '');  
2088 -  
2089 - globals.gListLevel--;  
2090 -  
2091 - if (trimTrailing) {  
2092 - listStr = listStr.replace(/\s+$/, '');  
2093 - }  
2094 -  
2095 - return listStr;  
2096 - }  
2097 -  
2098 - /**  
2099 - * Check and parse consecutive lists (better fix for issue #142)  
2100 - * @param {string} list  
2101 - * @param {string} listType  
2102 - * @param {boolean} trimTrailing  
2103 - * @returns {string}  
2104 - */  
2105 - function parseConsecutiveLists(list, listType, trimTrailing) {  
2106 - // check if we caught 2 or more consecutive lists by mistake  
2107 - // we use the counterRgx, meaning if listType is UL we look for UL and vice versa  
2108 - var counterRxg = (listType === 'ul') ? /^ {0,2}\d+\.[ \t]/gm : /^ {0,2}[*+-][ \t]/gm,  
2109 - subLists = [],  
2110 - result = '';  
2111 -  
2112 - if (list.search(counterRxg) !== -1) {  
2113 - (function parseCL(txt) {  
2114 - var pos = txt.search(counterRxg);  
2115 - if (pos !== -1) {  
2116 - // slice  
2117 - result += '\n\n<' + listType + '>' + processListItems(txt.slice(0, pos), !!trimTrailing) + '</' + listType + '>\n\n';  
2118 -  
2119 - // invert counterType and listType  
2120 - listType = (listType === 'ul') ? 'ol' : 'ul';  
2121 - counterRxg = (listType === 'ul') ? /^ {0,2}\d+\.[ \t]/gm : /^ {0,2}[*+-][ \t]/gm;  
2122 -  
2123 - //recurse  
2124 - parseCL(txt.slice(pos));  
2125 - } else {  
2126 - result += '\n\n<' + listType + '>' + processListItems(txt, !!trimTrailing) + '</' + listType + '>\n\n';  
2127 - }  
2128 - })(list);  
2129 - for (var i = 0; i < subLists.length; ++i) {  
2130 -  
2131 - }  
2132 - } else {  
2133 - result = '\n\n<' + listType + '>' + processListItems(list, !!trimTrailing) + '</' + listType + '>\n\n';  
2134 - }  
2135 -  
2136 - return result;  
2137 - }  
2138 -  
2139 - // attacklab: add sentinel to hack around khtml/safari bug:  
2140 - // http://bugs.webkit.org/show_bug.cgi?id=11231  
2141 - text += '~0';  
2142 -  
2143 - // Re-usable pattern to match any entire ul or ol list:  
2144 - var wholeList = /^(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;  
2145 -  
2146 - if (globals.gListLevel) {  
2147 - text = text.replace(wholeList, function (wholeMatch, list, m2) {  
2148 - var listType = (m2.search(/[*+-]/g) > -1) ? 'ul' : 'ol';  
2149 - return parseConsecutiveLists(list, listType, true);  
2150 - });  
2151 - } else {  
2152 - wholeList = /(\n\n|^\n?)(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;  
2153 - //wholeList = /(\n\n|^\n?)( {0,3}([*+-]|\d+\.)[ \t]+[\s\S]+?)(?=(~0)|(\n\n(?!\t| {2,}| {0,3}([*+-]|\d+\.)[ \t])))/g;  
2154 - text = text.replace(wholeList, function (wholeMatch, m1, list, m3) {  
2155 -  
2156 - var listType = (m3.search(/[*+-]/g) > -1) ? 'ul' : 'ol';  
2157 - return parseConsecutiveLists(list, listType);  
2158 - });  
2159 - }  
2160 -  
2161 - // attacklab: strip sentinel  
2162 - text = text.replace(/~0/, '');  
2163 -  
2164 - text = globals.converter._dispatch('lists.after', text, options, globals);  
2165 - return text;  
2166 -});  
2167 -  
2168 -/**  
2169 - * Remove one level of line-leading tabs or spaces  
2170 - */  
2171 -showdown.subParser('outdent', function (text) {  
2172 - 'use strict';  
2173 -  
2174 - // attacklab: hack around Konqueror 3.5.4 bug:  
2175 - // "----------bug".replace(/^-/g,"") == "bug"  
2176 - text = text.replace(/^(\t|[ ]{1,4})/gm, '~0'); // attacklab: g_tab_width  
2177 -  
2178 - // attacklab: clean up hack  
2179 - text = text.replace(/~0/g, '');  
2180 -  
2181 - return text;  
2182 -});  
2183 -  
2184 -/**  
2185 - *  
2186 - */  
2187 -showdown.subParser('paragraphs', function (text, options, globals) {  
2188 - 'use strict';  
2189 -  
2190 - text = globals.converter._dispatch('paragraphs.before', text, options, globals);  
2191 - // Strip leading and trailing lines:  
2192 - text = text.replace(/^\n+/g, '');  
2193 - text = text.replace(/\n+$/g, '');  
2194 -  
2195 - var grafs = text.split(/\n{2,}/g),  
2196 - grafsOut = [],  
2197 - end = grafs.length; // Wrap <p> tags  
2198 -  
2199 - for (var i = 0; i < end; i++) {  
2200 - var str = grafs[i];  
2201 - // if this is an HTML marker, copy it  
2202 - if (str.search(/~(K|G)(\d+)\1/g) >= 0) {  
2203 - grafsOut.push(str);  
2204 - } else {  
2205 - str = showdown.subParser('spanGamut')(str, options, globals);  
2206 - str = str.replace(/^([ \t]*)/g, '<p>');  
2207 - str += '</p>';  
2208 - grafsOut.push(str);  
2209 - }  
2210 - }  
2211 -  
2212 - /** Unhashify HTML blocks */  
2213 - end = grafsOut.length;  
2214 - for (i = 0; i < end; i++) {  
2215 - var blockText = '',  
2216 - grafsOutIt = grafsOut[i],  
2217 - codeFlag = false;  
2218 - // if this is a marker for an html block...  
2219 - while (grafsOutIt.search(/~(K|G)(\d+)\1/) >= 0) {  
2220 - var delim = RegExp.$1,  
2221 - num = RegExp.$2;  
2222 -  
2223 - if (delim === 'K') {  
2224 - blockText = globals.gHtmlBlocks[num];  
2225 - } else {  
2226 - // we need to check if ghBlock is a false positive  
2227 - if (codeFlag) {  
2228 - // use encoded version of all text  
2229 - blockText = showdown.subParser('encodeCode')(globals.ghCodeBlocks[num].text);  
2230 - } else {  
2231 - blockText = globals.ghCodeBlocks[num].codeblock;  
2232 - }  
2233 - }  
2234 - blockText = blockText.replace(/\$/g, '$$$$'); // Escape any dollar signs  
2235 -  
2236 - grafsOutIt = grafsOutIt.replace(/(\n\n)?~(K|G)\d+\2(\n\n)?/, blockText);  
2237 - // Check if grafsOutIt is a pre->code  
2238 - if (/^<pre\b[^>]*>\s*<code\b[^>]*>/.test(grafsOutIt)) {  
2239 - codeFlag = true;  
2240 - }  
2241 - }  
2242 - grafsOut[i] = grafsOutIt;  
2243 - }  
2244 - text = grafsOut.join('\n\n');  
2245 - // Strip leading and trailing lines:  
2246 - text = text.replace(/^\n+/g, '');  
2247 - text = text.replace(/\n+$/g, '');  
2248 - return globals.converter._dispatch('paragraphs.after', text, options, globals);  
2249 -});  
2250 -  
2251 -/**  
2252 - * Run extension  
2253 - */  
2254 -showdown.subParser('runExtension', function (ext, text, options, globals) {  
2255 - 'use strict';  
2256 -  
2257 - if (ext.filter) {  
2258 - text = ext.filter(text, globals.converter, options);  
2259 -  
2260 - } else if (ext.regex) {  
2261 - // TODO remove this when old extension loading mechanism is deprecated  
2262 - var re = ext.regex;  
2263 - if (!re instanceof RegExp) {  
2264 - re = new RegExp(re, 'g');  
2265 - }  
2266 - text = text.replace(re, ext.replace);  
2267 - }  
2268 -  
2269 - return text;  
2270 -});  
2271 -  
2272 -/**  
2273 - * These are all the transformations that occur *within* block-level  
2274 - * tags like paragraphs, headers, and list items.  
2275 - */  
2276 -showdown.subParser('spanGamut', function (text, options, globals) {  
2277 - 'use strict';  
2278 -  
2279 - text = globals.converter._dispatch('spanGamut.before', text, options, globals);  
2280 - text = showdown.subParser('codeSpans')(text, options, globals);  
2281 - text = showdown.subParser('escapeSpecialCharsWithinTagAttributes')(text, options, globals);  
2282 - text = showdown.subParser('encodeBackslashEscapes')(text, options, globals);  
2283 -  
2284 - // Process anchor and image tags. Images must come first,  
2285 - // because ![foo][f] looks like an anchor.  
2286 - text = showdown.subParser('images')(text, options, globals);  
2287 - text = showdown.subParser('anchors')(text, options, globals);  
2288 -  
2289 - // Make links out of things like `<http://example.com/>`  
2290 - // Must come after _DoAnchors(), because you can use < and >  
2291 - // delimiters in inline links like [this](<url>).  
2292 - text = showdown.subParser('autoLinks')(text, options, globals);  
2293 - text = showdown.subParser('encodeAmpsAndAngles')(text, options, globals);  
2294 - text = showdown.subParser('italicsAndBold')(text, options, globals);  
2295 - text = showdown.subParser('strikethrough')(text, options, globals);  
2296 -  
2297 - // Do hard breaks:  
2298 - text = text.replace(/ +\n/g, ' <br />\n');  
2299 -  
2300 - text = globals.converter._dispatch('spanGamut.after', text, options, globals);  
2301 - return text;  
2302 -});  
2303 -  
2304 -showdown.subParser('strikethrough', function (text, options, globals) {  
2305 - 'use strict';  
2306 -  
2307 - if (options.strikethrough) {  
2308 - text = globals.converter._dispatch('strikethrough.before', text, options, globals);  
2309 - text = text.replace(/(?:~T){2}([\s\S]+?)(?:~T){2}/g, '<del>$1</del>');  
2310 - text = globals.converter._dispatch('strikethrough.after', text, options, globals);  
2311 - }  
2312 -  
2313 - return text;  
2314 -});  
2315 -  
2316 -/**  
2317 - * Strip any lines consisting only of spaces and tabs.  
2318 - * This makes subsequent regexs easier to write, because we can  
2319 - * match consecutive blank lines with /\n+/ instead of something  
2320 - * contorted like /[ \t]*\n+/  
2321 - */  
2322 -showdown.subParser('stripBlankLines', function (text) {  
2323 - 'use strict';  
2324 - return text.replace(/^[ \t]+$/mg, '');  
2325 -});  
2326 -  
2327 -/**  
2328 - * Strips link definitions from text, stores the URLs and titles in  
2329 - * hash references.  
2330 - * Link defs are in the form: ^[id]: url "optional title"  
2331 - *  
2332 - * ^[ ]{0,3}\[(.+)\]: // id = $1 attacklab: g_tab_width - 1  
2333 - * [ \t]*  
2334 - * \n? // maybe *one* newline  
2335 - * [ \t]*  
2336 - * <?(\S+?)>? // url = $2  
2337 - * [ \t]*  
2338 - * \n? // maybe one newline  
2339 - * [ \t]*  
2340 - * (?:  
2341 - * (\n*) // any lines skipped = $3 attacklab: lookbehind removed  
2342 - * ["(]  
2343 - * (.+?) // title = $4  
2344 - * [")]  
2345 - * [ \t]*  
2346 - * )? // title is optional  
2347 - * (?:\n+|$)  
2348 - * /gm,  
2349 - * function(){...});  
2350 - *  
2351 - */  
2352 -showdown.subParser('stripLinkDefinitions', function (text, options, globals) {  
2353 - 'use strict';  
2354 -  
2355 - 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;  
2356 -  
2357 - // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug  
2358 - text += '~0';  
2359 -  
2360 - text = text.replace(regex, function (wholeMatch, linkId, url, width, height, blankLines, title) {  
2361 - linkId = linkId.toLowerCase();  
2362 - globals.gUrls[linkId] = showdown.subParser('encodeAmpsAndAngles')(url); // Link IDs are case-insensitive  
2363 -  
2364 - if (blankLines) {  
2365 - // Oops, found blank lines, so it's not a title.  
2366 - // Put back the parenthetical statement we stole.  
2367 - return blankLines + title;  
2368 -  
2369 - } else {  
2370 - if (title) {  
2371 - globals.gTitles[linkId] = title.replace(/"|'/g, '&quot;');  
2372 - }  
2373 - if (options.parseImgDimensions && width && height) {  
2374 - globals.gDimensions[linkId] = {  
2375 - width: width,  
2376 - height: height  
2377 - };  
2378 - }  
2379 - }  
2380 - // Completely remove the definition from the text  
2381 - return '';  
2382 - });  
2383 -  
2384 - // attacklab: strip sentinel  
2385 - text = text.replace(/~0/, '');  
2386 -  
2387 - return text;  
2388 -});  
2389 -  
2390 -showdown.subParser('tables', function (text, options, globals) {  
2391 - 'use strict';  
2392 -  
2393 - if (!options.tables) {  
2394 - return text;  
2395 - }  
2396 -  
2397 - var tableRgx = /^[ \t]{0,3}\|?.+\|.+\n[ \t]{0,3}\|?[ \t]*:?[ \t]*(?:-|=){2,}[ \t]*:?[ \t]*\|[ \t]*:?[ \t]*(?:-|=){2,}[\s\S]+?(?:\n\n|~0)/gm;  
2398 -  
2399 - function parseStyles(sLine) {  
2400 - if (/^:[ \t]*--*$/.test(sLine)) {  
2401 - return ' style="text-align:left;"';  
2402 - } else if (/^--*[ \t]*:[ \t]*$/.test(sLine)) {  
2403 - return ' style="text-align:right;"';  
2404 - } else if (/^:[ \t]*--*[ \t]*:$/.test(sLine)) {  
2405 - return ' style="text-align:center;"';  
2406 - } else {  
2407 - return '';  
2408 - }  
2409 - }  
2410 -  
2411 - function parseHeaders(header, style) {  
2412 - var id = '';  
2413 - header = header.trim();  
2414 - if (options.tableHeaderId) {  
2415 - id = ' id="' + header.replace(/ /g, '_').toLowerCase() + '"';  
2416 - }  
2417 - header = showdown.subParser('spanGamut')(header, options, globals);  
2418 -  
2419 - return '<th' + id + style + '>' + header + '</th>\n';  
2420 - }  
2421 -  
2422 - function parseCells(cell, style) {  
2423 - var subText = showdown.subParser('spanGamut')(cell, options, globals);  
2424 - return '<td' + style + '>' + subText + '</td>\n';  
2425 - }  
2426 -  
2427 - function buildTable(headers, cells) {  
2428 - var tb = '<table>\n<thead>\n<tr>\n',  
2429 - tblLgn = headers.length;  
2430 -  
2431 - for (var i = 0; i < tblLgn; ++i) {  
2432 - tb += headers[i];  
2433 - }  
2434 - tb += '</tr>\n</thead>\n<tbody>\n';  
2435 -  
2436 - for (i = 0; i < cells.length; ++i) {  
2437 - tb += '<tr>\n';  
2438 - for (var ii = 0; ii < tblLgn; ++ii) {  
2439 - tb += cells[i][ii];  
2440 - }  
2441 - tb += '</tr>\n';  
2442 - }  
2443 - tb += '</tbody>\n</table>\n';  
2444 - return tb;  
2445 - }  
2446 -  
2447 - text = globals.converter._dispatch('tables.before', text, options, globals);  
2448 -  
2449 - text = text.replace(tableRgx, function (rawTable) {  
2450 -  
2451 - var i, tableLines = rawTable.split('\n');  
2452 -  
2453 - // strip wrong first and last column if wrapped tables are used  
2454 - for (i = 0; i < tableLines.length; ++i) {  
2455 - if (/^[ \t]{0,3}\|/.test(tableLines[i])) {  
2456 - tableLines[i] = tableLines[i].replace(/^[ \t]{0,3}\|/, '');  
2457 - }  
2458 - if (/\|[ \t]*$/.test(tableLines[i])) {  
2459 - tableLines[i] = tableLines[i].replace(/\|[ \t]*$/, '');  
2460 - }  
2461 - }  
2462 -  
2463 - var rawHeaders = tableLines[0].split('|').map(function (s) { return s.trim();}),  
2464 - rawStyles = tableLines[1].split('|').map(function (s) { return s.trim();}),  
2465 - rawCells = [],  
2466 - headers = [],  
2467 - styles = [],  
2468 - cells = [];  
2469 -  
2470 - tableLines.shift();  
2471 - tableLines.shift();  
2472 -  
2473 - for (i = 0; i < tableLines.length; ++i) {  
2474 - if (tableLines[i].trim() === '') {  
2475 - continue;  
2476 - }  
2477 - rawCells.push(  
2478 - tableLines[i]  
2479 - .split('|')  
2480 - .map(function (s) {  
2481 - return s.trim();  
2482 - })  
2483 - );  
2484 - }  
2485 -  
2486 - if (rawHeaders.length < rawStyles.length) {  
2487 - return rawTable;  
2488 - }  
2489 -  
2490 - for (i = 0; i < rawStyles.length; ++i) {  
2491 - styles.push(parseStyles(rawStyles[i]));  
2492 - }  
2493 -  
2494 - for (i = 0; i < rawHeaders.length; ++i) {  
2495 - if (showdown.helper.isUndefined(styles[i])) {  
2496 - styles[i] = '';  
2497 - }  
2498 - headers.push(parseHeaders(rawHeaders[i], styles[i]));  
2499 - }  
2500 -  
2501 - for (i = 0; i < rawCells.length; ++i) {  
2502 - var row = [];  
2503 - for (var ii = 0; ii < headers.length; ++ii) {  
2504 - if (showdown.helper.isUndefined(rawCells[i][ii])) {  
2505 -  
2506 - }  
2507 - row.push(parseCells(rawCells[i][ii], styles[ii]));  
2508 - }  
2509 - cells.push(row);  
2510 - }  
2511 -  
2512 - return buildTable(headers, cells);  
2513 - });  
2514 -  
2515 - text = globals.converter._dispatch('tables.after', text, options, globals);  
2516 -  
2517 - return text;  
2518 -});  
2519 -  
2520 -/**  
2521 - * Swap back in all the special characters we've hidden.  
2522 - */  
2523 -showdown.subParser('unescapeSpecialChars', function (text) {  
2524 - 'use strict';  
2525 -  
2526 - text = text.replace(/~E(\d+)E/g, function (wholeMatch, m1) {  
2527 - var charCodeToReplace = parseInt(m1);  
2528 - return String.fromCharCode(charCodeToReplace);  
2529 - });  
2530 - return text;  
2531 -});  
2532 -module.exports = showdown;  
1 -// HTML 支持的数学符号  
2 -function strNumDiscode(str){  
3 - str = str.replace(/&forall;/g, '∀');  
4 - str = str.replace(/&part;/g, '∂');  
5 - str = str.replace(/&exists;/g, '∃');  
6 - str = str.replace(/&empty;/g, '∅');  
7 - str = str.replace(/&nabla;/g, '∇');  
8 - str = str.replace(/&isin;/g, '∈');  
9 - str = str.replace(/&notin;/g, '∉');  
10 - str = str.replace(/&ni;/g, '∋');  
11 - str = str.replace(/&prod;/g, '∏');  
12 - str = str.replace(/&sum;/g, '∑');  
13 - str = str.replace(/&minus;/g, '−');  
14 - str = str.replace(/&lowast;/g, '∗');  
15 - str = str.replace(/&radic;/g, '√');  
16 - str = str.replace(/&prop;/g, '∝');  
17 - str = str.replace(/&infin;/g, '∞');  
18 - str = str.replace(/&ang;/g, '∠');  
19 - str = str.replace(/&and;/g, '∧');  
20 - str = str.replace(/&or;/g, '∨');  
21 - str = str.replace(/&cap;/g, '∩');  
22 - str = str.replace(/&cap;/g, '∪');  
23 - str = str.replace(/&int;/g, '∫');  
24 - str = str.replace(/&there4;/g, '∴');  
25 - str = str.replace(/&sim;/g, '∼');  
26 - str = str.replace(/&cong;/g, '≅');  
27 - str = str.replace(/&asymp;/g, '≈');  
28 - str = str.replace(/&ne;/g, '≠');  
29 - str = str.replace(/&le;/g, '≤');  
30 - str = str.replace(/&ge;/g, '≥');  
31 - str = str.replace(/&sub;/g, '⊂');  
32 - str = str.replace(/&sup;/g, '⊃');  
33 - str = str.replace(/&nsub;/g, '⊄');  
34 - str = str.replace(/&sube;/g, '⊆');  
35 - str = str.replace(/&supe;/g, '⊇');  
36 - str = str.replace(/&oplus;/g, '⊕');  
37 - str = str.replace(/&otimes;/g, '⊗');  
38 - str = str.replace(/&perp;/g, '⊥');  
39 - str = str.replace(/&sdot;/g, '⋅');  
40 - return str;  
41 -}  
42 -  
43 -//HTML 支持的希腊字母  
44 -function strGreeceDiscode(str){  
45 - str = str.replace(/&Alpha;/g, 'Α');  
46 - str = str.replace(/&Beta;/g, 'Β');  
47 - str = str.replace(/&Gamma;/g, 'Γ');  
48 - str = str.replace(/&Delta;/g, 'Δ');  
49 - str = str.replace(/&Epsilon;/g, 'Ε');  
50 - str = str.replace(/&Zeta;/g, 'Ζ');  
51 - str = str.replace(/&Eta;/g, 'Η');  
52 - str = str.replace(/&Theta;/g, 'Θ');  
53 - str = str.replace(/&Iota;/g, 'Ι');  
54 - str = str.replace(/&Kappa;/g, 'Κ');  
55 - str = str.replace(/&Lambda;/g, 'Λ');  
56 - str = str.replace(/&Mu;/g, 'Μ');  
57 - str = str.replace(/&Nu;/g, 'Ν');  
58 - str = str.replace(/&Xi;/g, 'Ν');  
59 - str = str.replace(/&Omicron;/g, 'Ο');  
60 - str = str.replace(/&Pi;/g, 'Π');  
61 - str = str.replace(/&Rho;/g, 'Ρ');  
62 - str = str.replace(/&Sigma;/g, 'Σ');  
63 - str = str.replace(/&Tau;/g, 'Τ');  
64 - str = str.replace(/&Upsilon;/g, 'Υ');  
65 - str = str.replace(/&Phi;/g, 'Φ');  
66 - str = str.replace(/&Chi;/g, 'Χ');  
67 - str = str.replace(/&Psi;/g, 'Ψ');  
68 - str = str.replace(/&Omega;/g, 'Ω');  
69 -  
70 - str = str.replace(/&alpha;/g, 'α');  
71 - str = str.replace(/&beta;/g, 'β');  
72 - str = str.replace(/&gamma;/g, 'γ');  
73 - str = str.replace(/&delta;/g, 'δ');  
74 - str = str.replace(/&epsilon;/g, 'ε');  
75 - str = str.replace(/&zeta;/g, 'ζ');  
76 - str = str.replace(/&eta;/g, 'η');  
77 - str = str.replace(/&theta;/g, 'θ');  
78 - str = str.replace(/&iota;/g, 'ι');  
79 - str = str.replace(/&kappa;/g, 'κ');  
80 - str = str.replace(/&lambda;/g, 'λ');  
81 - str = str.replace(/&mu;/g, 'μ');  
82 - str = str.replace(/&nu;/g, 'ν');  
83 - str = str.replace(/&xi;/g, 'ξ');  
84 - str = str.replace(/&omicron;/g, 'ο');  
85 - str = str.replace(/&pi;/g, 'π');  
86 - str = str.replace(/&rho;/g, 'ρ');  
87 - str = str.replace(/&sigmaf;/g, 'ς');  
88 - str = str.replace(/&sigma;/g, 'σ');  
89 - str = str.replace(/&tau;/g, 'τ');  
90 - str = str.replace(/&upsilon;/g, 'υ');  
91 - str = str.replace(/&phi;/g, 'φ');  
92 - str = str.replace(/&chi;/g, 'χ');  
93 - str = str.replace(/&psi;/g, 'ψ');  
94 - str = str.replace(/&omega;/g, 'ω');  
95 - str = str.replace(/&thetasym;/g, 'ϑ');  
96 - str = str.replace(/&upsih;/g, 'ϒ');  
97 - str = str.replace(/&piv;/g, 'ϖ');  
98 - str = str.replace(/&middot;/g, '·');  
99 - return str;  
100 -}  
101 -  
102 -//  
103 -  
104 -function strcharacterDiscode(str){  
105 - // 加入常用解析  
106 - str = str.replace(/&nbsp;/g, ' ');  
107 - str = str.replace(/&quot;/g, "'");  
108 - str = str.replace(/&amp;/g, '&');  
109 - // str = str.replace(/&lt;/g, '‹');  
110 - // str = str.replace(/&gt;/g, '›');  
111 -  
112 - str = str.replace(/&lt;/g, '<');  
113 - str = str.replace(/&gt;/g, '>');  
114 - str = str.replace(/&#8226;/g, '•');  
115 -  
116 - return str;  
117 -}  
118 -  
119 -// HTML 支持的其他实体  
120 -function strOtherDiscode(str){  
121 - str = str.replace(/&OElig;/g, 'Œ');  
122 - str = str.replace(/&oelig;/g, 'œ');  
123 - str = str.replace(/&Scaron;/g, 'Š');  
124 - str = str.replace(/&scaron;/g, 'š');  
125 - str = str.replace(/&Yuml;/g, 'Ÿ');  
126 - str = str.replace(/&fnof;/g, 'ƒ');  
127 - str = str.replace(/&circ;/g, 'ˆ');  
128 - str = str.replace(/&tilde;/g, '˜');  
129 - str = str.replace(/&ensp;/g, '');  
130 - str = str.replace(/&emsp;/g, '');  
131 - str = str.replace(/&thinsp;/g, '');  
132 - str = str.replace(/&zwnj;/g, '');  
133 - str = str.replace(/&zwj;/g, '');  
134 - str = str.replace(/&lrm;/g, '');  
135 - str = str.replace(/&rlm;/g, '');  
136 - str = str.replace(/&ndash;/g, '–');  
137 - str = str.replace(/&mdash;/g, '—');  
138 - str = str.replace(/&lsquo;/g, '‘');  
139 - str = str.replace(/&rsquo;/g, '’');  
140 - str = str.replace(/&sbquo;/g, '‚');  
141 - str = str.replace(/&ldquo;/g, '“');  
142 - str = str.replace(/&rdquo;/g, '”');  
143 - str = str.replace(/&bdquo;/g, '„');  
144 - str = str.replace(/&dagger;/g, '†');  
145 - str = str.replace(/&Dagger;/g, '‡');  
146 - str = str.replace(/&bull;/g, '•');  
147 - str = str.replace(/&hellip;/g, '…');  
148 - str = str.replace(/&permil;/g, '‰');  
149 - str = str.replace(/&prime;/g, '′');  
150 - str = str.replace(/&Prime;/g, '″');  
151 - str = str.replace(/&lsaquo;/g, '‹');  
152 - str = str.replace(/&rsaquo;/g, '›');  
153 - str = str.replace(/&oline;/g, '‾');  
154 - str = str.replace(/&euro;/g, '€');  
155 - str = str.replace(/&trade;/g, '™');  
156 -  
157 - str = str.replace(/&larr;/g, '←');  
158 - str = str.replace(/&uarr;/g, '↑');  
159 - str = str.replace(/&rarr;/g, '→');  
160 - str = str.replace(/&darr;/g, '↓');  
161 - str = str.replace(/&harr;/g, '↔');  
162 - str = str.replace(/&crarr;/g, '↵');  
163 - str = str.replace(/&lceil;/g, '⌈');  
164 - str = str.replace(/&rceil;/g, '⌉');  
165 -  
166 - str = str.replace(/&lfloor;/g, '⌊');  
167 - str = str.replace(/&rfloor;/g, '⌋');  
168 - str = str.replace(/&loz;/g, '◊');  
169 - str = str.replace(/&spades;/g, '♠');  
170 - str = str.replace(/&clubs;/g, '♣');  
171 - str = str.replace(/&hearts;/g, '♥');  
172 -  
173 - str = str.replace(/&diams;/g, '♦');  
174 - str = str.replace(/&#39;/g, '\'');  
175 - return str;  
176 -}  
177 -  
178 -function strMoreDiscode(str){  
179 - str = str.replace(/\r\n/g,"");  
180 - str = str.replace(/\n/g,"");  
181 -  
182 - str = str.replace(/code/g,"wxxxcode-style");  
183 - return str;  
184 -}  
185 -  
186 -function strDiscode(str){  
187 - str = strNumDiscode(str);  
188 - str = strGreeceDiscode(str);  
189 - str = strcharacterDiscode(str);  
190 - str = strOtherDiscode(str);  
191 - str = strMoreDiscode(str);  
192 - return str;  
193 -}  
194 -function urlToHttpUrl(url,rep){  
195 -  
196 - var patt1 = new RegExp("^//");  
197 - var result = patt1.test(url);  
198 - if(result){  
199 - url = rep+":"+url;  
200 - }  
201 - return url;  
202 -}  
203 -  
204 -module.exports = {  
205 - strDiscode:strDiscode,  
206 - urlToHttpUrl:urlToHttpUrl  
207 -}  
1 -/**  
2 - * author: Di (微信小程序开发工程师)  
3 - * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)  
4 - * 垂直微信小程序开发交流社区  
5 - *  
6 - * github地址: https://github.com/icindy/wxParse  
7 - *  
8 - * for: 微信小程序富文本解析  
9 - * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184  
10 - */  
11 -  
12 -/**  
13 - * utils函数引入  
14 - **/  
15 -import showdown from './showdown.js';  
16 -import HtmlToJson from './html2json.js';  
17 -/**  
18 - * 配置及公有属性  
19 - **/  
20 -var realWindowWidth = 0;  
21 -var realWindowHeight = 0;  
22 -wx.getSystemInfo({  
23 - success: function (res) {  
24 - realWindowWidth = res.windowWidth  
25 - realWindowHeight = res.windowHeight  
26 - }  
27 -})  
28 -/**  
29 - * 主函数入口区  
30 - **/  
31 -function wxParse(bindName = 'wxParseData', type='html', data='<div class="color:red;">数据不能为空</div>', target,imagePadding) {  
32 - var that = target;  
33 - var transData = {};//存放转化后的数据  
34 - if (type == 'html') {  
35 - transData = HtmlToJson.html2json(data, bindName);  
36 - // console.log(JSON.stringify(transData, ' ', ' '));  
37 - } else if (type == 'md' || type == 'markdown') {  
38 - var converter = new showdown.Converter();  
39 - var html = converter.makeHtml(data);  
40 - transData = HtmlToJson.html2json(html, bindName);  
41 - console.log(JSON.stringify(transData, ' ', ' '));  
42 - }  
43 - transData.view = {};  
44 - transData.view.imagePadding = 0;  
45 - if(typeof(imagePadding) != 'undefined'){  
46 - transData.view.imagePadding = imagePadding  
47 - }  
48 - var bindData = {};  
49 - bindData[bindName] = transData;  
50 - that.setData(bindData)  
51 - that.wxParseImgLoad = wxParseImgLoad;  
52 - that.wxParseImgTap = wxParseImgTap;  
53 -}  
54 -// 图片点击事件  
55 -function wxParseImgTap(e) {  
56 - var that = this;  
57 - var nowImgUrl = e.target.dataset.src;  
58 - var tagFrom = e.target.dataset.from;  
59 - if (typeof (tagFrom) != 'undefined' && tagFrom.length > 0) {  
60 - wx.previewImage({  
61 - current: nowImgUrl, // 当前显示图片的http链接  
62 - urls: that.data[tagFrom].imageUrls // 需要预览的图片http链接列表  
63 - })  
64 - }  
65 -}  
66 -  
67 -/**  
68 - * 图片视觉宽高计算函数区  
69 - **/  
70 -function wxParseImgLoad(e) {  
71 - var that = this;  
72 - var tagFrom = e.target.dataset.from;  
73 - var idx = e.target.dataset.idx;  
74 - if (typeof (tagFrom) != 'undefined' && tagFrom.length > 0) {  
75 - calMoreImageInfo(e, idx, that, tagFrom)  
76 - }  
77 -}  
78 -// 假循环获取计算图片视觉最佳宽高  
79 -function calMoreImageInfo(e, idx, that, bindName) {  
80 - var temData = that.data[bindName];  
81 - if (!temData || temData.images.length == 0) {  
82 - return;  
83 - }  
84 - var temImages = temData.images;  
85 - //因为无法获取view宽度 需要自定义padding进行计算,稍后处理  
86 - var recal = wxAutoImageCal(e.detail.width, e.detail.height,that,bindName);  
87 - // temImages[idx].width = recal.imageWidth;  
88 - // temImages[idx].height = recal.imageheight;  
89 - // temData.images = temImages;  
90 - // var bindData = {};  
91 - // bindData[bindName] = temData;  
92 - // that.setData(bindData);  
93 - var index = temImages[idx].index  
94 - var key = `${bindName}`  
95 - for (var i of index.split('.')) key+=`.nodes[${i}]`  
96 - var keyW = key + '.width'  
97 - var keyH = key + '.height'  
98 - that.setData({  
99 - [keyW]: recal.imageWidth,  
100 - [keyH]: recal.imageheight,  
101 - })  
102 -}  
103 -  
104 -// 计算视觉优先的图片宽高  
105 -function wxAutoImageCal(originalWidth, originalHeight,that,bindName) {  
106 - //获取图片的原始长宽  
107 - var windowWidth = 0, windowHeight = 0;  
108 - var autoWidth = 0, autoHeight = 0;  
109 - var results = {};  
110 - var padding = that.data[bindName].view.imagePadding;  
111 - windowWidth = realWindowWidth-2*padding;  
112 - windowHeight = realWindowHeight;  
113 - //判断按照那种方式进行缩放  
114 - // console.log("windowWidth" + windowWidth);  
115 - if (originalWidth > windowWidth) {//在图片width大于手机屏幕width时候  
116 - autoWidth = windowWidth;  
117 - // console.log("autoWidth" + autoWidth);  
118 - autoHeight = (autoWidth * originalHeight) / originalWidth;  
119 - // console.log("autoHeight" + autoHeight);  
120 - results.imageWidth = autoWidth;  
121 - results.imageheight = autoHeight;  
122 - } else {//否则展示原来的数据  
123 - results.imageWidth = originalWidth;  
124 - results.imageheight = originalHeight;  
125 - }  
126 - return results;  
127 -}  
128 -  
129 -function wxParseTemArray(temArrayName,bindNameReg,total,that){  
130 - var array = [];  
131 - var temData = that.data;  
132 - var obj = null;  
133 - for(var i = 0; i < total; i++){  
134 - var simArr = temData[bindNameReg+i].nodes;  
135 - array.push(simArr);  
136 - }  
137 -  
138 - temArrayName = temArrayName || 'wxParseTemArray';  
139 - obj = JSON.parse('{"'+ temArrayName +'":""}');  
140 - obj[temArrayName] = array;  
141 - that.setData(obj);  
142 -}  
143 -  
144 -/**  
145 - * 配置emojis  
146 - *  
147 - */  
148 -  
149 -function emojisInit(reg='',baseSrc="/wxParse/emojis/",emojis){  
150 - HtmlToJson.emojisInit(reg,baseSrc,emojis);  
151 -}  
152 -  
153 -module.exports = {  
154 - wxParse: wxParse,  
155 - wxParseTemArray:wxParseTemArray,  
156 - emojisInit:emojisInit  
157 -}  
158 -  
159 -  
1 -<!--**  
2 - * author: Di (微信小程序开发工程师)  
3 - * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)  
4 - * 垂直微信小程序开发交流社区  
5 - *  
6 - * github地址: https://github.com/icindy/wxParse  
7 - *  
8 - * for: 微信小程序富文本解析  
9 - * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184  
10 - */-->  
11 -  
12 -<!--基础元素-->  
13 -<template name="wxParseVideo">  
14 - <!--增加video标签支持,并循环添加-->  
15 - <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">  
16 - <video class="{{item.classStr}} wxParse-{{item.tag}}-video" src="{{item.attr.src}}"></video>  
17 - </view>  
18 -</template>  
19 -  
20 -<template name="wxParseImg">  
21 - <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;"  
22 - />  
23 -</template>  
24 -  
25 -<template name="WxEmojiView">  
26 - <view class="WxEmojiView wxParse-inline" style="{{item.styleStr}}">  
27 - <block wx:for="{{item.textArray}}" wx:key="">  
28 - <block class="{{item.text == '\\n' ? 'wxParse-hide':''}}" wx:if="{{item.node == 'text'}}">{{item.text}}</block>  
29 - <block wx:elif="{{item.node == 'element'}}">  
30 - <image class="wxEmoji" src="{{item.baseSrc}}{{item.text}}" />  
31 - </block>  
32 - </block>  
33 - </view>  
34 -</template>  
35 -  
36 -<template name="WxParseBr">  
37 - <text>\n</text>  
38 -</template>  
39 -<!--入口模版-->  
40 -  
41 -<template name="wxParse">  
42 - <block wx:for="{{wxParseData}}" wx:key="">  
43 - <template is="wxParse0" data="{{item}}" />  
44 - </block>  
45 -</template>  
46 -  
47 -  
48 -<!--循环模版-->  
49 -<template name="wxParse0">  
50 - <!--<template is="wxParse1" data="{{item}}" />-->  
51 - <!--判断是否是标签节点-->  
52 - <block wx:if="{{item.node == 'element'}}">  
53 - <block wx:if="{{item.tag == 'button'}}">  
54 - <button type="default" size="mini">  
55 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
56 - <template is="wxParse1" data="{{item}}" />  
57 - </block>  
58 - </button>  
59 - </block>  
60 - <!--li类型-->  
61 - <block wx:elif="{{item.tag == 'li'}}">  
62 - <view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}">  
63 - <view class="{{item.classStr}} wxParse-li-inner">  
64 - <view class="{{item.classStr}} wxParse-li-text">  
65 - <view class="{{item.classStr}} wxParse-li-circle"></view>  
66 - </view>  
67 - <view class="{{item.classStr}} wxParse-li-text">  
68 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
69 - <template is="wxParse1" data="{{item}}" />  
70 - </block>  
71 - </view>  
72 - </view>  
73 - </view>  
74 - </block>  
75 -  
76 - <!--video类型-->  
77 - <block wx:elif="{{item.tag == 'video'}}">  
78 - <template is="wxParseVideo" data="{{item}}" />  
79 - </block>  
80 -  
81 - <!--img类型-->  
82 - <block wx:elif="{{item.tag == 'img'}}">  
83 - <template is="wxParseImg" data="{{item}}" />  
84 - </block>  
85 -  
86 - <!--a类型-->  
87 - <block wx:elif="{{item.tag == 'a'}}">  
88 - <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}">  
89 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
90 - <template is="wxParse1" data="{{item}}" />  
91 - </block>  
92 - </view>  
93 - </block>  
94 - <block wx:elif="{{item.tag == 'table'}}">  
95 - <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">  
96 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
97 - <template is="wxParse1" data="{{item}}" />  
98 - </block>  
99 - </view>  
100 - </block>  
101 -  
102 - <block wx:elif="{{item.tag == 'br'}}">  
103 - <template is="WxParseBr"></template>  
104 - </block>  
105 - <!--其他块级标签-->  
106 - <block wx:elif="{{item.tagType == 'block'}}">  
107 - <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">  
108 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
109 - <template is="wxParse1" data="{{item}}" />  
110 - </block>  
111 - </view>  
112 - </block>  
113 -  
114 - <!--内联标签-->  
115 - <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">  
116 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
117 - <template is="wxParse1" data="{{item}}" />  
118 - </block>  
119 - </view>  
120 -  
121 - </block>  
122 -  
123 - <!--判断是否是文本节点-->  
124 - <block wx:elif="{{item.node == 'text'}}">  
125 - <!--如果是,直接进行-->  
126 - <template is="WxEmojiView" data="{{item}}" />  
127 - </block>  
128 -  
129 -</template>  
130 -  
131 -  
132 -  
133 -<!--循环模版-->  
134 -<template name="wxParse1">  
135 - <!--<template is="wxParse2" data="{{item}}" />-->  
136 - <!--判断是否是标签节点-->  
137 - <block wx:if="{{item.node == 'element'}}">  
138 - <block wx:if="{{item.tag == 'button'}}">  
139 - <button type="default" size="mini">  
140 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
141 - <template is="wxParse2" data="{{item}}" />  
142 - </block>  
143 - </button>  
144 - </block>  
145 - <!--li类型-->  
146 - <block wx:elif="{{item.tag == 'li'}}">  
147 - <view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}">  
148 - <view class="{{item.classStr}} wxParse-li-inner">  
149 - <view class="{{item.classStr}} wxParse-li-text">  
150 - <view class="{{item.classStr}} wxParse-li-circle"></view>  
151 - </view>  
152 - <view class="{{item.classStr}} wxParse-li-text">  
153 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
154 - <template is="wxParse2" data="{{item}}" />  
155 - </block>  
156 - </view>  
157 - </view>  
158 - </view>  
159 - </block>  
160 -  
161 - <!--video类型-->  
162 - <block wx:elif="{{item.tag == 'video'}}">  
163 - <template is="wxParseVideo" data="{{item}}" />  
164 - </block>  
165 -  
166 - <!--img类型-->  
167 - <block wx:elif="{{item.tag == 'img'}}">  
168 - <template is="wxParseImg" data="{{item}}" />  
169 - </block>  
170 -  
171 - <!--a类型-->  
172 - <block wx:elif="{{item.tag == 'a'}}">  
173 - <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}">  
174 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
175 - <template is="wxParse2" data="{{item}}" />  
176 - </block>  
177 - </view>  
178 - </block>  
179 -  
180 - <block wx:elif="{{item.tag == 'br'}}">  
181 - <template is="WxParseBr"></template>  
182 - </block>  
183 - <!--其他块级标签-->  
184 - <block wx:elif="{{item.tagType == 'block'}}">  
185 - <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">  
186 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
187 - <template is="wxParse2" data="{{item}}" />  
188 - </block>  
189 - </view>  
190 - </block>  
191 -  
192 - <!--内联标签-->  
193 - <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">  
194 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
195 - <template is="wxParse2" data="{{item}}" />  
196 - </block>  
197 - </view>  
198 -  
199 - </block>  
200 -  
201 - <!--判断是否是文本节点-->  
202 - <block wx:elif="{{item.node == 'text'}}">  
203 - <!--如果是,直接进行-->  
204 - <template is="WxEmojiView" data="{{item}}" />  
205 - </block>  
206 -  
207 -</template>  
208 -  
209 -  
210 -<!--循环模版-->  
211 -<template name="wxParse2">  
212 - <!--<template is="wxParse3" data="{{item}}" />-->  
213 - <!--判断是否是标签节点-->  
214 - <block wx:if="{{item.node == 'element'}}">  
215 - <block wx:if="{{item.tag == 'button'}}">  
216 - <button type="default" size="mini">  
217 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
218 - <template is="wxParse3" data="{{item}}" />  
219 - </block>  
220 - </button>  
221 - </block>  
222 - <!--li类型-->  
223 - <block wx:elif="{{item.tag == 'li'}}">  
224 - <view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}">  
225 - <view class="{{item.classStr}} wxParse-li-inner">  
226 - <view class="{{item.classStr}} wxParse-li-text">  
227 - <view class="{{item.classStr}} wxParse-li-circle"></view>  
228 - </view>  
229 - <view class="{{item.classStr}} wxParse-li-text">  
230 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
231 - <template is="wxParse3" data="{{item}}" />  
232 - </block>  
233 - </view>  
234 - </view>  
235 - </view>  
236 - </block>  
237 -  
238 - <!--video类型-->  
239 - <block wx:elif="{{item.tag == 'video'}}">  
240 - <template is="wxParseVideo" data="{{item}}" />  
241 - </block>  
242 -  
243 - <!--img类型-->  
244 - <block wx:elif="{{item.tag == 'img'}}">  
245 - <template is="wxParseImg" data="{{item}}" />  
246 - </block>  
247 -  
248 - <!--a类型-->  
249 - <block wx:elif="{{item.tag == 'a'}}">  
250 - <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}">  
251 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
252 - <template is="wxParse3" data="{{item}}" />  
253 - </block>  
254 - </view>  
255 - </block>  
256 -  
257 - <block wx:elif="{{item.tag == 'br'}}">  
258 - <template is="WxParseBr"></template>  
259 - </block>  
260 - <!--其他块级标签-->  
261 - <block wx:elif="{{item.tagType == 'block'}}">  
262 - <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">  
263 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
264 - <template is="wxParse3" data="{{item}}" />  
265 - </block>  
266 - </view>  
267 - </block>  
268 -  
269 - <!--内联标签-->  
270 - <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">  
271 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
272 - <template is="wxParse3" data="{{item}}" />  
273 - </block>  
274 - </view>  
275 -  
276 - </block>  
277 -  
278 - <!--判断是否是文本节点-->  
279 - <block wx:elif="{{item.node == 'text'}}">  
280 - <!--如果是,直接进行-->  
281 - <template is="WxEmojiView" data="{{item}}" />  
282 - </block>  
283 -  
284 -</template>  
285 -  
286 -<!--循环模版-->  
287 -<template name="wxParse3">  
288 - <!--<template is="wxParse4" data="{{item}}" />-->  
289 - <!--判断是否是标签节点-->  
290 - <block wx:if="{{item.node == 'element'}}">  
291 - <block wx:if="{{item.tag == 'button'}}">  
292 - <button type="default" size="mini">  
293 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
294 - <template is="wxParse4" data="{{item}}" />  
295 - </block>  
296 - </button>  
297 - </block>  
298 - <!--li类型-->  
299 - <block wx:elif="{{item.tag == 'li'}}">  
300 - <view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}">  
301 - <view class="{{item.classStr}} wxParse-li-inner">  
302 - <view class="{{item.classStr}} wxParse-li-text">  
303 - <view class="{{item.classStr}} wxParse-li-circle"></view>  
304 - </view>  
305 - <view class="{{item.classStr}} wxParse-li-text">  
306 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
307 - <template is="wxParse4" data="{{item}}" />  
308 - </block>  
309 - </view>  
310 - </view>  
311 - </view>  
312 - </block>  
313 -  
314 - <!--video类型-->  
315 - <block wx:elif="{{item.tag == 'video'}}">  
316 - <template is="wxParseVideo" data="{{item}}" />  
317 - </block>  
318 -  
319 - <!--img类型-->  
320 - <block wx:elif="{{item.tag == 'img'}}">  
321 - <template is="wxParseImg" data="{{item}}" />  
322 - </block>  
323 -  
324 - <!--a类型-->  
325 - <block wx:elif="{{item.tag == 'a'}}">  
326 - <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}">  
327 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
328 - <template is="wxParse4" data="{{item}}" />  
329 - </block>  
330 - </view>  
331 - </block>  
332 -  
333 - <block wx:elif="{{item.tag == 'br'}}">  
334 - <template is="WxParseBr"></template>  
335 - </block>  
336 - <!--其他块级标签-->  
337 - <block wx:elif="{{item.tagType == 'block'}}">  
338 - <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">  
339 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
340 - <template is="wxParse4" data="{{item}}" />  
341 - </block>  
342 - </view>  
343 - </block>  
344 -  
345 - <!--内联标签-->  
346 - <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">  
347 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
348 - <template is="wxParse4" data="{{item}}" />  
349 - </block>  
350 - </view>  
351 -  
352 - </block>  
353 -  
354 - <!--判断是否是文本节点-->  
355 - <block wx:elif="{{item.node == 'text'}}">  
356 - <!--如果是,直接进行-->  
357 - <template is="WxEmojiView" data="{{item}}" />  
358 - </block>  
359 -  
360 -</template>  
361 -  
362 -<!--循环模版-->  
363 -<template name="wxParse4">  
364 - <!--<template is="wxParse5" data="{{item}}" />-->  
365 - <!--判断是否是标签节点-->  
366 - <block wx:if="{{item.node == 'element'}}">  
367 - <block wx:if="{{item.tag == 'button'}}">  
368 - <button type="default" size="mini">  
369 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
370 - <template is="wxParse5" data="{{item}}" />  
371 - </block>  
372 - </button>  
373 - </block>  
374 - <!--li类型-->  
375 - <block wx:elif="{{item.tag == 'li'}}">  
376 - <view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}">  
377 - <view class="{{item.classStr}} wxParse-li-inner">  
378 - <view class="{{item.classStr}} wxParse-li-text">  
379 - <view class="{{item.classStr}} wxParse-li-circle"></view>  
380 - </view>  
381 - <view class="{{item.classStr}} wxParse-li-text">  
382 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
383 - <template is="wxParse5" data="{{item}}" />  
384 - </block>  
385 - </view>  
386 - </view>  
387 - </view>  
388 - </block>  
389 -  
390 - <!--video类型-->  
391 - <block wx:elif="{{item.tag == 'video'}}">  
392 - <template is="wxParseVideo" data="{{item}}" />  
393 - </block>  
394 -  
395 - <!--img类型-->  
396 - <block wx:elif="{{item.tag == 'img'}}">  
397 - <template is="wxParseImg" data="{{item}}" />  
398 - </block>  
399 -  
400 - <!--a类型-->  
401 - <block wx:elif="{{item.tag == 'a'}}">  
402 - <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}">  
403 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
404 - <template is="wxParse5" data="{{item}}" />  
405 - </block>  
406 - </view>  
407 - </block>  
408 -  
409 - <block wx:elif="{{item.tag == 'br'}}">  
410 - <template is="WxParseBr"></template>  
411 - </block>  
412 - <!--其他块级标签-->  
413 - <block wx:elif="{{item.tagType == 'block'}}">  
414 - <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">  
415 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
416 - <template is="wxParse5" data="{{item}}" />  
417 - </block>  
418 - </view>  
419 - </block>  
420 -  
421 - <!--内联标签-->  
422 - <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">  
423 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
424 - <template is="wxParse5" data="{{item}}" />  
425 - </block>  
426 - </view>  
427 -  
428 - </block>  
429 -  
430 - <!--判断是否是文本节点-->  
431 - <block wx:elif="{{item.node == 'text'}}">  
432 - <!--如果是,直接进行-->  
433 - <template is="WxEmojiView" data="{{item}}" />  
434 - </block>  
435 -  
436 -</template>  
437 -  
438 -<!--循环模版-->  
439 -<template name="wxParse5">  
440 - <!--<template is="wxParse6" data="{{item}}" />-->  
441 - <!--判断是否是标签节点-->  
442 - <block wx:if="{{item.node == 'element'}}">  
443 - <block wx:if="{{item.tag == 'button'}}">  
444 - <button type="default" size="mini">  
445 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
446 - <template is="wxParse6" data="{{item}}" />  
447 - </block>  
448 - </button>  
449 - </block>  
450 - <!--li类型-->  
451 - <block wx:elif="{{item.tag == 'li'}}">  
452 - <view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}">  
453 - <view class="{{item.classStr}} wxParse-li-inner">  
454 - <view class="{{item.classStr}} wxParse-li-text">  
455 - <view class="{{item.classStr}} wxParse-li-circle"></view>  
456 - </view>  
457 - <view class="{{item.classStr}} wxParse-li-text">  
458 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
459 - <template is="wxParse6" data="{{item}}" />  
460 - </block>  
461 - </view>  
462 - </view>  
463 - </view>  
464 - </block>  
465 -  
466 - <!--video类型-->  
467 - <block wx:elif="{{item.tag == 'video'}}">  
468 - <template is="wxParseVideo" data="{{item}}" />  
469 - </block>  
470 -  
471 - <!--img类型-->  
472 - <block wx:elif="{{item.tag == 'img'}}">  
473 - <template is="wxParseImg" data="{{item}}" />  
474 - </block>  
475 -  
476 - <!--a类型-->  
477 - <block wx:elif="{{item.tag == 'a'}}">  
478 - <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}">  
479 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
480 - <template is="wxParse6" data="{{item}}" />  
481 - </block>  
482 - </view>  
483 - </block>  
484 -  
485 - <block wx:elif="{{item.tag == 'br'}}">  
486 - <template is="WxParseBr"></template>  
487 - </block>  
488 - <!--其他块级标签-->  
489 - <block wx:elif="{{item.tagType == 'block'}}">  
490 - <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">  
491 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
492 - <template is="wxParse6" data="{{item}}" />  
493 - </block>  
494 - </view>  
495 - </block>  
496 -  
497 - <!--内联标签-->  
498 - <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">  
499 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
500 - <template is="wxParse6" data="{{item}}" />  
501 - </block>  
502 - </view>  
503 -  
504 - </block>  
505 -  
506 - <!--判断是否是文本节点-->  
507 - <block wx:elif="{{item.node == 'text'}}">  
508 - <!--如果是,直接进行-->  
509 - <template is="WxEmojiView" data="{{item}}" />  
510 - </block>  
511 -  
512 -</template>  
513 -  
514 -<!--循环模版-->  
515 -<template name="wxParse6">  
516 - <!--<template is="wxParse7" data="{{item}}" />-->  
517 - <!--判断是否是标签节点-->  
518 - <block wx:if="{{item.node == 'element'}}">  
519 - <block wx:if="{{item.tag == 'button'}}">  
520 - <button type="default" size="mini">  
521 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
522 - <template is="wxParse7" data="{{item}}" />  
523 - </block>  
524 - </button>  
525 - </block>  
526 - <!--li类型-->  
527 - <block wx:elif="{{item.tag == 'li'}}">  
528 - <view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}">  
529 - <view class="{{item.classStr}} wxParse-li-inner">  
530 - <view class="{{item.classStr}} wxParse-li-text">  
531 - <view class="{{item.classStr}} wxParse-li-circle"></view>  
532 - </view>  
533 - <view class="{{item.classStr}} wxParse-li-text">  
534 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
535 - <template is="wxParse7" data="{{item}}" />  
536 - </block>  
537 - </view>  
538 - </view>  
539 - </view>  
540 - </block>  
541 -  
542 - <!--video类型-->  
543 - <block wx:elif="{{item.tag == 'video'}}">  
544 - <template is="wxParseVideo" data="{{item}}" />  
545 - </block>  
546 -  
547 - <!--img类型-->  
548 - <block wx:elif="{{item.tag == 'img'}}">  
549 - <template is="wxParseImg" data="{{item}}" />  
550 - </block>  
551 -  
552 - <!--a类型-->  
553 - <block wx:elif="{{item.tag == 'a'}}">  
554 - <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}">  
555 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
556 - <template is="wxParse7" data="{{item}}" />  
557 - </block>  
558 - </view>  
559 - </block>  
560 -  
561 - <block wx:elif="{{item.tag == 'br'}}">  
562 - <template is="WxParseBr"></template>  
563 - </block>  
564 - <!--其他块级标签-->  
565 - <block wx:elif="{{item.tagType == 'block'}}">  
566 - <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">  
567 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
568 - <template is="wxParse7" data="{{item}}" />  
569 - </block>  
570 - </view>  
571 - </block>  
572 -  
573 - <!--内联标签-->  
574 - <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">  
575 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
576 - <template is="wxParse7" data="{{item}}" />  
577 - </block>  
578 - </view>  
579 -  
580 - </block>  
581 -  
582 - <!--判断是否是文本节点-->  
583 - <block wx:elif="{{item.node == 'text'}}">  
584 - <!--如果是,直接进行-->  
585 - <template is="WxEmojiView" data="{{item}}" />  
586 - </block>  
587 -  
588 -</template>  
589 -<!--循环模版-->  
590 -<template name="wxParse7">  
591 - <!--<template is="wxParse8" data="{{item}}" />-->  
592 - <!--判断是否是标签节点-->  
593 - <block wx:if="{{item.node == 'element'}}">  
594 - <block wx:if="{{item.tag == 'button'}}">  
595 - <button type="default" size="mini">  
596 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
597 - <template is="wxParse8" data="{{item}}" />  
598 - </block>  
599 - </button>  
600 - </block>  
601 - <!--li类型-->  
602 - <block wx:elif="{{item.tag == 'li'}}">  
603 - <view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}">  
604 - <view class="{{item.classStr}} wxParse-li-inner">  
605 - <view class="{{item.classStr}} wxParse-li-text">  
606 - <view class="{{item.classStr}} wxParse-li-circle"></view>  
607 - </view>  
608 - <view class="{{item.classStr}} wxParse-li-text">  
609 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
610 - <template is="wxParse8" data="{{item}}" />  
611 - </block>  
612 - </view>  
613 - </view>  
614 - </view>  
615 - </block>  
616 -  
617 - <!--video类型-->  
618 - <block wx:elif="{{item.tag == 'video'}}">  
619 - <template is="wxParseVideo" data="{{item}}" />  
620 - </block>  
621 -  
622 - <!--img类型-->  
623 - <block wx:elif="{{item.tag == 'img'}}">  
624 - <template is="wxParseImg" data="{{item}}" />  
625 - </block>  
626 -  
627 - <!--a类型-->  
628 - <block wx:elif="{{item.tag == 'a'}}">  
629 - <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}">  
630 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
631 - <template is="wxParse8" data="{{item}}" />  
632 - </block>  
633 - </view>  
634 - </block>  
635 -  
636 - <block wx:elif="{{item.tag == 'br'}}">  
637 - <template is="WxParseBr"></template>  
638 - </block>  
639 - <!--其他块级标签-->  
640 - <block wx:elif="{{item.tagType == 'block'}}">  
641 - <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">  
642 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
643 - <template is="wxParse8" data="{{item}}" />  
644 - </block>  
645 - </view>  
646 - </block>  
647 -  
648 - <!--内联标签-->  
649 - <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">  
650 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
651 - <template is="wxParse8" data="{{item}}" />  
652 - </block>  
653 - </view>  
654 -  
655 - </block>  
656 -  
657 - <!--判断是否是文本节点-->  
658 - <block wx:elif="{{item.node == 'text'}}">  
659 - <!--如果是,直接进行-->  
660 - <template is="WxEmojiView" data="{{item}}" />  
661 - </block>  
662 -  
663 -</template>  
664 -  
665 -<!--循环模版-->  
666 -<template name="wxParse8">  
667 - <!--<template is="wxParse9" data="{{item}}" />-->  
668 - <!--判断是否是标签节点-->  
669 - <block wx:if="{{item.node == 'element'}}">  
670 - <block wx:if="{{item.tag == 'button'}}">  
671 - <button type="default" size="mini">  
672 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
673 - <template is="wxParse9" data="{{item}}" />  
674 - </block>  
675 - </button>  
676 - </block>  
677 - <!--li类型-->  
678 - <block wx:elif="{{item.tag == 'li'}}">  
679 - <view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}">  
680 - <view class="{{item.classStr}} wxParse-li-inner">  
681 - <view class="{{item.classStr}} wxParse-li-text">  
682 - <view class="{{item.classStr}} wxParse-li-circle"></view>  
683 - </view>  
684 - <view class="{{item.classStr}} wxParse-li-text">  
685 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
686 - <template is="wxParse9" data="{{item}}" />  
687 - </block>  
688 - </view>  
689 - </view>  
690 - </view>  
691 - </block>  
692 -  
693 - <!--video类型-->  
694 - <block wx:elif="{{item.tag == 'video'}}">  
695 - <template is="wxParseVideo" data="{{item}}" />  
696 - </block>  
697 -  
698 - <!--img类型-->  
699 - <block wx:elif="{{item.tag == 'img'}}">  
700 - <template is="wxParseImg" data="{{item}}" />  
701 - </block>  
702 -  
703 - <!--a类型-->  
704 - <block wx:elif="{{item.tag == 'a'}}">  
705 - <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}">  
706 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
707 - <template is="wxParse9" data="{{item}}" />  
708 - </block>  
709 - </view>  
710 - </block>  
711 -  
712 - <block wx:elif="{{item.tag == 'br'}}">  
713 - <template is="WxParseBr"></template>  
714 - </block>  
715 - <!--其他块级标签-->  
716 - <block wx:elif="{{item.tagType == 'block'}}">  
717 - <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">  
718 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
719 - <template is="wxParse9" data="{{item}}" />  
720 - </block>  
721 - </view>  
722 - </block>  
723 -  
724 - <!--内联标签-->  
725 - <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">  
726 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
727 - <template is="wxParse9" data="{{item}}" />  
728 - </block>  
729 - </view>  
730 -  
731 - </block>  
732 -  
733 - <!--判断是否是文本节点-->  
734 - <block wx:elif="{{item.node == 'text'}}">  
735 - <!--如果是,直接进行-->  
736 - <template is="WxEmojiView" data="{{item}}" />  
737 - </block>  
738 -  
739 -</template>  
740 -  
741 -<!--循环模版-->  
742 -<template name="wxParse9">  
743 - <!--<template is="wxParse10" data="{{item}}" />-->  
744 - <!--判断是否是标签节点-->  
745 - <block wx:if="{{item.node == 'element'}}">  
746 - <block wx:if="{{item.tag == 'button'}}">  
747 - <button type="default" size="mini">  
748 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
749 - <template is="wxParse10" data="{{item}}" />  
750 - </block>  
751 - </button>  
752 - </block>  
753 - <!--li类型-->  
754 - <block wx:elif="{{item.tag == 'li'}}">  
755 - <view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}">  
756 - <view class="{{item.classStr}} wxParse-li-inner">  
757 - <view class="{{item.classStr}} wxParse-li-text">  
758 - <view class="{{item.classStr}} wxParse-li-circle"></view>  
759 - </view>  
760 - <view class="{{item.classStr}} wxParse-li-text">  
761 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
762 - <template is="wxParse10" data="{{item}}" />  
763 - </block>  
764 - </view>  
765 - </view>  
766 - </view>  
767 - </block>  
768 -  
769 - <!--video类型-->  
770 - <block wx:elif="{{item.tag == 'video'}}">  
771 - <template is="wxParseVideo" data="{{item}}" />  
772 - </block>  
773 -  
774 - <!--img类型-->  
775 - <block wx:elif="{{item.tag == 'img'}}">  
776 - <template is="wxParseImg" data="{{item}}" />  
777 - </block>  
778 -  
779 - <!--a类型-->  
780 - <block wx:elif="{{item.tag == 'a'}}">  
781 - <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}">  
782 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
783 - <template is="wxParse10" data="{{item}}" />  
784 - </block>  
785 - </view>  
786 - </block>  
787 -  
788 - <block wx:elif="{{item.tag == 'br'}}">  
789 - <template is="WxParseBr"></template>  
790 - </block>  
791 - <!--其他块级标签-->  
792 - <block wx:elif="{{item.tagType == 'block'}}">  
793 - <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">  
794 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
795 - <template is="wxParse10" data="{{item}}" />  
796 - </block>  
797 - </view>  
798 - </block>  
799 -  
800 - <!--内联标签-->  
801 - <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">  
802 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
803 - <template is="wxParse10" data="{{item}}" />  
804 - </block>  
805 - </view>  
806 -  
807 - </block>  
808 -  
809 - <!--判断是否是文本节点-->  
810 - <block wx:elif="{{item.node == 'text'}}">  
811 - <!--如果是,直接进行-->  
812 - <template is="WxEmojiView" data="{{item}}" />  
813 - </block>  
814 -  
815 -</template>  
816 -  
817 -<!--循环模版-->  
818 -<template name="wxParse10">  
819 - <!--<template is="wxParse11" data="{{item}}" />-->  
820 - <!--判断是否是标签节点-->  
821 - <block wx:if="{{item.node == 'element'}}">  
822 - <block wx:if="{{item.tag == 'button'}}">  
823 - <button type="default" size="mini">  
824 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
825 - <template is="wxParse11" data="{{item}}" />  
826 - </block>  
827 - </button>  
828 - </block>  
829 - <!--li类型-->  
830 - <block wx:elif="{{item.tag == 'li'}}">  
831 - <view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}">  
832 - <view class="{{item.classStr}} wxParse-li-inner">  
833 - <view class="{{item.classStr}} wxParse-li-text">  
834 - <view class="{{item.classStr}} wxParse-li-circle"></view>  
835 - </view>  
836 - <view class="{{item.classStr}} wxParse-li-text">  
837 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
838 - <template is="wxParse11" data="{{item}}" />  
839 - </block>  
840 - </view>  
841 - </view>  
842 - </view>  
843 - </block>  
844 -  
845 - <!--video类型-->  
846 - <block wx:elif="{{item.tag == 'video'}}">  
847 - <template is="wxParseVideo" data="{{item}}" />  
848 - </block>  
849 -  
850 - <!--img类型-->  
851 - <block wx:elif="{{item.tag == 'img'}}">  
852 - <template is="wxParseImg" data="{{item}}" />  
853 - </block>  
854 -  
855 - <!--a类型-->  
856 - <block wx:elif="{{item.tag == 'a'}}">  
857 - <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}">  
858 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
859 - <template is="wxParse11" data="{{item}}" />  
860 - </block>  
861 - </view>  
862 - </block>  
863 -  
864 - <block wx:elif="{{item.tag == 'br'}}">  
865 - <template is="WxParseBr"></template>  
866 - </block>  
867 - <!--其他块级标签-->  
868 - <block wx:elif="{{item.tagType == 'block'}}">  
869 - <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">  
870 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
871 - <template is="wxParse11" data="{{item}}" />  
872 - </block>  
873 - </view>  
874 - </block>  
875 -  
876 - <!--内联标签-->  
877 - <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">  
878 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
879 - <template is="wxParse11" data="{{item}}" />  
880 - </block>  
881 - </view>  
882 -  
883 - </block>  
884 -  
885 - <!--判断是否是文本节点-->  
886 - <block wx:elif="{{item.node == 'text'}}">  
887 - <!--如果是,直接进行-->  
888 - <template is="WxEmojiView" data="{{item}}" />  
889 - </block>  
890 -  
891 -</template>  
892 -  
893 -<!--循环模版-->  
894 -<template name="wxParse11">  
895 - <!--<template is="wxParse12" data="{{item}}" />-->  
896 - <!--判断是否是标签节点-->  
897 - <block wx:if="{{item.node == 'element'}}">  
898 - <block wx:if="{{item.tag == 'button'}}">  
899 - <button type="default" size="mini">  
900 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
901 - <template is="wxParse12" data="{{item}}" />  
902 - </block>  
903 - </button>  
904 - </block>  
905 - <!--li类型-->  
906 - <block wx:elif="{{item.tag == 'li'}}">  
907 - <view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}">  
908 - <view class="{{item.classStr}} wxParse-li-inner">  
909 - <view class="{{item.classStr}} wxParse-li-text">  
910 - <view class="{{item.classStr}} wxParse-li-circle"></view>  
911 - </view>  
912 - <view class="{{item.classStr}} wxParse-li-text">  
913 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
914 - <template is="wxParse12" data="{{item}}" />  
915 - </block>  
916 - </view>  
917 - </view>  
918 - </view>  
919 - </block>  
920 -  
921 - <!--video类型-->  
922 - <block wx:elif="{{item.tag == 'video'}}">  
923 - <template is="wxParseVideo" data="{{item}}" />  
924 - </block>  
925 -  
926 - <!--img类型-->  
927 - <block wx:elif="{{item.tag == 'img'}}">  
928 - <template is="wxParseImg" data="{{item}}" />  
929 - </block>  
930 -  
931 - <!--a类型-->  
932 - <block wx:elif="{{item.tag == 'a'}}">  
933 - <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}">  
934 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
935 - <template is="wxParse12" data="{{item}}" />  
936 - </block>  
937 - </view>  
938 - </block>  
939 -  
940 - <block wx:elif="{{item.tag == 'br'}}">  
941 - <template is="WxParseBr"></template>  
942 - </block>  
943 - <!--其他块级标签-->  
944 - <block wx:elif="{{item.tagType == 'block'}}">  
945 - <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">  
946 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
947 - <template is="wxParse12" data="{{item}}" />  
948 - </block>  
949 - </view>  
950 - </block>  
951 -  
952 - <!--内联标签-->  
953 - <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">  
954 - <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">  
955 - <template is="wxParse12" data="{{item}}" />  
956 - </block>  
957 - </view>  
958 -  
959 - </block>  
960 -  
961 - <!--判断是否是文本节点-->  
962 - <block wx:elif="{{item.node == 'text'}}">  
963 - <!--如果是,直接进行-->  
964 - <template is="WxEmojiView" data="{{item}}" />  
965 - </block>  
966 -  
967 -</template>  
1 -  
2 -/**  
3 - * author: Di (微信小程序开发工程师)  
4 - * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)  
5 - * 垂直微信小程序开发交流社区  
6 - *  
7 - * github地址: https://github.com/icindy/wxParse  
8 - *  
9 - * for: 微信小程序富文本解析  
10 - * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184  
11 - */  
12 -  
13 -.wxParse{  
14 - margin: 0 5px;  
15 - font-family: Helvetica,sans-serif;  
16 - font-size: 28rpx;  
17 - color: #666;  
18 - line-height: 1.8;  
19 -}  
20 -view{  
21 - word-break:break-all;  
22 - /*overflow:auto;*/  
23 -}  
24 -.wxParse-inline{  
25 - display: inline;  
26 - line-height: 50rpx;  
27 - margin: 0;  
28 - padding: 0;  
29 -}  
30 -/*//标题 */  
31 -.wxParse-div{margin: 0;padding: 0;}  
32 -.wxParse-h1{ font-size:2em; margin: .67em 0 }  
33 -.wxParse-h2{ font-size:1.5em; margin: .75em 0 }  
34 -.wxParse-h3{ font-size:1.17em; margin: .83em 0 }  
35 -.wxParse-h4{ margin: 1.12em 0}  
36 -.wxParse-h5 { font-size:.83em; margin: 1.5em 0 }  
37 -.wxParse-h6{ font-size:.75em; margin: 1.67em 0 }  
38 -  
39 -.wxParse-h1 {  
40 - font-size: 18px;  
41 - font-weight: 400;  
42 - margin-bottom: .9em;  
43 -}  
44 -.wxParse-h2 {  
45 - font-size: 16px;  
46 - font-weight: 400;  
47 - margin-bottom: .34em;  
48 -}  
49 -.wxParse-h3 {  
50 - font-weight: 400;  
51 - font-size: 15px;  
52 - margin-bottom: .34em;  
53 -}  
54 -.wxParse-h4 {  
55 - font-weight: 400;  
56 - font-size: 14px;  
57 - margin-bottom: .24em;  
58 -}  
59 -.wxParse-h5 {  
60 - font-weight: 400;  
61 - font-size: 13px;  
62 - margin-bottom: .14em;  
63 -}  
64 -.wxParse-h6 {  
65 - font-weight: 400;  
66 - font-size: 12px;  
67 - margin-bottom: .04em;  
68 -}  
69 -  
70 -.wxParse-h1, .wxParse-h2, .wxParse-h3, .wxParse-h4, .wxParse-h5, .wxParse-h6, .wxParse-b, .wxParse-strong { font-weight: bolder }  
71 -  
72 -.wxParse-i,.wxParse-cite,.wxParse-em,.wxParse-var,.wxParse-address{font-style:italic}  
73 -.wxParse-pre,.wxParse-tt,.wxParse-code,.wxParse-kbd,.wxParse-samp{font-family:monospace}  
74 -.wxParse-pre{white-space:pre}  
75 -.wxParse-big{font-size:1.17em}  
76 -.wxParse-small,.wxParse-sub,.wxParse-sup{font-size:.83em}  
77 -.wxParse-sub{vertical-align:sub}  
78 -.wxParse-sup{vertical-align:super}  
79 -.wxParse-s,.wxParse-strike,.wxParse-del{text-decoration:line-through}  
80 -/*wxparse-自定义个性化的css样式*/  
81 -/*增加video的css样式*/  
82 -.wxParse-strong,.wxParse-s{display: inline}  
83 -.wxParse-a{  
84 - color: deepskyblue;  
85 - word-break:break-all;  
86 - overflow:auto;  
87 -}  
88 -  
89 -.wxParse-video{  
90 - text-align: center;  
91 - margin: 10px 0;  
92 -}  
93 -  
94 -.wxParse-video-video{  
95 - width:100%;  
96 -}  
97 -  
98 -.wxParse-img{  
99 - /*background-color: #efefef;*/  
100 - overflow: hidden;  
101 -}  
102 -  
103 -.wxParse-blockquote {  
104 - margin: 0;  
105 - padding:10px 0 10px 5px;  
106 - font-family:Courier, Calibri,"宋体";  
107 - background:#f5f5f5;  
108 - border-left: 3px solid #dbdbdb;  
109 -}  
110 -  
111 -.wxParse-code,.wxParse-wxxxcode-style{  
112 - display: inline;  
113 - background:#f5f5f5;  
114 -}  
115 -.wxParse-ul{  
116 - margin: 20rpx 10rpx;  
117 -}  
118 -  
119 -.wxParse-li,.wxParse-li-inner{  
120 - display: flex;  
121 - align-items: baseline;  
122 - margin: 10rpx 0;  
123 -}  
124 -.wxParse-li-text{  
125 -  
126 - align-items: center;  
127 - line-height: 20px;  
128 -}  
129 -  
130 -.wxParse-li-circle{  
131 - display: inline-flex;  
132 - width: 5px;  
133 - height: 5px;  
134 - background-color: #333;  
135 - margin-right: 5px;  
136 -}  
137 -  
138 -.wxParse-li-square{  
139 - display: inline-flex;  
140 - width: 10rpx;  
141 - height: 10rpx;  
142 - background-color: #333;  
143 - margin-right: 5px;  
144 -}  
145 -.wxParse-li-ring{  
146 - display: inline-flex;  
147 - width: 10rpx;  
148 - height: 10rpx;  
149 - border: 2rpx solid #333;  
150 - border-radius: 50%;  
151 - background-color: #fff;  
152 - margin-right: 5px;  
153 -}  
154 -  
155 -/*.wxParse-table{  
156 - width: 100%;  
157 - height: 400px;  
158 -}  
159 -.wxParse-thead,.wxParse-tfoot,.wxParse-tr{  
160 - display: flex;  
161 - flex-direction: row;  
162 -}  
163 -.wxParse-th,.wxParse-td{  
164 - display: flex;  
165 - width: 580px;  
166 - overflow: auto;  
167 -}*/  
168 -  
169 -.wxParse-u {  
170 - text-decoration: underline;  
171 -}  
172 -.wxParse-hide{  
173 - display: none;  
174 -}  
175 -.WxEmojiView{  
176 - align-items: center;  
177 -}  
178 -.wxEmoji{  
179 - width: 16px;  
180 - height:16px;  
181 -}  
182 -.wxParse-tr{  
183 - display: flex;  
184 - border-right:1px solid #e0e0e0;  
185 - border-bottom:1px solid #e0e0e0;  
186 - border-top:1px solid #e0e0e0;  
187 -}  
188 -.wxParse-th,  
189 -.wxParse-td{  
190 - flex:1;  
191 - padding:5px;  
192 - font-size:28rpx;  
193 - border-left:1px solid #e0e0e0;  
194 - word-break: break-all;  
195 -}  
196 -.wxParse-td:last{  
197 - border-top:1px solid #e0e0e0;  
198 -}  
199 -.wxParse-th{  
200 - background:#f0f0f0;  
201 - border-top:1px solid #e0e0e0;  
202 -}  
203 -.wxParse-del{  
204 - display: inline;  
205 -}  
206 -.wxParse-figure {  
207 - overflow: hidden;  
208 -}