render article on the client using headlines data
This commit is contained in:
parent
41e967136f
commit
bd66a9ef28
|
@ -27,6 +27,7 @@ class Article extends Handler_Protected {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
function view() {
|
function view() {
|
||||||
$id = clean($_REQUEST["id"]);
|
$id = clean($_REQUEST["id"]);
|
||||||
$cids = explode(",", clean($_REQUEST["cids"]));
|
$cids = explode(",", clean($_REQUEST["cids"]));
|
||||||
|
@ -63,8 +64,9 @@ class Article extends Handler_Protected {
|
||||||
}
|
}
|
||||||
|
|
||||||
print json_encode($articles);
|
print json_encode($articles);
|
||||||
}
|
} */
|
||||||
|
|
||||||
|
/*
|
||||||
private function catchupArticleById($id, $cmode) {
|
private function catchupArticleById($id, $cmode) {
|
||||||
|
|
||||||
if ($cmode == 0) {
|
if ($cmode == 0) {
|
||||||
|
@ -86,6 +88,7 @@ class Article extends Handler_Protected {
|
||||||
$feed_id = $this->getArticleFeed($id);
|
$feed_id = $this->getArticleFeed($id);
|
||||||
CCache::update($feed_id, $_SESSION["uid"]);
|
CCache::update($feed_id, $_SESSION["uid"]);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
static function create_published_article($title, $url, $content, $labels_str,
|
static function create_published_article($title, $url, $content, $labels_str,
|
||||||
$owner_uid) {
|
$owner_uid) {
|
||||||
|
|
|
@ -285,8 +285,6 @@ class Feeds extends Handler_Protected {
|
||||||
|
|
||||||
if (!$line["feed_title"]) $line["feed_title"] = "";
|
if (!$line["feed_title"]) $line["feed_title"] = "";
|
||||||
|
|
||||||
if (get_pref('COMBINED_DISPLAY_MODE')) {
|
|
||||||
|
|
||||||
$line["buttons_left"] = "";
|
$line["buttons_left"] = "";
|
||||||
foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_ARTICLE_LEFT_BUTTON) as $p) {
|
foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_ARTICLE_LEFT_BUTTON) as $p) {
|
||||||
$line["buttons_left"] .= $p->hook_article_left_button($line);
|
$line["buttons_left"] .= $p->hook_article_left_button($line);
|
||||||
|
@ -305,7 +303,6 @@ class Feeds extends Handler_Protected {
|
||||||
}
|
}
|
||||||
|
|
||||||
$line['content'] = rewrite_cached_urls($line['content']);
|
$line['content'] = rewrite_cached_urls($line['content']);
|
||||||
$line["content"] = htmlspecialchars($line["content"]);
|
|
||||||
|
|
||||||
if ($line['note'])
|
if ($line['note'])
|
||||||
$line['note'] = Article::format_article_note($id, $line['note']);
|
$line['note'] = Article::format_article_note($id, $line['note']);
|
||||||
|
@ -335,10 +332,11 @@ class Feeds extends Handler_Protected {
|
||||||
$line["orig_feed"] = [ $tmp_line["title"], $tmp_line["site_url"], $tmp_line["feed_url"] ];
|
$line["orig_feed"] = [ $tmp_line["title"], $tmp_line["site_url"], $tmp_line["feed_url"] ];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
$line["updated_long"] = make_local_datetime($line["updated"],true);
|
||||||
$line["updated"] = make_local_datetime($line["updated"], false, false, false, true);
|
$line["updated"] = make_local_datetime($line["updated"], false, false, false, true);
|
||||||
|
|
||||||
|
|
||||||
$line['imported'] = T_sprintf("Imported at %s",
|
$line['imported'] = T_sprintf("Imported at %s",
|
||||||
make_local_datetime($line["date_entered"], false));
|
make_local_datetime($line["date_entered"], false));
|
||||||
|
|
||||||
|
|
|
@ -137,58 +137,65 @@ define(["dojo/_base/declare"], function (declare) {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
formatComments: function(hl) {
|
||||||
|
let comments = "";
|
||||||
|
|
||||||
|
if (hl.comments) {
|
||||||
|
let comments_msg = __("comments");
|
||||||
|
|
||||||
|
if (hl.num_comments > 0) {
|
||||||
|
comments_msg = hl.num_comments + " " + ngettext("comment", "comments", hl.num_comments)
|
||||||
|
}
|
||||||
|
|
||||||
|
comments = `<a href="${hl.comments}">(${comments_msg})</a>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return comments;
|
||||||
|
},
|
||||||
|
formatOriginallyFrom: function(hl) {
|
||||||
|
return hl.orig_feed ? `<span>
|
||||||
|
${__('Originally from:')} <a target="_blank" rel="noopener noreferrer" href="${hl.orig_feed[1]}">${hl.orig_feed[0]}</a>
|
||||||
|
</span>` : "";
|
||||||
|
},
|
||||||
view: function (id, noexpand) {
|
view: function (id, noexpand) {
|
||||||
this.setActive(id);
|
this.setActive(id);
|
||||||
|
|
||||||
if (!noexpand) {
|
if (!noexpand) {
|
||||||
console.log("loading article", id);
|
const hl = Headlines.objectById(id);
|
||||||
|
|
||||||
const cids = [];
|
if (hl) {
|
||||||
|
|
||||||
/* only request uncached articles */
|
const comments = this.formatComments(hl);
|
||||||
|
const originally_from = this.formatOriginallyFrom(hl);
|
||||||
|
|
||||||
this.getRelativeIds(id).each((n) => {
|
const article = `<div class="post post-${hl.id}">
|
||||||
if (!ArticleCache.get(n))
|
<div class="header">
|
||||||
cids.push(n);
|
<div class="row">
|
||||||
});
|
<div class="title"><a target="_blank" rel="noopener noreferrer" title="${hl.title}" href="${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>
|
||||||
|
</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>`;
|
||||||
|
|
||||||
const cached_article = ArticleCache.get(id);
|
Headlines.toggleUnread(id, 0);
|
||||||
|
this.render(article);
|
||||||
if (cached_article) {
|
|
||||||
console.log('rendering cached', id);
|
|
||||||
this.render(cached_article);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
xhrPost("backend.php", {op: "article", method: "view", id: id, cids: cids.toString()}, (transport) => {
|
|
||||||
try {
|
|
||||||
const reply = App.handleRpcJson(transport);
|
|
||||||
|
|
||||||
if (reply) {
|
|
||||||
|
|
||||||
reply.each(function (article) {
|
|
||||||
if (Article.getActive() == article['id']) {
|
|
||||||
Article.render(article['content']);
|
|
||||||
}
|
|
||||||
ArticleCache.set(article['id'], article['content']);
|
|
||||||
});
|
|
||||||
|
|
||||||
} else {
|
|
||||||
console.error("Invalid object received: " + transport.responseText);
|
|
||||||
|
|
||||||
Article.render("<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.close();
|
|
||||||
|
|
||||||
} catch (e) {
|
|
||||||
App.Error.report(e);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
'use strict'
|
|
||||||
/* global __, ngettext */
|
|
||||||
define(["dojo/_base/declare"], function (declare) {
|
|
||||||
ArticleCache = {
|
|
||||||
has_storage: 'sessionStorage' in window && window['sessionStorage'] !== null,
|
|
||||||
set: function (id, obj) {
|
|
||||||
if (this.has_storage)
|
|
||||||
try {
|
|
||||||
sessionStorage["article:" + id] = obj;
|
|
||||||
} catch (e) {
|
|
||||||
sessionStorage.clear();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
get: function (id) {
|
|
||||||
if (this.has_storage)
|
|
||||||
return sessionStorage["article:" + id];
|
|
||||||
},
|
|
||||||
clear: function () {
|
|
||||||
if (this.has_storage)
|
|
||||||
sessionStorage.clear();
|
|
||||||
},
|
|
||||||
del: function (id) {
|
|
||||||
if (this.has_storage)
|
|
||||||
sessionStorage.removeItem("article:" + id);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return ArticleCache;
|
|
||||||
});
|
|
|
@ -4,7 +4,7 @@ define(["dojo/_base/declare"], function (declare) {
|
||||||
Headlines = {
|
Headlines = {
|
||||||
vgroup_last_feed: undefined,
|
vgroup_last_feed: undefined,
|
||||||
_headlines_scroll_timeout: 0,
|
_headlines_scroll_timeout: 0,
|
||||||
loaded_article_ids: [],
|
headlines: [],
|
||||||
current_first_id: 0,
|
current_first_id: 0,
|
||||||
catchup_id_batch: [],
|
catchup_id_batch: [],
|
||||||
click: function (event, id, in_body) {
|
click: function (event, id, in_body) {
|
||||||
|
@ -239,6 +239,9 @@ define(["dojo/_base/declare"], function (declare) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
objectById: function (id){
|
||||||
|
return this.headlines[id];
|
||||||
|
},
|
||||||
renderHeadline: function (headlines, hl) {
|
renderHeadline: function (headlines, hl) {
|
||||||
let row = null;
|
let row = null;
|
||||||
|
|
||||||
|
@ -266,24 +269,11 @@ define(["dojo/_base/declare"], function (declare) {
|
||||||
if (App.isCombinedMode()) {
|
if (App.isCombinedMode()) {
|
||||||
row_class += App.getInitParam("cdm_expanded") ? " expanded" : " expandable";
|
row_class += App.getInitParam("cdm_expanded") ? " expanded" : " expandable";
|
||||||
|
|
||||||
let originally_from = hl.orig_feed ? `<span>
|
const comments = Article.formatComments(hl);
|
||||||
${__('Originally from:')} <a target="_blank" rel="noopener noreferrer" href="${hl.orig_feed[1]}">${hl.orig_feed[0]}</a>
|
const originally_from = Article.formatOriginallyFrom(hl);
|
||||||
</span>` : "";
|
|
||||||
|
|
||||||
let comments = "";
|
|
||||||
|
|
||||||
if (hl.comments) {
|
|
||||||
let comments_msg = __("comments");
|
|
||||||
|
|
||||||
if (hl.num_comments > 0) {
|
|
||||||
comments_msg = hl.num_comments + " " + ngettext("comment", "comments", hl.num_comments)
|
|
||||||
}
|
|
||||||
|
|
||||||
comments = `<a href="${hl.comments}">(${comments_msg})</a>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
row = `<div class="cdm ${row_class} ${hl.score_class}" id="RROW-${hl.id}" data-article-id="${hl.id}" data-orig-feed-id="${hl.feed_id}"
|
row = `<div class="cdm ${row_class} ${hl.score_class}" id="RROW-${hl.id}" data-article-id="${hl.id}" data-orig-feed-id="${hl.feed_id}"
|
||||||
data-content="${hl.content}" onmouseover="Article.mouseIn(${hl.id})" onmouseout="Article.mouseOut(${hl.id})">
|
data-content="${escapeHtml(hl.content)}" onmouseover="Article.mouseIn(${hl.id})" onmouseout="Article.mouseOut(${hl.id})">
|
||||||
|
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="left">
|
<div class="left">
|
||||||
|
@ -319,7 +309,9 @@ define(["dojo/_base/declare"], function (declare) {
|
||||||
|
|
||||||
<div class="content" onclick="return Headlines.click(event, ${hl.id}, true);">
|
<div class="content" onclick="return Headlines.click(event, ${hl.id}, true);">
|
||||||
<div id="POSTNOTE-${hl.id}">${hl.note}</div>
|
<div id="POSTNOTE-${hl.id}">${hl.note}</div>
|
||||||
<div class="content-inner" lang="${hl.lang ? hl.lang : 'en'}"></div>
|
<div class="content-inner" lang="${hl.lang ? hl.lang : 'en'}">
|
||||||
|
<img src="${App.getInitParam('icon_indicator_white')}">
|
||||||
|
</div>
|
||||||
<div class="intermediate">
|
<div class="intermediate">
|
||||||
${hl.enclosures}
|
${hl.enclosures}
|
||||||
</div>
|
</div>
|
||||||
|
@ -329,7 +321,7 @@ define(["dojo/_base/declare"], function (declare) {
|
||||||
${hl.buttons_left}
|
${hl.buttons_left}
|
||||||
<i class="material-icons">label_outline</i>
|
<i class="material-icons">label_outline</i>
|
||||||
<span id="ATSTR-${hl.id}">${hl.tags_str}</span>
|
<span id="ATSTR-${hl.id}">${hl.tags_str}</span>
|
||||||
<a title="Edit tags for this article" href="#"
|
<a title="${__("Edit tags for this article")}" href="#"
|
||||||
onclick="Article.editTags(${hl.id})">(+)</a>
|
onclick="Article.editTags(${hl.id})">(+)</a>
|
||||||
${comments}
|
${comments}
|
||||||
</div>
|
</div>
|
||||||
|
@ -426,7 +418,7 @@ define(["dojo/_base/declare"], function (declare) {
|
||||||
this.current_first_id = reply['headlines']['first_id'];
|
this.current_first_id = reply['headlines']['first_id'];
|
||||||
|
|
||||||
if (offset == 0) {
|
if (offset == 0) {
|
||||||
this.loaded_article_ids = [];
|
//this.headlines = [];
|
||||||
this.vgroup_last_feed = undefined;
|
this.vgroup_last_feed = undefined;
|
||||||
|
|
||||||
dojo.html.set($("toolbar-headlines"),
|
dojo.html.set($("toolbar-headlines"),
|
||||||
|
@ -439,7 +431,10 @@ define(["dojo/_base/declare"], function (declare) {
|
||||||
$("headlines-frame").innerHTML = '';
|
$("headlines-frame").innerHTML = '';
|
||||||
|
|
||||||
for (let i = 0; i < reply['headlines']['content'].length; i++) {
|
for (let i = 0; i < reply['headlines']['content'].length; i++) {
|
||||||
this.renderHeadline(reply['headlines'], reply['headlines']['content'][i]);
|
const hl = reply['headlines']['content'][i];
|
||||||
|
|
||||||
|
this.renderHeadline(reply['headlines'], hl);
|
||||||
|
this.headlines[parseInt(hl.id)] = hl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -505,7 +500,10 @@ define(["dojo/_base/declare"], function (declare) {
|
||||||
$("headlines-frame").innerHTML = reply['headlines']['content'];
|
$("headlines-frame").innerHTML = reply['headlines']['content'];
|
||||||
} else {
|
} else {
|
||||||
for (let i = 0; i < reply['headlines']['content'].length; i++) {
|
for (let i = 0; i < reply['headlines']['content'].length; i++) {
|
||||||
this.renderHeadline(reply['headlines'], reply['headlines']['content'][i]);
|
const hl = reply['headlines']['content'][i];
|
||||||
|
|
||||||
|
this.renderHeadline(reply['headlines'], hl);
|
||||||
|
this.headlines[parseInt(hl.id)] = hl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1014,10 +1012,6 @@ define(["dojo/_base/declare"], function (declare) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < rows.length; i++) {
|
|
||||||
ArticleCache.del(rows[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const query = {op: "rpc", method: op, ids: rows.toString()};
|
const query = {op: "rpc", method: op, ids: rows.toString()};
|
||||||
|
|
||||||
xhrPost("backend.php", query, (transport) => {
|
xhrPost("backend.php", query, (transport) => {
|
||||||
|
|
13
js/common.js
13
js/common.js
|
@ -331,3 +331,16 @@ function popupOpenArticle(id) {
|
||||||
w.location = "backend.php?op=article&method=view&mode=raw&html=1&zoom=1&id=" + id + "&csrf_token=" + App.getInitParam("csrf_token");
|
w.location = "backend.php?op=article&method=view&mode=raw&html=1&zoom=1&id=" + id + "&csrf_token=" + App.getInitParam("csrf_token");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// htmlspecialchars()-alike for headlines data-content attribute
|
||||||
|
function escapeHtml(text) {
|
||||||
|
const map = {
|
||||||
|
'&': '&',
|
||||||
|
'<': '<',
|
||||||
|
'>': '>',
|
||||||
|
'"': '"',
|
||||||
|
"'": '''
|
||||||
|
};
|
||||||
|
|
||||||
|
return text.replace(/[&<>"']/g, function(m) { return map[m]; });
|
||||||
|
}
|
|
@ -7,7 +7,6 @@ let Filters;
|
||||||
let Feeds;
|
let Feeds;
|
||||||
let Headlines;
|
let Headlines;
|
||||||
let Article;
|
let Article;
|
||||||
let ArticleCache;
|
|
||||||
let PluginHost;
|
let PluginHost;
|
||||||
|
|
||||||
const Plugins = {};
|
const Plugins = {};
|
||||||
|
@ -54,7 +53,6 @@ require(["dojo/_base/kernel",
|
||||||
"fox/Feeds",
|
"fox/Feeds",
|
||||||
"fox/Headlines",
|
"fox/Headlines",
|
||||||
"fox/Article",
|
"fox/Article",
|
||||||
"fox/ArticleCache",
|
|
||||||
"fox/FeedStoreModel",
|
"fox/FeedStoreModel",
|
||||||
"fox/FeedTree"], function (dojo, declare, ready, parser, AppBase) {
|
"fox/FeedTree"], function (dojo, declare, ready, parser, AppBase) {
|
||||||
|
|
||||||
|
@ -138,8 +136,6 @@ require(["dojo/_base/kernel",
|
||||||
|
|
||||||
App.setLoadingProgress(50);
|
App.setLoadingProgress(50);
|
||||||
|
|
||||||
ArticleCache.clear();
|
|
||||||
|
|
||||||
this._widescreen_mode = App.getInitParam("widescreen");
|
this._widescreen_mode = App.getInitParam("widescreen");
|
||||||
this.switchPanelMode(this._widescreen_mode);
|
this.switchPanelMode(this._widescreen_mode);
|
||||||
|
|
||||||
|
@ -162,7 +158,6 @@ require(["dojo/_base/kernel",
|
||||||
document.title = tmp;
|
document.title = tmp;
|
||||||
},
|
},
|
||||||
onViewModeChanged: function() {
|
onViewModeChanged: function() {
|
||||||
ArticleCache.clear();
|
|
||||||
return Feeds.reloadCurrent('');
|
return Feeds.reloadCurrent('');
|
||||||
},
|
},
|
||||||
isCombinedMode: function() {
|
isCombinedMode: function() {
|
||||||
|
|
|
@ -18,8 +18,6 @@ Plugins.Note = {
|
||||||
dialog.hide();
|
dialog.hide();
|
||||||
|
|
||||||
if (reply) {
|
if (reply) {
|
||||||
ArticleCache.del(id);
|
|
||||||
|
|
||||||
const elem = $("POSTNOTE-" + id);
|
const elem = $("POSTNOTE-" + id);
|
||||||
|
|
||||||
if (elem) {
|
if (elem) {
|
||||||
|
|
Loading…
Reference in New Issue