nmbug.js: List tags as <a> in a <p> instead of as <li> in a <ul>
[nmhive.git] / nmbug.js
1 var nmbug_server = 'http://localhost:5000';
2
3 nmbug = {
4         show: function (message_id, frame) {
5                 var _this = this;
6                 if (frame === undefined) {
7                         frame = window;
8                 }
9                 this._get_available_tags(function (available_tags) {
10                         _this._get_tags(
11                                 message_id,
12                                 _this._edit_tags.bind(_this, frame, available_tags, message_id));
13                 });
14         },
15         _get_available_tags: function (callback) {
16                 var url = [
17                         nmbug_server,
18                         'tags',
19                         ].join('/');
20                 console.log('nmbug: get available tags from ' + url);
21                 var request = new XMLHttpRequest();
22                 request.onload = function () {
23                         if (this.status == 200) {
24                                 var available_tags = JSON.parse(this.response);
25                                 console.log('nmbug: got available tags', available_tags);
26                                 callback(available_tags);
27                         } else {
28                                 throw 'Error fetching ' + url + ' (status ' + this.status + ')';
29                         }
30                 };
31                 request.open('get', url, true);
32                 request.send();
33         },
34         _get_tags: function (message_id, callback) {
35                 var url = [
36                         nmbug_server,
37                         'mid',
38                         encodeURIComponent(message_id),
39                         ].join('/');
40                 console.log('nmbug: get tags from ' + url);
41                 var request = new XMLHttpRequest();
42                 request.onload = function () {
43                         if (this.status == 200) {
44                                 var tags = JSON.parse(this.response);
45                                 console.log('nmbug: got tags', tags);
46                                 callback(tags);
47                         } else {
48                                 throw 'Error fetching ' + url + ' (status ' + this.status + ')';
49                         }
50                 };
51                 request.open('get', url, true);
52                 request.send();
53         },
54         _edit_tags: function (frame, available_tags, message_id, tags) {
55                 var have_dialog_polyfill;
56                 try {
57                         have_dialog_polyfill = frame.dialogPolyfill !== undefined;
58                 } catch (error) {
59                         if (error.name == 'ReferenceError') {
60                                 have_dialog_polyfill = false;
61                         }
62                 }
63                 if (frame.document.createElement('dialog').show || have_dialog_polyfill) {
64                         this._x_edit_tags(frame, available_tags, message_id, tags);
65                 } else {
66                         var script = frame.document.createElement('script');
67                         script.type = 'text/javascript';
68                         script.src = nmbug_server + '/static/dialog-polyfill/dialog-polyfill.js';
69                         script.async = false;
70                         console.log('nmbug: loading dialog-polyfill.js');
71                         frame.document.head.appendChild(script);
72
73                         var link = frame.document.createElement('link');
74                         link.rel = 'stylesheet';
75                         link.type = 'text/css';
76                         link.href = nmbug_server + '/static/dialog-polyfill/dialog-polyfill.css';
77                         link.async = false;
78                         console.log('nmbug: loading dialog-polyfill.css');
79                         frame.document.head.appendChild(link);
80
81                         var _this = this;
82                         function edit_tags_after_dialog_polyfill () {
83                                 try {
84                                         have_dialog_polyfill = frame.dialogPolyfill !== undefined;
85                                         console.log('have dialogPolyfill');
86                                         window.setTimeout(
87                                                         _this._x_edit_tags.bind(_this), 200,
88                                                         frame, available_tags, message_id, tags);
89                                 } catch (error) {
90                                         if (error.name == 'ReferenceError') {
91                                                 console.log('waiting for dialogPolyfill');
92                                                 window.setTimeout(edit_tags_after_dialog_polyfill, 200);
93                                         }
94                                 }
95                         }
96                         edit_tags_after_dialog_polyfill();
97                 }
98         },
99         _x_edit_tags: function (frame, available_tags, message_id, tags) {
100                 var dialog = frame.document.createElement('dialog');
101                 if (!frame.document.createElement('dialog').show) {
102                         frame.dialogPolyfill.registerDialog(dialog);
103                 }
104
105                 dialog.style.border = '1px solid rgba(0, 0, 0, 0.3)';
106                 dialog.style.borderRadius = '6px';
107                 dialog.style.boxShadow = '0 3px 7px rgba(0, 0, 0, 0.3)';
108
109                 var content = frame.document.createElement('p');
110                 content.innerHTML = 'Edit tags for ' + message_id;
111                 dialog.appendChild(content);
112
113                 var tag_list = frame.document.createElement('p');
114                 dialog.appendChild(tag_list);
115                 for (var i = 0; i < available_tags.length; i++) {
116                         var tag = frame.document.createElement('a');
117                         tag.innerHTML = available_tags[i];
118                         tag.style.cursor = 'pointer';
119                         if (tags.indexOf(available_tags[i]) >= 0) {
120                                 tag.style.backgroundColor = 'lime';
121                         }
122                         tag.onclick = this._toggle_tag.bind(
123                                 this, message_id, available_tags[i], tag);
124                         tag_list.appendChild(tag);
125                         tag_list.appendChild(frame.document.createTextNode(' '));
126                 }
127                 var close = frame.document.createElement('button');
128                 close.innerHTML = 'Close';
129                 close.onclick = function () {
130                         dialog.close();
131                 };
132                 dialog.appendChild(close);
133
134                 frame.document.body.insertBefore(dialog, frame.document.body.firstChild);
135
136                 dialog.show();
137         },
138         _toggle_tag: function (message_id, tag, element) {
139                 var prefix;
140                 if (element.style.backgroundColor == 'lime') {
141                         prefix = '-';  /* unset */
142                         element.style.backgroundColor = null;
143                 } else {
144                         prefix = '+';  /* set */
145                         element.style.backgroundColor = 'lime';
146                 }
147                 var url = [
148                         nmbug_server,
149                         'mid',
150                         encodeURIComponent(message_id),
151                         ].join('/');
152                 console.log('nmbug: alter tags via ' + url);
153                 var request = new XMLHttpRequest();
154                 request.onload = function () {
155                         if (this.status == 200) {
156                                 var tags = JSON.parse(this.response);
157                                 console.log('nmbug: got tags', tags);
158                         } else {
159                                 throw 'Error posting to ' + url + ' (status ' + this.status + ')';
160                         }
161                 };
162                 request.open('post', url, true);
163                 request.setRequestHeader(
164                         'Content-Type', 'application/json; charset=UTF-8');
165                 request.send(JSON.stringify([prefix + tag]));
166         },
167 };
168
169 var _gmane_handler = {
170         regexp: /gmane[.]org/,
171         handle: function (callback) {
172                 var frame = this._get_frame();
173                 var article = this._article_from_url(frame.document.URL);
174                 this._get_message_id(article, function (message_id) {
175                         callback(message_id, frame);
176                 });
177         },
178         _article_from_url: function (url) {
179                 var regexp = new RegExp('http://article.gmane.org/([^/]+)/([0-9]+)');
180                 var match = regexp.exec(url);
181                 console.log('nmbug: get article from ' + url, match);
182                 if (match) {
183                         return {'group': match[1], 'id': parseInt(match[2])};
184                 }
185         },
186         _get_frame: function () {
187                 var frame = window;
188                 var article = this._article_from_url(frame.document.URL);
189                 var i = 0;
190                 for (var i = 0; !article && i < window.frames.length; i++) {
191                         frame = window.frames[i];
192                         article = this._article_from_url(frame.document.URL);
193                 }
194                 if (!article) {
195                         throw "Cannot extract an article from Gmane's " + document.URL;
196                 }
197                 return frame;
198         },
199         _get_message_id: function (article, callback) {
200                 var url = [
201                         nmbug_server,
202                         'gmane',
203                         article.group,
204                         article.id,
205                 ].join('/');
206                 console.log('nmbug: get Message-ID from ' + url);
207                 var request = new XMLHttpRequest();
208                 request.onload = function () {
209                         var message_id = this.responseText;
210                         callback(message_id);
211                 };
212                 request.open('get', url, true);
213                 request.send();
214         },
215 };
216
217 var handlers = [
218         _gmane_handler,
219 ];
220
221 function _check_handler(handler) {
222         var match = handler.regexp.test(document.URL);
223         console.log('nmbug: testing', handler, match);
224         if (match) {
225                 console.log('nmbug: matched', handler);
226                 handler.handle(nmbug.show.bind(nmbug));
227         }
228         return match;  /* break after the first match */
229 }
230
231 function run() {
232         var matched = handlers.some(_check_handler);
233         if (!matched) {
234                 throw 'No handler for ' + document.URL;
235         }
236 }