]> git.wh0rd.org - tt-rss.git/blob - tt-rss.js
ed6cae91e5f274ae3452aa59d43916081ea53b4a
[tt-rss.git] / tt-rss.js
1 var xmlhttp = false;
2 var total_unread = 0;
3 var first_run = true;
4 var display_tags = false;
5 var global_unread = -1;
6 var active_title_text = "";
7 var current_subtitle = "";
8 var daemon_enabled = false;
9 var _qfd_deleted_feed = 0;
10 var firsttime_update = true;
11 var last_refetch = 0;
12 var cookie_lifetime = 0;
13
14 var xmlhttp = Ajax.getTransport();
15
16 var init_params = new Array();
17
18 function toggleTags() {
19 display_tags = !display_tags;
20
21 var p = document.getElementById("dispSwitchPrompt");
22
23 if (display_tags) {
24 p.innerHTML = "display feeds";
25 } else {
26 p.innerHTML = "display tags";
27 }
28
29 updateFeedList();
30 }
31
32 function dlg_frefresh_callback() {
33 if (xmlhttp.readyState == 4) {
34 notify(xmlhttp.responseText);
35 updateFeedList(false, false);
36 if (_qfd_deleted_feed) {
37 var hframe = document.getElementById("headlines-frame");
38 if (hframe) {
39 hframe.src = "backend.php?op=error&msg=No%20feed%20selected.";
40 }
41 }
42 closeInfoBox();
43 }
44 }
45
46 function hide_unread_callback() {
47 if (xmlhttp.readyState == 4) {
48
49 try {
50
51 var reply = xmlhttp.responseXML.firstChild.firstChild;
52 var value = reply.getAttribute("value");
53 var hide_read_feeds = (value != "false")
54 var feeds_doc = window.frames["feeds-frame"].document;
55
56 hideOrShowFeeds(feeds_doc, hide_read_feeds);
57
58 if (hide_read_feeds) {
59 setCookie("ttrss_vf_hreadf", 1);
60 } else {
61 setCookie("ttrss_vf_hreadf", 0);
62 }
63
64 } catch (e) {
65 exception_error("hide_unread_callback", e);
66 }
67
68 }
69 }
70
71 function refetch_callback() {
72 if (xmlhttp.readyState == 4) {
73 try {
74
75 var date = new Date();
76
77 last_refetch = date.getTime() / 1000;
78
79 if (!xmlhttp.responseXML) {
80 notify("refetch_callback: backend did not return valid XML", true, true);
81 return;
82 }
83
84 var reply = xmlhttp.responseXML.firstChild;
85
86 if (!reply) {
87 notify("refetch_callback: backend did not return expected XML object", true, true);
88 updateTitle("");
89 return;
90 }
91
92 var error_code = reply.getAttribute("error-code");
93
94 if (error_code && error_code != 0) {
95 return fatalError(error_code, reply.getAttribute("error-msg"));
96 }
97
98 parse_counters(reply, true);
99
100 debug("refetch_callback: done");
101
102 if (!daemon_enabled) {
103 notify("All feeds updated.");
104 updateTitle("");
105 } else {
106 notify("");
107 }
108 } catch (e) {
109 exception_error("refetch_callback", e);
110 updateTitle("");
111 }
112 }
113 }
114
115 function backend_sanity_check_callback() {
116
117 if (xmlhttp.readyState == 4) {
118
119 try {
120
121 if (!xmlhttp.responseXML) {
122 fatalError(3, "[D001, Received reply is not XML]: " + xmlhttp.responseText);
123 return;
124 }
125
126 var reply = xmlhttp.responseXML.firstChild.firstChild;
127
128 if (!reply) {
129 fatalError(3, "[D002, Invalid RPC reply]: " + xmlhttp.responseText);
130 return;
131 }
132
133 var error_code = reply.getAttribute("error-code");
134
135 if (error_code && error_code != 0) {
136 return fatalError(error_code, reply.getAttribute("error-msg"));
137 }
138
139 debug("sanity check ok");
140
141 var params = reply.nextSibling;
142
143 if (params) {
144 debug('reading init-params...');
145 var param = params.firstChild;
146
147 while (param) {
148 var k = param.getAttribute("key");
149 var v = param.getAttribute("value");
150 debug(k + " => " + v);
151 init_params[k] = v;
152 param = param.nextSibling;
153 }
154 }
155
156 init_second_stage();
157
158 } catch (e) {
159 exception_error("backend_sanity_check_callback", e);
160 }
161 }
162 }
163
164 function scheduleFeedUpdate(force) {
165
166 if (!daemon_enabled) {
167 notify("Updating feeds, please wait.", true);
168 updateTitle("Updating");
169 }
170
171 var query_str = "backend.php?op=rpc&subop=";
172
173 if (force) {
174 query_str = query_str + "forceUpdateAllFeeds";
175 } else {
176 query_str = query_str + "updateAllFeeds";
177 }
178
179 var omode;
180
181 if (firsttime_update && !navigator.userAgent.match("Opera")) {
182 firsttime_update = false;
183 omode = "T";
184 } else {
185 if (display_tags) {
186 omode = "t";
187 } else {
188 omode = "flc";
189 }
190 }
191
192 query_str = query_str + "&omode=" + omode;
193 query_str = query_str + "&uctr=" + global_unread;
194
195 debug("in scheduleFeedUpdate");
196
197 var date = new Date();
198
199 if (!xmlhttp_ready(xmlhttp) && last_refetch < date.getTime() / 1000 - 60) {
200 debug("xmlhttp seems to be stuck, aborting");
201 xmlhttp.abort();
202 }
203
204 if (xmlhttp_ready(xmlhttp)) {
205 xmlhttp.open("GET", query_str, true);
206 xmlhttp.onreadystatechange=refetch_callback;
207 xmlhttp.send(null);
208 } else {
209 debug("xmlhttp busy");
210 printLockingError();
211 }
212 }
213
214 function updateFeedList(silent, fetch) {
215
216 // if (silent != true) {
217 // notify("Loading feed list...");
218 // }
219
220 var query_str = "backend.php?op=feeds";
221
222 if (display_tags) {
223 query_str = query_str + "&tags=1";
224 }
225
226 if (getActiveFeedId()) {
227 query_str = query_str + "&actid=" + getActiveFeedId();
228 }
229
230 if (navigator.userAgent.match("Opera")) {
231 var date = new Date();
232 var timestamp = Math.round(date.getTime() / 1000);
233 query_str = query_str + "&ts=" + timestamp
234 }
235
236 if (fetch) query_str = query_str + "&fetch=yes";
237
238 var feeds_frame = document.getElementById("feeds-frame");
239
240 feeds_frame.src = query_str;
241 }
242
243 function catchupAllFeeds() {
244
245 var query_str = "backend.php?op=feeds&subop=catchupAll";
246
247 notify("Marking all feeds as read...");
248
249 var feeds_frame = document.getElementById("feeds-frame");
250
251 feeds_frame.src = query_str;
252
253 global_unread = 0;
254 updateTitle("");
255
256 }
257
258 function viewCurrentFeed(skip, subop) {
259
260 if (getActiveFeedId()) {
261 viewfeed(getActiveFeedId(), skip, subop);
262 } else {
263 disableContainerChildren("headlinesToolbar", false, document);
264 viewfeed(-1, skip, subop); // FIXME
265 }
266 return false; // block unneeded form submits
267 }
268
269 function viewfeed(feed, skip, subop) {
270 var f = window.frames["feeds-frame"];
271 f.viewfeed(feed, skip, subop);
272 }
273
274 function timeout() {
275 scheduleFeedUpdate(false);
276
277 var refresh_time = getInitParam("feeds_frame_refresh");
278
279 if (!refresh_time) refresh_time = 600;
280
281 setTimeout("timeout()", refresh_time*1000);
282 }
283
284 function resetSearch() {
285 var searchbox = document.getElementById("searchbox")
286
287 if (searchbox.value != "" && getActiveFeedId()) {
288 searchbox.value = "";
289 viewfeed(getActiveFeedId(), 0, "");
290 }
291 }
292
293 function searchCancel() {
294 closeInfoBox(true);
295 }
296
297 function search() {
298 closeInfoBox();
299 viewCurrentFeed(0, "");
300 }
301
302 function localPiggieFunction(enable) {
303 if (enable) {
304 var query_str = "backend.php?op=feeds&subop=piggie";
305
306 if (xmlhttp_ready(xmlhttp)) {
307
308 xmlhttp.open("GET", query_str, true);
309 xmlhttp.onreadystatechange=feedlist_callback;
310 xmlhttp.send(null);
311 }
312 }
313 }
314
315 function localHotkeyHandler(keycode) {
316
317 if (keycode == 82) { // r
318 return scheduleFeedUpdate(true);
319 }
320
321 if (keycode == 85) { // u
322 if (getActiveFeedId()) {
323 return viewfeed(getActiveFeedId(), 0, "ForceUpdate");
324 }
325 }
326
327 if (keycode == 65) { // a
328 return toggleDispRead();
329 }
330
331 var f_doc = window.frames["feeds-frame"].document;
332 var feedlist = f_doc.getElementById('feedList');
333
334 if (keycode == 74) { // j
335 var feed = getActiveFeedId();
336 var new_feed = getRelativeFeedId(feedlist, feed, 'prev');
337 if (new_feed) viewfeed(new_feed, 0, '');
338 }
339
340 if (keycode == 75) { // k
341 var feed = getActiveFeedId();
342 var new_feed = getRelativeFeedId(feedlist, feed, 'next');
343 if (new_feed) viewfeed(new_feed, 0, '');
344 }
345
346 // notify("KC: " + keycode);
347
348 }
349
350 // if argument is undefined, current subtitle is not updated
351 // use blank string to clear subtitle
352 function updateTitle(s) {
353 var tmp = "Tiny Tiny RSS";
354
355 if (s != undefined) {
356 current_subtitle = s;
357 }
358
359 if (global_unread > 0) {
360 tmp = tmp + " (" + global_unread + ")";
361 }
362
363 if (current_subtitle) {
364 tmp = tmp + " - " + current_subtitle;
365 }
366
367 if (active_title_text.length > 0) {
368 tmp = tmp + " > " + active_title_text;
369 }
370
371 document.title = tmp;
372 }
373
374 function genericSanityCheck() {
375
376 if (!xmlhttp) fatalError(1);
377
378 setCookie("ttrss_vf_test", "TEST");
379
380 if (getCookie("ttrss_vf_test") != "TEST") {
381 fatalError(2);
382 }
383
384 return true;
385 }
386
387 function init() {
388
389 try {
390
391 // this whole shebang is based on http://www.birnamdesigns.com/misc/busted2.html
392
393 if (arguments.callee.done) return;
394 arguments.callee.done = true;
395
396 disableContainerChildren("headlinesToolbar", true);
397
398 Form.disable("main_toolbar_form");
399
400 if (!genericSanityCheck())
401 return;
402
403 if (getURLParam('debug')) {
404 document.getElementById('debug_output').style.display = 'block';
405 debug('debug mode activated');
406 }
407
408 xmlhttp.open("GET", "backend.php?op=rpc&subop=sanityCheck", true);
409 xmlhttp.onreadystatechange=backend_sanity_check_callback;
410 xmlhttp.send(null);
411
412 } catch (e) {
413 exception_error("init", e);
414 }
415 }
416
417 function resize_feeds_frame() {
418 var f = document.getElementById("feeds-frame");
419 var tf = document.getElementById("mainFooter");
420 var th = document.getElementById("mainHeader");
421
422 f.style.height = document.body.scrollHeight - tf.scrollHeight -
423 th.scrollHeight - 50 + "px";
424 }
425
426 function init_second_stage() {
427
428 try {
429
430 cookie_lifetime = getCookie("ttrss_cltime");
431
432 delCookie("ttrss_vf_test");
433
434 setCookie("ttrss_vf_actfeed", "");
435
436 updateFeedList(false, false);
437 document.onkeydown = hotkey_handler;
438
439 var tb = parent.document.forms["main_toolbar_form"];
440
441 dropboxSelect(tb.view_mode, getInitParam("toolbar_view_mode"));
442 dropboxSelect(tb.limit, getInitParam("toolbar_limit"));
443
444 daemon_enabled = getInitParam("daemon_enabled");
445
446 // FIXME should be callled after window resize
447
448 var h = document.getElementById("headlines");
449 var c = document.getElementById("content");
450
451 if (navigator.userAgent.match("Opera")) {
452 resize_feeds_frame();
453
454 /* // fix headlines frame height for Opera
455 var h = document.getElementById("headlines");
456 var c = document.getElementById("content");
457 var nh = document.body.scrollHeight * 0.25;
458
459 h.style.height = nh + "px";
460 c.style.height = c.scrollHeight - nh + "px"; */
461
462 }
463
464 debug("second stage ok");
465
466 } catch (e) {
467 exception_error("init_second_stage", e);
468 }
469 }
470
471 function quickMenuChange() {
472 var chooser = document.getElementById("quickMenuChooser");
473 var opid = chooser[chooser.selectedIndex].value;
474
475 chooser.selectedIndex = 0;
476 quickMenuGo(opid);
477 }
478
479 function quickMenuGo(opid) {
480 try {
481
482 if (opid == "qmcPrefs") {
483 gotoPreferences();
484 }
485
486 if (opid == "qmcSearch") {
487 displayDlg("search", getActiveFeedId());
488 return;
489 }
490
491 if (opid == "qmcAddFeed") {
492 displayDlg("quickAddFeed");
493 return;
494 }
495
496 if (opid == "qmcRemoveFeed") {
497 var actid = getActiveFeedId();
498
499 if (!actid) {
500 alert("Please select some feed first.");
501 return;
502 }
503
504 if (confirm("Unsubscribe from current feed?")) {
505 qfdDelete(actid);
506 }
507
508 return;
509 }
510
511 if (opid == "qmcUpdateFeeds") {
512 scheduleFeedUpdate(true);
513 return;
514 }
515
516 if (opid == "qmcCatchupAll") {
517 catchupAllFeeds();
518 return;
519 }
520
521 if (opid == "qmcShowOnlyUnread") {
522 toggleDispRead();
523 return;
524 }
525
526 if (opid == "qmcAddFilter") {
527 displayDlg("quickAddFilter", getActiveFeedId());
528 }
529 } catch (e) {
530 exception_error("quickMenuGo", e);
531 }
532 }
533
534 function qfdDelete(feed_id) {
535
536 notify("Removing feed...");
537
538 if (!xmlhttp_ready(xmlhttp)) {
539 printLockingError();
540 return
541 }
542
543 // var feeds_doc = window.frames["feeds-frame"].document;
544 // feeds_doc.location.href = "backend.php?op=error&msg=Loading,%20please wait...";
545
546 _qfd_deleted_feed = feed_id;
547
548 xmlhttp.open("GET", "backend.php?op=pref-feeds&quiet=1&subop=remove&ids=" + feed_id);
549 xmlhttp.onreadystatechange=dlg_frefresh_callback;
550 xmlhttp.send(null);
551 }
552
553
554 function updateFeedTitle(t) {
555 active_title_text = t;
556 updateTitle();
557 }
558
559 function toggleDispRead() {
560 try {
561
562 if (!xmlhttp_ready(xmlhttp)) {
563 printLockingError();
564 return
565 }
566
567 var hide_read_feeds = (getCookie("ttrss_vf_hreadf") == 1);
568
569 hide_read_feeds = !hide_read_feeds;
570
571 var query = "backend.php?op=rpc&subop=setpref" +
572 "&key=HIDE_READ_FEEDS&value=" + param_escape(hide_read_feeds);
573
574 xmlhttp.open("GET", query);
575 xmlhttp.onreadystatechange=hide_unread_callback;
576 xmlhttp.send(null);
577
578 } catch (e) {
579 exception_error("toggleDispRead", e);
580 }
581 }
582
583 function fatalError(code, message) {
584 try {
585 var fe = document.getElementById("fatal_error");
586 var fc = document.getElementById("fatal_error_msg");
587
588 fc.innerHTML = "Code " + code + ": " + message;
589
590 fe.style.display = "block";
591
592 } catch (e) {
593 exception_error("fatalError", e);
594 }
595 }
596
597 function getInitParam(key) {
598 return init_params[key];
599 }
600
601 function storeInitParam(key, value) {
602 try {
603 init_params[key] = value;
604 new Ajax.Request("backend.php?op=rpc&subop=storeParam&key=" +
605 param_escape(key) + "&value=" + param_escape(value));
606 } catch (e) {
607 exception_error("storeInitParam", e);
608 }
609 }