summaryrefslogtreecommitdiff
path: root/js/Headlines.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/Headlines.js')
-rwxr-xr-xjs/Headlines.js363
1 files changed, 229 insertions, 134 deletions
diff --git a/js/Headlines.js b/js/Headlines.js
index ea4c81a6a..6dbe24918 100755
--- a/js/Headlines.js
+++ b/js/Headlines.js
@@ -1,13 +1,13 @@
'use strict';
/* global __, ngettext, Article, App */
-/* global xhrPost, dojo, dijit, PluginHost, Notify, $$, Feeds */
+/* global dojo, dijit, PluginHost, Notify, xhr, Feeds */
/* global CommonDialogs */
const Headlines = {
vgroup_last_feed: undefined,
_headlines_scroll_timeout: 0,
- _observer_counters_timeout: 0,
+ //_observer_counters_timeout: 0,
headlines: [],
current_first_id: 0,
_scroll_reset_timeout: false,
@@ -44,7 +44,7 @@ const Headlines = {
row_observer: new MutationObserver((mutations) => {
const modified = [];
- mutations.each((m) => {
+ mutations.forEach((m) => {
if (m.type == 'attributes' && ['class', 'data-score'].indexOf(m.attributeName) != -1) {
const row = m.target;
@@ -54,7 +54,7 @@ const Headlines = {
const hl = Headlines.headlines[id];
if (hl) {
- const hl_old = Object.extend({}, hl);
+ const hl_old = {...{}, ...hl};
hl.unread = row.hasClassName("Unread");
hl.marked = row.hasClassName("marked");
@@ -94,7 +94,7 @@ const Headlines = {
rescore: {},
};
- modified.each(function (m) {
+ modified.forEach(function (m) {
if (m.old.marked != m.new.marked)
ops.tmark.push(m.id);
@@ -118,29 +118,29 @@ const Headlines = {
}
});
- ops.select.each((row) => {
- const cb = dijit.getEnclosingWidget(row.select(".rchk")[0]);
+ ops.select.forEach((row) => {
+ const cb = dijit.getEnclosingWidget(row.querySelector(".rchk"));
if (cb)
cb.attr('checked', true);
});
- ops.deselect.each((row) => {
- const cb = dijit.getEnclosingWidget(row.select(".rchk")[0]);
+ ops.deselect.forEach((row) => {
+ const cb = dijit.getEnclosingWidget(row.querySelector(".rchk"));
if (cb && !row.hasClassName("active"))
cb.attr('checked', false);
});
- ops.activate.each((row) => {
- const cb = dijit.getEnclosingWidget(row.select(".rchk")[0]);
+ ops.activate.forEach((row) => {
+ const cb = dijit.getEnclosingWidget(row.querySelector(".rchk"));
if (cb)
cb.attr('checked', true);
});
- ops.deactivate.each((row) => {
- const cb = dijit.getEnclosingWidget(row.select(".rchk")[0]);
+ ops.deactivate.forEach((row) => {
+ const cb = dijit.getEnclosingWidget(row.querySelector(".rchk"));
if (cb && !row.hasClassName("Selected"))
cb.attr('checked', false);
@@ -149,39 +149,56 @@ const Headlines = {
const promises = [];
if (ops.tmark.length != 0)
- promises.push(xhrPost("backend.php",
- {op: "rpc", method: "markSelected", ids: ops.tmark.toString(), cmode: 2}));
+ promises.push(xhr.post("backend.php",
+ {op: "rpc", method: "markSelected", "ids[]": ops.tmark, cmode: 2}));
if (ops.tpub.length != 0)
- promises.push(xhrPost("backend.php",
- {op: "rpc", method: "publishSelected", ids: ops.tpub.toString(), cmode: 2}));
+ promises.push(xhr.post("backend.php",
+ {op: "rpc", method: "publishSelected", "ids[]": ops.tpub, cmode: 2}));
if (ops.read.length != 0)
- promises.push(xhrPost("backend.php",
- {op: "rpc", method: "catchupSelected", ids: ops.read.toString(), cmode: 0}));
+ promises.push(xhr.post("backend.php",
+ {op: "rpc", method: "catchupSelected", "ids[]": ops.read, cmode: 0}));
if (ops.unread.length != 0)
- promises.push(xhrPost("backend.php",
- {op: "rpc", method: "catchupSelected", ids: ops.unread.toString(), cmode: 1}));
+ promises.push(xhr.post("backend.php",
+ {op: "rpc", method: "catchupSelected", "ids[]": ops.unread, cmode: 1}));
const scores = Object.keys(ops.rescore);
if (scores.length != 0) {
- scores.each((score) => {
- promises.push(xhrPost("backend.php",
- {op: "article", method: "setScore", id: ops.rescore[score].toString(), score: score}));
+ scores.forEach((score) => {
+ promises.push(xhr.post("backend.php",
+ {op: "article", method: "setScore", "ids[]": ops.rescore[score].toString(), score: score}));
});
}
- if (promises.length > 0)
- Promise.all([promises]).then(() => {
- window.clearTimeout(this._observer_counters_timeout);
+ Promise.all(promises).then((results) => {
+ let feeds = [];
+ let labels = [];
- this._observer_counters_timeout = setTimeout(() => {
- Feeds.requestCounters(true);
- }, 1000);
+ results.forEach((res) => {
+ if (res) {
+ try {
+ const obj = JSON.parse(res);
+
+ if (obj.feeds)
+ feeds = feeds.concat(obj.feeds);
+
+ if (obj.labels)
+ labels = labels.concat(obj.labels);
+
+ } catch (e) {
+ console.warn(e, res);
+ }
+ }
});
+ if (feeds.length > 0) {
+ console.log('requesting counters for', feeds, labels);
+ Feeds.requestCounters(feeds, labels);
+ }
+ });
},
click: function (event, id, in_body) {
in_body = in_body || false;
@@ -211,7 +228,7 @@ const Headlines = {
Headlines.select('none');
- const scroll_position_A = $("RROW-" + id).offsetTop - $("headlines-frame").scrollTop;
+ const scroll_position_A = App.byId(`RROW-${id}`).offsetTop - App.byId("headlines-frame").scrollTop;
Article.setActive(id);
@@ -222,10 +239,10 @@ const Headlines = {
Headlines.toggleUnread(id, 0);
} else {
- const scroll_position_B = $("RROW-" + id).offsetTop - $("headlines-frame").scrollTop;
+ const scroll_position_B = App.byId(`RROW-${id}`).offsetTop - App.byId("headlines-frame").scrollTop;
// this would only work if there's enough space
- $("headlines-frame").scrollTop -= scroll_position_A-scroll_position_B;
+ App.byId("headlines-frame").scrollTop -= scroll_position_A-scroll_position_B;
Article.cdmMoveToId(id);
}
@@ -252,7 +269,7 @@ const Headlines = {
return false;
},
initScrollHandler: function () {
- $("headlines-frame").onscroll = (event) => {
+ App.byId("headlines-frame").onscroll = (event) => {
clearTimeout(this._headlines_scroll_timeout);
this._headlines_scroll_timeout = window.setTimeout(function () {
//console.log('done scrolling', event);
@@ -262,8 +279,8 @@ const Headlines = {
},
loadMore: function () {
const view_mode = document.forms["toolbar-main"].view_mode.value;
- const unread_in_buffer = $$("#headlines-frame > div[id*=RROW][class*=Unread]").length;
- const num_all = $$("#headlines-frame > div[id*=RROW]").length;
+ const unread_in_buffer = App.findAll("#headlines-frame > div[id*=RROW][class*=Unread]").length;
+ const num_all = App.findAll("#headlines-frame > div[id*=RROW]").length;
const num_unread = Feeds.getUnread(Feeds.getActive(), Feeds.activeIsCat());
// TODO implement marked & published
@@ -289,10 +306,10 @@ const Headlines = {
Feeds.open({feed: Feeds.getActive(), is_cat: Feeds.activeIsCat(), offset: offset, append: true});
},
isChildVisible: function (elem) {
- return App.Scrollable.isChildVisible(elem, $("headlines-frame"));
+ return App.Scrollable.isChildVisible(elem, App.byId("headlines-frame"));
},
firstVisible: function () {
- const rows = $$("#headlines-frame > div[id*=RROW]");
+ const rows = App.findAll("#headlines-frame > div[id*=RROW]");
for (let i = 0; i < rows.length; i++) {
const row = rows[i];
@@ -303,7 +320,7 @@ const Headlines = {
}
},
unpackVisible: function(container) {
- const rows = $$("#headlines-frame > div[id*=RROW][data-content].cdm");
+ const rows = App.findAll("#headlines-frame > div[id*=RROW][data-content].cdm");
for (let i = 0; i < rows.length; i++) {
if (App.Scrollable.isChildVisible(rows[i], container)) {
@@ -315,8 +332,8 @@ const Headlines = {
scrollHandler: function (/*event*/) {
try {
if (!Feeds.infscroll_disabled && !Feeds.infscroll_in_progress) {
- const hsp = $("headlines-spacer");
- const container = $("headlines-frame");
+ const hsp = App.byId("headlines-spacer");
+ const container = App.byId("headlines-frame");
if (hsp && hsp.previousSibling) {
const last_row = hsp.previousSibling;
@@ -333,7 +350,7 @@ const Headlines = {
}
if (App.isCombinedMode() && App.getInitParam("cdm_expanded")) {
- const container = $("headlines-frame")
+ const container = App.byId("headlines-frame")
/* don't do anything until there was some scrolling */
if (container.scrollTop > 0)
@@ -342,12 +359,12 @@ const Headlines = {
if (App.getInitParam("cdm_auto_catchup")) {
- const rows = $$("#headlines-frame > div[id*=RROW][class*=Unread]");
+ const rows = App.findAll("#headlines-frame > div[id*=RROW][class*=Unread]");
for (let i = 0; i < rows.length; i++) {
const row = rows[i];
- if ($("headlines-frame").scrollTop > (row.offsetTop + row.offsetHeight / 2)) {
+ if (App.byId("headlines-frame").scrollTop > (row.offsetTop + row.offsetHeight / 2)) {
row.removeClassName("Unread");
} else {
break;
@@ -362,23 +379,23 @@ const Headlines = {
return this.headlines[id];
},
setCommonClasses: function () {
- $("headlines-frame").removeClassName("cdm");
- $("headlines-frame").removeClassName("normal");
+ App.byId("headlines-frame").removeClassName("cdm");
+ App.byId("headlines-frame").removeClassName("normal");
- $("headlines-frame").addClassName(App.isCombinedMode() ? "cdm" : "normal");
+ App.byId("headlines-frame").addClassName(App.isCombinedMode() ? "cdm" : "normal");
// for floating title because it's placed outside of headlines-frame
- $("main").removeClassName("expandable");
- $("main").removeClassName("expanded");
+ App.byId("main").removeClassName("expandable");
+ App.byId("main").removeClassName("expanded");
if (App.isCombinedMode())
- $("main").addClassName(App.getInitParam("cdm_expanded") ? " expanded" : " expandable");
+ App.byId("main").addClassName(App.getInitParam("cdm_expanded") ? "expanded" : "expandable");
},
renderAgain: function () {
// TODO: wrap headline elements into a knockoutjs model to prevent all this stuff
Headlines.setCommonClasses();
- $$("#headlines-frame > div[id*=RROW]").each((row) => {
+ App.findAll("#headlines-frame > div[id*=RROW]").forEach((row) => {
const id = row.getAttribute("data-article-id");
const hl = this.headlines[id];
@@ -401,12 +418,12 @@ const Headlines = {
}
});
- $$(".cdm .header-sticky-guard").each((e) => {
+ App.findAll(".cdm .header-sticky-guard").forEach((e) => {
this.sticky_header_observer.observe(e)
});
if (App.getInitParam("cdm_expanded"))
- $$("#headlines-frame > div[id*=RROW].cdm").each((e) => {
+ App.findAll("#headlines-frame > div[id*=RROW].cdm").forEach((e) => {
this.unpack_observer.observe(e)
});
@@ -423,7 +440,7 @@ const Headlines = {
if (headlines.vfeed_group_enabled && hl.feed_title && this.vgroup_last_feed != hl.feed_id) {
const vgrhdr = `<div data-feed-id='${hl.feed_id}' class='feed-title'>
- <div style='float : right'>${hl.feed_icon}</div>
+ <div style='float : right'>${Feeds.renderIcon(hl.feed_id, hl.has_icon)}</div>
<a class="title" href="#" onclick="Feeds.open({feed:${hl.feed_id}})">${hl.feed_title}
<a class="catchup" title="${__('mark feed as read')}" onclick="Feeds.catchupFeedInGroup(${hl.feed_id})" href="#"><i class="icon-done material-icons">done_all</i></a>
</div>`
@@ -431,7 +448,7 @@ const Headlines = {
const tmp = document.createElement("div");
tmp.innerHTML = vgrhdr;
- $("headlines-frame").appendChild(tmp.firstChild);
+ App.byId("headlines-frame").appendChild(tmp.firstChild);
this.vgroup_last_feed = hl.feed_id;
}
@@ -462,7 +479,7 @@ const Headlines = {
<a class="title" title="${App.escapeHtml(hl.title)}" target="_blank" rel="noopener noreferrer" href="${App.escapeHtml(hl.link)}">
${hl.title}</a>
<span class="author">${hl.author}</span>
- ${hl.labels}
+ ${Article.renderLabels(hl.id, hl.labels)}
${hl.cdm_excerpt ? hl.cdm_excerpt : ""}
</span>
@@ -477,25 +494,26 @@ const Headlines = {
<i class="material-icons icon-score" title="${hl.score}" onclick="Article.setScore(${hl.id}, this)">${Article.getScorePic(hl.score)}</i>
<span style="cursor : pointer" title="${App.escapeHtml(hl.feed_title)}" onclick="Feeds.open({feed:${hl.feed_id}})">
- ${hl.feed_icon}</span>
+ ${Feeds.renderIcon(hl.feed_id, hl.has_icon)}
+ </span>
</div>
</div>
<div class="content" onclick="return Headlines.click(event, ${hl.id}, true);">
- <div id="POSTNOTE-${hl.id}">${hl.note}</div>
+ ${Article.renderNote(hl.id, hl.note)}
<div class="content-inner" lang="${hl.lang ? hl.lang : 'en'}">
<img src="${App.getInitParam('icon_indicator_white')}">
</div>
<div class="intermediate">
- ${hl.enclosures}
+ ${Article.renderEnclosures(hl.enclosures)}
</div>
<div class="footer" onclick="event.stopPropagation()">
<div class="left">
${hl.buttons_left}
<i class="material-icons">label_outline</i>
- <span id="ATSTR-${hl.id}">${hl.tags_str}</span>
+ ${Article.renderTags(hl.id, hl.tags)}
<a title="${__("Edit tags for this article")}" href="#"
onclick="Article.editTags(${hl.id})">(+)</a>
${comments}
@@ -527,7 +545,7 @@ const Headlines = {
<span data-article-id="${hl.id}" class="hl-content hlMenuAttach">
<a class="title" href="${App.escapeHtml(hl.link)}">${hl.title} <span class="preview">${hl.content_preview}</span></a>
<span class="author">${hl.author}</span>
- ${hl.labels}
+ ${Article.renderLabels(hl.id, hl.labels)}
</span>
</div>
<span class="feed">
@@ -538,7 +556,7 @@ const Headlines = {
</div>
<div class="right">
<i class="material-icons icon-score" title="${hl.score}" onclick="Article.setScore(${hl.id}, this)">${Article.getScorePic(hl.score)}</i>
- <span onclick="Feeds.open({feed:${hl.feed_id}})" style="cursor : pointer" title="${App.escapeHtml(hl.feed_title)}">${hl.feed_icon}</span>
+ <span onclick="Feeds.open({feed:${hl.feed_id}})" style="cursor : pointer" title="${App.escapeHtml(hl.feed_title)}">${Feeds.renderIcon(hl.feed_id, hl.has_icon)}</span>
</div>
</div>
`;
@@ -555,20 +573,74 @@ const Headlines = {
return tmp.firstChild;
},
updateCurrentUnread: function () {
- if ($("feed_current_unread")) {
+ if (App.byId("feed_current_unread")) {
const feed_unread = Feeds.getUnread(Feeds.getActive(), Feeds.activeIsCat());
if (feed_unread > 0 && !Element.visible("feeds-holder")) {
- $("feed_current_unread").innerText = feed_unread;
+ App.byId("feed_current_unread").innerText = feed_unread;
Element.show("feed_current_unread");
} else {
Element.hide("feed_current_unread");
}
}
},
- onLoaded: function (transport, offset, append) {
- const reply = App.handleRpcJson(transport);
+ renderToolbar: function(headlines) {
+
+ const tb = headlines['toolbar'];
+ const search_query = Feeds._search_query ? Feeds._search_query.query : "";
+ const target = dijit.byId('toolbar-headlines');
+
+ if (tb && typeof tb == 'object') {
+ target.attr('innerHTML',
+ `
+ <span class='left'>
+ <a href="#" title="${__("Show as feed")}"
+ onclick='CommonDialogs.generatedFeed("${headlines.id}", ${headlines.is_cat}, "${App.escapeHtml(search_query)}")'>
+ <i class='icon-syndicate material-icons'>rss_feed</i>
+ </a>
+ ${tb.site_url ?
+ `<a class="feed_title" target="_blank" href="${App.escapeHtml(tb.site_url)}" title="${tb.last_updated}">${tb.title}</a>` :
+ `<span class="feed_title">${tb.title}</span>`}
+ ${search_query ?
+ `
+ <span class='cancel_search'>(<a href='#' onclick='Feeds.cancelSearch()'>${__("Cancel search")}</a>)</span>
+ ` : ''}
+ ${tb.error ? `<i title="${App.escapeHtml(tb.error)}" class='material-icons icon-error'>error</i>` : ''}
+ <span id='feed_current_unread' style='display: none'></span>
+ </span>
+ <span class='right'>
+ <span id='selected_prompt'></span>
+ <div dojoType='fox.form.DropDownButton' title='"${__('Select articles')}'>
+ <span>${__("Select...")}</span>
+ <div dojoType='dijit.Menu' style='display: none;'>
+ <div dojoType='dijit.MenuItem' onclick='Headlines.select("all")'>${__('All')}</div>
+ <div dojoType='dijit.MenuItem' onclick='Headlines.select("unread")'>${__('Unread')}</div>
+ <div dojoType='dijit.MenuItem' onclick='Headlines.select("invert")'>${__('Invert')}</div>
+ <div dojoType='dijit.MenuItem' onclick='Headlines.select("none")'>${__('None')}</div>
+ <div dojoType='dijit.MenuSeparator'></div>
+ <div dojoType='dijit.MenuItem' onclick='Headlines.selectionToggleUnread()'>${__('Toggle unread')}</div>
+ <div dojoType='dijit.MenuItem' onclick='Headlines.selectionToggleMarked()'>${__('Toggle starred')}</div>
+ <div dojoType='dijit.MenuItem' onclick='Headlines.selectionTogglePublished()'>${__('Toggle published')}</div>
+ <div dojoType='dijit.MenuSeparator'></div>
+ <div dojoType='dijit.MenuItem' onclick='Headlines.catchupSelection()'>${__('Mark as read')}</div>
+ <div dojoType='dijit.MenuItem' onclick='Article.selectionSetScore()'>${__('Set score')}</div>
+ ${tb.plugin_menu_items}
+ ${headlines.id === 0 && !headlines.is_cat ?
+ `
+ <div dojoType='dijit.MenuSeparator'></div>
+ <div dojoType='dijit.MenuItem' class='text-error' onclick='Headlines.deleteSelection()'>${__('Delete permanently')}</div>
+ ` : ''}
+ </div>
+ ${tb.plugin_buttons}
+ </span>
+ `);
+ } else {
+ target.attr('innerHTML', '');
+ }
+ dojo.parser.parse(target.domNode);
+ },
+ onLoaded: function (reply, offset, append) {
console.log("Headlines.onLoaded: offset=", offset, "append=", append);
let is_cat = false;
@@ -597,15 +669,15 @@ const Headlines = {
// also called in renderAgain() after view mode switch
Headlines.setCommonClasses();
- $("headlines-frame").setAttribute("is-vfeed",
+ App.byId("headlines-frame").setAttribute("is-vfeed",
reply['headlines']['is_vfeed'] ? 1 : 0);
Article.setActive(0);
try {
- $("headlines-frame").removeClassName("smooth-scroll");
- $("headlines-frame").scrollTop = 0;
- $("headlines-frame").addClassName("smooth-scroll");
+ App.byId("headlines-frame").removeClassName("smooth-scroll");
+ App.byId("headlines-frame").scrollTop = 0;
+ App.byId("headlines-frame").addClassName("smooth-scroll");
} catch (e) {
console.warn(e);
}
@@ -613,25 +685,27 @@ const Headlines = {
this.headlines = [];
this.vgroup_last_feed = undefined;
- dojo.html.set($("toolbar-headlines"),
+ /*dojo.html.set(App.byId("toolbar-headlines"),
reply['headlines']['toolbar'],
- {parseContent: true});
+ {parseContent: true});*/
+
+ Headlines.renderToolbar(reply['headlines']);
if (typeof reply['headlines']['content'] == 'string') {
- $("headlines-frame").innerHTML = reply['headlines']['content'];
+ App.byId("headlines-frame").innerHTML = reply['headlines']['content'];
} else {
- $("headlines-frame").innerHTML = '';
+ App.byId("headlines-frame").innerHTML = '';
for (let i = 0; i < reply['headlines']['content'].length; i++) {
const hl = reply['headlines']['content'][i];
- $("headlines-frame").appendChild(this.render(reply['headlines'], hl));
+ App.byId("headlines-frame").appendChild(this.render(reply['headlines'], hl));
this.headlines[parseInt(hl.id)] = hl;
}
}
- let hsp = $("headlines-spacer");
+ let hsp = App.byId("headlines-spacer");
if (!hsp) {
hsp = document.createElement("div");
@@ -646,18 +720,19 @@ const Headlines = {
hsp.innerHTML = "<a href='#' onclick='Feeds.openNextUnread()'>" +
__("Click to open next unread feed.") + "</a>";
+ /*
if (Feeds._search_query) {
- $("feed_title").innerHTML += "<span id='cancel_search'>" +
+ App.byId("feed_title").innerHTML += "<span id='cancel_search'>" +
" (<a href='#' onclick='Feeds.cancelSearch()'>" + __("Cancel search") + "</a>)" +
"</span>";
- }
+ } */
Headlines.updateCurrentUnread();
} else if (headlines_count > 0 && feed_id == Feeds.getActive() && is_cat == Feeds.activeIsCat()) {
const c = dijit.byId("headlines-frame");
- let hsp = $("headlines-spacer");
+ let hsp = App.byId("headlines-spacer");
if (hsp)
c.domNode.removeChild(hsp);
@@ -665,13 +740,13 @@ const Headlines = {
let headlines_appended = 0;
if (typeof reply['headlines']['content'] == 'string') {
- $("headlines-frame").innerHTML = reply['headlines']['content'];
+ App.byId("headlines-frame").innerHTML = reply['headlines']['content'];
} else {
for (let i = 0; i < reply['headlines']['content'].length; i++) {
const hl = reply['headlines']['content'][i];
if (!this.headlines[parseInt(hl.id)]) {
- $("headlines-frame").appendChild(this.render(reply['headlines'], hl));
+ App.byId("headlines-frame").appendChild(this.render(reply['headlines'], hl));
this.headlines[parseInt(hl.id)] = hl;
++headlines_appended;
@@ -703,7 +778,7 @@ const Headlines = {
console.log("no headlines received, infscroll_disabled=", Feeds.infscroll_disabled, 'first_id_changed=', first_id_changed);
- const hsp = $("headlines-spacer");
+ const hsp = App.byId("headlines-spacer");
if (hsp) {
if (first_id_changed) {
@@ -716,17 +791,16 @@ const Headlines = {
}
}
- $$(".cdm .header-sticky-guard").each((e) => {
+ App.findAll(".cdm .header-sticky-guard").forEach((e) => {
this.sticky_header_observer.observe(e)
});
if (App.getInitParam("cdm_expanded"))
- $$("#headlines-frame > div[id*=RROW].cdm").each((e) => {
+ App.findAll("#headlines-frame > div[id*=RROW].cdm").forEach((e) => {
this.unpack_observer.observe(e)
});
} else {
- console.error("Invalid object received: " + transport.responseText);
dijit.byId("headlines-frame").attr('content', "<div class='whiteBox'>" +
__('Could not update headlines (invalid object received - see error console for details)') +
"</div>");
@@ -755,9 +829,7 @@ const Headlines = {
Feeds.reloadCurrent();
},
- selectionToggleUnread: function (params) {
- params = params || {};
-
+ selectionToggleUnread: function (params = {}) {
const cmode = params.cmode != undefined ? params.cmode : 2;
const no_error = params.no_error || false;
const ids = params.ids || Headlines.getSelected();
@@ -769,8 +841,8 @@ const Headlines = {
return;
}
- ids.each((id) => {
- const row = $("RROW-" + id);
+ ids.forEach((id) => {
+ const row = App.byId(`RROW-${id}`);
if (row) {
switch (cmode) {
@@ -794,7 +866,7 @@ const Headlines = {
return;
}
- ids.each((id) => {
+ ids.forEach((id) => {
this.toggleMark(id);
});
},
@@ -806,26 +878,24 @@ const Headlines = {
return;
}
- ids.each((id) => {
+ ids.forEach((id) => {
this.togglePub(id);
});
},
toggleMark: function (id) {
- const row = $("RROW-" + id);
+ const row = App.byId(`RROW-${id}`);
if (row)
row.toggleClassName("marked");
},
togglePub: function (id) {
- const row = $("RROW-" + id);
+ const row = App.byId(`RROW-${id}`);
if (row)
row.toggleClassName("published");
},
- move: function (mode, params) {
- params = params || {};
-
+ move: function (mode, params = {}) {
const no_expand = params.no_expand || false;
const force_previous = params.force_previous || this.default_force_previous;
const force_to_top = params.force_to_top || this.default_force_to_top;
@@ -834,7 +904,7 @@ const Headlines = {
let next_id = false;
let current_id = Article.getActive();
- if (!Headlines.isChildVisible($("RROW-" + current_id))) {
+ if (!Headlines.isChildVisible(App.byId(`RROW-${current_id}`))) {
console.log('active article is obscured, resetting to first visible...');
current_id = Headlines.firstVisible();
prev_id = current_id;
@@ -871,13 +941,30 @@ const Headlines = {
} else {
Article.view(next_id, no_expand);
}
+ } else if (App.isCombinedMode()) {
+ // try to show hsp if no next article exists, in case there's useful information like first_id_changed etc
+ const row = App.byId(`RROW-${current_id}`);
+ const ctr = App.byId("headlines-frame");
+
+ if (row) {
+ const next = row.nextSibling;
+
+ // hsp has half-screen height in auto catchup mode therefore we use its first child (normally A element)
+ if (next && Element.visible(next) && next.id == "headlines-spacer" && next.firstChild) {
+ const offset = App.byId("headlines-spacer").offsetTop - App.byId("headlines-frame").offsetHeight + next.firstChild.offsetHeight;
+
+ // don't jump back either
+ if (ctr.scrollTop < offset)
+ ctr.scrollTop = offset;
+ }
+ }
}
} else if (mode === "prev") {
if (prev_id || current_id) {
if (App.isCombinedMode()) {
window.requestAnimationFrame(() => {
- const row = $("RROW-" + current_id);
- const ctr = $("headlines-frame");
+ const row = App.byId(`RROW-${current_id}`);
+ const ctr = App.byId("headlines-frame");
const delta_px = Math.round(row.offsetTop) - Math.round(ctr.scrollTop);
console.log('moving back, delta_px', delta_px);
@@ -898,7 +985,7 @@ const Headlines = {
},
updateSelectedPrompt: function () {
const count = Headlines.getSelected().length;
- const elem = $("selected_prompt");
+ const elem = App.byId("selected_prompt");
if (elem) {
elem.innerHTML = ngettext("%d article selected",
@@ -908,7 +995,7 @@ const Headlines = {
}
},
toggleUnread: function (id, cmode) {
- const row = $("RROW-" + id);
+ const row = App.byId(`RROW-${id}`);
if (row) {
if (typeof cmode == "undefined") cmode = 2;
@@ -939,9 +1026,8 @@ const Headlines = {
ids: ids.toString(), lid: id
};
- xhrPost("backend.php", query, (transport) => {
- App.handleRpcJson(transport);
- this.onLabelsUpdated(transport);
+ xhr.json("backend.php", query, (reply) => {
+ this.onLabelsUpdated(reply);
});
},
selectionAssignLabel: function (id, ids) {
@@ -957,9 +1043,8 @@ const Headlines = {
ids: ids.toString(), lid: id
};
- xhrPost("backend.php", query, (transport) => {
- App.handleRpcJson(transport);
- this.onLabelsUpdated(transport);
+ xhr.json("backend.php", query, (reply) => {
+ this.onLabelsUpdated(reply);
});
},
deleteSelection: function () {
@@ -988,15 +1073,14 @@ const Headlines = {
const query = {op: "rpc", method: "delete", ids: rows.toString()};
- xhrPost("backend.php", query, (transport) => {
- App.handleRpcJson(transport);
+ xhr.json("backend.php", query, () => {
Feeds.reloadCurrent();
});
},
getSelected: function () {
const rv = [];
- $$("#headlines-frame > div[id*=RROW][class*=Selected]").each(
+ App.findAll("#headlines-frame > div[id*=RROW][class*=Selected]").forEach(
function (child) {
rv.push(child.getAttribute("data-article-id"));
});
@@ -1010,9 +1094,9 @@ const Headlines = {
getLoaded: function () {
const rv = [];
- const children = $$("#headlines-frame > div[id*=RROW-]");
+ const children = App.findAll("#headlines-frame > div[id*=RROW-]");
- children.each(function (child) {
+ children.forEach(function (child) {
if (Element.visible(child)) {
rv.push(child.getAttribute("data-article-id"));
}
@@ -1021,7 +1105,7 @@ const Headlines = {
return rv;
},
onRowChecked: function (elem) {
- const row = elem.domNode.up("div[id*=RROW]");
+ const row = elem.domNode.closest("div[id*=RROW]");
// do not allow unchecking active article checkbox
if (row.hasClassName("active")) {
@@ -1039,7 +1123,7 @@ const Headlines = {
if (start == stop)
return [start];
- const rows = $$("#headlines-frame > div[id*=RROW]");
+ const rows = App.findAll("#headlines-frame > div[id*=RROW]");
const results = [];
let collecting = false;
@@ -1066,7 +1150,7 @@ const Headlines = {
// mode = all,none,unread,invert,marked,published
let query = "#headlines-frame > div[id*=RROW]";
- if (articleId) query += "[data-article-id=" + articleId + "]";
+ if (articleId) query += `[data-article-id="${articleId}"]`;
switch (mode) {
case "none":
@@ -1086,10 +1170,7 @@ const Headlines = {
console.warn("select: unknown mode", mode);
}
- const rows = $$(query);
-
- for (let i = 0; i < rows.length; i++) {
- const row = rows[i];
+ App.findAll(query).forEach((row) => {
switch (mode) {
case "none":
@@ -1101,7 +1182,7 @@ const Headlines = {
default:
row.addClassName("Selected");
}
- }
+ });
},
catchupSelection: function () {
const rows = Headlines.getSelected();
@@ -1140,7 +1221,7 @@ const Headlines = {
if (!below) {
for (let i = 0; i < visible_ids.length; i++) {
if (visible_ids[i] != id) {
- const e = $("RROW-" + visible_ids[i]);
+ const e = App.byId(`RROW-${visible_ids[i]}`);
if (e && e.hasClassName("Unread")) {
ids_to_mark.push(visible_ids[i]);
@@ -1152,7 +1233,7 @@ const Headlines = {
} else {
for (let i = visible_ids.length - 1; i >= 0; i--) {
if (visible_ids[i] != id) {
- const e = $("RROW-" + visible_ids[i]);
+ const e = App.byId(`RROW-${visible_ids[i]}`);
if (e && e.hasClassName("Unread")) {
ids_to_mark.push(visible_ids[i]);
@@ -1171,26 +1252,40 @@ const Headlines = {
if (App.getInitParam("confirm_feed_catchup") != 1 || confirm(msg)) {
for (let i = 0; i < ids_to_mark.length; i++) {
- const e = $("RROW-" + ids_to_mark[i]);
+ const e = App.byId(`RROW-${ids_to_mark[i]}`);
e.removeClassName("Unread");
}
}
}
},
- onLabelsUpdated: function (transport) {
- const data = JSON.parse(transport.responseText);
+ onTagsUpdated: function (data) {
+ if (data) {
+ if (this.headlines[data.id]) {
+ this.headlines[data.id].tags = data.tags;
+ }
+ App.findAll(`span[data-tags-for="${data.id}"`).forEach((ctr) => {
+ ctr.innerHTML = Article.renderTags(data.id, data.tags);
+ });
+ }
+ },
+ // TODO: maybe this should cause article to be rendered again, although it might cause flicker etc
+ onLabelsUpdated: function (data) {
if (data) {
- data['info-for-headlines'].each(function (elem) {
- $$(".HLLCTR-" + elem.id).each(function (ctr) {
- ctr.innerHTML = elem.labels;
+ data["labels-for"].forEach((row) => {
+ if (this.headlines[row.id]) {
+ this.headlines[row.id].labels = row.labels;
+ }
+
+ App.findAll(`span[data-labels-for="${row.id}"]`).forEach((ctr) => {
+ ctr.innerHTML = Article.renderLabels(row.id, row.labels);
});
});
}
},
scrollToArticleId: function (id) {
- const container = $("headlines-frame");
- const row = $("RROW-" + id);
+ const container = App.byId("headlines-frame");
+ const row = App.byId(`RROW-${id}`);
if (!container || !row) return;
@@ -1289,7 +1384,7 @@ const Headlines = {
const labelAddMenu = new dijit.Menu({ownerMenu: menu});
const labelDelMenu = new dijit.Menu({ownerMenu: menu});
- labels.each(function (label) {
+ labels.forEach(function (label) {
const bare_id = label.id;
const name = label.caption;
@@ -1337,10 +1432,10 @@ const Headlines = {
}
},
scrollByPages: function (page_offset) {
- App.Scrollable.scrollByPages($("headlines-frame"), page_offset);
+ App.Scrollable.scrollByPages(App.byId("headlines-frame"), page_offset);
},
scroll: function (offset) {
- App.Scrollable.scroll($("headlines-frame"), offset);
+ App.Scrollable.scroll(App.byId("headlines-frame"), offset);
},
initHeadlinesMenu: function () {
if (!dijit.byId("headlinesMenu")) {