4
0
Эх сурвалжийг харах

Prepare for batch mark as read

Alexandre Alapetite 7 жил өмнө
parent
commit
4888f919f1

+ 7 - 6
app/Controllers/entryController.php

@@ -97,14 +97,15 @@ class FreshRSS_entry_Controller extends Minz_ActionController {
 				}
 			}
 		} else {
-			$entryDAO->markRead($id, $is_read);
-
+			$ids = is_array($id) ? $id : array($id);
+			$entryDAO->markRead($ids, $is_read);
 			$tagDAO = FreshRSS_Factory::createTagDao();
-			foreach ($tagDAO->getTagsForEntry($id) as $tag) {
-				if (!empty($tag['checked'])) {
-					$this->view->tags[] = $tag['id'];
-				}
+			$tagsForEntries = $tagDAO->getTagsForEntries($ids);
+			$tags = array();
+			foreach ($tagsForEntries as $line) {
+				$tags['t_' . $line['id_tag']][] = $line['id_entry'];
 			}
+			$this->view->tags = $tags;
 		}
 
 		if (!$this->ajax) {

+ 1 - 1
app/Models/EntryDAO.php

@@ -383,7 +383,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
 	 */
 	public function markRead($ids, $is_read = true) {
 		FreshRSS_UserDAO::touch();
-		if (is_array($ids)) {	//Many IDs at once (used by API)
+		if (is_array($ids)) {	//Many IDs at once
 			if (count($ids) < 6) {	//Speed heuristics
 				$affected = 0;
 				foreach ($ids as $id) {

+ 31 - 17
app/Models/TagDAO.php

@@ -256,42 +256,56 @@ class FreshRSS_TagDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
 		}
 	}
 
-	//For API
-	public function getEntryIdsTagNames($entries) {
-		$sql = 'SELECT et.id_entry, t.name '
+	public function getTagsForEntries($entries) {
+		$sql = 'SELECT et.id_entry, et.id_tag, t.name '
 			 . 'FROM `' . $this->prefix . 'tag` t '
 			 . 'INNER JOIN `' . $this->prefix . 'entrytag` et ON et.id_tag = t.id';
 
 		$values = array();
 		if (is_array($entries) && count($entries) > 0) {
 			$sql .= ' AND et.id_entry IN (' . str_repeat('?,', count($entries) - 1). '?)';
-			foreach ($entries as $entry) {
-				$values[] = is_array($entry) ? $entry['id'] : $entry->id();
+			if (is_array($entries[0])) {
+				foreach ($entries as $entry) {
+					$values[] = $entry['id'];
+				}
+			} elseif (is_object($entries[0])) {
+				foreach ($entries as $entry) {
+					$values[] = $entry->id();
+				}
+			} else {
+				foreach ($entries as $entry) {
+					$values[] = $entry;
+				}
 			}
 		}
 		$stm = $this->bd->prepare($sql);
 
 		if ($stm && $stm->execute($values)) {
-			$result = array();
-			foreach ($stm->fetchAll(PDO::FETCH_ASSOC) as $line) {
-				$entryId = 'e_' . $line['id_entry'];
-				$tagName = $line['name'];
-				if (empty($result[$entryId])) {
-					$result[$entryId] = array();
-				}
-				$result[$entryId][] = $tagName;
-			}
-			return $result;
+			return $stm->fetchAll(PDO::FETCH_ASSOC);
 		} else {
 			$info = $stm == null ? array(0 => '', 1 => '', 2 => 'syntax error') : $stm->errorInfo();
 			if ($this->autoUpdateDb($info)) {
-				return $this->getTagNamesEntryIds($id_entry);
+				return $this->getTagsForEntries($entries);
 			}
-			Minz_Log::error('SQL error getTagNamesEntryIds: ' . $info[2]);
+			Minz_Log::error('SQL error getTagsForEntries: ' . $info[2]);
 			return false;
 		}
 	}
 
+	//For API
+	public function getEntryIdsTagNames($entries) {
+		$result = array();
+		foreach ($this->getTagsForEntries($entries) as $line) {
+			$entryId = 'e_' . $line['id_entry'];
+			$tagName = $line['name'];
+			if (empty($result[$entryId])) {
+				$result[$entryId] = array();
+			}
+			$result[$entryId][] = $tagName;
+		}
+		return $result;
+	}
+
 	public static function daoToTag($listDAO) {
 		$list = array();
 		if (!is_array($listDAO)) {

+ 0 - 10
app/views/entry/read.phtml

@@ -1,17 +1,7 @@
 <?php
 header('Content-Type: application/json; charset=UTF-8');
 
-$url = array(
-	'c' => Minz_Request::controllerName(),
-	'a' => Minz_Request::actionName(),
-	'params' => Minz_Request::fetchGET(),
-);
-
-$url['params']['is_read'] = Minz_Request::param('is_read', true) ? '0' : '1';
-
 FreshRSS::loadStylesAndScripts();
 echo json_encode(array(
-		'url' => str_ireplace('&amp;', '&', Minz_Url::display($url)),
-		'icon' => _i($url['params']['is_read'] === '1' ? 'unread' : 'read'),
 		'tags' => $this->tags,
 	));

+ 2 - 1
app/views/helpers/javascript_vars.phtml

@@ -56,6 +56,7 @@ echo htmlspecialchars(json_encode(array(
 		'category_empty' => _t('gen.js.category_empty'),
 	),
 	'icons' => array(
-		'close' => _i('close'),
+		'read' => rawurlencode(_i('read')),
+		'unread' => rawurlencode(_i('unread')),
 	),
 ), JSON_UNESCAPED_UNICODE), ENT_NOQUOTES, 'UTF-8');

+ 35 - 27
p/scripts/main.js

@@ -7,6 +7,8 @@ var $stream = null,
 	shares = 0,
 	ajax_loading = false;
 
+if (!NodeList.prototype.forEach) { NodeList.prototype.forEach = Array.prototype.forEach; }	//IE11
+
 function redirect(url, new_tab) {
 	if (url) {
 		if (new_tab) {
@@ -89,7 +91,7 @@ function incUnreadsFeed(article, feed_id, nb) {
 	}
 
 	//Update unread: favourites
-	if (article && article.closest('div').hasClass('favorite')) {
+	if (article && $(article).closest('div').hasClass('favorite')) {
 		elem = $('#aside_feed .favorites .title').get(0);
 		if (elem) {
 			feed_unreads = elem ? str2int(elem.getAttribute('data-unread')) : 0;
@@ -115,7 +117,7 @@ function incUnreadsFeed(article, feed_id, nb) {
 }
 
 function incUnreadsTag(tag_id, nb) {
-	var $t = $('#t_' + tag_id);
+	var $t = $('#' + tag_id);
 	var unreads = str2int($t.attr('data-unread'));
 	$t.attr('data-unread', unreads + nb)
 		.children('.item-title').attr('data-unread', numberFormat(unreads + nb));
@@ -126,20 +128,20 @@ function incUnreadsTag(tag_id, nb) {
 }
 
 var pending_entries = {};
-function mark_read(active, only_not_read) {
-	if ((active.length === 0) || (!active.attr('id')) ||
-		context.anonymous ||
-		(only_not_read && !active.hasClass("not_read"))) {
+function mark_read($active, only_not_read) {
+	let div = $active ? $active[0] : null;
+	if (!div || !div.id || context.anonymous ||
+		(only_not_read && !div.classList.contains('not_read'))) {
 		return false;
 	}
 
-	if (pending_entries[active.attr('id')]) {
+	if (pending_entries[div.id]) {
 		return false;
 	}
-	pending_entries[active.attr('id')] = true;
+	pending_entries[div.id] = true;
 
-	var url = '.?c=entry&a=read&id=' + active.attr('id').replace(/^flux_/, '') +
-		(active.hasClass('not_read') ? '' : '&is_read=0');
+	let url = '.?c=entry&a=read&id=' + div.id.replace(/^flux_/, '') +
+		(div.classList.contains('not_read') ? '' : '&is_read=0');
 
 	$.ajax({
 		type: 'POST',
@@ -149,35 +151,39 @@ function mark_read(active, only_not_read) {
 			_csrf: context.csrf,
 		},
 	}).done(function (data) {
-		var $r = active.find("a.read").attr("href", data.url),
-			inc = 0;
-		if (active.hasClass("not_read")) {
-			active.removeClass("not_read");
+		let inc = 0;
+		if (div.classList.contains('not_read')) {
+			div.classList.remove('not_read');
+			div.querySelectorAll('a.read').forEach(function (a) { a.setAttribute('href', a.getAttribute('href').replace('&is_read=0', '') + '&is_read=1'); });
+			div.querySelectorAll('a.read > .icon').forEach(function (img) { img.outerHTML = icons.read; });
 			inc--;
 		} else {
-			active.addClass("not_read");
-			active.addClass("keep_unread");
+			div.classList.add('not_read', 'keep_unread');
+			div.querySelectorAll('a.read').forEach(function (a) { a.setAttribute('href', a.getAttribute('href').replace('&is_read=1', '')); });
+			div.querySelectorAll('a.read > .icon').forEach(function (img) { img.outerHTML = icons.unread; });
 			inc++;
 		}
-		$r.find('.icon').replaceWith(data.icon);
 
-		var feed_url = active.find(".website>a").attr("href");
-		if (feed_url) {
-			var feed_id = feed_url.substr(feed_url.lastIndexOf('f_'));
-			incUnreadsFeed(active, feed_id, inc);
+		let feed_link = div.querySelector('.website > a');
+		if (feed_link) {
+			let feed_url = feed_link.getAttribute('href');
+			let feed_id = feed_url.substr(feed_url.lastIndexOf('f_'));
+			incUnreadsFeed(div, feed_id, inc);
 		}
 		faviconNbUnread();
 
 		if (data.tags) {
-			for (var i = data.tags.length - 1; i >= 0; i--) {
-				incUnreadsTag(data.tags[i], inc);
+			let tagIds = Object.keys(data.tags);
+			for (let i = tagIds.length - 1; i >= 0; i--) {
+				let tagId = tagIds[i];
+				incUnreadsTag(tagId, inc * data.tags[tagId].length);
 			}
 		}
 
-		delete pending_entries[active.attr('id')];
+		delete pending_entries[div.id];
 	}).fail(function (data) {
 		openNotification(i18n.notif_request_failed, 'bad');
-		delete pending_entries[active.attr('id')];
+		delete pending_entries[div.id];
 	});
 }
 
@@ -911,7 +917,7 @@ function init_dynamic_tags() {
 			})
 			.done(function () {
 				if ($entry.hasClass('not_read')) {
-					incUnreadsTag(tagId, isChecked ? 1 : -1);
+					incUnreadsTag('t_' + tagId, isChecked ? 1 : -1);
 				}
 			})
 			.fail(function () {
@@ -1079,7 +1085,7 @@ function notifs_html5_show(nb) {
 	var notification = new window.Notification(i18n.notif_title_articles, {
 		icon: "../themes/icons/favicon-256.png",
 		body: i18n.notif_body_articles.replace('%d', nb),
-		tag: "freshRssNewArticles"
+		tag: 'freshRssNewArticles',
 	});
 
 	notification.onclick = function() {
@@ -1491,6 +1497,8 @@ function parseJsonVars() {
 	window.url = json.url;
 	window.i18n = json.i18n;
 	window.icons = json.icons;
+	icons.read = decodeURIComponent(icons.read);
+	icons.unread = decodeURIComponent(icons.unread);
 }
 
 function init_normal() {