Skip to content

Commit 4888f91

Browse files
committed
Prepare for batch mark as read
1 parent 06ea262 commit 4888f91

File tree

6 files changed

+76
-62
lines changed

6 files changed

+76
-62
lines changed

app/Controllers/entryController.php

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,14 +97,15 @@ public function readAction() {
9797
}
9898
}
9999
} else {
100-
$entryDAO->markRead($id, $is_read);
101-
100+
$ids = is_array($id) ? $id : array($id);
101+
$entryDAO->markRead($ids, $is_read);
102102
$tagDAO = FreshRSS_Factory::createTagDao();
103-
foreach ($tagDAO->getTagsForEntry($id) as $tag) {
104-
if (!empty($tag['checked'])) {
105-
$this->view->tags[] = $tag['id'];
106-
}
103+
$tagsForEntries = $tagDAO->getTagsForEntries($ids);
104+
$tags = array();
105+
foreach ($tagsForEntries as $line) {
106+
$tags['t_' . $line['id_tag']][] = $line['id_entry'];
107107
}
108+
$this->view->tags = $tags;
108109
}
109110

110111
if (!$this->ajax) {

app/Models/EntryDAO.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ protected function updateCacheUnreads($catId = false, $feedId = false) {
383383
*/
384384
public function markRead($ids, $is_read = true) {
385385
FreshRSS_UserDAO::touch();
386-
if (is_array($ids)) { //Many IDs at once (used by API)
386+
if (is_array($ids)) { //Many IDs at once
387387
if (count($ids) < 6) { //Speed heuristics
388388
$affected = 0;
389389
foreach ($ids as $id) {

app/Models/TagDAO.php

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -256,42 +256,56 @@ public function getTagsForEntry($id_entry) {
256256
}
257257
}
258258

259-
//For API
260-
public function getEntryIdsTagNames($entries) {
261-
$sql = 'SELECT et.id_entry, t.name '
259+
public function getTagsForEntries($entries) {
260+
$sql = 'SELECT et.id_entry, et.id_tag, t.name '
262261
. 'FROM `' . $this->prefix . 'tag` t '
263262
. 'INNER JOIN `' . $this->prefix . 'entrytag` et ON et.id_tag = t.id';
264263

265264
$values = array();
266265
if (is_array($entries) && count($entries) > 0) {
267266
$sql .= ' AND et.id_entry IN (' . str_repeat('?,', count($entries) - 1). '?)';
268-
foreach ($entries as $entry) {
269-
$values[] = is_array($entry) ? $entry['id'] : $entry->id();
267+
if (is_array($entries[0])) {
268+
foreach ($entries as $entry) {
269+
$values[] = $entry['id'];
270+
}
271+
} elseif (is_object($entries[0])) {
272+
foreach ($entries as $entry) {
273+
$values[] = $entry->id();
274+
}
275+
} else {
276+
foreach ($entries as $entry) {
277+
$values[] = $entry;
278+
}
270279
}
271280
}
272281
$stm = $this->bd->prepare($sql);
273282

274283
if ($stm && $stm->execute($values)) {
275-
$result = array();
276-
foreach ($stm->fetchAll(PDO::FETCH_ASSOC) as $line) {
277-
$entryId = 'e_' . $line['id_entry'];
278-
$tagName = $line['name'];
279-
if (empty($result[$entryId])) {
280-
$result[$entryId] = array();
281-
}
282-
$result[$entryId][] = $tagName;
283-
}
284-
return $result;
284+
return $stm->fetchAll(PDO::FETCH_ASSOC);
285285
} else {
286286
$info = $stm == null ? array(0 => '', 1 => '', 2 => 'syntax error') : $stm->errorInfo();
287287
if ($this->autoUpdateDb($info)) {
288-
return $this->getTagNamesEntryIds($id_entry);
288+
return $this->getTagsForEntries($entries);
289289
}
290-
Minz_Log::error('SQL error getTagNamesEntryIds: ' . $info[2]);
290+
Minz_Log::error('SQL error getTagsForEntries: ' . $info[2]);
291291
return false;
292292
}
293293
}
294294

295+
//For API
296+
public function getEntryIdsTagNames($entries) {
297+
$result = array();
298+
foreach ($this->getTagsForEntries($entries) as $line) {
299+
$entryId = 'e_' . $line['id_entry'];
300+
$tagName = $line['name'];
301+
if (empty($result[$entryId])) {
302+
$result[$entryId] = array();
303+
}
304+
$result[$entryId][] = $tagName;
305+
}
306+
return $result;
307+
}
308+
295309
public static function daoToTag($listDAO) {
296310
$list = array();
297311
if (!is_array($listDAO)) {

app/views/entry/read.phtml

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,7 @@
11
<?php
22
header('Content-Type: application/json; charset=UTF-8');
33

4-
$url = array(
5-
'c' => Minz_Request::controllerName(),
6-
'a' => Minz_Request::actionName(),
7-
'params' => Minz_Request::fetchGET(),
8-
);
9-
10-
$url['params']['is_read'] = Minz_Request::param('is_read', true) ? '0' : '1';
11-
124
FreshRSS::loadStylesAndScripts();
135
echo json_encode(array(
14-
'url' => str_ireplace('&amp;', '&', Minz_Url::display($url)),
15-
'icon' => _i($url['params']['is_read'] === '1' ? 'unread' : 'read'),
166
'tags' => $this->tags,
177
));

app/views/helpers/javascript_vars.phtml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ echo htmlspecialchars(json_encode(array(
5656
'category_empty' => _t('gen.js.category_empty'),
5757
),
5858
'icons' => array(
59-
'close' => _i('close'),
59+
'read' => rawurlencode(_i('read')),
60+
'unread' => rawurlencode(_i('unread')),
6061
),
6162
), JSON_UNESCAPED_UNICODE), ENT_NOQUOTES, 'UTF-8');

p/scripts/main.js

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ var $stream = null,
77
shares = 0,
88
ajax_loading = false;
99

10+
if (!NodeList.prototype.forEach) { NodeList.prototype.forEach = Array.prototype.forEach; } //IE11
11+
1012
function redirect(url, new_tab) {
1113
if (url) {
1214
if (new_tab) {
@@ -89,7 +91,7 @@ function incUnreadsFeed(article, feed_id, nb) {
8991
}
9092

9193
//Update unread: favourites
92-
if (article && article.closest('div').hasClass('favorite')) {
94+
if (article && $(article).closest('div').hasClass('favorite')) {
9395
elem = $('#aside_feed .favorites .title').get(0);
9496
if (elem) {
9597
feed_unreads = elem ? str2int(elem.getAttribute('data-unread')) : 0;
@@ -115,7 +117,7 @@ function incUnreadsFeed(article, feed_id, nb) {
115117
}
116118

117119
function incUnreadsTag(tag_id, nb) {
118-
var $t = $('#t_' + tag_id);
120+
var $t = $('#' + tag_id);
119121
var unreads = str2int($t.attr('data-unread'));
120122
$t.attr('data-unread', unreads + nb)
121123
.children('.item-title').attr('data-unread', numberFormat(unreads + nb));
@@ -126,20 +128,20 @@ function incUnreadsTag(tag_id, nb) {
126128
}
127129

128130
var pending_entries = {};
129-
function mark_read(active, only_not_read) {
130-
if ((active.length === 0) || (!active.attr('id')) ||
131-
context.anonymous ||
132-
(only_not_read && !active.hasClass("not_read"))) {
131+
function mark_read($active, only_not_read) {
132+
let div = $active ? $active[0] : null;
133+
if (!div || !div.id || context.anonymous ||
134+
(only_not_read && !div.classList.contains('not_read'))) {
133135
return false;
134136
}
135137

136-
if (pending_entries[active.attr('id')]) {
138+
if (pending_entries[div.id]) {
137139
return false;
138140
}
139-
pending_entries[active.attr('id')] = true;
141+
pending_entries[div.id] = true;
140142

141-
var url = '.?c=entry&a=read&id=' + active.attr('id').replace(/^flux_/, '') +
142-
(active.hasClass('not_read') ? '' : '&is_read=0');
143+
let url = '.?c=entry&a=read&id=' + div.id.replace(/^flux_/, '') +
144+
(div.classList.contains('not_read') ? '' : '&is_read=0');
143145

144146
$.ajax({
145147
type: 'POST',
@@ -149,35 +151,39 @@ function mark_read(active, only_not_read) {
149151
_csrf: context.csrf,
150152
},
151153
}).done(function (data) {
152-
var $r = active.find("a.read").attr("href", data.url),
153-
inc = 0;
154-
if (active.hasClass("not_read")) {
155-
active.removeClass("not_read");
154+
let inc = 0;
155+
if (div.classList.contains('not_read')) {
156+
div.classList.remove('not_read');
157+
div.querySelectorAll('a.read').forEach(function (a) { a.setAttribute('href', a.getAttribute('href').replace('&is_read=0', '') + '&is_read=1'); });
158+
div.querySelectorAll('a.read > .icon').forEach(function (img) { img.outerHTML = icons.read; });
156159
inc--;
157160
} else {
158-
active.addClass("not_read");
159-
active.addClass("keep_unread");
161+
div.classList.add('not_read', 'keep_unread');
162+
div.querySelectorAll('a.read').forEach(function (a) { a.setAttribute('href', a.getAttribute('href').replace('&is_read=1', '')); });
163+
div.querySelectorAll('a.read > .icon').forEach(function (img) { img.outerHTML = icons.unread; });
160164
inc++;
161165
}
162-
$r.find('.icon').replaceWith(data.icon);
163166

164-
var feed_url = active.find(".website>a").attr("href");
165-
if (feed_url) {
166-
var feed_id = feed_url.substr(feed_url.lastIndexOf('f_'));
167-
incUnreadsFeed(active, feed_id, inc);
167+
let feed_link = div.querySelector('.website > a');
168+
if (feed_link) {
169+
let feed_url = feed_link.getAttribute('href');
170+
let feed_id = feed_url.substr(feed_url.lastIndexOf('f_'));
171+
incUnreadsFeed(div, feed_id, inc);
168172
}
169173
faviconNbUnread();
170174

171175
if (data.tags) {
172-
for (var i = data.tags.length - 1; i >= 0; i--) {
173-
incUnreadsTag(data.tags[i], inc);
176+
let tagIds = Object.keys(data.tags);
177+
for (let i = tagIds.length - 1; i >= 0; i--) {
178+
let tagId = tagIds[i];
179+
incUnreadsTag(tagId, inc * data.tags[tagId].length);
174180
}
175181
}
176182

177-
delete pending_entries[active.attr('id')];
183+
delete pending_entries[div.id];
178184
}).fail(function (data) {
179185
openNotification(i18n.notif_request_failed, 'bad');
180-
delete pending_entries[active.attr('id')];
186+
delete pending_entries[div.id];
181187
});
182188
}
183189

@@ -911,7 +917,7 @@ function init_dynamic_tags() {
911917
})
912918
.done(function () {
913919
if ($entry.hasClass('not_read')) {
914-
incUnreadsTag(tagId, isChecked ? 1 : -1);
920+
incUnreadsTag('t_' + tagId, isChecked ? 1 : -1);
915921
}
916922
})
917923
.fail(function () {
@@ -1079,7 +1085,7 @@ function notifs_html5_show(nb) {
10791085
var notification = new window.Notification(i18n.notif_title_articles, {
10801086
icon: "../themes/icons/favicon-256.png",
10811087
body: i18n.notif_body_articles.replace('%d', nb),
1082-
tag: "freshRssNewArticles"
1088+
tag: 'freshRssNewArticles',
10831089
});
10841090

10851091
notification.onclick = function() {
@@ -1491,6 +1497,8 @@ function parseJsonVars() {
14911497
window.url = json.url;
14921498
window.i18n = json.i18n;
14931499
window.icons = json.icons;
1500+
icons.read = decodeURIComponent(icons.read);
1501+
icons.unread = decodeURIComponent(icons.unread);
14941502
}
14951503

14961504
function init_normal() {

0 commit comments

Comments
 (0)