From 937cb4b066f07888dabe8400b71be6633a19a1d6 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 22 Jul 2014 13:41:31 +0200 Subject: Idle feeds: link to configuration page https://github.com/marienfressinaud/FreshRSS/issues/544 --- app/Controllers/statsController.php | 14 +++++++------- app/Models/StatsDAO.php | 3 ++- app/views/stats/idle.phtml | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/app/Controllers/statsController.php b/app/Controllers/statsController.php index 9009468bc..be58dd0eb 100644 --- a/app/Controllers/statsController.php +++ b/app/Controllers/statsController.php @@ -4,9 +4,9 @@ class FreshRSS_stats_Controller extends Minz_ActionController { public function indexAction() { $statsDAO = FreshRSS_Factory::createStatsDAO(); - Minz_View::appendScript (Minz_Url::display ('/scripts/flotr2.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/flotr2.min.js'))); + Minz_View::appendScript(Minz_Url::display('/scripts/flotr2.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/flotr2.min.js'))); $this->view->repartition = $statsDAO->calculateEntryRepartition(); - $this->view->count = ($statsDAO->calculateEntryCount()); + $this->view->count = $statsDAO->calculateEntryCount(); $this->view->feedByCategory = $statsDAO->calculateFeedByCategory(); $this->view->entryByCategory = $statsDAO->calculateEntryByCategory(); $this->view->topFeed = $statsDAO->calculateTopFeed(); @@ -35,19 +35,19 @@ class FreshRSS_stats_Controller extends Minz_ActionController { continue; } if ($feedDate < $lastWeek) { - $idleFeeds['last_week'][] = $feed['name']; + $idleFeeds['last_week'][] = $feed; } if ($feedDate < $lastMonth) { - $idleFeeds['last_month'][] = $feed['name']; + $idleFeeds['last_month'][] = $feed; } if ($feedDate < $last3Month) { - $idleFeeds['last_3_month'][] = $feed['name']; + $idleFeeds['last_3_month'][] = $feed; } if ($feedDate < $last6Month) { - $idleFeeds['last_6_month'][] = $feed['name']; + $idleFeeds['last_6_month'][] = $feed; } if ($feedDate < $lastYear) { - $idleFeeds['last_year'][] = $feed['name']; + $idleFeeds['last_year'][] = $feed; } } diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 66f5104b3..9a88a4fcf 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -170,7 +170,8 @@ SQL; */ public function calculateFeedLastDate() { $sql = <<prefix}feed AS f, {$this->prefix}entry AS e diff --git a/app/views/stats/idle.phtml b/app/views/stats/idle.phtml index 356fea20f..f62fa8d8b 100644 --- a/app/views/stats/idle.phtml +++ b/app/views/stats/idle.phtml @@ -11,7 +11,7 @@ -- cgit v1.2.3 From 72293427ac222dba03e88b2e34abc41e12a657c5 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 22 Jul 2014 13:56:01 +0200 Subject: Idle feeds: show tooltip with last update date https://github.com/marienfressinaud/FreshRSS/issues/544 --- app/views/stats/idle.phtml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/views/stats/idle.phtml b/app/views/stats/idle.phtml index f62fa8d8b..a167fcccb 100644 --- a/app/views/stats/idle.phtml +++ b/app/views/stats/idle.phtml @@ -1,17 +1,17 @@ partial('aside_stats'); ?>
- + -

+

