From 78b2c6ce9a0574433791cc7f3330bf8d729123d2 Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Wed, 31 Aug 2011 14:03:52 +0400 Subject: [PATCH] rework caching, use html5 local storage allow caching of headlines code cleanup --- feedlist.js | 27 ++- functions.js | 4 +- functions.php | 4 +- tt-rss.js | 5 +- viewfeed.js | 442 ++++++++++++-------------------------------------- 5 files changed, 134 insertions(+), 348 deletions(-) diff --git a/feedlist.js b/feedlist.js index fb8a5de28..ab21a30fb 100644 --- a/feedlist.js +++ b/feedlist.js @@ -50,15 +50,22 @@ function loadMoreHeadlines() { function viewfeed(feed, subop, is_cat, offset) { try { - if (is_cat == undefined) is_cat = false; + if (is_cat == undefined) + is_cat = false; + else + is_cat = !!is_cat; + if (subop == undefined) subop = ''; if (offset == undefined) offset = 0; last_requested_article = 0; - if (feed == getActiveFeedId()) { - cache_invalidate("F:" + feed); - } + var cached_headlines = false; + + if (feed == getActiveFeedId()) + cache_delete("feed:" + feed + ":" + is_cat); + else + cached_headlines = cache_get("feed:" + feed + ":" + is_cat); dijit.byId("content-tabs").selectChild( dijit.byId("content-tabs").getChildren()[0]); @@ -70,6 +77,15 @@ function viewfeed(feed, subop, is_cat, offset) { _infscroll_disable = 0; } + if (!offset && !subop && cached_headlines) { + try { + render_local_headlines(feed, is_cat, JSON.parse(cached_headlines)); + return; + } catch (e) { + console.warn("render_local_headlines failed: " + e); + } + } + if (offset != 0 && !subop) { var date = new Date(); var timestamp = Math.round(date.getTime() / 1000); @@ -283,6 +299,9 @@ function parse_counters(elems, scheduled_call) { displayNewContentPrompt(id); } + if (getFeedUnread(id, (kind == "cat")) != ctr) + cache_delete("feed:" + id + ":" + (kind == "cat")); + setFeedUnread(id, (kind == "cat"), ctr); if (kind != "cat") { diff --git a/functions.js b/functions.js index 1a06a9bf3..1fd421809 100644 --- a/functions.js +++ b/functions.js @@ -1136,13 +1136,13 @@ function backend_sanity_check_callback(transport) { } } -function has_local_storage() { +/*function has_local_storage() { try { return 'sessionStorage' in window && window['sessionStorage'] != null; } catch (e) { return false; } -} +} */ function catSelectOnChange(elem) { try { diff --git a/functions.php b/functions.php index e0b5fc999..bb6164d7b 100644 --- a/functions.php +++ b/functions.php @@ -5098,7 +5098,7 @@ $vgroup_last_feed = $vgr_last_feed; - if (!$offset) { +// if (!$offset) { if (db_num_rows($result) > 0) { $reply['toolbar'] = format_headline_subtoolbar($link, $feed_site_url, @@ -5106,7 +5106,7 @@ $feed, $cat_view, $search, $match_on, $search_mode, $view_mode, $last_error); } - } +// } $headlines_count = db_num_rows($result); diff --git a/tt-rss.js b/tt-rss.js index 7987be7ab..c8f4ab83e 100644 --- a/tt-rss.js +++ b/tt-rss.js @@ -330,8 +330,7 @@ function init_second_stage() { loading_set_progress(30); - if (has_local_storage()) - sessionStorage.clear(); + cache_clear(); console.log("second stage ok"); @@ -565,12 +564,10 @@ function collapse_feedlist() { } function viewModeChanged() { - cache_flush(); return viewCurrentFeed('') } function viewLimitChanged() { - cache_flush(); return viewCurrentFeed('') } diff --git a/viewfeed.js b/viewfeed.js index 3a21323da..0d20faf81 100644 --- a/viewfeed.js +++ b/viewfeed.js @@ -9,14 +9,11 @@ var post_under_pointer = false; var last_requested_article = false; -var preload_id_batch = []; -var preload_timeout_id = false; - -var cache_added = []; - var catchup_id_batch = []; var catchup_timeout_id = false; +var has_storage = 'sessionStorage' in window && window['sessionStorage'] !== null; + function headlines_callback2(transport, offset) { try { handle_rpc_json(transport); @@ -138,10 +135,12 @@ function headlines_callback2(transport, offset) { } } + cache_headlines(feed_id, is_cat, reply['headlines']['toolbar'], $("headlines-frame").innerHTML); + if (articles) { for (var i = 0; i < articles.length; i++) { var a_id = articles[i]['id']; - cache_inject(a_id, articles[i]['content']); + cache_set("article:" + a_id, articles[i]['content']); } } else { console.log("no cached articles received"); @@ -210,14 +209,6 @@ function showArticleInHeadlines(id) { var upd_img_pic = $("FUPDPIC-" + id); - var cache_prefix = ""; - - if (activeFeedIsCat()) { - cache_prefix = "C:"; - } else { - cache_prefix = "F:"; - } - var view_mode = false; try { @@ -232,22 +223,10 @@ function showArticleInHeadlines(id) { upd_img_pic.src = "images/blank_icon.gif"; - cache_invalidate(cache_prefix + getActiveFeedId()); - - /* cache_inject(cache_prefix + getActiveFeedId(), - $("headlines-frame").innerHTML, - getFeedUnread(getActiveFeedId())); */ + cache_headlines(getActiveFeedId(), activeFeedIsCat(), null, $("headlines-frame").innerHTML); } else if (article_is_unread && view_mode == "all_articles") { - - cache_invalidate(cache_prefix + getActiveFeedId()); - - /* cache_inject(cache_prefix + getActiveFeedId(), - $("headlines-frame").innerHTML, - getFeedUnread(getActiveFeedId())-1); */ - - } else if (article_is_unread) { - cache_invalidate(cache_prefix + getActiveFeedId()); + cache_headlines(getActiveFeedId(), activeFeedIsCat(), null, $("headlines-frame").innerHTML); } markHeadline(id); @@ -282,7 +261,7 @@ function article_callback2(transport, id) { if (active_post_id == article['id']) { render_article(article['content']); } - cache_inject(article['id'], article['content']); + cache_set("article:" + article['id'], article['content']); }); } else { @@ -307,7 +286,7 @@ function view(id) { try { console.log("loading article: " + id); - var cached_article = cache_find(id); + var cached_article = cache_get("article:" + id); console.log("cache check result: " + (cached_article != false)); @@ -322,7 +301,7 @@ function view(id) { var cids_to_request = Array(); for (var i = 0; i < neighbor_ids.length; i++) { - if (!cache_check(neighbor_ids[i])) { + if (!cache_get("article:" + neighbor_ids[i])) { cids_to_request.push(neighbor_ids[i]); } } @@ -356,9 +335,9 @@ function view(id) { query = query + "&mode=prefetch_old"; render_article(cached_article); - } + return; // do not do prefetch_old request - cache_expire(); + } last_requested_article = id; @@ -606,27 +585,17 @@ function selectionRemoveLabel(id, ids) { return; } -// var ok = confirm(__("Remove selected articles from label?")); + var query = "?op=rpc&subop=removeFromLabel&ids=" + + param_escape(ids.toString()) + "&lid=" + param_escape(id); -// if (ok) { + console.log(query); - var query = "?op=rpc&subop=removeFromLabel&ids=" + - param_escape(ids.toString()) + "&lid=" + param_escape(id); - - console.log(query); - -// notify_progress("Loading, please wait..."); - - cache_invalidate("F:" + (-11 - id)); - - new Ajax.Request("backend.php", { - parameters: query, - onComplete: function(transport) { - handle_rpc_json(transport); - show_labels_in_headlines(transport); - } }); - -// } + new Ajax.Request("backend.php", { + parameters: query, + onComplete: function(transport) { + handle_rpc_json(transport); + show_labels_in_headlines(transport); + } }); } catch (e) { exception_error("selectionAssignLabel", e); @@ -644,27 +613,17 @@ function selectionAssignLabel(id, ids) { return; } -// var ok = confirm(__("Assign selected articles to label?")); + var query = "?op=rpc&subop=assignToLabel&ids=" + + param_escape(ids.toString()) + "&lid=" + param_escape(id); -// if (ok) { + console.log(query); - cache_invalidate("F:" + (-11 - id)); - - var query = "?op=rpc&subop=assignToLabel&ids=" + - param_escape(ids.toString()) + "&lid=" + param_escape(id); - - console.log(query); - -// notify_progress("Loading, please wait..."); - - new Ajax.Request("backend.php", { - parameters: query, - onComplete: function(transport) { - handle_rpc_json(transport); - show_labels_in_headlines(transport); - } }); - -// } + new Ajax.Request("backend.php", { + parameters: query, + onComplete: function(transport) { + handle_rpc_json(transport); + show_labels_in_headlines(transport); + } }); } catch (e) { exception_error("selectionAssignLabel", e); @@ -959,7 +918,7 @@ function archiveSelection() { console.log(query); for (var i = 0; i < rows.length; i++) { - cache_invalidate(rows[i]); + cache_delete("article:" + rows[i]); } new Ajax.Request("backend.php", { @@ -1037,7 +996,7 @@ function editArticleTags(id) { if (tags) tags.innerHTML = tags_str.content; if (tooltip) tooltip.attr('label', tags_str.content_full); - cache_invalidate(id); + cache_delete("article:" + id); } }}); @@ -1072,274 +1031,16 @@ function cdmScrollToArticleId(id) { } } -function cache_inject(id, article, param) { - - try { - if (!cache_check_param(id, param)) { - //console.log("cache_article: miss: " + id + " [p=" + param + "]"); - - var date = new Date(); - var ts = Math.round(date.getTime() / 1000); - - var cache_obj = {}; - - cache_obj["id"] = id; - cache_obj["data"] = article; - cache_obj["param"] = param; - - if (param) id = id + ":" + param; - - cache_added["TS:" + id] = ts; - - if (has_local_storage()) - sessionStorage.setItem(id, JSON.stringify(cache_obj)); - else - article_cache.push(cache_obj); - - } else { - //console.log("cache_article: hit: " + id + " [p=" + param + "]"); - } - } catch (e) { - exception_error("cache_inject", e); - } -} - -function cache_find(id) { - - if (has_local_storage()) { - var cache_obj = sessionStorage.getItem(id); - - if (cache_obj) { - cache_obj = JSON.parse(cache_obj); - - if (cache_obj) - return cache_obj['data']; - } - - } else { - for (var i = 0; i < article_cache.length; i++) { - if (article_cache[i]["id"] == id) { - return article_cache[i]["data"]; - } - } - } - return false; -} - -function cache_find_param(id, param) { - - if (has_local_storage()) { - - if (param) id = id + ":" + param; - - var cache_obj = sessionStorage.getItem(id); - - if (cache_obj) { - cache_obj = JSON.parse(cache_obj); - - if (cache_obj) - return cache_obj['data']; - } - - } else { - for (var i = 0; i < article_cache.length; i++) { - if (article_cache[i]["id"] == id && article_cache[i]["param"] == param) { - return article_cache[i]["data"]; - } - } - } - - return false; -} - -function cache_check(id) { - if (has_local_storage()) { - if (sessionStorage.getItem(id)) - return true; - } else { - for (var i = 0; i < article_cache.length; i++) { - if (article_cache[i]["id"] == id) { - return true; - } - } - } - return false; -} - -function cache_check_param(id, param) { - if (has_local_storage()) { - - if (param) id = id + ":" + param; - - if (sessionStorage.getItem(id)) - return true; - - } else { - for (var i = 0; i < article_cache.length; i++) { - if (article_cache[i]["id"] == id && article_cache[i]["param"] == param) { - return true; - } - } - } - return false; -} - -function cache_expire() { -if (has_local_storage()) { - - var date = new Date(); - var timestamp = Math.round(date.getTime() / 1000); - - for (var i = 0; i < sessionStorage.length; i++) { - - var id = sessionStorage.key(i); - - if (timestamp - cache_added["TS:" + id] > 180) { - sessionStorage.removeItem(id); - } - } - - } else { - while (article_cache.length > 25) { - article_cache.shift(); - } - } -} - -function cache_flush() { - if (has_local_storage()) { - sessionStorage.clear(); - } else { - article_cache = new Array(); - } -} - -function cache_invalidate(id) { - try { - if (has_local_storage()) { - - var found = false; - - for (var i = 0; i < sessionStorage.length; i++) { - var key = sessionStorage.key(i); - -// console.warn("cache_invalidate: " + key_id + " cmp " + id); - - if (key == id || key.indexOf(id + ":") == 0) { - sessionStorage.removeItem(key); - found = true; - break; - } - } - - return found; - - } else { - var i = 0 - - while (i < article_cache.length) { - if (article_cache[i]["id"] == id) { - //console.log("cache_invalidate: removed id " + id); - article_cache.splice(i, 1); - return true; - } - i++; - } - } - - //console.log("cache_invalidate: id not found: " + id); - return false; - } catch (e) { - exception_error("cache_invalidate", e); - } -} - function getActiveArticleId() { return active_post_id; } -function preloadBatchedArticles() { - try { - - var query = "?op=rpc&subop=getArticles&ids=" + - preload_id_batch.toString(); - - new Ajax.Request("backend.php", { - parameters: query, - onComplete: function(transport) { - - preload_id_batch = []; - - var articles = JSON.parse(transport.responseText); - - for (var i = 0; i < articles.length; i++) { - var id = articles[i]['id']; - if (!cache_check(id)) { - cache_inject(id, articles[i]['content']); - //console.log("preloaded article: " + id); - } - } - } }); - - } catch (e) { - exception_error("preloadBatchedArticles", e); - } -} - -function preloadArticleUnderPointer(id) { - try { - if (getInitParam("bw_limit") == "1") return; - - if (post_under_pointer == id && !cache_check(id)) { - - //console.log("trying to preload article " + id); - - var neighbor_ids = getRelativePostIds(id, 1); - - /* only request uncached articles */ - - if (preload_id_batch.indexOf(id) == -1) { - for (var i = 0; i < neighbor_ids.length; i++) { - if (!cache_check(neighbor_ids[i])) { - preload_id_batch.push(neighbor_ids[i]); - } - } - } - - if (preload_id_batch.indexOf(id) == -1) - preload_id_batch.push(id); - - //console.log("preload ids batch: " + preload_id_batch.toString()); - - window.clearTimeout(preload_timeout_id); - preload_batch_timeout_id = window.setTimeout('preloadBatchedArticles()', 1000); - - } - } catch (e) { - exception_error("preloadArticleUnderPointer", e); - } -} - function postMouseIn(id) { - try { - if (post_under_pointer != id) { - post_under_pointer = id; - if (!isCdmMode()) { - window.setTimeout("preloadArticleUnderPointer(" + id + ")", 250); - } - } - - } catch (e) { - exception_error("postMouseIn", e); - } + post_under_pointer = id; } function postMouseOut(id) { - try { - post_under_pointer = false; - } catch (e) { - exception_error("postMouseOut", e); - } + post_under_pointer = false; } function headlines_scroll_handler(e) { @@ -1692,13 +1393,16 @@ function show_labels_in_headlines(transport) { if (ctr) ctr.innerHTML = elem.labels; }); + + cache_headlines(getActiveFeedId(), activeFeedIsCat(), null, $("headlines-frame").innerHTML); + } } catch (e) { exception_error("show_labels_in_headlines", e); } } -function toggleHeadlineActions() { +/* function toggleHeadlineActions() { try { var e = $("headlineActionsBody"); var p = $("headlineActionsDrop"); @@ -1716,7 +1420,7 @@ function toggleHeadlineActions() { } catch (e) { exception_error("toggleHeadlineActions", e); } -} +} */ /* function publishWithNote(id, def_note) { try { @@ -2273,7 +1977,7 @@ function editArticleNote(id) { var reply = JSON.parse(transport.responseText); - cache_invalidate(id); + cache_delete("article:" + id); var elem = $("POSTNOTE-" + id); @@ -2325,3 +2029,69 @@ function player(elem) { } } +function cache_set(id, obj) { + console.log("cache_set: " + id); + if (has_storage) + try { + sessionStorage[id] = obj; + } catch (e) { + if (e == QUOTA_EXCEEDED_ERR) + sessionStorage.clear(); + } +} + +function cache_get(id) { + if (has_storage) + return sessionStorage[id]; +} + +function cache_clear() { + if (has_storage) + sessionStorage.clear(); +} + +function cache_delete(id) { + if (has_storage) + sessionStorage.removeItem(id); +} + +function cache_headlines(feed, is_cat, toolbar_obj, content_obj) { + if (toolbar_obj && content_obj) { + cache_set("feed:" + feed + ":" + is_cat, + JSON.stringify({toolbar: toolbar_obj, content: content_obj})); + } else { + try { + obj = JSON.parse(cache_get("feed:" + feed + ":" + is_cat)); + + if (obj) { + if (toolbar_obj) obj.toolbar = toolbar_obj; + if (content_obj) obj.content = content_obj; + + cache_set("feed:" + feed + ":" + is_cat, JSON.stringify(obj)); + } + + } catch (e) { + console.warn("cache_headlines failed: " + e); + } + } +} + +function render_local_headlines(feed, is_cat, obj) { + try { + + dijit.byId("headlines-toolbar").attr('content', + obj.toolbar); + + dijit.byId("headlines-frame").attr('content', + obj.content); + + dojo.parser.parse('headlines-toolbar'); + + $("headlines-frame").scrollTop = 0; + selectArticles('none'); + setActiveFeedId(feed, is_cat); + initHeadlinesMenu(); + } catch (e) { + exception_error("render_local_headlines", e); + } +}