summaryrefslogtreecommitdiff
path: root/js/Article.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/Article.js')
-rw-r--r--js/Article.js527
1 files changed, 263 insertions, 264 deletions
diff --git a/js/Article.js b/js/Article.js
index 50447c2a1..76637cd69 100644
--- a/js/Article.js
+++ b/js/Article.js
@@ -1,243 +1,272 @@
'use strict'
-/* global __, ngettext */
-define(["dojo/_base/declare"], function (declare) {
- Article = {
- _scroll_reset_timeout: false,
- getScoreClass: function (score) {
- if (score > 500) {
- return "score-high";
- } else if (score > 0) {
- return "score-half-high";
- } else if (score < -100) {
- return "score-low";
- } else if (score < 0) {
- return "score-half-low";
- } else {
- return "score-neutral";
- }
- },
- getScorePic: function (score) {
- if (score > 500) {
- return "trending_up";
- } else if (score > 0) {
- return "trending_up";
- } else if (score < 0) {
- return "trending_down";
- } else {
- return "trending_neutral";
- }
- },
- selectionSetScore: function () {
- const ids = Headlines.getSelected();
- if (ids.length > 0) {
- const score = prompt(__("Please enter new score for selected articles:"));
+/* global __, ngettext, App, Headlines, xhrPost, xhrJson, dojo, dijit, PluginHost, Notify, $$, Ajax */
+
+const Article = {
+ _scroll_reset_timeout: false,
+ getScoreClass: function (score) {
+ if (score > 500) {
+ return "score-high";
+ } else if (score > 0) {
+ return "score-half-high";
+ } else if (score < -100) {
+ return "score-low";
+ } else if (score < 0) {
+ return "score-half-low";
+ } else {
+ return "score-neutral";
+ }
+ },
+ getScorePic: function (score) {
+ if (score > 500) {
+ return "trending_up";
+ } else if (score > 0) {
+ return "trending_up";
+ } else if (score < 0) {
+ return "trending_down";
+ } else {
+ return "trending_neutral";
+ }
+ },
+ selectionSetScore: function () {
+ const ids = Headlines.getSelected();
- if (!isNaN(parseInt(score))) {
- ids.each((id) => {
- const row = $("RROW-" + id);
+ if (ids.length > 0) {
+ const score = prompt(__("Please enter new score for selected articles:"));
- if (row) {
- row.setAttribute("data-score", score);
+ if (!isNaN(parseInt(score))) {
+ ids.each((id) => {
+ const row = $("RROW-" + id);
- const pic = row.select(".icon-score")[0];
+ if (row) {
+ row.setAttribute("data-score", score);
- pic.innerHTML = Article.getScorePic(score);
- pic.setAttribute("title", score);
+ const pic = row.select(".icon-score")[0];
- ["score-low", "score-high", "score-half-low", "score-half-high", "score-neutral"]
- .each(function(scl) {
- if (row.hasClassName(scl))
- row.removeClassName(scl);
- });
+ pic.innerHTML = Article.getScorePic(score);
+ pic.setAttribute("title", score);
- row.addClassName(Article.getScoreClass(score));
- }
- });
- }
+ ["score-low", "score-high", "score-half-low", "score-half-high", "score-neutral"]
+ .each(function(scl) {
+ if (row.hasClassName(scl))
+ row.removeClassName(scl);
+ });
- } else {
- alert(__("No articles selected."));
+ row.addClassName(Article.getScoreClass(score));
+ }
+ });
}
- },
- setScore: function (id, pic) {
- const row = pic.up("div[id*=RROW]");
- if (row) {
- const score_old = row.getAttribute("data-score");
- const score = prompt(__("Please enter new score for this article:"), score_old);
-
- if (!isNaN(parseInt(score))) {
- row.setAttribute("data-score", score);
+ } else {
+ alert(__("No articles selected."));
+ }
+ },
+ setScore: function (id, pic) {
+ const row = pic.up("div[id*=RROW]");
- const pic = row.select(".icon-score")[0];
+ if (row) {
+ const score_old = row.getAttribute("data-score");
+ const score = prompt(__("Please enter new score for this article:"), score_old);
- pic.innerHTML = Article.getScorePic(score);
- pic.setAttribute("title", score);
+ if (!isNaN(parseInt(score))) {
+ row.setAttribute("data-score", score);
- ["score-low", "score-high", "score-half-low", "score-half-high", "score-neutral"]
- .each(function(scl) {
- if (row.hasClassName(scl))
- row.removeClassName(scl);
- });
+ const pic = row.select(".icon-score")[0];
- row.addClassName(Article.getScoreClass(score));
- }
- }
- },
- cdmUnsetActive: function (event) {
- const row = $("RROW-" + Article.getActive());
+ pic.innerHTML = Article.getScorePic(score);
+ pic.setAttribute("title", score);
- if (row) {
- row.removeClassName("active");
-
- if (event)
- event.stopPropagation();
+ ["score-low", "score-high", "score-half-low", "score-half-high", "score-neutral"]
+ .each(function(scl) {
+ if (row.hasClassName(scl))
+ row.removeClassName(scl);
+ });
- return false;
+ row.addClassName(Article.getScoreClass(score));
}
- },
- close: function () {
- if (dijit.byId("content-insert"))
- dijit.byId("headlines-wrap-inner").removeChild(
- dijit.byId("content-insert"));
-
- Article.setActive(0);
- },
- displayUrl: function (id) {
- const query = {op: "rpc", method: "getlinktitlebyid", id: id};
-
- xhrJson("backend.php", query, (reply) => {
- if (reply && reply.link) {
- prompt(__("Article URL:"), reply.link);
- }
- });
- },
- openInNewWindow: function (id) {
- const w = window.open("");
+ }
+ },
+ popupOpenUrl: function(url) {
+ const w = window.open("");
+
+ w.opener = null;
+ w.location = url;
+ },
+ /* popupOpenArticle: function(id) {
+ const w = window.open("",
+ "ttrss_article_popup",
+ "height=900,width=900,resizable=yes,status=no,location=no,menubar=no,directories=no,scrollbars=yes,toolbar=no");
+
+ if (w) {
+ w.opener = null;
+ w.location = "backend.php?op=article&method=view&mode=raw&html=1&zoom=1&id=" + id + "&csrf_token=" + App.getInitParam("csrf_token");
+ }
+ }, */
+ cdmUnsetActive: function (event) {
+ const row = $("RROW-" + Article.getActive());
- if (w) {
- w.opener = null;
- w.location = "backend.php?op=article&method=redirect&id=" + id;
+ if (row) {
+ row.removeClassName("active");
- Headlines.toggleUnread(id, 0);
- }
- },
- render: function (article) {
- App.cleanupMemory("content-insert");
+ if (event)
+ event.stopPropagation();
- dijit.byId("headlines-wrap-inner").addChild(
+ return false;
+ }
+ },
+ close: function () {
+ if (dijit.byId("content-insert"))
+ dijit.byId("headlines-wrap-inner").removeChild(
dijit.byId("content-insert"));
- const c = dijit.byId("content-insert");
+ Article.setActive(0);
+ },
+ displayUrl: function (id) {
+ const query = {op: "rpc", method: "getlinktitlebyid", id: id};
- try {
- c.domNode.scrollTop = 0;
- } catch (e) {
+ xhrJson("backend.php", query, (reply) => {
+ if (reply && reply.link) {
+ prompt(__("Article URL:"), reply.link);
}
+ });
+ },
+ openInNewWindow: function (id) {
+ /* global __csrf_token */
+ App.postOpenWindow("backend.php",
+ { "op": "article", "method": "redirect", "id": id, "csrf_token": __csrf_token });
+
+ Headlines.toggleUnread(id, 0);
+ },
+ render: function (article) {
+ App.cleanupMemory("content-insert");
+
+ dijit.byId("headlines-wrap-inner").addChild(
+ dijit.byId("content-insert"));
+
+ const c = dijit.byId("content-insert");
+
+ try {
+ c.domNode.scrollTop = 0;
+ } catch (e) {
+ }
- c.attr('content', article);
- PluginHost.run(PluginHost.HOOK_ARTICLE_RENDERED, c.domNode);
-
- Headlines.correctHeadlinesOffset(Article.getActive());
+ c.attr('content', article);
+ PluginHost.run(PluginHost.HOOK_ARTICLE_RENDERED, c.domNode);
- try {
- c.focus();
- } catch (e) {
- }
- },
- formatComments: function(hl) {
- let comments = "";
+ //Headlines.correctHeadlinesOffset(Article.getActive());
- if (hl.comments) {
- let comments_msg = __("comments");
+ try {
+ c.focus();
+ } catch (e) {
+ }
+ },
+ formatComments: function(hl) {
+ let comments = "";
- if (hl.num_comments > 0) {
- comments_msg = hl.num_comments + " " + ngettext("comment", "comments", hl.num_comments)
- }
+ if (hl.comments || hl.num_comments > 0) {
+ let comments_msg = __("comments");
- comments = `<a href="${escapeHtml(hl.comments)}">(${comments_msg})</a>`;
+ if (hl.num_comments > 0) {
+ comments_msg = hl.num_comments + " " + ngettext("comment", "comments", hl.num_comments)
}
- return comments;
- },
- formatOriginallyFrom: function(hl) {
- return hl.orig_feed ? `<span>
- ${__('Originally from:')} <a target="_blank" rel="noopener noreferrer" href="${escapeHtml(hl.orig_feed[1])}">${hl.orig_feed[0]}</a>
- </span>` : "";
- },
- unpack: function(row) {
- if (row.hasAttribute("data-content")) {
- console.log("unpacking: " + row.id);
+ comments = `<a target="_blank" rel="noopener noreferrer" href="${App.escapeHtml(hl.comments ? hl.comments : hl.link)}">(${comments_msg})</a>`;
+ }
- const container = row.querySelector(".content-inner");
+ return comments;
+ },
+ formatOriginallyFrom: function(hl) {
+ return hl.orig_feed ? `<span>
+ ${__('Originally from:')} <a target="_blank" rel="noopener noreferrer" href="${App.escapeHtml(hl.orig_feed[1])}">${hl.orig_feed[0]}</a>
+ </span>` : "";
+ },
+ unpack: function(row) {
+ if (row.hasAttribute("data-content")) {
+ console.log("unpacking: " + row.id);
- container.innerHTML = row.getAttribute("data-content").trim();
+ const container = row.querySelector(".content-inner");
- // blank content element might screw up onclick selection and keyboard moving
- if (container.textContent.length == 0)
- container.innerHTML += "&nbsp;";
+ container.innerHTML = row.getAttribute("data-content").trim();
- row.removeAttribute("data-content");
+ // blank content element might screw up onclick selection and keyboard moving
+ if (container.textContent.length == 0)
+ container.innerHTML += "&nbsp;";
- PluginHost.run(PluginHost.HOOK_ARTICLE_RENDERED_CDM, row);
- }
- },
- view: function (id, noexpand) {
- this.setActive(id);
-
- if (!noexpand) {
- const hl = Headlines.objectById(id);
-
- if (hl) {
-
- const comments = this.formatComments(hl);
- const originally_from = this.formatOriginallyFrom(hl);
-
- const article = `<div class="post post-${hl.id}" data-article-id="${hl.id}">
- <div class="header">
- <div class="row">
- <div class="title"><a target="_blank" rel="noopener noreferrer"
- title="${escapeHtml(hl.title)}"
- href="${escapeHtml(hl.link)}">${hl.title}</a></div>
- <div class="date">${hl.updated_long}</div>
- </div>
- <div class="row">
- <div class="buttons left">${hl.buttons_left}</div>
- <div class="comments">${comments}</div>
- <div class="author">${hl.author}</div>
- <i class="material-icons">label_outline</i>
- <span id="ATSTR-${hl.id}">${hl.tags_str}</span>
- &nbsp;<a title="${__("Edit tags for this article")}" href="#"
- onclick="Article.editTags(${hl.id})">(+)</a>
- <div class="buttons right">${hl.buttons}</div>
- </div>
+ // in expandable mode, save content for later, so that we can pack unfocused rows back
+ if (App.isCombinedMode() && $("main").hasClassName("expandable"))
+ row.setAttribute("data-content-original", row.getAttribute("data-content"));
+
+ row.removeAttribute("data-content");
+
+ PluginHost.run(PluginHost.HOOK_ARTICLE_RENDERED_CDM, row);
+ }
+ },
+ pack: function(row) {
+ if (row.hasAttribute("data-content-original")) {
+ console.log("packing", row.id);
+ row.setAttribute("data-content", row.getAttribute("data-content-original"));
+ row.removeAttribute("data-content-original");
+
+ row.querySelector(".content-inner").innerHTML = "&nbsp;";
+ }
+ },
+ view: function (id, no_expand) {
+ this.setActive(id);
+ Headlines.scrollToArticleId(id);
+
+ if (!no_expand) {
+ const hl = Headlines.objectById(id);
+
+ if (hl) {
+
+ const comments = this.formatComments(hl);
+ const originally_from = this.formatOriginallyFrom(hl);
+
+ const article = `<div class="post post-${hl.id}" data-article-id="${hl.id}">
+ <div class="header">
+ <div class="row">
+ <div class="title"><a target="_blank" rel="noopener noreferrer"
+ title="${App.escapeHtml(hl.title)}"
+ href="${App.escapeHtml(hl.link)}">${hl.title}</a></div>
+ <div class="date">${hl.updated_long}</div>
</div>
- <div id="POSTNOTE-${hl.id}">${hl.note}</div>
- <div class="content" lang="${hl.lang ? hl.lang : 'en'}">
- ${originally_from}
- ${hl.content}
- ${hl.enclosures}
+ <div class="row">
+ <div class="buttons left">${hl.buttons_left}</div>
+ <div class="comments">${comments}</div>
+ <div class="author">${hl.author}</div>
+ <i class="material-icons">label_outline</i>
+ <span id="ATSTR-${hl.id}">${hl.tags_str}</span>
+ &nbsp;<a title="${__("Edit tags for this article")}" href="#"
+ onclick="Article.editTags(${hl.id})">(+)</a>
+ <div class="buttons right">${hl.buttons}</div>
</div>
- </div>`;
+ </div>
+ <div id="POSTNOTE-${hl.id}">${hl.note}</div>
+ <div class="content" lang="${hl.lang ? hl.lang : 'en'}">
+ ${originally_from}
+ ${hl.content}
+ ${hl.enclosures}
+ </div>
+ </div>`;
- Headlines.toggleUnread(id, 0);
- this.render(article);
- }
+ Headlines.toggleUnread(id, 0);
+ this.render(article);
}
+ }
- return false;
- },
- editTags: function (id) {
- const query = "backend.php?op=article&method=editArticleTags&param=" + encodeURIComponent(id);
+ return false;
+ },
+ editTags: function (id) {
+ if (dijit.byId("editTagsDlg"))
+ dijit.byId("editTagsDlg").destroyRecursive();
- if (dijit.byId("editTagsDlg"))
- dijit.byId("editTagsDlg").destroyRecursive();
+ xhrPost("backend.php", {op: "article", method: "editarticletags", param: id}, (transport) => {
const dialog = new dijit.Dialog({
id: "editTagsDlg",
title: __("Edit article Tags"),
style: "width: 600px",
+ content: transport.responseText,
execute: function () {
if (this.validate()) {
Notify.progress("Saving article tags...", true);
@@ -264,7 +293,6 @@ define(["dojo/_base/declare"], function (declare) {
});
}
},
- href: query
});
const tmph = dojo.connect(dialog, 'onLoad', function () {
@@ -276,39 +304,31 @@ define(["dojo/_base/declare"], function (declare) {
});
dialog.show();
- },
- cdmScrollToId: function (id, force, event) {
- const ctr = $("headlines-frame");
- const e = $("RROW-" + id);
- const is_expanded = App.getInitParam("cdm_expanded");
-
- if (!e || !ctr) return;
- if (force || is_expanded || e.offsetTop + e.offsetHeight > (ctr.scrollTop + ctr.offsetHeight) ||
- e.offsetTop < ctr.scrollTop) {
+ });
- if (event && event.repeat || !is_expanded) {
- ctr.addClassName("forbid-smooth-scroll");
- window.clearTimeout(this._scroll_reset_timeout);
+ },
+ cdmMoveToId: function (id, params) {
+ params = params || {};
- this._scroll_reset_timeout = window.setTimeout(() => {
- if (ctr) ctr.removeClassName("forbid-smooth-scroll");
- }, 250)
+ const force_to_top = params.force_to_top || false;
- } else {
- ctr.removeClassName("forbid-smooth-scroll");
- }
+ const ctr = $("headlines-frame");
+ const row = $("RROW-" + id);
- ctr.scrollTop = e.offsetTop;
+ if (!row || !ctr) return;
- Element.hide("floatingTitle");
- }
- },
- setActive: function (id) {
- console.log("setActive", id);
+ if (force_to_top || !App.Scrollable.fitsInContainer(row, ctr)) {
+ ctr.scrollTop = row.offsetTop;
+ }
+ },
+ setActive: function (id) {
+ if (id != Article.getActive()) {
+ console.log("setActive", id, "was", Article.getActive());
- $$("div[id*=RROW][class*=active]").each((e) => {
- e.removeClassName("active");
+ $$("div[id*=RROW][class*=active]").each((row) => {
+ row.removeClassName("active");
+ Article.pack(row);
});
const row = $("RROW-" + id);
@@ -321,50 +341,29 @@ define(["dojo/_base/declare"], function (declare) {
PluginHost.run(PluginHost.HOOK_ARTICLE_SET_ACTIVE, row.getAttribute("data-article-id"));
}
- },
- getActive: function () {
- const row = document.querySelector("#headlines-frame > div[id*=RROW][class*=active]");
-
- if (row)
- return row.getAttribute("data-article-id");
- else
- return 0;
- },
- scrollByPages: function (page_offset, event) {
- const elem = App.isCombinedMode() ? $("headlines-frame") : $("content-insert");
-
- const offset = elem.offsetHeight * page_offset * 0.99;
-
- this.scroll(offset, event);
- },
- scroll: function (offset, event) {
-
- const elem = App.isCombinedMode() ? $("headlines-frame") : $("content-insert");
-
- if (event && event.repeat) {
- elem.addClassName("forbid-smooth-scroll");
- window.clearTimeout(this._scroll_reset_timeout);
-
- this._scroll_reset_timeout = window.setTimeout(() => {
- if (elem) elem.removeClassName("forbid-smooth-scroll");
- }, 250)
-
- } else {
- elem.removeClassName("forbid-smooth-scroll");
- }
-
- elem.scrollTop += offset;
- },
- mouseIn: function (id) {
- this.post_under_pointer = id;
- },
- mouseOut: function (id) {
- this.post_under_pointer = false;
- },
- getUnderPointer: function () {
- return this.post_under_pointer;
}
+ },
+ getActive: function () {
+ const row = document.querySelector("#headlines-frame > div[id*=RROW][class*=active]");
+
+ if (row)
+ return row.getAttribute("data-article-id");
+ else
+ return 0;
+ },
+ scrollByPages: function (page_offset) {
+ App.Scrollable.scrollByPages($("content-insert"), page_offset);
+ },
+ scroll: function (offset) {
+ App.Scrollable.scroll($("content-insert"), offset);
+ },
+ mouseIn: function (id) {
+ this.post_under_pointer = id;
+ },
+ mouseOut: function (/* id */) {
+ this.post_under_pointer = false;
+ },
+ getUnderPointer: function () {
+ return this.post_under_pointer;
}
-
- return Article;
-});
+}