catchup batching:

* behave better if invoked during an infinite scroll request
* flush catchup batch when article is selected manually
This commit is contained in:
Andrew Dolgov 2018-12-01 11:42:57 +03:00
parent 195180b64d
commit 710d06a288
1 changed files with 26 additions and 233 deletions

View File

@ -178,10 +178,11 @@ function headlines_callback2(transport, offset, background, infscroll_req) {
_infscroll_request_sent = 0;
_last_headlines_update = new Date().getTime();
unpackVisibleHeadlines();
// this is used to auto-catchup articles if needed after infscroll request has finished,
// unpack visible articles, etc
headlinesScrollHandler();
// if we have some more space in the buffer, why not try to fill it
if (!_infscroll_disable && $("headlines-spacer") &&
$("headlines-spacer").offsetTop < $("headlines-frame").offsetHeight) {
@ -215,50 +216,6 @@ function render_article(article) {
} catch (e) { }
}
/*
function showArticleInHeadlines(id, noexpand) {
const row = $("RROW-" + id);
if (!row) return;
if (!noexpand)
row.removeClassName("Unread");
row.addClassName("active");
selectArticles('none');
markHeadline(id);
}
function article_callback2(transport, id) {
console.log("article_callback2 " + id);
const reply = handle_rpc_json(transport);
if (reply) {
reply.each(function(article) {
if (getActiveArticleId() == article['id']) {
render_article(article['content']);
}
cids_requested.remove(article['id']);
cache_set("article:" + article['id'], article['content']);
});
} else {
console.error("Invalid object received: " + transport.responseText);
render_article("<div class='whiteBox'>" +
__('Could not display article (invalid object received - see error console for details)') + "</div>");
}
const unread_in_buffer = $$("#headlines-frame > div[id*=RROW][class*=Unread]").length;
request_counters(unread_in_buffer == 0);
notify("");
}
*/
function view(id, noexpand) {
setActiveArticleId(id);
@ -316,83 +273,10 @@ function view(id, noexpand) {
}
return false;
/* const oldrow = $("RROW-" + getActiveArticleId());
if (oldrow) oldrow.removeClassName("active");
const crow = $("RROW-" + id);
if (!crow) return;
if (noexpand) {
setActiveArticleId(id);
showArticleInHeadlines(id, noexpand);
return;
}
console.log("loading article: " + id);
const cached_article = cache_get("article:" + id);
console.log("cache check result: " + (cached_article != false));
const query = {op: "article", method: "view", id: id};
const neighbor_ids = getRelativePostIds(id);
/* only request uncached articles */
/* const cids_to_request = [];
for (let i = 0; i < neighbor_ids.length; i++) {
if (cids_requested.indexOf(neighbor_ids[i]) == -1)
if (!cache_get("article:" + neighbor_ids[i])) {
cids_to_request.push(neighbor_ids[i]);
cids_requested.push(neighbor_ids[i]);
}
}
console.log("additional ids: " + cids_to_request.toString());
query.cids = cids_to_request.toString();
const article_is_unread = crow.hasClassName("Unread");
setActiveArticleId(id);
showArticleInHeadlines(id);
if (cached_article && article_is_unread) {
query.mode = "prefetch";
render_article(cached_article);
} else if (cached_article) {
query.mode = "prefetch_old";
render_article(cached_article);
// if we don't need to request any relative ids, we might as well skip
// the server roundtrip altogether
if (cids_to_request.length == 0) {
return;
}
}
last_requested_article = id;
console.log(query);
if (article_is_unread) {
decrementFeedCounter(getActiveFeedId(), activeFeedIsCat());
}
xhrPost("backend.php", query, (transport) => {
article_callback2(transport, id);
})
return false;
*/
}
function toggleMark(id, client_only) {
const query = { op: "rpc", id: id, method: "mark" };
const row = $("RROW-" + id);
if (row) {
@ -526,28 +410,8 @@ function moveToPost(mode, noscroll, noexpand) {
}
}
}
}
/* function toggleSelected(id, force_on) {
const row = $("RROW-" + id);
if (row) {
const cb = dijit.getEnclosingWidget(
row.getElementsByClassName("rchk")[0]);
if (row.hasClassName('Selected') && !force_on) {
row.removeClassName('Selected');
if (cb) cb.attr("checked", false);
} else {
row.addClassName('Selected');
if (cb) cb.attr("checked", true);
}
}
updateSelectedPrompt();
} */
function updateSelectedPrompt() {
const count = getSelectedArticleIds2().length;
const elem = $("selected_prompt");
@ -556,12 +420,8 @@ function updateSelectedPrompt() {
elem.innerHTML = ngettext("%d article selected",
"%d articles selected", count).replace("%d", count);
if (count > 0)
Element.show(elem);
else
Element.hide(elem);
count > 0 ? Element.show(elem) : Element.hide(elem);
}
}
function toggleUnread(id, cmode) {
@ -721,8 +581,7 @@ function getSelectedArticleIds2() {
rv.push(child.getAttribute("data-article-id"));
});
// i wonder if this is a good idea: consider active article a honorary member
// of selected articles
// consider active article a honorary member of selected articles
if (getActiveArticleId())
rv.push(getActiveArticleId());
@ -741,7 +600,6 @@ function getLoadedArticleIds() {
});
return rv;
}
// mode = all,none,unread,invert,marked,published
@ -799,64 +657,7 @@ function selectArticles(mode) {
}
}
// mode = all,none,unread,invert,marked,published
/* function selectArticles(mode, query) {
if (!query) query = "#headlines-frame > div[id*=RROW]";
const children = $$(query);
children.each(function(child) {
//const id = child.getAttribute("data-article-id");
const cb = dijit.getEnclosingWidget(
child.getElementsByClassName("rchk")[0]);
if (mode == "all") {
child.addClassName("Selected");
if (cb) cb.attr("checked", true);
} else if (mode == "unread") {
if (child.hasClassName("Unread")) {
child.addClassName("Selected");
if (cb) cb.attr("checked", true);
} else {
child.removeClassName("Selected");
if (cb) cb.attr("checked", false);
}
} else if (mode == "marked") {
if (child.hasClassName("marked")) {
child.addClassName("Selected");
if (cb) cb.attr("checked", true);
} else {
child.removeClassName("Selected");
if (cb) cb.attr("checked", false);
}
} else if (mode == "published") {
if (child.hasClassName("published")) {
child.addClassName("Selected");
if (cb) cb.attr("checked", true);
} else {
child.removeClassName("Selected");
if (cb) cb.attr("checked", false);
}
} else if (mode == "invert") {
if (child.hasClassName("Selected")) {
child.removeClassName("Selected");
if (cb) cb.attr("checked", false);
} else {
child.addClassName("Selected");
if (cb) cb.attr("checked", true);
}
} else {
child.removeClassName("Selected");
if (cb) cb.attr("checked", false);
}
});
updateSelectedPrompt();
} */
// noinspection JSUnusedGlobalSymbols
function deleteSelection() {
const rows = getSelectedArticleIds2();
@ -890,6 +691,7 @@ function deleteSelection() {
});
}
// noinspection JSUnusedGlobalSymbols
function archiveSelection() {
const rows = getSelectedArticleIds2();
@ -908,7 +710,6 @@ function archiveSelection() {
op = "archive";
} else {
str = ngettext("Move %d archived article back?", "Move %d archived articles back?", rows.length);
str += " " + __("Please note that unstarred articles might get purged on next feed update.");
op = "unarchive";
@ -968,8 +769,6 @@ function editArticleTags(id) {
style: "width: 600px",
execute: function() {
if (this.validate()) {
const query = dojo.objectToQuery(this.attr('value'));
notify_progress("Saving article tags...", true);
xhrPost("backend.php", this.attr('value'), (transport) => {
@ -997,7 +796,7 @@ function editArticleTags(id) {
href: query
});
var tmph = dojo.connect(dialog, 'onLoad', function() {
const tmph = dojo.connect(dialog, 'onLoad', function() {
dojo.disconnect(tmph);
new Ajax.Autocompleter('tags_str', 'tags_choices',
@ -1021,17 +820,10 @@ function cdmScrollToArticleId(id, force) {
// expanded cdm has a 4px margin now
ctr.scrollTop = parseInt(e.offsetTop) - 4;
/*setActiveArticleId(id);
// article is selected manually, set it read
toggleUnread(id, 0); */
Element.hide("floatingTitle");
}
}
// for the time being active article does not affect buffer selection (we still re/set the checkbox
// because of getSelectedArticleIds2() hack
function setActiveArticleId(id) {
console.log("setActiveArticleId", id);
@ -1042,7 +834,7 @@ function setActiveArticleId(id) {
const cb = dijit.getEnclosingWidget(e.select(".rchk")[0]);
if (cb) cb.attr("checked", false);
}
})
});
_active_article_id = id;
@ -1059,10 +851,13 @@ function setActiveArticleId(id) {
}
if (row.hasClassName("Unread")) {
toggleUnread(id, 0);
catchupBatchedArticles(() => {
decrementFeedCounter(getActiveFeedId(), activeFeedIsCat());
toggleUnread(id, 0);
updateFloatingTitle(true);
});
}
row.addClassName("active");
@ -1090,7 +885,7 @@ function postMouseOut(id) {
post_under_pointer = false;
}
function unpackVisibleHeadlines() {
function unpackVisibleArticles() {
if (!isCombinedMode() || !getInitParam("cdm_expanded")) return;
const rows = $$("#headlines-frame div[id*=RROW][data-content]");
@ -1106,20 +901,15 @@ function unpackVisibleHeadlines() {
row.removeAttribute("data-content");
PluginHost.run(PluginHost.HOOK_ARTICLE_RENDERED_CDM, row);
// i wonder if this is a good idea?
//if (!getActiveArticleId() && !row.hasClassName("Unread"))
// setActiveArticleId(row.getAttribute("data-article-id"));
} else {
break;
}
}
}
function headlinesScrollHandler(event) {
function headlinesScrollHandler(/* event */) {
try {
unpackVisibleHeadlines();
unpackVisibleArticles();
if (isCombinedMode()) {
updateFloatingTitle();
@ -1158,7 +948,7 @@ function headlinesScrollHandler(event) {
}
}
if (getInitParam("cdm_auto_catchup") == 1) {
if (getInitParam("cdm_auto_catchup") == 1 && !_infscroll_request_sent) {
let rows = $$("#headlines-frame > div[id*=RROW][class*=Unread]");
@ -1166,7 +956,6 @@ function headlinesScrollHandler(event) {
const row = rows[i];
if ($("headlines-frame").scrollTop > (row.offsetTop + row.offsetHeight/2)) {
const id = row.getAttribute("data-article-id")
if (catchup_id_batch.indexOf(id) == -1)
@ -1202,11 +991,11 @@ function openNextUnreadFeed() {
if (nuf) viewfeed({feed: nuf, is_cat: is_cat});
}
function catchupBatchedArticles() {
if (catchup_id_batch.length > 0 && !_infscroll_request_sent && !_catchup_request_sent) {
function catchupBatchedArticles(callback) {
console.log("catchupBatchedArticles, size=", catchup_id_batch.length);
if (catchup_id_batch.length > 0 /* && !_infscroll_request_sent */ && !_catchup_request_sent) {
// make a copy of the array
const batch = catchup_id_batch.slice();
const query = { op: "rpc", method: "catchupSelected",
@ -1230,7 +1019,11 @@ function catchupBatchedArticles() {
}
updateFloatingTitle(true);
if (callback) callback();
});
} else {
if (callback) callback();
}
}