summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Marien Fressinaud <dev@marienfressinaud.fr> 2014-07-31 17:21:09 +0200
committerGravatar Marien Fressinaud <dev@marienfressinaud.fr> 2014-07-31 17:21:09 +0200
commitaafcd3a879225414ca7fb5a9b74ba06e5ece8c12 (patch)
treea263cd8d3378b31539ad2138771d82829f2e76f3
parent3ffa2e301850154c6d7959f70dbbd37dc7fbffc9 (diff)
parent4a0e5ac037dc3c8fd16ca086924087f8ccaed46b (diff)
Merge branch 'dev' of github.com:marienfressinaud/freshrss into dev
-rw-r--r--app/Controllers/statsController.php15
-rw-r--r--app/Controllers/usersController.php4
-rw-r--r--app/Models/StatsDAO.php129
-rw-r--r--app/Models/StatsDAOSQLite.php28
-rw-r--r--app/Models/UserDAO.php6
-rw-r--r--app/i18n/en.php47
-rw-r--r--app/i18n/fr.php23
-rw-r--r--app/layout/aside_flux.phtml7
-rw-r--r--app/layout/aside_stats.phtml3
-rw-r--r--app/views/stats/idle.phtml10
-rw-r--r--app/views/stats/main.phtml127
-rw-r--r--app/views/stats/repartition.phtml99
-rw-r--r--p/scripts/main.js8
-rw-r--r--p/themes/Dark/template.css3
-rw-r--r--p/themes/Flat/template.css3
-rw-r--r--p/themes/Origine/template.css3
-rw-r--r--p/themes/base-theme/template.css3
17 files changed, 366 insertions, 152 deletions
diff --git a/app/Controllers/statsController.php b/app/Controllers/statsController.php
index 45d13e043..06a20c2a6 100644
--- a/app/Controllers/statsController.php
+++ b/app/Controllers/statsController.php
@@ -55,7 +55,20 @@ class FreshRSS_stats_Controller extends Minz_ActionController {
$this->view->idleFeeds = $idleFeeds;
}
-
+
+ public function repartitionAction() {
+ $statsDAO = FreshRSS_Factory::createStatsDAO();
+ $feedDAO = FreshRSS_Factory::createFeedDao();
+ Minz_View::appendScript(Minz_Url::display('/scripts/flotr2.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/flotr2.min.js')));
+ $id = Minz_Request::param ('id', null);
+ $this->view->feed = $feedDAO->searchById($id);
+ $this->view->days = $statsDAO->getDays();
+ $this->view->months = $statsDAO->getMonths();
+ $this->view->repartitionHour = $statsDAO->calculateEntryRepartitionPerFeedPerHour($id);
+ $this->view->repartitionDayOfWeek = $statsDAO->calculateEntryRepartitionPerFeedPerDayOfWeek($id);
+ $this->view->repartitionMonth = $statsDAO->calculateEntryRepartitionPerFeedPerMonth($id);
+ }
+
public function firstAction() {
if (!$this->view->loginOk) {
Minz_Error::error(
diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php
index 35fa3675f..a9e6c32bc 100644
--- a/app/Controllers/usersController.php
+++ b/app/Controllers/usersController.php
@@ -100,7 +100,7 @@ class FreshRSS_users_Controller extends Minz_ActionController {
public function createAction() {
if (Minz_Request::isPost() && Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) {
$db = Minz_Configuration::dataBase();
- require_once(APP_PATH . '/SQL/sql.' . $db['type'] . '.php');
+ require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php');
$new_user_language = Minz_Request::param('new_user_language', $this->view->conf->language);
if (!in_array($new_user_language, $this->view->conf->availableLanguages())) {
@@ -172,7 +172,7 @@ class FreshRSS_users_Controller extends Minz_ActionController {
public function deleteAction() {
if (Minz_Request::isPost() && Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) {
$db = Minz_Configuration::dataBase();
- require_once(APP_PATH . '/SQL/sql.' . $db['type'] . '.php');
+ require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php');
$username = Minz_Request::param('username');
$ok = ctype_alnum($username);
diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php
index 9a88a4fcf..89be76a26 100644
--- a/app/Models/StatsDAO.php
+++ b/app/Models/StatsDAO.php
@@ -85,9 +85,83 @@ SQL;
* @return array
*/
protected function initEntryCountArray() {
+ return $this->initStatsArray(-self::ENTRY_COUNT_PERIOD, -1);
+ }
+
+ /**
+ * Calculates the number of article per hour of the day per feed
+ *
+ * @param integer $feed id
+ * @return string
+ */
+ public function calculateEntryRepartitionPerFeedPerHour($feed = null) {
+ return $this->calculateEntryRepartitionPerFeedPerPeriod('%H', $feed);
+ }
+
+ /**
+ * Calculates the number of article per day of week per feed
+ *
+ * @param integer $feed id
+ * @return string
+ */
+ public function calculateEntryRepartitionPerFeedPerDayOfWeek($feed = null) {
+ return $this->calculateEntryRepartitionPerFeedPerPeriod('%w', $feed);
+ }
+
+ /**
+ * Calculates the number of article per month per feed
+ *
+ * @param integer $feed
+ * @return string
+ */
+ public function calculateEntryRepartitionPerFeedPerMonth($feed = null) {
+ return $this->calculateEntryRepartitionPerFeedPerPeriod('%m', $feed);
+ }
+
+ /**
+ * Calculates the number of article per period per feed
+ *
+ * @param string $period format string to use for grouping
+ * @param integer $feed id
+ * @return string
+ */
+ protected function calculateEntryRepartitionPerFeedPerPeriod($period, $feed = null) {
+ if ($feed) {
+ $restrict = "WHERE e.id_feed = {$feed}";
+ } else {
+ $restrict = '';
+ }
+ $sql = <<<SQL
+SELECT DATE_FORMAT(FROM_UNIXTIME(e.date), '{$period}') AS period
+, COUNT(1) AS count
+FROM {$this->prefix}entry AS e
+{$restrict}
+GROUP BY period
+ORDER BY period ASC
+SQL;
+
+ $stm = $this->bd->prepare($sql);
+ $stm->execute();
+ $res = $stm->fetchAll(PDO::FETCH_NAMED);
+
+ foreach ($res as $value) {
+ $repartition[(int) $value['period']] = (int) $value['count'];
+ }
+
+ return $this->convertToSerie($repartition);
+ }
+
+ /**
+ * Initialize an array for statistics depending on a range
+ *
+ * @param integer $min
+ * @param integer $max
+ * @return array
+ */
+ protected function initStatsArray($min, $max) {
return array_map(function () {
return 0;
- }, array_flip(range(-self::ENTRY_COUNT_PERIOD, -1)));
+ }, array_flip(range($min, $max)));
}
/**
@@ -205,4 +279,57 @@ SQL;
return json_encode($serie);
}
+ /**
+ * Gets days ready for graphs
+ *
+ * @return string
+ */
+ public function getDays() {
+ return $this->convertToTranslatedJson(array(
+ 'sun',
+ 'mon',
+ 'tue',
+ 'wed',
+ 'thu',
+ 'fri',
+ 'sat',
+ ));
+ }
+
+ /**
+ * Gets months ready for graphs
+ *
+ * @return string
+ */
+ public function getMonths() {
+ return $this->convertToTranslatedJson(array(
+ 'jan',
+ 'feb',
+ 'mar',
+ 'apr',
+ 'may',
+ 'jun',
+ 'jul',
+ 'aug',
+ 'sep',
+ 'oct',
+ 'nov',
+ 'dec',
+ ));
+ }
+
+ /**
+ * Translates array content and encode it as JSON
+ *
+ * @param array $data
+ * @return string
+ */
+ private function convertToTranslatedJson($data = array()) {
+ $translated = array_map(function ($a) {
+ return Minz_Translate::t($a);
+ }, $data);
+
+ return json_encode($translated);
+ }
+
}
diff --git a/app/Models/StatsDAOSQLite.php b/app/Models/StatsDAOSQLite.php
index dea590c92..6cb54ddf6 100644
--- a/app/Models/StatsDAOSQLite.php
+++ b/app/Models/StatsDAOSQLite.php
@@ -28,10 +28,36 @@ SQL;
$res = $stm->fetchAll(PDO::FETCH_ASSOC);
foreach ($res as $value) {
- $count[(int)$value['day']] = (int) $value['count'];
+ $count[(int) $value['day']] = (int) $value['count'];
}
return $this->convertToSerie($count);
}
+ protected function calculateEntryRepartitionPerFeedPerPeriod($period, $feed = null) {
+ if ($feed) {
+ $restrict = "WHERE e.id_feed = {$feed}";
+ } else {
+ $restrict = '';
+ }
+ $sql = <<<SQL
+SELECT strftime('{$period}', e.date, 'unixepoch') AS period
+, COUNT(1) AS count
+FROM {$this->prefix}entry AS e
+{$restrict}
+GROUP BY period
+ORDER BY period ASC
+SQL;
+
+ $stm = $this->bd->prepare($sql);
+ $stm->execute();
+ $res = $stm->fetchAll(PDO::FETCH_NAMED);
+
+ foreach ($res as $value) {
+ $repartition[(int) $value['period']] = (int) $value['count'];
+ }
+
+ return $this->convertToSerie($repartition);
+ }
+
}
diff --git a/app/Models/UserDAO.php b/app/Models/UserDAO.php
index dcf847a62..1763fac67 100644
--- a/app/Models/UserDAO.php
+++ b/app/Models/UserDAO.php
@@ -3,11 +3,11 @@
class FreshRSS_UserDAO extends Minz_ModelPdo {
public function createUser($username) {
$db = Minz_Configuration::dataBase();
- require_once(APP_PATH . '/SQL/sql.' . $db['type'] . '.php');
+ require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php');
if (defined('SQL_CREATE_TABLES')) {
$sql = sprintf(SQL_CREATE_TABLES, $db['prefix'] . $username . '_', Minz_Translate::t('default_category'));
- $stm = $c->prepare($sql);
+ $stm = $this->bd->prepare($sql);
$ok = $stm && $stm->execute();
} else {
global $SQL_CREATE_TABLES;
@@ -32,7 +32,7 @@ class FreshRSS_UserDAO extends Minz_ModelPdo {
public function deleteUser($username) {
$db = Minz_Configuration::dataBase();
- require_once(APP_PATH . '/SQL/sql.' . $db['type'] . '.php');
+ require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php');
$sql = sprintf(SQL_DROP_TABLES, $db['prefix'] . $username . '_');
$stm = $this->bd->prepare($sql);
diff --git a/app/i18n/en.php b/app/i18n/en.php
index 8634f99b5..10327c7f5 100644
--- a/app/i18n/en.php
+++ b/app/i18n/en.php
@@ -48,6 +48,10 @@ return array (
'stats' => 'Statistics',
'stats_idle' => 'Idle feeds',
'stats_main' => 'Main statistics',
+ 'stats_repartition' => 'Articles repartition',
+ 'stats_entry_per_hour' => 'Per hour',
+ 'stats_entry_per_day_of_week' => 'Per day of week',
+ 'stats_entry_per_month' => 'Per month',
'last_week' => 'Last week',
'last_month' => 'Last month',
@@ -341,18 +345,37 @@ return array (
'confirm_action' => 'Are you sure you want to perform this action? It cannot be cancelled!',
// DATE
- 'january' => 'january',
- 'february' => 'february',
- 'march' => 'march',
- 'april' => 'april',
- 'may' => 'may',
- 'june' => 'june',
- 'july' => 'july',
- 'august' => 'august',
- 'september' => 'september',
- 'october' => 'october',
- 'november' => 'november',
- 'december' => 'december',
+ 'january' => 'January',
+ 'february' => 'February',
+ 'march' => 'March',
+ 'april' => 'April',
+ 'may' => 'May',
+ 'june' => 'June',
+ 'july' => 'July',
+ 'august' => 'August',
+ 'september' => 'September',
+ 'october' => 'October',
+ 'november' => 'November',
+ 'december' => 'December',
+ 'january' => 'Jan',
+ 'february' => 'Feb',
+ 'march' => 'Mar',
+ 'april' => 'Apr',
+ 'may' => 'May',
+ 'june' => 'Jun',
+ 'july' => 'Jul',
+ 'august' => 'Aug',
+ 'september' => 'Sep',
+ 'october' => 'Oct',
+ 'november' => 'Nov',
+ 'december' => 'Dec',
+ 'sun' => 'Sun',
+ 'mon' => 'Mon',
+ 'tue' => 'Tue',
+ 'wed' => 'Wed',
+ 'thu' => 'Thu',
+ 'fri' => 'Fri',
+ 'sat' => 'Sat',
// special format for date() function
'Jan' => '\J\a\n\u\a\r\y',
'Feb' => '\F\e\b\r\u\a\r\y',
diff --git a/app/i18n/fr.php b/app/i18n/fr.php
index e04078dba..6ab3d7335 100644
--- a/app/i18n/fr.php
+++ b/app/i18n/fr.php
@@ -48,6 +48,10 @@ return array (
'stats' => 'Statistiques',
'stats_idle' => 'Flux inactifs',
'stats_main' => 'Statistiques principales',
+ 'stats_repartition' => 'Répartition des articles',
+ 'stats_entry_per_hour' => 'Par heure',
+ 'stats_entry_per_day_of_week' => 'Par jour de la semaine',
+ 'stats_entry_per_month' => 'Par mois',
'last_week' => 'La dernière semaine',
'last_month' => 'Le dernier mois',
@@ -353,6 +357,25 @@ return array (
'october' => 'octobre',
'november' => 'novembre',
'december' => 'décembre',
+ 'jan' => 'jan.',
+ 'feb' => 'fév.',
+ 'mar' => 'mar.',
+ 'apr' => 'avr.',
+ 'may' => 'mai.',
+ 'jun' => 'juin',
+ 'jul' => 'jui.',
+ 'aug' => 'août',
+ 'sep' => 'sep.',
+ 'oct' => 'oct.',
+ 'nov' => 'nov.',
+ 'dec' => 'déc.',
+ 'sun' => 'dim.',
+ 'mon' => 'lun.',
+ 'tue' => 'mar.',
+ 'wed' => 'mer.',
+ 'thu' => 'jeu.',
+ 'fri' => 'ven.',
+ 'sat' => 'sam.',
// format spécial pour la fonction date()
'Jan' => '\j\a\n\v\i\e\r',
'Feb' => '\f\é\v\r\i\e\r',
diff --git a/app/layout/aside_flux.phtml b/app/layout/aside_flux.phtml
index 817dae676..cc04e757c 100644
--- a/app/layout/aside_flux.phtml
+++ b/app/layout/aside_flux.phtml
@@ -1,4 +1,4 @@
-<div class="aside aside_flux" id="aside_flux">
+<div class="aside aside_flux<?php if (($this->state & FreshRSS_Entry::STATE_NOT_READ) && !($this->state & FreshRSS_Entry::STATE_READ)) echo ' state_unread'; ?>" id="aside_flux">
<a class="toggle_aside" href="#close"><?php echo FreshRSS_Themes::icon('close'); ?></a>
<ul class="categories">
@@ -41,11 +41,11 @@
foreach ($this->cat_aside as $cat) {
$feeds = $cat->feeds ();
if (!empty ($feeds)) {
- ?><li><?php
$c_active = false;
if ($this->get_c == $cat->id ()) {
$c_active = true;
}
+ ?><li data-unread="<?php echo $cat->nbNotRead(); ?>"<?php if ($c_active) echo ' class="active"'; ?>><?php
?><div class="category stick<?php echo $c_active ? ' active' : ''; ?>"><?php
?><a data-unread="<?php echo formatNumber($cat->nbNotRead()); ?>" class="btn<?php echo $c_active ? ' active' : ''; ?>" href="<?php $arUrl['params']['get'] = 'c_' . $cat->id(); echo Minz_Url::display($arUrl); ?>"><?php echo $cat->name (); ?></a><?php
?><a class="btn dropdown-toggle" href="#"><?php echo FreshRSS_Themes::icon($c_active ? 'up' : 'down'); ?></a><?php
@@ -55,7 +55,7 @@
$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' : ''; ?>"><?php
+ ?><li id="f_<?php echo $feed_id; ?>" class="item<?php echo $f_active ? ' active' : ''; ?><?php echo $feed->inError () ? ' error' : ''; ?><?php echo $nbEntries == 0 ? ' empty' : ''; ?>" data-unread="<?php echo $feed->nbNotRead(); ?>"><?php
?><div class="dropdown"><?php
?><div class="dropdown-target"></div><?php
?><a class="dropdown-toggle" data-fweb="<?php echo $feed->website (); ?>"><?php echo FreshRSS_Themes::icon('configure'); ?></a><?php
@@ -77,6 +77,7 @@
<ul class="dropdown-menu">
<li class="dropdown-close"><a href="#close">❌</a></li>
<li class="item"><a href="<?php echo _url ('index', 'index', 'get', 'f_!!!!!!'); ?>"><?php echo Minz_Translate::t ('filter'); ?></a></li>
+ <li class="item"><a href="<?php echo _url ('stats', 'repartition', 'id', '!!!!!!'); ?>"><?php echo Minz_Translate::t ('stats'); ?></a></li>
<li class="item"><a target="_blank" href="http://example.net/"><?php echo Minz_Translate::t ('see_website'); ?></a></li>
<?php if ($this->loginOk) { ?>
<li class="separator"></li>
diff --git a/app/layout/aside_stats.phtml b/app/layout/aside_stats.phtml
index 32a3f5dee..fbfb9d84d 100644
--- a/app/layout/aside_stats.phtml
+++ b/app/layout/aside_stats.phtml
@@ -6,4 +6,7 @@
<li class="item<?php echo Minz_Request::actionName () == 'idle' ? ' active' : ''; ?>">
<a href="<?php echo _url ('stats', 'idle'); ?>"><?php echo Minz_Translate::t ('stats_idle'); ?></a>
</li>
+ <li class="item<?php echo Minz_Request::actionName () == 'repartition' ? ' active' : ''; ?>">
+ <a href="<?php echo _url ('stats', 'repartition'); ?>"><?php echo Minz_Translate::t ('stats_repartition'); ?></a>
+ </li>
</ul>
diff --git a/app/views/stats/idle.phtml b/app/views/stats/idle.phtml
index a167fcccb..2ba5237f7 100644
--- a/app/views/stats/idle.phtml
+++ b/app/views/stats/idle.phtml
@@ -5,7 +5,10 @@
<h1><?php echo _t('stats_idle'); ?></h1>
- <?php foreach ($this->idleFeeds as $period => $feeds) { ?>
+ <?php
+ foreach ($this->idleFeeds as $period => $feeds) {
+ if (!empty($feeds)) {
+ ?>
<div class="stat">
<h2><?php echo _t($period); ?></h2>
@@ -15,5 +18,8 @@
<?php } ?>
</ul>
</div>
- <?php } ?>
+ <?php
+ }
+ }
+ ?>
</div>
diff --git a/app/views/stats/main.phtml b/app/views/stats/main.phtml
deleted file mode 100644
index fe372e221..000000000
--- a/app/views/stats/main.phtml
+++ /dev/null
@@ -1,127 +0,0 @@
-<?php $this->partial('aside_stats'); ?>
-
-<div class="post content">
- <a href="<?php echo _url ('index', 'index'); ?>"><?php echo Minz_Translate::t ('back_to_rss_feeds'); ?></a>
-
- <h1><?php echo Minz_Translate::t ('stats_main'); ?></h1>
-
- <div class="stat">
- <h2><?php echo Minz_Translate::t ('stats_entry_repartition'); ?></h2>
- <table>
- <thead>
- <tr>
- <th> </th>
- <th><?php echo Minz_Translate::t ('main_stream'); ?></th>
- <th><?php echo Minz_Translate::t ('all_feeds'); ?></th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <th><?php echo Minz_Translate::t ('status_total'); ?></th>
- <td class="numeric"><?php echo formatNumber($this->repartition['main_stream']['total']); ?></td>
- <td class="numeric"><?php echo formatNumber($this->repartition['all_feeds']['total']); ?></td>
- </tr>
- <tr>
- <th><?php echo Minz_Translate::t ('status_read'); ?></th>
- <td class="numeric"><?php echo formatNumber($this->repartition['main_stream']['read']); ?></td>
- <td class="numeric"><?php echo formatNumber($this->repartition['all_feeds']['read']); ?></td>
- </tr>
- <tr>
- <th><?php echo Minz_Translate::t ('status_unread'); ?></th>
- <td class="numeric"><?php echo formatNumber($this->repartition['main_stream']['unread']); ?></td>
- <td class="numeric"><?php echo formatNumber($this->repartition['all_feeds']['unread']); ?></td>
- </tr>
- <tr>
- <th><?php echo Minz_Translate::t ('status_favorites'); ?></th>
- <td class="numeric"><?php echo formatNumber($this->repartition['main_stream']['favorite']); ?></td>
- <td class="numeric"><?php echo formatNumber($this->repartition['all_feeds']['favorite']); ?></td>
- </tr>
- </tbody>
- </table>
- </div>
-
- <div class="stat">
- <h2><?php echo Minz_Translate::t ('stats_entry_per_day'); ?></h2>
- <div id="statsEntryPerDay" style="height: 300px"></div>
- </div>
-
- <div class="stat">
- <h2><?php echo Minz_Translate::t ('stats_feed_per_category'); ?></h2>
- <div id="statsFeedPerCategory" style="height: 300px"></div>
- <div id="statsFeedPerCategoryLegend"></div>
- </div>
-
- <div class="stat">
- <h2><?php echo Minz_Translate::t ('stats_entry_per_category'); ?></h2>
- <div id="statsEntryPerCategory" style="height: 300px"></div>
- <div id="statsEntryPerCategoryLegend"></div>
- </div>
-
- <div class="stat">
- <h2><?php echo Minz_Translate::t ('stats_top_feed'); ?></h2>
- <table>
- <thead>
- <tr>
- <th><?php echo Minz_Translate::t ('feed'); ?></th>
- <th><?php echo Minz_Translate::t ('category'); ?></th>
- <th><?php echo Minz_Translate::t ('stats_entry_count'); ?></th>
- </tr>
- </thead>
- <tbody>
- <?php foreach ($this->topFeed as $feed): ?>
- <tr>
- <td><?php echo $feed['name']; ?></td>
- <td><?php echo $feed['category']; ?></td>
- <td class="numeric"><?php echo formatNumber($feed['count']); ?></td>
- </tr>
- <?php endforeach;?>
- </tbody>
- </table>
- </div>
-</div>
-
-<script>
-"use strict";
-function initStats() {
- if (!window.Flotr) {
- if (window.console) {
- console.log('FreshRSS waiting for Flotr…');
- }
- window.setTimeout(initStats, 50);
- return;
- }
- // Entry per day
- Flotr.draw(document.getElementById('statsEntryPerDay'),
- [<?php echo $this->count ?>],
- {
- grid: {verticalLines: false},
- bars: {horizontal: false, show: true},
- xaxis: {noTicks: 6, showLabels: false, tickDecimals: 0},
- yaxis: {min: 0},
- mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}}
- });
- // Feed per category
- Flotr.draw(document.getElementById('statsFeedPerCategory'),
- <?php echo $this->feedByCategory ?>,
- {
- grid: {verticalLines: false, horizontalLines: false},
- pie: {explode: 10, show: true, labelFormatter: function(){return '';}},
- xaxis: {showLabels: false},
- yaxis: {showLabels: false},
- mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return obj.series.label + ' - '+ numberFormat(obj.y) + ' ('+ (obj.fraction * 100).toFixed(1) + '%)';}},
- legend: {container: document.getElementById('statsFeedPerCategoryLegend'), noColumns: 3}
- });
- // Entry per category
- Flotr.draw(document.getElementById('statsEntryPerCategory'),
- <?php echo $this->entryByCategory ?>,
- {
- grid: {verticalLines: false, horizontalLines: false},
- pie: {explode: 10, show: true, labelFormatter: function(){return '';}},
- xaxis: {showLabels: false},
- yaxis: {showLabels: false},
- mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return obj.series.label + ' - '+ numberFormat(obj.y) + ' ('+ (obj.fraction * 100).toFixed(1) + '%)';}},
- legend: {container: document.getElementById('statsEntryPerCategoryLegend'), noColumns: 3}
- });
-}
-initStats();
-</script>
diff --git a/app/views/stats/repartition.phtml b/app/views/stats/repartition.phtml
new file mode 100644
index 000000000..09892d3c5
--- /dev/null
+++ b/app/views/stats/repartition.phtml
@@ -0,0 +1,99 @@
+<?php $this->partial('aside_stats'); ?>
+
+<div class="post content">
+ <a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('back_to_rss_feeds'); ?></a>
+
+ <?php if ($this->feed) {?>
+ <h1>
+ <?php echo _t('stats_repartition'), " - "; ?>
+ <a href="<?php echo _url('configure', 'feed', 'id', $this->feed->id()); ?>">
+ <?php echo $this->feed->name(); ?>
+ </a>
+ </h1>
+ <?php } else {?>
+ <h1><?php echo _t('stats_repartition'); ?></h1>
+ <?php }?>
+
+ <div class="stat">
+ <h2><?php echo _t('stats_entry_per_hour'); ?></h2>
+ <div id="statsEntryPerHour" style="height: 300px"></div>
+ </div>
+
+ <div class="stat">
+ <h2><?php echo _t('stats_entry_per_day_of_week'); ?></h2>
+ <div id="statsEntryPerDayOfWeek" style="height: 300px"></div>
+ </div>
+
+ <div class="stat">
+ <h2><?php echo _t('stats_entry_per_month'); ?></h2>
+ <div id="statsEntryPerMonth" style="height: 300px"></div>
+ </div>
+</div>
+
+<script>
+"use strict";
+function initStats() {
+ if (!window.Flotr) {
+ if (window.console) {
+ console.log('FreshRSS waiting for Flotr…');
+ }
+ window.setTimeout(initStats, 50);
+ return;
+ }
+ // Entry per hour
+ Flotr.draw(document.getElementById('statsEntryPerHour'),
+ [<?php echo $this->repartitionHour ?>],
+ {
+ grid: {verticalLines: false},
+ bars: {horizontal: false, show: true},
+ xaxis: {noTicks: 23,
+ tickFormatter: function(x) {
+ var x = parseInt(x);
+ return x + 1;
+ },
+ min: -0.9,
+ max: 23.9,
+ tickDecimals: 0},
+ yaxis: {min: 0},
+ mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}}
+ });
+ // Entry per day of week
+ Flotr.draw(document.getElementById('statsEntryPerDayOfWeek'),
+ [<?php echo $this->repartitionDayOfWeek ?>],
+ {
+ grid: {verticalLines: false},
+ bars: {horizontal: false, show: true},
+ xaxis: {noTicks: 6,
+ tickFormatter: function(x) {
+ var x = parseInt(x),
+ days = <?php echo $this->days?>;
+ return days[x];
+ },
+ min: -0.9,
+ max: 6.9,
+ tickDecimals: 0},
+ yaxis: {min: 0},
+ mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}}
+ });
+ // Entry per month
+ Flotr.draw(document.getElementById('statsEntryPerMonth'),
+ [<?php echo $this->repartitionMonth ?>],
+ {
+ grid: {verticalLines: false},
+ bars: {horizontal: false, show: true},
+ xaxis: {noTicks: 12,
+ tickFormatter: function(x) {
+ var x = parseInt(x),
+ months = <?php echo $this->months?>;
+ return months[(x - 1)];
+ },
+ min: 0.1,
+ max: 12.9,
+ tickDecimals: 0},
+ yaxis: {min: 0},
+ mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}}
+ });
+
+}
+initStats();
+</script>
diff --git a/p/scripts/main.js b/p/scripts/main.js
index adbd5eab8..5d7d60a35 100644
--- a/p/scripts/main.js
+++ b/p/scripts/main.js
@@ -69,6 +69,10 @@ function incUnreadsFeed(article, feed_id, nb) {
feed_priority = elem ? str2int(elem.getAttribute('data-priority')) : 0;
if (elem) {
elem.setAttribute('data-unread', numberFormat(feed_unreads + nb));
+ elem = $(elem).closest('li').get(0);
+ if (elem) {
+ elem.setAttribute('data-unread', feed_unreads + nb);
+ }
}
//Update unread: category
@@ -76,6 +80,10 @@ function incUnreadsFeed(article, feed_id, nb) {
feed_unreads = elem ? str2int(elem.getAttribute('data-unread')) : 0;
if (elem) {
elem.setAttribute('data-unread', numberFormat(feed_unreads + nb));
+ elem = $(elem).closest('li').get(0);
+ if (elem) {
+ elem.setAttribute('data-unread', feed_unreads + nb);
+ }
}
//Update unread: all
diff --git a/p/themes/Dark/template.css b/p/themes/Dark/template.css
index 09ecaf685..466ec4603 100644
--- a/p/themes/Dark/template.css
+++ b/p/themes/Dark/template.css
@@ -309,6 +309,9 @@ a.btn {
list-style: none;
margin: 0;
}
+.state_unread li:not(.active)[data-unread="0"] {
+ display: none;
+}
.category {
display: block;
overflow: hidden;
diff --git a/p/themes/Flat/template.css b/p/themes/Flat/template.css
index 09ecaf685..466ec4603 100644
--- a/p/themes/Flat/template.css
+++ b/p/themes/Flat/template.css
@@ -309,6 +309,9 @@ a.btn {
list-style: none;
margin: 0;
}
+.state_unread li:not(.active)[data-unread="0"] {
+ display: none;
+}
.category {
display: block;
overflow: hidden;
diff --git a/p/themes/Origine/template.css b/p/themes/Origine/template.css
index 09ecaf685..466ec4603 100644
--- a/p/themes/Origine/template.css
+++ b/p/themes/Origine/template.css
@@ -309,6 +309,9 @@ a.btn {
list-style: none;
margin: 0;
}
+.state_unread li:not(.active)[data-unread="0"] {
+ display: none;
+}
.category {
display: block;
overflow: hidden;
diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css
index 09ecaf685..466ec4603 100644
--- a/p/themes/base-theme/template.css
+++ b/p/themes/base-theme/template.css
@@ -309,6 +309,9 @@ a.btn {
list-style: none;
margin: 0;
}
+.state_unread li:not(.active)[data-unread="0"] {
+ display: none;
+}
.category {
display: block;
overflow: hidden;