]> git.wh0rd.org Git - tt-rss.git/blob - offline.js
offline: store category collapsed state
[tt-rss.git] / offline.js
1 var SCHEMA_VERSION = 5;
2
3 var offline_mode = false;
4 var store = false;
5 var localServer = false;
6 var db = false;
7
8 function view_offline(id, feed_id) {
9         try {
10
11                 enableHotkeys();
12                 showArticleInHeadlines(id);
13
14                 db.execute("UPDATE articles SET unread = 0 WHERE id = ?", [id]);
15
16                 var rs = db.execute("SELECT * FROM articles WHERE id = ?", [id]);
17
18                 if (rs.isValidRow()) {
19
20                         var tmp = "<div class=\"postReply\">";
21
22                         tmp += "<div class=\"postHeader\" onmouseover=\"enable_resize(true)\" "+
23                                 "onmouseout=\"enable_resize(false)\">";
24
25                         tmp += "<div class=\"postDate\">"+rs.fieldByName("updated")+"</div>";
26
27                         if (rs.fieldByName("link") != "") {
28                                 tmp += "<div clear='both'><a target=\"_blank\" "+
29                                         "href=\"" + rs.fieldByName("link") + "\">" +
30                                         rs.fieldByName("title") + "</a></div>";
31                         } else {
32                                 tmp += "<div clear='both'>" + rs.fieldByName("title") + "</div>";
33                         }
34
35 /*                      tmp += "<div style='float : right'> "+
36                                 "<img src='images/tag.png' class='tagsPic' alt='Tags' title='Tags'>";
37                         tmp += rs.fieldByName("tags");
38                         tmp += "</div>"; */
39
40                         tmp += "<div clear='both'>"+
41                                 "<a target=\"_blank\" "+
42                                         "href=\"" + rs.fieldByName("comments") + "\">" +
43                                         __("comments") + "</a></div>";
44
45                         tmp += "</div>";
46
47                         tmp += "<div class=\"postContent\">"
48                         tmp += rs.fieldByName("content");
49                         tmp += "</div>";
50
51                         tmp += "</div>";
52
53                         render_article(tmp);
54                         update_local_feedlist_counters();
55                 }
56
57                 rs.close();
58
59                 return false;
60
61         } catch (e) {
62                 exception_error("view_offline", e);
63         }
64 }
65
66 function viewfeed_offline(feed_id, subop, is_cat, subop_param, skip_history, offset) {
67         try {
68                 notify('');
69
70                 if (!offset) offset = 0;
71
72                 if (offset > 0) {
73                         _feed_cur_page = parseInt(offset);
74                         if (_infscroll_request_sent) {
75                                 return;
76                         }
77                 } else {
78                         _feed_cur_page = 0;
79                         _infscroll_disable = 0;
80                 }
81
82                 if (getActiveFeedId() != feed_id) {
83                         _feed_cur_page = 0;
84                         active_post_id = 0;
85                         _infscroll_disable = 0;
86                 }
87
88                 loading_set_progress(100);
89
90                 clean_feed_selections();
91         
92                 setActiveFeedId(feed_id, is_cat);
93
94                 if (!is_cat) {
95                         var feedr = document.getElementById("FEEDR-" + feed_id);
96                         if (feedr && !feedr.className.match("Selected")) {      
97                                 feedr.className = feedr.className + "Selected";
98                         } 
99                 } else {
100                         var feedr = document.getElementById("FCAT-" + feed_id);
101                         if (feedr && !feedr.className.match("Selected")) {      
102                                 feedr.className = feedr.className + "Selected";
103                         } 
104                 }
105
106                 disableContainerChildren("headlinesToolbar", false);
107                 Form.enable("main_toolbar_form");
108
109                 var f = document.getElementById("headlines-frame");
110                 try {
111                         if (reply.offset == 0) { 
112                                 debug("resetting headlines scrollTop");
113                                 f.scrollTop = 0; 
114                         }
115                 } catch (e) { };
116
117
118                 var tmp = "";
119
120                 rs = db.execute("SELECT title FROM feeds WHERE id = ?", [feed_id]);
121
122                 if (rs.isValidRow() || feed_id == -1 || feed_id == -4) {
123
124                         feed_title = rs.field(0);
125
126                         if (feed_id == -1) {
127                                 feed_title = __("Starred articles");
128                         }
129
130                         if (feed_id == -4) {
131                                 feed_title = __("All articles");
132                         }
133
134                         if (offset == 0) {
135                                 tmp += "<div id=\"headlinesContainer\">";
136                 
137                                 tmp += "<div class=\"headlinesSubToolbar\">";
138                                 tmp += "<div id=\"subtoolbar_ftitle\">";
139                                 tmp += feed_title;
140                                 tmp += "</div>";
141
142                                 var sel_all_link;
143                                 var sel_unread_link;
144                                 var sel_none_link;
145                                 var sel_inv_link;
146
147                                 if (document.getElementById("content-frame")) {
148                                         sel_all_link = "javascript:selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', true, '', true)";
149                                         sel_unread_link = "javascript:selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', true, 'Unread', true)";
150                                         sel_none_link = "javascript:selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', false)";
151                                         sel_inv_link = "javascript:invertHeadlineSelection()";
152                                 } else {
153                                         sel_all_link = "javascript:cdmSelectArticles('all')";
154                                         sel_unread_link = "javascript:cdmSelectArticles('unread')";
155                                         sel_none_link = "javascript:cdmSelectArticles('none')";
156                                         sel_inv_link = "javascript:invertHeadlineSelection()";
157                                 }
158
159                                 tmp += __('Select:')+
160                                         " <a href=\""+sel_all_link+"\">"+__('All')+"</a>, "+
161                                         "<a href=\""+sel_unread_link+"\">"+__('Unread')+"</a>, "+
162                                         "<a href=\""+sel_inv_link+"\">"+__('Invert')+"</a>, "+
163                                         "<a href=\""+sel_none_link+"\">"+__('None')+"</a>";
164         
165                                 tmp += "&nbsp;&nbsp;";
166         
167                                 tmp += "</div>";
168         
169                                 tmp += "<div id=\"headlinesInnerContainer\" onscroll=\"headlines_scroll_handler()\">";
170                                 if (document.getElementById("content-frame")) {
171                                         tmp += "<table class=\"headlinesList\" id=\"headlinesList\" cellspacing=\"0\">";
172                                 }
173                         
174                         }
175         
176                         var limit = 30;
177                 
178                         var toolbar_form = document.forms["main_toolbar_form"];
179                         
180                         var limit = toolbar_form.limit[toolbar_form.limit.selectedIndex].value;
181                         var view_mode = toolbar_form.view_mode[toolbar_form.view_mode.selectedIndex].value;
182
183                         var limit_qpart = "";
184                         var strategy_qpart = "";
185                         var mode_qpart = "";
186                         var offset_qpart = "";
187
188                         if (limit != 0) {
189                                 limit_qpart = "LIMIT " + limit;
190                         }
191
192                         if (view_mode == "all_articles") {
193                                 mode_qpart = "1";
194                         } else if (view_mode == "adaptive") {
195                                 if (get_local_feed_unread(feed_id) > 0) {
196                                         mode_qpart = "unread = 1";
197                                 } else {
198                                         mode_qpart = "1";
199                                 }
200                         } else if (view_mode == "marked") {
201                                 mode_qpart = "marked = 1";
202                         } else if (view_mode == "unread") {
203                                 mode_qpart = "unread = 1";
204                         } else {
205                                 mode_qpart = "1";
206                         }
207
208                         if (feed_id > 0) {
209                                 strategy_qpart = "feed_id = " + feed_id;
210                         } else if (feed_id == -1) {
211                                 strategy_qpart = "marked = 1";
212                         } else if (feed_id == -4) {
213                                 strategy_qpart = "1";
214                         }
215
216                         if (offset > 0) {
217                                 offset_qpart = "OFFSET " + (offset*30);
218                         } else {
219                                 offset_qpart = "";
220                         }
221
222                         var query = "SELECT *,feeds.title AS feed_title "+
223                                 "FROM articles,feeds WHERE " +
224                                 "feed_id = feeds.id AND " +
225                                 strategy_qpart +
226                                 " AND " + mode_qpart + 
227                                 " ORDER BY updated DESC "+
228                                 limit_qpart + " " +
229                                 offset_qpart;
230
231                         var rs = db.execute(query);
232
233                         var line_num = offset*30;
234
235                         var real_feed_id = feed_id;
236
237                         while (rs.isValidRow()) {
238
239                                 var id = rs.fieldByName("id");
240                                 var feed_id = rs.fieldByName("feed_id");
241
242                                 var entry_feed_title = false;
243
244                                 if (real_feed_id < 0) {
245                                         entry_feed_title = rs.fieldByName("feed_title");
246                                 }
247
248                                 var marked_pic;
249         
250                                 var row_class = (line_num % 2) ? "even" : "odd";
251
252                                 if (rs.fieldByName("unread") == "1") {
253                                         row_class += "Unread";
254                                 }
255         
256                                 if (rs.fieldByName("marked") == "1") {
257                                         marked_pic = "<img id=\"FMPIC-"+id+"\" "+
258                                                 "src=\"images/mark_set.png\" class=\"markedPic\""+
259                                                 "alt=\"Unstar article\" onclick='javascript:tMark("+id+")'>";
260                                 } else {
261                                         marked_pic = "<img id=\"FMPIC-"+id+"\" "+
262                                                 "src=\"images/mark_unset.png\" class=\"markedPic\""+
263                                                 "alt=\"Star article\" onclick='javascript:tMark("+id+")'>";
264                                 }
265
266                                 var mouseover_attrs = "onmouseover='postMouseIn($id)' "+
267                                         "onmouseout='postMouseOut($id)'";
268
269                                 var content_preview = truncate_string(strip_tags(rs.fieldByName("content")), 
270                                                 100);
271         
272                                 if (document.getElementById("content-frame")) {
273
274                                         tmp += "<tr class='"+row_class+"' id='RROW-"+id+"' "+mouseover_attrs+">";
275                                         
276                                         tmp += "<td class='hlUpdPic'> </td>";
277         
278                                         tmp += "<td class='hlSelectRow'>"+
279                                                 "<input type=\"checkbox\" onclick=\"tSR(this)\" id=\"RCHK-"+id+"\"></td>";
280                                         
281                                         tmp += "<td class='hlMarkedPic'>"+marked_pic+"</td>";
282                 
283                                         tmp += "<td onclick='view("+id+","+feed_id+")' "+
284                                                 "class='hlContent' valign='middle'>";
285                 
286                                         tmp += "<a target=\"_blank\" id=\"RTITLE-"+id+"\" href=\"" + 
287                                                 rs.fieldByName("link") + "\"" +
288                                                 "onclick=\"return view("+id+","+feed_id+");\">"+
289                                                 rs.fieldByName("title");
290         
291                                         tmp += "<span class=\"contentPreview\"> - "+content_preview+"</span>";
292         
293                                         tmp += "</a>";
294
295                                         if (entry_feed_title) {
296                                                 tmp += " <span class=\"hlFeed\">"+
297                                                         "(<a href='javascript:viewfeed("+feed_id+
298                                                         ")'>"+entry_feed_title+"</a>)</span>";
299                                         }
300
301                                         tmp += "</td>";
302
303                                         tmp += "<td class=\"hlUpdated\" onclick='view("+id+","+feed_id+")'>"+
304                                                 "<nobr>"+rs.fieldByName("updated").substring(0,16)+
305                                                 "</nobr></td>";
306         
307                                         tmp += "</tr>";
308                                 } else {
309
310                                         var add_class = "";
311
312                                         if (rs.fieldByName("unread") == "1") {
313                                                 add_class = "Unread";                                   
314                                         }
315                                 
316                                         tmp += "<div class=\"cdmArticle"+add_class+"\" id=\"RROW-"+id+"\" "+
317                                                 mouseover_attrs+"'>";
318
319                                         feed_icon_img = "<img class=\"tinyFeedIcon\" src=\""+
320                                                 getInitParam("icons_url")+"/"+feed_id+".ico\" alt=\"\">";
321                                         cdm_feed_icon = "<span style=\"cursor : pointer\" "+
322                                                 "onclick=\"viewfeed("+feed_id+")\">"+feed_icon_img+"</span>";
323
324                                         tmp += "<div class=\"cdmHeader\">";
325                                         tmp += "<div class=\"articleUpdated\">"+
326                                                 rs.fieldByName("updated").substring(0,16)+
327                                                 " "+cdm_feed_icon+"</div>";
328
329                                         tmp += "<span id=\"RTITLE-"+id+"\" class=\"titleWrap\">"+
330                                                 "<a class=\"title\" onclick=\"javascript:toggleUnread("+id+", 0)\""+
331                                                 "target=\"_blank\" href=\""+rs.fieldByName("link")+
332                                                 "\">"+rs.fieldByName("title")+"</a>";
333
334                                         if (entry_feed_title) {
335                                                 tmp += "&nbsp;(<a href='javascript:viewfeed("+feed_id+
336                                                         ")'>"+entry_feed_title+"</a>)";
337                                         }
338
339                                         tmp += "</span></div>";
340
341                                         tmp += "<div class=\"cdmContent\" onclick=\"cdmClicked("+id+")\""+
342                                                 "id=\"CICD-"+id+"\">";
343                                         tmp += rs.fieldByName("content");
344                                         tmp += "<br clear='both'>"
345                                         tmp += "</div>"; 
346
347                                         tmp += "<div class=\"cdmFooter\"><span class='s0'>";
348                                         tmp += __("Select:")+
349                                                 " <input type=\"checkbox\" "+
350                                                 "onclick=\"toggleSelectRowById(this, 'RROW-"+id+"')\" "+
351                                                 "class=\"feedCheckBox\" id=\"RCHK-"+id+"\">";
352
353                                         tmp += "</span><span class='s1'>"+marked_pic+"</span> ";
354
355 /*                                      tmp += "<span class='s1'>"+
356                                                 "<img class='tagsPic' src='images/tag.png' alt='Tags' title='Tags'>"+
357                                                 "<span id=\"ATSTR-"+id+"\">"+rs.fieldByName("tags")+"</span>"+
358                                                 "</span>"; */
359
360                                         tmp += "<span class='s2'>Toggle: <a class=\"cdmToggleLink\""+
361                                                 "href=\"javascript:toggleUnread("+id+")\">"+
362                                                 "Unread</a></span>";
363                                         tmp += "</div>";
364
365                                         tmp += "</div>";
366                                 }
367
368                                 rs.next();
369                                 line_num++;
370                         }
371
372                         if (line_num - offset*30 < 30) {
373                                 _infscroll_disable = 1;
374                         }
375
376                         rs.close();
377         
378                         if (offset == 0) {
379                                 tmp += "</table>";
380
381                                 if (line_num - offset*30 == 0) {
382                                         tmp += "<div class='whiteBox'>" +
383                                                 __("No articles found to display.") +
384                                                 "</div>";
385                                 }
386                                 tmp += "</div></div>";
387                         }
388         
389                         if (offset == 0) {
390                                 var container = document.getElementById("headlines-frame");
391                                 container.innerHTML = tmp;
392                         } else {
393                                 var ids = getSelectedArticleIds2();
394                 
395                                 var container = document.getElementById("headlinesList");
396                                 container.innerHTML = container.innerHTML + tmp;
397         
398                                 for (var i = 0; i < ids.length; i++) {
399                                         markHeadline(ids[i]);
400                                 }
401                         }
402                 }
403
404                 remove_splash();
405
406                 _infscroll_request_sent = 0;
407
408         } catch (e) {
409                 exception_error("viewfeed_offline", e);
410         }
411 }
412
413 function render_offline_feedlist() {
414         try {
415                 var tmp = "<ul class=\"feedList\" id=\"feedList\">";
416
417                 var unread = get_local_feed_unread(-4);
418
419                 global_unread = unread;
420                 updateTitle();
421
422                 tmp += printFeedEntry(-4, __("All articles"), "feed", unread,
423                         "images/tag.png");
424
425                 var unread = get_local_feed_unread(-1);
426
427                 tmp += printFeedEntry(-1, __("Starred articles"), "feed", unread,
428                         "images/mark_set.png");
429
430                 tmp += "<li><hr/></li>";
431
432 /*              var rs = db.execute("SELECT feeds.id,feeds.title,has_icon,COUNT(articles.id) "+
433                         "FROM feeds LEFT JOIN articles ON (feed_id = feeds.id) "+
434                         "WHERE unread = 1 OR unread IS NULL GROUP BY feeds.id "+
435                         "ORDER BY feeds.title"); */
436
437                 var rs = db.execute("SELECT id,title,has_icon FROM feeds "+
438                         "ORDER BY title");
439
440                 while (rs.isValidRow()) {
441
442                         var id = rs.field(0);
443                         var title = rs.field(1);
444                         var has_icon = rs.field(2);
445                         var unread = get_local_feed_unread(id);
446
447                         var icon = "";
448
449                         if (has_icon) {
450                                 icon = "icons/" + id + ".ico";
451                         }
452
453
454                         var feed_icon = "";
455
456                         var row_class = "feed";
457
458                         if (unread > 0) {
459                                 row_class += "Unread";
460                                 fctr_class = "feedCtrHasUnread";
461                         } else {
462                                 fctr_class = "feedCtrNoUnread";
463                         }
464
465                         tmp += printFeedEntry(id, title, "feed", unread, icon);
466
467                         rs.next();
468                 }
469
470                 rs.close();
471
472                 tmp += "</ul>";
473
474                 render_feedlist(tmp);
475         } catch (e) {
476                 exception_error("render_offline_feedlist", e);
477         }
478 }
479
480 function init_offline() {
481         try {
482                 offline_mode = true;
483
484                 Element.hide("dispSwitchPrompt");
485                 Element.hide("feedBrowserPrompt");
486
487                 Element.hide("topLinksOnline");
488                 Element.show("topLinksOffline");
489
490                 var tb_form = document.getElementById("main_toolbar_form");
491                 Element.hide(tb_form.update);
492
493                 var chooser = document.getElementById("quickMenuChooser");
494                 chooser.disabled = true;
495
496                 var rs = db.execute("SELECT key, value FROM init_params");
497
498                 while (rs.isValidRow()) {
499                         init_params[rs.field(0)] = rs.field(1);
500                         rs.next();
501                 }
502
503                 rs.close();
504
505                 var rs = db.execute("SELECT COUNT(*) FROM feeds");
506
507                 var num_feeds = 0;
508
509                 if (rs.isValidRow()) {
510                         num_feeds = rs.field(0);                        
511                 }
512                 
513                 rs.close();
514
515                 if (num_feeds == 0) {
516                         remove_splash();
517                         return fatalError(0, 
518                                 __("Data for offline browsing has not been downloaded yet."));
519                 }
520
521                 render_offline_feedlist();
522                 init_second_stage();
523                 window.setTimeout("viewfeed(-4)", 50);
524
525         } catch (e) {
526                 exception_error("init_offline", e);
527         }
528 }
529
530 function offline_download_parse(stage, transport) {
531         try {
532                 if (transport.responseXML) {
533
534                         if (stage == 0) {
535
536                                 var feeds = transport.responseXML.getElementsByTagName("feed");
537
538                                 if (feeds.length > 0) {
539                                         db.execute("DELETE FROM feeds");
540                                 }
541
542                                 for (var i = 0; i < feeds.length; i++) {
543                                         var id = feeds[i].getAttribute("id");
544                                         var has_icon = feeds[i].getAttribute("has_icon");
545                                         var title = feeds[i].firstChild.nodeValue;
546                                         var cat_id = feeds[i].getAttribute("cat_id");
547
548                                         db.execute("INSERT INTO feeds (id,title,has_icon,cat_id)"+
549                                                 "VALUES (?,?,?,?)",
550                                                 [id, title, has_icon, cat_id]);
551                                 }
552
553                                 var cats = transport.responseXML.getElementsByTagName("category");
554
555                                 if (feeds.length > 0) {
556                                         db.execute("DELETE FROM categories");
557                                 }
558
559                                 for (var i = 0; i < cats.length; i++) {
560                                         var id = cats[i].getAttribute("id");
561                                         var collapsed = cats[i].getAttribute("collapsed");
562                                         var title = cats[i].firstChild.nodeValue;
563
564                                         db.execute("INSERT INTO categories (id,title,collapsed)"+
565                                                 "VALUES (?,?,?)",
566                                                 [id, title, collapsed]);
567                                 }
568
569                                 window.setTimeout("update_offline_data("+(stage+1)+")", 10*1000);
570                         } else {
571
572                                 var articles = transport.responseXML.getElementsByTagName("article");
573
574                                 var limit = transport.responseXML.getElementsByTagName("limit")[0];
575
576                                 if (limit) {
577                                         limit = limit.getAttribute("value");
578                                 } else {
579                                         limit = 0;
580                                 }
581
582                                 var articles_found = 0;
583
584                                 for (var i = 0; i < articles.length; i++) {                                     
585                                         var a = eval("("+articles[i].firstChild.nodeValue+")");
586                                         articles_found++;
587                                         if (a) {
588
589                                                 var date = new Date();
590                                                 var ts = Math.round(date.getTime() / 1000);
591
592                                                 db.execute("DELETE FROM articles WHERE id = ?", [a.id]);
593                                                 db.execute("INSERT INTO articles "+
594                                                 "(id, feed_id, title, link, guid, updated, content, "+
595                                                         "unread, marked, tags, added, comments) "+
596                                                 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", 
597                                                         [a.id, a.feed_id, a.title, a.link, a.guid, a.updated, 
598                                                                 a.content, a.unread, a.marked, a.tags, ts,
599                                                                 a.comments]);
600
601                                         }
602                                 }
603
604                                 debug("downloaded articles: " + articles_found + " limit: " + limit);
605
606                                 if (articles_found >= limit) {
607                                         window.setTimeout("update_offline_data("+(stage+1)+")", 10*1000);
608                                         debug("update_offline_data: done " + stage);
609                                 } else {
610                                         window.setTimeout("update_offline_data(0)", 1800*1000);
611                                         debug("update_offline_data: finished");
612
613                                         var date = new Date();
614                                         var ts = Math.round(date.getTime() / 1000);
615
616                                         db.execute("DELETE FROM articles WHERE added < ? - 2592000", [ts]);
617
618                                 }
619                         }
620
621 //                      notify('');
622
623                 }
624         } catch (e) {
625                 exception_error("offline_download_parse", e);
626         }
627 }
628
629 function update_offline_data(stage) {
630         try {
631
632                 if (!stage) stage = 0;
633                 if (offline_mode) return;
634
635                 debug("update_offline_data: stage " + stage);
636
637 //              notify_progress("Updating offline data... (" + stage +")", true);
638
639                 var query = "backend.php?op=rpc&subop=download&stage=" + stage;
640
641                 var rs = db.execute("SELECT MAX(id), MIN(id) FROM articles");
642
643                 if (rs.isValidRow() && rs.field(0)) {
644                         var offline_dl_max_id = rs.field(0);
645                         var offline_dl_min_id = rs.field(1);
646
647                         query = query + "&cidt=" + offline_dl_max_id;
648                         query = query + "&cidb=" + offline_dl_min_id;
649                 }
650
651                 rs.close();
652
653                 new Ajax.Request(query, {
654                         onComplete: function(transport) { 
655                                 offline_download_parse(stage, transport);                               
656                         } });
657
658         } catch (e) {
659                 exception_error("initiate_offline_download", e);
660         }
661 }
662
663 function set_feedlist_counter(id, ctr) {
664         try {
665
666                 var feedctr = document.getElementById("FEEDCTR-" + id);
667                 var feedu = document.getElementById("FEEDU-" + id);
668                 var feedr = document.getElementById("FEEDR-" + id);
669
670                 if (feedctr && feedu && feedr) {
671
672                         var row_needs_hl = (ctr > 0 && ctr > parseInt(feedu.innerHTML));
673
674                         feedu.innerHTML = ctr;
675
676                         if (ctr > 0) {                                  
677                                 feedctr.className = "feedCtrHasUnread";
678                                 if (!feedr.className.match("Unread")) {
679                                         var is_selected = feedr.className.match("Selected");
680         
681                                         feedr.className = feedr.className.replace("Selected", "");
682                                         feedr.className = feedr.className.replace("Unread", "");
683         
684                                         feedr.className = feedr.className + "Unread";
685         
686                                         if (is_selected) {
687                                                 feedr.className = feedr.className + "Selected";
688                                         }       
689                                         
690                                 }
691
692                                 if (row_needs_hl) { 
693                                         new Effect.Highlight(feedr, {duration: 1, startcolor: "#fff7d5",
694                                                 queue: { position:'end', scope: 'EFQ-' + id, limit: 1 } } );
695                                 }
696                         } else {
697                                 feedctr.className = "feedCtrNoUnread";
698                                 feedr.className = feedr.className.replace("Unread", "");
699                         }                       
700                 }
701
702         } catch (e) {
703                 exception_error("set_feedlist_counter", e);
704         }
705 }
706
707 function update_local_feedlist_counters() {
708         try {
709                 if (!offline_mode) return;
710
711 /*              var rs = db.execute("SELECT feeds.id,COUNT(articles.id) "+
712                         "FROM feeds LEFT JOIN articles ON (feed_id = feeds.id) "+
713                         "WHERE unread = 1 OR unread IS NULL GROUP BY feeds.id "+
714                         "ORDER BY feeds.title"); */
715
716                 var rs = db.execute("SELECT id,title,has_icon FROM feeds "+
717                         "ORDER BY title");
718
719                 while (rs.isValidRow()) {
720                         var id = rs.field(0);
721                         var ctr = get_local_feed_unread(id);
722
723                         set_feedlist_counter(id, ctr);
724
725                         rs.next();
726                 }
727
728                 rs.close();
729
730                 set_feedlist_counter(-4, get_local_feed_unread(-4));
731                 set_feedlist_counter(-1, get_local_feed_unread(-1));
732
733                 hideOrShowFeeds(getInitParam("hide_read_feeds") == 1);
734
735                 global_unread = get_local_feed_unread(-4);
736                 updateTitle();
737
738         } catch (e) {
739                 exception_error("update_local_feedlist_counters", e);
740         }
741 }
742
743 function get_local_feed_unread(id) {
744         try {
745                 var rs;
746
747                 if (id == -4) {
748                         rs = db.execute("SELECT SUM(unread) FROM articles");
749                 } else if (id == -1) {
750                         rs = db.execute("SELECT SUM(unread) FROM articles WHERE marked = 1");
751                 } else {
752                         rs = db.execute("SELECT SUM(unread) FROM articles WHERE feed_id = ?", [id]);
753                 }
754
755                 var a = false;
756
757                 if (rs.isValidRow()) {
758                         a = rs.field(0);
759                 } else {
760                         a = 0;
761                 }
762
763                 rs.close();
764
765                 return a;
766
767         } catch (e) {
768                 exception_error("get_local_feed_unread", e);
769         }
770 }
771
772 function init_gears() {
773         try {
774
775                 if (window.google && google.gears) {
776                         localServer = google.gears.factory.create("beta.localserver");
777                         store = localServer.createManagedStore("tt-rss");
778                         db = google.gears.factory.create('beta.database');
779                         db.open('tt-rss');
780
781                         db.execute("CREATE TABLE IF NOT EXISTS version (schema_version text)");
782
783                         var rs = db.execute("SELECT schema_version FROM version");
784
785                         var version = "";
786
787                         if (rs.isValidRow()) {
788                                 version = rs.field(0);
789                         }
790
791                         rs.close();
792
793                         if (version != SCHEMA_VERSION) {
794                                 db.execute("DROP TABLE IF EXISTS init_params");
795                                 db.execute("DROP TABLE IF EXISTS cache");
796                                 db.execute("DROP TABLE IF EXISTS feeds");
797                                 db.execute("DROP TABLE IF EXISTS categories");
798                                 db.execute("DROP TABLE IF EXISTS articles");
799                                 db.execute("DROP TABLE IF EXISTS version");
800                                 db.execute("CREATE TABLE IF NOT EXISTS version (schema_version text)");
801                                 db.execute("INSERT INTO version (schema_version) VALUES (?)", 
802                                         [SCHEMA_VERSION]);
803                         }
804
805                         db.execute("CREATE TABLE IF NOT EXISTS init_params (key text, value text)");
806
807                         db.execute("CREATE TABLE IF NOT EXISTS cache (id text, article text, param text, added text)");
808                         db.execute("CREATE TABLE IF NOT EXISTS feeds (id integer, title text, has_icon integer, cat_id integer)");
809                         db.execute("CREATE TABLE IF NOT EXISTS categories (id integer, title text, collapsed integer)");
810                         db.execute("CREATE TABLE IF NOT EXISTS articles (id integer, feed_id integer, title text, link text, guid text, updated text, content text, tags text, unread text, marked text, added text, comments text)");
811
812                         db.execute("DELETE FROM cache WHERE id LIKE 'F:%' OR id LIKE 'C:%'");
813
814                         Element.show("restartOfflinePic");
815
816                 }       
817         
818                 cache_expire();
819
820         } catch (e) {
821                 exception_error("init_gears", e);
822         }
823 }
824
825 function gotoOffline() {
826         window.location.href = "tt-rss.php?offline=1";
827 }
828
829 function gotoOnline() {
830         window.location.href = "tt-rss.php";
831 }
832