diff options
Diffstat (limited to 'js/Article.js')
-rw-r--r-- | js/Article.js | 527 |
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 += " "; + 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 += " "; - 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> - <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 = " "; + } + }, + 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> + <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¶m=" + 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; -}); +} |