8706f8140c78ef44ed23b41dad2db647597ab95b
[blerg.git] / www / jssrc / blerg / Util.js
1 blerg = window.blerg || {};
2
3 blerg.Util = {};
4
5 // Dirty, terrible shim for rewritten links below
6 blerg.Util.qlink = function(ev) {
7     try {
8         location.href = ev.target.href;
9     } catch(e) { }
10     enyo.$.blerg.bubble('onNavigate');
11     return false;
12 }
13
14 blerg.Util.formatLinkHooks = [
15     BlergMedia
16 ];
17
18 blerg.Util.formatMarkdownLinks = function(l) {
19         m = l.match(/(\s[()\[\]{}]?|^)\[([^\]]+)\]\((https?:\/\/[a-zA-Z0-9.-]*[a-zA-Z0-9](\/[^)"]*?)?|mailto:[^)"]*?)(\s([^)]*))?\)/);
20         if (!m)
21             return l;
22         var whitespace = m[1];
23         var data = {
24             label: m[2],
25             url: m[3],
26             extra: m[5]
27         };
28
29         for (var i = 0; i < blerg.Util.formatLinkHooks.length; i++) {
30             var newdata = blerg.Util.formatLinkHooks[i].process(data);
31             if (newdata)
32                 data = newdata;
33             else
34                 console.warn("Format Link Hook " + i + " returned null");
35         }
36         var s = whitespace + '<a href="' + data.url + '">' + data.label + '</a>' +
37             (data.widget ? ' ' + data.widget : '');
38         return l.slice(0, m.index) + s + blerg.Util.formatMarkdownLinks(l.slice(m.index + m[0].length));
39 }
40
41 blerg.Util.blergFormat = function(text) {
42     var lines = text.split(/\r?\n/);
43     if (lines[lines.length - 1] == '')
44         lines.pop();
45
46     var out = ['<p>'];
47     var endpush = null;
48     var listMode = false;
49     var codeMode = false;
50     var githubCodeMode = false;
51     lines.forEach(function(l) {
52         // Blank line
53         if (l == '') {
54             // Turn single linebreaks into paragraphs
55             if (out[out.length - 1] == '<br>') {
56                 out[out.length - 1] = '<p>';
57             }
58             // End bullet list
59             if (out[out.length - 1] == '</li>') {
60                 out.push('</ul>');
61                 out.push('<p>');
62                 listMode = false;
63             }
64             // End code mode
65             if (codeMode) {
66                 out.push('</pre>');
67                 out.push('<p>');
68                 codeMode = false;
69             }
70             return;
71         }
72
73         // Sometimes I wish more languages had Perl's bistable .. operator.
74         if (githubCodeMode) {
75             if (l == '```') {
76                 out.push('</pre>');
77                 out.push('<p>');
78                 githubCodeMode = false;
79             } else {
80                 out.push(l + "\n");
81             }
82             return;
83         } else {
84             if (l == '```') {
85                 out.push('<pre>');
86                 githubCodeMode = true;
87                 return;
88             }
89         }
90
91         // Create a code block when lines begin with at least four spaces
92         if (l.substr(0, 4) == '    ') {
93             if (!codeMode) {
94                 out.push('<pre>');
95                 codeMode = true;
96             }
97             out.push(l.substr(4) + "\n");
98             return;
99         } else {
100             if (codeMode) {
101                 out.push('</pre>');
102                 codeMode = false;
103             }
104         }
105
106         // Put quoted material into a special paragraph
107         if (l[0] == '>') {
108             var pi = out.lastIndexOf('<p>');
109             if (pi != -1) {
110                 out[pi] = '<p class="quote">';
111                 l = l.replace(/^>\s*/, '');
112             }
113         }
114
115         // Sanitize HTML input
116         l = l.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
117
118         // Turn HTTP URLs into links
119         l = l.replace(/(\s[()\[\]{}]?|^)(https?:\/\/[a-zA-Z0-9.-]*[a-zA-Z0-9](\/([^\s"]*[^.!,;?()\s])?)?)/g, '$1<a href="$2">$2</a>');
120
121         // Turn markdown links into links
122         l = blerg.Util.formatMarkdownLinks(l);
123
124         // Turn *foo* into italics and **foo** into bold
125         l = l.replace(/([^\w\\]|^)\*\*(\w[^*]*)\*\*(\W|$)/g, '$1<b>$2</b>$3');
126         l = l.replace(/([^\w\\]|^)\*(\w[^*]*)\*(\W|$)/g, '$1<i>$2</i>$3');
127
128         // Turn ~~foo~~ into strikethrough
129         l = l.replace(/([^\w\\]|^)~~(\w[^~]*)~~(\W|$)/g, '$1<s>$2</s>$3');
130
131         // Turn refs and tags into links
132         l = l.replace(/(\s|^)#([A-Za-z0-9_-]+)/g, '$1<a href="#/tag/$2" class="ref" onclick="return blerg.Util.qlink(event)">#$2</a>');
133         l = l.replace(/(\s|^)@([A-Za-z0-9_-]+)(\/\d+)?/g, '$1<a href="#$2$3" class="ref" onclick="return blerg.Util.qlink(event)">@$2</a>');
134
135         // Create lists when lines begin with *
136         if (l[0] == '*') {
137             if (!listMode) {
138                 var pi = out.lastIndexOf('<p>');
139                 out[pi] = '<ul>';
140                 listMode = true;
141             }
142             l = l.replace(/^\*\s*/, '');
143             out.push('<li>');
144             endpush = '</li>';
145         }
146
147         // Create headers when lines begin with = or #
148         if (l[0] == '=' || l[0] == '#') {
149             var m = l.match(/^([=#]+)/);
150             var depth = m[1].length;
151             if (depth <= 5) {
152                 l = l.replace(/^[=#]+\s*/, '').replace(/\s*[=#]+$/, '');
153                 out.push('<h' + depth + '>');
154                 endpush = '</h' + depth + '>';
155             }
156         }
157
158         // Remove backslashes from escaped metachars
159         l = l.replace(/\\([*\[\]@#~])/g, '$1');
160
161         out.push(l);
162         if (endpush) {
163             out.push(endpush);
164             endpush = null;
165         } else {
166             out.push('<br>');
167         }
168     });
169     while (out[out.length - 1] == '<br>' || out[out.length - 1] == '<p>') {
170         out.pop();
171     }
172     if (listMode) {
173         out.push('</ul>');
174     }
175     if (codeMode || githubCodeMode) {
176         out.push('</pre>');
177     }
178
179     return out.join('');
180 }