- idleFeeds as $period => $feeds){ ?> + idleFeeds as $period => $feeds) { ?>
-

+

    - -
  • + +
-- cgit v1.2.3 From e507256d0bdebd02cf1fcd6fe1477cbac0b6934e Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 23 Jul 2014 00:24:00 +0200 Subject: Stats idle feed small bug Some feeds were listed more than once. A bit more independent from the SQL query. https://github.com/marienfressinaud/FreshRSS/issues/544 --- app/Controllers/statsController.php | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/app/Controllers/statsController.php b/app/Controllers/statsController.php index be58dd0eb..45d13e043 100644 --- a/app/Controllers/statsController.php +++ b/app/Controllers/statsController.php @@ -15,7 +15,13 @@ class FreshRSS_stats_Controller extends Minz_ActionController { public function idleAction() { $statsDAO = FreshRSS_Factory::createStatsDAO(); $feeds = $statsDAO->calculateFeedLastDate(); - $idleFeeds = array(); + $idleFeeds = array( + 'last_year' => array(), + 'last_6_month' => array(), + 'last_3_month' => array(), + 'last_month' => array(), + 'last_week' => array(), + ); $now = new \DateTime(); $feedDate = clone $now; $lastWeek = clone $now; @@ -34,24 +40,20 @@ class FreshRSS_stats_Controller extends Minz_ActionController { if ($feedDate >= $lastWeek) { continue; } - if ($feedDate < $lastWeek) { - $idleFeeds['last_week'][] = $feed; - } - if ($feedDate < $lastMonth) { - $idleFeeds['last_month'][] = $feed; - } - if ($feedDate < $last3Month) { - $idleFeeds['last_3_month'][] = $feed; - } - if ($feedDate < $last6Month) { - $idleFeeds['last_6_month'][] = $feed; - } if ($feedDate < $lastYear) { $idleFeeds['last_year'][] = $feed; + } elseif ($feedDate < $last6Month) { + $idleFeeds['last_6_month'][] = $feed; + } elseif ($feedDate < $last3Month) { + $idleFeeds['last_3_month'][] = $feed; + } elseif ($feedDate < $lastMonth) { + $idleFeeds['last_month'][] = $feed; + } elseif ($feedDate < $lastWeek) { + $idleFeeds['last_week'][] = $feed; } } - $this->view->idleFeeds = array_reverse($idleFeeds); + $this->view->idleFeeds = $idleFeeds; } public function firstAction() { -- cgit v1.2.3 From d5d3f6dcfa21e7defb26f3d470289e957bdb3dde Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 23 Jul 2014 23:56:16 +0200 Subject: Fix bugs in import/export - EntryDAO.php: add a missing "FreshRSS_EntryDAO::" - Fix htmlspecialchars in opml export --- app/Models/EntryDAO.php | 4 +++- app/views/helpers/export/opml.phtml | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 8c001e73b..74b5306e9 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -17,7 +17,9 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { } public function addEntry($valuesTmp, $preparedStatement = null) { - $stm = $preparedStatement === null ? addEntryPrepare() : $preparedStatement; + $stm = $preparedStatement === null ? + FreshRSS_EntryDAO::addEntryPrepare() : + $preparedStatement; $values = array( $valuesTmp['id'], diff --git a/app/views/helpers/export/opml.phtml b/app/views/helpers/export/opml.phtml index f667d093c..8622d9144 100644 --- a/app/views/helpers/export/opml.phtml +++ b/app/views/helpers/export/opml.phtml @@ -18,9 +18,9 @@ foreach ($this->categories as $key => $cat) { $opml_array['body'][$key]['@outlines'][] = array( 'text' => htmlspecialchars_decode($feed->name()), 'type' => 'rss', - 'xmlUrl' => $feed->url(), - 'htmlUrl' => $feed->website(), - 'description' => $feed->description() + 'xmlUrl' => htmlspecialchars_decode($feed->url()), + 'htmlUrl' => htmlspecialchars_decode($feed->website()), + 'description' => htmlspecialchars_decode($feed->description()), ); } } -- cgit v1.2.3 From d049c1bc806dc0677a4b2b17faf06080600c372f Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Thu, 24 Jul 2014 21:57:59 -0400 Subject: Add article repartition in stats Add article repartition per hour, per day of week, per month for all feeds but also for individual feeds. --- app/Controllers/statsController.php | 15 ++++- app/Models/StatsDAO.php | 129 +++++++++++++++++++++++++++++++++++- app/i18n/en.php | 47 +++++++++---- app/i18n/fr.php | 23 +++++++ app/layout/aside_flux.phtml | 1 + app/layout/aside_stats.phtml | 3 + app/views/stats/main.phtml | 127 ----------------------------------- app/views/stats/repartition.phtml | 100 ++++++++++++++++++++++++++++ 8 files changed, 304 insertions(+), 141 deletions(-) delete mode 100644 app/views/stats/main.phtml create mode 100644 app/views/stats/repartition.phtml 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/Models/StatsDAO.php b/app/Models/StatsDAO.php index 9a88a4fcf..ee8d0d663 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('%k', $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 = <<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/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..5fbb36730 100644 --- a/app/layout/aside_flux.phtml +++ b/app/layout/aside_flux.phtml @@ -83,6 +83,7 @@
  • +
  • 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 @@
  • +
  • + +
  • 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 @@ -partial('aside_stats'); ?> - -
    - - -

    - -
    -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     
    repartition['main_stream']['total']); ?>repartition['all_feeds']['total']); ?>
    repartition['main_stream']['read']); ?>repartition['all_feeds']['read']); ?>
    repartition['main_stream']['unread']); ?>repartition['all_feeds']['unread']); ?>
    repartition['main_stream']['favorite']); ?>repartition['all_feeds']['favorite']); ?>
    -
    - -
    -

    -
    -
    - -
    -

    -
    -
    -
    - -
    -

    -
    -
    -
    - -
    -

    - - - - - - - - - - topFeed as $feed): ?> - - - - - - - -
    -
    -
    - - diff --git a/app/views/stats/repartition.phtml b/app/views/stats/repartition.phtml new file mode 100644 index 000000000..4455abe2a --- /dev/null +++ b/app/views/stats/repartition.phtml @@ -0,0 +1,100 @@ +partial('aside_stats'); ?> + +
    + + + feed) {?> +

    + + + feed->name(); ?> + +

    + +

    + + +
    +

    +
    +
    + +
    +

    +
    +
    + +
    +

    +
    +
    +
    + + \ No newline at end of file -- cgit v1.2.3 From aa317eb2948b5caa5472bf307099efe850f7b314 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Thu, 24 Jul 2014 22:57:31 -0400 Subject: Add repartition statistic support in Sqlite --- app/Models/StatsDAO.php | 2 +- app/Models/StatsDAOSQLite.php | 28 +++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index ee8d0d663..89be76a26 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -95,7 +95,7 @@ SQL; * @return string */ public function calculateEntryRepartitionPerFeedPerHour($feed = null) { - return $this->calculateEntryRepartitionPerFeedPerPeriod('%k', $feed); + return $this->calculateEntryRepartitionPerFeedPerPeriod('%H', $feed); } /** 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 = <<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); + } + } -- cgit v1.2.3 From 584665eed4dfc1bf31c7557edd96e90b64f90c54 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Fri, 25 Jul 2014 10:33:06 +0200 Subject: Stats idle: hide empty periods https://github.com/marienfressinaud/FreshRSS/commit/e507256d0bdebd02cf1fcd6fe1477cbac0b6934e#commitcomment-7119169 --- app/views/stats/idle.phtml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) 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 @@

    - idleFeeds as $period => $feeds) { ?> + idleFeeds as $period => $feeds) { + if (!empty($feeds)) { + ?>

    @@ -15,5 +18,8 @@
    - +
    -- cgit v1.2.3 From 84dcd25d89a85c00df39d70525aa6d401a69b005 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Fri, 25 Jul 2014 06:36:43 -0400 Subject: Small fixes to follow @marienfressinaud recommandations --- app/layout/aside_flux.phtml | 2 +- app/views/stats/repartition.phtml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/layout/aside_flux.phtml b/app/layout/aside_flux.phtml index 5fbb36730..b1ed7a10d 100644 --- a/app/layout/aside_flux.phtml +++ b/app/layout/aside_flux.phtml @@ -77,13 +77,13 @@ diff --git a/app/views/stats/repartition.phtml b/app/views/stats/repartition.phtml index 4455abe2a..26b20e424 100644 --- a/app/views/stats/repartition.phtml +++ b/app/views/stats/repartition.phtml @@ -1,4 +1,4 @@ -partial('aside_stats'); ?> +partial ('aside_stats'); ?>
    @@ -6,8 +6,8 @@ feed) {?>

    - + feed->name(); ?>

    @@ -97,4 +97,4 @@ function initStats() { } initStats(); - \ No newline at end of file + -- cgit v1.2.3 From ad9fbf3887b79d69dcb53080e3f7c367b5bc17e1 Mon Sep 17 00:00:00 2001 From: plopoyop Date: Sat, 26 Jul 2014 13:29:55 +0200 Subject: Correct bug in add/remove users --- app/Controllers/usersController.php | 4 ++-- app/Models/UserDAO.php | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) 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/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); -- cgit v1.2.3 From d19824b919289ad63743f27da7861f2422da5baa Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 26 Jul 2014 13:56:44 +0200 Subject: Hide read feeds and read categories when in unread mode https://github.com/marienfressinaud/FreshRSS/issues/430 There are some repeated HTML attributes (`data-unread` and `active`) which could maybe be simplified. If some people do not like this behaviour, we could consider having an option. --- app/layout/aside_flux.phtml | 6 +++--- p/scripts/main.js | 8 ++++++++ p/themes/Dark/template.css | 3 +++ p/themes/Flat/template.css | 3 +++ p/themes/Origine/template.css | 3 +++ p/themes/base-theme/template.css | 3 +++ 6 files changed, 23 insertions(+), 3 deletions(-) diff --git a/app/layout/aside_flux.phtml b/app/layout/aside_flux.phtml index 817dae676..7eebc569b 100644 --- a/app/layout/aside_flux.phtml +++ b/app/layout/aside_flux.phtml @@ -1,4 +1,4 @@ -
    +
      @@ -41,11 +41,11 @@ foreach ($this->cat_aside as $cat) { $feeds = $cat->feeds (); if (!empty ($feeds)) { - ?>
    • get_c == $cat->id ()) { $c_active = true; } + ?>
    • >
      name (); ?>id (); $nbEntries = $feed->nbEntries (); $f_active = ($this->get_f == $feed_id); - ?>
    diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 7ca611b04..86c0a4ae4 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -121,10 +121,10 @@ function customSimplePie() { 'onmouseover', 'onmousemove', 'onmouseout', 'onfocus', 'onblur', 'onkeypress', 'onkeydown', 'onkeyup', 'onselect', 'onchange', 'seamless'))); $simplePie->add_attributes(array( - 'img' => array('lazyload' => ''), //http://www.w3.org/TR/resource-priorities/ - 'audio' => array('preload' => 'none'), - 'iframe' => array('postpone' => '', 'sandbox' => 'allow-scripts allow-same-origin'), - 'video' => array('postpone' => '', 'preload' => 'none'), + 'img' => array('lazyload' => '', 'postpone' => ''), //http://www.w3.org/TR/resource-priorities/ + 'audio' => array('lazyload' => '', 'postpone' => '', 'preload' => 'none'), + 'iframe' => array('lazyload' => '', 'postpone' => '', 'sandbox' => 'allow-scripts allow-same-origin'), + 'video' => array('lazyload' => '', 'postpone' => '', 'preload' => 'none'), )); $simplePie->set_url_replacements(array( 'a' => 'href', @@ -183,16 +183,8 @@ function get_content_by_parsing ($url, $path) { */ function lazyimg($content) { return preg_replace( - '/]+?)src=[\'"]([^"\']+)[\'"]([^>]*)>/i', - '', - $content - ); -} - -function lazyIframe($content) { - return preg_replace( - '/]+?)src=[\'"]([^"\']+)[\'"]([^>]*)>/i', - '', + '/<((?:img|iframe)[^>]+?)src=[\'"]([^"\']+)[\'"]([^>]*)>/i', + '<$1src="' . Minz_Url::display('/themes/icons/grey.gif') . '" data-original="$2"$3>', $content ); } diff --git a/p/scripts/jquery.lazyload.min.js b/p/scripts/jquery.lazyload.min.js deleted file mode 100644 index 8dd097dc3..000000000 --- a/p/scripts/jquery.lazyload.min.js +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Lazy Load - jQuery plugin for lazy loading images - * - * Copyright (c) 2007-2013 Mika Tuupola - * - * Licensed under the MIT license: - * http://www.opensource.org/licenses/mit-license.php - * - * Project home: - * http://www.appelsiini.net/projects/lazyload - * - * Version: 1.9.0 - * - */ -!function(a,b,c,d){var e=a(b);a.fn.lazyload=function(f){function g(){var b=0;i.each(function(){var c=a(this);if(!j.skip_invisible||c.is(":visible"))if(a.abovethetop(this,j)||a.leftofbegin(this,j));else if(a.belowthefold(this,j)||a.rightoffold(this,j)){if(++b>j.failure_limit)return!1}else c.trigger("appear"),b=0})}var h,i=this,j={threshold:0,failure_limit:0,event:"scroll",effect:"show",container:b,data_attribute:"original",skip_invisible:!0,appear:null,load:null,placeholder:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC"};return f&&(d!==f.failurelimit&&(f.failure_limit=f.failurelimit,delete f.failurelimit),d!==f.effectspeed&&(f.effect_speed=f.effectspeed,delete f.effectspeed),a.extend(j,f)),h=j.container===d||j.container===b?e:a(j.container),0===j.event.indexOf("scroll")&&h.bind(j.event,function(){return g()}),this.each(function(){var b=this,c=a(b);b.loaded=!1,(c.attr("src")===d||c.attr("src")===!1)&&c.attr("src",j.placeholder),c.one("appear",function(){if(!this.loaded){if(j.appear){var d=i.length;j.appear.call(b,d,j)}a("").bind("load",function(){var d=c.data(j.data_attribute);c.hide(),c.is("img")?c.attr("src",d):c.css("background-image","url('"+d+"')"),c[j.effect](j.effect_speed),b.loaded=!0;var e=a.grep(i,function(a){return!a.loaded});if(i=a(e),j.load){var f=i.length;j.load.call(b,f,j)}}).attr("src",c.data(j.data_attribute))}}),0!==j.event.indexOf("scroll")&&c.bind(j.event,function(){b.loaded||c.trigger("appear")})}),e.bind("resize",function(){g()}),/iphone|ipod|ipad.*os 5/gi.test(navigator.appVersion)&&e.bind("pageshow",function(b){b.originalEvent&&b.originalEvent.persisted&&i.each(function(){a(this).trigger("appear")})}),a(c).ready(function(){g()}),this},a.belowthefold=function(c,f){var g;return g=f.container===d||f.container===b?(b.innerHeight?b.innerHeight:e.height())+e.scrollTop():a(f.container).offset().top+a(f.container).height(),g<=a(c).offset().top-f.threshold},a.rightoffold=function(c,f){var g;return g=f.container===d||f.container===b?e.width()+e.scrollLeft():a(f.container).offset().left+a(f.container).width(),g<=a(c).offset().left-f.threshold},a.abovethetop=function(c,f){var g;return g=f.container===d||f.container===b?e.scrollTop():a(f.container).offset().top,g>=a(c).offset().top+f.threshold+a(c).height()},a.leftofbegin=function(c,f){var g;return g=f.container===d||f.container===b?e.scrollLeft():a(f.container).offset().left,g>=a(c).offset().left+f.threshold+a(c).width()},a.inviewport=function(b,c){return!(a.rightoffold(b,c)||a.leftofbegin(b,c)||a.belowthefold(b,c)||a.abovethetop(b,c))},a.extend(a.expr[":"],{"below-the-fold":function(b){return a.belowthefold(b,{threshold:0})},"above-the-top":function(b){return!a.belowthefold(b,{threshold:0})},"right-of-screen":function(b){return a.rightoffold(b,{threshold:0})},"left-of-screen":function(b){return!a.rightoffold(b,{threshold:0})},"in-viewport":function(b){return a.inviewport(b,{threshold:0})},"above-the-fold":function(b){return!a.belowthefold(b,{threshold:0})},"right-of-fold":function(b){return a.rightoffold(b,{threshold:0})},"left-of-fold":function(b){return!a.rightoffold(b,{threshold:0})}})}(jQuery,window,document); \ No newline at end of file diff --git a/p/scripts/main.js b/p/scripts/main.js index b6214e508..acb7bd527 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -421,21 +421,7 @@ function inMarkViewport(flux, box_to_follow, relative_follow) { return (windowBot >= begin && bot >= windowBot); } -function init_lazyload() { - if ($.fn.lazyload) { - if (is_global_mode()) { - $(".flux_content img").lazyload({ - container: $("#panel") - }); - } else { - $(".flux_content img").lazyload(); - } - } -} - function init_posts() { - init_lazyload(); - var box_to_follow = $(window), relative_follow = false; if (is_global_mode()) { @@ -827,7 +813,6 @@ function load_more_posts() { }); init_load_more(box_load_more); - init_lazyload(); $('#load_more').removeClass('loading'); load_more = false; @@ -841,6 +826,12 @@ function focus_search() { function init_load_more(box) { box_load_more = box; + if (!does_lazyload) { + $('img[postpone], audio[postpone], iframe[postpone], video[postpone]').each(function () { + this.removeAttribute('postpone'); + }); + } + var $next_link = $("#load_more"); if (!$next_link.length) { // no more article to load @@ -1093,7 +1084,7 @@ function faviconNbUnread(n) { ctx.fillStyle = 'rgba(255, 255, 255, 127)'; ctx.fillRect(0, 8, 1 + ctx.measureText(text).width, 7); ctx.fillStyle = '#F00'; - ctx.fillText(text, 0, 16); + ctx.fillText(text, 0, canvas.height); } link.href = canvas.toDataURL('image/png'); $('link[rel~=icon]').remove(); @@ -1104,7 +1095,7 @@ function faviconNbUnread(n) { } function init_all() { - if (!(window.$ && window.url_freshrss && ((!full_lazyload) || $.fn.lazyload))) { + if (!(window.$ && window.url_freshrss)) { if (window.console) { console.log('FreshRSS waiting for JS…'); } -- cgit v1.2.3 From a9a61929485279c819d42b7a2d65b8a1f5e2cfdd Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 2 Aug 2014 20:29:51 +0200 Subject: Unicode tick without colour https://github.com/marienfressinaud/FreshRSS/issues/560 The former was green in Firefox 32 beta --- app/views/helpers/pagination.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/helpers/pagination.phtml b/app/views/helpers/pagination.phtml index f38913c06..f237e1f3e 100755 --- a/app/views/helpers/pagination.phtml +++ b/app/views/helpers/pagination.phtml @@ -14,7 +14,7 @@ conf->reading_confirm) { echo ' class="confirm"';} ?>>
    -
    +
    -- cgit v1.2.3 From e05e9a87021862b334bccedb3d2383e9fa568a9b Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sun, 3 Aug 2014 08:47:18 -0400 Subject: Refactor install file to check available databases Now it checks for any pdo driver supported instead of only mysql --- app/i18n/install.en.php | 4 ++-- app/i18n/install.fr.php | 4 ++-- app/install.php | 18 +++++++++++++----- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/app/i18n/install.en.php b/app/i18n/install.en.php index 553a79921..50208fcef 100644 --- a/app/i18n/install.en.php +++ b/app/i18n/install.en.php @@ -28,8 +28,8 @@ return array ( 'minz_is_nok' => 'You lack the Minz framework. You should execute build.sh script or download it on Github and install in %s directory the content of its /lib directory.', 'curl_is_ok' => 'You have version %s of cURL', 'curl_is_nok' => 'You lack cURL (php5-curl package)', - 'pdomysql_is_ok' => 'You have PDO and its driver for MySQL', - 'pdomysql_is_nok' => 'You lack PDO or its driver for MySQL (php5-mysql package)', + 'pdo_is_ok' => 'You have PDO and at least one of the supported drivers (pdo_mysql, pdo_sqlite)', + 'pdo_is_nok' => 'You lack PDO or one of the supported drivers (pdo_mysql, pdo_sqlite)', 'dom_is_ok' => 'You have the required library to browse the DOM', 'dom_is_nok' => 'You lack a required library to browse the DOM (php-xml package)', 'pcre_is_ok' => 'You have the required library for regular expressions (PCRE)', diff --git a/app/i18n/install.fr.php b/app/i18n/install.fr.php index 470d83e1a..9c039f904 100644 --- a/app/i18n/install.fr.php +++ b/app/i18n/install.fr.php @@ -28,8 +28,8 @@ return array ( 'minz_is_nok' => 'Vous ne disposez pas de la librairie Minz. Vous devriez exécuter le script build.sh ou bien la télécharger sur Github et installer dans le répertoire %s le contenu de son répertoire /lib.', 'curl_is_ok' => 'Vous disposez de cURL dans sa version %s', 'curl_is_nok' => 'Vous ne disposez pas de cURL (paquet php5-curl)', - 'pdomysql_is_ok' => 'Vous disposez de PDO et de son driver pour MySQL (paquet php5-mysql)', - 'pdomysql_is_nok' => 'Vous ne disposez pas de PDO ou de son driver pour MySQL', + 'pdo_is_ok' => 'Vous disposez de PDO et d’au moins un des drivers supportés (pdo_mysql, pdo_sqlite)', + 'pdo_is_nok' => 'Vous ne disposez pas de PDO ou d’un des drivers supportés (pdo_mysql, pdo_sqlite)', 'dom_is_ok' => 'Vous disposez du nécessaire pour parcourir le DOM', 'dom_is_nok' => 'Il manque une librairie pour parcourir le DOM (paquet php-xml)', 'pcre_is_ok' => 'Vous disposez du nécessaire pour les expressions régulières (PCRE)', diff --git a/app/install.php b/app/install.php index 66d663114..eaa1100c1 100644 --- a/app/install.php +++ b/app/install.php @@ -574,7 +574,9 @@ function checkStep1 () { $php = version_compare (PHP_VERSION, '5.2.1') >= 0; $minz = file_exists (LIB_PATH . '/Minz'); $curl = extension_loaded ('curl'); - $pdo = extension_loaded ('pdo_mysql'); + $pdo_mysql = extension_loaded ('pdo_mysql'); + $pdo_sqlite = extension_loaded ('pdo_sqlite'); + $pdo = $pdo_mysql || $pdo_sqlite; $pcre = extension_loaded ('pcre'); $ctype = extension_loaded ('ctype'); $dom = class_exists('DOMDocument'); @@ -588,7 +590,9 @@ function checkStep1 () { 'php' => $php ? 'ok' : 'ko', 'minz' => $minz ? 'ok' : 'ko', 'curl' => $curl ? 'ok' : 'ko', - 'pdo-mysql' => $pdo ? 'ok' : 'ko', + 'pdo-mysql' => $pdo_mysql ? 'ok' : 'ko', + 'pdo-sqlite' => $pdo_sqlite ? 'ok' : 'ko', + 'pdo' => $pdo ? 'ok' : 'ko', 'pcre' => $pcre ? 'ok' : 'ko', 'ctype' => $ctype ? 'ok' : 'ko', 'dom' => $dom ? 'ok' : 'ko', @@ -766,10 +770,10 @@ function printStep1 () {

    - -

    + +

    -

    +

    @@ -923,14 +927,18 @@ function printStep3 () {
    -- cgit v1.2.3 From 6ef9fc7a92e494c4c64189762053ef39fdfbb786 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 3 Aug 2014 20:20:54 +0200 Subject: Minor change dynamic favicon https://github.com/marienfressinaud/FreshRSS/issues/539 --- p/scripts/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p/scripts/main.js b/p/scripts/main.js index acb7bd527..762b2e58e 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -1078,7 +1078,7 @@ function faviconNbUnread(n) { } else if (n < 100000) { text = Math.floor(n / 1000) + 'k'; } else { - text = 'E' + Math.min(99, Math.floor(Math.log10(n))); + text = 'E' + Math.floor(Math.log10(n)); } ctx.font = 'bold 9px "Arial", sans-serif'; ctx.fillStyle = 'rgba(255, 255, 255, 127)'; -- cgit v1.2.3 From 6972a469794a654c6ecd6b32b68a813e1c47f7ec Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 6 Aug 2014 20:41:47 +0200 Subject: Dynamic favicon all unread articles https://github.com/marienfressinaud/FreshRSS/issues/539 --- p/scripts/main.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/p/scripts/main.js b/p/scripts/main.js index 762b2e58e..7a85be9c6 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -1060,7 +1060,10 @@ function init_password_observers() { function faviconNbUnread(n) { if (typeof n === 'undefined') { - n = str2int($('.category.all>a').attr('data-unread')); + n = 0; + $('.feed[data-unread]').each(function() { + n += str2int(this.getAttribute('data-unread')); + }); } //http://remysharp.com/2010/08/24/dynamic-favicons/ var canvas = document.createElement('canvas'), -- cgit v1.2.3 From 65d6796e9244bbc94f5d04cf47723a533b6a5351 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 7 Aug 2014 11:29:19 +0200 Subject: First bug for old articles first https://github.com/marienfressinaud/FreshRSS/issues/495 --- app/Models/EntryDAO.php | 6 +++--- app/Models/EntryDAOSQLite.php | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 74b5306e9..a9ffa138b 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -175,7 +175,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { public function markReadEntries($idMax = 0, $onlyFavorites = false, $priorityMin = 0) { if ($idMax == 0) { $idMax = time() . '000000'; - Minz_Log::record($nb . 'Calling markReadEntries(0) is deprecated!', Minz_Log::DEBUG); + Minz_Log::record('Calling markReadEntries(0) is deprecated!', Minz_Log::DEBUG); } $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed=f.id ' @@ -203,7 +203,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { public function markReadCat($id, $idMax = 0) { if ($idMax == 0) { $idMax = time() . '000000'; - Minz_Log::record($nb . 'Calling markReadCat(0) is deprecated!', Minz_Log::DEBUG); + Minz_Log::record('Calling markReadCat(0) is deprecated!', Minz_Log::DEBUG); } $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed=f.id ' @@ -226,7 +226,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { public function markReadFeed($id, $idMax = 0) { if ($idMax == 0) { $idMax = time() . '000000'; - Minz_Log::record($nb . 'Calling markReadFeed(0) is deprecated!', Minz_Log::DEBUG); + Minz_Log::record('Calling markReadFeed(0) is deprecated!', Minz_Log::DEBUG); } $this->bd->beginTransaction(); diff --git a/app/Models/EntryDAOSQLite.php b/app/Models/EntryDAOSQLite.php index 3dabce4b2..9dc395c3c 100644 --- a/app/Models/EntryDAOSQLite.php +++ b/app/Models/EntryDAOSQLite.php @@ -72,7 +72,7 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { public function markReadEntries($idMax = 0, $onlyFavorites = false, $priorityMin = 0) { if ($idMax == 0) { $idMax = time() . '000000'; - Minz_Log::record($nb . 'Calling markReadEntries(0) is deprecated!', Minz_Log::DEBUG); + Minz_Log::record('Calling markReadEntries(0) is deprecated!', Minz_Log::DEBUG); } $sql = 'UPDATE `' . $this->prefix . 'entry` SET is_read=1 WHERE is_read=0 AND id <= ?'; @@ -98,7 +98,7 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { public function markReadCat($id, $idMax = 0) { if ($idMax == 0) { $idMax = time() . '000000'; - Minz_Log::record($nb . 'Calling markReadCat(0) is deprecated!', Minz_Log::DEBUG); + Minz_Log::record('Calling markReadCat(0) is deprecated!', Minz_Log::DEBUG); } $sql = 'UPDATE `' . $this->prefix . 'entry` ' -- cgit v1.2.3 From 83b8af59e506b4c0f0784e767ed3da633243406e Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 7 Aug 2014 20:34:08 +0200 Subject: Revert "Dynamic favicon all unread articles" This reverts commit 6972a469794a654c6ecd6b32b68a813e1c47f7ec. --- p/scripts/main.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/p/scripts/main.js b/p/scripts/main.js index 7a85be9c6..762b2e58e 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -1060,10 +1060,7 @@ function init_password_observers() { function faviconNbUnread(n) { if (typeof n === 'undefined') { - n = 0; - $('.feed[data-unread]').each(function() { - n += str2int(this.getAttribute('data-unread')); - }); + n = str2int($('.category.all>a').attr('data-unread')); } //http://remysharp.com/2010/08/24/dynamic-favicons/ var canvas = document.createElement('canvas'), -- cgit v1.2.3 From eed05c06e98b22d5d68e21028dc22956c86ba75f Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 7 Aug 2014 21:33:38 +0200 Subject: Dynamic favicon style A bit more transparency in the background of the text https://github.com/marienfressinaud/FreshRSS/issues/539 --- p/scripts/main.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/p/scripts/main.js b/p/scripts/main.js index 762b2e58e..9b47e52d2 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -1081,10 +1081,10 @@ function faviconNbUnread(n) { text = 'E' + Math.floor(Math.log10(n)); } ctx.font = 'bold 9px "Arial", sans-serif'; - ctx.fillStyle = 'rgba(255, 255, 255, 127)'; - ctx.fillRect(0, 8, 1 + ctx.measureText(text).width, 7); + ctx.fillStyle = 'rgba(255, 255, 255, 0.8)'; + ctx.fillRect(0, 7, 1 + ctx.measureText(text).width, 9); ctx.fillStyle = '#F00'; - ctx.fillText(text, 0, canvas.height); + ctx.fillText(text, 0, canvas.height - 1); } link.href = canvas.toDataURL('image/png'); $('link[rel~=icon]').remove(); -- cgit v1.2.3 From a7632b54293100d71a6eadfcb98746da05358ddb Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 7 Aug 2014 21:45:52 +0200 Subject: Dynamic favicon style 2 https://github.com/marienfressinaud/FreshRSS/issues/539 --- p/scripts/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p/scripts/main.js b/p/scripts/main.js index 9b47e52d2..a82450e7f 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -1082,7 +1082,7 @@ function faviconNbUnread(n) { } ctx.font = 'bold 9px "Arial", sans-serif'; ctx.fillStyle = 'rgba(255, 255, 255, 0.8)'; - ctx.fillRect(0, 7, 1 + ctx.measureText(text).width, 9); + ctx.fillRect(0, 7, ctx.measureText(text).width, 9); ctx.fillStyle = '#F00'; ctx.fillText(text, 0, canvas.height - 1); } -- cgit v1.2.3 From e08e8ee633fab138c18636d787b3515011acf160 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Fri, 8 Aug 2014 07:35:13 -0400 Subject: Change event handling for confirmation dialog See #567 Before, when content was loaded dynamically, the confirmation was not poping. Now, the confirmation pops by changing event handling. --- p/scripts/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p/scripts/main.js b/p/scripts/main.js index a82450e7f..a1628df85 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -973,7 +973,7 @@ function init_persona() { // function init_confirm_action() { - $('.confirm').click(function () { + $('body').on('click', '.confirm', function () { return confirm(str_confirmation); }); } -- cgit v1.2.3 From d289c5340f3b21f1561e57390e89b0b5c7881d17 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 8 Aug 2014 21:30:23 +0200 Subject: Add support of HTML5 notifications Show a notification if there are at least 1 new article to read. Support only window.Notification API. See https://github.com/marienfressinaud/FreshRSS/issues/399 --- app/i18n/en.php | 2 ++ app/i18n/fr.php | 2 ++ app/views/helpers/javascript_vars.phtml | 2 ++ p/scripts/main.js | 48 ++++++++++++++++++++++++++++++++- 4 files changed, 53 insertions(+), 1 deletion(-) diff --git a/app/i18n/en.php b/app/i18n/en.php index 10327c7f5..9e5bfb223 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -343,6 +343,8 @@ return array ( 'login_required' => 'Login required:', 'confirm_action' => 'Are you sure you want to perform this action? It cannot be cancelled!', + 'notif_title_new_articles' => 'FreshRSS: new articles!', + 'notif_body_new_articles' => 'There are \d new articles to read on FreshRSS.', // DATE 'january' => 'January', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 6ab3d7335..94d2e5f06 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -343,6 +343,8 @@ return array ( 'login_required' => 'Accès protégé par mot de passe :', 'confirm_action' => 'Êtes-vous sûr(e) de vouloir continuer ? Cette action ne peut être annulée !', + 'notif_title_new_articles' => 'FreshRSS : nouveaux articles !', + 'notif_body_new_articles' => 'Il y a \d nouveaux articles à lire sur FreshRSS.', // DATE 'january' => 'janvier', diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index a04d3d527..7144c519a 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -49,6 +49,8 @@ echo 'authType="', $authType, '",', 'url_logout="', _url ('index', 'logout'), '",'; echo 'str_confirmation="', Minz_Translate::t('confirm_action'), '"', ",\n"; +echo 'str_notif_title_articles="', Minz_Translate::t('notif_title_new_articles'), '"', ",\n"; +echo 'str_notif_body_articles="', Minz_Translate::t('notif_body_new_articles'), '"', ",\n"; $autoActualise = Minz_Session::param('actualize_feeds', false); echo 'auto_actualize_feeds=', $autoActualise ? 'true' : 'false', ";\n"; diff --git a/p/scripts/main.js b/p/scripts/main.js index a82450e7f..bd412d6e9 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -768,6 +768,46 @@ function init_notifications() { } // +// +var notifs_html5_permission = 'denied', + notifs_html5_shown = false; + +function notifs_html5_is_supported() { + return window.Notification !== undefined; +} + +function notifs_html5_ask_permission() { + window.Notification.requestPermission(function () { + notifs_html5_permission = window.Notification.permission; + }); +} + +function notifs_html5_show(nb) { + if (notifs_html5_permission !== "granted" || notifs_html5_shown) { + return + } + + var notification = new window.Notification(str_notif_title_articles, { + icon: "../themes/icons/favicon-256.png", + body: str_notif_body_articles.replace("\d", nb) + }); + + notification.onclick = function() { + window.location.reload(); + } + + notifs_html5_shown = true; +} + +function init_notifs_html5() { + if (!notifs_html5_is_supported()) { + return; + } + + notifs_html5_permission = notifs_html5_ask_permission(); +} +// + function refreshUnreads() { $.getJSON('./?c=javascript&a=nbUnreadsPerFeed').done(function (data) { var isAll = $('.category.all > .active').length > 0; @@ -780,7 +820,12 @@ function refreshUnreads() { $('#new-article').show(); }; }); - faviconNbUnread(); + + var nb_unreads = str2int($('.category.all>a').attr('data-unread')); + if (nb_unreads > 0) { + faviconNbUnread(nb_unreads); + notifs_html5_show(nb_unreads); + } }); } @@ -1123,6 +1168,7 @@ function init_all() { init_shortcuts(); faviconNbUnread(); init_print_action(); + init_notifs_html5(); window.setInterval(refreshUnreads, 120000); } else { init_share_observers(); -- cgit v1.2.3 From 84826491a3fac3bde21c07ad69b114e5b56ed297 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 8 Aug 2014 23:53:16 +0200 Subject: Improve export function If there is only one file to export, we don't need of a .zip archive. So it is exported as a simple file (.json or .opml) See https://github.com/marienfressinaud/FreshRSS/issues/494 --- app/Controllers/importExportController.php | 74 ++++++++++++++++++++---------- app/views/importExport/export.phtml | 0 2 files changed, 51 insertions(+), 23 deletions(-) create mode 100644 app/views/importExport/export.phtml diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index ba172cc6d..67c6eb867 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -316,39 +316,42 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $export_opml = Minz_Request::param('export_opml', false); $export_starred = Minz_Request::param('export_starred', false); - $export_feeds = Minz_Request::param('export_feeds', false); + $export_feeds = Minz_Request::param('export_feeds', array ()); - // From https://stackoverflow.com/questions/1061710/php-zip-files-on-the-fly - $file = tempnam('tmp', 'zip'); - $zip = new ZipArchive(); - $zip->open($file, ZipArchive::OVERWRITE); - - // Stuff with content + $export_files = array (); if ($export_opml) { - $zip->addFromString( - 'feeds.opml', $this->generateOpml() - ); + $export_files['feeds.opml'] = $this->generateOpml(); } + if ($export_starred) { - $zip->addFromString( - 'starred.json', $this->generateArticles('starred') - ); + $export_files['starred.json'] = $this->generateArticles('starred'); } + foreach ($export_feeds as $feed_id) { $feed = $this->feedDAO->searchById($feed_id); - $zip->addFromString( - 'feed_' . $feed->category() . '_' . $feed->id() . '.json', - $this->generateArticles('feed', $feed) + $filename = 'feed_' . $feed->category() . '_' + . $feed->id() . '.json'; + $export_files[$filename] = $this->generateArticles( + 'feed', $feed ); } - // Close and send to user - $zip->close(); - header('Content-Type: application/zip'); - header('Content-Length: ' . filesize($file)); - header('Content-Disposition: attachment; filename="freshrss_export.zip"'); - readfile($file); - unlink($file); + $nb_files = count($export_files); + if ($nb_files > 1) { + // If there are more than 1 file to export, we need an .zip + $this->exportZip($export_files); + } elseif ($nb_files === 1) { + // Only one file? Guess its type and export it. + $filename = key($export_files); + $type = null; + if (substr_compare($filename, '.opml', -5) === 0) { + $type = "text/xml"; + } elseif (substr_compare($filename, '.json', -5) === 0) { + $type = "text/json"; + } + + $this->exportFile($filename, $export_files[$filename], $type); + } } } @@ -388,4 +391,29 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { return $this->view->helperToString('export/articles'); } + + private function exportZip($files) { + // From https://stackoverflow.com/questions/1061710/php-zip-files-on-the-fly + $zip_file = tempnam('tmp', 'zip'); + $zip = new ZipArchive(); + $zip->open($zip_file, ZipArchive::OVERWRITE); + + foreach ($files as $filename => $content) { + $zip->addFromString($filename, $content); + } + + // Close and send to user + $zip->close(); + header('Content-Type: application/zip'); + header('Content-Length: ' . filesize($zip_file)); + header('Content-Disposition: attachment; filename="freshrss_export.zip"'); + readfile($zip_file); + unlink($zip_file); + } + + private function exportFile($filename, $content, $type) { + header('Content-Type: ' . $type . '; charset=utf-8'); + header('Content-disposition: attachment; filename=' . $filename); + print($content); + } } diff --git a/app/views/importExport/export.phtml b/app/views/importExport/export.phtml new file mode 100644 index 000000000..e69de29bb -- cgit v1.2.3 From fda8eba4d147a7624f64c03001df1d317804c0d4 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sat, 9 Aug 2014 00:12:37 +0200 Subject: Add a test to check presence of Zip archive. A notification is shown if we cannot use ZipArchive. See https://github.com/marienfressinaud/FreshRSS/issues/494 --- app/Controllers/importExportController.php | 22 +++++++++++++++++++++- app/i18n/en.php | 1 + app/i18n/fr.php | 1 + 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index 67c6eb867..ba4ca4eb0 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -339,7 +339,17 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $nb_files = count($export_files); if ($nb_files > 1) { // If there are more than 1 file to export, we need an .zip - $this->exportZip($export_files); + try { + $this->exportZip($export_files); + } catch (Exception $e) { + # Oops, there is no Zip extension! + $notif = array( + 'type' => 'bad', + 'content' => _t('export_no_zip_extension') + ); + Minz_Session::_param('notification', $notif); + Minz_Request::forward(array('c' => 'importExport'), true); + } } elseif ($nb_files === 1) { // Only one file? Guess its type and export it. $filename = key($export_files); @@ -351,6 +361,8 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { } $this->exportFile($filename, $export_files[$filename], $type); + } else { + Minz_Request::forward(array('c' => 'importExport'), true); } } } @@ -393,6 +405,10 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { } private function exportZip($files) { + if (!extension_loaded('zip')) { + throw new Exception(); + } + // From https://stackoverflow.com/questions/1061710/php-zip-files-on-the-fly $zip_file = tempnam('tmp', 'zip'); $zip = new ZipArchive(); @@ -412,6 +428,10 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { } private function exportFile($filename, $content, $type) { + if (is_null($type)) { + return; + } + header('Content-Type: ' . $type . '; charset=utf-8'); header('Content-disposition: attachment; filename=' . $filename); print($content); diff --git a/app/i18n/en.php b/app/i18n/en.php index 9e5bfb223..532327e4a 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -185,6 +185,7 @@ return array ( 'export' => 'Export', 'export_opml' => 'Export list of feeds (OPML)', 'export_starred' => 'Export your favourites', + 'export_no_zip_extension' => 'Zip extension is not present on your server. Please try to export files one by one.', 'starred_list' => 'List of favourite articles', 'feed_list' => 'List of %s articles', 'or' => 'or', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 94d2e5f06..1f2844d47 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -185,6 +185,7 @@ return array ( 'export' => 'Exporter', 'export_opml' => 'Exporter la liste des flux (OPML)', 'export_starred' => 'Exporter les favoris', + 'export_no_zip_extension' => 'L’extension Zip n’est pas présente sur votre serveur. Veuillez essayer d’exporter les fichiers un par un.', 'starred_list' => 'Liste des articles favoris', 'feed_list' => 'Liste des articles de %s', 'or' => 'ou', -- cgit v1.2.3 From d007b22beb701b78968db420c3be6336ee98a350 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sat, 9 Aug 2014 00:23:22 +0200 Subject: Change view import/export if no zip extension Show a select with only one choice is there is no zip extension on the server. Fix typo. See https://github.com/marienfressinaud/FreshRSS/issues/494 --- app/Controllers/importExportController.php | 12 +++++++----- app/views/importExport/index.phtml | 27 +++++++++++++++++---------- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index ba4ca4eb0..2b3353d93 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -329,11 +329,13 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { foreach ($export_feeds as $feed_id) { $feed = $this->feedDAO->searchById($feed_id); - $filename = 'feed_' . $feed->category() . '_' - . $feed->id() . '.json'; - $export_files[$filename] = $this->generateArticles( - 'feed', $feed - ); + if ($feed) { + $filename = 'feed_' . $feed->category() . '_' + . $feed->id() . '.json'; + $export_files[$filename] = $this->generateArticles( + 'feed', $feed + ); + } } $nb_files = count($export_files); diff --git a/app/views/importExport/index.phtml b/app/views/importExport/index.phtml index 309058959..d7df1619d 100644 --- a/app/views/importExport/index.phtml +++ b/app/views/importExport/index.phtml @@ -1,12 +1,12 @@ -partial ('aside_feed'); ?> +partial('aside_feed'); ?>
    - +
    - +
    - +
    @@ -14,27 +14,34 @@
    - +
    feeds) > 0) { ?>
    - +
    - > + '; ?> feeds as $feed) { ?> @@ -44,7 +51,7 @@
    - +
    -- cgit v1.2.3 From 773d73314bf1f6e6c2ddec33a324d0aef6e8155b Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sat, 9 Aug 2014 00:35:06 +0200 Subject: Fix typo Oops? :) --- app/views/importExport/index.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/importExport/index.phtml b/app/views/importExport/index.phtml index d7df1619d..96cd2b4e7 100644 --- a/app/views/importExport/index.phtml +++ b/app/views/importExport/index.phtml @@ -41,7 +41,7 @@ } ?> + /> feeds)); ?>" multiple="multiple"'; + $select_args = ' size="' . min(10, count($this->feeds)) .'" multiple="multiple"'; } ?> - > + '; ?> feeds as $feed) { ?> -- cgit v1.2.3 From c81be3c20aab4eb1773a0acd99d4aa5a9e30c4d6 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sat, 9 Aug 2014 15:26:12 +0200 Subject: Fix problem token Token was present in RSS url even without token value. --- app/layout/nav_menu.phtml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/layout/nav_menu.phtml b/app/layout/nav_menu.phtml index 29ea9032c..73a921c5d 100644 --- a/app/layout/nav_menu.phtml +++ b/app/layout/nav_menu.phtml @@ -221,7 +221,9 @@ conf->token; + if ($this->conf->token) { + $url_output['params']['token'] = $this->conf->token; + } ?> -- cgit v1.2.3 From 2b25aa8f68dccf7001b965fc6c08c3a794ec6b04 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 9 Aug 2014 18:46:22 +0200 Subject: Option to hide (or not) feeds/categories with no unread article https://github.com/marienfressinaud/FreshRSS/issues/430 https://github.com/marienfressinaud/FreshRSS/issues/575 --- app/Controllers/configureController.php | 1 + app/Models/Configuration.php | 4 ++++ app/i18n/en.php | 1 + app/i18n/fr.php | 1 + app/layout/aside_flux.phtml | 2 +- app/views/configure/reading.phtml | 9 +++++++++ 6 files changed, 17 insertions(+), 1 deletion(-) diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 79f40b30b..0bf58880f 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -184,6 +184,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $this->view->conf->_default_view((int)Minz_Request::param('default_view', FreshRSS_Entry::STATE_ALL)); $this->view->conf->_auto_load_more(Minz_Request::param('auto_load_more', false)); $this->view->conf->_display_posts(Minz_Request::param('display_posts', false)); + $this->view->conf->_hide_read_feeds(Minz_Request::param('hide_read_feeds', false)); $this->view->conf->_onread_jump_next(Minz_Request::param('onread_jump_next', false)); $this->view->conf->_lazyload(Minz_Request::param('lazyload', false)); $this->view->conf->_sticky_post(Minz_Request::param('sticky_post', false)); diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php index 7596c54cd..2f47312c0 100644 --- a/app/Models/Configuration.php +++ b/app/Models/Configuration.php @@ -17,6 +17,7 @@ class FreshRSS_Configuration { 'default_view' => FreshRSS_Entry::STATE_NOT_READ, 'auto_load_more' => true, 'display_posts' => false, + 'hide_read_feeds' => true, 'onread_jump_next' => true, 'lazyload' => true, 'sticky_post' => true, @@ -141,6 +142,9 @@ class FreshRSS_Configuration { public function _display_posts ($value) { $this->data['display_posts'] = ((bool)$value) && $value !== 'no'; } + public function _hide_read_feeds($value) { + $this->data['hide_read_feeds'] = (bool)$value; + } public function _onread_jump_next ($value) { $this->data['onread_jump_next'] = ((bool)$value) && $value !== 'no'; } diff --git a/app/i18n/en.php b/app/i18n/en.php index 532327e4a..d80299b10 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -262,6 +262,7 @@ return array ( 'sort_order' => 'Sort order', 'auto_load_more' => 'Load next articles at the page bottom', 'display_articles_unfolded' => 'Show articles unfolded by default', + 'hide_read_feeds' => 'Hide categories & feeds with no unread article (only in “unread articles” display mode)', 'after_onread' => 'After “mark all as read”,', 'jump_next' => 'jump to next unread sibling (feed or category)', 'article_icons' => 'Article icons', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 0705d80b2..4be028ac3 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -262,6 +262,7 @@ return array ( 'sort_order' => 'Ordre de tri', 'auto_load_more' => 'Charger les articles suivants en bas de page', 'display_articles_unfolded' => 'Afficher les articles dépliés par défaut', + 'hide_read_feeds' => 'Cacher les catégories & flux sans article non-lu (uniquement en affichage “articles non lus”)', 'after_onread' => 'Après “marquer tout comme lu”,', 'jump_next' => 'sauter au prochain voisin non lu (flux ou catégorie)', 'article_icons' => 'Icônes d’article', diff --git a/app/layout/aside_flux.phtml b/app/layout/aside_flux.phtml index cc04e757c..aee8f8754 100644 --- a/app/layout/aside_flux.phtml +++ b/app/layout/aside_flux.phtml @@ -1,4 +1,4 @@ -
    +
      diff --git a/app/views/configure/reading.phtml b/app/views/configure/reading.phtml index d56726730..c0525f1ed 100644 --- a/app/views/configure/reading.phtml +++ b/app/views/configure/reading.phtml @@ -62,6 +62,15 @@
    +
    +
    + +
    +
    +