]> git.wh0rd.org - tt-rss.git/blame - tt-rss.js
fix setting scrollTop on headlines buffer
[tt-rss.git] / tt-rss.js
CommitLineData
76798ff3 1var total_unread = 0;
8143ae1f 2var display_tags = false;
806a3d14 3var global_unread = -1;
2bf6e0a8 4var firsttime_update = true;
3d72bbdb
AD
5var _active_feed_id = 0;
6var _active_feed_is_cat = false;
9e397d0f 7var number_of_feeds = 0;
93f66472 8var hotkey_prefix = false;
164469f9 9var hotkey_prefix_pressed = false;
f8fb4498 10var init_params = {};
f8fb4498
AD
11var _force_scheduled_update = false;
12var last_scheduled_update = false;
13e785e0 13var treeModel;
a5550322 14
6237ea05
AD
15var _rpc_seq = 0;
16
17function next_seq() {
18 _rpc_seq += 1;
19 return _rpc_seq;
20}
21
22function get_seq() {
23 return _rpc_seq;
24}
25
3d72bbdb
AD
26function activeFeedIsCat() {
27 return _active_feed_is_cat;
28}
29
30function getActiveFeedId() {
3d72bbdb 31 try {
50eefedb 32 //console.log("gAFID: " + _active_feed_id);
3d72bbdb
AD
33 return _active_feed_id;
34 } catch (e) {
35 exception_error("getActiveFeedId", e);
36 }
37}
38
39function setActiveFeedId(id, is_cat) {
3d72bbdb 40 try {
3d72bbdb
AD
41 _active_feed_id = id;
42
43 if (is_cat != undefined) {
44 _active_feed_is_cat = is_cat;
45 }
46
fcf70c51
AD
47 selectFeed(id, is_cat);
48
3d72bbdb
AD
49 } catch (e) {
50 exception_error("setActiveFeedId", e);
51 }
52}
53
54
a5550322
AD
55function isFeedlistSortable() {
56 return feedlist_sortable_enabled;
57}
3ac2b520 58
0b126ac2
AD
59function tagsAreDisplayed() {
60 return display_tags;
61}
62
0979b696 63function toggleTags(show_all) {
8143ae1f 64
17a756d1
AD
65 try {
66
84c7b824 67 console.log("toggleTags: " + show_all + "; " + display_tags);
17a756d1 68
acac8448 69 var p = $("dispSwitchPrompt");
8143ae1f 70
0979b696
AD
71 if (!show_all && !display_tags) {
72 displayDlg("printTagCloud");
73 } else if (show_all) {
74 closeInfoBox();
75 display_tags = true;
709e7dc2 76 p.innerHTML = __("display feeds");
35a03bdd 77 notify_progress("Loading, please wait...", true);
0979b696
AD
78 updateFeedList();
79 } else if (display_tags) {
80 display_tags = false;
81 p.innerHTML = __("tag cloud");
35a03bdd 82 notify_progress("Loading, please wait...", true);
0979b696 83 updateFeedList();
8143ae1f 84 }
17a756d1
AD
85
86 } catch (e) {
87 exception_error("toggleTags", e);
88 }
8143ae1f
AD
89}
90
f3c6bf6e
AD
91function dlg_frefresh_callback(transport, deleted_feed) {
92 if (getActiveFeedId() == deleted_feed) {
fe1087fb 93 setTimeout("viewfeed(-5)", 100);
f3c6bf6e 94 }
abbe0154 95
fcf70c51 96 setTimeout('updateFeedList()', 50);
f3c6bf6e 97 closeInfoBox();
1cd17194 98}
e2f8f7b4 99
50eefedb
AD
100function updateFeedList() {
101 try {
fcf70c51 102 console.warn("updateFeedList: function not implemented");
59b8192f 103
13e785e0 104/* var query_str = "backend.php?op=feeds";
50eefedb
AD
105
106 if (display_tags) {
107 query_str = query_str + "&tags=1";
108 }
109
110 if (getActiveFeedId() && !activeFeedIsCat()) {
111 query_str = query_str + "&actid=" + getActiveFeedId();
112 }
113
114 new Ajax.Request("backend.php", {
115 parameters: query_str,
116 onComplete: function(transport) {
117 render_feedlist(transport.responseText);
13e785e0 118 } }); */
e1123aee 119
50eefedb
AD
120 } catch (e) {
121 exception_error("updateFeedList", e);
122 }
1a66d16e 123}
175847de 124
476cac42 125function catchupAllFeeds() {
076682aa 126
f8232151 127 var str = __("Mark all articles as read?");
476cac42 128
f8232151 129 if (getInitParam("confirm_feed_catchup") != 1 || confirm(str)) {
476cac42 130
f8232151 131 var query_str = "backend.php?op=feeds&subop=catchupAll";
1a66d16e 132
f8232151 133 notify_progress("Marking all feeds as read...");
476cac42 134
f8fb4498 135 //console.log("catchupAllFeeds Q=" + query_str);
fc69e641 136
b4e75b2a
AD
137 new Ajax.Request("backend.php", {
138 parameters: query_str,
f8232151
AD
139 onComplete: function(transport) {
140 feedlist_callback2(transport);
141 } });
142
143 global_unread = 0;
144 updateTitle("");
145 }
476cac42 146}
1cd17194 147
767e2486 148function viewCurrentFeed(subop) {
1a66d16e 149
ec6e2fd3 150 if (getActiveFeedId() != undefined) {
3d72bbdb 151 viewfeed(getActiveFeedId(), subop, activeFeedIsCat());
f0601b87 152 }
164f4738 153 return false; // block unneeded form submits
f0601b87
AD
154}
155
40d13c28 156function timeout() {
a598370d
AD
157 if (getInitParam("bw_limit") == "1") return;
158
f8fb4498
AD
159 try {
160 var date = new Date();
161 var ts = Math.round(date.getTime() / 1000);
162
163 if (ts - last_scheduled_update > 10 || _force_scheduled_update) {
f5de0d8d 164
ac49453b
AD
165 //console.log("timeout()");
166
f8fb4498
AD
167 window.clearTimeout(counter_timeout_id);
168
6237ea05 169 var query_str = "?op=rpc&subop=getAllCounters&seq=" + next_seq();
f8fb4498
AD
170
171 var omode;
172
173 if (firsttime_update && !navigator.userAgent.match("Opera")) {
174 firsttime_update = false;
175 omode = "T";
176 } else {
177 if (display_tags) {
178 omode = "tl";
179 } else {
180 omode = "flc";
181 }
182 }
183
184 query_str = query_str + "&omode=" + omode;
ac49453b
AD
185
186 if (!_force_scheduled_update)
187 query_str = query_str + "&last_article_id=" + getInitParam("last_article_id");
f8fb4498
AD
188
189 //console.log("[timeout]" + query_str);
190
191 new Ajax.Request("backend.php", {
192 parameters: query_str,
193 onComplete: function(transport) {
47fb32b0
AD
194 handle_rpc_reply(transport, !_force_scheduled_update);
195 _force_scheduled_update = false;
f8fb4498
AD
196 } });
197
198 last_scheduled_update = ts;
199 }
200
201 } catch (e) {
202 exception_error("timeout", e);
203 }
204
205 setTimeout("timeout()", 3000);
ac53063a
AD
206}
207
f0601b87 208function search() {
eff4997c 209 closeInfoBox();
4169bb67 210 viewCurrentFeed();
76798ff3 211}
1cd17194 212
f8fb4498 213function updateTitle() {
fc69e641 214 var tmp = "Tiny Tiny RSS";
21703604 215
fc69e641
AD
216 if (global_unread > 0) {
217 tmp = tmp + " (" + global_unread + ")";
218 }
219
fdf47b9d
AD
220 if (window.fluid) {
221 if (global_unread > 0) {
222 window.fluid.dockBadge = global_unread;
223 } else {
224 window.fluid.dockBadge = "";
225 }
226 }
227
fc69e641
AD
228 document.title = tmp;
229}
230
22a93ad8 231function genericSanityCheck() {
57937c42 232 setCookie("ttrss_test", "TEST");
295f9b42 233
57937c42 234 if (getCookie("ttrss_test") != "TEST") {
295f9b42
AD
235 fatalError(2);
236 }
237
22a93ad8
AD
238 return true;
239}
240
241function init() {
7719618b 242 try {
86b682ce
AD
243 Form.disable("main_toolbar_form");
244
2f01fe57
AD
245 dojo.require("dijit.layout.BorderContainer");
246 dojo.require("dijit.layout.ContentPane");
6e4f4ce1
AD
247 dojo.require("dijit.Dialog");
248 dojo.require("dijit.form.Button");
13e785e0
AD
249 dojo.require("dojo.data.ItemFileWriteStore");
250 dojo.require("dijit.Tree");
fcf70c51
AD
251 dojo.require("dijit.form.Select");
252 dojo.require("dojo.parser");
13e785e0
AD
253
254 dojo.addOnLoad(function() {
255
256 var store = new dojo.data.ItemFileWriteStore({
257 url: "backend.php?op=feeds"});
258
259 treeModel = new dijit.tree.ForestStoreModel({
260 store: store,
261 query: {
262 "type": "feed"
263 },
264 rootId: "root",
265 rootLabel: "Feeds",
266 childrenAttrs: ["items"]
267 });
268
269 var tree = new dijit.Tree({
270 model: treeModel,
271 _createTreeNode: function(args) {
272 var tnode = new dijit._TreeNode(args);
2ef5c21f
AD
273
274 if (args.item.icon)
275 tnode.iconNode.src = args.item.icon[0];
276
277 //tnode.labelNode.innerHTML = args.label;
13e785e0
AD
278 return tnode;
279 },
2ef5c21f
AD
280 getIconClass: function (item, opened) {
281 return (!item || this.model.mayHaveChildren(item)) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "feedIcon";
282 },
13e785e0
AD
283 getLabelClass: function (item, opened) {
284 return (item.unread == 0) ? "dijitTreeLabel" : "dijitTreeLabel Unread";
285 },
fcf70c51
AD
286 getRowClass: function (item, opened) {
287 return (!item.error || item.error == '') ? "dijitTreeRow" :
288 "dijitTreeRow Error";
289 },
13e785e0
AD
290 getLabel: function(item) {
291 if (item.unread > 0) {
292 return item.name + " (" + item.unread + ")";
293 } else {
294 return item.name;
295 }
296 },
fcf70c51
AD
297 onOpen: function (item, node) {
298 var id = String(item.id);
299 var cat_id = id.substr(id.indexOf(":")+1);
300
301 new Ajax.Request("backend.php",
302 { parameters: "backend.php?op=feeds&subop=collapse&cid=" +
303 param_escape(cat_id) + "&mode=1" } );
304 },
305 onClose: function (item, node) {
306 var id = String(item.id);
307 var cat_id = id.substr(id.indexOf(":")+1);
308
309 new Ajax.Request("backend.php",
310 { parameters: "backend.php?op=feeds&subop=collapse&cid=" +
311 param_escape(cat_id) + "&mode=0" } );
312
313 },
13e785e0
AD
314 onClick: function (item, node) {
315 var id = String(item.id);
316 var is_cat = id.match("^CAT:");
317 var feed = id.substr(id.indexOf(":")+1);
7923cfe9
AD
318 viewfeed(feed, '', is_cat);
319 return false;
13e785e0 320 },
7923cfe9 321 openOnClick: false,
13e785e0
AD
322 showRoot: false,
323 }, "feedTree");
324
325 });
2f01fe57 326
7719618b
AD
327 if (!genericSanityCheck())
328 return;
ac43eba1 329
4220d6b0
AD
330 var params = "&ua=" + param_escape(navigator.userAgent);
331
fca95d5f
AD
332 loading_set_progress(30);
333
b4e75b2a
AD
334 new Ajax.Request("backend.php", {
335 parameters: "backend.php?op=rpc&subop=sanityCheck" + params,
9ca945a6
AD
336 onComplete: function(transport) {
337 backend_sanity_check_callback(transport);
338 } });
47179952 339
7719618b
AD
340 } catch (e) {
341 exception_error("init", e);
a8d28f48 342 }
7719618b 343}
86741347 344
7719618b 345function init_second_stage() {
295f9b42 346
7719618b 347 try {
2f587484 348
57937c42 349 delCookie("ttrss_test");
770bbb02 350
40496720 351 var toolbar = document.forms["main_toolbar_form"];
f31673f7 352
40496720 353 dropboxSelect(toolbar.view_mode, getInitParam("default_view_mode"));
7b4d02a8 354 dropboxSelect(toolbar.order_by, getInitParam("default_view_order_by"));
c6784aea 355
61a20560 356 feeds_sort_by_unread = getInitParam("feeds_sort_by_unread") == 1;
5f136c9a 357
730dbf19
AD
358 loading_set_progress(60);
359
ff0010c1
AD
360 if (has_local_storage())
361 localStorage.clear();
362
fcf70c51 363 feedlist_init();
4a28ab44
AD
364 setTimeout("timeout()", 3000);
365
366 console.log("second stage ok");
fcf70c51 367
7719618b
AD
368 } catch (e) {
369 exception_error("init_second_stage", e);
2f587484 370 }
1cd17194 371}
ac43eba1 372
c09ec856 373function quickMenuChange() {
acac8448 374 var chooser = $("quickMenuChooser");
86b682ce 375 var opid = chooser[chooser.selectedIndex].value;
e2f8f7b4 376
c09ec856
AD
377 chooser.selectedIndex = 0;
378 quickMenuGo(opid);
379}
380
381function quickMenuGo(opid) {
bb3423cf 382 try {
c09ec856 383
bb3423cf
AD
384 if (opid == "qmcPrefs") {
385 gotoPreferences();
386 }
387
388 if (opid == "qmcSearch") {
a44049f6
AD
389 displayDlg("search", getActiveFeedId() + ":" + activeFeedIsCat(),
390 function() {
391 document.forms['search_form'].query.focus();
392 });
6de5d056
AD
393 return;
394 }
bb3423cf
AD
395
396 if (opid == "qmcAddFeed") {
3393238d 397 quickAddFeed();
bb3423cf 398 return;
69668465 399 }
7086277c
AD
400
401 if (opid == "qmcEditFeed") {
402 editFeedDlg(getActiveFeedId());
403 }
6de5d056 404
bb3423cf
AD
405 if (opid == "qmcRemoveFeed") {
406 var actid = getActiveFeedId();
442d77f1
AD
407
408 if (activeFeedIsCat()) {
89cb787e 409 alert(__("You can't unsubscribe from the category."));
442d77f1
AD
410 return;
411 }
412
413 if (!actid) {
89cb787e 414 alert(__("Please select some feed first."));
bb3423cf
AD
415 return;
416 }
64a2875d
AD
417
418 var fn = getFeedName(actid);
89cb787e
AD
419
420 var pr = __("Unsubscribe from %s?").replace("%s", fn);
421
422 if (confirm(pr)) {
e978f78d 423 unsubscribeFeed(actid);
bb3423cf
AD
424 }
425
426 return;
427 }
d1f0c584 428
bb3423cf
AD
429 if (opid == "qmcCatchupAll") {
430 catchupAllFeeds();
431 return;
432 }
433
434 if (opid == "qmcShowOnlyUnread") {
435 toggleDispRead();
436 return;
437 }
438
439 if (opid == "qmcAddFilter") {
a6d0014d
AD
440 displayDlg('quickAddFilter', '',
441 function () {document.forms['filter_add_form'].reg_exp.focus();});
bb3423cf 442 }
0979b696 443
1380f8ee
AD
444 if (opid == "qmcAddLabel") {
445 addLabel();
446 }
447
9a85081a
AD
448 if (opid == "qmcRescoreFeed") {
449 rescoreCurrentFeed();
450 }
451
238eff01 452 if (opid == "qmcHKhelp") {
86deaa0e
AD
453 //Element.show("hotkey_help_overlay");
454 Effect.Appear("hotkey_help_overlay", {duration : 0.3});
238eff01
AD
455 }
456
d16a5159 457 if (opid == "qmcResetUI") {
6e4f4ce1 458 alert("Function not implemented");
d16a5159
AD
459 }
460
791c8396
AD
461 if (opid == "qmcToggleReorder") {
462 feedlist_sortable_enabled = !feedlist_sortable_enabled;
463
464 if (feedlist_sortable_enabled) {
465 notify_info("Category reordering enabled");
466 toggle_sortable_feedlist(true);
467 } else {
468 notify_info("Category reordering disabled");
469 toggle_sortable_feedlist(false);
470 }
471 }
472
9d393c84
AD
473 if (opid == "qmcResetCats") {
474
475 if (confirm(__("Reset category order?"))) {
476
b4e75b2a 477 var query = "?op=feeds&subop=catsortreset";
9d393c84
AD
478
479 notify_progress("Loading, please wait...", true);
480
b4e75b2a
AD
481 new Ajax.Request("backend.php", {
482 parameters: query,
9d393c84
AD
483 onComplete: function(transport) {
484 window.setTimeout('updateFeedList(false, false)', 50);
485 } });
486 }
487 }
488
bb3423cf
AD
489 } catch (e) {
490 exception_error("quickMenuGo", e);
a24f525c 491 }
e2f8f7b4
AD
492}
493
3745788e 494function toggleDispRead() {
7f123cda 495 try {
3745788e 496
dbfc9522 497 var hide = !(getInitParam("hide_read_feeds") == "1");
3745788e 498
dbfc9522 499 hideOrShowFeeds(hide);
e8bd0da9 500
dbfc9522
AD
501 var query = "?op=rpc&subop=setpref&key=HIDE_READ_FEEDS&value=" +
502 param_escape(hide);
e8bd0da9 503
dbfc9522
AD
504 new Ajax.Request("backend.php", {
505 parameters: query,
506 onComplete: function(transport) {
507 setInitParam("hide_read_feeds", hide);
508 } });
5158ced9 509
7f123cda
AD
510 } catch (e) {
511 exception_error("toggleDispRead", e);
3745788e 512 }
3745788e 513}
295f9b42 514
71ad883b 515function parse_runtime_info(elem) {
c4f7ba80
AD
516
517 if (!elem || !elem.firstChild) {
f8fb4498 518 console.warn("parse_runtime_info: invalid node passed");
4724a093
AD
519 return;
520 }
521
c4f7ba80 522 var data = JSON.parse(elem.firstChild.nodeValue);
71ad883b 523
f8fb4498 524 //console.log("parsing runtime info...");
1cb7492d 525
c4f7ba80
AD
526 for (k in data) {
527 var v = data[k];
3ac2b520 528
f8fb4498 529 // console.log("RI: " + k + " => " + v);
1cb7492d 530
d9fa39f1 531 if (k == "new_version_available") {
acac8448 532 var icon = $("newVersionIcon");
d9fa39f1
AD
533 if (icon) {
534 if (v == "1") {
535 icon.style.display = "inline";
536 } else {
537 icon.style.display = "none";
538 }
539 }
5ae8f858 540 return;
d9fa39f1
AD
541 }
542
8e00ae9b
AD
543 var error_flag;
544
ef16ae37 545 if (k == "daemon_is_running" && v != 1) {
8e00ae9b 546 notify_error("<span onclick=\"javascript:explainError(1)\">Update daemon is not running.</span>", true);
5ae8f858 547 return;
8e00ae9b
AD
548 }
549
550 if (k == "daemon_stamp_ok" && v != 1) {
551 notify_error("<span onclick=\"javascript:explainError(3)\">Update daemon is not updating feeds.</span>", true);
5ae8f858 552 return;
8e00ae9b
AD
553 }
554
5ae8f858
AD
555 init_params[k] = v;
556 notify('');
71ad883b
AD
557 }
558}
fce24838
AD
559
560function catchupCurrentFeed() {
561
3d72bbdb 562 var fn = getFeedName(getActiveFeedId(), activeFeedIsCat());
fce24838 563
2d936cd1 564 var str = __("Mark all articles in %s as read?").replace("%s", fn);
234e467c 565
f6d6e22f 566 if (getInitParam("confirm_feed_catchup") != 1 || confirm(str)) {
28de3732 567 return viewCurrentFeed('MarkAllRead')
fce24838
AD
568 }
569}
88040f57 570
338ce36c 571function catchupFeedInGroup(id) {
a9bcfb8f 572
338ce36c 573 try {
a9bcfb8f 574
338ce36c
AD
575 var title = getFeedName(id);
576
577 var str = __("Mark all articles in %s as read?").replace("%s", title);
578
579 if (getInitParam("confirm_feed_catchup") != 1 || confirm(str)) {
580 return viewCurrentFeed('MarkAllReadGR:' + id)
581 }
582
583 } catch (e) {
584 exception_error("catchupFeedInGroup", e);
a9bcfb8f
AD
585 }
586}
587
7086277c 588function editFeedDlg(feed) {
2a8504cd 589 try {
7086277c 590
2a8504cd
AD
591 if (!feed) {
592 alert(__("Please select some feed first."));
593 return;
594 }
595
f11b8a34 596 if ((feed <= 0) || activeFeedIsCat() || tagsAreDisplayed()) {
2a8504cd
AD
597 alert(__("You can't edit this kind of feed."));
598 return;
599 }
600
601 var query = "";
602
6f151277 603 if (feed > 0) {
b4e75b2a 604 query = "?op=pref-feeds&subop=editfeed&id=" + param_escape(feed);
6f151277 605 } else {
b4e75b2a 606 query = "?op=pref-labels&subop=edit&id=" + param_escape(-feed-11);
6f151277 607 }
c67d2990
AD
608
609 disableHotkeys();
610
219f57fd
AD
611 notify_progress("Loading, please wait...", true);
612
b4e75b2a
AD
613 new Ajax.Request("backend.php", {
614 parameters: query,
2a8504cd
AD
615 onComplete: function(transport) {
616 infobox_callback2(transport);
3393238d 617 document.forms["edit_feed_form"].title.focus();
2a8504cd
AD
618 } });
619
620 } catch (e) {
621 exception_error("editFeedDlg", e);
7086277c
AD
622 }
623}
624
625/* this functions duplicate those of prefs.js feed editor, with
626 some differences because there is no feedlist */
627
628function feedEditCancel() {
629 closeInfoBox();
630 return false;
631}
632
633function feedEditSave() {
634
635 try {
636
7086277c
AD
637 // FIXME: add parameter validation
638
639 var query = Form.serialize("edit_feed_form");
640
42c32916 641 notify_progress("Saving feed...");
7086277c 642
f3c6bf6e
AD
643 new Ajax.Request("backend.php", {
644 parameters: query,
645 onComplete: function(transport) {
646 dlg_frefresh_callback(transport);
647 } });
648
641444d3 649 cache_flush();
7086277c
AD
650 closeInfoBox();
651
652 return false;
653
654 } catch (e) {
655 exception_error("feedEditSave (main)", e);
656 }
657}
1dc8dba0 658
8389b150
AD
659function collapse_feedlist() {
660 try {
0ce61157
AD
661
662 if (!Element.visible('feeds-holder')) {
663 Element.show('feeds-holder');
664 $("collapse_feeds_btn").innerHTML = "&lt;&lt;";
665 } else {
666 Element.hide('feeds-holder');
667 $("collapse_feeds_btn").innerHTML = "&gt;&gt;";
668 }
669
670 dijit.byId("main").resize();
6e4f4ce1
AD
671
672 query = "?op=rpc&subop=setpref&key=_COLLAPSED_FEEDLIST&value=true";
fcf70c51 673 new Ajax.Request("backend.php", { parameters: query });
6e4f4ce1 674
8389b150 675 } catch (e) {
f88c7814 676 exception_error("collapse_feedlist", e);
8389b150 677 }
3c2d7945 678}
8389b150 679
3c2d7945 680function viewModeChanged() {
641444d3 681 cache_flush();
35322147 682 return viewCurrentFeed('')
3c2d7945 683}
8389b150 684
3c2d7945 685function viewLimitChanged() {
641444d3 686 cache_flush();
35322147 687 return viewCurrentFeed('')
8389b150 688}
546499a9 689
9bf3f101 690/* function adjustArticleScore(id, score) {
546499a9
AD
691 try {
692
693 var pr = prompt(__("Assign score to article:"), score);
694
695 if (pr != undefined) {
b4e75b2a 696 var query = "?op=rpc&subop=setScore&id=" + id + "&score=" + pr;
546499a9 697
b4e75b2a
AD
698 new Ajax.Request("backend.php", {
699 parameters: query,
546499a9
AD
700 onComplete: function(transport) {
701 viewCurrentFeed();
702 } });
703
704 }
705 } catch (e) {
438f2ce9 706 exception_error("adjustArticleScore", e);
546499a9 707 }
9bf3f101 708} */
9a85081a
AD
709
710function rescoreCurrentFeed() {
711
712 var actid = getActiveFeedId();
713
714 if (activeFeedIsCat() || actid < 0 || tagsAreDisplayed()) {
715 alert(__("You can't rescore this kind of feed."));
716 return;
717 }
718
719 if (!actid) {
720 alert(__("Please select some feed first."));
721 return;
722 }
723
724 var fn = getFeedName(actid);
69811a7d 725 var pr = __("Rescore articles in %s?").replace("%s", fn);
9a85081a
AD
726
727 if (confirm(pr)) {
728 notify_progress("Rescoring articles...");
729
b4e75b2a 730 var query = "?op=pref-feeds&subop=rescore&quiet=1&ids=" + actid;
9a85081a 731
b4e75b2a
AD
732 new Ajax.Request("backend.php", {
733 parameters: query,
734 onComplete: function(transport) {
735 viewCurrentFeed();
736 } });
9a85081a
AD
737 }
738}
739
93f66472
AD
740function hotkey_handler(e) {
741
742 try {
743
744 var keycode;
745 var shift_key = false;
746
78935092 747 var cmdline = $('cmdline');
93f66472
AD
748
749 try {
750 shift_key = e.shiftKey;
751 } catch (e) {
752
753 }
754
755 if (window.event) {
756 keycode = window.event.keyCode;
757 } else if (e) {
758 keycode = e.which;
759 }
760
eec498c3 761 var keychar = String.fromCharCode(keycode);
c177f2e6 762
93f66472
AD
763 if (keycode == 27) { // escape
764 if (Element.visible("hotkey_help_overlay")) {
765 Element.hide("hotkey_help_overlay");
766 }
767 hotkey_prefix = false;
768 closeInfoBox();
769 }
770
6e4f4ce1 771 if (dialogs.length > 0 || !hotkeys_enabled) {
84c7b824 772 console.log("hotkeys disabled");
93f66472
AD
773 return;
774 }
775
776 if (keycode == 16) return; // ignore lone shift
ac743c83 777 if (keycode == 17) return; // ignore lone ctrl
93f66472 778
fe3320d2
AD
779 if ((keycode == 70 || keycode == 67 || keycode == 71)
780 && !hotkey_prefix) {
344702be 781
164469f9
AD
782 var date = new Date();
783 var ts = Math.round(date.getTime() / 1000);
784
93f66472 785 hotkey_prefix = keycode;
164469f9 786 hotkey_prefix_pressed = ts;
78935092
AD
787
788 cmdline.innerHTML = keychar;
789 Element.show(cmdline);
790
84c7b824 791 console.log("KP: PREFIX=" + keycode + " CHAR=" + keychar + " TS=" + ts);
344702be 792 return true;
93f66472
AD
793 }
794
795 if (Element.visible("hotkey_help_overlay")) {
796 Element.hide("hotkey_help_overlay");
797 }
798
799 /* Global hotkeys */
800
78935092
AD
801 Element.hide(cmdline);
802
93f66472
AD
803 if (!hotkey_prefix) {
804
eec498c3 805 if ((keycode == 191 || keychar == '?') && shift_key) { // ?
93f66472 806 if (!Element.visible("hotkey_help_overlay")) {
86deaa0e
AD
807 //Element.show("hotkey_help_overlay");
808 Effect.Appear("hotkey_help_overlay", {duration : 0.3});
93f66472
AD
809 } else {
810 Element.hide("hotkey_help_overlay");
811 }
eec498c3 812 return false;
93f66472 813 }
60ea2377 814
eec498c3 815 if (keycode == 191 || keychar == '/') { // /
a44049f6
AD
816 displayDlg("search", getActiveFeedId() + ":" + activeFeedIsCat(),
817 function() {
818 document.forms['search_form'].query.focus();
819 });
eec498c3 820 return false;
93f66472
AD
821 }
822
f8fb4498 823/* if (keycode == 82 && shift_key) { // R
eec498c3 824 scheduleFeedUpdate(true);
19d7bfcd 825 return;
f8fb4498 826 } */
bd7ad16c 827
93f66472
AD
828 if (keycode == 74) { // j
829 var feed = getActiveFeedId();
ec37f4f1
AD
830 var new_feed = getRelativeFeedId2(feed, activeFeedIsCat(), 'prev');
831// alert(feed + " IC: " + activeFeedIsCat() + " => " + new_feed);
832 if (new_feed) {
833 var is_cat = new_feed.match("CAT:");
834 if (is_cat) {
835 new_feed = new_feed.replace("CAT:", "");
836 viewCategory(new_feed);
837 } else {
838 viewfeed(new_feed, '', false);
839 }
840 }
19d7bfcd 841 return;
93f66472
AD
842 }
843
844 if (keycode == 75) { // k
845 var feed = getActiveFeedId();
ec37f4f1
AD
846 var new_feed = getRelativeFeedId2(feed, activeFeedIsCat(), 'next');
847// alert(feed + " IC: " + activeFeedIsCat() + " => " + new_feed);
848 if (new_feed) {
849 var is_cat = new_feed.match("CAT:");
850 if (is_cat == "CAT:") {
851 new_feed = new_feed.replace("CAT:", "");
852 viewCategory(new_feed);
853 } else {
854 viewfeed(new_feed, '', false);
855 }
856 }
19d7bfcd 857 return;
93f66472
AD
858 }
859
a411875b 860 if (shift_key && keycode == 40) { // shift-down
62f2d58f 861 catchupRelativeToArticle(1);
19d7bfcd 862 return;
62f2d58f
AD
863 }
864
a411875b 865 if (shift_key && keycode == 38) { // shift-up
62f2d58f 866 catchupRelativeToArticle(0);
19d7bfcd 867 return;
62f2d58f
AD
868 }
869
a411875b
AD
870 if (shift_key && keycode == 78) { // N
871 scrollArticle(50);
872 return;
873 }
874
875 if (shift_key && keycode == 80) { // P
876 scrollArticle(-50);
877 return;
878 }
879
0129090b 880 if (keycode == 68 && shift_key) { // shift-D
1ede5814
AD
881 dismissSelectedArticles();
882 }
883
884 if (keycode == 88 && shift_key) { // shift-X
885 dismissReadArticles();
0129090b 886 }
a411875b 887
93f66472
AD
888 if (keycode == 78 || keycode == 40) { // n, down
889 if (typeof moveToPost != 'undefined') {
314fcd2b 890 moveToPost('next');
dad14b51 891 return false;
93f66472
AD
892 }
893 }
894
895 if (keycode == 80 || keycode == 38) { // p, up
896 if (typeof moveToPost != 'undefined') {
314fcd2b 897 moveToPost('prev');
dad14b51 898 return false;
93f66472
AD
899 }
900 }
901
902 if (keycode == 83 && shift_key) { // S
ac743c83 903 selectionTogglePublished(undefined, false, true);
19d7bfcd 904 return;
93f66472
AD
905 }
906
907 if (keycode == 83) { // s
ac743c83 908 selectionToggleMarked(undefined, false, true);
19d7bfcd 909 return;
93f66472
AD
910 }
911
912
913 if (keycode == 85) { // u
ac743c83 914 selectionToggleUnread(undefined, false, true)
19d7bfcd 915 return;
93f66472
AD
916 }
917
314fcd2b 918 if (keycode == 84 && shift_key) { // T
93f66472
AD
919 var id = getActiveArticleId();
920 if (id) {
921 editArticleTags(id, getActiveFeedId(), isCdmMode());
19d7bfcd 922 return;
93f66472
AD
923 }
924 }
925
314fcd2b
AD
926 if (keycode == 9) { // tab
927 var id = getArticleUnderPointer();
93f66472 928 if (id) {
acac8448 929 var cb = $("RCHK-" + id);
93f66472
AD
930
931 if (cb) {
932 cb.checked = !cb.checked;
933 toggleSelectRowById(cb, "RROW-" + id);
eec498c3 934 return false;
93f66472
AD
935 }
936 }
314fcd2b 937 }
93f66472
AD
938
939 if (keycode == 79) { // o
940 if (getActiveArticleId()) {
941 openArticleInNewWindow(getActiveArticleId());
19d7bfcd 942 return;
93f66472
AD
943 }
944 }
945
c1780289
AD
946 if (keycode == 81 && shift_key) { // Q
947 if (typeof catchupAllFeeds != 'undefined') {
948 catchupAllFeeds();
36cebe0f 949 return;
c1780289
AD
950 }
951 }
952
9bbbc82c
AD
953 if (keycode == 88) { // x
954 if (activeFeedIsCat()) {
955 toggleCollapseCat(getActiveFeedId());
956 }
957 }
93f66472
AD
958 }
959
960 /* Prefix f */
961
962 if (hotkey_prefix == 70) { // f
963
964 hotkey_prefix = false;
965
617698d7
AD
966 if (keycode == 81) { // q
967 if (getActiveFeedId()) {
968 catchupCurrentFeed();
969 return;
970 }
971 }
972
973 if (keycode == 82) { // r
974 if (getActiveFeedId()) {
975 viewfeed(getActiveFeedId(), "ForceUpdate", activeFeedIsCat());
976 return;
977 }
978 }
979
93f66472 980 if (keycode == 65) { // a
eec498c3
AD
981 toggleDispRead();
982 return false;
93f66472
AD
983 }
984
f8fb4498 985/* if (keycode == 85 && shift_key) { // U
eec498c3
AD
986 scheduleFeedUpdate(true);
987 return false;
f8fb4498 988 } */
93f66472
AD
989
990 if (keycode == 85) { // u
991 if (getActiveFeedId()) {
eec498c3
AD
992 viewfeed(getActiveFeedId(), "ForceUpdate");
993 return false;
93f66472
AD
994 }
995 }
996
997 if (keycode == 69) { // e
eec498c3
AD
998 editFeedDlg(getActiveFeedId());
999 return false;
93f66472
AD
1000 }
1001
1002 if (keycode == 83) { // s
3393238d 1003 quickAddFeed();
eec498c3 1004 return false;
93f66472
AD
1005 }
1006
1007 if (keycode == 67 && shift_key) { // C
1008 if (typeof catchupAllFeeds != 'undefined') {
eec498c3
AD
1009 catchupAllFeeds();
1010 return false;
93f66472
AD
1011 }
1012 }
1013
1014 if (keycode == 67) { // c
1015 if (getActiveFeedId()) {
eec498c3
AD
1016 catchupCurrentFeed();
1017 return false;
93f66472
AD
1018 }
1019 }
1020
60ea2377 1021 if (keycode == 87) { // w
61a20560 1022 feeds_sort_by_unread = !feeds_sort_by_unread;
60ea2377
AD
1023 return resort_feedlist();
1024 }
1025
8a3e0b1a
AD
1026 if (keycode == 88) { // x
1027 reverseHeadlineOrder();
1028 return;
1029 }
93f66472
AD
1030 }
1031
1032 /* Prefix c */
1033
1034 if (hotkey_prefix == 67) { // c
1035 hotkey_prefix = false;
1036
1037 if (keycode == 70) { // f
a6d0014d
AD
1038 displayDlg('quickAddFilter', '',
1039 function () {document.forms['filter_add_form'].reg_exp.focus();});
eec498c3 1040 return false;
93f66472
AD
1041 }
1042
fc2732f4
AD
1043 if (keycode == 76) { // l
1044 addLabel();
1045 return false;
1046 }
1047
93f66472
AD
1048 if (keycode == 83) { // s
1049 if (typeof collapse_feedlist != 'undefined') {
eec498c3
AD
1050 collapse_feedlist();
1051 return false;
93f66472
AD
1052 }
1053 }
1054
a5550322
AD
1055 if (keycode == 77) { // m
1056 feedlist_sortable_enabled = !feedlist_sortable_enabled;
1057 if (feedlist_sortable_enabled) {
1058 notify_info("Category reordering enabled");
1059 toggle_sortable_feedlist(true);
1060 } else {
1061 notify_info("Category reordering disabled");
1062 toggle_sortable_feedlist(false);
1063 }
1064 }
1065
a411875b
AD
1066 if (keycode == 78) { // n
1067 catchupRelativeToArticle(1);
1068 return;
1069 }
1070
1071 if (keycode == 80) { // p
1072 catchupRelativeToArticle(0);
1073 return;
1074 }
1075
1076
93f66472
AD
1077 }
1078
1079 /* Prefix g */
1080
1081 if (hotkey_prefix == 71) { // g
1082
1083 hotkey_prefix = false;
1084
49f4a7e9
AD
1085
1086 if (keycode == 65) { // a
1087 viewfeed(-4);
1088 return false;
1089 }
1090
93f66472 1091 if (keycode == 83) { // s
eec498c3
AD
1092 viewfeed(-1);
1093 return false;
93f66472
AD
1094 }
1095
1096 if (keycode == 80 && shift_key) { // P
eec498c3
AD
1097 gotoPreferences();
1098 return false;
93f66472
AD
1099 }
1100
1101 if (keycode == 80) { // p
eec498c3
AD
1102 viewfeed(-2);
1103 return false;
93f66472
AD
1104 }
1105
1106 if (keycode == 70) { // f
eec498c3
AD
1107 viewfeed(-3);
1108 return false;
93f66472
AD
1109 }
1110
5cf0cc5d 1111 if (keycode == 84 && shift_key) { // T
3a391f67 1112 toggleTags();
eec498c3 1113 return false;
3a391f67 1114 }
43319e5e
AD
1115 }
1116
1117 /* Cmd */
93f66472 1118
43319e5e
AD
1119 if (hotkey_prefix == 224 || hotkey_prefix == 91) { // f
1120 hotkey_prefix = false;
1121 return;
93f66472
AD
1122 }
1123
93f66472 1124 if (hotkey_prefix) {
84c7b824 1125 console.log("KP: PREFIX=" + hotkey_prefix + " CODE=" + keycode + " CHAR=" + keychar);
93f66472 1126 } else {
84c7b824 1127 console.log("KP: CODE=" + keycode + " CHAR=" + keychar);
93f66472
AD
1128 }
1129
1130
1131 } catch (e) {
1132 exception_error("hotkey_handler", e);
1133 }
1134}
61a20560 1135
a5819bb3
AD
1136function inPreferences() {
1137 return false;
1138}
8a3e0b1a
AD
1139
1140function reverseHeadlineOrder() {
1141 try {
1142
1143 var query_str = "?op=rpc&subop=togglepref&key=REVERSE_HEADLINES";
1144
1145 new Ajax.Request("backend.php", {
1146 parameters: query_str,
1147 onComplete: function(transport) {
1148 viewCurrentFeed();
1149 } });
1150
1151 } catch (e) {
1152 exception_error("reverseHeadlineOrder", e);
1153 }
1154}
fe1087fb
AD
1155
1156function showFeedsWithErrors() {
1157 displayDlg('feedUpdateErrors');
1158}
1159
f705f206
AD
1160function handle_rpc_reply(transport, scheduled_call) {
1161 try {
f705f206
AD
1162 if (transport.responseXML) {
1163
1164 if (!transport_error_check(transport)) return false;
1165
6237ea05
AD
1166 var seq = transport.responseXML.getElementsByTagName("seq")[0];
1167
1168 if (seq) {
1169 seq = seq.firstChild.nodeValue;
1170
1171 if (get_seq() != seq) {
1172 //console.log("[handle_rpc_reply] sequence mismatch: " + seq);
1173 return true;
1174 }
1175 }
1176
f705f206
AD
1177 var message = transport.responseXML.getElementsByTagName("message")[0];
1178
1179 if (message) {
1180 message = message.firstChild.nodeValue;
1181
1182 if (message == "UPDATE_COUNTERS") {
47fb32b0 1183 console.log("need to refresh counters...");
f705f206
AD
1184 setInitParam("last_article_id", -1);
1185 _force_scheduled_update = true;
1186 }
1187 }
1188
1189 var counters = transport.responseXML.getElementsByTagName("counters")[0];
1190
1191 if (counters)
1192 parse_counters(counters, scheduled_call);
1193
1194 var runtime_info = transport.responseXML.getElementsByTagName("runtime-info")[0];
1195
1196 if (runtime_info)
1197 parse_runtime_info(runtime_info);
1198
1199 if (feedsSortByUnread())
1200 resort_feedlist();
1201
1202 hideOrShowFeeds(getInitParam("hide_read_feeds") == 1);
1203
1204 } else {
1205 notify_error("Error communicating with server.");
1206 }
1207
1208 } catch (e) {
1209 exception_error("handle_rpc_reply", e, transport);
1210 }
1211
1212 return true;
1213}
1214
428b704d
AD
1215function scheduleFeedUpdate() {
1216 try {
1217
1218 if (!getActiveFeedId()) {
1219 alert(__("Please select some feed first."));
1220 return;
1221 }
1222
1223 var query = "?op=rpc&subop=scheduleFeedUpdate&id=" +
1224 param_escape(getActiveFeedId()) +
1225 "&is_cat=" + param_escape(activeFeedIsCat());
1226
1227 console.log(query);
1228
1229 new Ajax.Request("backend.php", {
1230 parameters: query,
1231 onComplete: function(transport) {
1232
1233 if (transport.responseXML) {
1234 var message = transport.responseXML.getElementsByTagName("message")[0];
1235
1236 if (message) {
1237 notify_info(message.firstChild.nodeValue);
1238 return;
1239 }
1240 }
1241
1242 notify_error("Error communicating with server.");
1243
1244 } });
1245
1246
1247 } catch (e) {
1248 exception_error("scheduleFeedUpdate", e);
1249 }
1250}