aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Alexandre Alapetite <alexandre@alapetite.fr> 2013-10-26 17:21:11 +0200
committerGravatar Alexandre Alapetite <alexandre@alapetite.fr> 2013-10-26 17:21:11 +0200
commite7dd4829799e9e14456e1b1fc3aca20412394798 (patch)
tree86ae5ab0fb167120ba61fe559646cf863570283d
parentdd5273871a74d01d87fa1eaad7aa53bc1c148f85 (diff)
Mise à jour automatique des nombres d'articles non lus et favoris
En JavaScript, sans requête au serveur, décrémente ou incrémente le nombre d'articles non lus ou en favoris suite à une action de l'utilisateur. Utilise un nouvel attribut data-unread pour stocker le nombre d'articles non-lus et du pur CSS pour afficher cette valeur. Nouvel attribut data-priority (pour savoir s'il faut inclure le flux ou pas dans les nombres d'articles non lus). Légère simplification CSS au passage (d'autres optimisations des performances CSS seraient souhaitables en évitant les règles contenant trop de sélecteurs universels imbriqués genre ".categories .favorites .btn" et en évitant les changements de style en JavaScript lors du chargement - j'essayerai de faire une proposition dans un patch séparé). Bug connu : une catégorie finissant par une espace suivi d'un nombre entre parenthèses comme "Exemple (2)" cause actuellement un léger bug d'affichage dans le <title> s'il y a 0 article non lu et que l'utilisateur en marque un comme "non lu". Il faudra une modification pour utiliser data-unread aussi pour le <title>
-rw-r--r--app/layout/aside_flux.phtml47
-rw-r--r--public/scripts/main.js53
-rw-r--r--public/themes/default/freshrss.css39
-rw-r--r--public/themes/flat-design/freshrss.css35
4 files changed, 106 insertions, 68 deletions
diff --git a/app/layout/aside_flux.phtml b/app/layout/aside_flux.phtml
index 8928ffca0..22f52d25a 100644
--- a/app/layout/aside_flux.phtml
+++ b/app/layout/aside_flux.phtml
@@ -30,20 +30,16 @@
<?php } ?>
<li>
- <div class="all">
- <a class="btn<?php echo $this->get_c == 'all' ? ' active' : ''; ?>" href="<?php echo _url ('index', 'index'); ?>">
- <i class="icon i_all"></i>
- <?php echo Translate::t ('all_feeds', $this->nb_total); ?>
- <?php if ($this->nb_not_read > 0) { ?>
- <span class="notRead"><?php echo $this->nb_not_read > 1 ? Translate::t ('not_reads', $this->nb_not_read) : Translate::t ('not_read', $this->nb_not_read); ?></span>
- <?php } ?>
+ <div class="category all">
+ <a data-unread="<?php echo $this->nb_not_read; ?>" class="btn<?php echo $this->get_c == 'all' ? ' active' : ''; ?>" href="<?php echo _url ('index', 'index'); ?>">
+ <i class="icon i_all"></i><?php echo Translate::t ('all_feeds', $this->nb_total); ?>
</a>
</div>
</li>
<li>
- <div class="favorites">
- <a class="btn<?php echo $this->get_c == 'favoris' ? ' active' : ''; ?>" href="<?php echo _url ('index', 'index', 'get', 'favoris'); ?>">
+ <div class="category favorites">
+ <a data-unread="0" class="btn<?php echo $this->get_c == 'favoris' ? ' active' : ''; ?>" href="<?php echo _url ('index', 'index', 'get', 'favoris'); ?>">
<i class="icon i_bookmark"></i>
<?php echo Translate::t ('favorite_feeds', $this->nb_favorites); ?>
</a>
@@ -51,36 +47,27 @@
</li>
<?php foreach ($this->cat_aside as $cat) { ?>
- <?php $feeds = $cat->feeds (); $catNotRead = $cat->nbNotRead (); ?>
+ <?php $feeds = $cat->feeds (); ?>
<?php if (!empty ($feeds)) { ?>
<li>
<?php $c_active = false; if ($this->get_c == $cat->id ()) { $c_active = true; } ?>
<div class="category<?php echo $c_active ? ' active' : ''; ?>">
- <a class="btn<?php echo $c_active ? ' active' : ''; ?>" href="<?php echo _url ('index', 'index', 'get', 'c_' . $cat->id ()); ?>">
- <?php echo $cat->name (); ?>
- <?php if ($catNotRead > 0) { ?>
- <span class="notRead" title="<?php echo $catNotRead > 1 ? Translate::t ('not_reads', $catNotRead) : Translate::t ('not_read', $catNotRead); ?>"><?php echo $catNotRead ; ?></span>
- <?php } ?>
- </a>
+ <a data-unread="<?php echo $cat->nbNotRead (); ?>" class="btn<?php echo $c_active ? ' active' : ''; ?>" href="<?php echo _url ('index', 'index', 'get', 'c_' . $cat->id ()); ?>"><?php echo $cat->name (); ?></a>
</div>
<ul class="feeds<?php echo $c_active ? ' active' : ''; ?>">
- <?php foreach ($feeds as $feed) { ?>
- <?php $nbEntries = $feed->nbEntries (); ?>
- <?php $f_active = false; if ($this->get_f == $feed->id ()) { $f_active = true; } ?>
- <li class="item<?php echo $f_active ? ' active' : ''; ?><?php echo $feed->inError () ? ' error' : ''; ?><?php echo $nbEntries == 0 ? ' empty' : ''; ?>">
+ <?php foreach ($feeds as $feed) {
+ $feed_id = $feed->id (); $nbEntries = $feed->nbEntries ();
+ $f_active = ($this->get_f == $feed_id);
+ ?>
+ <li id="f_<?php echo $feed_id; ?>" class="item<?php echo $f_active ? ' active' : ''; ?><?php echo $feed->inError () ? ' error' : ''; ?><?php echo $nbEntries == 0 ? ' empty' : ''; ?>">
<div class="dropdown">
<div class="dropdown-target"></div>
- <a class="dropdown-toggle" data-fid="<?php echo $feed->id (); ?>" data-fweb="<?php echo $feed->website (); ?>"><i class="icon i_configure"></i></a>
+ <a class="dropdown-toggle" data-fweb="<?php echo $feed->website (); ?>"><i class="icon i_configure"></i></a>
<?php /* feed_config_template */ ?>
</div>
- <?php $not_read = $feed->nbNotRead (); ?>
- <img class="favicon" src="<?php echo $feed->favicon (); ?>" alt="" />
- <?php echo $not_read > 0 ? '<b>' : ''; ?>
- <a class="feed" href="<?php echo _url ('index', 'index', 'get', 'f_' . $feed->id ()); ?>">
- <?php echo ($not_read > 0 ? '(' . $not_read . ') ' : ''), $feed->name(); ?>
- </a>
- <?php echo $not_read > 0 ? '</b>' : ''; ?>
+ <img class="favicon" src="<?php echo $feed->favicon (); ?>" />
+ <a class="feed" data-unread="<?php echo $feed->nbNotRead (); ?>" data-priority="<?php echo $feed->priority (); ?>" href="<?php echo _url ('index', 'index', 'get', 'f_' . $feed_id); ?>"><?php echo $feed->name(); ?></a>
</li>
<?php } ?>
</ul>
@@ -94,13 +81,13 @@
<script id="feed_config_template" type="text/html">
<ul class="dropdown-menu">
<li class="dropdown-close"><a href="#close">&nbsp;</a></li>
- <li class="item"><a href="<?php echo _url ('index', 'index', 'get', 'f_' . '!!!!!!'); ?>"><?php echo Translate::t ('filter'); ?></a></li>
+ <li class="item"><a href="<?php echo _url ('index', 'index', 'get', 'f_!!!!!!'); ?>"><?php echo Translate::t ('filter'); ?></a></li>
<li class="item"><a target="_blank" href="http://example.net/"><?php echo Translate::t ('see_website'); ?></a></li>
<?php if (!login_is_conf ($this->conf) || is_logged ()) { ?>
<li class="separator"></li>
<li class="item"><a href="<?php echo _url ('configure', 'feed', 'id', '!!!!!!'); ?>"><?php echo Translate::t ('administration'); ?></a></li>
<li class="item"><a href="<?php echo _url ('feed', 'actualize', 'id', '!!!!!!'); ?>"><?php echo Translate::t ('actualize'); ?></a></li>
- <li class="item"><a href="<?php echo _url ('entry', 'read', 'is_read', 1, 'get', 'f_' . '!!!!!!'); ?>"><?php echo Translate::t ('mark_read'); ?></a></li>
+ <li class="item"><a href="<?php echo _url ('entry', 'read', 'is_read', 1, 'get', 'f_!!!!!!'); ?>"><?php echo Translate::t ('mark_read'); ?></a></li>
<?php } ?>
</ul>
</script>
diff --git a/public/scripts/main.js b/public/scripts/main.js
index 72795be51..ea4f3bec6 100644
--- a/public/scripts/main.js
+++ b/public/scripts/main.js
@@ -71,6 +71,11 @@ function toggleContent (new_active, old_active) {
}
}
+function _incLabel(p, inc) {
+ var i = (parseInt(p.replace(/\D/g, '')) || 0) + inc;
+ return i > 0 ? ' (' + i + ')' : '';
+}
+
function mark_read (active, only_not_read) {
if (active[0] === undefined || (
only_not_read === true && !active.hasClass("not_read"))) {
@@ -91,11 +96,41 @@ function mark_read (active, only_not_read) {
active.find ("a.read").attr ("href", res.url);
+ var inc = 0;
if (active.hasClass ("not_read")) {
active.removeClass ("not_read");
+ inc--;
} else if (only_not_read !== true || active.hasClass("not_read")) {
active.addClass ("not_read");
+ inc++;
+ }
+
+ //Update unread: feed //Alex
+ var feed_url = active.find(".website>a").attr("href"),
+ feed_id = feed_url.substr(feed_url.lastIndexOf('f_')),
+ elem = $('#' + feed_id + ' .feed').get(0),
+ attr_unread = elem ? elem.getAttributeNode('data-unread') : null,
+ feed_priority = elem ? parseInt(elem.getAttribute('data-priority')) : 0;
+ if (attr_unread)
+ attr_unread.value = Math.max(0, parseInt(attr_unread.value) + inc);
+
+ //Update unread: category
+ elem = $('#' + feed_id).parent().prevAll('.category').children(':first').get(0);
+ attr_unread = elem ? elem.getAttributeNode('data-unread') : null;
+ if (attr_unread)
+ attr_unread.value = Math.max(0, parseInt(attr_unread.value) + inc);
+
+ if (feed_priority > 0) { //Update unread: all
+ elem = $('#aside_flux .all').children(':first').get(0);
+ attr_unread = elem ? elem.getAttributeNode('data-unread') : null;
+ if (attr_unread)
+ attr_unread.value = Math.max(0, parseInt(attr_unread.value) + inc);
}
+
+ //Update unread: title
+ document.title = document.title.replace(/((?: \(\d+\))?)( - .*?)((?: \(\d+\))?)$/, function(m, p1, p2, p3) {
+ return _incLabel(p1, inc) + p2 + _incLabel(p3, feed_priority > 0 ? inc : 0);
+ });
});
}
@@ -117,11 +152,20 @@ function mark_favorite (active) {
res = jQuery.parseJSON(data);
active.find ("a.bookmark").attr ("href", res.url);
+ var inc = 0;
if (active.hasClass ("favorite")) {
active.removeClass ("favorite");
+ inc--;
} else {
active.addClass ("favorite");
+ inc++;
}
+
+ var favourites = $('.favorites>a').contents().last().get(0);
+ if (favourites && favourites.textContent)
+ favourites.textContent = favourites.textContent.replace(/((?: \(\d+\))?\s*)$/, function(m, p1) {
+ return _incLabel(p1, inc);
+ });
});
}
@@ -235,9 +279,10 @@ function init_column_categories () {
return;
}
- $(".category").addClass ("stick");
- $(".categories .category .btn:first-child").width ("160px");
- $(".category").append ("<a class=\"btn dropdown-toggle\" href=\"#\"><i class=\"icon i_down\"></i></a>");
+ //TODO: toggle class in PHP and remove the CSS changes done in JavaScript
+ $(".category:not(.all):not(.favorites) .btn:first-child").width ("160px");
+ $(".category:not(.all):not(.favorites)").addClass("stick").
+ append ("<a class=\"btn dropdown-toggle\" href=\"#\"><i class=\"icon i_down\"></i></a>");
$(".category + .feeds").not(".active").hide();
$(".category.active a.dropdown-toggle i").toggleClass ("i_up");
@@ -391,7 +436,7 @@ function init_nav_entries() {
function init_templates() {
$('#aside_flux').on('click', '.dropdown-toggle', function () {
if ($(this).nextAll('.dropdown-menu').length === 0) {
- var feed_id = $(this).data('fid'),
+ var feed_id = $(this).closest('li').attr('id').substr(2),
feed_web = $(this).data('fweb'),
template = $('#feed_config_template').html().replace(/!!!!!!/g, feed_id).replace('http://example.net/', feed_web);
$(this).attr('href', '#dropdown-' + feed_id).prev('.dropdown-target').attr('id', 'dropdown-' + feed_id).parent().append(template);
diff --git a/public/themes/default/freshrss.css b/public/themes/default/freshrss.css
index e464b9fe4..dc852d4fd 100644
--- a/public/themes/default/freshrss.css
+++ b/public/themes/default/freshrss.css
@@ -93,9 +93,7 @@
text-align: center;
list-style: none;
}
- .categories .all,
- .categories .favorites,
- .categories .category {
+ .category {
display: block;
padding: 5px 0;
width: 220px;
@@ -105,12 +103,23 @@
white-space: nowrap;
text-overflow: ellipsis;
}
- .categories .all .btn,
- .categories .favorites .btn,
- .categories .category .btn:first-child {
+ .category .btn:first-child {
width: 195px;
position: relative;
}
+ .category .btn:first-child:not([data-unread="0"]):after {
+ content: attr(data-unread);
+ position: absolute;
+ top: 3px; right: 3px;
+ padding: 1px 5px;
+ background: #ccc;
+ color: #fff;
+ font-size: 90%;
+ border: 1px solid #bbb;
+ border-radius: 5px;
+ box-shadow: 1px 3px 3px #aaa inset;
+ text-shadow: 0 0 1px #aaa;
+ }
.categories .feeds {
width: 100%;
margin: 0;
@@ -146,6 +155,12 @@
white-space: nowrap;
text-overflow: ellipsis;
}
+ .feed:not([data-unread="0"]) {
+ font-weight:bold;
+ }
+ .feed:not([data-unread="0"]):before {
+ content: "(" attr(data-unread) ") ";
+ }
.categories .feeds .dropdown .dropdown-menu {
left: 0;
}
@@ -163,18 +178,6 @@
background-color: #fff;
border-radius: 3px;
}
- .categories .notRead {
- position: absolute;
- top: 3px; right: 3px;
- padding: 1px 5px;
- background: #ccc;
- color: #fff;
- font-size: 90%;
- border: 1px solid #bbb;
- border-radius: 5px;
- box-shadow: 1px 3px 3px #aaa inset;
- text-shadow: 0 0 1px #aaa;
- }
.post {
padding: 10px 50px;
diff --git a/public/themes/flat-design/freshrss.css b/public/themes/flat-design/freshrss.css
index 49533f017..886791830 100644
--- a/public/themes/flat-design/freshrss.css
+++ b/public/themes/flat-design/freshrss.css
@@ -92,9 +92,7 @@ body {
text-align: center;
list-style: none;
}
- .categories .all,
- .categories .favorites,
- .categories .category {
+ .category {
display: block;
padding: 5px 0;
width: 220px;
@@ -104,12 +102,21 @@ body {
white-space: nowrap;
text-overflow: ellipsis;
}
- .categories .all .btn,
- .categories .favorites .btn,
- .categories .category .btn:first-child {
+ .category .btn:first-child {
width: 195px;
position: relative;
}
+ .category .btn:first-child:not([data-unread="0"]):after {
+ content: attr(data-unread);
+ position: absolute;
+ top: 5px; right: 0px;
+ padding: 0 5px;
+ color: #fff;
+ font-size: 90%;
+ background: #3498DB;
+ border-left: 3px solid #2980B9;
+ border-radius: 5px 0 0 5px;
+ }
.categories .feeds {
width: 220px;
margin: 0 auto;
@@ -138,6 +145,12 @@ body {
white-space: nowrap;
text-overflow: ellipsis;
}
+ .feed:not([data-unread="0"]) {
+ font-weight:bold;
+ }
+ .feed:not([data-unread="0"]):before {
+ content: "(" attr(data-unread) ") ";
+ }
.categories .feeds .dropdown .dropdown-menu {
left: 0;
}
@@ -155,16 +168,6 @@ body {
background-color: #95a5a6;
border-radius: 3px;
}
- .categories .notRead {
- position: absolute;
- top: 5px; right: 0px;
- padding: 0 5px;
- color: #fff;
- font-size: 90%;
- background: #3498DB;
- border-left: 3px solid #2980B9;
- border-radius: 5px 0 0 5px;
- }
.categories .btn:hover .notRead,
.categories .btn.active .notRead {
background: #2980B9;