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