├── images
└── arrowright.png
├── screenshots
├── list.png
└── detail.png
├── app.wxss
├── pages
├── index
│ ├── index.wxml
│ ├── header.wxml
│ ├── list.wxml
│ ├── index.wxss
│ └── index.js
└── detail
│ ├── index.wxml
│ ├── index.wxss
│ └── index.js
├── README.md
├── app.js
├── app.json
├── util
├── util.js
└── marked.min.js
└── wxParse
├── wxParse.js
├── wxParse.wxss
├── html2json.js
├── wxDiscode.js
├── htmlparser.js
├── wxParse.wxml
└── showdown.js
/images/arrowright.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eyasliu/wechat-app-github-blog/HEAD/images/arrowright.png
--------------------------------------------------------------------------------
/screenshots/list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eyasliu/wechat-app-github-blog/HEAD/screenshots/list.png
--------------------------------------------------------------------------------
/screenshots/detail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eyasliu/wechat-app-github-blog/HEAD/screenshots/detail.png
--------------------------------------------------------------------------------
/app.wxss:
--------------------------------------------------------------------------------
1 | /**app.wxss**/
2 | .container {
3 | min-height: 100%;
4 | font-family: "microsoft yahei";
5 | background: #f2f2f2;
6 | }
7 |
--------------------------------------------------------------------------------
/pages/index/index.wxml:
--------------------------------------------------------------------------------
1 |
2 | "+text+"
71 | // add to parents
72 | var parent = bufArray[0] || results;
73 | if (parent.child === undefined) {
74 | parent.child = [];
75 | }
76 | parent.child.push(node);
77 | } else {
78 | bufArray.unshift(node);
79 | }
80 | },
81 | end: function(tag) {
82 | //debug(tag);
83 | // merge into parent tag
84 | var node = bufArray.shift();
85 | if (node.tag !== tag) console.error('invalid state: mismatch end tag');
86 |
87 | if (bufArray.length === 0) {
88 | results.child.push(node);
89 | } else {
90 | var parent = bufArray[0];
91 | if (parent.child === undefined) {
92 | parent.child = [];
93 | }
94 | parent.child.push(node);
95 | }
96 | },
97 | chars: function(text) {
98 | //debug(text);
99 | var node = {
100 | node: 'text',
101 | text: text,
102 | };
103 | if (bufArray.length === 0) {
104 | results.child.push(node);
105 | } else {
106 | var parent = bufArray[0];
107 | if (parent.child === undefined) {
108 | parent.child = [];
109 | }
110 | parent.child.push(node);
111 | }
112 | },
113 | comment: function(text) {
114 | //debug(text);
115 | var node = {
116 | node: 'comment',
117 | text: text,
118 | };
119 | var parent = bufArray[0];
120 | if (parent.child === undefined) {
121 | parent.child = [];
122 | }
123 | parent.child.push(node);
124 | },
125 | });
126 | return results;
127 | };
128 |
129 | function json2html(json) {
130 | // Empty Elements - HTML 4.01
131 | var empty = ['area', 'base', 'basefont', 'br', 'col', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param', 'embed'];
132 |
133 | var child = '';
134 | if (json.child) {
135 | child = json.child.map(function(c) {
136 | return json2html(c);
137 | }).join('');
138 | }
139 |
140 | var attr = '';
141 | if (json.attr) {
142 | attr = Object.keys(json.attr).map(function(key) {
143 | var value = json.attr[key];
144 | if (Array.isArray(value)) value = value.join(' ');
145 | return key + '=' + q(value);
146 | }).join(' ');
147 | if (attr !== '') attr = ' ' + attr;
148 | }
149 |
150 | if (json.node === 'element') {
151 | var tag = json.tag;
152 | if (empty.indexOf(tag) > -1) {
153 | // empty element
154 | return '<' + json.tag + attr + '/>';
155 | }
156 |
157 | // non empty element
158 | var open = '<' + json.tag + attr + '>';
159 | var close = '' + json.tag + '>';
160 | return open + child + close;
161 | }
162 |
163 | if (json.node === 'text') {
164 | return json.text;
165 | }
166 |
167 | if (json.node === 'comment') {
168 | return '';
169 | }
170 |
171 | if (json.node === 'root') {
172 | return child;
173 | }
174 | };
175 |
176 | module.exports = html2json;
177 |
178 |
--------------------------------------------------------------------------------
/wxParse/wxDiscode.js:
--------------------------------------------------------------------------------
1 | // HTML 支持的数学符号
2 | function strNumDiscode(str){
3 | str = str.replace(/∀/g, '∀');
4 | str = str.replace(/∂/g, '∂');
5 | str = str.replace(/&exists;/g, '∃');
6 | str = str.replace(/∅/g, '∅');
7 | str = str.replace(/∇/g, '∇');
8 | str = str.replace(/∈/g, '∈');
9 | str = str.replace(/∉/g, '∉');
10 | str = str.replace(/∋/g, '∋');
11 | str = str.replace(/∏/g, '∏');
12 | str = str.replace(/∑/g, '∑');
13 | str = str.replace(/−/g, '−');
14 | str = str.replace(/∗/g, '∗');
15 | str = str.replace(/√/g, '√');
16 | str = str.replace(/∝/g, '∝');
17 | str = str.replace(/∞/g, '∞');
18 | str = str.replace(/∠/g, '∠');
19 | str = str.replace(/∧/g, '∧');
20 | str = str.replace(/∨/g, '∨');
21 | str = str.replace(/∩/g, '∩');
22 | str = str.replace(/∩/g, '∪');
23 | str = str.replace(/∫/g, '∫');
24 | str = str.replace(/∴/g, '∴');
25 | str = str.replace(/∼/g, '∼');
26 | str = str.replace(/≅/g, '≅');
27 | str = str.replace(/≈/g, '≈');
28 | str = str.replace(/≠/g, '≠');
29 | str = str.replace(/≤/g, '≤');
30 | str = str.replace(/≥/g, '≥');
31 | str = str.replace(/⊂/g, '⊂');
32 | str = str.replace(/⊃/g, '⊃');
33 | str = str.replace(/⊄/g, '⊄');
34 | str = str.replace(/⊆/g, '⊆');
35 | str = str.replace(/⊇/g, '⊇');
36 | str = str.replace(/⊕/g, '⊕');
37 | str = str.replace(/⊗/g, '⊗');
38 | str = str.replace(/⊥/g, '⊥');
39 | str = str.replace(/⋅/g, '⋅');
40 | return str;
41 | }
42 |
43 | //HTML 支持的希腊字母
44 | function strGreeceDiscode(str){
45 | str = str.replace(/Α/g, 'Α');
46 | str = str.replace(/Β/g, 'Β');
47 | str = str.replace(/Γ/g, 'Γ');
48 | str = str.replace(/Δ/g, 'Δ');
49 | str = str.replace(/Ε/g, 'Ε');
50 | str = str.replace(/Ζ/g, 'Ζ');
51 | str = str.replace(/Η/g, 'Η');
52 | str = str.replace(/Θ/g, 'Θ');
53 | str = str.replace(/Ι/g, 'Ι');
54 | str = str.replace(/Κ/g, 'Κ');
55 | str = str.replace(/Λ/g, 'Λ');
56 | str = str.replace(/Μ/g, 'Μ');
57 | str = str.replace(/Ν/g, 'Ν');
58 | str = str.replace(/Ξ/g, 'Ν');
59 | str = str.replace(/Ο/g, 'Ο');
60 | str = str.replace(/Π/g, 'Π');
61 | str = str.replace(/Ρ/g, 'Ρ');
62 | str = str.replace(/Σ/g, 'Σ');
63 | str = str.replace(/Τ/g, 'Τ');
64 | str = str.replace(/Υ/g, 'Υ');
65 | str = str.replace(/Φ/g, 'Φ');
66 | str = str.replace(/Χ/g, 'Χ');
67 | str = str.replace(/Ψ/g, 'Ψ');
68 | str = str.replace(/Ω/g, 'Ω');
69 |
70 | str = str.replace(/α/g, 'α');
71 | str = str.replace(/β/g, 'β');
72 | str = str.replace(/γ/g, 'γ');
73 | str = str.replace(/δ/g, 'δ');
74 | str = str.replace(/ε/g, 'ε');
75 | str = str.replace(/ζ/g, 'ζ');
76 | str = str.replace(/η/g, 'η');
77 | str = str.replace(/θ/g, 'θ');
78 | str = str.replace(/ι/g, 'ι');
79 | str = str.replace(/κ/g, 'κ');
80 | str = str.replace(/λ/g, 'λ');
81 | str = str.replace(/μ/g, 'μ');
82 | str = str.replace(/ν/g, 'ν');
83 | str = str.replace(/ξ/g, 'ξ');
84 | str = str.replace(/ο/g, 'ο');
85 | str = str.replace(/π/g, 'π');
86 | str = str.replace(/ρ/g, 'ρ');
87 | str = str.replace(/ς/g, 'ς');
88 | str = str.replace(/σ/g, 'σ');
89 | str = str.replace(/τ/g, 'τ');
90 | str = str.replace(/υ/g, 'υ');
91 | str = str.replace(/φ/g, 'φ');
92 | str = str.replace(/χ/g, 'χ');
93 | str = str.replace(/ψ/g, 'ψ');
94 | str = str.replace(/ω/g, 'ω');
95 | str = str.replace(/ϑ/g, 'ϑ');
96 | str = str.replace(/ϒ/g, 'ϒ');
97 | str = str.replace(/ϖ/g, 'ϖ');
98 |
99 | return str;
100 | }
101 |
102 | //
103 |
104 | function strcharacterDiscode(str){
105 | // 加入常用解析
106 | str = str.replace(/ /g, ' ');
107 | str = str.replace(/"/g, '"');
108 | str = str.replace(/&/g, '&');
109 | str = str.replace(/</g, '<');
110 | str = str.replace(/>/g, '>');
111 |
112 | return str;
113 | }
114 |
115 | // HTML 支持的其他实体
116 | function strOtherDiscode(str){
117 | str = str.replace(/Œ/g, 'Œ');
118 | str = str.replace(/œ/g, 'œ');
119 | str = str.replace(/Š/g, 'Š');
120 | str = str.replace(/š/g, 'š');
121 | str = str.replace(/Ÿ/g, 'Ÿ');
122 | str = str.replace(/ƒ/g, 'ƒ');
123 | str = str.replace(/ˆ/g, 'ˆ');
124 | str = str.replace(/˜/g, '˜');
125 | str = str.replace(/ /g, '');
126 | str = str.replace(/ /g, '');
127 | str = str.replace(/ /g, '');
128 | str = str.replace(//g, '');
129 | str = str.replace(//g, '');
130 | str = str.replace(//g, '');
131 | str = str.replace(//g, '');
132 | str = str.replace(/–/g, '–');
133 | str = str.replace(/—/g, '—');
134 | str = str.replace(/‘/g, '‘');
135 | str = str.replace(/’/g, '’');
136 | str = str.replace(/‚/g, '‚');
137 | str = str.replace(/“/g, '“');
138 | str = str.replace(/”/g, '”');
139 | str = str.replace(/„/g, '„');
140 | str = str.replace(/†/g, '†');
141 | str = str.replace(/‡/g, '‡');
142 | str = str.replace(/•/g, '•');
143 | str = str.replace(/…/g, '…');
144 | str = str.replace(/‰/g, '‰');
145 | str = str.replace(/′/g, '′');
146 | str = str.replace(/″/g, '″');
147 | str = str.replace(/‹/g, '‹');
148 | str = str.replace(/›/g, '›');
149 | str = str.replace(/‾/g, '‾');
150 | str = str.replace(/€/g, '€');
151 | str = str.replace(/™/g, '™');
152 |
153 | str = str.replace(/←/g, '←');
154 | str = str.replace(/↑/g, '↑');
155 | str = str.replace(/→/g, '→');
156 | str = str.replace(/↓/g, '↓');
157 | str = str.replace(/↔/g, '↔');
158 | str = str.replace(/↵/g, '↵');
159 | str = str.replace(/⌈/g, '⌈');
160 | str = str.replace(/⌉/g, '⌉');
161 |
162 | str = str.replace(/⌊/g, '⌊');
163 | str = str.replace(/⌋/g, '⌋');
164 | str = str.replace(/◊/g, '◊');
165 | str = str.replace(/♠/g, '♠');
166 | str = str.replace(/♣/g, '♣');
167 | str = str.replace(/♥/g, '♥');
168 |
169 | str = str.replace(/♦/g, '♦');
170 |
171 | return str;
172 | }
173 |
174 | function strMoreDiscode(str){
175 | str = str.replace(/\r\n/g,"");
176 | str = str.replace(/\n\n/g,"\n");
177 | str = str.replace(/code/g,"wxxxcode-style");
178 | return str;
179 | }
180 |
181 | function strDiscode(str){
182 | str = strNumDiscode(str);
183 | str = strGreeceDiscode(str);
184 | str = strcharacterDiscode(str);
185 | str = strOtherDiscode(str);
186 | str = strMoreDiscode(str);
187 | return str;
188 | }
189 |
190 | module.exports = {
191 | strDiscode:strDiscode
192 | }
--------------------------------------------------------------------------------
/wxParse/htmlparser.js:
--------------------------------------------------------------------------------
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 | // Regular Expressions for parsing tags and attributes
12 | var startTag = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/,
13 | endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/,
14 | attr = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g;
15 |
16 | // Empty Elements - HTML 5
17 | var empty = makeMap("area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr");
18 |
19 | // Block Elements - HTML 5
20 | var block = makeMap("a,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");
21 |
22 | // Inline Elements - HTML 5
23 | var inline = makeMap("abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,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");
24 |
25 | // Elements that you can, intentionally, leave open
26 | // (and which close themselves)
27 | var closeSelf = makeMap("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr");
28 |
29 | // Attributes that have their values filled in disabled="disabled"
30 | var fillAttrs = makeMap("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected");
31 |
32 | // Special Elements (can contain anything)
33 | var special = makeMap("wxxxcode-style,script,style,view,scroll-view,block");
34 |
35 | function HTMLParser(html, handler) {
36 | var index, chars, match, stack = [], last = html;
37 | stack.last = function () {
38 | return this[this.length - 1];
39 | };
40 |
41 | while (html) {
42 | chars = true;
43 |
44 | // Make sure we're not in a script or style element
45 | if (!stack.last() || !special[stack.last()]) {
46 |
47 | // Comment
48 | if (html.indexOf("");
50 |
51 | if (index >= 0) {
52 | if (handler.comment)
53 | handler.comment(html.substring(4, index));
54 | html = html.substring(index + 3);
55 | chars = false;
56 | }
57 |
58 | // end tag
59 | } else if (html.indexOf("") == 0) {
60 | match = html.match(endTag);
61 |
62 | if (match) {
63 | html = html.substring(match[0].length);
64 | match[0].replace(endTag, parseEndTag);
65 | chars = false;
66 | }
67 |
68 | // start tag
69 | } else if (html.indexOf("<") == 0) {
70 | match = html.match(startTag);
71 |
72 | if (match) {
73 | html = html.substring(match[0].length);
74 | match[0].replace(startTag, parseStartTag);
75 | chars = false;
76 | }
77 | }
78 |
79 | if (chars) {
80 | index = html.indexOf("<");
81 |
82 | var text = index < 0 ? html : html.substring(0, index);
83 | html = index < 0 ? "" : html.substring(index);
84 |
85 | if (handler.chars)
86 | handler.chars(text);
87 | }
88 |
89 | } else {
90 |
91 |
92 | // if(special[stack.last()]){
93 | // console.log("code");
94 | // }else{
95 | // html = html.replace(new RegExp("([\\s\\S]*?)<\/" + stack.last() + "[^>]*>"), function (all, text) {
96 | // text = text.replace(/|/g, "$1$2");
97 | // if (handler.chars)
98 | // handler.chars(text);
99 |
100 | // return "";
101 | // });
102 | // }
103 |
104 | html = html.replace(new RegExp("([\\s\\S]*?)<\/" + stack.last() + "[^>]*>"), function (all, text) {
105 | text = text.replace(/|/g, "$1$2");
106 | if (handler.chars)
107 | handler.chars(text);
108 |
109 | return "";
110 | });
111 |
112 |
113 | parseEndTag("", stack.last());
114 | }
115 |
116 | if (html == last)
117 | throw "Parse Error: " + html;
118 | last = html;
119 | }
120 |
121 | // Clean up any remaining tags
122 | parseEndTag();
123 |
124 | function parseStartTag(tag, tagName, rest, unary) {
125 | tagName = tagName.toLowerCase();
126 |
127 | if (block[tagName]) {
128 | while (stack.last() && inline[stack.last()]) {
129 | parseEndTag("", stack.last());
130 | }
131 | }
132 |
133 | if (closeSelf[tagName] && stack.last() == tagName) {
134 | parseEndTag("", tagName);
135 | }
136 |
137 | unary = empty[tagName] || !!unary;
138 |
139 | if (!unary)
140 | stack.push(tagName);
141 |
142 | if (handler.start) {
143 | var attrs = [];
144 |
145 | rest.replace(attr, function (match, name) {
146 | var value = arguments[2] ? arguments[2] :
147 | arguments[3] ? arguments[3] :
148 | arguments[4] ? arguments[4] :
149 | fillAttrs[name] ? name : "";
150 |
151 | attrs.push({
152 | name: name,
153 | value: value,
154 | escaped: value.replace(/(^|[^\\])"/g, '$1\\\"') //"
155 | });
156 | });
157 |
158 | if (handler.start)
159 | handler.start(tagName, attrs, unary);
160 | }
161 | }
162 |
163 | function parseEndTag(tag, tagName) {
164 | // If no tag name is provided, clean shop
165 | if (!tagName)
166 | var pos = 0;
167 |
168 | // Find the closest opened tag of the same type
169 | else
170 | for (var pos = stack.length - 1; pos >= 0; pos--)
171 | if (stack[pos] == tagName)
172 | break;
173 |
174 | if (pos >= 0) {
175 | // Close all the open elements, up the stack
176 | for (var i = stack.length - 1; i >= pos; i--)
177 | if (handler.end)
178 | handler.end(stack[i]);
179 |
180 | // Remove the open elements from the stack
181 | stack.length = pos;
182 | }
183 | }
184 | };
185 |
186 | function HTMLtoXML(html) {
187 | var results = "";
188 |
189 | HTMLParser(html, {
190 | start: function (tag, attrs, unary) {
191 | results += "<" + tag;
192 |
193 | for (var i = 0; i < attrs.length; i++)
194 | results += " " + attrs[i].name + '="' + attrs[i].escaped + '"';
195 | results += ">";
196 | },
197 | end: function (tag) {
198 | results += "" + tag + ">";
199 | },
200 | chars: function (text) {
201 | results += text;
202 | },
203 | comment: function (text) {
204 | results += "";
205 | }
206 | });
207 |
208 | return results;
209 | };
210 |
211 | function HTMLtoDOM(html, doc) {
212 | // There can be only one of these elements
213 | var one = makeMap("html,head,body,title");
214 |
215 | // Enforce a structure for the document
216 | var structure = {
217 | link: "head",
218 | base: "head"
219 | };
220 |
221 | if (!doc) {
222 | if (typeof DOMDocument != "undefined")
223 | doc = new DOMDocument();
224 | else if (typeof document != "undefined" && document.implementation && document.implementation.createDocument)
225 | doc = document.implementation.createDocument("", "", null);
226 | else if (typeof ActiveX != "undefined")
227 | doc = new ActiveXObject("Msxml.DOMDocument");
228 |
229 | } else
230 | doc = doc.ownerDocument ||
231 | doc.getOwnerDocument && doc.getOwnerDocument() ||
232 | doc;
233 |
234 | var elems = [],
235 | documentElement = doc.documentElement ||
236 | doc.getDocumentElement && doc.getDocumentElement();
237 |
238 | // If we're dealing with an empty document then we
239 | // need to pre-populate it with the HTML document structure
240 | if (!documentElement && doc.createElement) (function () {
241 | var html = doc.createElement("html");
242 | var head = doc.createElement("head");
243 | head.appendChild(doc.createElement("title"));
244 | html.appendChild(head);
245 | html.appendChild(doc.createElement("body"));
246 | doc.appendChild(html);
247 | })();
248 |
249 | // Find all the unique elements
250 | if (doc.getElementsByTagName)
251 | for (var i in one)
252 | one[i] = doc.getElementsByTagName(i)[0];
253 |
254 | // If we're working with a document, inject contents into
255 | // the body element
256 | var curParentNode = one.body;
257 |
258 | HTMLParser(html, {
259 | start: function (tagName, attrs, unary) {
260 | // If it's a pre-built element, then we can ignore
261 | // its construction
262 | if (one[tagName]) {
263 | curParentNode = one[tagName];
264 | if (!unary) {
265 | elems.push(curParentNode);
266 | }
267 | return;
268 | }
269 |
270 | var elem = doc.createElement(tagName);
271 |
272 | for (var attr in attrs)
273 | elem.setAttribute(attrs[attr].name, attrs[attr].value);
274 |
275 | if (structure[tagName] && typeof one[structure[tagName]] != "boolean")
276 | one[structure[tagName]].appendChild(elem);
277 |
278 | else if (curParentNode && curParentNode.appendChild)
279 | curParentNode.appendChild(elem);
280 |
281 | if (!unary) {
282 | elems.push(elem);
283 | curParentNode = elem;
284 | }
285 | },
286 | end: function (tag) {
287 | elems.length -= 1;
288 |
289 | // Init the new parentNode
290 | curParentNode = elems[elems.length - 1];
291 | },
292 | chars: function (text) {
293 | curParentNode.appendChild(doc.createTextNode(text));
294 | },
295 | comment: function (text) {
296 | // create comment node
297 | }
298 | });
299 |
300 | return doc;
301 | };
302 |
303 | function makeMap(str) {
304 | var obj = {}, items = str.split(",");
305 | for (var i = 0; i < items.length; i++)
306 | obj[items[i]] = true;
307 | return obj;
308 | }
309 |
310 |
311 | // CommonJS/nodeJS Loader
312 |
313 | module.exports = HTMLParser;
314 |
--------------------------------------------------------------------------------
/util/marked.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * marked - a markdown parser
3 | * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
4 | * https://github.com/chjj/marked
5 | */
6 | (function(){var block={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:noop,hr:/^( *[-*_]){3,} *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,nptable:noop,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,blockquote:/^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,def:/^ *\[([^\]]+)\]: *([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:noop,paragraph:/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,text:/^[^\n]+/};block.bullet=/(?:[*+-]|\d+\.)/;block.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;block.item=replace(block.item,"gm")(/bull/g,block.bullet)();block.list=replace(block.list)(/bull/g,block.bullet)("hr","\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))")("def","\\n+(?="+block.def.source+")")();block.blockquote=replace(block.blockquote)("def",block.def)();block._tag="(?!(?:"+"a|em|strong|small|s|cite|q|dfn|abbr|data|time|code"+"|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo"+"|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b";block.html=replace(block.html)("comment",//)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/
"}return'"+(escaped?code:escape(code,true))+"\n
\n"};Renderer.prototype.blockquote=function(quote){return"'+(escaped?code:escape(code,true))+"\n\n"+quote+"
\n"};Renderer.prototype.html=function(html){return html};Renderer.prototype.heading=function(text,level,raw){return"
\n":"
\n"};Renderer.prototype.list=function(body,ordered){var type=ordered?"ol":"ul";return"<"+type+">\n"+body+""+type+">\n"};Renderer.prototype.listitem=function(text){return"\n"+"\n"+header+"\n"+"\n"+body+"\n"+"
\n"};Renderer.prototype.tablerow=function(content){return"\n"+content+" \n"};Renderer.prototype.tablecell=function(content,flags){var type=flags.header?"th":"td";var tag=flags.align?"<"+type+' style="text-align:'+flags.align+'">':"<"+type+">";return tag+content+""+type+">\n"};Renderer.prototype.strong=function(text){return""+text+""};Renderer.prototype.em=function(text){return""+text+""};Renderer.prototype.codespan=function(text){return""+text+""};Renderer.prototype.br=function(){return this.options.xhtml?"
":"
"};Renderer.prototype.del=function(text){return""+text+""};Renderer.prototype.link=function(href,title,text){if(this.options.sanitize){try{var prot=decodeURIComponent(unescape(href)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return""}if(prot.indexOf("javascript:")===0||prot.indexOf("vbscript:")===0){return""}}var out='"+text+"";return out};Renderer.prototype.image=function(href,title,text){var out='":">";return out};Renderer.prototype.text=function(text){return text};function Parser(options){this.tokens=[];this.token=null;this.options=options||marked.defaults;this.options.renderer=this.options.renderer||new Renderer;this.renderer=this.options.renderer;this.renderer.options=this.options}Parser.parse=function(src,options,renderer){var parser=new Parser(options,renderer);return parser.parse(src)};Parser.prototype.parse=function(src){this.inline=new InlineLexer(src.links,this.options,this.renderer);this.tokens=src.reverse();var out="";while(this.next()){out+=this.tok()}return out};Parser.prototype.next=function(){return this.token=this.tokens.pop()};Parser.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0};Parser.prototype.parseText=function(){var body=this.token.text;while(this.peek().type==="text"){body+="\n"+this.next().text}return this.inline.output(body)};Parser.prototype.tok=function(){switch(this.token.type){case"space":{return""}case"hr":{return this.renderer.hr()}case"heading":{return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,this.token.text)}case"code":{return this.renderer.code(this.token.text,this.token.lang,this.token.escaped)}case"table":{var header="",body="",i,row,cell,flags,j;cell="";for(i=0;i
"+escape(e.message+"",true)+""}throw e}}marked.options=marked.setOptions=function(opt){merge(marked.defaults,opt);return marked};marked.defaults={gfm:true,tables:true,breaks:false,pedantic:false,sanitize:false,sanitizer:null,mangle:true,smartLists:false,silent:false,highlight:null,langPrefix:"lang-",smartypants:false,headerPrefix:"",renderer:new Renderer,xhtml:false};marked.Parser=Parser;marked.parser=Parser.parse;marked.Renderer=Renderer;marked.Lexer=Lexer;marked.lexer=Lexer.lex;marked.InlineLexer=InlineLexer;marked.inlineLexer=InlineLexer.output;marked.parse=marked;if(true){module.exports=marked}else if(typeof define==="function"&&define.amd){define(function(){return marked})}else{this.marked=marked}}).call(function(){return module.exports}()); -------------------------------------------------------------------------------- /wxParse/wxParse.wxml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 |
tags around block-level tags. 1310 | text = showdown.subParser('hashHTMLBlocks')(text, options, globals); 1311 | text = showdown.subParser('paragraphs')(text, options, globals); 1312 | 1313 | text = globals.converter._dispatch('blockGamut.after', text, options, globals); 1314 | 1315 | return text; 1316 | }); 1317 | 1318 | showdown.subParser('blockQuotes', function (text, options, globals) { 1319 | 'use strict'; 1320 | 1321 | text = globals.converter._dispatch('blockQuotes.before', text, options, globals); 1322 | /* 1323 | text = text.replace(/ 1324 | ( // Wrap whole match in $1 1325 | ( 1326 | ^[ \t]*>[ \t]? // '>' at the start of a line 1327 | .+\n // rest of the first line 1328 | (.+\n)* // subsequent consecutive lines 1329 | \n* // blanks 1330 | )+ 1331 | ) 1332 | /gm, function(){...}); 1333 | */ 1334 | 1335 | text = text.replace(/((^[ \t]{0,3}>[ \t]?.+\n(.+\n)*\n*)+)/gm, function (wholeMatch, m1) { 1336 | var bq = m1; 1337 | 1338 | // attacklab: hack around Konqueror 3.5.4 bug: 1339 | // "----------bug".replace(/^-/g,"") == "bug" 1340 | bq = bq.replace(/^[ \t]*>[ \t]?/gm, '~0'); // trim one level of quoting 1341 | 1342 | // attacklab: clean up hack 1343 | bq = bq.replace(/~0/g, ''); 1344 | 1345 | bq = bq.replace(/^[ \t]+$/gm, ''); // trim whitespace-only lines 1346 | bq = showdown.subParser('githubCodeBlocks')(bq, options, globals); 1347 | bq = showdown.subParser('blockGamut')(bq, options, globals); // recurse 1348 | 1349 | bq = bq.replace(/(^|\n)/g, '$1 '); 1350 | // These leading spaces screw with
content, so we need to fix that:
1351 | bq = bq.replace(/(\s*[^\r]+?<\/pre>)/gm, function (wholeMatch, m1) {
1352 | var pre = m1;
1353 | // attacklab: hack around Konqueror 3.5.4 bug:
1354 | pre = pre.replace(/^ /mg, '~0');
1355 | pre = pre.replace(/~0/g, '');
1356 | return pre;
1357 | });
1358 |
1359 | return showdown.subParser('hashBlock')('\n' + bq + '\n
', options, globals);
1360 | });
1361 |
1362 | text = globals.converter._dispatch('blockQuotes.after', text, options, globals);
1363 | return text;
1364 | });
1365 |
1366 | /**
1367 | * Process Markdown `` blocks.
1368 | */
1369 | showdown.subParser('codeBlocks', function (text, options, globals) {
1370 | 'use strict';
1371 |
1372 | text = globals.converter._dispatch('codeBlocks.before', text, options, globals);
1373 | /*
1374 | text = text.replace(text,
1375 | /(?:\n\n|^)
1376 | ( // $1 = the code block -- one or more lines, starting with a space/tab
1377 | (?:
1378 | (?:[ ]{4}|\t) // Lines must start with a tab or a tab-width of spaces - attacklab: g_tab_width
1379 | .*\n+
1380 | )+
1381 | )
1382 | (\n*[ ]{0,3}[^ \t\n]|(?=~0)) // attacklab: g_tab_width
1383 | /g,function(){...});
1384 | */
1385 |
1386 | // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug
1387 | text += '~0';
1388 |
1389 | var pattern = /(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g;
1390 | text = text.replace(pattern, function (wholeMatch, m1, m2) {
1391 | var codeblock = m1,
1392 | nextChar = m2,
1393 | end = '\n';
1394 |
1395 | codeblock = showdown.subParser('outdent')(codeblock);
1396 | codeblock = showdown.subParser('encodeCode')(codeblock);
1397 | codeblock = showdown.subParser('detab')(codeblock);
1398 | codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines
1399 | codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing newlines
1400 |
1401 | if (options.omitExtraWLInCodeBlocks) {
1402 | end = '';
1403 | }
1404 |
1405 | codeblock = '' + codeblock + end + '
';
1406 |
1407 | return showdown.subParser('hashBlock')(codeblock, options, globals) + nextChar;
1408 | });
1409 |
1410 | // attacklab: strip sentinel
1411 | text = text.replace(/~0/, '');
1412 |
1413 | text = globals.converter._dispatch('codeBlocks.after', text, options, globals);
1414 | return text;
1415 | });
1416 |
1417 | /**
1418 | *
1419 | * * Backtick quotes are used for spans.
1420 | *
1421 | * * You can use multiple backticks as the delimiters if you want to
1422 | * include literal backticks in the code span. So, this input:
1423 | *
1424 | * Just type ``foo `bar` baz`` at the prompt.
1425 | *
1426 | * Will translate to:
1427 | *
1428 | * Just type foo `bar` baz at the prompt.
1429 | *
1430 | * There's no arbitrary limit to the number of backticks you
1431 | * can use as delimters. If you need three consecutive backticks
1432 | * in your code, use four for delimiters, etc.
1433 | *
1434 | * * You can use spaces to get literal backticks at the edges:
1435 | *
1436 | * ... type `` `bar` `` ...
1437 | *
1438 | * Turns to:
1439 | *
1440 | * ... type `bar` ...
1441 | */
1442 | showdown.subParser('codeSpans', function (text, options, globals) {
1443 | 'use strict';
1444 |
1445 | text = globals.converter._dispatch('codeSpans.before', text, options, globals);
1446 |
1447 | /*
1448 | text = text.replace(/
1449 | (^|[^\\]) // Character before opening ` can't be a backslash
1450 | (`+) // $2 = Opening run of `
1451 | ( // $3 = The code block
1452 | [^\r]*?
1453 | [^`] // attacklab: work around lack of lookbehind
1454 | )
1455 | \2 // Matching closer
1456 | (?!`)
1457 | /gm, function(){...});
1458 | */
1459 |
1460 | if (typeof(text) === 'undefined') {
1461 | text = '';
1462 | }
1463 | text = text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,
1464 | function (wholeMatch, m1, m2, m3) {
1465 | var c = m3;
1466 | c = c.replace(/^([ \t]*)/g, ''); // leading whitespace
1467 | c = c.replace(/[ \t]*$/g, ''); // trailing whitespace
1468 | c = showdown.subParser('encodeCode')(c);
1469 | return m1 + '' + c + '';
1470 | }
1471 | );
1472 |
1473 | text = globals.converter._dispatch('codeSpans.after', text, options, globals);
1474 | return text;
1475 | });
1476 |
1477 | /**
1478 | * Convert all tabs to spaces
1479 | */
1480 | showdown.subParser('detab', function (text) {
1481 | 'use strict';
1482 |
1483 | // expand first n-1 tabs
1484 | text = text.replace(/\t(?=\t)/g, ' '); // g_tab_width
1485 |
1486 | // replace the nth with two sentinels
1487 | text = text.replace(/\t/g, '~A~B');
1488 |
1489 | // use the sentinel to anchor our regex so it doesn't explode
1490 | text = text.replace(/~B(.+?)~A/g, function (wholeMatch, m1) {
1491 | var leadingText = m1,
1492 | numSpaces = 4 - leadingText.length % 4; // g_tab_width
1493 |
1494 | // there *must* be a better way to do this:
1495 | for (var i = 0; i < numSpaces; i++) {
1496 | leadingText += ' ';
1497 | }
1498 |
1499 | return leadingText;
1500 | });
1501 |
1502 | // clean up sentinels
1503 | text = text.replace(/~A/g, ' '); // g_tab_width
1504 | text = text.replace(/~B/g, '');
1505 |
1506 | return text;
1507 |
1508 | });
1509 |
1510 | /**
1511 | * Smart processing for ampersands and angle brackets that need to be encoded.
1512 | */
1513 | showdown.subParser('encodeAmpsAndAngles', function (text) {
1514 | 'use strict';
1515 | // Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:
1516 | // http://bumppo.net/projects/amputator/
1517 | text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g, '&');
1518 |
1519 | // Encode naked <'s
1520 | text = text.replace(/<(?![a-z\/?\$!])/gi, '<');
1521 |
1522 | return text;
1523 | });
1524 |
1525 | /**
1526 | * Returns the string, with after processing the following backslash escape sequences.
1527 | *
1528 | * attacklab: The polite way to do this is with the new escapeCharacters() function:
1529 | *
1530 | * text = escapeCharacters(text,"\\",true);
1531 | * text = escapeCharacters(text,"`*_{}[]()>#+-.!",true);
1532 | *
1533 | * ...but we're sidestepping its use of the (slow) RegExp constructor
1534 | * as an optimization for Firefox. This function gets called a LOT.
1535 | */
1536 | showdown.subParser('encodeBackslashEscapes', function (text) {
1537 | 'use strict';
1538 | text = text.replace(/\\(\\)/g, showdown.helper.escapeCharactersCallback);
1539 | text = text.replace(/\\([`*_{}\[\]()>#+-.!])/g, showdown.helper.escapeCharactersCallback);
1540 | return text;
1541 | });
1542 |
1543 | /**
1544 | * Encode/escape certain characters inside Markdown code runs.
1545 | * The point is that in code, these characters are literals,
1546 | * and lose their special Markdown meanings.
1547 | */
1548 | showdown.subParser('encodeCode', function (text) {
1549 | 'use strict';
1550 |
1551 | // Encode all ampersands; HTML entities are not
1552 | // entities within a Markdown code span.
1553 | text = text.replace(/&/g, '&');
1554 |
1555 | // Do the angle bracket song and dance:
1556 | text = text.replace(//g, '>');
1558 |
1559 | // Now, escape characters that are magic in Markdown:
1560 | text = showdown.helper.escapeCharacters(text, '*_{}[]\\', false);
1561 |
1562 | // jj the line above breaks this:
1563 | //---
1564 | //* Item
1565 | // 1. Subitem
1566 | // special char: *
1567 | // ---
1568 |
1569 | return text;
1570 | });
1571 |
1572 | /**
1573 | * Input: an email address, e.g. "foo@example.com"
1574 | *
1575 | * Output: the email address as a mailto link, with each character
1576 | * of the address encoded as either a decimal or hex entity, in
1577 | * the hopes of foiling most address harvesting spam bots. E.g.:
1578 | *
1579 | * foo
1581 | * @example.com
1582 | *
1583 | * Based on a filter by Matthew Wickline, posted to the BBEdit-Talk
1584 | * mailing list:
1585 | *
1586 | */
1587 | showdown.subParser('encodeEmailAddress', function (addr) {
1588 | 'use strict';
1589 |
1590 | var encode = [
1591 | function (ch) {
1592 | return '' + ch.charCodeAt(0) + ';';
1593 | },
1594 | function (ch) {
1595 | return '' + ch.charCodeAt(0).toString(16) + ';';
1596 | },
1597 | function (ch) {
1598 | return ch;
1599 | }
1600 | ];
1601 |
1602 | addr = 'mailto:' + addr;
1603 |
1604 | addr = addr.replace(/./g, function (ch) {
1605 | if (ch === '@') {
1606 | // this *must* be encoded. I insist.
1607 | ch = encode[Math.floor(Math.random() * 2)](ch);
1608 | } else if (ch !== ':') {
1609 | // leave ':' alone (to spot mailto: later)
1610 | var r = Math.random();
1611 | // roughly 10% raw, 45% hex, 45% dec
1612 | ch = (
1613 | r > 0.9 ? encode[2](ch) : r > 0.45 ? encode[1](ch) : encode[0](ch)
1614 | );
1615 | }
1616 | return ch;
1617 | });
1618 |
1619 | addr = '' + addr + '';
1620 | addr = addr.replace(/">.+:/g, '">'); // strip the mailto: from the visible part
1621 |
1622 | return addr;
1623 | });
1624 |
1625 | /**
1626 | * Within tags -- meaning between < and > -- encode [\ ` * _] so they
1627 | * don't conflict with their use in Markdown for code, italics and strong.
1628 | */
1629 | showdown.subParser('escapeSpecialCharsWithinTagAttributes', function (text) {
1630 | 'use strict';
1631 |
1632 | // Build a regex to find HTML tags and comments. See Friedl's
1633 | // "Mastering Regular Expressions", 2nd Ed., pp. 200-201.
1634 | var regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|)/gi;
1635 |
1636 | text = text.replace(regex, function (wholeMatch) {
1637 | var tag = wholeMatch.replace(/(.)<\/?code>(?=.)/g, '$1`');
1638 | tag = showdown.helper.escapeCharacters(tag, '\\`*_', false);
1639 | return tag;
1640 | });
1641 |
1642 | return text;
1643 | });
1644 |
1645 | /**
1646 | * Handle github codeblocks prior to running HashHTML so that
1647 | * HTML contained within the codeblock gets escaped properly
1648 | * Example:
1649 | * ```ruby
1650 | * def hello_world(x)
1651 | * puts "Hello, #{x}"
1652 | * end
1653 | * ```
1654 | */
1655 | showdown.subParser('githubCodeBlocks', function (text, options, globals) {
1656 | 'use strict';
1657 |
1658 | // early exit if option is not enabled
1659 | if (!options.ghCodeBlocks) {
1660 | return text;
1661 | }
1662 |
1663 | text = globals.converter._dispatch('githubCodeBlocks.before', text, options, globals);
1664 |
1665 | text += '~0';
1666 |
1667 | text = text.replace(/(?:^|\n)```(.*)\n([\s\S]*?)\n```/g, function (wholeMatch, language, codeblock) {
1668 | var end = (options.omitExtraWLInCodeBlocks) ? '' : '\n';
1669 |
1670 | // First parse the github code block
1671 | codeblock = showdown.subParser('encodeCode')(codeblock);
1672 | codeblock = showdown.subParser('detab')(codeblock);
1673 | codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines
1674 | codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing whitespace
1675 |
1676 | codeblock = '' + codeblock + end + '
';
1677 |
1678 | codeblock = showdown.subParser('hashBlock')(codeblock, options, globals);
1679 |
1680 | // Since GHCodeblocks can be false positives, we need to
1681 | // store the primitive text and the parsed text in a global var,
1682 | // and then return a token
1683 | return '\n\n~G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\n\n';
1684 | });
1685 |
1686 | // attacklab: strip sentinel
1687 | text = text.replace(/~0/, '');
1688 |
1689 | return globals.converter._dispatch('githubCodeBlocks.after', text, options, globals);
1690 | });
1691 |
1692 | showdown.subParser('hashBlock', function (text, options, globals) {
1693 | 'use strict';
1694 | text = text.replace(/(^\n+|\n+$)/g, '');
1695 | return '\n\n~K' + (globals.gHtmlBlocks.push(text) - 1) + 'K\n\n';
1696 | });
1697 |
1698 | showdown.subParser('hashElement', function (text, options, globals) {
1699 | 'use strict';
1700 |
1701 | return function (wholeMatch, m1) {
1702 | var blockText = m1;
1703 |
1704 | // Undo double lines
1705 | blockText = blockText.replace(/\n\n/g, '\n');
1706 | blockText = blockText.replace(/^\n/, '');
1707 |
1708 | // strip trailing blank lines
1709 | blockText = blockText.replace(/\n+$/g, '');
1710 |
1711 | // Replace the element text with a marker ("~KxK" where x is its key)
1712 | blockText = '\n\n~K' + (globals.gHtmlBlocks.push(blockText) - 1) + 'K\n\n';
1713 |
1714 | return blockText;
1715 | };
1716 | });
1717 |
1718 | showdown.subParser('hashHTMLBlocks', function (text, options, globals) {
1719 | 'use strict';
1720 |
1721 | var blockTags = [
1722 | 'pre',
1723 | 'div',
1724 | 'h1',
1725 | 'h2',
1726 | 'h3',
1727 | 'h4',
1728 | 'h5',
1729 | 'h6',
1730 | 'blockquote',
1731 | 'table',
1732 | 'dl',
1733 | 'ol',
1734 | 'ul',
1735 | 'script',
1736 | 'noscript',
1737 | 'form',
1738 | 'fieldset',
1739 | 'iframe',
1740 | 'math',
1741 | 'style',
1742 | 'section',
1743 | 'header',
1744 | 'footer',
1745 | 'nav',
1746 | 'article',
1747 | 'aside',
1748 | 'address',
1749 | 'audio',
1750 | 'canvas',
1751 | 'figure',
1752 | 'hgroup',
1753 | 'output',
1754 | 'video',
1755 | 'p'
1756 | ],
1757 | repFunc = function (wholeMatch, match, left, right) {
1758 | var txt = wholeMatch;
1759 | // check if this html element is marked as markdown
1760 | // if so, it's contents should be parsed as markdown
1761 | if (left.search(/\bmarkdown\b/) !== -1) {
1762 | txt = left + globals.converter.makeHtml(match) + right;
1763 | }
1764 | return '\n\n~K' + (globals.gHtmlBlocks.push(txt) - 1) + 'K\n\n';
1765 | };
1766 |
1767 | for (var i = 0; i < blockTags.length; ++i) {
1768 | text = showdown.helper.replaceRecursiveRegExp(text, repFunc, '^(?: |\\t){0,3}<' + blockTags[i] + '\\b[^>]*>', '' + blockTags[i] + '>', 'gim');
1769 | }
1770 |
1771 | // HR SPECIAL CASE
1772 | text = text.replace(/(\n[ ]{0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,
1773 | showdown.subParser('hashElement')(text, options, globals));
1774 |
1775 | // Special case for standalone HTML comments:
1776 | text = text.replace(/()/g,
1777 | showdown.subParser('hashElement')(text, options, globals));
1778 |
1779 | // PHP and ASP-style processor instructions (...?> and <%...%>)
1780 | text = text.replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,
1781 | showdown.subParser('hashElement')(text, options, globals));
1782 | return text;
1783 | });
1784 |
1785 | /**
1786 | * Hash span elements that should not be parsed as markdown
1787 | */
1788 | showdown.subParser('hashHTMLSpans', function (text, config, globals) {
1789 | 'use strict';
1790 |
1791 | var matches = showdown.helper.matchRecursiveRegExp(text, ']*>', '', 'gi');
1792 |
1793 | for (var i = 0; i < matches.length; ++i) {
1794 | text = text.replace(matches[i][0], '~L' + (globals.gHtmlSpans.push(matches[i][0]) - 1) + 'L');
1795 | }
1796 | return text;
1797 | });
1798 |
1799 | /**
1800 | * Unhash HTML spans
1801 | */
1802 | showdown.subParser('unhashHTMLSpans', function (text, config, globals) {
1803 | 'use strict';
1804 |
1805 | for (var i = 0; i < globals.gHtmlSpans.length; ++i) {
1806 | text = text.replace('~L' + i + 'L', globals.gHtmlSpans[i]);
1807 | }
1808 |
1809 | return text;
1810 | });
1811 |
1812 | /**
1813 | * Hash span elements that should not be parsed as markdown
1814 | */
1815 | showdown.subParser('hashPreCodeTags', function (text, config, globals) {
1816 | 'use strict';
1817 |
1818 | var repFunc = function (wholeMatch, match, left, right) {
1819 | // encode html entities
1820 | var codeblock = left + showdown.subParser('encodeCode')(match) + right;
1821 | return '\n\n~G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\n\n';
1822 | };
1823 |
1824 | text = showdown.helper.replaceRecursiveRegExp(text, repFunc, '^(?: |\\t){0,3}]*>\\s*]*>', '^(?: |\\t){0,3}\\s*
', 'gim');
1825 | return text;
1826 | });
1827 |
1828 | showdown.subParser('headers', function (text, options, globals) {
1829 | 'use strict';
1830 |
1831 | text = globals.converter._dispatch('headers.before', text, options, globals);
1832 |
1833 | var prefixHeader = options.prefixHeaderId,
1834 | headerLevelStart = (isNaN(parseInt(options.headerLevelStart))) ? 1 : parseInt(options.headerLevelStart),
1835 |
1836 | // Set text-style headers:
1837 | // Header 1
1838 | // ========
1839 | //
1840 | // Header 2
1841 | // --------
1842 | //
1843 | setextRegexH1 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n={2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n=+[ \t]*\n+/gm,
1844 | setextRegexH2 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n-{2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n-+[ \t]*\n+/gm;
1845 |
1846 | text = text.replace(setextRegexH1, function (wholeMatch, m1) {
1847 |
1848 | var spanGamut = showdown.subParser('spanGamut')(m1, options, globals),
1849 | hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"',
1850 | hLevel = headerLevelStart,
1851 | hashBlock = '' + spanGamut + ' ';
1852 | return showdown.subParser('hashBlock')(hashBlock, options, globals);
1853 | });
1854 |
1855 | text = text.replace(setextRegexH2, function (matchFound, m1) {
1856 | var spanGamut = showdown.subParser('spanGamut')(m1, options, globals),
1857 | hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"',
1858 | hLevel = headerLevelStart + 1,
1859 | hashBlock = '' + spanGamut + ' ';
1860 | return showdown.subParser('hashBlock')(hashBlock, options, globals);
1861 | });
1862 |
1863 | // atx-style headers:
1864 | // # Header 1
1865 | // ## Header 2
1866 | // ## Header 2 with closing hashes ##
1867 | // ...
1868 | // ###### Header 6
1869 | //
1870 | text = text.replace(/^(#{1,6})[ \t]*(.+?)[ \t]*#*\n+/gm, function (wholeMatch, m1, m2) {
1871 | var span = showdown.subParser('spanGamut')(m2, options, globals),
1872 | hID = (options.noHeaderId) ? '' : ' id="' + headerId(m2) + '"',
1873 | hLevel = headerLevelStart - 1 + m1.length,
1874 | header = '' + span + ' ';
1875 |
1876 | return showdown.subParser('hashBlock')(header, options, globals);
1877 | });
1878 |
1879 | function headerId(m) {
1880 | var title, escapedId = m.replace(/[^\w]/g, '').toLowerCase();
1881 |
1882 | if (globals.hashLinkCounts[escapedId]) {
1883 | title = escapedId + '-' + (globals.hashLinkCounts[escapedId]++);
1884 | } else {
1885 | title = escapedId;
1886 | globals.hashLinkCounts[escapedId] = 1;
1887 | }
1888 |
1889 | // Prefix id to prevent causing inadvertent pre-existing style matches.
1890 | if (prefixHeader === true) {
1891 | prefixHeader = 'section';
1892 | }
1893 |
1894 | if (showdown.helper.isString(prefixHeader)) {
1895 | return prefixHeader + title;
1896 | }
1897 | return title;
1898 | }
1899 |
1900 | text = globals.converter._dispatch('headers.after', text, options, globals);
1901 | return text;
1902 | });
1903 |
1904 | /**
1905 | * Turn Markdown image shortcuts into
tags.
1906 | */
1907 | showdown.subParser('images', function (text, options, globals) {
1908 | 'use strict';
1909 |
1910 | text = globals.converter._dispatch('images.before', text, options, globals);
1911 |
1912 | var inlineRegExp = /!\[(.*?)]\s?\([ \t]*()(\S+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(['"])(.*?)\6[ \t]*)?\)/g,
1913 | referenceRegExp = /!\[([^\]]*?)] ?(?:\n *)?\[(.*?)]()()()()()/g;
1914 |
1915 | function writeImageTag (wholeMatch, altText, linkId, url, width, height, m5, title) {
1916 |
1917 | var gUrls = globals.gUrls,
1918 | gTitles = globals.gTitles,
1919 | gDims = globals.gDimensions;
1920 |
1921 | linkId = linkId.toLowerCase();
1922 |
1923 | if (!title) {
1924 | title = '';
1925 | }
1926 |
1927 | if (url === '' || url === null) {
1928 | if (linkId === '' || linkId === null) {
1929 | // lower-case and turn embedded newlines into spaces
1930 | linkId = altText.toLowerCase().replace(/ ?\n/g, ' ');
1931 | }
1932 | url = '#' + linkId;
1933 |
1934 | if (!showdown.helper.isUndefined(gUrls[linkId])) {
1935 | url = gUrls[linkId];
1936 | if (!showdown.helper.isUndefined(gTitles[linkId])) {
1937 | title = gTitles[linkId];
1938 | }
1939 | if (!showdown.helper.isUndefined(gDims[linkId])) {
1940 | width = gDims[linkId].width;
1941 | height = gDims[linkId].height;
1942 | }
1943 | } else {
1944 | return wholeMatch;
1945 | }
1946 | }
1947 |
1948 | altText = altText.replace(/"/g, '"');
1949 | altText = showdown.helper.escapeCharacters(altText, '*_', false);
1950 | url = showdown.helper.escapeCharacters(url, '*_', false);
1951 | var result = '
';
1968 | return result;
1969 | }
1970 |
1971 | // First, handle reference-style labeled images: ![alt text][id]
1972 | text = text.replace(referenceRegExp, writeImageTag);
1973 |
1974 | // Next, handle inline images: 
1975 | text = text.replace(inlineRegExp, writeImageTag);
1976 |
1977 | text = globals.converter._dispatch('images.after', text, options, globals);
1978 | return text;
1979 | });
1980 |
1981 | showdown.subParser('italicsAndBold', function (text, options, globals) {
1982 | 'use strict';
1983 |
1984 | text = globals.converter._dispatch('italicsAndBold.before', text, options, globals);
1985 |
1986 | if (options.literalMidWordUnderscores) {
1987 | //underscores
1988 | // Since we are consuming a \s character, we need to add it
1989 | text = text.replace(/(^|\s|>|\b)__(?=\S)([\s\S]+?)__(?=\b|<|\s|$)/gm, '$1$2');
1990 | text = text.replace(/(^|\s|>|\b)_(?=\S)([\s\S]+?)_(?=\b|<|\s|$)/gm, '$1$2');
1991 | //asterisks
1992 | text = text.replace(/(\*\*)(?=\S)([^\r]*?\S[*]*)\1/g, '$2');
1993 | text = text.replace(/(\*)(?=\S)([^\r]*?\S)\1/g, '$2');
1994 |
1995 | } else {
1996 | // must go first:
1997 | text = text.replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g, '$2');
1998 | text = text.replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g, '$2');
1999 | }
2000 |
2001 | text = globals.converter._dispatch('italicsAndBold.after', text, options, globals);
2002 | return text;
2003 | });
2004 |
2005 | /**
2006 | * Form HTML ordered (numbered) and unordered (bulleted) lists.
2007 | */
2008 | showdown.subParser('lists', function (text, options, globals) {
2009 | 'use strict';
2010 |
2011 | text = globals.converter._dispatch('lists.before', text, options, globals);
2012 | /**
2013 | * Process the contents of a single ordered or unordered list, splitting it
2014 | * into individual list items.
2015 | * @param {string} listStr
2016 | * @param {boolean} trimTrailing
2017 | * @returns {string}
2018 | */
2019 | function processListItems (listStr, trimTrailing) {
2020 | // The $g_list_level global keeps track of when we're inside a list.
2021 | // Each time we enter a list, we increment it; when we leave a list,
2022 | // we decrement. If it's zero, we're not in a list anymore.
2023 | //
2024 | // We do this because when we're not inside a list, we want to treat
2025 | // something like this:
2026 | //
2027 | // I recommend upgrading to version
2028 | // 8. Oops, now this line is treated
2029 | // as a sub-list.
2030 | //
2031 | // As a single paragraph, despite the fact that the second line starts
2032 | // with a digit-period-space sequence.
2033 | //
2034 | // Whereas when we're inside a list (or sub-list), that line will be
2035 | // treated as the start of a sub-list. What a kludge, huh? This is
2036 | // an aspect of Markdown's syntax that's hard to parse perfectly
2037 | // without resorting to mind-reading. Perhaps the solution is to
2038 | // change the syntax rules such that sub-lists must start with a
2039 | // starting cardinal number; e.g. "1." or "a.".
2040 | globals.gListLevel++;
2041 |
2042 | // trim trailing blank lines:
2043 | listStr = listStr.replace(/\n{2,}$/, '\n');
2044 |
2045 | // attacklab: add sentinel to emulate \z
2046 | listStr += '~0';
2047 |
2048 | var rgx = /(\n)?(^[ \t]*)([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(~0|\2([*+-]|\d+[.])[ \t]+))/gm,
2049 | isParagraphed = (/\n[ \t]*\n(?!~0)/.test(listStr));
2050 |
2051 | listStr = listStr.replace(rgx, function (wholeMatch, m1, m2, m3, m4, taskbtn, checked) {
2052 | checked = (checked && checked.trim() !== '');
2053 | var item = showdown.subParser('outdent')(m4, options, globals),
2054 | bulletStyle = '';
2055 |
2056 | // Support for github tasklists
2057 | if (taskbtn && options.tasklists) {
2058 | bulletStyle = ' class="task-list-item" style="list-style-type: none;"';
2059 | item = item.replace(/^[ \t]*\[(x|X| )?]/m, function () {
2060 | var otp = '';
2065 | return otp;
2066 | });
2067 | }
2068 | // m1 - Leading line or
2069 | // Has a double return (multi paragraph) or
2070 | // Has sublist
2071 | if (m1 || (item.search(/\n{2,}/) > -1)) {
2072 | item = showdown.subParser('githubCodeBlocks')(item, options, globals);
2073 | item = showdown.subParser('blockGamut')(item, options, globals);
2074 | } else {
2075 | // Recursion for sub-lists:
2076 | item = showdown.subParser('lists')(item, options, globals);
2077 | item = item.replace(/\n$/, ''); // chomp(item)
2078 | if (isParagraphed) {
2079 | item = showdown.subParser('paragraphs')(item, options, globals);
2080 | } else {
2081 | item = showdown.subParser('spanGamut')(item, options, globals);
2082 | }
2083 | }
2084 | item = '\n' + item + ' \n';
2085 | return item;
2086 | });
2087 |
2088 | // attacklab: strip sentinel
2089 | listStr = listStr.replace(/~0/g, '');
2090 |
2091 | globals.gListLevel--;
2092 |
2093 | if (trimTrailing) {
2094 | listStr = listStr.replace(/\s+$/, '');
2095 | }
2096 |
2097 | return listStr;
2098 | }
2099 |
2100 | /**
2101 | * Check and parse consecutive lists (better fix for issue #142)
2102 | * @param {string} list
2103 | * @param {string} listType
2104 | * @param {boolean} trimTrailing
2105 | * @returns {string}
2106 | */
2107 | function parseConsecutiveLists(list, listType, trimTrailing) {
2108 | // check if we caught 2 or more consecutive lists by mistake
2109 | // we use the counterRgx, meaning if listType is UL we look for UL and vice versa
2110 | var counterRxg = (listType === 'ul') ? /^ {0,2}\d+\.[ \t]/gm : /^ {0,2}[*+-][ \t]/gm,
2111 | subLists = [],
2112 | result = '';
2113 |
2114 | if (list.search(counterRxg) !== -1) {
2115 | (function parseCL(txt) {
2116 | var pos = txt.search(counterRxg);
2117 | if (pos !== -1) {
2118 | // slice
2119 | result += '\n\n<' + listType + '>' + processListItems(txt.slice(0, pos), !!trimTrailing) + '' + listType + '>\n\n';
2120 |
2121 | // invert counterType and listType
2122 | listType = (listType === 'ul') ? 'ol' : 'ul';
2123 | counterRxg = (listType === 'ul') ? /^ {0,2}\d+\.[ \t]/gm : /^ {0,2}[*+-][ \t]/gm;
2124 |
2125 | //recurse
2126 | parseCL(txt.slice(pos));
2127 | } else {
2128 | result += '\n\n<' + listType + '>' + processListItems(txt, !!trimTrailing) + '' + listType + '>\n\n';
2129 | }
2130 | })(list);
2131 | for (var i = 0; i < subLists.length; ++i) {
2132 |
2133 | }
2134 | } else {
2135 | result = '\n\n<' + listType + '>' + processListItems(list, !!trimTrailing) + '' + listType + '>\n\n';
2136 | }
2137 |
2138 | return result;
2139 | }
2140 |
2141 | // attacklab: add sentinel to hack around khtml/safari bug:
2142 | // http://bugs.webkit.org/show_bug.cgi?id=11231
2143 | text += '~0';
2144 |
2145 | // Re-usable pattern to match any entire ul or ol list:
2146 | var wholeList = /^(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;
2147 |
2148 | if (globals.gListLevel) {
2149 | text = text.replace(wholeList, function (wholeMatch, list, m2) {
2150 | var listType = (m2.search(/[*+-]/g) > -1) ? 'ul' : 'ol';
2151 | return parseConsecutiveLists(list, listType, true);
2152 | });
2153 | } else {
2154 | wholeList = /(\n\n|^\n?)(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;
2155 | //wholeList = /(\n\n|^\n?)( {0,3}([*+-]|\d+\.)[ \t]+[\s\S]+?)(?=(~0)|(\n\n(?!\t| {2,}| {0,3}([*+-]|\d+\.)[ \t])))/g;
2156 | text = text.replace(wholeList, function (wholeMatch, m1, list, m3) {
2157 |
2158 | var listType = (m3.search(/[*+-]/g) > -1) ? 'ul' : 'ol';
2159 | return parseConsecutiveLists(list, listType);
2160 | });
2161 | }
2162 |
2163 | // attacklab: strip sentinel
2164 | text = text.replace(/~0/, '');
2165 |
2166 | text = globals.converter._dispatch('lists.after', text, options, globals);
2167 | return text;
2168 | });
2169 |
2170 | /**
2171 | * Remove one level of line-leading tabs or spaces
2172 | */
2173 | showdown.subParser('outdent', function (text) {
2174 | 'use strict';
2175 |
2176 | // attacklab: hack around Konqueror 3.5.4 bug:
2177 | // "----------bug".replace(/^-/g,"") == "bug"
2178 | text = text.replace(/^(\t|[ ]{1,4})/gm, '~0'); // attacklab: g_tab_width
2179 |
2180 | // attacklab: clean up hack
2181 | text = text.replace(/~0/g, '');
2182 |
2183 | return text;
2184 | });
2185 |
2186 | /**
2187 | *
2188 | */
2189 | showdown.subParser('paragraphs', function (text, options, globals) {
2190 | 'use strict';
2191 |
2192 | text = globals.converter._dispatch('paragraphs.before', text, options, globals);
2193 | // Strip leading and trailing lines:
2194 | text = text.replace(/^\n+/g, '');
2195 | text = text.replace(/\n+$/g, '');
2196 |
2197 | var grafs = text.split(/\n{2,}/g),
2198 | grafsOut = [],
2199 | end = grafs.length; // Wrap tags
2200 |
2201 | for (var i = 0; i < end; i++) {
2202 | var str = grafs[i];
2203 | // if this is an HTML marker, copy it
2204 | if (str.search(/~(K|G)(\d+)\1/g) >= 0) {
2205 | grafsOut.push(str);
2206 | } else {
2207 | str = showdown.subParser('spanGamut')(str, options, globals);
2208 | str = str.replace(/^([ \t]*)/g, '
');
2209 | str += '
';
2210 | grafsOut.push(str);
2211 | }
2212 | }
2213 |
2214 | /** Unhashify HTML blocks */
2215 | end = grafsOut.length;
2216 | for (i = 0; i < end; i++) {
2217 | var blockText = '',
2218 | grafsOutIt = grafsOut[i],
2219 | codeFlag = false;
2220 | // if this is a marker for an html block...
2221 | while (grafsOutIt.search(/~(K|G)(\d+)\1/) >= 0) {
2222 | var delim = RegExp.$1,
2223 | num = RegExp.$2;
2224 |
2225 | if (delim === 'K') {
2226 | blockText = globals.gHtmlBlocks[num];
2227 | } else {
2228 | // we need to check if ghBlock is a false positive
2229 | if (codeFlag) {
2230 | // use encoded version of all text
2231 | blockText = showdown.subParser('encodeCode')(globals.ghCodeBlocks[num].text);
2232 | } else {
2233 | blockText = globals.ghCodeBlocks[num].codeblock;
2234 | }
2235 | }
2236 | blockText = blockText.replace(/\$/g, '$$$$'); // Escape any dollar signs
2237 |
2238 | grafsOutIt = grafsOutIt.replace(/(\n\n)?~(K|G)\d+\2(\n\n)?/, blockText);
2239 | // Check if grafsOutIt is a pre->code
2240 | if (/^]*>\s*]*>/.test(grafsOutIt)) {
2241 | codeFlag = true;
2242 | }
2243 | }
2244 | grafsOut[i] = grafsOutIt;
2245 | }
2246 | text = grafsOut.join('\n\n');
2247 | // Strip leading and trailing lines:
2248 | text = text.replace(/^\n+/g, '');
2249 | text = text.replace(/\n+$/g, '');
2250 | return globals.converter._dispatch('paragraphs.after', text, options, globals);
2251 | });
2252 |
2253 | /**
2254 | * Run extension
2255 | */
2256 | showdown.subParser('runExtension', function (ext, text, options, globals) {
2257 | 'use strict';
2258 |
2259 | if (ext.filter) {
2260 | text = ext.filter(text, globals.converter, options);
2261 |
2262 | } else if (ext.regex) {
2263 | // TODO remove this when old extension loading mechanism is deprecated
2264 | var re = ext.regex;
2265 | if (!re instanceof RegExp) {
2266 | re = new RegExp(re, 'g');
2267 | }
2268 | text = text.replace(re, ext.replace);
2269 | }
2270 |
2271 | return text;
2272 | });
2273 |
2274 | /**
2275 | * These are all the transformations that occur *within* block-level
2276 | * tags like paragraphs, headers, and list items.
2277 | */
2278 | showdown.subParser('spanGamut', function (text, options, globals) {
2279 | 'use strict';
2280 |
2281 | text = globals.converter._dispatch('spanGamut.before', text, options, globals);
2282 | text = showdown.subParser('codeSpans')(text, options, globals);
2283 | text = showdown.subParser('escapeSpecialCharsWithinTagAttributes')(text, options, globals);
2284 | text = showdown.subParser('encodeBackslashEscapes')(text, options, globals);
2285 |
2286 | // Process anchor and image tags. Images must come first,
2287 | // because ![foo][f] looks like an anchor.
2288 | text = showdown.subParser('images')(text, options, globals);
2289 | text = showdown.subParser('anchors')(text, options, globals);
2290 |
2291 | // Make links out of things like ` `
2292 | // Must come after _DoAnchors(), because you can use < and >
2293 | // delimiters in inline links like [this]().
2294 | text = showdown.subParser('autoLinks')(text, options, globals);
2295 | text = showdown.subParser('encodeAmpsAndAngles')(text, options, globals);
2296 | text = showdown.subParser('italicsAndBold')(text, options, globals);
2297 | text = showdown.subParser('strikethrough')(text, options, globals);
2298 |
2299 | // Do hard breaks:
2300 | text = text.replace(/ +\n/g, '
\n');
2301 |
2302 | text = globals.converter._dispatch('spanGamut.after', text, options, globals);
2303 | return text;
2304 | });
2305 |
2306 | showdown.subParser('strikethrough', function (text, options, globals) {
2307 | 'use strict';
2308 |
2309 | if (options.strikethrough) {
2310 | text = globals.converter._dispatch('strikethrough.before', text, options, globals);
2311 | text = text.replace(/(?:~T){2}([\s\S]+?)(?:~T){2}/g, '$1');
2312 | text = globals.converter._dispatch('strikethrough.after', text, options, globals);
2313 | }
2314 |
2315 | return text;
2316 | });
2317 |
2318 | /**
2319 | * Strip any lines consisting only of spaces and tabs.
2320 | * This makes subsequent regexs easier to write, because we can
2321 | * match consecutive blank lines with /\n+/ instead of something
2322 | * contorted like /[ \t]*\n+/
2323 | */
2324 | showdown.subParser('stripBlankLines', function (text) {
2325 | 'use strict';
2326 | return text.replace(/^[ \t]+$/mg, '');
2327 | });
2328 |
2329 | /**
2330 | * Strips link definitions from text, stores the URLs and titles in
2331 | * hash references.
2332 | * Link defs are in the form: ^[id]: url "optional title"
2333 | *
2334 | * ^[ ]{0,3}\[(.+)\]: // id = $1 attacklab: g_tab_width - 1
2335 | * [ \t]*
2336 | * \n? // maybe *one* newline
2337 | * [ \t]*
2338 | * (\S+?)>? // url = $2
2339 | * [ \t]*
2340 | * \n? // maybe one newline
2341 | * [ \t]*
2342 | * (?:
2343 | * (\n*) // any lines skipped = $3 attacklab: lookbehind removed
2344 | * ["(]
2345 | * (.+?) // title = $4
2346 | * [")]
2347 | * [ \t]*
2348 | * )? // title is optional
2349 | * (?:\n+|$)
2350 | * /gm,
2351 | * function(){...});
2352 | *
2353 | */
2354 | showdown.subParser('stripLinkDefinitions', function (text, options, globals) {
2355 | 'use strict';
2356 |
2357 | 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;
2358 |
2359 | // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug
2360 | text += '~0';
2361 |
2362 | text = text.replace(regex, function (wholeMatch, linkId, url, width, height, blankLines, title) {
2363 | linkId = linkId.toLowerCase();
2364 | globals.gUrls[linkId] = showdown.subParser('encodeAmpsAndAngles')(url); // Link IDs are case-insensitive
2365 |
2366 | if (blankLines) {
2367 | // Oops, found blank lines, so it's not a title.
2368 | // Put back the parenthetical statement we stole.
2369 | return blankLines + title;
2370 |
2371 | } else {
2372 | if (title) {
2373 | globals.gTitles[linkId] = title.replace(/"|'/g, '"');
2374 | }
2375 | if (options.parseImgDimensions && width && height) {
2376 | globals.gDimensions[linkId] = {
2377 | width: width,
2378 | height: height
2379 | };
2380 | }
2381 | }
2382 | // Completely remove the definition from the text
2383 | return '';
2384 | });
2385 |
2386 | // attacklab: strip sentinel
2387 | text = text.replace(/~0/, '');
2388 |
2389 | return text;
2390 | });
2391 |
2392 | showdown.subParser('tables', function (text, options, globals) {
2393 | 'use strict';
2394 |
2395 | if (!options.tables) {
2396 | return text;
2397 | }
2398 |
2399 | var tableRgx = /^[ \t]{0,3}\|?.+\|.+\n[ \t]{0,3}\|?[ \t]*:?[ \t]*(?:-|=){2,}[ \t]*:?[ \t]*\|[ \t]*:?[ \t]*(?:-|=){2,}[\s\S]+?(?:\n\n|~0)/gm;
2400 |
2401 | function parseStyles(sLine) {
2402 | if (/^:[ \t]*--*$/.test(sLine)) {
2403 | return ' style="text-align:left;"';
2404 | } else if (/^--*[ \t]*:[ \t]*$/.test(sLine)) {
2405 | return ' style="text-align:right;"';
2406 | } else if (/^:[ \t]*--*[ \t]*:$/.test(sLine)) {
2407 | return ' style="text-align:center;"';
2408 | } else {
2409 | return '';
2410 | }
2411 | }
2412 |
2413 | function parseHeaders(header, style) {
2414 | var id = '';
2415 | header = header.trim();
2416 | if (options.tableHeaderId) {
2417 | id = ' id="' + header.replace(/ /g, '_').toLowerCase() + '"';
2418 | }
2419 | header = showdown.subParser('spanGamut')(header, options, globals);
2420 |
2421 | return '' + header + ' \n';
2422 | }
2423 |
2424 | function parseCells(cell, style) {
2425 | var subText = showdown.subParser('spanGamut')(cell, options, globals);
2426 | return '' + subText + ' \n';
2427 | }
2428 |
2429 | function buildTable(headers, cells) {
2430 | var tb = '\n\n\n',
2431 | tblLgn = headers.length;
2432 |
2433 | for (var i = 0; i < tblLgn; ++i) {
2434 | tb += headers[i];
2435 | }
2436 | tb += ' \n\n\n';
2437 |
2438 | for (i = 0; i < cells.length; ++i) {
2439 | tb += '\n';
2440 | for (var ii = 0; ii < tblLgn; ++ii) {
2441 | tb += cells[i][ii];
2442 | }
2443 | tb += ' \n';
2444 | }
2445 | tb += '\n
\n';
2446 | return tb;
2447 | }
2448 |
2449 | text = globals.converter._dispatch('tables.before', text, options, globals);
2450 |
2451 | text = text.replace(tableRgx, function (rawTable) {
2452 |
2453 | var i, tableLines = rawTable.split('\n');
2454 |
2455 | // strip wrong first and last column if wrapped tables are used
2456 | for (i = 0; i < tableLines.length; ++i) {
2457 | if (/^[ \t]{0,3}\|/.test(tableLines[i])) {
2458 | tableLines[i] = tableLines[i].replace(/^[ \t]{0,3}\|/, '');
2459 | }
2460 | if (/\|[ \t]*$/.test(tableLines[i])) {
2461 | tableLines[i] = tableLines[i].replace(/\|[ \t]*$/, '');
2462 | }
2463 | }
2464 |
2465 | var rawHeaders = tableLines[0].split('|').map(function (s) { return s.trim();}),
2466 | rawStyles = tableLines[1].split('|').map(function (s) { return s.trim();}),
2467 | rawCells = [],
2468 | headers = [],
2469 | styles = [],
2470 | cells = [];
2471 |
2472 | tableLines.shift();
2473 | tableLines.shift();
2474 |
2475 | for (i = 0; i < tableLines.length; ++i) {
2476 | if (tableLines[i].trim() === '') {
2477 | continue;
2478 | }
2479 | rawCells.push(
2480 | tableLines[i]
2481 | .split('|')
2482 | .map(function (s) {
2483 | return s.trim();
2484 | })
2485 | );
2486 | }
2487 |
2488 | if (rawHeaders.length < rawStyles.length) {
2489 | return rawTable;
2490 | }
2491 |
2492 | for (i = 0; i < rawStyles.length; ++i) {
2493 | styles.push(parseStyles(rawStyles[i]));
2494 | }
2495 |
2496 | for (i = 0; i < rawHeaders.length; ++i) {
2497 | if (showdown.helper.isUndefined(styles[i])) {
2498 | styles[i] = '';
2499 | }
2500 | headers.push(parseHeaders(rawHeaders[i], styles[i]));
2501 | }
2502 |
2503 | for (i = 0; i < rawCells.length; ++i) {
2504 | var row = [];
2505 | for (var ii = 0; ii < headers.length; ++ii) {
2506 | if (showdown.helper.isUndefined(rawCells[i][ii])) {
2507 |
2508 | }
2509 | row.push(parseCells(rawCells[i][ii], styles[ii]));
2510 | }
2511 | cells.push(row);
2512 | }
2513 |
2514 | return buildTable(headers, cells);
2515 | });
2516 |
2517 | text = globals.converter._dispatch('tables.after', text, options, globals);
2518 |
2519 | return text;
2520 | });
2521 |
2522 | /**
2523 | * Swap back in all the special characters we've hidden.
2524 | */
2525 | showdown.subParser('unescapeSpecialChars', function (text) {
2526 | 'use strict';
2527 |
2528 | text = text.replace(/~E(\d+)E/g, function (wholeMatch, m1) {
2529 | var charCodeToReplace = parseInt(m1);
2530 | return String.fromCharCode(charCodeToReplace);
2531 | });
2532 | return text;
2533 | });
2534 |
2535 | var root = this;
2536 |
2537 | // CommonJS/nodeJS Loader
2538 | if (typeof module !== 'undefined' && module.exports) {
2539 | module.exports = showdown;
2540 |
2541 | // AMD Loader
2542 | } else if (typeof define === 'function' && define.amd) {
2543 | define(function () {
2544 | 'use strict';
2545 | return showdown;
2546 | });
2547 |
2548 | // Regular Browser loader
2549 | } else {
2550 | root.showdown = showdown;
2551 | }
2552 | }).call(this);
2553 |
2554 | //# sourceMappingURL=showdown.js.map
2555 |
--------------------------------------------------------------------------------