Make Account Center only usable when logged in
[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                 // Sanitize HTML input
81                 l = l.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
82                 out.push(l + "\n");
83             }
84             return;
85         } else {
86             if (l == '```') {
87                 out.push('<pre>');
88                 githubCodeMode = true;
89                 return;
90             }
91         }
92
93         // Create a code block when lines begin with at least four spaces
94         if (l.substr(0, 4) == '    ') {
95             if (!codeMode) {
96                 out.push('<pre>');
97                 codeMode = true;
98             }
99             // Sanitize HTML input
100             l = l.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
101             out.push(l.substr(4) + "\n");
102             return;
103         } else {
104             if (codeMode) {
105                 out.push('</pre>');
106                 codeMode = false;
107             }
108         }
109
110         // Put quoted material into a special paragraph
111         if (l[0] == '>') {
112             var pi = out.lastIndexOf('<p>');
113             if (pi != -1) {
114                 out[pi] = '<p class="quote">';
115                 l = l.replace(/^>\s*/, '');
116             }
117         }
118
119         // Sanitize HTML input
120         l = l.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
121
122         // Turn HTTP URLs into links
123         l = l.replace(/(\s[()\[\]{}]?|^)(https?:\/\/[a-zA-Z0-9.-]*[a-zA-Z0-9](\/([^\s"]*[^.!,;?()\s])?)?)/g, '$1<a href="$2">$2</a>');
124
125         // Turn markdown links into links
126         l = blerg.Util.formatMarkdownLinks(l);
127
128         // Turn *foo* into italics and **foo** into bold
129         l = l.replace(/([^\w\\]|^)\*\*(\w[^*]*)\*\*(\W|$)/g, '$1<b>$2</b>$3');
130         l = l.replace(/([^\w\\]|^)\*(\w[^*]*)\*(\W|$)/g, '$1<i>$2</i>$3');
131
132         // Turn ~~foo~~ into strikethrough
133         l = l.replace(/([^\w\\]|^)~~(\w[^~]*)~~(\W|$)/g, '$1<s>$2</s>$3');
134
135         // Turn refs and tags into links
136         l = l.replace(/(\s|^)#([A-Za-z0-9_-]+)/g, '$1<a href="#/tag/$2" class="ref" onclick="return blerg.Util.qlink(event)">#$2</a>');
137         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>');
138
139         // Create lists when lines begin with *
140         if (l[0] == '*') {
141             if (!listMode) {
142                 var pi = out.lastIndexOf('<p>');
143                 out[pi] = '<ul>';
144                 listMode = true;
145             }
146             l = l.replace(/^\*\s*/, '');
147             out.push('<li>');
148             endpush = '</li>';
149         }
150
151         // Create headers when lines begin with = or #
152         if (l[0] == '=' || l[0] == '#') {
153             var m = l.match(/^([=#]+)/);
154             var depth = m[1].length;
155             if (depth <= 5) {
156                 l = l.replace(/^[=#]+\s*/, '').replace(/\s*[=#]+$/, '');
157                 out.push('<h' + depth + '>');
158                 endpush = '</h' + depth + '>';
159             }
160         }
161
162         // Remove backslashes from escaped metachars
163         l = l.replace(/\\([*\[\]@#~])/g, '$1');
164
165         out.push(l);
166         if (endpush) {
167             out.push(endpush);
168             endpush = null;
169         } else {
170             out.push('<br>');
171         }
172     });
173     while (out[out.length - 1] == '<br>' || out[out.length - 1] == '<p>') {
174         out.pop();
175     }
176     if (listMode) {
177         out.push('</ul>');
178     }
179     if (codeMode || githubCodeMode) {
180         out.push('</pre>');
181     }
182
183     return out.join('');
184 }