summaryrefslogtreecommitdiff
path: root/js/Headlines.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/Headlines.js')
-rwxr-xr-xjs/Headlines.js108
1 files changed, 79 insertions, 29 deletions
diff --git a/js/Headlines.js b/js/Headlines.js
index 28e43be1f..d01993838 100755
--- a/js/Headlines.js
+++ b/js/Headlines.js
@@ -17,17 +17,27 @@ const Headlines = {
sticky_header_observer: new IntersectionObserver(
(entries, observer) => {
entries.forEach((entry) => {
- const header = entry.target.nextElementSibling;
+ const header = entry.target.closest('.cdm').querySelector(".header");
- if (entry.intersectionRatio == 0) {
- header.setAttribute("stuck", "1");
-
- } else if (entry.intersectionRatio == 1) {
- header.removeAttribute("stuck");
+ if (entry.isIntersecting) {
+ header.removeAttribute("data-is-stuck");
+ } else {
+ header.setAttribute("data-is-stuck", "true");
}
- //console.log(entry.target, header, entry.intersectionRatio);
+ //console.log(entry.target, entry.intersectionRatio, entry.isIntersecting, entry.boundingClientRect.top);
+ });
+ },
+ {threshold: [0, 1], root: document.querySelector("#headlines-frame")}
+ ),
+ sticky_content_observer: new IntersectionObserver(
+ (entries, observer) => {
+ entries.forEach((entry) => {
+ const header = entry.target.closest('.cdm').querySelector(".header");
+
+ header.style.position = entry.isIntersecting ? "sticky" : "unset";
+ //console.log(entry.target, entry.intersectionRatio, entry.isIntersecting, entry.boundingClientRect.top);
});
},
{threshold: [0, 1], root: document.querySelector("#headlines-frame")}
@@ -72,14 +82,13 @@ const Headlines = {
}
});
+ PluginHost.run(PluginHost.HOOK_HEADLINE_MUTATIONS, mutations);
+
Headlines.updateSelectedPrompt();
- if ('requestIdleCallback' in window)
- window.requestIdleCallback(() => {
- Headlines.syncModified(modified);
- });
- else
+ window.requestIdleCallback(() => {
Headlines.syncModified(modified);
+ });
}),
syncModified: function (modified) {
const ops = {
@@ -173,14 +182,14 @@ const Headlines = {
});
}
- Promise.all(promises).then((results) => {
+ Promise.allSettled(promises).then((results) => {
let feeds = [];
let labels = [];
results.forEach((res) => {
if (res) {
try {
- const obj = JSON.parse(res);
+ const obj = JSON.parse(res.value);
if (obj.feeds)
feeds = feeds.concat(obj.feeds);
@@ -198,6 +207,8 @@ const Headlines = {
console.log('requesting counters for', feeds, labels);
Feeds.requestCounters(feeds, labels);
}
+
+ PluginHost.run(PluginHost.HOOK_HEADLINE_MUTATIONS_SYNCED, results);
});
},
click: function (event, id, in_body) {
@@ -340,8 +351,7 @@ const Headlines = {
// invoke lazy load if last article in buffer is nearly visible OR is active
if (Article.getActive() == last_row.getAttribute("data-article-id") || last_row.offsetTop - 250 <= container.scrollTop + container.offsetHeight) {
- hsp.innerHTML = "<span class='loading'><img src='images/indicator_tiny.gif'> " +
- __("Loading, please wait...") + "</span>";
+ hsp.innerHTML = `<span class='text-muted text-small text-center'><img class="icon-three-dots" src="${App.getInitParam('icon_three_dots')}"> ${__("Loading, please wait...")}</span>`;
Headlines.loadMore();
return;
@@ -371,6 +381,9 @@ const Headlines = {
}
}
}
+
+ PluginHost.run(PluginHost.HOOK_HEADLINES_SCROLL_HANDLER);
+
} catch (e) {
console.warn("scrollHandler", e);
}
@@ -378,11 +391,17 @@ const Headlines = {
objectById: function (id) {
return this.headlines[id];
},
- setCommonClasses: function () {
- App.byId("headlines-frame").removeClassName("cdm");
- App.byId("headlines-frame").removeClassName("normal");
+ setCommonClasses: function (headlines_count) {
+ const container = App.byId("headlines-frame");
+
+ container.removeClassName("cdm");
+ container.removeClassName("normal");
- App.byId("headlines-frame").addClassName(App.isCombinedMode() ? "cdm" : "normal");
+ container.addClassName(App.isCombinedMode() ? "cdm" : "normal");
+ container.setAttribute("data-enable-grid", App.getInitParam("cdm_enable_grid") ? "true" : "false");
+ container.setAttribute("data-headlines-count", parseInt(headlines_count));
+ container.setAttribute("data-is-cdm", App.isCombinedMode() ? "true" : "false");
+ container.setAttribute("data-is-cdm-expanded", App.getInitParam("cdm_expanded"));
// for floating title because it's placed outside of headlines-frame
App.byId("main").removeClassName("expandable");
@@ -393,7 +412,7 @@ const Headlines = {
},
renderAgain: function () {
// TODO: wrap headline elements into a knockoutjs model to prevent all this stuff
- Headlines.setCommonClasses();
+ Headlines.setCommonClasses(this.headlines.filter((h) => h.id).length);
App.findAll("#headlines-frame > div[id*=RROW]").forEach((row) => {
const id = row.getAttribute("data-article-id");
@@ -422,11 +441,18 @@ const Headlines = {
this.sticky_header_observer.observe(e)
});
+ App.findAll(".cdm .content").forEach((e) => {
+ this.sticky_content_observer.observe(e)
+ });
+
if (App.getInitParam("cdm_expanded"))
App.findAll("#headlines-frame > div[id*=RROW].cdm").forEach((e) => {
this.unpack_observer.observe(e)
});
+ dijit.byId('main').resize();
+
+ PluginHost.run(PluginHost.HOOK_HEADLINES_RENDERED);
},
render: function (headlines, hl) {
let row = null;
@@ -464,7 +490,9 @@ const Headlines = {
id="RROW-${hl.id}"
data-article-id="${hl.id}"
data-orig-feed-id="${hl.feed_id}"
+ data-is-packed="1"
data-content="${App.escapeHtml(hl.content)}"
+ data-rendered-enclosures="${App.escapeHtml(Article.renderEnclosures(hl.enclosures))}"
data-score="${hl.score}"
data-article-title="${App.escapeHtml(hl.title)}"
onmouseover="Article.mouseIn(${hl.id})"
@@ -494,9 +522,10 @@ const Headlines = {
<span class="updated" title="${hl.imported}">${hl.updated}</span>
<div class="right">
+ <i class="material-icons icon-grid-span" title="${__("Span all columns")}" onclick="Article.cdmToggleGridSpan(${hl.id})">fullscreen</i>
<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}})">
+ <span class="icon-feed" title="${App.escapeHtml(hl.feed_title)}" onclick="Feeds.open({feed:${hl.feed_id}})">
${Feeds.renderIcon(hl.feed_id, hl.has_icon)}
</span>
</div>
@@ -506,11 +535,14 @@ const Headlines = {
<div class="content" onclick="return Headlines.click(event, ${hl.id}, true);">
${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">
- ${Article.renderEnclosures(hl.enclosures)}
+ <div class="text-center text-muted">
+ ${__("Loading, please wait...")}
+ </div>
</div>
+
+ <!-- intermediate: unstyled, kept for compatibility -->
+ <div class="intermediate"></div>
+
<div class="footer" onclick="event.stopPropagation()">
<div class="left">
@@ -560,7 +592,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)}">${Feeds.renderIcon(hl.feed_id, hl.has_icon)}</span>
+ <span onclick="Feeds.open({feed:${hl.feed_id}})" class="icon-feed" title="${App.escapeHtml(hl.feed_title)}">${Feeds.renderIcon(hl.feed_id, hl.has_icon)}</span>
</div>
</div>
`;
@@ -614,7 +646,7 @@ const Headlines = {
</span>
<span class='right'>
<span id='selected_prompt'></span>
- <div dojoType='fox.form.DropDownButton' title='"${__('Select articles')}'>
+ <div class='select-articles-dropdown' 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>
@@ -671,11 +703,15 @@ const Headlines = {
console.log('infscroll_disabled=', Feeds.infscroll_disabled);
// also called in renderAgain() after view mode switch
- Headlines.setCommonClasses();
+ Headlines.setCommonClasses(headlines_count);
+ /** TODO: remove @deprecated */
App.byId("headlines-frame").setAttribute("is-vfeed",
reply['headlines']['is_vfeed'] ? 1 : 0);
+ App.byId("headlines-frame").setAttribute("data-is-vfeed",
+ reply['headlines']['is_vfeed'] ? "true" : "false");
+
Article.setActive(0);
try {
@@ -716,6 +752,9 @@ const Headlines = {
hsp.id = "headlines-spacer";
}
+ // clear out hsp contents in case there's a power-hungry svg icon rotating there
+ hsp.innerHTML = "";
+
dijit.byId('headlines-frame').domNode.appendChild(hsp);
this.initHeadlinesMenu();
@@ -767,6 +806,9 @@ const Headlines = {
hsp.id = "headlines-spacer";
}
+ // clear out hsp contents in case there's a power-hungry svg icon rotating there
+ hsp.innerHTML = "";
+
c.domNode.appendChild(hsp);
this.initHeadlinesMenu();
@@ -799,6 +841,10 @@ const Headlines = {
this.sticky_header_observer.observe(e)
});
+ App.findAll(".cdm .content").forEach((e) => {
+ this.sticky_content_observer.observe(e)
+ });
+
if (App.getInitParam("cdm_expanded"))
App.findAll("#headlines-frame > div[id*=RROW].cdm").forEach((e) => {
this.unpack_observer.observe(e)
@@ -816,6 +862,10 @@ const Headlines = {
// unpack visible articles, fill buffer more, etc
this.scrollHandler();
+ dijit.byId('main').resize();
+
+ PluginHost.run(PluginHost.HOOK_HEADLINES_RENDERED);
+
Notify.close();
},
reverse: function () {