2 Copyright (C) 2014 W. Trevor King <wking@tremily.us>
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright notice, this
8 list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright notice,
11 this list of conditions and the following disclaimer in the documentation
12 and/or other materials provided with the distribution.
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
18 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 POSSIBILITY OF SUCH DAMAGE.
27 var nmbug_server = 'http://localhost:5000';
30 show: function (message_id, frame) {
32 if (frame === undefined) {
35 this._get_available_tags(function (available_tags) {
38 _this._edit_tags.bind(_this, frame, available_tags, message_id));
41 _get_available_tags: function (callback) {
46 console.log('nmbug: get available tags from ' + url);
47 var request = new XMLHttpRequest();
48 request.onload = function () {
49 if (this.status == 200) {
50 var available_tags = JSON.parse(this.response);
51 console.log('nmbug: got available tags', available_tags);
52 callback(available_tags);
54 throw 'Error fetching ' + url + ' (status ' + this.status + ')';
57 request.open('get', url, true);
60 _get_tags: function (message_id, callback) {
64 encodeURIComponent(message_id),
66 console.log('nmbug: get tags from ' + url);
67 var request = new XMLHttpRequest();
68 request.onload = function () {
69 if (this.status == 200) {
70 var tags = JSON.parse(this.response);
71 console.log('nmbug: got tags', tags);
74 throw 'Error fetching ' + url + ' (status ' + this.status + ')';
77 request.open('get', url, true);
80 _edit_tags: function (frame, available_tags, message_id, tags) {
81 var have_dialog_polyfill;
83 have_dialog_polyfill = frame.dialogPolyfill !== undefined;
85 if (error.name == 'ReferenceError') {
86 have_dialog_polyfill = false;
89 if (frame.document.createElement('dialog').show || have_dialog_polyfill) {
90 this._x_edit_tags(frame, available_tags, message_id, tags);
92 var script = frame.document.createElement('script');
93 script.type = 'text/javascript';
94 script.src = nmbug_server + '/static/dialog-polyfill/dialog-polyfill.js';
96 console.log('nmbug: loading dialog-polyfill.js');
97 frame.document.head.appendChild(script);
99 var link = frame.document.createElement('link');
100 link.rel = 'stylesheet';
101 link.type = 'text/css';
102 link.href = nmbug_server + '/static/dialog-polyfill/dialog-polyfill.css';
104 console.log('nmbug: loading dialog-polyfill.css');
105 frame.document.head.appendChild(link);
108 function edit_tags_after_dialog_polyfill () {
110 have_dialog_polyfill = frame.dialogPolyfill !== undefined;
111 console.log('have dialogPolyfill');
113 _this._x_edit_tags.bind(_this), 200,
114 frame, available_tags, message_id, tags);
116 if (error.name == 'ReferenceError') {
117 console.log('waiting for dialogPolyfill');
118 window.setTimeout(edit_tags_after_dialog_polyfill, 200);
122 edit_tags_after_dialog_polyfill();
125 _x_edit_tags: function (frame, available_tags, message_id, tags) {
126 var dialog = frame.document.createElement('dialog');
127 if (!frame.document.createElement('dialog').show) {
128 frame.dialogPolyfill.registerDialog(dialog);
131 dialog.style.border = '1px solid rgba(0, 0, 0, 0.3)';
132 dialog.style.borderRadius = '6px';
133 dialog.style.boxShadow = '0 3px 7px rgba(0, 0, 0, 0.3)';
134 dialog.style.marginLeft = '10em';
135 dialog.style.marginRight = '10em';
137 var content = frame.document.createElement('p');
138 content.innerHTML = 'Edit tags for ' + message_id;
139 dialog.appendChild(content);
141 var tag_list = frame.document.createElement('p');
142 dialog.appendChild(tag_list);
143 for (var i = 0; i < available_tags.length; i++) {
144 var tag = frame.document.createElement('a');
145 tag.innerHTML = available_tags[i];
146 tag.style.cursor = 'pointer';
147 if (tags.indexOf(available_tags[i]) >= 0) {
148 tag.style.backgroundColor = 'lime';
150 tag.onclick = this._toggle_tag.bind(
151 this, message_id, available_tags[i], tag);
152 tag_list.appendChild(tag);
153 tag_list.appendChild(frame.document.createTextNode(' '));
155 var close = frame.document.createElement('button');
156 close.innerHTML = 'Close';
157 close.onclick = function () {
160 dialog.appendChild(close);
162 frame.document.body.insertBefore(dialog, frame.document.body.firstChild);
166 _toggle_tag: function (message_id, tag, element) {
168 if (element.style.backgroundColor == 'lime') {
169 prefix = '-'; /* unset */
170 element.style.backgroundColor = null;
172 prefix = '+'; /* set */
173 element.style.backgroundColor = 'lime';
178 encodeURIComponent(message_id),
180 console.log('nmbug: alter tags via ' + url);
181 var request = new XMLHttpRequest();
182 request.onload = function () {
183 if (this.status == 200) {
184 var tags = JSON.parse(this.response);
185 console.log('nmbug: got tags', tags);
187 throw 'Error posting to ' + url + ' (status ' + this.status + ')';
190 request.open('post', url, true);
191 request.setRequestHeader(
192 'Content-Type', 'application/json; charset=UTF-8');
193 request.send(JSON.stringify([prefix + tag]));
197 var _gmane_handler = {
198 regexp: /gmane[.]org/,
199 handle: function (callback) {
200 var frame = this._get_frame();
201 var article = this._article_from_url(frame.document.URL);
202 this._get_message_id(article, function (message_id) {
203 callback(message_id, frame);
206 _article_from_url: function (url) {
207 var regexp = new RegExp('http://article.gmane.org/([^/]+)/([0-9]+)');
208 var match = regexp.exec(url);
209 console.log('nmbug: get article from ' + url, match);
211 return {'group': match[1], 'id': parseInt(match[2])};
214 _get_frame: function () {
216 var article = this._article_from_url(frame.document.URL);
218 for (var i = 0; !article && i < window.frames.length; i++) {
219 frame = window.frames[i];
220 article = this._article_from_url(frame.document.URL);
223 throw "Cannot extract an article from Gmane's " + document.URL;
227 _get_message_id: function (article, callback) {
234 console.log('nmbug: get Message-ID from ' + url);
235 var request = new XMLHttpRequest();
236 request.onload = function () {
237 var message_id = this.responseText;
238 callback(message_id);
240 request.open('get', url, true);
249 function _check_handler(handler) {
250 var match = handler.regexp.test(document.URL);
251 console.log('nmbug: testing', handler, match);
253 console.log('nmbug: matched', handler);
254 handler.handle(nmbug.show.bind(nmbug));
256 return match; /* break after the first match */
260 var matched = handlers.some(_check_handler);
262 throw 'No handler for ' + document.URL;