Kaynağa Gözat

Merge branch 'dev' into beta

Marien Fressinaud 11 yıl önce
ebeveyn
işleme
f0fb1fbb07
100 değiştirilmiş dosya ile 2896 ekleme ve 3229 silme
  1. 23 1
      CHANGELOG
  2. 229 91
      app/Controllers/configureController.php
  3. 4 0
      app/Controllers/entryController.php
  4. 19 3
      app/Controllers/feedController.php
  5. 20 8
      app/Controllers/importExportController.php
  6. 80 0
      app/Controllers/indexController.php
  7. 45 0
      app/Controllers/statsController.php
  8. 129 0
      app/Controllers/updateController.php
  9. 13 4
      app/FreshRSS.php
  10. 37 2
      app/Models/Configuration.php
  11. 1 0
      app/Models/Entry.php
  12. 2 0
      app/Models/EntryDAO.php
  13. 1 1
      app/Models/FeedDAO.php
  14. 69 0
      app/Models/StatsDAO.php
  15. 1 0
      app/Models/StatsDAOSQLite.php
  16. 1 0
      app/Models/Themes.php
  17. 45 8
      app/i18n/en.php
  18. 46 9
      app/i18n/fr.php
  19. 2 0
      app/i18n/install.en.php
  20. 2 0
      app/i18n/install.fr.php
  21. 246 509
      app/install.php
  22. 23 15
      app/layout/aside_configure.phtml
  23. 41 33
      app/layout/aside_flux.phtml
  24. 6 0
      app/layout/header.phtml
  25. 1 0
      app/layout/layout.phtml
  26. 101 74
      app/layout/nav_menu.phtml
  27. 7 1
      app/views/configure/categorize.phtml
  28. 7 0
      app/views/configure/display.phtml
  29. 18 12
      app/views/configure/feed.phtml
  30. 11 4
      app/views/configure/queries.phtml
  31. 12 8
      app/views/configure/reading.phtml
  32. 15 0
      app/views/configure/shortcut.phtml
  33. 8 3
      app/views/helpers/javascript_vars.phtml
  34. 26 15
      app/views/helpers/pagination.phtml
  35. 8 0
      app/views/helpers/view/global_view.phtml
  36. 3 3
      app/views/helpers/view/normal_view.phtml
  37. 3 3
      app/views/helpers/view/reader_view.phtml
  38. 10 3
      app/views/index/formLogin.phtml
  39. 33 0
      app/views/index/resetAuth.phtml
  40. 28 5
      app/views/stats/idle.phtml
  41. 24 24
      app/views/stats/index.phtml
  42. 51 15
      app/views/stats/repartition.phtml
  43. 9 0
      app/views/update/apply.phtml
  44. 36 0
      app/views/update/index.phtml
  45. 3 0
      constants.php
  46. 2 0
      data/.gitignore
  47. 3 0
      lib/Minz/ModelPdo.php
  48. 5 0
      lib/Minz/Request.php
  49. 11 4
      lib/Minz/View.php
  50. 1 1
      lib/SimplePie/SimplePie/Parser.php
  51. 14 0
      lib/lib_rss.php
  52. 131 40
      p/scripts/main.js
  53. 17 5
      p/themes/Dark/dark.css
  54. 1 1
      p/themes/Dark/metadata.json
  55. 0 698
      p/themes/Dark/template.css
  56. 33 7
      p/themes/Flat/flat.css
  57. 1 1
      p/themes/Flat/metadata.json
  58. 0 698
      p/themes/Flat/template.css
  59. 1 1
      p/themes/Origine/metadata.json
  60. 20 12
      p/themes/Origine/origine.css
  61. 0 698
      p/themes/Origine/template.css
  62. 4 0
      p/themes/Pafat/README.md
  63. 7 0
      p/themes/Pafat/icons/all.svg
  64. 5 0
      p/themes/Pafat/icons/bookmark.svg
  65. 1 1
      p/themes/Pafat/icons/down.svg
  66. 2 2
      p/themes/Pafat/icons/icon.svg
  67. 4 0
      p/themes/Pafat/icons/link.svg
  68. 2 2
      p/themes/Pafat/icons/login.svg
  69. 2 2
      p/themes/Pafat/icons/logout.svg
  70. 1 1
      p/themes/Pafat/icons/next.svg
  71. 2 0
      p/themes/Pafat/icons/non-starred.svg
  72. 5 0
      p/themes/Pafat/icons/prev.svg
  73. 5 0
      p/themes/Pafat/icons/read.svg
  74. 1 1
      p/themes/Pafat/icons/share.svg
  75. 5 0
      p/themes/Pafat/icons/starred.svg
  76. 1 1
      p/themes/Pafat/icons/tag.svg
  77. 6 0
      p/themes/Pafat/icons/unread.svg
  78. 5 0
      p/themes/Pafat/icons/up.svg
  79. BIN
      p/themes/Pafat/loader.gif
  80. 7 0
      p/themes/Pafat/metadata.json
  81. 1084 0
      p/themes/Pafat/pafat.css
  82. 0 5
      p/themes/Screwdriver/icons/add.svg
  83. 0 7
      p/themes/Screwdriver/icons/all.svg
  84. BIN
      p/themes/Screwdriver/icons/apple-touch-icon.png
  85. 0 6
      p/themes/Screwdriver/icons/bookmark-add.svg
  86. 5 60
      p/themes/Screwdriver/icons/bookmark.svg
  87. 0 7
      p/themes/Screwdriver/icons/category-white.svg
  88. 0 7
      p/themes/Screwdriver/icons/category.svg
  89. 0 7
      p/themes/Screwdriver/icons/close.svg
  90. 0 5
      p/themes/Screwdriver/icons/configure.svg
  91. BIN
      p/themes/Screwdriver/icons/favicon-16-32-48-64.ico
  92. BIN
      p/themes/Screwdriver/icons/favicon-256.png
  93. 0 13
      p/themes/Screwdriver/icons/favicon.svg
  94. BIN
      p/themes/Screwdriver/icons/grey.gif
  95. 0 7
      p/themes/Screwdriver/icons/help.svg
  96. 0 7
      p/themes/Screwdriver/icons/key.svg
  97. 0 4
      p/themes/Screwdriver/icons/link.svg
  98. 0 2
      p/themes/Screwdriver/icons/non-starred.svg
  99. 0 5
      p/themes/Screwdriver/icons/prev.svg
  100. 3 57
      p/themes/Screwdriver/icons/read.svg

+ 23 - 1
CHANGELOG

@@ -1,6 +1,28 @@
 # Journal des modifications
 # Journal des modifications
 
 
-## 2014-08-xx FreshRSS 0.7.4
+## 2014-09-xx FreshRSS 0.8.0
+
+* UI
+	* New interface for statistics
+	* Fix filter buttons
+	* Number of articles divided by 2 in reading view
+	* Redesign of bigMarkAsRead
+* Features
+	* New automatic update system
+	* New reset auth system
+* Security
+	* "Mark as read" requires POST requests for several articles
+	* Test HTTP REFERER in install.php
+* Configuration
+	* New "Show all articles" / "Show only unread" / "Adjust viewing" option
+	* New notification timeout option
+* Misc.
+	* Improve coding style + comments
+	* Fix SQLite bug "ON DELETE CASCADE"
+	* Improve performance when importing articles
+
+
+## 2014-08-24 FreshRSS 0.7.4
 
 
 * UI
 * UI
 	* Hide categories/feeds with unread articles when showing only unread articles
 	* Hide categories/feeds with unread articles when showing only unread articles

+ 229 - 91
app/Controllers/configureController.php

@@ -1,11 +1,22 @@
 <?php
 <?php
 
 
+/**
+ * Controller to handle every configuration options.
+ */
 class FreshRSS_configure_Controller extends Minz_ActionController {
 class FreshRSS_configure_Controller extends Minz_ActionController {
+	/**
+	 * This action is called before every other action in that class. It is
+	 * the common boiler plate for every action. It is triggered by the
+	 * underlying framework.
+	 *
+	 * @todo see if the category default configuration is needed here or if
+	 *       we can move it to the categorize action
+	 */
 	public function firstAction() {
 	public function firstAction() {
 		if (!$this->view->loginOk) {
 		if (!$this->view->loginOk) {
 			Minz_Error::error(
 			Minz_Error::error(
 				403,
 				403,
-				array('error' => array(Minz_Translate::t('access_denied')))
+				array('error' => array(_t('access_denied')))
 			);
 			);
 		}
 		}
 
 
@@ -13,6 +24,18 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
 		$catDAO->checkDefault();
 		$catDAO->checkDefault();
 	}
 	}
 
 
+	/**
+	 * This action handles the category configuration page
+	 *
+	 * It displays the category configuration page.
+	 * If this action is reached through a POST request, it loops through
+	 * every category to check for modification then add a new category if
+	 * needed then sends a notification to the user.
+	 * If a category name is emptied, the category is deleted and all
+	 * related feeds are moved to the default category. Related user queries
+	 * are deleted too.
+	 * If a category name is changed, it is updated.
+	 */
 	public function categorizeAction() {
 	public function categorizeAction() {
 		$feedDAO = FreshRSS_Factory::createFeedDao();
 		$feedDAO = FreshRSS_Factory::createFeedDao();
 		$catDAO = new FreshRSS_CategoryDAO();
 		$catDAO = new FreshRSS_CategoryDAO();
@@ -34,6 +57,10 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
 				} elseif ($ids[$key] != $defaultId) {
 				} elseif ($ids[$key] != $defaultId) {
 					$feedDAO->changeCategory($ids[$key], $defaultId);
 					$feedDAO->changeCategory($ids[$key], $defaultId);
 					$catDAO->deleteCategory($ids[$key]);
 					$catDAO->deleteCategory($ids[$key]);
+
+					// Remove related queries.
+					$this->view->conf->remove_query_by_get('c_' . $ids[$key]);
+					$this->view->conf->save();
 				}
 				}
 			}
 			}
 
 
@@ -50,22 +77,37 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
 			}
 			}
 			invalidateHttpCache();
 			invalidateHttpCache();
 
 
-			$notif = array(
-				'type' => 'good',
-				'content' => Minz_Translate::t('categories_updated')
-			);
-			Minz_Session::_param('notification', $notif);
-
-			Minz_Request::forward(array('c' => 'configure', 'a' => 'categorize'), true);
+			Minz_Request::good(_t('categories_updated'),
+			                   array('c' => 'configure', 'a' => 'categorize'));
 		}
 		}
 
 
 		$this->view->categories = $catDAO->listCategories(false);
 		$this->view->categories = $catDAO->listCategories(false);
 		$this->view->defaultCategory = $catDAO->getDefault();
 		$this->view->defaultCategory = $catDAO->getDefault();
 		$this->view->feeds = $feedDAO->listFeeds();
 		$this->view->feeds = $feedDAO->listFeeds();
 
 
-		Minz_View::prependTitle(Minz_Translate::t('categories_management') . ' · ');
+		Minz_View::prependTitle(_t('categories_management') . ' · ');
 	}
 	}
 
 
+	/**
+	 * This action handles the feed configuration page.
+	 *
+	 * It displays the feed configuration page.
+	 * If this action is reached through a POST request, it stores all new
+	 * configuraiton values then sends a notification to the user.
+	 *
+	 * The options available on the page are:
+	 *   - name
+	 *   - description
+	 *   - website URL
+	 *   - feed URL
+	 *   - category id (default: default category id)
+	 *   - CSS path to article on website
+	 *   - display in main stream (default: 0)
+	 *   - HTTP authentication
+	 *   - number of article to retain (default: -2)
+	 *   - refresh frequency (default: -2)
+	 * Default values are empty strings unless specified.
+	 */
 	public function feedAction() {
 	public function feedAction() {
 		$catDAO = new FreshRSS_CategoryDAO();
 		$catDAO = new FreshRSS_CategoryDAO();
 		$this->view->categories = $catDAO->listCategories(false);
 		$this->view->categories = $catDAO->listCategories(false);
@@ -85,7 +127,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
 			if (!$this->view->flux) {
 			if (!$this->view->flux) {
 				Minz_Error::error(
 				Minz_Error::error(
 					404,
 					404,
-					array('error' => array(Minz_Translate::t('page_not_found')))
+					array('error' => array(_t('page_not_found')))
 				);
 				);
 			} else {
 			} else {
 				if (Minz_Request::isPost() && $this->view->flux) {
 				if (Minz_Request::isPost() && $this->view->flux) {
@@ -117,12 +159,12 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
 						$this->view->flux->faviconPrepare();
 						$this->view->flux->faviconPrepare();
 						$notif = array(
 						$notif = array(
 							'type' => 'good',
 							'type' => 'good',
-							'content' => Minz_Translate::t('feed_updated')
+							'content' => _t('feed_updated')
 						);
 						);
 					} else {
 					} else {
 						$notif = array(
 						$notif = array(
 							'type' => 'bad',
 							'type' => 'bad',
-							'content' => Minz_Translate::t('error_occurred_update')
+							'content' => _t('error_occurred_update')
 						);
 						);
 					}
 					}
 					invalidateHttpCache();
 					invalidateHttpCache();
@@ -131,21 +173,41 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
 					Minz_Request::forward(array('c' => 'configure', 'a' => 'feed', 'params' => array('id' => $id)), true);
 					Minz_Request::forward(array('c' => 'configure', 'a' => 'feed', 'params' => array('id' => $id)), true);
 				}
 				}
 
 
-				Minz_View::prependTitle(Minz_Translate::t('rss_feed_management') . ' — ' . $this->view->flux->name() . ' · ');
+				Minz_View::prependTitle(_t('rss_feed_management') . ' — ' . $this->view->flux->name() . ' · ');
 			}
 			}
 		} else {
 		} else {
-			Minz_View::prependTitle(Minz_Translate::t('rss_feed_management') . ' · ');
+			Minz_View::prependTitle(_t('rss_feed_management') . ' · ');
 		}
 		}
 	}
 	}
 
 
+	/**
+	 * This action handles the display configuration page.
+	 *
+	 * It displays the display configuration page.
+	 * If this action is reached through a POST request, it stores all new
+	 * configuration values then sends a notification to the user.
+	 *
+	 * The options available on the page are:
+	 *   - language (default: en)
+	 *   - theme (default: Origin)
+	 *   - content width (default: thin)
+	 *   - display of read action in header
+	 *   - display of favorite action in header
+	 *   - display of date in header
+	 *   - display of open action in header
+	 *   - display of read action in footer
+	 *   - display of favorite action in footer
+	 *   - display of sharing action in footer
+	 *   - display of tags in footer
+	 *   - display of date in footer
+	 *   - display of open action in footer
+	 *   - html5 notification timeout (default: 0)
+	 * Default values are false unless specified.
+	 */
 	public function displayAction() {
 	public function displayAction() {
 		if (Minz_Request::isPost()) {
 		if (Minz_Request::isPost()) {
 			$this->view->conf->_language(Minz_Request::param('language', 'en'));
 			$this->view->conf->_language(Minz_Request::param('language', 'en'));
-			$themeId = Minz_Request::param('theme', '');
-			if ($themeId == '') {
-				$themeId = FreshRSS_Themes::defaultTheme;
-			}
-			$this->view->conf->_theme($themeId);
+			$this->view->conf->_theme(Minz_Request::param('theme', FreshRSS_Themes::$defaultTheme));
 			$this->view->conf->_content_width(Minz_Request::param('content_width', 'thin'));
 			$this->view->conf->_content_width(Minz_Request::param('content_width', 'thin'));
 			$this->view->conf->_topline_read(Minz_Request::param('topline_read', false));
 			$this->view->conf->_topline_read(Minz_Request::param('topline_read', false));
 			$this->view->conf->_topline_favorite(Minz_Request::param('topline_favorite', false));
 			$this->view->conf->_topline_favorite(Minz_Request::param('topline_favorite', false));
@@ -157,26 +219,49 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
 			$this->view->conf->_bottomline_tags(Minz_Request::param('bottomline_tags', false));
 			$this->view->conf->_bottomline_tags(Minz_Request::param('bottomline_tags', false));
 			$this->view->conf->_bottomline_date(Minz_Request::param('bottomline_date', false));
 			$this->view->conf->_bottomline_date(Minz_Request::param('bottomline_date', false));
 			$this->view->conf->_bottomline_link(Minz_Request::param('bottomline_link', false));
 			$this->view->conf->_bottomline_link(Minz_Request::param('bottomline_link', false));
+			$this->view->conf->_html5_notif_timeout(Minz_Request::param('html5_notif_timeout', 0));
 			$this->view->conf->save();
 			$this->view->conf->save();
 
 
 			Minz_Session::_param('language', $this->view->conf->language);
 			Minz_Session::_param('language', $this->view->conf->language);
 			Minz_Translate::reset();
 			Minz_Translate::reset();
 			invalidateHttpCache();
 			invalidateHttpCache();
 
 
-			$notif = array(
-				'type' => 'good',
-				'content' => Minz_Translate::t('configuration_updated')
-			);
-			Minz_Session::_param('notification', $notif);
-
-			Minz_Request::forward(array('c' => 'configure', 'a' => 'display'), true);
+			Minz_Request::good(_t('configuration_updated'),
+			                   array('c' => 'configure', 'a' => 'display'));
 		}
 		}
 
 
 		$this->view->themes = FreshRSS_Themes::get();
 		$this->view->themes = FreshRSS_Themes::get();
 
 
-		Minz_View::prependTitle(Minz_Translate::t('display_configuration') . ' · ');
+		Minz_View::prependTitle(_t('display_configuration') . ' · ');
 	}
 	}
 
 
+	/**
+	 * This action handles the reading configuration page.
+	 *
+	 * It displays the reading configuration page.
+	 * If this action is reached through a POST request, it stores all new
+	 * configuration values then sends a notification to the user.
+	 *
+	 * The options available on the page are:
+	 *   - number of posts per page (default: 10)
+	 *   - view mode (default: normal)
+	 *   - default article view (default: all)
+	 *   - load automatically articles
+	 *   - display expanded articles
+	 *   - display expanded categories
+	 *   - hide categories and feeds without unread articles
+	 *   - jump on next category or feed when marked as read
+	 *   - image lazy loading
+	 *   - stick open articles to the top
+	 *   - display a confirmation when reading all articles
+	 *   - article order (default: DESC)
+	 *   - mark articles as read when:
+	 *       - displayed
+	 *       - opened on site
+	 *       - scrolled
+	 *       - received
+	 * Default values are false unless specified.
+	 */
 	public function readingAction() {
 	public function readingAction() {
 		if (Minz_Request::isPost()) {
 		if (Minz_Request::isPost()) {
 			$this->view->conf->_posts_per_page(Minz_Request::param('posts_per_page', 10));
 			$this->view->conf->_posts_per_page(Minz_Request::param('posts_per_page', 10));
@@ -203,18 +288,20 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
 			Minz_Translate::reset();
 			Minz_Translate::reset();
 			invalidateHttpCache();
 			invalidateHttpCache();
 
 
-			$notif = array(
-				'type' => 'good',
-				'content' => Minz_Translate::t('configuration_updated')
-			);
-			Minz_Session::_param('notification', $notif);
-
-			Minz_Request::forward(array('c' => 'configure', 'a' => 'reading'), true);
+			Minz_Request::good(_t('configuration_updated'),
+			                   array('c' => 'configure', 'a' => 'reading'));
 		}
 		}
 
 
-		Minz_View::prependTitle(Minz_Translate::t('reading_configuration') . ' · ');
+		Minz_View::prependTitle(_t('reading_configuration') . ' · ');
 	}
 	}
 
 
+	/**
+	 * This action handles the sharing configuration page.
+	 *
+	 * It displays the sharing configuration page.
+	 * If this action is reached through a POST request, it stores all
+	 * configuration values then sends a notification to the user.
+	 */
 	public function sharingAction() {
 	public function sharingAction() {
 		if (Minz_Request::isPost()) {
 		if (Minz_Request::isPost()) {
 			$params = Minz_Request::params();
 			$params = Minz_Request::params();
@@ -222,25 +309,31 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
 			$this->view->conf->save();
 			$this->view->conf->save();
 			invalidateHttpCache();
 			invalidateHttpCache();
 
 
-			$notif = array(
-				'type' => 'good',
-				'content' => Minz_Translate::t('configuration_updated')
-			);
-			Minz_Session::_param('notification', $notif);
-
-			Minz_Request::forward(array('c' => 'configure', 'a' => 'sharing'), true);
+			Minz_Request::good(_t('configuration_updated'),
+			                   array('c' => 'configure', 'a' => 'sharing'));
 		}
 		}
 
 
-		Minz_View::prependTitle(Minz_Translate::t('sharing') . ' · ');
+		Minz_View::prependTitle(_t('sharing') . ' · ');
 	}
 	}
 
 
+	/**
+	 * This action handles the shortcut configuration page.
+	 *
+	 * It displays the shortcut configuration page.
+	 * If this action is reached through a POST request, it stores all new
+	 * configuration values then sends a notification to the user.
+	 *
+	 * The authorized values for shortcuts are letters (a to z), numbers (0
+	 * to 9), function keys (f1 to f12), backspace, delete, down, end, enter,
+	 * escape, home, insert, left, page down, page up, return, right, space,
+	 * tab and up.
+	 */
 	public function shortcutAction() {
 	public function shortcutAction() {
 		$list_keys = array('a', 'b', 'backspace', 'c', 'd', 'delete', 'down', 'e', 'end', 'enter',
 		$list_keys = array('a', 'b', 'backspace', 'c', 'd', 'delete', 'down', 'e', 'end', 'enter',
 		                    'escape', 'f', 'g', 'h', 'home', 'i', 'insert', 'j', 'k', 'l', 'left',
 		                    'escape', 'f', 'g', 'h', 'home', 'i', 'insert', 'j', 'k', 'l', 'left',
 		                    'm', 'n', 'o', 'p', 'page_down', 'page_up', 'q', 'r', 'return', 'right',
 		                    'm', 'n', 'o', 'p', 'page_down', 'page_up', 'q', 'r', 'return', 'right',
 		                    's', 'space', 't', 'tab', 'u', 'up', 'v', 'w', 'x', 'y',
 		                    's', 'space', 't', 'tab', 'u', 'up', 'v', 'w', 'x', 'y',
-		                    'z', '0', '1', '2', '3', '4', '5', '6', '7', '8',
-		                    '9', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9',
+		                    'z', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9',
 		                    'f10', 'f11', 'f12');
 		                    'f10', 'f11', 'f12');
 		$this->view->list_keys = $list_keys;
 		$this->view->list_keys = $list_keys;
 
 
@@ -258,44 +351,50 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
 			$this->view->conf->save();
 			$this->view->conf->save();
 			invalidateHttpCache();
 			invalidateHttpCache();
 
 
-			$notif = array(
-				'type' => 'good',
-				'content' => Minz_Translate::t('shortcuts_updated')
-			);
-			Minz_Session::_param('notification', $notif);
-
-			Minz_Request::forward(array('c' => 'configure', 'a' => 'shortcut'), true);
+			Minz_Request::good(_t('shortcuts_updated'),
+			                   array('c' => 'configure', 'a' => 'shortcut'));
 		}
 		}
 
 
-		Minz_View::prependTitle(Minz_Translate::t('shortcuts') . ' · ');
+		Minz_View::prependTitle(_t('shortcuts') . ' · ');
 	}
 	}
 
 
+	/**
+	 * This action display the user configuration page
+	 *
+	 * @todo move that action in the user controller
+	 */
 	public function usersAction() {
 	public function usersAction() {
-		Minz_View::prependTitle(Minz_Translate::t('users') . ' · ');
+		Minz_View::prependTitle(_t('users') . ' · ');
 	}
 	}
 
 
+	/**
+	 * This action handles the archive configuration page.
+	 *
+	 * It displays the archive configuration page.
+	 * If this action is reached through a POST request, it stores all new
+	 * configuration values then sends a notification to the user.
+	 *
+	 * The options available on that page are:
+	 *   - duration to retain old article (default: 3)
+	 *   - number of article to retain per feed (default: 0)
+	 *   - refresh frequency (default: -2)
+	 *
+	 * @todo explain why the default value is -2 but this value does not
+	 *       exist in the drop-down list
+	 */
 	public function archivingAction() {
 	public function archivingAction() {
 		if (Minz_Request::isPost()) {
 		if (Minz_Request::isPost()) {
-			$old = Minz_Request::param('old_entries', 3);
-			$keepHistoryDefault = Minz_Request::param('keep_history_default', 0);
-			$ttlDefault = Minz_Request::param('ttl_default', -2);
-
-			$this->view->conf->_old_entries($old);
-			$this->view->conf->_keep_history_default($keepHistoryDefault);
-			$this->view->conf->_ttl_default($ttlDefault);
+			$this->view->conf->_old_entries(Minz_Request::param('old_entries', 3));
+			$this->view->conf->_keep_history_default(Minz_Request::param('keep_history_default', 0));
+			$this->view->conf->_ttl_default(Minz_Request::param('ttl_default', -2));
 			$this->view->conf->save();
 			$this->view->conf->save();
 			invalidateHttpCache();
 			invalidateHttpCache();
 
 
-			$notif = array(
-				'type' => 'good',
-				'content' => Minz_Translate::t('configuration_updated')
-			);
-			Minz_Session::_param('notification', $notif);
-
-			Minz_Request::forward(array('c' => 'configure', 'a' => 'archiving'), true);
+			Minz_Request::good(_t('configuration_updated'),
+			                   array('c' => 'configure', 'a' => 'archiving'));
 		}
 		}
 
 
-		Minz_View::prependTitle(Minz_Translate::t('archiving_configuration') . ' · ');
+		Minz_View::prependTitle(_t('archiving_configuration') . ' · ');
 
 
 		$entryDAO = FreshRSS_Factory::createEntryDao();
 		$entryDAO = FreshRSS_Factory::createEntryDao();
 		$this->view->nb_total = $entryDAO->count();
 		$this->view->nb_total = $entryDAO->count();
@@ -305,28 +404,35 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
 			$this->view->size_total = $entryDAO->size(true);
 			$this->view->size_total = $entryDAO->size(true);
 		}
 		}
 	}
 	}
-	
+
+	/**
+	 * This action handles the user queries configuration page.
+	 *
+	 * If this action is reached through a POST request, it stores all new
+	 * configuration values then sends a notification to the user then
+	 * redirect to the same page.
+	 * If this action is not reached through a POST request, it displays the
+	 * configuration page and verifies that every user query is runable by
+	 * checking if categories and feeds are still in use.
+	 */
 	public function queriesAction() {
 	public function queriesAction() {
 		if (Minz_Request::isPost()) {
 		if (Minz_Request::isPost()) {
 			$queries = Minz_Request::param('queries', array());
 			$queries = Minz_Request::param('queries', array());
 
 
 			foreach ($queries as $key => $query) {
 			foreach ($queries as $key => $query) {
 				if (!$query['name']) {
 				if (!$query['name']) {
-					$query['name'] = Minz_Translate::t('query_number', $key + 1);
+					$query['name'] = _t('query_number', $key + 1);
 				}
 				}
 			}
 			}
 			$this->view->conf->_queries($queries);
 			$this->view->conf->_queries($queries);
 			$this->view->conf->save();
 			$this->view->conf->save();
 
 
-			$notif = array(
-				'type' => 'good',
-				'content' => Minz_Translate::t('configuration_updated')
-			);
-			Minz_Session::_param('notification', $notif);
-
-			Minz_Request::forward(array('c' => 'configure', 'a' => 'queries'), true);
+			Minz_Request::good(_t('configuration_updated'),
+			                   array('c' => 'configure', 'a' => 'queries'));
 		} else {
 		} else {
 			$this->view->query_get = array();
 			$this->view->query_get = array();
+			$cat_dao = new FreshRSS_CategoryDAO();
+			$feed_dao = FreshRSS_Factory::createFeedDao();
 			foreach ($this->view->conf->queries as $key => $query) {
 			foreach ($this->view->conf->queries as $key => $query) {
 				if (!isset($query['get'])) {
 				if (!isset($query['get'])) {
 					continue;
 					continue;
@@ -334,51 +440,83 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
 
 
 				switch ($query['get'][0]) {
 				switch ($query['get'][0]) {
 				case 'c':
 				case 'c':
-					$dao = new FreshRSS_CategoryDAO();
-					$category = $dao->searchById(substr($query['get'], 2));
+					$category = $cat_dao->searchById(substr($query['get'], 2));
+
+					$deprecated = true;
+					$cat_name = '';
+					if ($category) {
+						$cat_name = $category->name();
+						$deprecated = false;
+					}
+
 					$this->view->query_get[$key] = array(
 					$this->view->query_get[$key] = array(
 						'type' => 'category',
 						'type' => 'category',
-						'name' => $category->name(),
+						'name' => $cat_name,
+						'deprecated' => $deprecated,
 					);
 					);
 					break;
 					break;
 				case 'f':
 				case 'f':
-					$dao = FreshRSS_Factory::createFeedDao();
-					$feed = $dao->searchById(substr($query['get'], 2));
+					$feed = $feed_dao->searchById(substr($query['get'], 2));
+
+					$deprecated = true;
+					$feed_name = '';
+					if ($feed) {
+						$feed_name = $feed->name();
+						$deprecated = false;
+					}
+
 					$this->view->query_get[$key] = array(
 					$this->view->query_get[$key] = array(
 						'type' => 'feed',
 						'type' => 'feed',
-						'name' => $feed->name(),
+						'name' => $feed_name,
+						'deprecated' => $deprecated,
 					);
 					);
 					break;
 					break;
 				case 's':
 				case 's':
 					$this->view->query_get[$key] = array(
 					$this->view->query_get[$key] = array(
 						'type' => 'favorite',
 						'type' => 'favorite',
 						'name' => 'favorite',
 						'name' => 'favorite',
+						'deprecated' => false,
 					);
 					);
 					break;
 					break;
 				case 'a':
 				case 'a':
 					$this->view->query_get[$key] = array(
 					$this->view->query_get[$key] = array(
 						'type' => 'all',
 						'type' => 'all',
 						'name' => 'all',
 						'name' => 'all',
+						'deprecated' => false,
 					);
 					);
 					break;
 					break;
 				}
 				}
 			}
 			}
 		}
 		}
 
 
-		Minz_View::prependTitle(Minz_Translate::t('queries') . ' · ');
+		Minz_View::prependTitle(_t('queries') . ' · ');
 	}
 	}
-	
+
+	/**
+	 * This action handles the creation of a user query.
+	 *
+	 * It gets the GET parameters and stores them in the configuration query
+	 * storage. Before it is saved, the unwanted parameters are unset to keep
+	 * lean data.
+	 */
 	public function addQueryAction() {
 	public function addQueryAction() {
+		$whitelist = array('get', 'order', 'name', 'search', 'state');
 		$queries = $this->view->conf->queries;
 		$queries = $this->view->conf->queries;
 		$query = Minz_Request::params();
 		$query = Minz_Request::params();
-		$query['name'] = Minz_Translate::t('query_number', count($queries) + 1);
-		unset($query['output']);
-		unset($query['token']);
+		$query['name'] = _t('query_number', count($queries) + 1);
+		foreach ($query as $key => $value) {
+			if (!in_array($key, $whitelist)) {
+				unset($query[$key]);
+			}
+		}
+		if (!empty($query['state']) && $query['state'] & FreshRSS_Entry::STATE_STRICT) {
+			$query['state'] -= FreshRSS_Entry::STATE_STRICT;
+		}
 		$queries[] = $query;
 		$queries[] = $query;
 		$this->view->conf->_queries($queries);
 		$this->view->conf->_queries($queries);
 		$this->view->conf->save();
 		$this->view->conf->save();
 
 
-		// Minz_Request::forward(array('params' => $query), true);
-		Minz_Request::forward(array('c' => 'configure', 'a' => 'queries'), true);
+		Minz_Request::good(_t('query_created', $query['name']),
+		                   array('c' => 'configure', 'a' => 'queries'));
 	}
 	}
 }
 }

+ 4 - 0
app/Controllers/entryController.php

@@ -45,6 +45,10 @@ class FreshRSS_entry_Controller extends Minz_ActionController {
 
 
 		$entryDAO = FreshRSS_Factory::createEntryDao();
 		$entryDAO = FreshRSS_Factory::createEntryDao();
 		if ($id == false) {
 		if ($id == false) {
+			if (!Minz_Request::isPost()) {
+				return;
+			}
+
 			if (!$get) {
 			if (!$get) {
 				$entryDAO->markReadEntries ($idMax);
 				$entryDAO->markReadEntries ($idMax);
 			} else {
 			} else {

+ 19 - 3
app/Controllers/feedController.php

@@ -383,7 +383,16 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
 
 
 			$feedDAO = FreshRSS_Factory::createFeedDao();
 			$feedDAO = FreshRSS_Factory::createFeedDao();
 			if ($type == 'category') {
 			if ($type == 'category') {
+				// List feeds to remove then related user queries.
+				$feeds = $feedDAO->listByCategory($id);
+
 				if ($feedDAO->deleteFeedByCategory ($id)) {
 				if ($feedDAO->deleteFeedByCategory ($id)) {
+					// Remove related queries
+					foreach ($feeds as $feed) {
+						$this->view->conf->remove_query_by_get('f_' . $feed->id());
+					}
+					$this->view->conf->save();
+
 					$notif = array (
 					$notif = array (
 						'type' => 'good',
 						'type' => 'good',
 						'content' => Minz_Translate::t ('category_emptied')
 						'content' => Minz_Translate::t ('category_emptied')
@@ -397,6 +406,10 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
 				}
 				}
 			} else {
 			} else {
 				if ($feedDAO->deleteFeed ($id)) {
 				if ($feedDAO->deleteFeed ($id)) {
+					// Remove related queries
+					$this->view->conf->remove_query_by_get('f_' . $id);
+					$this->view->conf->save();
+
 					$notif = array (
 					$notif = array (
 						'type' => 'good',
 						'type' => 'good',
 						'content' => Minz_Translate::t ('feed_deleted')
 						'content' => Minz_Translate::t ('feed_deleted')
@@ -412,10 +425,13 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
 
 
 			Minz_Session::_param ('notification', $notif);
 			Minz_Session::_param ('notification', $notif);
 
 
-			if ($type == 'category') {
-				Minz_Request::forward (array ('c' => 'configure', 'a' => 'categorize'), true);
+			$redirect_url = Minz_Request::param('r', false, true);
+			if ($redirect_url) {
+				Minz_Request::forward($redirect_url);
+			} elseif ($type == 'category') {
+				Minz_Request::forward(array ('c' => 'configure', 'a' => 'categorize'), true);
 			} else {
 			} else {
-				Minz_Request::forward (array ('c' => 'configure', 'a' => 'feed'), true);
+				Minz_Request::forward(array ('c' => 'configure', 'a' => 'feed'), true);
 			}
 			}
 		}
 		}
 	}
 	}

+ 20 - 8
app/Controllers/importExportController.php

@@ -109,7 +109,6 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
 		// A *very* basic guess file type function. Only based on filename
 		// A *very* basic guess file type function. Only based on filename
 		// That's could be improved but should be enough, at least for a first
 		// That's could be improved but should be enough, at least for a first
 		// implementation.
 		// implementation.
-		// TODO: improve this function?
 
 
 		if (substr_compare($filename, '.zip', -4) === 0) {
 		if (substr_compare($filename, '.zip', -4) === 0) {
 			return 'zip';
 			return 'zip';
@@ -119,8 +118,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
 		} elseif (substr_compare($filename, '.json', -5) === 0 &&
 		} elseif (substr_compare($filename, '.json', -5) === 0 &&
 		          strpos($filename, 'starred') !== false) {
 		          strpos($filename, 'starred') !== false) {
 			return 'json_starred';
 			return 'json_starred';
-		} elseif (substr_compare($filename, '.json', -5) === 0 &&
-		          strpos($filename, 'feed_') === 0) {
+		} elseif (substr_compare($filename, '.json', -5) === 0) {
 			return 'json_feed';
 			return 'json_feed';
 		} else {
 		} else {
 			return 'unknown';
 			return 'unknown';
@@ -239,13 +237,27 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
 		);
 		);
 
 
 		$error = false;
 		$error = false;
+		$article_to_feed = array();
+
+		// First, we check feeds of articles are in DB (and add them if needed).
 		foreach ($article_object['items'] as $item) {
 		foreach ($article_object['items'] as $item) {
 			$feed = $this->addFeedArticles($item['origin'], $google_compliant);
 			$feed = $this->addFeedArticles($item['origin'], $google_compliant);
 			if (is_null($feed)) {
 			if (is_null($feed)) {
 				$error = true;
 				$error = true;
+			} else {
+				$article_to_feed[$item['id']] = $feed->id();
+			}
+		}
+
+		// Then, articles are imported.
+		$prepared_statement = $this->entryDAO->addEntryPrepare();
+		$this->entryDAO->beginTransaction();
+		foreach ($article_object['items'] as $item) {
+			if (!isset($article_to_feed[$item['id']])) {
 				continue;
 				continue;
 			}
 			}
 
 
+			$feed_id = $article_to_feed[$item['id']];
 			$author = isset($item['author']) ? $item['author'] : '';
 			$author = isset($item['author']) ? $item['author'] : '';
 			$key_content = ($google_compliant && !isset($item['content'])) ?
 			$key_content = ($google_compliant && !isset($item['content'])) ?
 			               'summary' : 'content';
 			               'summary' : 'content';
@@ -257,21 +269,21 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
 			}
 			}
 
 
 			$entry = new FreshRSS_Entry(
 			$entry = new FreshRSS_Entry(
-				$feed->id(), $item['id'], $item['title'], $author,
+				$feed_id, $item['id'], $item['title'], $author,
 				$item[$key_content]['content'], $item['alternate'][0]['href'],
 				$item[$key_content]['content'], $item['alternate'][0]['href'],
 				$item['published'], $is_read, $starred
 				$item['published'], $is_read, $starred
 			);
 			);
+			$entry->_id(min(time(), $entry->date(true)) . uSecString());
 			$entry->_tags($tags);
 			$entry->_tags($tags);
 
 
-			//FIME: Use entryDAO->addEntryPrepare(). Do not call entryDAO->listLastGuidsByFeed() for each entry. Consider using a transaction.
-			$id = $this->entryDAO->addEntryObject(
-				$entry, $this->view->conf, $feed->keepHistory()
-			);
+			$values = $entry->toArray();
+			$id = $this->entryDAO->addEntry($values, $prepared_statement);
 
 
 			if (!$error && ($id === false)) {
 			if (!$error && ($id === false)) {
 				$error = true;
 				$error = true;
 			}
 			}
 		}
 		}
+		$this->entryDAO->commit();
 
 
 		return $error;
 		return $error;
 	}
 	}

+ 80 - 0
app/Controllers/indexController.php

@@ -83,6 +83,11 @@ class FreshRSS_index_Controller extends Minz_ActionController {
 		$nb = Minz_Request::param ('nb', $this->view->conf->posts_per_page);
 		$nb = Minz_Request::param ('nb', $this->view->conf->posts_per_page);
 		$first = Minz_Request::param ('next', '');
 		$first = Minz_Request::param ('next', '');
 
 
+		$ajax_request = Minz_Request::param('ajax', false);
+		if ($output === 'reader') {
+			$nb = max(1, round($nb / 2));
+		}
+
 		if ($this->view->state === FreshRSS_Entry::STATE_NOT_READ) {	//Any unread article in this category at all?
 		if ($this->view->state === FreshRSS_Entry::STATE_NOT_READ) {	//Any unread article in this category at all?
 			switch ($getType) {
 			switch ($getType) {
 				case 'a':
 				case 'a':
@@ -332,6 +337,10 @@ class FreshRSS_index_Controller extends Minz_ActionController {
 	}
 	}
 
 
 	public function formLoginAction () {
 	public function formLoginAction () {
+		if ($this->view->loginOk) {
+			Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true);
+		}
+
 		if (Minz_Request::isPost()) {
 		if (Minz_Request::isPost()) {
 			$ok = false;
 			$ok = false;
 			$nonce = Minz_Session::param('nonce');
 			$nonce = Minz_Session::param('nonce');
@@ -415,4 +424,75 @@ class FreshRSS_index_Controller extends Minz_ActionController {
 		self::deleteLongTermCookie();
 		self::deleteLongTermCookie();
 		Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true);
 		Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true);
 	}
 	}
+
+	public function resetAuthAction() {
+		Minz_View::prependTitle(_t('auth_reset') . ' · ');
+		Minz_View::appendScript(Minz_Url::display(
+			'/scripts/bcrypt.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/bcrypt.min.js')
+		));
+
+		$this->view->no_form = false;
+		// Enable changement of auth only if Persona!
+		if (Minz_Configuration::authType() != 'persona') {
+			$this->view->message = array(
+				'status' => 'bad',
+				'title' => _t('damn'),
+				'body' => _t('auth_not_persona')
+			);
+			$this->view->no_form = true;
+			return;
+		}
+
+		$conf = new FreshRSS_Configuration(Minz_Configuration::defaultUser());
+		// Admin user must have set its master password.
+		if (!$conf->passwordHash) {
+			$this->view->message = array(
+				'status' => 'bad',
+				'title' => _t('damn'),
+				'body' => _t('auth_no_password_set')
+			);
+			$this->view->no_form = true;
+			return;
+		}
+
+		invalidateHttpCache();
+
+		if (Minz_Request::isPost()) {
+			$nonce = Minz_Session::param('nonce');
+			$username = Minz_Request::param('username', '');
+			$c = Minz_Request::param('challenge', '');
+			if (!(ctype_alnum($username) && ctype_graph($c) && ctype_alnum($nonce))) {
+				Minz_Log::debug('Invalid credential parameters:' .
+				                ' user=' . $username .
+				                ' challenge=' . $c .
+				                ' nonce=' . $nonce);
+				Minz_Request::bad(_t('invalid_login'),
+				                  array('c' => 'index', 'a' => 'resetAuth'));
+			}
+
+			if (!function_exists('password_verify')) {
+				include_once(LIB_PATH . '/password_compat.php');
+			}
+
+			$s = $conf->passwordHash;
+			$ok = password_verify($nonce . $s, $c);
+			if ($ok) {
+				Minz_Configuration::_authType('form');
+				$ok = Minz_Configuration::writeFile();
+
+				if ($ok) {
+					Minz_Request::good(_t('auth_form_set'));
+				} else {
+					Minz_Request::bad(_t('auth_form_not_set'),
+				                      array('c' => 'index', 'a' => 'resetAuth'));
+				}
+			} else {
+				Minz_Log::debug('Password mismatch for user ' . $username .
+				                ', nonce=' . $nonce . ', c=' . $c);
+
+				Minz_Request::bad(_t('invalid_login'),
+				                  array('c' => 'index', 'a' => 'resetAuth'));
+			}
+		}
+	}
 }
 }

+ 45 - 0
app/Controllers/statsController.php

@@ -1,7 +1,21 @@
 <?php
 <?php
 
 
+/**
+ * Controller to handle application statistics.
+ */
 class FreshRSS_stats_Controller extends Minz_ActionController {
 class FreshRSS_stats_Controller extends Minz_ActionController {
 
 
+	/**
+	 * This action handles the statistic main page.
+	 *
+	 * It displays the statistic main page.
+	 * The values computed to display the page are:
+	 *   - repartition of read/unread/favorite/not favorite
+	 *   - number of article per day
+	 *   - number of feed by category
+	 *   - number of article by category
+	 *   - list of most prolific feed
+	 */
 	public function indexAction() {
 	public function indexAction() {
 		$statsDAO = FreshRSS_Factory::createStatsDAO();
 		$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')));
@@ -12,6 +26,17 @@ class FreshRSS_stats_Controller extends Minz_ActionController {
 		$this->view->topFeed = $statsDAO->calculateTopFeed();
 		$this->view->topFeed = $statsDAO->calculateTopFeed();
 	}
 	}
 
 
+	/**
+	 * This action handles the idle feed statistic page.
+	 *
+	 * It displays the list of idle feed for different period. The supported
+	 * periods are:
+	 *   - last year
+	 *   - last 6 months
+	 *   - last 3 months
+	 *   - last month
+	 *   - last week
+	 */
 	public function idleAction() {
 	public function idleAction() {
 		$statsDAO = FreshRSS_Factory::createStatsDAO();
 		$statsDAO = FreshRSS_Factory::createStatsDAO();
 		$feeds = $statsDAO->calculateFeedLastDate();
 		$feeds = $statsDAO->calculateFeedLastDate();
@@ -56,6 +81,18 @@ class FreshRSS_stats_Controller extends Minz_ActionController {
 		$this->view->idleFeeds = $idleFeeds;
 		$this->view->idleFeeds = $idleFeeds;
 	}
 	}
 
 
+	/**
+	 * This action handles the article repartition statistic page.
+	 *
+	 * It displays the number of article and the average of article for the
+	 * following periods:
+	 *   - hour of the day
+	 *   - day of the week
+	 *   - month
+	 *
+	 * @todo verify that the metrics used here make some sense. Especially
+	 *       for the average.
+	 */
 	public function repartitionAction() {
 	public function repartitionAction() {
 		$statsDAO = FreshRSS_Factory::createStatsDAO();
 		$statsDAO = FreshRSS_Factory::createStatsDAO();
 		$categoryDAO = new FreshRSS_CategoryDAO();
 		$categoryDAO = new FreshRSS_CategoryDAO();
@@ -67,10 +104,18 @@ class FreshRSS_stats_Controller extends Minz_ActionController {
 		$this->view->days = $statsDAO->getDays();
 		$this->view->days = $statsDAO->getDays();
 		$this->view->months = $statsDAO->getMonths();
 		$this->view->months = $statsDAO->getMonths();
 		$this->view->repartitionHour = $statsDAO->calculateEntryRepartitionPerFeedPerHour($id);
 		$this->view->repartitionHour = $statsDAO->calculateEntryRepartitionPerFeedPerHour($id);
+		$this->view->averageHour = $statsDAO->calculateEntryAveragePerFeedPerHour($id);
 		$this->view->repartitionDayOfWeek = $statsDAO->calculateEntryRepartitionPerFeedPerDayOfWeek($id);
 		$this->view->repartitionDayOfWeek = $statsDAO->calculateEntryRepartitionPerFeedPerDayOfWeek($id);
+		$this->view->averageDayOfWeek = $statsDAO->calculateEntryAveragePerFeedPerDayOfWeek($id);
 		$this->view->repartitionMonth = $statsDAO->calculateEntryRepartitionPerFeedPerMonth($id);
 		$this->view->repartitionMonth = $statsDAO->calculateEntryRepartitionPerFeedPerMonth($id);
+		$this->view->averageMonth = $statsDAO->calculateEntryAveragePerFeedPerMonth($id);
 	}
 	}
 
 
+	/**
+	 * This action is called before every other action in that class. It is
+	 * the common boiler plate for every action. It is triggered by the
+	 * underlying framework.
+	 */
 	public function firstAction() {
 	public function firstAction() {
 		if (!$this->view->loginOk) {
 		if (!$this->view->loginOk) {
 			Minz_Error::error(
 			Minz_Error::error(

+ 129 - 0
app/Controllers/updateController.php

@@ -0,0 +1,129 @@
+<?php
+
+class FreshRSS_update_Controller extends Minz_ActionController {
+	public function firstAction() {
+		$current_user = Minz_Session::param('currentUser', '');
+		if (!$this->view->loginOk && Minz_Configuration::isAdmin($current_user)) {
+			Minz_Error::error(
+				403,
+				array('error' => array(_t('access_denied')))
+			);
+		}
+
+		invalidateHttpCache();
+
+		Minz_View::prependTitle(_t('update_system') . ' · ');
+		$this->view->update_to_apply = false;
+		$this->view->last_update_time = 'unknown';
+		$this->view->check_last_hour = false;
+		$timestamp = (int)@file_get_contents(DATA_PATH . '/last_update.txt');
+		if (is_numeric($timestamp) && $timestamp > 0) {
+			$this->view->last_update_time = timestamptodate($timestamp);
+			$this->view->check_last_hour = (time() - 3600) <= $timestamp;
+		}
+	}
+
+	public function indexAction() {
+		if (file_exists(UPDATE_FILENAME) && !is_writable(FRESHRSS_PATH)) {
+			$this->view->message = array(
+				'status' => 'bad',
+				'title' => _t('damn'),
+				'body' => _t('file_is_nok', FRESHRSS_PATH)
+			);
+		} elseif (file_exists(UPDATE_FILENAME)) {
+			// There is an update file to apply!
+			$this->view->update_to_apply = true;
+			$this->view->message = array(
+				'status' => 'good',
+				'title' => _t('ok'),
+				'body' => _t('update_can_apply')
+			);
+		}
+	}
+
+	public function checkAction() {
+		$this->view->change_view('update', 'index');
+
+		if (file_exists(UPDATE_FILENAME) || $this->view->check_last_hour) {
+			// There is already an update file to apply: we don't need to check
+			// the webserver!
+			// Or if already check during the last hour, do nothing.
+			Minz_Request::forward(array('c' => 'update'));
+
+			return;
+		}
+
+		$c = curl_init(FRESHRSS_UPDATE_WEBSITE);
+		curl_setopt($c, CURLOPT_RETURNTRANSFER, true);
+		curl_setopt($c, CURLOPT_SSL_VERIFYPEER, true);
+		curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2);
+		$result = curl_exec($c);
+		$c_status = curl_getinfo($c, CURLINFO_HTTP_CODE);
+		$c_error = curl_error($c);
+		curl_close($c);
+
+		if ($c_status !== 200) {
+			Minz_Log::error(
+				'Error during update (HTTP code ' . $c_status . '): ' . $c_error
+			);
+
+			$this->view->message = array(
+				'status' => 'bad',
+				'title' => _t('damn'),
+				'body' => _t('update_server_not_found', FRESHRSS_UPDATE_WEBSITE)
+			);
+			return;
+		}
+
+		$res_array = explode("\n", $result, 2);
+		$status = $res_array[0];
+		if (strpos($status, 'UPDATE') !== 0) {
+			$this->view->message = array(
+				'status' => 'bad',
+				'title' => _t('damn'),
+				'body' => _t('no_update')
+			);
+
+			@file_put_contents(DATA_PATH . '/last_update.txt', time());
+
+			return;
+		}
+
+		$script = $res_array[1];
+		if (file_put_contents(UPDATE_FILENAME, $script) !== false) {
+			Minz_Request::forward(array('c' => 'update'));
+		} else {
+			$this->view->message = array(
+				'status' => 'bad',
+				'title' => _t('damn'),
+				'body' => _t('update_problem', 'Cannot save the update script')
+			);
+		}
+	}
+
+	public function applyAction() {
+		if (!file_exists(UPDATE_FILENAME) || !is_writable(FRESHRSS_PATH)) {
+			Minz_Request::forward(array('c' => 'update'), true);
+		}
+
+		require(UPDATE_FILENAME);
+
+		if (Minz_Request::isPost()) {
+			save_info_update();
+		}
+
+		if (!need_info_update()) {
+			$res = apply_update();
+
+			if ($res === true) {
+				@unlink(UPDATE_FILENAME);
+				@file_put_contents(DATA_PATH . '/last_update.txt', time());
+
+				Minz_Request::good(_t('update_finished'));
+			} else {
+				Minz_Request::bad(_t('update_problem', $res),
+				                  array('c' => 'update', 'a' => 'index'));
+			}
+		}
+	}
+}

+ 13 - 4
app/FreshRSS.php

@@ -6,8 +6,7 @@ class FreshRSS extends Minz_FrontController {
 		}
 		}
 		$loginOk = $this->accessControl(Minz_Session::param('currentUser', ''));
 		$loginOk = $this->accessControl(Minz_Session::param('currentUser', ''));
 		$this->loadParamsView();
 		$this->loadParamsView();
-		if (Minz_Request::isPost() && (empty($_SERVER['HTTP_REFERER']) ||
-			Minz_Request::getDomainName() !== parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST))) {
+		if (Minz_Request::isPost() && !is_referer_from_same_domain()) {
 			$loginOk = false;	//Basic protection against XSRF attacks
 			$loginOk = false;	//Basic protection against XSRF attacks
 			Minz_Error::error(
 			Minz_Error::error(
 				403,
 				403,
@@ -140,11 +139,21 @@ class FreshRSS extends Minz_FrontController {
 		}
 		}
 	}
 	}
 
 
-	private function loadStylesAndScripts ($loginOk) {
+	private function loadStylesAndScripts($loginOk) {
 		$theme = FreshRSS_Themes::load($this->conf->theme);
 		$theme = FreshRSS_Themes::load($this->conf->theme);
 		if ($theme) {
 		if ($theme) {
 			foreach($theme['files'] as $file) {
 			foreach($theme['files'] as $file) {
-				Minz_View::appendStyle (Minz_Url::display ('/themes/' . $theme['id'] . '/' . $file . '?' . @filemtime(PUBLIC_PATH . '/themes/' . $theme['id'] . '/' . $file)));
+				if ($file[0] === '_') {
+					$theme_id = 'base-theme';
+					$filename = substr($file, 1);
+				} else {
+					$theme_id = $theme['id'];
+					$filename = $file;
+				}
+				$filetime = @filemtime(PUBLIC_PATH . '/themes/' . $theme_id . '/' . $filename);
+				Minz_View::appendStyle(Minz_Url::display(
+					'/themes/' . $theme_id . '/' . $filename . '?' . $filetime
+				));
 			}
 			}
 		}
 		}
 
 

+ 37 - 2
app/Models/Configuration.php

@@ -45,6 +45,8 @@ class FreshRSS_Configuration {
 			'load_more' => 'm',
 			'load_more' => 'm',
 			'auto_share' => 's',
 			'auto_share' => 's',
 			'focus_search' => 'a',
 			'focus_search' => 'a',
+			'user_filter' => 'u',
+			'help' => 'f1',
 		),
 		),
 		'topline_read' => true,
 		'topline_read' => true,
 		'topline_favorite' => true,
 		'topline_favorite' => true,
@@ -58,6 +60,7 @@ class FreshRSS_Configuration {
 		'bottomline_link' => true,
 		'bottomline_link' => true,
 		'sharing' => array(),
 		'sharing' => array(),
 		'queries' => array(),
 		'queries' => array(),
+		'html5_notif_timeout' => 0,
 	);
 	);
 
 
 	private $available_languages = array(
 	private $available_languages = array(
@@ -120,6 +123,16 @@ class FreshRSS_Configuration {
 		return $this->available_languages;
 		return $this->available_languages;
 	}
 	}
 
 
+	public function remove_query_by_get($get) {
+		$final_queries = array();
+		foreach ($this->queries as $key => $query) {
+			if (empty($query['get']) || $query['get'] !== $get) {
+				$final_queries[$key] = $query;
+			}
+		}
+		$this->_queries($final_queries);
+	}
+
 	public function _language($value) {
 	public function _language($value) {
 		if (!isset($this->available_languages[$value])) {
 		if (!isset($this->available_languages[$value])) {
 			$value = 'en';
 			$value = 'en';
@@ -138,7 +151,18 @@ class FreshRSS_Configuration {
 		}
 		}
 	}
 	}
 	public function _default_view ($value) {
 	public function _default_view ($value) {
-		$this->data['default_view'] = $value === FreshRSS_Entry::STATE_ALL ? FreshRSS_Entry::STATE_ALL : FreshRSS_Entry::STATE_NOT_READ;
+		switch ($value) {
+		case FreshRSS_Entry::STATE_ALL:
+			// left blank on purpose
+		case FreshRSS_Entry::STATE_NOT_READ:
+			// left blank on purpose
+		case FreshRSS_Entry::STATE_STRICT + FreshRSS_Entry::STATE_NOT_READ:
+			$this->data['default_view'] = $value;
+			break;
+		default:
+			$this->data['default_view'] = FreshRSS_Entry::STATE_ALL;
+			break;
+		}
 	}
 	}
 	public function _display_posts ($value) {
 	public function _display_posts ($value) {
 		$this->data['display_posts'] = ((bool)$value) && $value !== 'no';
 		$this->data['display_posts'] = ((bool)$value) && $value !== 'no';
@@ -209,6 +233,7 @@ class FreshRSS_Configuration {
 	}
 	}
 	public function _sharing ($values) {
 	public function _sharing ($values) {
 		$this->data['sharing'] = array();
 		$this->data['sharing'] = array();
+		$unique = array();
 		foreach ($values as $value) {
 		foreach ($values as $value) {
 			if (!is_array($value)) {
 			if (!is_array($value)) {
 				continue;
 				continue;
@@ -234,7 +259,11 @@ class FreshRSS_Configuration {
 				$value['name'] = $value['type'];
 				$value['name'] = $value['type'];
 			}
 			}
 
 
-			$this->data['sharing'][] = $value;
+			$json_value = json_encode($value);
+			if (!in_array($json_value, $unique)) {
+				$unique[] = $json_value;
+				$this->data['sharing'][] = $value;
+			}
 		}
 		}
 	}
 	}
 	public function _queries ($values) {
 	public function _queries ($values) {
@@ -261,6 +290,12 @@ class FreshRSS_Configuration {
 			$this->data['content_width'] = 'thin';
 			$this->data['content_width'] = 'thin';
 		}
 		}
 	}
 	}
+	
+	public function _html5_notif_timeout ($value) {
+		$value = intval($value);
+		$this->data['html5_notif_timeout'] = $value >= 0 ? $value : 0;
+	}
+	
 	public function _token($value) {
 	public function _token($value) {
 		$this->data['token'] = $value;
 		$this->data['token'] = $value;
 	}
 	}

+ 1 - 0
app/Models/Entry.php

@@ -6,6 +6,7 @@ class FreshRSS_Entry extends Minz_Model {
 	const STATE_NOT_READ = 2;
 	const STATE_NOT_READ = 2;
 	const STATE_FAVORITE = 4;
 	const STATE_FAVORITE = 4;
 	const STATE_NOT_FAVORITE = 8;
 	const STATE_NOT_FAVORITE = 8;
+	const STATE_STRICT = 16;
 
 
 	private $id = 0;
 	private $id = 0;
 	private $guid;
 	private $guid;

+ 2 - 0
app/Models/EntryDAO.php

@@ -333,6 +333,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
 		if ($state & FreshRSS_Entry::STATE_NOT_READ) {
 		if ($state & FreshRSS_Entry::STATE_NOT_READ) {
 			if (!($state & FreshRSS_Entry::STATE_READ)) {
 			if (!($state & FreshRSS_Entry::STATE_READ)) {
 				$where .= 'AND e1.is_read=0 ';
 				$where .= 'AND e1.is_read=0 ';
+			} elseif ($state & FreshRSS_Entry::STATE_STRICT) {
+				$where .= 'AND e1.is_read=0 ';
 			}
 			}
 		}
 		}
 		elseif ($state & FreshRSS_Entry::STATE_READ) {
 		elseif ($state & FreshRSS_Entry::STATE_READ) {

+ 1 - 1
app/Models/FeedDAO.php

@@ -331,7 +331,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
 		$id_max = intval($date_min) . '000000';
 		$id_max = intval($date_min) . '000000';
 
 
 		$stm->bindParam(':id_feed', $id, PDO::PARAM_INT);
 		$stm->bindParam(':id_feed', $id, PDO::PARAM_INT);
-		$stm->bindParam(':id_max', $id_max, PDO::PARAM_INT);
+		$stm->bindParam(':id_max', $id_max, PDO::PARAM_STR);
 		$stm->bindParam(':keep', $keep, PDO::PARAM_INT);
 		$stm->bindParam(':keep', $keep, PDO::PARAM_INT);
 
 
 		if ($stm && $stm->execute()) {
 		if ($stm && $stm->execute()) {

+ 69 - 0
app/Models/StatsDAO.php

@@ -151,6 +151,74 @@ SQL;
 		return $this->convertToSerie($repartition);
 		return $this->convertToSerie($repartition);
 	}
 	}
 
 
+	/**
+	 * Calculates the average number of article per hour per feed
+	 *
+	 * @param integer $feed id
+	 * @return integer
+	 */
+	public function calculateEntryAveragePerFeedPerHour($feed = null) {
+		return $this->calculateEntryAveragePerFeedPerPeriod(1/24, $feed);
+	}
+	
+	/**
+	 * Calculates the average number of article per day of week per feed
+	 *
+	 * @param integer $feed id
+	 * @return integer
+	 */
+	public function calculateEntryAveragePerFeedPerDayOfWeek($feed = null) {
+		return $this->calculateEntryAveragePerFeedPerPeriod(7, $feed);
+	}
+
+	/**
+	 * Calculates the average number of article per month per feed
+	 *
+	 * @param integer $feed id
+	 * @return integer
+	 */
+	public function calculateEntryAveragePerFeedPerMonth($feed = null) {
+		return $this->calculateEntryAveragePerFeedPerPeriod(30, $feed);
+	}
+	
+	/**
+	 * Calculates the average number of article per feed
+	 * 
+	 * @param float $period number used to divide the number of day in the period
+	 * @param integer $feed id
+	 * @return integer
+	 */
+	protected function calculateEntryAveragePerFeedPerPeriod($period, $feed = null) {
+		if ($feed) {
+			$restrict = "WHERE e.id_feed = {$feed}";
+		} else {
+			$restrict = '';
+		}
+		$sql = <<<SQL
+SELECT COUNT(1) AS count
+, MIN(date) AS date_min
+, MAX(date) AS date_max
+FROM {$this->prefix}entry AS e
+{$restrict}
+SQL;
+		$stm = $this->bd->prepare($sql);
+		$stm->execute();
+		$res = $stm->fetch(PDO::FETCH_NAMED);
+		$date_min = new \DateTime();
+		$date_min->setTimestamp($res['date_min']);
+		$date_max = new \DateTime();
+		$date_max->setTimestamp($res['date_max']);
+		$interval = $date_max->diff($date_min, true);
+		$interval_in_days = $interval->format('%a');
+		if ($interval_in_days <= 0) {
+			// Surely only one article.
+			// We will return count / (period/period) == count.
+			$interval_in_days = $period;
+		}
+
+		return round($res['count'] / ($interval_in_days / $period), 2);
+	}
+
 	/**
 	/**
 	 * Initialize an array for statistics depending on a range
 	 * Initialize an array for statistics depending on a range
 	 *
 	 *
@@ -247,6 +315,7 @@ SQL;
 SELECT MAX(f.id) as id
 SELECT MAX(f.id) as id
 , MAX(f.name) AS name
 , MAX(f.name) AS name
 , MAX(date) AS last_date
 , MAX(date) AS last_date
+, COUNT(*) AS nb_articles
 FROM {$this->prefix}feed AS f,
 FROM {$this->prefix}feed AS f,
 {$this->prefix}entry AS e
 {$this->prefix}entry AS e
 WHERE f.id = e.id_feed
 WHERE f.id = e.id_feed

+ 1 - 0
app/Models/StatsDAOSQLite.php

@@ -53,6 +53,7 @@ SQL;
 		$stm->execute();
 		$stm->execute();
 		$res = $stm->fetchAll(PDO::FETCH_NAMED);
 		$res = $stm->fetchAll(PDO::FETCH_NAMED);
 
 
+		$repartition = array();
 		foreach ($res as $value) {
 		foreach ($res as $value) {
 			$repartition[(int) $value['period']] = (int) $value['count'];
 			$repartition[(int) $value['period']] = (int) $value['count'];
 		}
 		}

+ 1 - 0
app/Models/Themes.php

@@ -96,6 +96,7 @@ class FreshRSS_Themes extends Minz_Model {
 			'search' => '🔍',
 			'search' => '🔍',
 			'share' => '♺',
 			'share' => '♺',
 			'starred' => '★',
 			'starred' => '★',
+			'stats' => '%',
 			'tag' => '⚐',
 			'tag' => '⚐',
 			'up' => '△',
 			'up' => '△',
 			'view-normal' => '☰',
 			'view-normal' => '☰',

+ 45 - 8
app/i18n/en.php

@@ -5,6 +5,7 @@ return array (
 	'login'				=> 'Login',
 	'login'				=> 'Login',
 	'keep_logged_in'		=> 'Keep me logged in <small>(1 month)</small>',
 	'keep_logged_in'		=> 'Keep me logged in <small>(1 month)</small>',
 	'login_with_persona'		=> 'Login with Persona',
 	'login_with_persona'		=> 'Login with Persona',
+	'login_persona_problem'		=> 'Connection problem with Persona?',
 	'logout'			=> 'Logout',
 	'logout'			=> 'Logout',
 	'search'			=> 'Search words or #tags',
 	'search'			=> 'Search words or #tags',
 	'search_short'			=> 'Search',
 	'search_short'			=> 'Search',
@@ -42,9 +43,11 @@ return array (
 	'query_state_15'		=> 'Display all articles',
 	'query_state_15'		=> 'Display all articles',
 	'query_number'			=> 'Query n°%d',
 	'query_number'			=> 'Query n°%d',
 	'add_query'			=> 'Add a query',
 	'add_query'			=> 'Add a query',
+	'query_created'			=> 'Query "%s" has been created.',
 	'no_query'			=> 'You haven’t created any user query yet.',
 	'no_query'			=> 'You haven’t created any user query yet.',
 	'query_filter'			=> 'Filter applied:',
 	'query_filter'			=> 'Filter applied:',
 	'no_query_filter'		=> 'No filter',
 	'no_query_filter'		=> 'No filter',
+	'query_deprecated'		=> 'This query is no longer valid. The referenced category or feed has been deleted.',
 	'about'				=> 'About',
 	'about'				=> 'About',
 	'stats'				=> 'Statistics',
 	'stats'				=> 'Statistics',
 	'stats_idle'			=> 'Idle feeds',
 	'stats_idle'			=> 'Idle feeds',
@@ -92,6 +95,7 @@ return array (
 	'rss_view'			=> 'RSS feed',
 	'rss_view'			=> 'RSS feed',
 	'show_all_articles'		=> 'Show all articles',
 	'show_all_articles'		=> 'Show all articles',
 	'show_not_reads'		=> 'Show only unread',
 	'show_not_reads'		=> 'Show only unread',
+	'show_adaptive'			=> 'Adjust showing',
 	'show_read'			=> 'Show only read',
 	'show_read'			=> 'Show only read',
 	'show_favorite'			=> 'Show only favorites',
 	'show_favorite'			=> 'Show only favorites',
 	'show_not_favorite'		=> 'Show all but favorites',
 	'show_not_favorite'		=> 'Show all but favorites',
@@ -111,7 +115,7 @@ return array (
 	'access_denied'			=> 'You don’t have permission to access this page',
 	'access_denied'			=> 'You don’t have permission to access this page',
 	'page_not_found'		=> 'You are looking for a page which doesn’t exist',
 	'page_not_found'		=> 'You are looking for a page which doesn’t exist',
 	'error_occurred'		=> 'An error occurred',
 	'error_occurred'		=> 'An error occurred',
-	'error_occurred_update'	=> 'Nothing was changed',
+	'error_occurred_update'		=> 'Nothing was changed',
 
 
 	'default_category'		=> 'Uncategorized',
 	'default_category'		=> 'Uncategorized',
 	'categories_updated'		=> 'Categories have been updated',
 	'categories_updated'		=> 'Categories have been updated',
@@ -152,10 +156,13 @@ return array (
 	'public'			=> 'Public',
 	'public'			=> 'Public',
 	'invalid_login'			=> 'Login is invalid',
 	'invalid_login'			=> 'Login is invalid',
 
 
+	'file_is_nok'			=> 'Check permissions on <em>%s</em> directory. HTTP server must have rights to write into.',
+
 	// VIEWS
 	// VIEWS
 	'save'				=> 'Save',
 	'save'				=> 'Save',
 	'delete'			=> 'Delete',
 	'delete'			=> 'Delete',
 	'cancel'			=> 'Cancel',
 	'cancel'			=> 'Cancel',
+	'submit'			=> 'Submit',
 
 
 	'back_to_rss_feeds'		=> '← Go back to your RSS feeds',
 	'back_to_rss_feeds'		=> '← Go back to your RSS feeds',
 	'feeds_moved_category_deleted'	=> 'When you delete a category, their feeds are automatically classified under <em>%s</em>.',
 	'feeds_moved_category_deleted'	=> 'When you delete a category, their feeds are automatically classified under <em>%s</em>.',
@@ -180,6 +187,9 @@ return array (
 	'auto_share'			=> 'Share',
 	'auto_share'			=> 'Share',
 	'auto_share_help'		=> 'If there is only one sharing mode, it is used. Else modes are accessible by their number.',
 	'auto_share_help'		=> 'If there is only one sharing mode, it is used. Else modes are accessible by their number.',
 	'focus_search'			=> 'Access search box',
 	'focus_search'			=> 'Access search box',
+	'user_filter'			=> 'Access user filters',
+	'user_filter_help'		=> 'If there is only one user filter, it is used. Else filters are accessible by their number.',
+	'help'				=> 'Display documentation',
 
 
 	'file_to_import'		=> 'File to import<br />(OPML, Json or Zip)',
 	'file_to_import'		=> 'File to import<br />(OPML, Json or Zip)',
 	'file_to_import_no_zip'		=> 'File to import<br />(OPML or Json)',
 	'file_to_import_no_zip'		=> 'File to import<br />(OPML or Json)',
@@ -197,13 +207,15 @@ return array (
 
 
 	'informations'			=> 'Information',
 	'informations'			=> 'Information',
 	'damn'				=> 'Damn!',
 	'damn'				=> 'Damn!',
+	'ok'				=> 'Ok!',
+	'attention'			=> 'Be careful!',
 	'feed_in_error'			=> 'This feed has encountered a problem. Please verify that it is always reachable then actualize it.',
 	'feed_in_error'			=> 'This feed has encountered a problem. Please verify that it is always reachable then actualize it.',
 	'feed_empty'			=> 'This feed is empty. Please verify that it is still maintained.',
 	'feed_empty'			=> 'This feed is empty. Please verify that it is still maintained.',
 	'feed_description'		=> 'Description',
 	'feed_description'		=> 'Description',
 	'website_url'			=> 'Website URL',
 	'website_url'			=> 'Website URL',
 	'feed_url'			=> 'Feed URL',
 	'feed_url'			=> 'Feed URL',
 	'articles'			=> 'articles',
 	'articles'			=> 'articles',
-	'number_articles'		=> 'Number of articles',
+	'number_articles'		=> '%d articles',
 	'by_feed'			=> 'by feed',
 	'by_feed'			=> 'by feed',
 	'by_default'			=> 'By default',
 	'by_default'			=> 'By default',
 	'keep_history'			=> 'Minimum number of articles to keep',
 	'keep_history'			=> 'Minimum number of articles to keep',
@@ -225,7 +237,7 @@ return array (
 	'not_yet_implemented'		=> 'Not yet implemented',
 	'not_yet_implemented'		=> 'Not yet implemented',
 	'access_protected_feeds'	=> 'Connection allows to access HTTP protected RSS feeds',
 	'access_protected_feeds'	=> 'Connection allows to access HTTP protected RSS feeds',
 	'no_selected_feed'		=> 'No feed selected.',
 	'no_selected_feed'		=> 'No feed selected.',
-	'think_to_add'			=> '<a href="./?c=configure&amp;a=feed">You may add some feeds</a>.',
+	'think_to_add'			=> 'You may add some feeds.',
 
 
 	'current_user'			=> 'Current user',
 	'current_user'			=> 'Current user',
 	'default_user'			=> 'Username of the default user <small>(maximum 16 alphanumeric characters)</small>',
 	'default_user'			=> 'Username of the default user <small>(maximum 16 alphanumeric characters)</small>',
@@ -237,7 +249,7 @@ return array (
 	'unsafe_autologin'		=> 'Allow unsafe automatic login using the format: ',
 	'unsafe_autologin'		=> 'Allow unsafe automatic login using the format: ',
 	'api_enabled'			=> 'Allow <abbr>API</abbr> access <small>(required for mobile apps)</small>',
 	'api_enabled'			=> 'Allow <abbr>API</abbr> access <small>(required for mobile apps)</small>',
 	'auth_token'			=> 'Authentication token',
 	'auth_token'			=> 'Authentication token',
-	'explain_token'			=> 'Allows to access RSS output of the default user without authentication.<br /><kbd>%s?output=rss&token=%s</kbd>',
+	'explain_token'			=> 'Allows to access RSS output of the default user without authentication.<br /><kbd>%s?output=rss&amp;token=%s</kbd>',
 	'login_configuration'		=> 'Login',
 	'login_configuration'		=> 'Login',
 	'is_admin'			=> 'is administrator',
 	'is_admin'			=> 'is administrator',
 	'auth_type'			=> 'Authentication method',
 	'auth_type'			=> 'Authentication method',
@@ -248,6 +260,7 @@ return array (
 	'users_list'			=> 'List of users',
 	'users_list'			=> 'List of users',
 	'create_user'			=> 'Create new user',
 	'create_user'			=> 'Create new user',
 	'username'			=> 'Username',
 	'username'			=> 'Username',
+	'username_admin'		=> 'Administrator username',
 	'password'			=> 'Password',
 	'password'			=> 'Password',
 	'create'			=> 'Create',
 	'create'			=> 'Create',
 	'user_created'			=> 'User %s has been created',
 	'user_created'			=> 'User %s has been created',
@@ -256,31 +269,35 @@ return array (
 	'language'			=> 'Language',
 	'language'			=> 'Language',
 	'month'				=> 'months',
 	'month'				=> 'months',
 	'archiving_configuration'	=> 'Archiving',
 	'archiving_configuration'	=> 'Archiving',
-	'delete_articles_every'	=> 'Remove articles after',
+	'delete_articles_every'		=> 'Remove articles after',
 	'purge_now'			=> 'Purge now',
 	'purge_now'			=> 'Purge now',
 	'purge_completed'		=> 'Purge completed (%d articles deleted)',
 	'purge_completed'		=> 'Purge completed (%d articles deleted)',
 	'archiving_configuration_help'	=> 'More options are available in the individual stream settings',
 	'archiving_configuration_help'	=> 'More options are available in the individual stream settings',
 	'reading_configuration'		=> 'Reading',
 	'reading_configuration'		=> 'Reading',
 	'display_configuration'		=> 'Display',
 	'display_configuration'		=> 'Display',
 	'articles_per_page'		=> 'Number of articles per page',
 	'articles_per_page'		=> 'Number of articles per page',
+	'number_divided_when_reader'	=> 'Divided by 2 in the reading view.',
 	'default_view'			=> 'Default view',
 	'default_view'			=> 'Default view',
+	'articles_to_display'		=> 'Articles to display',
 	'sort_order'			=> 'Sort order',
 	'sort_order'			=> 'Sort order',
 	'auto_load_more'		=> 'Load next articles at the page bottom',
 	'auto_load_more'		=> 'Load next articles at the page bottom',
 	'display_articles_unfolded'	=> 'Show articles unfolded by default',
 	'display_articles_unfolded'	=> 'Show articles unfolded by default',
 	'display_categories_unfolded'	=> 'Show categories folded by default',
 	'display_categories_unfolded'	=> 'Show categories folded by default',
-	'hide_read_feeds'		=> 'Hide categories &amp; feeds with no unread article (only in “unread articles” display mode)',
+	'hide_read_feeds'		=> 'Hide categories &amp; feeds with no unread article (does not work with “Show all articles” configuration)',
 	'after_onread'			=> 'After “mark all as read”,',
 	'after_onread'			=> 'After “mark all as read”,',
 	'jump_next'			=> 'jump to next unread sibling (feed or category)',
 	'jump_next'			=> 'jump to next unread sibling (feed or category)',
 	'article_icons'			=> 'Article icons',
 	'article_icons'			=> 'Article icons',
 	'top_line'			=> 'Top line',
 	'top_line'			=> 'Top line',
 	'bottom_line'			=> 'Bottom line',
 	'bottom_line'			=> 'Bottom line',
+	'html5_notif_timeout'		=> 'HTML5 notification timeout',
+	'seconds_(0_means_no_timeout)'	=> 'seconds (0 means no timeout)',
 	'img_with_lazyload'		=> 'Use "lazy load" mode to load pictures',
 	'img_with_lazyload'		=> 'Use "lazy load" mode to load pictures',
 	'sticky_post'			=> 'Stick the article to the top when opened',
 	'sticky_post'			=> 'Stick the article to the top when opened',
 	'reading_confirm'		=> 'Display a confirmation dialog on “mark all as read” actions',
 	'reading_confirm'		=> 'Display a confirmation dialog on “mark all as read” actions',
 	'auto_read_when'		=> 'Mark article as read…',
 	'auto_read_when'		=> 'Mark article as read…',
 	'article_viewed'		=> 'when article is viewed',
 	'article_viewed'		=> 'when article is viewed',
 	'article_open_on_website'	=> 'when article is opened on its original website',
 	'article_open_on_website'	=> 'when article is opened on its original website',
-	'scroll'			=> 'during page scrolls',
+	'scroll'			=> 'while scrolling',
 	'upon_reception'		=> 'upon reception of the article',
 	'upon_reception'		=> 'upon reception of the article',
 	'your_shaarli'			=> 'Your Shaarli',
 	'your_shaarli'			=> 'Your Shaarli',
 	'your_wallabag'			=> 'Your wallabag',
 	'your_wallabag'			=> 'Your wallabag',
@@ -340,7 +357,7 @@ return array (
 	'agpl3'				=> '<a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPL 3</a>',
 	'agpl3'				=> '<a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPL 3</a>',
 	'freshrss_description'		=> 'FreshRSS is a RSS feeds aggregator to self-host like <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> or <a href="http://projet.idleman.fr/leed/">Leed</a>. It is light and easy to take in hand while being powerful and configurable tool.',
 	'freshrss_description'		=> 'FreshRSS is a RSS feeds aggregator to self-host like <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> or <a href="http://projet.idleman.fr/leed/">Leed</a>. It is light and easy to take in hand while being powerful and configurable tool.',
 	'credits'			=> 'Credits',
 	'credits'			=> 'Credits',
-	'credits_content'		=> 'Some design elements come from <a href="http://twitter.github.io/bootstrap/">Bootstrap</a> although FreshRSS doesn’t use this framework. <a href="https://git.gnome.org/browse/gnome-icon-theme-symbolic">Icons</a> come from <a href="https://www.gnome.org/">GNOME project</a>. <em>Open Sans</em> font police used has been created by <a href="https://www.google.com/webfonts/specimen/Open+Sans">Steve Matteson</a>. Favicons are collected with <a href="https://getfavicon.appspot.com/">getFavicon API</a>. FreshRSS is based on <a href="https://github.com/marienfressinaud/MINZ">Minz</a>, a PHP framework.',
+	'credits_content'		=> 'Some design elements come from <a href="http://twitter.github.io/bootstrap/">Bootstrap</a> although FreshRSS doesn’t use this framework. <a href="https://git.gnome.org/browse/gnome-icon-theme-symbolic">Icons</a> come from <a href="https://www.gnome.org/">GNOME project</a>. <em>Open Sans</em> font police has been created by <a href="https://www.google.com/webfonts/specimen/Open+Sans">Steve Matteson</a>. Favicons are collected with <a href="https://getfavicon.appspot.com/">getFavicon API</a>. FreshRSS is based on <a href="https://github.com/marienfressinaud/MINZ">Minz</a>, a PHP framework.',
 	'version'			=> 'Version',
 	'version'			=> 'Version',
 
 
 	'logs'				=> 'Logs',
 	'logs'				=> 'Logs',
@@ -351,6 +368,7 @@ return array (
 	'login_required'		=> 'Login required:',
 	'login_required'		=> 'Login required:',
 
 
 	'confirm_action'		=> 'Are you sure you want to perform this action? It cannot be cancelled!',
 	'confirm_action'		=> 'Are you sure you want to perform this action? It cannot be cancelled!',
+	'confirm_action_feed_cat'	=> 'Are you sure you want to perform this action? You may lost related favorites and user queries. It cannot be cancelled!',
 	'notif_title_new_articles'	=> 'FreshRSS: new articles!',
 	'notif_title_new_articles'	=> 'FreshRSS: new articles!',
 	'notif_body_new_articles'	=> 'There are \d new articles to read on FreshRSS.',
 	'notif_body_new_articles'	=> 'There are \d new articles to read on FreshRSS.',
 
 
@@ -414,4 +432,23 @@ return array (
 	'stats_entry_per_category'	=> 'Entries per category',
 	'stats_entry_per_category'	=> 'Entries per category',
 	'stats_top_feed'		=> 'Top ten feeds',
 	'stats_top_feed'		=> 'Top ten feeds',
 	'stats_entry_count'		=> 'Entry count',
 	'stats_entry_count'		=> 'Entry count',
+	'stats_no_idle'			=> 'There is no idle feed!',
+
+	'update'			=> 'Update',
+	'update_system'			=> 'Update system',
+	'update_check'			=> 'Check for new updates',
+	'update_last'			=> 'Last verification: %s',
+	'update_can_apply'		=> 'An update is available.',
+	'update_apply'			=> 'Apply',
+	'update_server_not_found'	=> 'Update server cannot be found. [%s]',
+	'no_update'			=> 'No update to apply',
+	'update_problem'		=> 'The update process has encountered an error: %s',
+	'update_finished'		=> 'Update completed!',
+
+	'auth_reset'			=> 'Authentication reset',
+	'auth_will_reset'		=> 'Authentication system will be reset: a form will be used instead of Persona.',
+	'auth_not_persona'		=> 'Only Persona system can be reset.',
+	'auth_no_password_set'		=> 'Administrator password hasn’t been set. This feature isn’t available.',
+	'auth_form_set'			=> 'Form is now your default authentication system.',
+	'auth_form_not_set'		=> 'A problem occured during authentication system configuration. Please retry later.',
 );
 );

+ 46 - 9
app/i18n/fr.php

@@ -5,6 +5,7 @@ return array (
 	'login'				=> 'Connexion',
 	'login'				=> 'Connexion',
 	'keep_logged_in'		=> 'Rester connecté <small>(1 mois)</small>',
 	'keep_logged_in'		=> 'Rester connecté <small>(1 mois)</small>',
 	'login_with_persona'		=> 'Connexion avec Persona',
 	'login_with_persona'		=> 'Connexion avec Persona',
+	'login_persona_problem'		=> 'Problème de connexion à Persona ?',
 	'logout'			=> 'Déconnexion',
 	'logout'			=> 'Déconnexion',
 	'search'			=> 'Rechercher des mots ou des #tags',
 	'search'			=> 'Rechercher des mots ou des #tags',
 	'search_short'			=> 'Rechercher',
 	'search_short'			=> 'Rechercher',
@@ -42,9 +43,11 @@ return array (
 	'query_state_15'		=> 'Afficher tous les articles',
 	'query_state_15'		=> 'Afficher tous les articles',
 	'query_number'			=> 'Filtre n°%d',
 	'query_number'			=> 'Filtre n°%d',
 	'add_query'			=> 'Créer un filtre',
 	'add_query'			=> 'Créer un filtre',
+	'query_created'			=> 'Le filtre "%s" a bien été créé.',
 	'no_query'			=> 'Vous n’avez pas encore créé de filtre.',
 	'no_query'			=> 'Vous n’avez pas encore créé de filtre.',
 	'query_filter'			=> 'Filtres appliqués :',
 	'query_filter'			=> 'Filtres appliqués :',
 	'no_query_filter'		=> 'Aucun filtre appliqué',
 	'no_query_filter'		=> 'Aucun filtre appliqué',
+	'query_deprecated'		=> 'Ce filtre n’est plus valide. La catégorie ou le flux concerné a été supprimé.',
 	'about'				=> 'À propos',
 	'about'				=> 'À propos',
 	'stats'				=> 'Statistiques',
 	'stats'				=> 'Statistiques',
 	'stats_idle'			=> 'Flux inactifs',
 	'stats_idle'			=> 'Flux inactifs',
@@ -54,11 +57,11 @@ return array (
 	'stats_entry_per_day_of_week'	=> 'Par jour de la semaine',
 	'stats_entry_per_day_of_week'	=> 'Par jour de la semaine',
 	'stats_entry_per_month'		=> 'Par mois',
 	'stats_entry_per_month'		=> 'Par mois',
 
 
-	'last_week'			=> 'La dernière semaine',
-	'last_month'			=> 'Le dernier mois',
-	'last_3_month'			=> 'Les derniers trois mois',
-	'last_6_month'			=> 'Les derniers six mois',
-	'last_year'			=> 'La dernière année',
+	'last_week'			=> 'Depuis la semaine dernière',
+	'last_month'			=> 'Depuis le mois dernier',
+	'last_3_month'			=> 'Depuis les trois derniers mois',
+	'last_6_month'			=> 'Depuis les six derniers mois',
+	'last_year'			=> 'Depuis l’année dernière',
 
 
 	'your_rss_feeds'		=> 'Vos flux RSS',
 	'your_rss_feeds'		=> 'Vos flux RSS',
 	'add_rss_feed'			=> 'Ajouter un flux RSS',
 	'add_rss_feed'			=> 'Ajouter un flux RSS',
@@ -92,6 +95,7 @@ return array (
 	'rss_view'			=> 'Flux RSS',
 	'rss_view'			=> 'Flux RSS',
 	'show_all_articles'		=> 'Afficher tous les articles',
 	'show_all_articles'		=> 'Afficher tous les articles',
 	'show_not_reads'		=> 'Afficher les non lus',
 	'show_not_reads'		=> 'Afficher les non lus',
+	'show_adaptive'			=> 'Adapter l’affichage',
 	'show_read'			=> 'Afficher les lus',
 	'show_read'			=> 'Afficher les lus',
 	'show_favorite'			=> 'Afficher les favoris',
 	'show_favorite'			=> 'Afficher les favoris',
 	'show_not_favorite'		=> 'Afficher tout sauf les favoris',
 	'show_not_favorite'		=> 'Afficher tout sauf les favoris',
@@ -152,10 +156,13 @@ return array (
 	'public'			=> 'Public',
 	'public'			=> 'Public',
 	'invalid_login'			=> 'L’identifiant est invalide !',
 	'invalid_login'			=> 'L’identifiant est invalide !',
 
 
+	'file_is_nok'			=> 'Veuillez vérifier les droits sur le répertoire <em>%s</em>. Le serveur HTTP doit être capable d’écrire dedans.',
+
 	// VIEWS
 	// VIEWS
 	'save'				=> 'Enregistrer',
 	'save'				=> 'Enregistrer',
 	'delete'			=> 'Supprimer',
 	'delete'			=> 'Supprimer',
 	'cancel'			=> 'Annuler',
 	'cancel'			=> 'Annuler',
+	'submit'			=> 'Valider',
 
 
 	'back_to_rss_feeds'		=> '← Retour à vos flux RSS',
 	'back_to_rss_feeds'		=> '← Retour à vos flux RSS',
 	'feeds_moved_category_deleted'	=> 'Lors de la suppression d’une catégorie, ses flux seront automatiquement classés dans <em>%s</em>.',
 	'feeds_moved_category_deleted'	=> 'Lors de la suppression d’une catégorie, ses flux seront automatiquement classés dans <em>%s</em>.',
@@ -180,6 +187,9 @@ return array (
 	'auto_share'			=> 'Partager',
 	'auto_share'			=> 'Partager',
 	'auto_share_help'		=> 'S’il n’y a qu’un mode de partage, celui ci est utilisé automatiquement. Sinon ils sont accessibles par leur numéro.',
 	'auto_share_help'		=> 'S’il n’y a qu’un mode de partage, celui ci est utilisé automatiquement. Sinon ils sont accessibles par leur numéro.',
 	'focus_search'			=> 'Accéder à la recherche',
 	'focus_search'			=> 'Accéder à la recherche',
+	'user_filter'			=> 'Accéder aux filtres utilisateur',
+	'user_filter_help'		=> 'S’il n’y a qu’un filtre utilisateur, celui ci est utilisé automatiquement. Sinon ils sont accessibles par leur numéro.',
+	'help'				=> 'Afficher la documentation',
 
 
 	'file_to_import'		=> 'Fichier à importer<br />(OPML, Json ou Zip)',
 	'file_to_import'		=> 'Fichier à importer<br />(OPML, Json ou Zip)',
 	'file_to_import_no_zip'		=> 'Fichier à importer<br />(OPML ou Json)',
 	'file_to_import_no_zip'		=> 'Fichier à importer<br />(OPML ou Json)',
@@ -197,13 +207,15 @@ return array (
 
 
 	'informations'			=> 'Informations',
 	'informations'			=> 'Informations',
 	'damn'				=> 'Arf !',
 	'damn'				=> 'Arf !',
+	'ok'				=> 'Ok !',
+	'attention'			=> 'Attention !',
 	'feed_in_error'			=> 'Ce flux a rencontré un problème. Veuillez vérifier qu’il est toujours accessible puis actualisez-le.',
 	'feed_in_error'			=> 'Ce flux a rencontré un problème. Veuillez vérifier qu’il est toujours accessible puis actualisez-le.',
 	'feed_empty'			=> 'Ce flux est vide. Veuillez vérifier qu’il est toujours maintenu.',
 	'feed_empty'			=> 'Ce flux est vide. Veuillez vérifier qu’il est toujours maintenu.',
 	'feed_description'		=> 'Description',
 	'feed_description'		=> 'Description',
 	'website_url'			=> 'URL du site',
 	'website_url'			=> 'URL du site',
 	'feed_url'			=> 'URL du flux',
 	'feed_url'			=> 'URL du flux',
 	'articles'			=> 'articles',
 	'articles'			=> 'articles',
-	'number_articles'		=> 'Nombre d’articles',
+	'number_articles'		=> '%d articles',
 	'by_feed'			=> 'par flux',
 	'by_feed'			=> 'par flux',
 	'by_default'			=> 'Par défaut',
 	'by_default'			=> 'Par défaut',
 	'keep_history'			=> 'Nombre minimum d’articles à conserver',
 	'keep_history'			=> 'Nombre minimum d’articles à conserver',
@@ -225,7 +237,7 @@ return array (
 	'not_yet_implemented'		=> 'Pas encore implémenté',
 	'not_yet_implemented'		=> 'Pas encore implémenté',
 	'access_protected_feeds'	=> 'La connexion permet d’accéder aux flux protégés par une authentification HTTP.',
 	'access_protected_feeds'	=> 'La connexion permet d’accéder aux flux protégés par une authentification HTTP.',
 	'no_selected_feed'		=> 'Aucun flux sélectionné.',
 	'no_selected_feed'		=> 'Aucun flux sélectionné.',
-	'think_to_add'			=> '<a href="./?c=configure&amp;a=feed">Vous pouvez ajouter des flux</a>.',
+	'think_to_add'			=> 'Vous pouvez ajouter des flux.',
 
 
 	'current_user'			=> 'Utilisateur actuel',
 	'current_user'			=> 'Utilisateur actuel',
 	'password_form'			=> 'Mot de passe<br /><small>(pour connexion par formulaire)</small>',
 	'password_form'			=> 'Mot de passe<br /><small>(pour connexion par formulaire)</small>',
@@ -237,7 +249,7 @@ return array (
 	'unsafe_autologin'		=> 'Autoriser les connexions automatiques non-sûres au format : ',
 	'unsafe_autologin'		=> 'Autoriser les connexions automatiques non-sûres au format : ',
 	'api_enabled'			=> 'Autoriser l’accès par <abbr>API</abbr> <small>(nécessaire pour les applis mobiles)</small>',
 	'api_enabled'			=> 'Autoriser l’accès par <abbr>API</abbr> <small>(nécessaire pour les applis mobiles)</small>',
 	'auth_token'			=> 'Jeton d’identification',
 	'auth_token'			=> 'Jeton d’identification',
-	'explain_token'			=> 'Permet d’accéder à la sortie RSS de l’utilisateur par défaut sans besoin de s’authentifier.<br /><kbd>%s?output=rss&token=%s</kbd>',
+	'explain_token'			=> 'Permet d’accéder à la sortie RSS de l’utilisateur par défaut sans besoin de s’authentifier.<br /><kbd>%s?output=rss&amp;token=%s</kbd>',
 	'login_configuration'		=> 'Identification',
 	'login_configuration'		=> 'Identification',
 	'is_admin'			=> 'est administrateur',
 	'is_admin'			=> 'est administrateur',
 	'auth_type'			=> 'Méthode d’authentification',
 	'auth_type'			=> 'Méthode d’authentification',
@@ -248,6 +260,7 @@ return array (
 	'users_list'			=> 'Liste des utilisateurs',
 	'users_list'			=> 'Liste des utilisateurs',
 	'create_user'			=> 'Créer un nouvel utilisateur',
 	'create_user'			=> 'Créer un nouvel utilisateur',
 	'username'			=> 'Nom d’utilisateur',
 	'username'			=> 'Nom d’utilisateur',
+	'username_admin'		=> 'Nom d’utilisateur administrateur',
 	'password'			=> 'Mot de passe',
 	'password'			=> 'Mot de passe',
 	'create'			=> 'Créer',
 	'create'			=> 'Créer',
 	'user_created'			=> 'L’utilisateur %s a été créé.',
 	'user_created'			=> 'L’utilisateur %s a été créé.',
@@ -263,17 +276,21 @@ return array (
 	'reading_configuration'		=> 'Lecture',
 	'reading_configuration'		=> 'Lecture',
 	'display_configuration'		=> 'Affichage',
 	'display_configuration'		=> 'Affichage',
 	'articles_per_page'		=> 'Nombre d’articles par page',
 	'articles_per_page'		=> 'Nombre d’articles par page',
+	'number_divided_when_reader'	=> 'Divisé par 2 dans la vue de lecture.',
 	'default_view'			=> 'Vue par défaut',
 	'default_view'			=> 'Vue par défaut',
+	'articles_to_display'		=> 'Articles à afficher',
 	'sort_order'			=> 'Ordre de tri',
 	'sort_order'			=> 'Ordre de tri',
 	'auto_load_more'		=> 'Charger les articles suivants en bas de page',
 	'auto_load_more'		=> 'Charger les articles suivants en bas de page',
 	'display_articles_unfolded'	=> 'Afficher les articles dépliés par défaut',
 	'display_articles_unfolded'	=> 'Afficher les articles dépliés par défaut',
 	'display_categories_unfolded'	=> 'Afficher les catégories pliées par défaut',
 	'display_categories_unfolded'	=> 'Afficher les catégories pliées par défaut',
-	'hide_read_feeds'		=> 'Cacher les catégories &amp; flux sans article non-lu (uniquement en affichage “articles non lus”)',
+	'hide_read_feeds'		=> 'Cacher les catégories &amp; flux sans article non-lu (ne fonctionne pas avec la configuration “Afficher tous les articles”)',
 	'after_onread'			=> 'Après “marquer tout comme lu”,',
 	'after_onread'			=> 'Après “marquer tout comme lu”,',
 	'jump_next'			=> 'sauter au prochain voisin non lu (flux ou catégorie)',
 	'jump_next'			=> 'sauter au prochain voisin non lu (flux ou catégorie)',
 	'article_icons'			=> 'Icônes d’article',
 	'article_icons'			=> 'Icônes d’article',
 	'top_line'			=> 'Ligne du haut',
 	'top_line'			=> 'Ligne du haut',
 	'bottom_line'			=> 'Ligne du bas',
 	'bottom_line'			=> 'Ligne du bas',
+	'html5_notif_timeout'		=> 'Temps d’affichage de la notification HTML5',
+	'seconds_(0_means_no_timeout)'	=> 'secondes (0 signifie aucun timeout ) ',
 	'img_with_lazyload'		=> 'Utiliser le mode “chargement différé” pour les images',
 	'img_with_lazyload'		=> 'Utiliser le mode “chargement différé” pour les images',
 	'sticky_post'			=> 'Aligner l’article en haut quand il est ouvert',
 	'sticky_post'			=> 'Aligner l’article en haut quand il est ouvert',
 	'reading_confirm'		=> 'Afficher une confirmation lors des actions “marquer tout comme lu”',
 	'reading_confirm'		=> 'Afficher une confirmation lors des actions “marquer tout comme lu”',
@@ -351,6 +368,7 @@ return array (
 	'login_required'		=> 'Accès protégé par mot de passe :',
 	'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 !',
 	'confirm_action'		=> 'Êtes-vous sûr(e) de vouloir continuer ? Cette action ne peut être annulée !',
+	'confirm_action_feed_cat'	=> 'Êtes-vous sûr(e) de vouloir continuer ? Vous pourriez perdre les favoris et les filtres associés. Cette action ne peut être annulée !',
 	'notif_title_new_articles'	=> 'FreshRSS : nouveaux articles !',
 	'notif_title_new_articles'	=> 'FreshRSS : nouveaux articles !',
 	'notif_body_new_articles'	=> 'Il y a \d nouveaux articles à lire sur FreshRSS.',
 	'notif_body_new_articles'	=> 'Il y a \d nouveaux articles à lire sur FreshRSS.',
 
 
@@ -414,4 +432,23 @@ return array (
 	'stats_entry_per_category'	=> 'Articles par catégorie',
 	'stats_entry_per_category'	=> 'Articles par catégorie',
 	'stats_top_feed'		=> 'Les dix plus gros flux',
 	'stats_top_feed'		=> 'Les dix plus gros flux',
 	'stats_entry_count'		=> 'Nombre d’articles',
 	'stats_entry_count'		=> 'Nombre d’articles',
+	'stats_no_idle'			=> 'Il n’y a aucun flux inactif !',
+
+	'update'			=> 'Mise à jour',
+	'update_system'			=> 'Système de mise à jour',
+	'update_check'			=> 'Vérifier les mises à jour',
+	'update_last'			=> 'Dernière vérification : %s',
+	'update_can_apply'		=> 'Une mise à jour est disponible.',
+	'update_apply'			=> 'Appliquer la mise à jour',
+	'update_server_not_found'	=> 'Le serveur de mise à jour n’a pas été trouvé. [%s]',
+	'no_update'			=> 'Aucune mise à jour à appliquer',
+	'update_problem'		=> 'La mise à jour a rencontré un problème : %s',
+	'update_finished'		=> 'La mise à jour est terminée !',
+
+	'auth_reset'			=> 'Réinitialisation de l’authentification',
+	'auth_will_reset'		=> 'Le système d’authentification va être réinitialisé : un formulaire sera utilisé à la place de Persona.',
+	'auth_not_persona'		=> 'Seul le système d’authentification Persona peut être réinitialisé.',
+	'auth_no_password_set'		=> 'Aucun mot de passe administrateur n’a été précisé. Cette fonctionnalité n’est pas disponible.',
+	'auth_form_set'			=> 'Le formulaire est désormais votre système d’authentification.',
+	'auth_form_not_set'		=> 'Un problème est survenu lors de la configuration de votre système d’authentification. Veuillez réessayer plus tard.',
 );
 );

+ 2 - 0
app/i18n/install.en.php

@@ -42,6 +42,8 @@ return array (
 	'data_is_ok'			=> 'Permissions on data directory are good',
 	'data_is_ok'			=> 'Permissions on data directory are good',
 	'persona_is_ok'			=> 'Permissions on Mozilla Persona directory are good',
 	'persona_is_ok'			=> 'Permissions on Mozilla Persona directory are good',
 	'file_is_nok'			=> 'Check permissions on <em>%s</em> directory. HTTP server must have rights to write into',
 	'file_is_nok'			=> 'Check permissions on <em>%s</em> directory. HTTP server must have rights to write into',
+	'http_referer_is_ok'		=> 'Your HTTP REFERER is known and corresponds to your server.',
+	'http_referer_is_nok'		=> 'Please check that you are not altering your HTTP REFERER.',
 	'fix_errors_before'		=> 'Fix errors before skip to the next step.',
 	'fix_errors_before'		=> 'Fix errors before skip to the next step.',
 
 
 	'general_conf_is_ok'		=> 'General configuration has been saved.',
 	'general_conf_is_ok'		=> 'General configuration has been saved.',

+ 2 - 0
app/i18n/install.fr.php

@@ -42,6 +42,8 @@ return array (
 	'data_is_ok'			=> 'Les droits sur le répertoire de data sont bons',
 	'data_is_ok'			=> 'Les droits sur le répertoire de data sont bons',
 	'persona_is_ok'			=> 'Les droits sur le répertoire de Mozilla Persona sont bons',
 	'persona_is_ok'			=> 'Les droits sur le répertoire de Mozilla Persona sont bons',
 	'file_is_nok'			=> 'Veuillez vérifier les droits sur le répertoire <em>%s</em>. Le serveur HTTP doit être capable d’écrire dedans',
 	'file_is_nok'			=> 'Veuillez vérifier les droits sur le répertoire <em>%s</em>. Le serveur HTTP doit être capable d’écrire dedans',
+	'http_referer_is_ok'		=> 'Le HTTP REFERER est connu et semble correspondre à votre serveur.',
+	'http_referer_is_nok'		=> 'Veuillez vérifier que vous ne modifiez pas votre HTTP REFERER.',
 	'fix_errors_before'		=> 'Veuillez corriger les erreurs avant de passer à l’étape suivante.',
 	'fix_errors_before'		=> 'Veuillez corriger les erreurs avant de passer à l’étape suivante.',
 
 
 	'general_conf_is_ok'		=> 'La configuration générale a été enregistrée.',
 	'general_conf_is_ok'		=> 'La configuration générale a été enregistrée.',

Dosya farkı çok büyük olduğundan ihmal edildi
+ 246 - 509
app/install.php


+ 23 - 15
app/layout/aside_configure.phtml

@@ -1,25 +1,33 @@
 <ul class="nav nav-list aside">
 <ul class="nav nav-list aside">
-	<li class="nav-header"><?php echo Minz_Translate::t ('configuration'); ?></li>
-	<li class="item<?php echo Minz_Request::actionName () == 'display' ? ' active' : ''; ?>">
-		<a href="<?php echo _url ('configure', 'display'); ?>"><?php echo Minz_Translate::t ('display_configuration'); ?></a>
+	<li class="nav-header"><?php echo _t('configuration'); ?></li>
+	<li class="item<?php echo Minz_Request::actionName() === 'display' ? ' active' : ''; ?>">
+		<a href="<?php echo _url('configure', 'display'); ?>"><?php echo _t('display_configuration'); ?></a>
 	</li>
 	</li>
-	<li class="item<?php echo Minz_Request::actionName () == 'reading' ? ' active' : ''; ?>">
-		<a href="<?php echo _url ('configure', 'reading'); ?>"><?php echo Minz_Translate::t ('reading_configuration'); ?></a>
+	<li class="item<?php echo Minz_Request::actionName() === 'reading' ? ' active' : ''; ?>">
+		<a href="<?php echo _url('configure', 'reading'); ?>"><?php echo _t('reading_configuration'); ?></a>
 	</li>
 	</li>
-	<li class="item<?php echo Minz_Request::actionName () == 'archiving' ? ' active' : ''; ?>">
-		<a href="<?php echo _url ('configure', 'archiving'); ?>"><?php echo Minz_Translate::t ('archiving_configuration'); ?></a>
+	<li class="item<?php echo Minz_Request::actionName() === 'archiving' ? ' active' : ''; ?>">
+		<a href="<?php echo _url('configure', 'archiving'); ?>"><?php echo _t('archiving_configuration'); ?></a>
 	</li>
 	</li>
-	<li class="item<?php echo Minz_Request::actionName () == 'sharing' ? ' active' : ''; ?>">
-		<a href="<?php echo _url ('configure', 'sharing'); ?>"><?php echo Minz_Translate::t ('sharing'); ?></a>
+	<li class="item<?php echo Minz_Request::actionName() === 'sharing' ? ' active' : ''; ?>">
+		<a href="<?php echo _url('configure', 'sharing'); ?>"><?php echo _t('sharing'); ?></a>
 	</li>
 	</li>
-	<li class="item<?php echo Minz_Request::actionName () == 'shortcut' ? ' active' : ''; ?>">
-		<a href="<?php echo _url ('configure', 'shortcut'); ?>"><?php echo Minz_Translate::t ('shortcuts'); ?></a>
+	<li class="item<?php echo Minz_Request::actionName() === 'shortcut' ? ' active' : ''; ?>">
+		<a href="<?php echo _url('configure', 'shortcut'); ?>"><?php echo _t('shortcuts'); ?></a>
 	</li>
 	</li>
-	<li class="item<?php echo Minz_Request::actionName () == 'queries' ? ' active' : ''; ?>">
-		<a href="<?php echo _url ('configure', 'queries'); ?>"><?php echo Minz_Translate::t ('queries'); ?></a>
+	<li class="item<?php echo Minz_Request::actionName() === 'queries' ? ' active' : ''; ?>">
+		<a href="<?php echo _url('configure', 'queries'); ?>"><?php echo _t('queries'); ?></a>
 	</li>
 	</li>
 	<li class="separator"></li>
 	<li class="separator"></li>
-	<li class="item<?php echo Minz_Request::actionName () == 'users' ? ' active' : ''; ?>">
-		<a href="<?php echo _url ('configure', 'users'); ?>"><?php echo Minz_Translate::t ('users'); ?></a>
+	<li class="item<?php echo Minz_Request::actionName() === 'users' ? ' active' : ''; ?>">
+		<a href="<?php echo _url('configure', 'users'); ?>"><?php echo _t('users'); ?></a>
 	</li>
 	</li>
+	<?php
+		$current_user = Minz_Session::param('currentUser', '');
+		if (Minz_Configuration::isAdmin($current_user)) {
+	?>
+	<li class="item<?php echo Minz_Request::controllerName() === 'update' ? ' active' : ''; ?>">
+		<a href="<?php echo _url('update', 'index'); ?>"><?php echo _t('update'); ?></a>
+	</li>
+	<?php } ?>
 </ul>
 </ul>

+ 41 - 33
app/layout/aside_flux.phtml

@@ -1,16 +1,18 @@
 <div class="aside aside_flux<?php if ($this->conf->hide_read_feeds && ($this->state & FreshRSS_Entry::STATE_NOT_READ) && !($this->state & FreshRSS_Entry::STATE_READ)) echo ' state_unread'; ?>" id="aside_flux">
 <div class="aside aside_flux<?php if ($this->conf->hide_read_feeds && ($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>
+	<a class="toggle_aside" href="#close"><?php echo _i('close'); ?></a>
 
 
 	<ul class="categories">
 	<ul class="categories">
 		<?php if ($this->loginOk) { ?>
 		<?php if ($this->loginOk) { ?>
+		<form id="mark-read-aside" method="post" style="display: none"></form>
+
 		<li>
 		<li>
-			<div class="stick">
-				<a class="btn btn-important" href="<?php echo _url ('configure', 'feed'); ?>"><?php echo Minz_Translate::t ('subscription_management'); ?></a>
-				<a class="btn btn-important" href="<?php echo _url ('configure', 'categorize'); ?>" title="<?php echo Minz_Translate::t ('categories_management'); ?>"><?php echo FreshRSS_Themes::icon('category-white'); ?></a>
+			<div class="stick configure-feeds">
+				<a class="btn btn-important" href="<?php echo _url('configure', 'feed'); ?>"><?php echo _t('subscription_management'); ?></a>
+				<a class="btn btn-important" href="<?php echo _url('configure', 'categorize'); ?>" title="<?php echo _t('categories_management'); ?>"><?php echo _i('category-white'); ?></a>
 			</div>
 			</div>
 		</li>
 		</li>
 		<?php } elseif (Minz_Configuration::needsLogin()) { ?>
 		<?php } elseif (Minz_Configuration::needsLogin()) { ?>
-		<li><a href="<?php echo _url ('index', 'about'); ?>"><?php echo Minz_Translate::t ('about_freshrss'); ?></a></li>
+		<li><a href="<?php echo _url('index', 'about'); ?>"><?php echo _t('about_freshrss'); ?></a></li>
 		<?php } ?>
 		<?php } ?>
 
 
 		<?php
 		<?php
@@ -22,8 +24,8 @@
 		<li>
 		<li>
 			<div class="category all<?php echo $this->get_c == 'a' ? ' active' : ''; ?>">
 			<div class="category all<?php echo $this->get_c == 'a' ? ' active' : ''; ?>">
 				<a data-unread="<?php echo formatNumber($this->nb_not_read); ?>" class="btn<?php echo $this->get_c == 'a' ? ' active' : ''; ?>" href="<?php echo Minz_Url::display($arUrl); ?>">
 				<a data-unread="<?php echo formatNumber($this->nb_not_read); ?>" class="btn<?php echo $this->get_c == 'a' ? ' active' : ''; ?>" href="<?php echo Minz_Url::display($arUrl); ?>">
-					<?php echo FreshRSS_Themes::icon('all'); ?>
-					<?php echo Minz_Translate::t ('main_stream'); ?>
+					<?php echo _i('all'); ?>
+					<?php echo _t('main_stream'); ?>
 				</a>
 				</a>
 			</div>
 			</div>
 		</li>
 		</li>
@@ -31,44 +33,42 @@
 		<li>
 		<li>
 			<div class="category favorites<?php echo $this->get_c == 's' ? ' active' : ''; ?>">
 			<div class="category favorites<?php echo $this->get_c == 's' ? ' active' : ''; ?>">
 				<a data-unread="<?php echo formatNumber($this->nb_favorites['unread']); ?>" class="btn<?php echo $this->get_c == 's' ? ' active' : ''; ?>" href="<?php $arUrl['params']['get'] = 's'; echo Minz_Url::display($arUrl); ?>">
 				<a data-unread="<?php echo formatNumber($this->nb_favorites['unread']); ?>" class="btn<?php echo $this->get_c == 's' ? ' active' : ''; ?>" href="<?php $arUrl['params']['get'] = 's'; echo Minz_Url::display($arUrl); ?>">
-					<?php echo FreshRSS_Themes::icon('bookmark'); ?>
-					<?php echo Minz_Translate::t('favorite_feeds', formatNumber($this->nb_favorites['all'])); ?>
+					<?php echo _i('bookmark'); ?>
+					<?php echo _t('favorite_feeds', formatNumber($this->nb_favorites['all'])); ?>
 				</a>
 				</a>
 			</div>
 			</div>
 		</li>
 		</li>
 
 
 		<?php
 		<?php
 		foreach ($this->cat_aside as $cat) {
 		foreach ($this->cat_aside as $cat) {
-			$feeds = $cat->feeds ();
-			if (!empty ($feeds)) {
+			$feeds = $cat->feeds();
+			if (!empty($feeds)) {
 				$c_active = false;
 				$c_active = false;
-				if ($this->conf->display_categories) {
-					if ($this->get_c == $cat->id () && $this->get_f) {
-						$c_active = true;
-					}
-				} else {
-					if ($this->get_c == $cat->id ()) {
-						$c_active = true;
+				$c_show = false;
+				if ($this->get_c == $cat->id()) {
+					$c_active = true;
+					if (!$this->conf->display_categories || $this->get_f) {
+						$c_show = true;
 					}
 					}
 				}
 				}
 				?><li data-unread="<?php echo $cat->nbNotRead(); ?>"<?php if ($c_active) echo ' class="active"'; ?>><?php
 				?><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
 				?><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
+					?><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 _i($c_show ? 'up' : 'down'); ?></a><?php
 				?></div><?php
 				?></div><?php
-				?><ul class="feeds<?php echo $c_active ? ' active' : ''; ?>"><?php
+				?><ul class="feeds<?php echo $c_show ? ' active' : ''; ?>"><?php
 				foreach ($feeds as $feed) {
 				foreach ($feeds as $feed) {
-					$feed_id = $feed->id ();
-					$nbEntries = $feed->nbEntries ();
+					$feed_id = $feed->id();
+					$nbEntries = $feed->nbEntries();
 					$f_active = ($this->get_f == $feed_id);
 					$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' : ''; ?>" data-unread="<?php echo $feed->nbNotRead(); ?>"><?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"><?php
 							?><div class="dropdown-target"></div><?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
+							?><a class="dropdown-toggle" data-fweb="<?php echo $feed->website(); ?>"><?php echo _i('configure'); ?></a><?php
 							/* feed_config_template */
 							/* feed_config_template */
 						?></div><?php
 						?></div><?php
-						?> <img class="favicon" src="<?php echo $feed->favicon (); ?>" alt="✇" /> <?php
-						?><a class="feed" data-unread="<?php echo formatNumber($feed->nbNotRead()); ?>" data-priority="<?php echo $feed->priority (); ?>" href="<?php $arUrl['params']['get'] = 'f_' . $feed_id; echo Minz_Url::display($arUrl); ?>"><?php echo $feed->name(); ?></a><?php
+						?> <img class="favicon" src="<?php echo $feed->favicon(); ?>" alt="✇" /> <?php
+						?><a class="feed" data-unread="<?php echo formatNumber($feed->nbNotRead()); ?>" data-priority="<?php echo $feed->priority(); ?>" href="<?php $arUrl['params']['get'] = 'f_' . $feed_id; echo Minz_Url::display($arUrl); ?>"><?php echo $feed->name(); ?></a><?php
 					?></li><?php
 					?></li><?php
 				}
 				}
 				?></ul><?php
 				?></ul><?php
@@ -82,14 +82,22 @@
 <script id="feed_config_template" type="text/html">
 <script id="feed_config_template" type="text/html">
 	<ul class="dropdown-menu">
 	<ul class="dropdown-menu">
 		<li class="dropdown-close"><a href="#close">❌</a></li>
 		<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>
+		<li class="item"><a href="<?php echo _url('index', 'index', 'get', 'f_!!!!!!'); ?>"><?php echo _t('filter'); ?></a></li>
+		<?php if ($this->loginOk) { ?>
+		<li class="item"><a href="<?php echo _url('stats', 'repartition', 'id', '!!!!!!'); ?>"><?php echo _t('stats'); ?></a></li>
+		<?php } ?>
+		<li class="item"><a target="_blank" href="http://example.net/"><?php echo _t('see_website'); ?></a></li>
 		<?php if ($this->loginOk) { ?>
 		<?php if ($this->loginOk) { ?>
 		<li class="separator"></li>
 		<li class="separator"></li>
-		<li class="item"><a href="<?php echo _url ('configure', 'feed', 'id', '!!!!!!'); ?>"><?php echo Minz_Translate::t ('administration'); ?></a></li>
-		<li class="item"><a href="<?php echo _url ('feed', 'actualize', 'id', '!!!!!!'); ?>"><?php echo Minz_Translate::t ('actualize'); ?></a></li>
-		<li class="item"><a href="<?php echo _url ('entry', 'read', 'get', 'f_!!!!!!'); ?>"><?php echo Minz_Translate::t ('mark_read'); ?></a></li>
+		<li class="item"><a href="<?php echo _url('configure', 'feed', 'id', '!!!!!!'); ?>"><?php echo _t('administration'); ?></a></li>
+		<li class="item"><a href="<?php echo _url('feed', 'actualize', 'id', '!!!!!!'); ?>"><?php echo _t('actualize'); ?></a></li>
+		<li class="item">
+			<?php $confirm = $this->conf->reading_confirm ? 'confirm' : ''; ?>
+			<button class="read_all as-link <?php echo $confirm; ?>"
+			        form="mark-read-aside"
+			        formaction="<?php echo _url('entry', 'read', 'get', 'f_!!!!!!'); ?>"
+			        type="submit"><?php echo _t('mark_read'); ?></button>
+		</li>
 		<?php } ?>
 		<?php } ?>
 	</ul>
 	</ul>
 </script>
 </script>

+ 6 - 0
app/layout/header.phtml

@@ -75,6 +75,12 @@ if (Minz_Configuration::canLogIn()) {
 				<li class="item"><a href="<?php echo _url('configure', 'queries'); ?>"><?php echo _t('queries'); ?></a></li>
 				<li class="item"><a href="<?php echo _url('configure', 'queries'); ?>"><?php echo _t('queries'); ?></a></li>
 				<li class="separator"></li>
 				<li class="separator"></li>
 				<li class="item"><a href="<?php echo _url('configure', 'users'); ?>"><?php echo _t('users'); ?></a></li>
 				<li class="item"><a href="<?php echo _url('configure', 'users'); ?>"><?php echo _t('users'); ?></a></li>
+				<?php
+					$current_user = Minz_Session::param('currentUser', '');
+					if (Minz_Configuration::isAdmin($current_user)) {
+				?>
+				<li class="item"><a href="<?php echo _url('update', 'index'); ?>"><?php echo _t('update'); ?></a></li>
+				<?php } ?>
 				<li class="separator"></li>
 				<li class="separator"></li>
 				<li class="item"><a href="<?php echo _url('stats', 'index'); ?>"><?php echo _t('stats'); ?></a></li>
 				<li class="item"><a href="<?php echo _url('stats', 'index'); ?>"><?php echo _t('stats'); ?></a></li>
 				<li class="item"><a href="<?php echo _url('index', 'logs'); ?>"><?php echo _t('logs'); ?></a></li>
 				<li class="item"><a href="<?php echo _url('index', 'logs'); ?>"><?php echo _t('logs'); ?></a></li>

+ 1 - 0
app/layout/layout.phtml

@@ -13,6 +13,7 @@
 	if (!empty($this->nextId)) {
 	if (!empty($this->nextId)) {
 		$params = Minz_Request::params();
 		$params = Minz_Request::params();
 		$params['next'] = $this->nextId;
 		$params['next'] = $this->nextId;
+		$params['ajax'] = 1;
 ?>
 ?>
 		<link id="prefetch" rel="next prefetch" href="<?php echo Minz_Url::display(array('c' => Minz_Request::controllerName(), 'a' => Minz_Request::actionName(), 'params' => $params)); ?>" />
 		<link id="prefetch" rel="next prefetch" href="<?php echo Minz_Url::display(array('c' => Minz_Request::controllerName(), 'a' => Minz_Request::actionName(), 'params' => $params)); ?>" />
 <?php } ?>
 <?php } ?>

+ 101 - 74
app/layout/nav_menu.phtml

@@ -3,11 +3,11 @@
 ?>
 ?>
 <div class="nav_menu">
 <div class="nav_menu">
 	<?php if ($actual_view === 'normal') { ?>
 	<?php if ($actual_view === 'normal') { ?>
-	<a class="btn toggle_aside" href="#aside_flux"><?php echo FreshRSS_Themes::icon('category'); ?></a>
+	<a class="btn toggle_aside" href="#aside_flux"><?php echo _i('category'); ?></a>
 	<?php } ?>
 	<?php } ?>
 
 
 	<?php if ($this->loginOk) { ?>
 	<?php if ($this->loginOk) { ?>
-	<div class="stick">
+	<div id="nav_menu_actions" class="stick">
 		<?php
 		<?php
 			$url_state = $this->url;
 			$url_state = $this->url;
 
 
@@ -24,9 +24,9 @@
 		<a id="toggle-read"
 		<a id="toggle-read"
 		   class="btn <?php echo $class; ?>"
 		   class="btn <?php echo $class; ?>"
 		   aria-checked="<?php echo $checked; ?>"
 		   aria-checked="<?php echo $checked; ?>"
-		   href="<?php echo Minz_Url::display ($url_state); ?>"
-		   title="<?php echo Minz_Translate::t ('show_read'); ?>">
-			<?php echo FreshRSS_Themes::icon('read'); ?>
+		   href="<?php echo Minz_Url::display($url_state); ?>"
+		   title="<?php echo _t('show_read'); ?>">
+			<?php echo _i('read'); ?>
 		</a>
 		</a>
 
 
 		<?php
 		<?php
@@ -43,13 +43,13 @@
 		<a id="toggle-unread"
 		<a id="toggle-unread"
 		   class="btn <?php echo $class; ?>"
 		   class="btn <?php echo $class; ?>"
 		   aria-checked="<?php echo $checked; ?>"
 		   aria-checked="<?php echo $checked; ?>"
-		   href="<?php echo Minz_Url::display ($url_state); ?>"
-		   title="<?php echo Minz_Translate::t ('show_not_reads'); ?>">
-			<?php echo FreshRSS_Themes::icon('unread'); ?>
+		   href="<?php echo Minz_Url::display($url_state); ?>"
+		   title="<?php echo _t('show_not_reads'); ?>">
+			<?php echo _i('unread'); ?>
 		</a>
 		</a>
 
 
 		<?php
 		<?php
-			if ($this->state & FreshRSS_Entry::STATE_FAVORITE) {
+			if ($this->state & FreshRSS_Entry::STATE_FAVORITE || $this->get_c == 's') {
 				$url_state['params']['state'] = $this->state & ~FreshRSS_Entry::STATE_FAVORITE;
 				$url_state['params']['state'] = $this->state & ~FreshRSS_Entry::STATE_FAVORITE;
 				$checked = 'true';
 				$checked = 'true';
 				$class = 'active';
 				$class = 'active';
@@ -62,9 +62,9 @@
 		<a id="toggle-favorite"
 		<a id="toggle-favorite"
 		   class="btn <?php echo $class; ?>"
 		   class="btn <?php echo $class; ?>"
 		   aria-checked="<?php echo $checked; ?>"
 		   aria-checked="<?php echo $checked; ?>"
-		   href="<?php echo Minz_Url::display ($url_state); ?>"
-		   title="<?php echo Minz_Translate::t ('show_favorite'); ?>">
-			<?php echo FreshRSS_Themes::icon('starred'); ?>
+		   href="<?php echo Minz_Url::display($url_state); ?>"
+		   title="<?php echo _t('show_favorite'); ?>">
+			<?php echo _i('starred'); ?>
 		</a>
 		</a>
 
 
 		<?php
 		<?php
@@ -81,22 +81,25 @@
 		<a id="toggle-not-favorite"
 		<a id="toggle-not-favorite"
 		   class="btn <?php echo $class; ?>"
 		   class="btn <?php echo $class; ?>"
 		   aria-checked="<?php echo $checked; ?>"
 		   aria-checked="<?php echo $checked; ?>"
-		   href="<?php echo Minz_Url::display ($url_state); ?>"
-		   title="<?php echo Minz_Translate::t ('show_not_favorite'); ?>">
-			<?php echo FreshRSS_Themes::icon('non-starred'); ?>
+		   href="<?php echo Minz_Url::display($url_state); ?>"
+		   title="<?php echo _t('show_not_favorite'); ?>">
+			<?php echo _i('non-starred'); ?>
 		</a>
 		</a>
 
 
 		<div class="dropdown">
 		<div class="dropdown">
 			<div id="dropdown-query" class="dropdown-target"></div>
 			<div id="dropdown-query" class="dropdown-target"></div>
 
 
-			<a class="dropdown-toggle btn" href="#dropdown-query"><?php echo FreshRSS_Themes::icon('down'); ?></a>
+			<a class="dropdown-toggle btn" href="#dropdown-query"><?php echo _i('down'); ?></a>
 			<ul class="dropdown-menu">
 			<ul class="dropdown-menu">
 				<li class="dropdown-close"><a href="#close">❌</a></li>
 				<li class="dropdown-close"><a href="#close">❌</a></li>
 
 
-				<li class="dropdown-header"><?php echo Minz_Translate::t('queries'); ?> <a class="no-mobile" href="<?php echo _url('configure', 'queries'); ?>"><?php echo FreshRSS_Themes::icon('configure'); ?></a></li>
+				<li class="dropdown-header">
+					<?php echo _t('queries'); ?>
+					<a class="no-mobile" href="<?php echo _url('configure', 'queries'); ?>"><?php echo _i('configure'); ?></a>
+				</li>
 
 
 				<?php foreach ($this->conf->queries as $query) { ?>
 				<?php foreach ($this->conf->queries as $query) { ?>
-				<li class="item">
+				<li class="item query">
 					<a href="<?php echo $query['url']; ?>"><?php echo $query['name']; ?></a>
 					<a href="<?php echo $query['url']; ?>"><?php echo $query['name']; ?></a>
 				</li>
 				</li>
 				<?php } ?>
 				<?php } ?>
@@ -110,58 +113,58 @@
 					$url_query['c'] = 'configure';
 					$url_query['c'] = 'configure';
 					$url_query['a'] = 'addQuery';
 					$url_query['a'] = 'addQuery';
 				?>
 				?>
-				<li class="item no-mobile"><a href="<?php echo Minz_Url::display($url_query); ?>"><?php echo FreshRSS_Themes::icon('bookmark-add'); ?> <?php echo Minz_Translate::t('add_query'); ?></a></li>
+				<li class="item no-mobile"><a href="<?php echo Minz_Url::display($url_query); ?>"><?php echo _i('bookmark-add'); ?> <?php echo _t('add_query'); ?></a></li>
 			</ul>
 			</ul>
 		</div>
 		</div>
 	</div>
 	</div>
 	<?php
 	<?php
 		$get = false;
 		$get = false;
-		$string_mark = Minz_Translate::t ('mark_all_read');
+		$string_mark = _t('mark_all_read');
 		if ($this->get_f) {
 		if ($this->get_f) {
 			$get = 'f_' . $this->get_f;
 			$get = 'f_' . $this->get_f;
-			$string_mark = Minz_Translate::t ('mark_feed_read');
+			$string_mark = _t('mark_feed_read');
 		} elseif ($this->get_c && $this->get_c != 'a') {
 		} elseif ($this->get_c && $this->get_c != 'a') {
 			if ($this->get_c === 's') {
 			if ($this->get_c === 's') {
 				$get = 's';
 				$get = 's';
 			} else {
 			} else {
 				$get = 'c_' . $this->get_c;
 				$get = 'c_' . $this->get_c;
 			}
 			}
-			$string_mark = Minz_Translate::t ('mark_cat_read');
+			$string_mark = _t('mark_cat_read');
 		}
 		}
 		$nextGet = $get;
 		$nextGet = $get;
-		if ($this->conf->onread_jump_next && (strlen ($get) > 2)) {
+		if ($this->conf->onread_jump_next && strlen($get) > 2) {
 			$anotherUnreadId = '';
 			$anotherUnreadId = '';
 			$foundCurrent = false;
 			$foundCurrent = false;
 			switch ($get[0]) {
 			switch ($get[0]) {
-				case 'c':
-					foreach ($this->cat_aside as $cat) {
-						if ($cat->id () == $this->get_c) {
-							$foundCurrent = true;
-							continue;
-						}
-						if ($cat->nbNotRead () <= 0) continue;
-						$anotherUnreadId = $cat->id ();
-						if ($foundCurrent) break;
+			case 'c':
+				foreach ($this->cat_aside as $cat) {
+					if ($cat->id() == $this->get_c) {
+						$foundCurrent = true;
+						continue;
 					}
 					}
-					$nextGet = empty ($anotherUnreadId) ? 'a' : 'c_' . $anotherUnreadId;
-					break;
-				case 'f':
-					foreach ($this->cat_aside as $cat) {
-						if ($cat->id () == $this->get_c) {
-							foreach ($cat->feeds () as $feed) {
-								if ($feed->id () == $this->get_f) {
-									$foundCurrent = true;
-									continue;
-								}
-								if ($feed->nbNotRead () <= 0) continue;
-								$anotherUnreadId = $feed->id ();
-								if ($foundCurrent) break;
+					if ($cat->nbNotRead() <= 0) continue;
+					$anotherUnreadId = $cat->id();
+					if ($foundCurrent) break;
+				}
+				$nextGet = empty($anotherUnreadId) ? 'a' : 'c_' . $anotherUnreadId;
+				break;
+			case 'f':
+				foreach ($this->cat_aside as $cat) {
+					if ($cat->id() == $this->get_c) {
+						foreach ($cat->feeds() as $feed) {
+							if ($feed->id() == $this->get_f) {
+								$foundCurrent = true;
+								continue;
 							}
 							}
-							break;
+							if ($feed->nbNotRead() <= 0) continue;
+							$anotherUnreadId = $feed->id();
+							if ($foundCurrent) break;
 						}
 						}
+						break;
 					}
 					}
-					$nextGet = empty ($anotherUnreadId) ? 'c_' . $this->get_c : 'f_' . $anotherUnreadId;
-					break;
+				}
+				$nextGet = empty($anotherUnreadId) ? 'c_' . $this->get_c : 'f_' . $anotherUnreadId;
+				break;
 			}
 			}
 		}
 		}
 
 
@@ -177,30 +180,54 @@
 
 
 		$arUrl = array('c' => 'entry', 'a' => 'read', 'params' => array('get' => $get, 'nextGet' => $nextGet, 'idMax' => $idMax));
 		$arUrl = array('c' => 'entry', 'a' => 'read', 'params' => array('get' => $get, 'nextGet' => $nextGet, 'idMax' => $idMax));
 		$output = Minz_Request::param('output', '');
 		$output = Minz_Request::param('output', '');
-		if (($output != '') && ($this->conf->view_mode !== $output)) {
+		if ($output != '' && $this->conf->view_mode !== $output) {
 			$arUrl['params']['output'] = $output;
 			$arUrl['params']['output'] = $output;
 		}
 		}
 		$markReadUrl = Minz_Url::display($arUrl);
 		$markReadUrl = Minz_Url::display($arUrl);
-		Minz_Session::_param ('markReadUrl', $markReadUrl);
+		Minz_Session::_param('markReadUrl', $markReadUrl);
 	?>
 	?>
 
 
+	<form id="mark-read-menu" method="post" style="display: none"></form>
+
 	<div class="stick" id="nav_menu_read_all">
 	<div class="stick" id="nav_menu_read_all">
-		<a class="read_all btn<?php if ($this->conf->reading_confirm) {echo ' confirm';} ?>" href="<?php echo $markReadUrl; ?>"><?php echo Minz_Translate::t ('mark_read'); ?></a>
+		<?php $confirm = $this->conf->reading_confirm ? 'confirm' : ''; ?>
+		<button class="read_all btn <?php echo $confirm; ?>"
+		        form="mark-read-menu"
+		        formaction="<?php echo $markReadUrl; ?>"
+		        type="submit"><?php echo _t('mark_read'); ?></button>
+
 		<div class="dropdown">
 		<div class="dropdown">
 			<div id="dropdown-read" class="dropdown-target"></div>
 			<div id="dropdown-read" class="dropdown-target"></div>
 
 
-			<a class="dropdown-toggle btn" href="#dropdown-read"><?php echo FreshRSS_Themes::icon('down'); ?></a>
+			<a class="dropdown-toggle btn" href="#dropdown-read"><?php echo _i('down'); ?></a>
 			<ul class="dropdown-menu">
 			<ul class="dropdown-menu">
 				<li class="dropdown-close"><a href="#close">❌</a></li>
 				<li class="dropdown-close"><a href="#close">❌</a></li>
 
 
-				<li class="item"><a href="<?php echo $markReadUrl; ?>"><?php echo $string_mark; ?></a></li>
+				<li class="item">
+					<button class="as-link <?php echo $confirm; ?>"
+					        form="mark-read-menu"
+					        formaction="<?php echo $markReadUrl; ?>"
+					        type="submit"><?php echo $string_mark; ?></button>
+				</li>
 				<li class="separator"></li>
 				<li class="separator"></li>
 <?php
 <?php
-	$today = $this->today;
-	$one_week = $today - 604800;
+	$mark_before_today = $arUrl;
+	$mark_before_today['params']['idMax'] = $this->today . '000000';
+	$mark_before_one_week = $arUrl;
+	$mark_before_one_week['params']['idMax'] = ($this->today - 604800) . '000000';
 ?>
 ?>
-				<li class="item"><a href="<?php echo _url ('entry', 'read', 'is_read', 1, 'get', $get, 'idMax', $today . '000000'); ?>"><?php echo Minz_Translate::t ('before_one_day'); ?></a></li>
-				<li class="item"><a href="<?php echo _url ('entry', 'read', 'is_read', 1, 'get', $get, 'idMax', $one_week . '000000'); ?>"><?php echo Minz_Translate::t ('before_one_week'); ?></a></li>
+				<li class="item">
+					<button class="as-link <?php echo $confirm; ?>"
+					        form="mark-read-menu"
+					        formaction="<?php echo Minz_Url::display($mark_before_today); ?>"
+					        type="submit"><?php echo _t('before_one_day'); ?></button>
+				</li>
+				<li class="item">
+					<button class="as-link <?php echo $confirm; ?>"
+					        form="mark-read-menu"
+					        formaction="<?php echo Minz_Url::display($mark_before_one_week); ?>"
+					        type="submit"><?php echo _t('before_one_week'); ?></button>
+				</li>
 			</ul>
 			</ul>
 		</div>
 		</div>
 	</div>
 	</div>
@@ -209,18 +236,18 @@
 	<?php $url_output = $this->url; ?>
 	<?php $url_output = $this->url; ?>
 	<div class="stick" id="nav_menu_views">
 	<div class="stick" id="nav_menu_views">
 		<?php $url_output['params']['output'] = 'normal'; ?>
 		<?php $url_output['params']['output'] = 'normal'; ?>
-		<a class="view_normal btn <?php echo $actual_view == 'normal'? 'active' : ''; ?>" title="<?php echo Minz_Translate::t('normal_view'); ?>" href="<?php echo Minz_Url::display($url_output); ?>">
-			<?php echo FreshRSS_Themes::icon("view-normal"); ?>
+		<a class="view_normal btn <?php echo $actual_view == 'normal'? 'active' : ''; ?>" title="<?php echo _t('normal_view'); ?>" href="<?php echo Minz_Url::display($url_output); ?>">
+			<?php echo _i("view-normal"); ?>
 		</a>
 		</a>
 
 
 		<?php $url_output['params']['output'] = 'global'; ?>
 		<?php $url_output['params']['output'] = 'global'; ?>
-		<a class="view_global btn <?php echo $actual_view == 'global'? 'active' : ''; ?>" title="<?php echo Minz_Translate::t('global_view'); ?>" href="<?php echo Minz_Url::display($url_output); ?>">
-			<?php echo FreshRSS_Themes::icon("view-global"); ?>
+		<a class="view_global btn <?php echo $actual_view == 'global'? 'active' : ''; ?>" title="<?php echo _t('global_view'); ?>" href="<?php echo Minz_Url::display($url_output); ?>">
+			<?php echo _i("view-global"); ?>
 		</a>
 		</a>
 
 
 		<?php $url_output['params']['output'] = 'reader'; ?>
 		<?php $url_output['params']['output'] = 'reader'; ?>
-		<a class="view_reader btn <?php echo $actual_view == 'reader'? 'active' : ''; ?>" title="<?php echo Minz_Translate::t('reader_view'); ?>" href="<?php echo Minz_Url::display($url_output); ?>">
-			<?php echo FreshRSS_Themes::icon("view-reader"); ?>
+		<a class="view_reader btn <?php echo $actual_view == 'reader'? 'active' : ''; ?>" title="<?php echo _t('reader_view'); ?>" href="<?php echo Minz_Url::display($url_output); ?>">
+			<?php echo _i("view-reader"); ?>
 		</a>
 		</a>
 
 
 		<?php
 		<?php
@@ -229,27 +256,27 @@
 				$url_output['params']['token'] = $this->conf->token;
 				$url_output['params']['token'] = $this->conf->token;
 			}
 			}
 		?>
 		?>
-		<a class="view_rss btn" target="_blank" title="<?php echo Minz_Translate::t ('rss_view'); ?>" href="<?php echo Minz_Url::display($url_output); ?>">
-			<?php echo FreshRSS_Themes::icon('rss'); ?>
+		<a class="view_rss btn" target="_blank" title="<?php echo _t('rss_view'); ?>" href="<?php echo Minz_Url::display($url_output); ?>">
+			<?php echo _i('rss'); ?>
 		</a>
 		</a>
 	</div>
 	</div>
 
 
 	<div class="item search">
 	<div class="item search">
-		<form action="<?php echo _url ('index', 'index'); ?>" method="get">
-			<?php $search = Minz_Request::param ('search', ''); ?>
-			<input type="search" name="search" class="extend" value="<?php echo $search; ?>" placeholder="<?php echo Minz_Translate::t ('search_short'); ?>" />
+		<form action="<?php echo _url('index', 'index'); ?>" method="get">
+			<?php $search = Minz_Request::param('search', ''); ?>
+			<input type="search" name="search" class="extend" value="<?php echo $search; ?>" placeholder="<?php echo _t('search_short'); ?>" />
 
 
-			<?php $get = Minz_Request::param ('get', ''); ?>
+			<?php $get = Minz_Request::param('get', ''); ?>
 			<?php if($get != '') { ?>
 			<?php if($get != '') { ?>
 			<input type="hidden" name="get" value="<?php echo $get; ?>" />
 			<input type="hidden" name="get" value="<?php echo $get; ?>" />
 			<?php } ?>
 			<?php } ?>
 
 
-			<?php $order = Minz_Request::param ('order', ''); ?>
+			<?php $order = Minz_Request::param('order', ''); ?>
 			<?php if($order != '') { ?>
 			<?php if($order != '') { ?>
 			<input type="hidden" name="order" value="<?php echo $order; ?>" />
 			<input type="hidden" name="order" value="<?php echo $order; ?>" />
 			<?php } ?>
 			<?php } ?>
 
 
-			<?php $state = Minz_Request::param ('state', ''); ?>
+			<?php $state = Minz_Request::param('state', ''); ?>
 			<?php if($state != '') { ?>
 			<?php if($state != '') { ?>
 			<input type="hidden" name="state" value="<?php echo $state; ?>" />
 			<input type="hidden" name="state" value="<?php echo $state; ?>" />
 			<?php } ?>
 			<?php } ?>
@@ -269,11 +296,11 @@
 		$url_order = $this->url;
 		$url_order = $this->url;
 		$url_order['params']['order'] = $order;
 		$url_order['params']['order'] = $order;
 	?>
 	?>
-	<a class="btn" href="<?php echo Minz_Url::display ($url_order); ?>" title="<?php echo Minz_Translate::t ($title); ?>">
-		<?php echo FreshRSS_Themes::icon($icon); ?>
+	<a id="toggle-order" class="btn" href="<?php echo Minz_Url::display($url_order); ?>" title="<?php echo _t($title); ?>">
+		<?php echo _i($icon); ?>
 	</a>
 	</a>
 	
 	
 	<?php if ($this->loginOk || Minz_Configuration::allowAnonymousRefresh()) { ?>
 	<?php if ($this->loginOk || Minz_Configuration::allowAnonymousRefresh()) { ?>
-	<a id="actualize" class="btn" href="<?php echo _url ('feed', 'actualize'); ?>"><?php echo FreshRSS_Themes::icon('refresh'); ?></a>
+	<a id="actualize" class="btn" href="<?php echo _url('feed', 'actualize'); ?>"><?php echo _i('refresh'); ?></a>
 	<?php } ?>
 	<?php } ?>
 </div>
 </div>

+ 7 - 1
app/views/configure/categorize.phtml

@@ -18,7 +18,13 @@
 					<input type="text" id="cat_<?php echo $cat->id (); ?>" name="categories[]" value="<?php echo $cat->name (); ?>" />
 					<input type="text" id="cat_<?php echo $cat->id (); ?>" name="categories[]" value="<?php echo $cat->name (); ?>" />
 
 
 					<?php if ($cat->nbFeed () > 0) { ?>
 					<?php if ($cat->nbFeed () > 0) { ?>
-					<button type="submit" class="btn btn-attention confirm" formaction="<?php echo _url ('feed', 'delete', 'id', $cat->id (), 'type', 'category'); ?>"><?php echo Minz_Translate::t ('ask_empty'); ?></button>
+					<a class="btn" href="<?php echo _url('index', 'index', 'get', 'c_' . $cat->id ()); ?>">
+						<?php echo _i('link'); ?>
+					</a>
+					<button formaction="<?php echo _url('feed', 'delete', 'id', $cat->id (), 'type', 'category'); ?>"
+					        class="btn btn-attention confirm"
+					        data-str-confirm="<?php echo _t('confirm_action_feed_cat'); ?>"
+					        type="submit"><?php echo _t('ask_empty'); ?></button>
 					<?php } ?>
 					<?php } ?>
 				</div>
 				</div>
 				(<?php echo Minz_Translate::t ('number_feeds', $cat->nbFeed ()); ?>)
 				(<?php echo Minz_Translate::t ('number_feeds', $cat->nbFeed ()); ?>)

+ 7 - 0
app/views/configure/display.phtml

@@ -91,6 +91,13 @@
 				</tbody>
 				</tbody>
 			</table><br />
 			</table><br />
 		</div>
 		</div>
+		
+		<div class="form-group">
+			<label class="group-name" for="posts_per_page"><?php echo Minz_Translate::t ('html5_notif_timeout'); ?></label>
+			<div class="group-controls">
+				<input type="number" id="html5_notif_timeout" name="html5_notif_timeout" value="<?php echo $this->conf->html5_notif_timeout; ?>" /> <?php echo Minz_Translate::t ('seconds_(0_means_no_timeout)'); ?>
+			</div>
+		</div>
 
 
 		<div class="form-group form-actions">
 		<div class="form-group form-actions">
 			<div class="group-controls">
 			<div class="group-controls">

+ 18 - 12
app/views/configure/feed.phtml

@@ -70,27 +70,33 @@
 				</label>
 				</label>
 			</div>
 			</div>
 		</div>
 		</div>
+		<div class="form-group">
+			<div class="group-controls">
+				<a href="<?php echo _url('stats', 'repartition', 'id', $this->flux->id()); ?>">
+					<?php echo _i('stats'); ?> <?php echo _t('stats'); ?>
+				</a>
+			</div>
+		</div>
 		<div class="form-group form-actions">
 		<div class="form-group form-actions">
 			<div class="group-controls">
 			<div class="group-controls">
-				<button class="btn btn-important"><?php echo Minz_Translate::t ('save'); ?></button>
-				<button class="btn btn-attention confirm" formmethod="post" formaction="<?php echo Minz_Url::display (array ('c' => 'feed', 'a' => 'delete', 'params' => array ('id' => $this->flux->id ()))); ?>"><?php echo Minz_Translate::t ('delete'); ?></button>
+				<button class="btn btn-important"><?php echo _t('save'); ?></button>
+				<button class="btn btn-attention confirm"
+				        data-str-confirm="<?php echo _t('confirm_action_feed_cat'); ?>"
+				        formaction="<?php echo _url('feed', 'delete', 'id', $this->flux->id ()); ?>"
+				        formmethod="post"><?php echo _t('delete'); ?></button>
 			</div>
 			</div>
 		</div>
 		</div>
 
 
 		<legend><?php echo Minz_Translate::t ('archiving_configuration'); ?></legend>
 		<legend><?php echo Minz_Translate::t ('archiving_configuration'); ?></legend>
 
 
 		<div class="form-group">
 		<div class="form-group">
-			<label class="group-name"></label>
 			<div class="group-controls">
 			<div class="group-controls">
-				<a class="btn" href="<?php echo _url ('feed', 'actualize', 'id', $this->flux->id ()); ?>">
-					<?php echo FreshRSS_Themes::icon('refresh'); ?> <?php echo Minz_Translate::t('actualize'); ?>
-				</a>
-			</div>
-		</div>
-		<div class="form-group">
-			<label class="group-name"><?php echo Minz_Translate::t ('number_articles'); ?></label>
-			<div class="group-controls">
-				<span class="control"><?php echo $nbEntries; ?></span>
+				<div class="stick">
+					<input type="text" value="<?php echo _t('number_articles', $nbEntries); ?>" disabled="disabled" />
+					<a class="btn" href="<?php echo _url('feed', 'actualize', 'id', $this->flux->id ()); ?>">
+						<?php echo _i('refresh'); ?> <?php echo _t('actualize'); ?>
+					</a>
+				</div>
 			</div>
 			</div>
 		</div>
 		</div>
 		<div class="form-group">
 		<div class="form-group">

+ 11 - 4
app/views/configure/queries.phtml

@@ -42,30 +42,37 @@
 						   + (isset($query['get']) ? 1 : 0);
 						   + (isset($query['get']) ? 1 : 0);
 					// If the only filter is "all" articles, we consider there is no filter
 					// If the only filter is "all" articles, we consider there is no filter
 					$exist = ($exist === 1 && isset($query['get']) && $query['get'] === 'a') ? 0 : $exist;
 					$exist = ($exist === 1 && isset($query['get']) && $query['get'] === 'a') ? 0 : $exist;
+
+					$deprecated = (isset($this->query_get[$key]) &&
+					               $this->query_get[$key]['deprecated']);
 				?>
 				?>
 
 
 				<?php if ($exist === 0) { ?>
 				<?php if ($exist === 0) { ?>
 				<div class="alert alert-warn">
 				<div class="alert alert-warn">
 					<div class="alert-head"><?php echo _t('no_query_filter'); ?></div>
 					<div class="alert-head"><?php echo _t('no_query_filter'); ?></div>
 				</div>
 				</div>
+				<?php } elseif ($deprecated) { ?>
+				<div class="alert alert-error">
+					<div class="alert-head"><?php echo _t('query_deprecated'); ?></div>
+				</div>
 				<?php } else { ?>
 				<?php } else { ?>
 				<div class="alert alert-success">
 				<div class="alert alert-success">
 					<div class="alert-head"><?php echo _t('query_filter'); ?></div>
 					<div class="alert-head"><?php echo _t('query_filter'); ?></div>
 
 
 					<ul>
 					<ul>
-						<?php if (isset($query['search'])) { $exist = true; ?>
+						<?php if (isset($query['search'])) { ?>
 						<li class="item"><?php echo _t('query_search', $query['search']); ?></li>
 						<li class="item"><?php echo _t('query_search', $query['search']); ?></li>
 						<?php } ?>
 						<?php } ?>
 
 
-						<?php if (isset($query['state'])) { $exist = true; ?>
+						<?php if (isset($query['state'])) { ?>
 						<li class="item"><?php echo _t('query_state_' . $query['state']); ?></li>
 						<li class="item"><?php echo _t('query_state_' . $query['state']); ?></li>
 						<?php } ?>
 						<?php } ?>
 
 
-						<?php if (isset($query['order'])) { $exist = true; ?>
+						<?php if (isset($query['order'])) { ?>
 						<li class="item"><?php echo _t('query_order_' . strtolower($query['order'])); ?></li>
 						<li class="item"><?php echo _t('query_order_' . strtolower($query['order'])); ?></li>
 						<?php } ?>
 						<?php } ?>
 
 
-						<?php if (isset($query['get'])) { $exist = true; ?>
+						<?php if (isset($query['get'])) { ?>
 						<li class="item"><?php echo _t('query_get_' . $this->query_get[$key]['type'], $this->query_get[$key]['name']); ?></li>
 						<li class="item"><?php echo _t('query_get_' . $this->query_get[$key]['type'], $this->query_get[$key]['name']); ?></li>
 						<?php } ?>
 						<?php } ?>
 					</ul>
 					</ul>

+ 12 - 8
app/views/configure/reading.phtml

@@ -10,6 +10,7 @@
 			<label class="group-name" for="posts_per_page"><?php echo Minz_Translate::t ('articles_per_page'); ?></label>
 			<label class="group-name" for="posts_per_page"><?php echo Minz_Translate::t ('articles_per_page'); ?></label>
 			<div class="group-controls">
 			<div class="group-controls">
 				<input type="number" id="posts_per_page" name="posts_per_page" value="<?php echo $this->conf->posts_per_page; ?>" min="5" max="50" />
 				<input type="number" id="posts_per_page" name="posts_per_page" value="<?php echo $this->conf->posts_per_page; ?>" min="5" max="50" />
+				<?php echo _i('help'); ?> <?php echo _t('number_divided_when_reader'); ?>
 			</div>
 			</div>
 		</div>
 		</div>
 
 
@@ -31,14 +32,17 @@
 					<option value="reader"<?php echo $this->conf->view_mode === 'reader' ? ' selected="selected"' : ''; ?>><?php echo Minz_Translate::t ('reader_view'); ?></option>
 					<option value="reader"<?php echo $this->conf->view_mode === 'reader' ? ' selected="selected"' : ''; ?>><?php echo Minz_Translate::t ('reader_view'); ?></option>
 					<option value="global"<?php echo $this->conf->view_mode === 'global' ? ' selected="selected"' : ''; ?>><?php echo Minz_Translate::t ('global_view'); ?></option>
 					<option value="global"<?php echo $this->conf->view_mode === 'global' ? ' selected="selected"' : ''; ?>><?php echo Minz_Translate::t ('global_view'); ?></option>
 				</select>
 				</select>
-				<label class="radio" for="radio_all">
-					<input type="radio" name="default_view" id="radio_all" value="<?php echo FreshRSS_Entry::STATE_ALL; ?>"<?php echo $this->conf->default_view === FreshRSS_Entry::STATE_ALL ? ' checked="checked"' : ''; ?> />
-					<?php echo Minz_Translate::t ('show_all_articles'); ?>
-				</label>
-				<label class="radio" for="radio_not_read">
-					<input type="radio" name="default_view" id="radio_not_read" value="<?php echo FreshRSS_Entry::STATE_NOT_READ; ?>"<?php echo $this->conf->default_view === FreshRSS_Entry::STATE_NOT_READ ? ' checked="checked"' : ''; ?> />
-					<?php echo Minz_Translate::t ('show_not_reads'); ?>
-				</label>
+			</div>
+		</div>
+
+		<div class="form-group">
+			<label class="group-name" for="view_mode"><?php echo _t('articles_to_display'); ?></label>
+			<div class="group-controls">
+				<select name="default_view" id="default_view">
+					<option value="<?php echo FreshRSS_Entry::STATE_NOT_READ; ?>"<?php echo $this->conf->default_view === FreshRSS_Entry::STATE_NOT_READ ? ' selected="selected"' : ''; ?>><?php echo _t('show_adaptive'); ?></option>
+					<option value="<?php echo FreshRSS_Entry::STATE_ALL; ?>"<?php echo $this->conf->default_view === FreshRSS_Entry::STATE_ALL ? ' selected="selected"' : ''; ?>><?php echo _t('show_all_articles'); ?></option>
+					<option value="<?php echo FreshRSS_Entry::STATE_STRICT + FreshRSS_Entry::STATE_NOT_READ; ?>"<?php echo $this->conf->default_view === FreshRSS_Entry::STATE_STRICT + FreshRSS_Entry::STATE_NOT_READ ? ' selected="selected"' : ''; ?>><?php echo _t('show_not_reads'); ?></option>
+				</select>
 			</div>
 			</div>
 		</div>
 		</div>
 
 

+ 15 - 0
app/views/configure/shortcut.phtml

@@ -103,6 +103,21 @@
 			</div>
 			</div>
 		</div>
 		</div>
 
 
+		<div class="form-group">
+			<label class="group-name" for="user_filter_shortcut"><?php echo Minz_Translate::t ('user_filter'); ?></label>
+			<div class="group-controls">
+				<input type="text" id="user_filter_shortcut" name="shortcuts[user_filter]" list="keys" value="<?php echo $s['user_filter']; ?>" />
+				<?php echo Minz_Translate::t ('user_filter_help'); ?>
+			</div>
+		</div>
+
+		<div class="form-group">
+			<label class="group-name" for="help_shortcut"><?php echo Minz_Translate::t ('help'); ?></label>
+			<div class="group-controls">
+				<input type="text" id="help_shortcut" name="shortcuts[help]" list="keys" value="<?php echo $s['help']; ?>" />
+			</div>
+		</div>
+
 		<div class="form-group form-actions">
 		<div class="form-group form-actions">
 			<div class="group-controls">
 			<div class="group-controls">
 				<button type="submit" class="btn btn-important"><?php echo Minz_Translate::t ('save'); ?></button>
 				<button type="submit" class="btn btn-important"><?php echo Minz_Translate::t ('save'); ?></button>

+ 8 - 3
app/views/helpers/javascript_vars.phtml

@@ -4,7 +4,8 @@ echo '"use strict";', "\n";
 
 
 $mark = $this->conf->mark_when;
 $mark = $this->conf->mark_when;
 echo 'var ',
 echo 'var ',
-	'hide_posts=', ($this->conf->display_posts || Minz_Request::param('output') === 'reader') ? 'false' : 'true',
+	'help_url="', FRESHRSS_WIKI, '"',
+	',hide_posts=', ($this->conf->display_posts || Minz_Request::param('output') === 'reader') ? 'false' : 'true',
 	',display_order="', Minz_Request::param('order', $this->conf->sort_order), '"',
 	',display_order="', Minz_Request::param('order', $this->conf->sort_order), '"',
 	',auto_mark_article=', $mark['article'] ? 'true' : 'false',
 	',auto_mark_article=', $mark['article'] ? 'true' : 'false',
 	',auto_mark_site=', $mark['site'] ? 'true' : 'false',
 	',auto_mark_site=', $mark['site'] ? 'true' : 'false',
@@ -25,7 +26,9 @@ echo ',shortcuts={',
 	'collapse_entry:"', $s['collapse_entry'], '",',
 	'collapse_entry:"', $s['collapse_entry'], '",',
 	'load_more:"', $s['load_more'], '",',
 	'load_more:"', $s['load_more'], '",',
 	'auto_share:"', $s['auto_share'], '",',
 	'auto_share:"', $s['auto_share'], '",',
-	'focus_search:"', $s['focus_search'], '"',
+	'focus_search:"', $s['focus_search'], '",',
+	'user_filter:"', $s['user_filter'], '",',
+	'help:"', $s['help'], '"',
 "},\n";
 "},\n";
 
 
 if (Minz_Request::param ('output') === 'global') {
 if (Minz_Request::param ('output') === 'global') {
@@ -48,9 +51,11 @@ echo 'authType="', $authType, '",',
 	'url_login="', _url ('index', 'login'), '",',
 	'url_login="', _url ('index', 'login'), '",',
 	'url_logout="', _url ('index', 'logout'), '",';
 	'url_logout="', _url ('index', 'logout'), '",';
 
 
-echo 'str_confirmation="', Minz_Translate::t('confirm_action'), '"', ",\n";
+echo 'str_confirmation_default="', Minz_Translate::t('confirm_action'), '"', ",\n";
 echo 'str_notif_title_articles="', Minz_Translate::t('notif_title_new_articles'), '"', ",\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";
 echo 'str_notif_body_articles="', Minz_Translate::t('notif_body_new_articles'), '"', ",\n";
+echo 'html5_notif_timeout=', $this->conf->html5_notif_timeout,",\n";
+
 
 
 $autoActualise = Minz_Session::param('actualize_feeds', false);
 $autoActualise = Minz_Session::param('actualize_feeds', false);
 echo 'auto_actualize_feeds=', $autoActualise ? 'true' : 'false', ";\n";
 echo 'auto_actualize_feeds=', $autoActualise ? 'true' : 'false', ";\n";

+ 26 - 15
app/views/helpers/pagination.phtml

@@ -1,26 +1,37 @@
 <?php
 <?php
-	$c = Minz_Request::controllerName ();
-	$a = Minz_Request::actionName ();
-	$params = Minz_Request::params ();
-	$markReadUrl = Minz_Session::param ('markReadUrl');
-	Minz_Session::_param ('markReadUrl', false);
+	$c = Minz_Request::controllerName();
+	$a = Minz_Request::actionName();
+	$params = Minz_Request::params();
+	$markReadUrl = Minz_Session::param('markReadUrl');
+	Minz_Session::_param('markReadUrl', false);
 ?>
 ?>
 
 
+<form id="mark-read-pagination" method="post" style="display: none"></form>
+
 <ul class="pagination">
 <ul class="pagination">
 	<li class="item pager-next">
 	<li class="item pager-next">
 	<?php if (!empty($this->nextId)) { ?>
 	<?php if (!empty($this->nextId)) { ?>
-	<?php $params['next'] = $this->nextId; ?>
-	<a id="load_more" href="<?php echo Minz_Url::display (array ('c' => $c, 'a' => $a, 'params' => $params)); ?>"><?php echo Minz_Translate::t ('load_more'); ?></a>
+		<?php
+			$params['next'] = $this->nextId;
+			$params['ajax'] = 1;
+		?>
+		<a id="load_more" href="<?php echo Minz_Url::display(array('c' => $c, 'a' => $a, 'params' => $params)); ?>">
+			<?php echo _t('load_more'); ?>
+		</a>
 	<?php } elseif ($markReadUrl) { ?>
 	<?php } elseif ($markReadUrl) { ?>
-	<a id="bigMarkAsRead" href="<?php echo $markReadUrl; ?>"<?php if ($this->conf->reading_confirm) { echo ' class="confirm"';} ?>>
-		<?php echo Minz_Translate::t ('nothing_to_load'); ?><br />
-		<span class="bigTick">✓</span><br />
-		<?php echo Minz_Translate::t ('mark_all_read'); ?>
-	</a>
+		<button id="bigMarkAsRead"
+		        class="as-link <?php echo $this->conf->reading_confirm ? 'confirm' : ''; ?>"
+		        form="mark-read-pagination"
+		        formaction="<?php echo $markReadUrl; ?>"
+		        type="submit">
+			<?php echo _t('nothing_to_load'); ?><br />
+			<span class="bigTick">✓</span><br />
+			<?php echo _t('mark_all_read'); ?>
+		</button>
 	<?php } else { ?>
 	<?php } else { ?>
-	<a id="bigMarkAsRead" href=".">
-		<?php echo Minz_Translate::t ('nothing_to_load'); ?><br />
-	</a>
+		<a id="bigMarkAsRead" href=".">
+			<?php echo _t('nothing_to_load'); ?><br />
+		</a>
 	<?php } ?>
 	<?php } ?>
 	</li>
 	</li>
 </ul>
 </ul>

+ 8 - 0
app/views/helpers/view/global_view.phtml

@@ -1,5 +1,6 @@
 <?php $this->partial ('nav_menu'); ?>
 <?php $this->partial ('nav_menu'); ?>
 
 
+<?php if (!empty($this->entries)) { ?>
 <div id="stream" class="global categories">
 <div id="stream" class="global categories">
 <?php
 <?php
 	$arUrl = array('c' => 'index', 'a' => 'index', 'params' => array());
 	$arUrl = array('c' => 'index', 'a' => 'index', 'params' => array());
@@ -43,3 +44,10 @@
 <div id="panel"<?php echo $this->conf->display_posts ? '' : ' class="hide_posts"'; ?>>
 <div id="panel"<?php echo $this->conf->display_posts ? '' : ' class="hide_posts"'; ?>>
 	<a class="close" href="#"><?php echo FreshRSS_Themes::icon('close'); ?></a>
 	<a class="close" href="#"><?php echo FreshRSS_Themes::icon('close'); ?></a>
 </div>
 </div>
+
+<?php } else { ?>
+<div id="stream" class="prompt alert alert-warn global">
+	<h2><?php echo _t('no_feed_to_display'); ?></h2>
+	<a href="<?php echo _url('configure', 'feed'); ?>"><?php echo _t('think_to_add'); ?></a><br /><br />
+</div>
+<?php } ?>

+ 3 - 3
app/views/helpers/view/normal_view.phtml

@@ -183,8 +183,8 @@ if (!empty($this->entries)) {
 <?php $this->partial ('nav_entries'); ?>
 <?php $this->partial ('nav_entries'); ?>
 
 
 <?php } else { ?>
 <?php } else { ?>
-<div id="stream" class="alert alert-warn normal">
-	<span class="alert-head"><?php echo Minz_Translate::t ('no_feed_to_display'); ?></span>
-	<?php echo Minz_Translate::t ('think_to_add'); ?>
+<div id="stream" class="prompt alert alert-warn normal">
+	<h2><?php echo _t('no_feed_to_display'); ?></h2>
+	<a href="<?php echo _url('configure', 'feed'); ?>"><?php echo _t('think_to_add'); ?></a><br /><br />
 </div>
 </div>
 <?php } ?>
 <?php } ?>

+ 3 - 3
app/views/helpers/view/reader_view.phtml

@@ -37,8 +37,8 @@ if (!empty($this->entries)) {
 </div>
 </div>
 
 
 <?php } else { ?>
 <?php } else { ?>
-<div id="stream" class="alert alert-warn reader">
-	<span class="alert-head"><?php echo Minz_Translate::t ('no_feed_to_display'); ?></span>
-	<?php echo Minz_Translate::t ('think_to_add'); ?>
+<div id="stream" class="prompt alert alert-warn reader">
+	<h2><?php echo _t('no_feed_to_display'); ?></h2>
+	<a href="<?php echo _url('configure', 'feed'); ?>"><?php echo _t('think_to_add'); ?></a><br /><br />
 </div>
 </div>
 <?php } ?>
 <?php } ?>

+ 10 - 3
app/views/index/formLogin.phtml

@@ -3,7 +3,7 @@
 
 
 	switch (Minz_Configuration::authType()) {
 	switch (Minz_Configuration::authType()) {
 	case 'form':
 	case 'form':
-	?><form id="loginForm" method="post" action="<?php echo _url('index', 'formLogin'); ?>">
+	?><form id="crypto-form" method="post" action="<?php echo _url('index', 'formLogin'); ?>">
 		<div>
 		<div>
 			<label for="username"><?php echo _t('username'); ?></label>
 			<label for="username"><?php echo _t('username'); ?></label>
 			<input type="text" id="username" name="username" size="16" required="required" maxlength="16" pattern="[0-9a-zA-Z]{1,16}" autofocus="autofocus" />
 			<input type="text" id="username" name="username" size="16" required="required" maxlength="16" pattern="[0-9a-zA-Z]{1,16}" autofocus="autofocus" />
@@ -29,8 +29,15 @@
 
 
 	case 'persona':
 	case 'persona':
 		?><p>
 		?><p>
-			<?php echo _i('login'); ?>
-			<a class="signin" href="#"><?php echo _t('login_with_persona'); ?></a>
+			<a class="signin btn btn-important" href="#">
+				<?php echo _i('login'); ?>
+				<?php echo _t('login_with_persona'); ?>
+			</a><br /><br />
+
+			<?php echo _i('help'); ?>
+			<small>
+				<a href="<?php echo _url('index', 'resetAuth'); ?>"><?php echo _t('login_persona_problem'); ?></a>
+			</small>
 		</p><?php
 		</p><?php
 		break;
 		break;
 	} ?>
 	} ?>

+ 33 - 0
app/views/index/resetAuth.phtml

@@ -0,0 +1,33 @@
+<div class="prompt">
+	<h1><?php echo _t('auth_reset'); ?></h1>
+
+	<?php if (!empty($this->message)) { ?>
+	<p class="alert <?php echo $this->message['status'] === 'bad' ? 'alert-error' : 'alert-warn'; ?>">
+		<span class="alert-head"><?php echo $this->message['title']; ?></span><br />
+		<?php echo $this->message['body']; ?>
+	</p>
+	<?php } ?>
+
+	<?php if (!$this->no_form) { ?>
+	<form id="crypto-form" method="post" action="<?php echo _url('index', 'resetAuth'); ?>">
+		<p class="alert alert-warn">
+			<span class="alert-head"><?php echo _t('attention'); ?></span><br />
+			<?php echo _t('auth_will_reset'); ?>
+		</p>
+
+		<div>
+			<label for="username"><?php echo _t('username_admin'); ?></label>
+			<input type="text" id="username" name="username" size="16" required="required" maxlength="16" pattern="[0-9a-zA-Z]{1,16}" autofocus="autofocus" />
+		</div>
+		<div>
+			<label for="passwordPlain"><?php echo _t('password'); ?></label>
+				<input type="password" id="passwordPlain" required="required" />
+				<input type="hidden" id="challenge" name="challenge" /><br />
+				<noscript><strong><?php echo _t('javascript_should_be_activated'); ?></strong></noscript>
+		</div>
+		<div>
+			<button id="loginButton" type="submit" class="btn btn-important"><?php echo _t('submit'); ?></button>
+		</div>
+	</form>
+	<?php } ?>
+</div>

+ 28 - 5
app/views/stats/idle.phtml

@@ -1,25 +1,48 @@
 <?php $this->partial('aside_stats'); ?>
 <?php $this->partial('aside_stats'); ?>
 
 
-<div class="post content">
+<div class="post">
 	<a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('back_to_rss_feeds'); ?></a>
 	<a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('back_to_rss_feeds'); ?></a>
 
 
 	<h1><?php echo _t('stats_idle'); ?></h1>
 	<h1><?php echo _t('stats_idle'); ?></h1>
 
 
 	<?php
 	<?php
+		$current_url = urlencode(Minz_Url::display(
+			array('c' => 'stats', 'a' => 'idle'),
+			'php', true
+		));
+		$nothing = true;
 		foreach ($this->idleFeeds as $period => $feeds) {
 		foreach ($this->idleFeeds as $period => $feeds) {
 			if (!empty($feeds)) {
 			if (!empty($feeds)) {
+				$nothing = false;
 	?>
 	?>
 		<div class="stat">
 		<div class="stat">
 			<h2><?php echo _t($period); ?></h2>
 			<h2><?php echo _t($period); ?></h2>
 
 
-			<ul>
-				<?php foreach ($feeds as $feed) { ?>
-					<li><a href="<?php echo _url('configure', 'feed', 'id', $feed['id']); ?>" title="<?php echo date('Y-m-d', $feed['last_date']); ?>"><?php echo $feed['name']; ?></a></li>
-				<?php } ?>
+			<form id="form-delete" method="post" style="display: none"></form>
+
+			<?php foreach ($feeds as $feed) { ?>
+			<ul class="horizontal-list">
+				<li class="item">
+					<div class="stick">
+						<a class="btn" href="<?php echo _url('index', 'index', 'get', 'f_' . $feed['id']); ?>"><?php echo _i('link'); ?> <?php echo _t('filter'); ?></a>
+						<a class="btn" href="<?php echo _url('configure', 'feed', 'id', $feed['id']); ?>"><?php echo _i('configure'); ?> <?php echo _t('administration'); ?></a>
+						<button class="btn btn-attention confirm" form="form-delete" formaction="<?php echo _url('feed', 'delete', 'id', $feed['id'], 'r', $current_url); ?>"><?php echo _t('delete'); ?></button>
+					</div>
+				</li>
+				<li class="item">
+					<span title="<?php echo timestamptodate($feed['last_date'], false); ?>"><?php echo $feed['name']; ?> (<?php echo _t('number_articles', $feed['nb_articles']); ?>)</span>
+				</li>
 			</ul>
 			</ul>
+			<?php } ?>
 		</div>
 		</div>
 	<?php
 	<?php
 			}
 			}
 		}
 		}
+
+		if ($nothing) {
 	?>
 	?>
+	<p class="alert alert-warn">
+		<span class="alert-head"><?php echo _t('stats_no_idle'); ?></span>
+	</p>
+	<?php } ?>
 </div>
 </div>

+ 24 - 24
app/views/stats/index.phtml

@@ -1,11 +1,11 @@
 <?php $this->partial('aside_stats'); ?>
 <?php $this->partial('aside_stats'); ?>
 
 
-<div class="post content">
+<div class="post">
 	<a href="<?php echo _url ('index', 'index'); ?>"><?php echo _t ('back_to_rss_feeds'); ?></a>
 	<a href="<?php echo _url ('index', 'index'); ?>"><?php echo _t ('back_to_rss_feeds'); ?></a>
-	
+
 	<h1><?php echo _t ('stats_main'); ?></h1>
 	<h1><?php echo _t ('stats_main'); ?></h1>
 
 
-	<div class="stat">
+	<div class="stat half">
 		<h2><?php echo _t ('stats_entry_repartition'); ?></h2>
 		<h2><?php echo _t ('stats_entry_repartition'); ?></h2>
 		<table>
 		<table>
 			<thead>
 			<thead>
@@ -38,26 +38,9 @@
 				</tr>
 				</tr>
 			</tbody>
 			</tbody>
 		</table>
 		</table>
-	</div>
-	
-	<div class="stat">
-		<h2><?php echo _t ('stats_entry_per_day'); ?></h2>
-		<div id="statsEntryPerDay" style="height: 300px"></div>
-	</div>
-	
-	<div class="stat">
-		<h2><?php echo _t ('stats_feed_per_category'); ?></h2>
-		<div id="statsFeedPerCategory" style="height: 300px"></div>
-		<div id="statsFeedPerCategoryLegend"></div>
-	</div>
-	
-	<div class="stat">
-		<h2><?php echo _t ('stats_entry_per_category'); ?></h2>
-		<div id="statsEntryPerCategory" style="height: 300px"></div>
-		<div id="statsEntryPerCategoryLegend"></div>
-	</div>
-	
-	<div class="stat">
+	</div><!--
+
+	--><div class="stat half">
 		<h2><?php echo _t ('stats_top_feed'); ?></h2>
 		<h2><?php echo _t ('stats_top_feed'); ?></h2>
 		<table>
 		<table>
 			<thead>
 			<thead>
@@ -70,7 +53,7 @@
 			<tbody>
 			<tbody>
 				<?php foreach ($this->topFeed as $feed): ?>
 				<?php foreach ($this->topFeed as $feed): ?>
 					<tr>
 					<tr>
-						<td><?php echo $feed['name']; ?></td>
+						<td><a href="<?php echo _url('stats', 'repartition', 'id', $feed['id']); ?>"><?php echo $feed['name']; ?></a></td>
 						<td><?php echo $feed['category']; ?></td>
 						<td><?php echo $feed['category']; ?></td>
 						<td class="numeric"><?php echo formatNumber($feed['count']); ?></td>
 						<td class="numeric"><?php echo formatNumber($feed['count']); ?></td>
 					</tr>
 					</tr>
@@ -78,6 +61,23 @@
 			</tbody>
 			</tbody>
 		</table>
 		</table>
 	</div>
 	</div>
+
+	<div class="stat">
+		<h2><?php echo _t ('stats_entry_per_day'); ?></h2>
+		<div id="statsEntryPerDay" style="height: 300px"></div>
+	</div>
+
+	<div class="stat half">
+		<h2><?php echo _t ('stats_feed_per_category'); ?></h2>
+		<div id="statsFeedPerCategory" style="height: 300px"></div>
+		<div id="statsFeedPerCategoryLegend"></div>
+	</div><!--
+
+	--><div class="stat half">
+		<h2><?php echo _t ('stats_entry_per_category'); ?></h2>
+		<div id="statsEntryPerCategory" style="height: 300px"></div>
+		<div id="statsEntryPerCategoryLegend"></div>
+	</div>
 </div>
 </div>
 
 
 <script>
 <script>

+ 51 - 15
app/views/stats/repartition.phtml

@@ -1,6 +1,6 @@
 <?php $this->partial('aside_stats'); ?>
 <?php $this->partial('aside_stats'); ?>
 
 
-<div class="post content">
+<div class="post ">
 	<a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('back_to_rss_feeds'); ?></a>
 	<a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('back_to_rss_feeds'); ?></a>
 
 
 	<h1><?php echo _t('stats_repartition'); ?></h1>
 	<h1><?php echo _t('stats_repartition'); ?></h1>
@@ -10,12 +10,12 @@
 	<?php foreach ($this->categories as $category) {
 	<?php foreach ($this->categories as $category) {
 		$feeds = $category->feeds();
 		$feeds = $category->feeds();
 		if (!empty($feeds)) {
 		if (!empty($feeds)) {
-			echo '<optgroup label=', $category->name(), '>';
+			echo '<optgroup label="', $category->name(), '">';
 			foreach ($feeds as $feed) {
 			foreach ($feeds as $feed) {
 				if ($this->feed && $feed->id() == $this->feed->id()){
 				if ($this->feed && $feed->id() == $this->feed->id()){
-					echo '<option value ="', $feed->id(), '" selected data-url="', _url('stats', 'repartition', 'id', $feed->id()), '">', $feed->name(), '</option>';
+					echo '<option value="', $feed->id(), '" selected="selected" data-url="', _url('stats', 'repartition', 'id', $feed->id()), '">', $feed->name(), '</option>';
 				} else {
 				} else {
-					echo '<option value ="', $feed->id(), '" data-url="', _url('stats', 'repartition', 'id', $feed->id()), '">', $feed->name(), '</option>';
+					echo '<option value="', $feed->id(), '" data-url="', _url('stats', 'repartition', 'id', $feed->id()), '">', $feed->name(), '</option>';
 				}
 				}
 			}
 			}
 			echo '</optgroup>';
 			echo '</optgroup>';
@@ -24,8 +24,8 @@
 	</select>
 	</select>
 
 
 	<?php if ($this->feed) {?>
 	<?php if ($this->feed) {?>
-		<a href="<?php echo _url('configure', 'feed', 'id', $this->feed->id()); ?>">
-			<?php echo _t('administration'); ?>
+		<a class="btn" href="<?php echo _url('configure', 'feed', 'id', $this->feed->id()); ?>">
+			<?php echo _i('configure'); ?> <?php echo _t('administration'); ?>
 		</a>
 		</a>
 	<?php }?>
 	<?php }?>
 
 
@@ -34,12 +34,12 @@
 		<div id="statsEntryPerHour" style="height: 300px"></div>
 		<div id="statsEntryPerHour" style="height: 300px"></div>
 	</div>
 	</div>
 
 
-	<div class="stat">
+	<div class="stat half">
 		<h2><?php echo _t('stats_entry_per_day_of_week'); ?></h2>
 		<h2><?php echo _t('stats_entry_per_day_of_week'); ?></h2>
 		<div id="statsEntryPerDayOfWeek" style="height: 300px"></div>
 		<div id="statsEntryPerDayOfWeek" style="height: 300px"></div>
-	</div>
+	</div><!--
 
 
-	<div class="stat">
+	--><div class="stat half">
 		<h2><?php echo _t('stats_entry_per_month'); ?></h2>
 		<h2><?php echo _t('stats_entry_per_month'); ?></h2>
 		<div id="statsEntryPerMonth" style="height: 300px"></div>
 		<div id="statsEntryPerMonth" style="height: 300px"></div>
 	</div>
 	</div>
@@ -56,11 +56,22 @@ function initStats() {
 		return;
 		return;
 	}
 	}
 	// Entry per hour
 	// Entry per hour
+	var avg_h = [];
+	for (var i = -1; i <= 24; i++) {
+		avg_h.push([i, <?php echo $this->averageHour?>]);
+	}
 	Flotr.draw(document.getElementById('statsEntryPerHour'),
 	Flotr.draw(document.getElementById('statsEntryPerHour'),
-		[<?php echo $this->repartitionHour ?>],
+		[{
+			data: <?php echo $this->repartitionHour ?>,
+			bars: {horizontal: false, show: true}
+		}, {
+			data: avg_h,
+			lines: {show: true},
+			label: <?php echo $this->averageHour?>,
+			yaxis: 2
+		}],
 		{
 		{
 			grid: {verticalLines: false},
 			grid: {verticalLines: false},
-			bars: {horizontal: false, show: true},
 			xaxis: {noTicks: 23,
 			xaxis: {noTicks: 23,
 				tickFormatter: function(x) {
 				tickFormatter: function(x) {
 					var x = parseInt(x);
 					var x = parseInt(x);
@@ -70,14 +81,26 @@ function initStats() {
 				max: 23.9,
 				max: 23.9,
 				tickDecimals: 0},
 				tickDecimals: 0},
 			yaxis: {min: 0},
 			yaxis: {min: 0},
+			y2axis: {showLabels: false},
 			mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}}
 			mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}}
 		});
 		});
 	// Entry per day of week
 	// Entry per day of week
+	var avg_dow = [];
+	for (var i = -1; i <= 7; i++) {
+		avg_dow.push([i, <?php echo $this->averageDayOfWeek?>]);
+	}
 	Flotr.draw(document.getElementById('statsEntryPerDayOfWeek'),
 	Flotr.draw(document.getElementById('statsEntryPerDayOfWeek'),
-		[<?php echo $this->repartitionDayOfWeek ?>],
+		[{
+			data: <?php echo $this->repartitionDayOfWeek ?>,
+			bars: {horizontal: false, show: true}
+		}, {
+			data: avg_dow,
+			lines: {show: true},
+			label: <?php echo $this->averageDayOfWeek?>,
+			yaxis: 2
+		}],
 		{
 		{
 			grid: {verticalLines: false},
 			grid: {verticalLines: false},
-			bars: {horizontal: false, show: true},
 			xaxis: {noTicks: 6,
 			xaxis: {noTicks: 6,
 				tickFormatter: function(x) {
 				tickFormatter: function(x) {
 					var x = parseInt(x),
 					var x = parseInt(x),
@@ -88,14 +111,26 @@ function initStats() {
 				max: 6.9,
 				max: 6.9,
 				tickDecimals: 0},
 				tickDecimals: 0},
 			yaxis: {min: 0},
 			yaxis: {min: 0},
+			y2axis: {showLabels: false},
 			mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}}
 			mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}}
 		});
 		});
 	// Entry per month
 	// Entry per month
+	var avg_m = [];
+	for (var i = 0; i <= 13; i++) {
+		avg_m.push([i, <?php echo $this->averageMonth?>]);
+	}
 	Flotr.draw(document.getElementById('statsEntryPerMonth'),
 	Flotr.draw(document.getElementById('statsEntryPerMonth'),
-		[<?php echo $this->repartitionMonth ?>],
+		[{
+			data: <?php echo $this->repartitionMonth ?>,
+			bars: {horizontal: false, show: true}
+		}, {
+			data: avg_m,
+			lines: {show: true},
+			label: <?php echo $this->averageMonth?>,
+			yaxis: 2
+		}],
 		{
 		{
 			grid: {verticalLines: false},
 			grid: {verticalLines: false},
-			bars: {horizontal: false, show: true},
 			xaxis: {noTicks: 12,
 			xaxis: {noTicks: 12,
 				tickFormatter: function(x) {
 				tickFormatter: function(x) {
 					var x = parseInt(x),
 					var x = parseInt(x),
@@ -106,6 +141,7 @@ function initStats() {
 				max: 12.9,
 				max: 12.9,
 				tickDecimals: 0},
 				tickDecimals: 0},
 			yaxis: {min: 0},
 			yaxis: {min: 0},
+			y2axis: {showLabels: false},
 			mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}}
 			mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}}
 		});
 		});
 
 

+ 9 - 0
app/views/update/apply.phtml

@@ -0,0 +1,9 @@
+<?php $this->partial('aside_configure'); ?>
+
+<div class="post">
+	<a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('back_to_rss_feeds'); ?></a>
+
+	<h1><?php echo _t('update_system'); ?></h1>
+
+	<?php ask_info_update(); ?>
+</div>

+ 36 - 0
app/views/update/index.phtml

@@ -0,0 +1,36 @@
+<?php $this->partial('aside_configure'); ?>
+
+<div class="post">
+	<a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('back_to_rss_feeds'); ?></a>
+
+	<h1><?php echo _t('update_system'); ?></h1>
+
+	<p>
+		<?php echo _i('help'); ?> <?php echo _t('update_last', $this->last_update_time); ?>
+	</p>
+
+	<?php if (!empty($this->message)) { ?>
+	<p class="alert <?php echo $this->message['status'] === 'bad' ? 'alert-error' : 'alert-warn'; ?>">
+		<span class="alert-head"><?php echo $this->message['title']; ?></span>
+		<?php echo $this->message['body']; ?>
+	</p>
+	<?php } elseif ($this->check_last_hour) { ?>
+	<p class="alert alert-warn">
+		<span class="alert-head"><?php echo _t('damn'); ?></span>
+		<?php echo _t('no_update'); ?>
+	</p>
+	<?php } ?>
+
+	<?php
+		if (!$this->check_last_hour &&
+				(empty($this->message) || $this->message['status'] !== 'good')) {
+	?>
+	<p>
+		<a href="<?php echo _url('update', 'check'); ?>" class="btn"><?php echo _t('update_check'); ?></a>
+	</p>
+	<?php } ?>
+
+	<?php if ($this->update_to_apply) { ?>
+	<a class="btn btn-important" href="<?php echo _url('update', 'apply'); ?>"><?php echo _t('update_apply'); ?></a>
+	<?php } ?>
+</div>

+ 3 - 0
constants.php

@@ -1,6 +1,8 @@
 <?php
 <?php
 define('FRESHRSS_VERSION', '0.7.4');
 define('FRESHRSS_VERSION', '0.7.4');
 define('FRESHRSS_WEBSITE', 'http://freshrss.org');
 define('FRESHRSS_WEBSITE', 'http://freshrss.org');
+define('FRESHRSS_UPDATE_WEBSITE', 'https://update.freshrss.org?v=' . FRESHRSS_VERSION);
+define('FRESHRSS_WIKI', 'http://doc.freshrss.org');
 
 
 // PHP text output compression http://php.net/ob_gzhandler (better to do it at Web server level)
 // PHP text output compression http://php.net/ob_gzhandler (better to do it at Web server level)
 define('PHP_COMPRESSION', false);
 define('PHP_COMPRESSION', false);
@@ -13,6 +15,7 @@ define('FRESHRSS_PATH', dirname(__FILE__));
 		define('PUBLIC_RELATIVE', '..');
 		define('PUBLIC_RELATIVE', '..');
 
 
 	define('DATA_PATH', FRESHRSS_PATH . '/data');
 	define('DATA_PATH', FRESHRSS_PATH . '/data');
+		define('UPDATE_FILENAME', DATA_PATH . '/update.php');
 		define('LOG_PATH', DATA_PATH . '/log');
 		define('LOG_PATH', DATA_PATH . '/log');
 		define('CACHE_PATH', DATA_PATH . '/cache');
 		define('CACHE_PATH', DATA_PATH . '/cache');
 
 

+ 2 - 0
data/.gitignore

@@ -6,3 +6,5 @@ touch.txt
 no-cache.txt
 no-cache.txt
 *.bak.php
 *.bak.php
 *.lock.txt
 *.lock.txt
+last_update.txt
+update.php

+ 3 - 0
lib/Minz/ModelPdo.php

@@ -77,6 +77,9 @@ class Minz_ModelPdo {
 				$db['password'],
 				$db['password'],
 				$driver_options
 				$driver_options
 			);
 			);
+			if ($type === 'sqlite') {
+				$this->bd->exec('PRAGMA foreign_keys = ON;');
+			}
 			self::$sharedBd = $this->bd;
 			self::$sharedBd = $this->bd;
 		} catch (Exception $e) {
 		} catch (Exception $e) {
 			throw new Minz_PDOConnectionException(
 			throw new Minz_PDOConnectionException(

+ 5 - 0
lib/Minz/Request.php

@@ -124,6 +124,11 @@ class Minz_Request {
 	 *                > sinon, le dispatcher recharge en interne
 	 *                > sinon, le dispatcher recharge en interne
 	 */
 	 */
 	public static function forward($url = array(), $redirect = false) {
 	public static function forward($url = array(), $redirect = false) {
+		if (!is_array($url)) {
+			header('Location: ' . $url);
+			exit();
+		}
+
 		$url = Minz_Url::checkUrl($url);
 		$url = Minz_Url::checkUrl($url);
 
 
 		if ($redirect) {
 		if ($redirect) {

+ 11 - 4
lib/Minz/View.php

@@ -26,12 +26,19 @@ class Minz_View {
 	 * Détermine si on utilise un layout ou non
 	 * Détermine si on utilise un layout ou non
 	 */
 	 */
 	public function __construct () {
 	public function __construct () {
+		$this->change_view(Minz_Request::controllerName(),
+		                   Minz_Request::actionName());
+		self::$title = Minz_Configuration::title ();
+	}
+
+	/**
+	 * Change le fichier de vue en fonction d'un controller / action
+	 */
+	public function change_view($controller_name, $action_name) {
 		$this->view_filename = APP_PATH
 		$this->view_filename = APP_PATH
 		                     . self::VIEWS_PATH_NAME . '/'
 		                     . self::VIEWS_PATH_NAME . '/'
-		                     . Minz_Request::controllerName () . '/'
-		                     . Minz_Request::actionName () . '.phtml';
-
-		self::$title = Minz_Configuration::title ();
+		                     . $controller_name . '/'
+		                     . $action_name . '.phtml';
 	}
 	}
 
 
 	/**
 	/**

+ 1 - 1
lib/SimplePie/SimplePie/Parser.php

@@ -142,7 +142,7 @@ class SimplePie_Parser
 				$dom = new DOMDocument();
 				$dom = new DOMDocument();
 				$dom->recover = true;
 				$dom->recover = true;
 				$dom->strictErrorChecking = false;
 				$dom->strictErrorChecking = false;
-				$dom->loadXML($data);
+				@$dom->loadXML($data);
 				$this->encoding = $encoding = $dom->encoding = 'UTF-8';
 				$this->encoding = $encoding = $dom->encoding = 'UTF-8';
 				$data2 = $dom->saveXML();
 				$data2 = $dom->saveXML();
 				if (function_exists('mb_convert_encoding'))
 				if (function_exists('mb_convert_encoding'))

+ 14 - 0
lib/lib_rss.php

@@ -230,3 +230,17 @@ function cryptAvailable() {
 	}
 	}
 	return false;
 	return false;
 }
 }
+
+function is_referer_from_same_domain() {
+	if (empty($_SERVER['HTTP_REFERER'])) {
+		return false;
+	}
+	$host = parse_url(((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') ? 'https://' : 'http://') .
+		(empty($_SERVER['HTTP_HOST']) ? $_SERVER['SERVER_NAME'] : $_SERVER['HTTP_HOST']));
+	$referer = parse_url($_SERVER['HTTP_REFERER']);
+	if (empty($host['scheme']) || empty($referer['scheme']) || $host['scheme'] !== $referer['scheme'] ||
+	    empty($host['host']) || empty($referer['host']) || $host['host'] !== $referer['host']) {
+		return false;
+	}
+	return (isset($host['port']) ? $host['port'] : 0) === (isset($referer['port']) ? $referer['port'] : 0);
+}

+ 131 - 40
p/scripts/main.js

@@ -251,9 +251,14 @@ function toggleContent(new_active, old_active) {
 	}
 	}
 
 
 	if (sticky_post) {
 	if (sticky_post) {
-		var new_pos = new_active.position().top - new_active.children('.flux_header').outerHeight(),
+		var prev_article = new_active.prevAll('.flux'),
+		    new_pos = new_active.position().top,
 			old_scroll = $(box_to_move).scrollTop();
 			old_scroll = $(box_to_move).scrollTop();
 
 
+		if (prev_article.length > 0 && new_pos - prev_article.position().top <= 150) {
+			new_pos = prev_article.position().top;
+		}
+
 		if (hide_posts) {
 		if (hide_posts) {
 			if (relative_move) {
 			if (relative_move) {
 				new_pos += old_scroll;
 				new_pos += old_scroll;
@@ -297,7 +302,7 @@ function next_entry() {
 function prev_feed() {
 function prev_feed() {
 	var active_feed = $("#aside_flux .feeds li.active");
 	var active_feed = $("#aside_flux .feeds li.active");
 	if (active_feed.length > 0) {
 	if (active_feed.length > 0) {
-		active_feed.prev().find('a.feed').each(function(){this.click();});
+		active_feed.prevAll(':visible:first').find('a.feed').each(function(){this.click();});
 	} else {
 	} else {
 		last_feed();
 		last_feed();
 	}
 	}
@@ -306,21 +311,21 @@ function prev_feed() {
 function next_feed() {
 function next_feed() {
 	var active_feed = $("#aside_flux .feeds li.active");
 	var active_feed = $("#aside_flux .feeds li.active");
 	if (active_feed.length > 0) {
 	if (active_feed.length > 0) {
-		active_feed.next().find('a.feed').each(function(){this.click();});
+		active_feed.nextAll(':visible:first').find('a.feed').each(function(){this.click();});
 	} else {
 	} else {
 		first_feed();
 		first_feed();
 	}
 	}
 }
 }
 
 
 function first_feed() {
 function first_feed() {
-	var feed = $("#aside_flux .feeds.active li:first");
+	var feed = $("#aside_flux .feeds.active li:visible:first");
 	if (feed.length > 0) {
 	if (feed.length > 0) {
 		feed.find('a')[1].click();
 		feed.find('a')[1].click();
 	}
 	}
 }
 }
 
 
 function last_feed() {
 function last_feed() {
-	var feed = $("#aside_flux .feeds.active li:last");
+	var feed = $("#aside_flux .feeds.active li:visible:last");
 	if (feed.length > 0) {
 	if (feed.length > 0) {
 		feed.find('a')[1].click();
 		feed.find('a')[1].click();
 	}
 	}
@@ -330,7 +335,7 @@ function prev_category() {
 	var active_cat = $("#aside_flux .category.stick.active");
 	var active_cat = $("#aside_flux .category.stick.active");
 
 
 	if (active_cat.length > 0) {
 	if (active_cat.length > 0) {
-		var prev_cat = active_cat.parent('li').prev().find('.category.stick a.btn');
+		var prev_cat = active_cat.parent('li').prevAll(':visible:first').find('.category.stick a.btn');
 		if (prev_cat.length > 0) {
 		if (prev_cat.length > 0) {
 			prev_cat[0].click();
 			prev_cat[0].click();
 		}
 		}
@@ -344,7 +349,7 @@ function next_category() {
 	var active_cat = $("#aside_flux .category.stick.active");
 	var active_cat = $("#aside_flux .category.stick.active");
 
 
 	if (active_cat.length > 0) {
 	if (active_cat.length > 0) {
-		var next_cat = active_cat.parent('li').next().find('.category.stick a.btn');
+		var next_cat = active_cat.parent('li').nextAll(':visible:first').find('.category.stick a.btn');
 		if (next_cat.length > 0) {
 		if (next_cat.length > 0) {
 			next_cat[0].click();
 			next_cat[0].click();
 		}
 		}
@@ -355,14 +360,14 @@ function next_category() {
 }
 }
 
 
 function first_category() {
 function first_category() {
-	var cat = $("#aside_flux .category.stick:first");
+	var cat = $("#aside_flux .category.stick:visible:first");
 	if (cat.length > 0) {
 	if (cat.length > 0) {
 		cat.find('a.btn')[0].click();
 		cat.find('a.btn')[0].click();
 	}
 	}
 }
 }
 
 
 function last_category() {
 function last_category() {
-	var cat = $("#aside_flux .category.stick:last");
+	var cat = $("#aside_flux .category.stick:visible:last");
 	if (cat.length > 0) {
 	if (cat.length > 0) {
 		cat.find('a.btn')[0].click();
 		cat.find('a.btn')[0].click();
 	}
 	}
@@ -373,11 +378,41 @@ function collapse_entry() {
 
 
 	var flux_current = $(".flux.current");
 	var flux_current = $(".flux.current");
 	flux_current.toggleClass("active");
 	flux_current.toggleClass("active");
-	if (isCollapsed) {
+	if (isCollapsed && auto_mark_article) {
 		mark_read(flux_current, true);
 		mark_read(flux_current, true);
 	}
 	}
 }
 }
 
 
+function user_filter(key) {
+	console.log('user filter');
+	console.warn(key);
+	var filter = $('#dropdown-query');
+	var filters = filter.siblings('.dropdown-menu').find('.item.query a');
+	if (typeof key === "undefined") {
+		if (!filter.length) {
+			return;
+		}
+		// Display the filter div
+		window.location.hash = filter.attr('id');
+		// Force scrolling to the filter div
+		var scroll = needsScroll($('.header'));
+		if (scroll !== 0) {
+			$('html,body').scrollTop(scroll);
+		}
+		// Force the key value if there is only one action, so we can trigger it automatically
+		if (filters.length === 1) {
+			key = 1;
+		} else {
+			return;
+		}
+	}
+	// Trigger selected share action
+	key = parseInt(key);
+	if (key <= filters.length) {
+		filters[key - 1].click();
+	}
+}
+
 function auto_share(key) {
 function auto_share(key) {
 	var share = $(".flux.current.active").find('.dropdown-target[id^="dropdown-share"]');
 	var share = $(".flux.current.active").find('.dropdown-target[id^="dropdown-share"]');
 	var shares = share.siblings('.dropdown-menu').find('.item a');
 	var shares = share.siblings('.dropdown-menu').find('.item a');
@@ -503,13 +538,13 @@ function init_shortcuts() {
 	});
 	});
 	shortcut.add("shift+" + shortcuts.mark_read, function () {
 	shortcut.add("shift+" + shortcuts.mark_read, function () {
 		// on marque tout comme lu
 		// on marque tout comme lu
-		var url = $(".nav_menu a.read_all").attr("href");
-		if ($(".nav_menu a.read_all").hasClass('confirm')) {
+		var btn = $(".nav_menu .read_all");
+		if (btn.hasClass('confirm')) {
 			if (confirm(str_confirmation)) {
 			if (confirm(str_confirmation)) {
-				redirect(url, false);
+				btn.click();
 			}
 			}
 		} else {
 		} else {
-			redirect(url, false);
+			btn.click();
 		}
 		}
 	}, {
 	}, {
 		'disable_in_input': true
 		'disable_in_input': true
@@ -531,9 +566,19 @@ function init_shortcuts() {
 	}, {
 	}, {
 		'disable_in_input': true
 		'disable_in_input': true
 	});
 	});
+
+	shortcut.add(shortcuts.user_filter, function () {
+		user_filter();
+	}, {
+		'disable_in_input': true
+	});
 	for(var i = 1; i < 10; i++){
 	for(var i = 1; i < 10; i++){
 		shortcut.add(i.toString(), function (e) {
 		shortcut.add(i.toString(), function (e) {
-			auto_share(String.fromCharCode(e.keyCode));
+			if ($('#dropdown-query').siblings('.dropdown-menu').is(':visible')) {
+				user_filter(String.fromCharCode(e.keyCode));
+			} else {
+				auto_share(String.fromCharCode(e.keyCode));
+			}
 		}, {
 		}, {
 			'disable_in_input': true
 			'disable_in_input': true
 		});
 		});
@@ -618,6 +663,13 @@ function init_shortcuts() {
 	}, {
 	}, {
 		'disable_in_input': true
 		'disable_in_input': true
 	});
 	});
+
+	shortcut.add(shortcuts.help, function () {
+		redirect(help_url, true);
+	}, {
+		'disable_in_input': true
+	});
+
 }
 }
 
 
 function init_stream(divStream) {
 function init_stream(divStream) {
@@ -650,11 +702,25 @@ function init_stream(divStream) {
 	});
 	});
 
 
 	divStream.on('click', '.item.title > a', function (e) {
 	divStream.on('click', '.item.title > a', function (e) {
+		// Allow default control-click behaviour such as open in backround-tab.
+		return e.ctrlKey;
+	});
+	divStream.on('mouseup', '.item.title > a', function (e) {
+		// Mouseup enables us to catch middle click.
 		if (e.ctrlKey) {
 		if (e.ctrlKey) {
-			return true;	//Allow default control-click behaviour such as open in backround-tab
+			// CTRL+click, it will be manage by previous rule.
+			return;
+		}
+
+		if (e.which == 2) {
+			// If middle click, we want same behaviour as CTRL+click.
+			var e = jQuery.Event("click");
+			e.ctrlKey = true;
+			$(this).trigger(e);
+		} else if(e.which == 1) {
+			// Normal click, just toggle article.
+			$(this).parent().click();
 		}
 		}
-		$(this).parent().click();	//Will perform toggle flux_content
-		return false;
 	});
 	});
 
 
 	divStream.on('click', '.flux .content a', function () {
 	divStream.on('click', '.flux .content a', function () {
@@ -662,7 +728,13 @@ function init_stream(divStream) {
 	});
 	});
 
 
 	if (auto_mark_site) {
 	if (auto_mark_site) {
-		divStream.on('click', '.flux .link > a', function () {
+		// catch mouseup instead of click so we can have the correct behaviour
+		// with middle button click (scroll button).
+		divStream.on('mouseup', '.flux .link > a', function (e) {
+			if (e.which == 3) {
+				return;
+			}
+
 			mark_read($(this).parents(".flux"), true);
 			mark_read($(this).parents(".flux"), true);
 		});
 		});
 	}
 	}
@@ -740,7 +812,7 @@ function openNotification(msg, status) {
 	notification.find(".msg").html(msg);
 	notification.find(".msg").html(msg);
 	notification.fadeIn(300);
 	notification.fadeIn(300);
 
 
-	notification_interval = window.setInterval(closeNotification, 4000);
+	notification_interval = window.setTimeout(closeNotification, 4000);
 }
 }
 
 
 function closeNotification() {
 function closeNotification() {
@@ -763,7 +835,7 @@ function init_notifications() {
 
 
 	if (notification.find(".msg").html().length > 0) {
 	if (notification.find(".msg").html().length > 0) {
 		notification_working = true;
 		notification_working = true;
-		notification_interval = window.setInterval(closeNotification, 4000);
+		notification_interval = window.setTimeout(closeNotification, 4000);
 	}
 	}
 }
 }
 // </notification>
 // </notification>
@@ -788,12 +860,19 @@ function notifs_html5_show(nb) {
 
 
 	var notification = new window.Notification(str_notif_title_articles, {
 	var notification = new window.Notification(str_notif_title_articles, {
 		icon: "../themes/icons/favicon-256.png",
 		icon: "../themes/icons/favicon-256.png",
-		body: str_notif_body_articles.replace("\d", nb)
+		body: str_notif_body_articles.replace("\d", nb),
+		tag: "freshRssNewArticles"
 	});
 	});
 
 
 	notification.onclick = function() {
 	notification.onclick = function() {
 		window.location.reload();
 		window.location.reload();
 	}
 	}
+
+	if (html5_notif_timeout !== 0){
+		setTimeout(function() {
+					notification.close();
+				}, html5_notif_timeout * 1000);
+	}
 }
 }
 
 
 function init_notifs_html5() {
 function init_notifs_html5() {
@@ -847,9 +926,13 @@ function load_more_posts() {
 		box_load_more.children('.flux:last').after($('#stream', data).children('.flux, .day'));
 		box_load_more.children('.flux:last').after($('#stream', data).children('.flux, .day'));
 		$('.pagination').replaceWith($('.pagination', data));
 		$('.pagination').replaceWith($('.pagination', data));
 		if (display_order === 'ASC') {
 		if (display_order === 'ASC') {
-			$('#nav_menu_read_all>a').attr('href', $('#bigMarkAsRead').attr('href'));
+			$('#nav_menu_read_all > .read_all').attr(
+				'formaction', $('#bigMarkAsRead').attr('formaction')
+			);
 		} else {
 		} else {
-			$('#bigMarkAsRead').attr('href', $('#nav_menu_read_all>a').attr('href'));
+			$('#bigMarkAsRead').attr(
+				'formaction', $('#nav_menu_read_all > .read_all').attr('formaction')
+			);
 		}
 		}
 
 
 		$('[id^=day_]').each(function (i) {
 		$('[id^=day_]').each(function (i) {
@@ -901,7 +984,7 @@ function init_load_more(box) {
 }
 }
 //</endless_mode>
 //</endless_mode>
 
 
-//<Web login form>
+//<crypto form (Web login)>
 function poormanSalt() {	//If crypto.getRandomValues is not available
 function poormanSalt() {	//If crypto.getRandomValues is not available
 	var text = '$2a$04$',
 	var text = '$2a$04$',
 		base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ.0123456789/abcdefghijklmnopqrstuvwxyz';
 		base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ.0123456789/abcdefghijklmnopqrstuvwxyz';
@@ -911,20 +994,24 @@ function poormanSalt() {	//If crypto.getRandomValues is not available
 	return text;
 	return text;
 }
 }
 
 
-function init_loginForm() {
-	var $loginForm = $('#loginForm');
-	if ($loginForm.length === 0) {
+function init_crypto_form() {
+	var $crypto_form = $('#crypto-form');
+	if ($crypto_form.length === 0) {
 		return;
 		return;
 	}
 	}
+
 	if (!(window.dcodeIO)) {
 	if (!(window.dcodeIO)) {
 		if (window.console) {
 		if (window.console) {
 			console.log('FreshRSS waiting for bcrypt.js…');
 			console.log('FreshRSS waiting for bcrypt.js…');
 		}
 		}
-		window.setTimeout(init_loginForm, 100);
+		window.setTimeout(init_crypto_form, 100);
 		return;
 		return;
 	}
 	}
-	$loginForm.on('submit', function() {
-		$('#loginButton').attr('disabled', '');
+
+	$crypto_form.on('submit', function() {
+		var $submit_button = $(this).find('button[type="submit"]');
+		$submit_button.attr('disabled', '');
+
 		var success = false;
 		var success = false;
 		$.ajax({
 		$.ajax({
 			url: './?c=javascript&a=nonce&user=' + $('#username').val(),
 			url: './?c=javascript&a=nonce&user=' + $('#username').val(),
@@ -932,7 +1019,7 @@ function init_loginForm() {
 			async: false
 			async: false
 		}).done(function (data) {
 		}).done(function (data) {
 			if (data.salt1 == '' || data.nonce == '') {
 			if (data.salt1 == '' || data.nonce == '') {
-				alert('Invalid user!');
+				openNotification('Invalid user!', 'bad');
 			} else {
 			} else {
 				try {
 				try {
 					var strong = window.Uint32Array && window.crypto && (typeof window.crypto.getRandomValues === 'function'),
 					var strong = window.Uint32Array && window.crypto && (typeof window.crypto.getRandomValues === 'function'),
@@ -940,22 +1027,23 @@ function init_loginForm() {
 						c = dcodeIO.bcrypt.hashSync(data.nonce + s, strong ? 4 : poormanSalt());
 						c = dcodeIO.bcrypt.hashSync(data.nonce + s, strong ? 4 : poormanSalt());
 					$('#challenge').val(c);
 					$('#challenge').val(c);
 					if (s == '' || c == '') {
 					if (s == '' || c == '') {
-						alert('Crypto error!');
+						openNotification('Crypto error!', 'bad');
 					} else {
 					} else {
 						success = true;
 						success = true;
 					}
 					}
 				} catch (e) {
 				} catch (e) {
-					alert('Crypto exception! ' + e);
+					openNotification('Crypto exception! ' + e, 'bad');
 				}
 				}
 			}
 			}
 		}).fail(function() {
 		}).fail(function() {
-			alert('Communication error!');
+			openNotification('Communication error!', 'bad');
 		});
 		});
-		$('#loginButton').removeAttr('disabled');
+
+		$submit_button.removeAttr('disabled');
 		return success;
 		return success;
 	});
 	});
 }
 }
-//</Web login form>
+//</crypto form (Web login)>
 
 
 //<persona>
 //<persona>
 function init_persona() {
 function init_persona() {
@@ -1021,6 +1109,11 @@ function init_persona() {
 
 
 function init_confirm_action() {
 function init_confirm_action() {
 	$('body').on('click', '.confirm', function () {
 	$('body').on('click', '.confirm', function () {
+		var str_confirmation = $(this).attr('data-str-confirm');
+		if (!str_confirmation) {
+			str_confirmation = str_confirmation_default;
+		}
+
 		return confirm(str_confirmation);
 		return confirm(str_confirmation);
 	});
 	});
 }
 }
@@ -1157,9 +1250,6 @@ function init_all() {
 	}
 	}
 	init_notifications();
 	init_notifications();
 	switch (authType) {
 	switch (authType) {
-		case 'form':
-			init_loginForm();
-			break;
 		case 'persona':
 		case 'persona':
 			init_persona();
 			init_persona();
 			break;
 			break;
@@ -1179,6 +1269,7 @@ function init_all() {
 		init_notifs_html5();
 		init_notifs_html5();
 		window.setInterval(refreshUnreads, 120000);
 		window.setInterval(refreshUnreads, 120000);
 	} else {
 	} else {
+		init_crypto_form();
 		init_share_observers();
 		init_share_observers();
 		init_remove_observers();
 		init_remove_observers();
 		init_feed_observers();
 		init_feed_observers();

+ 17 - 5
p/themes/Dark/dark.css

@@ -16,9 +16,9 @@ html, body {
 }
 }
 
 
 /*=== Links */
 /*=== Links */
-a {
-	outline: none;
+a, button.as-link {
 	color: #6986B2;
 	color: #6986B2;
+	outline: none;
 }
 }
 
 
 /*=== Images */
 /*=== Images */
@@ -338,8 +338,9 @@ a.btn {
 	padding: 0 25px;
 	padding: 0 25px;
 	line-height: 2.5em;
 	line-height: 2.5em;
 }
 }
-.dropdown-menu > .item > span {
-	padding: 0 25px;
+.dropdown-menu > .item > span,
+.dropdown-menu > .item > .as-link {
+	padding: 0 22px;
 	line-height: 2em;
 	line-height: 2em;
 }
 }
 .dropdown-menu > .item:hover {
 .dropdown-menu > .item:hover {
@@ -871,7 +872,18 @@ a.btn {
 .stat > table td,
 .stat > table td,
 .stat > table th {
 .stat > table th {
 	border-bottom: 1px solid #333;
 	border-bottom: 1px solid #333;
-	text-align: center;
+}
+
+.stat > .horizontal-list {
+	margin: 0 0 5px;
+}
+.stat > .horizontal-list .item {
+	overflow: hidden;
+	white-space: nowrap;
+	text-overflow: ellipsis;
+}
+.stat > .horizontal-list .item:first-child {
+	width: 270px;
 }
 }
 
 
 /*=== LOGS */
 /*=== LOGS */

+ 1 - 1
p/themes/Dark/metadata.json

@@ -3,5 +3,5 @@
 	"author": "AD",
 	"author": "AD",
 	"description": "Le coté obscur du thème “Origine”",
 	"description": "Le coté obscur du thème “Origine”",
 	"version": 0.2,
 	"version": 0.2,
-	"files": ["template.css", "dark.css"]
+	"files": ["_template.css", "dark.css"]
 }
 }

+ 0 - 698
p/themes/Dark/template.css

@@ -1,698 +0,0 @@
-@charset "UTF-8";
-
-/*=== GENERAL */
-/*============*/
-html, body {
-	margin: 0;
-	padding: 0;
-	font-size: 100%;
-}
-
-/*=== Links */
-a {
-	text-decoration: none;
-}
-a:hover {
-	text-decoration: underline;
-}
-
-/*=== Lists */
-ul, ol, dd {
-	margin: 0;
-	padding: 0;
-}
-
-/*=== Titles */
-h1 {
-	margin: 0.6em 0 0.3em;
-	font-size: 1.5em;
-	line-height: 1.6em;
-}
-h2 {
-	margin: 0.5em 0 0.25em;
-	font-size: 1.3em;
-	line-height: 2em;
-}
-h3 {
-	margin: 0.5em 0 0.25em;
-	font-size: 1.1em;
-	line-height: 2em;
-}
-
-/*=== Paragraphs */
-p {
-	margin: 1em 0 0.5em;
-	font-size: 1em;
-}
-
-/*=== Images */
-img {
-	height: auto;
-	max-width: 100%;
-}
-img.favicon {
-	height: 16px;
-	width: 16px;
-	vertical-align: middle;
-}
-
-/*=== Videos */
-iframe, embed, object, video {
-	max-width: 100%;
-}
-
-/*=== Forms */
-legend {
-	display: block;
-	width: 100%;
-	clear: both;
-}
-label {
-	display: block;
-}
-input {
-	width: 180px;
-}
-textarea {
-	width: 300px;
-}
-input, select, textarea {
-	display: inline-block;
-	max-width: 100%;
-}
-input[type="radio"],
-input[type="checkbox"] {
-	width: 15px !important;
-	min-height: 15px !important;
-}
-input.extend:focus {
-	width: 300px;
-}
-
-/*=== COMPONENTS */
-/*===============*/
-/*=== Forms */
-.form-group:after {
-	content: "";
-	display: block;
-	clear: both;
-}
-.form-group.form-actions {
-	min-width: 250px;
-}
-.form-group .group-name {
-	display: block;
-	float: left;
-	width: 200px;
-}
-.form-group .group-controls {
-	min-width: 250px;
-	margin: 0 0 0 220px;
-}
-.form-group .group-controls .control {
-	display: block;
-}
-
-/*=== Buttons */
-.stick {
-	display: inline-block;
-	white-space: nowrap;
-}
-.btn,
-a.btn {
-	display: inline-block;
-	cursor: pointer;
-	overflow: hidden;
-}
-.btn-important {
-	font-weight: bold;
-}
-
-/*=== Navigation */
-.nav-list .nav-header,
-.nav-list .item {
-	display: block;
-}
-.nav-list .item,
-.nav-list .item > a {
-	display: block;
-	overflow: hidden;
-	white-space: nowrap;
-	text-overflow: ellipsis;
-}
-.nav-head {
-	display: block;
-}
-.nav-head .item {
-	display: inline-block;
-}
-
-/*=== Horizontal-list */
-.horizontal-list {
-	display: table;
-	table-layout: fixed;
-	width: 100%;
-}
-.horizontal-list .item {
-	display: table-cell;
-}
-
-/*=== Dropdown */
-.dropdown {
-	position: relative;
-	display: inline-block;
-}
-.dropdown-target {
-	display: none;
-}
-.dropdown-menu {
-	display: none;
-	min-width: 200px;
-	margin: 0;
-	position: absolute;
-	right: 0;
-	background: #fff;
-	border: 1px solid #aaa;
-}
-.dropdown-header {
-	display: block;
-}
-.dropdown-menu > .item {
-	display: block;
-}
-.dropdown-menu > .item > a,
-.dropdown-menu > .item > span {
-	display: block;
-}
-.dropdown-menu > .item[aria-checked="true"] > a:before {
-	content: '✓';
-}
-.dropdown-menu .input {
-	display: block;
-}
-.dropdown-menu .input select,
-.dropdown-menu .input input {
-	display: block;
-	max-width: 95%;
-}
-.dropdown-target:target ~ .dropdown-menu {
-	display: block;
-	z-index: 10;
-}
-.dropdown-close {
-	display: inline;
-}
-.dropdown-close a {
-	font-size: 0;
-	position: fixed;
-	top: 0; bottom: 0;
-	left: 0; right: 0;
-	display: block;
-	z-index: -10;
-}
-.separator {
-	display: block;
-	height: 0;
-	border-bottom: 1px solid #aaa;
-}
-
-/*=== Alerts */
-.alert {
-	display: block;
-	width: 90%;
-}
-.group-controls .alert {
-	width: 100%
-}
-.alert-head {
-	margin: 0;
-	font-weight: bold;
-}
-.alert ul {
-	margin: 5px 20px;
-}
-
-/*=== Icons */
-.icon {
-	display: inline-block;
-	width: 16px;
-	height: 16px;
-	vertical-align: middle;
-	line-height: 16px;
-}
-
-/*=== Pagination */
-.pagination {
-	display: table;
-	width: 100%;
-	margin: 0;
-	padding: 0;
-	table-layout: fixed;
-}
-.pagination .item {
-	display: table-cell;
-}
-.pagination .pager-first,
-.pagination .pager-previous,
-.pagination .pager-next,
-.pagination .pager-last {
-	width: 100px;
-}
-
-/*=== STRUCTURE */
-/*===============*/
-/*=== Header */
-.header {
-	display: table;
-	width: 100%;
-	table-layout: fixed;
-}
-.header > .item {
-	display: table-cell;
-}
-.header > .item.title {
-	width: 250px;
-	white-space: nowrap;
-}
-.header > .item.title h1 {
-	display: inline-block;
-}
-.header > .item.title .logo {
-	display: inline-block;
-	height: 32px;
-	width: 32px;
-	vertical-align: middle;
-}
-.header > .item.configure {
-	width: 100px;
-}
-
-/*=== Body */
-#global {
-	display: table;
-	width: 100%;
-	height: 100%;
-	table-layout: fixed;
-}
-.aside {
-	display: table-cell;
-	height: 100%;
-	width: 250px;
-	vertical-align: top;
-}
-.aside.aside_flux {
-	background: #fff;
-}
-
-/*=== Aside main page (categories) */
-.categories {
-	list-style: none;
-	margin: 0;
-}
-.state_unread li:not(.active)[data-unread="0"] {
-	display: none;
-}
-.category {
-	display: block;
-	overflow: hidden;
-	white-space: nowrap;
-	text-overflow: ellipsis;
-}
-.category .btn:not([data-unread="0"]):after {
-	content: attr(data-unread);
-}
-
-/*=== Aside main page (feeds) */
-.categories .feeds {
-	width: 100%;
-	list-style: none;
-}
-.categories .feeds:not(.active) {
-	display: none;
-}
-.categories .feeds .feed {
-	display: inline-block;
-	overflow: hidden;
-	white-space: nowrap;
-	text-overflow: ellipsis;
-	vertical-align: middle;
-}
-.categories .feeds .feed:not([data-unread="0"]):before {
-	content: "(" attr(data-unread) ") ";
-}
-.categories .feeds .dropdown-menu {
-	left: 0;
-}
-.categories .feeds .item .dropdown-toggle > .icon {
-	visibility: hidden;
-	cursor: pointer;
-	vertical-align: top;
-}
-.categories .feeds .item .dropdown-target:target ~ .dropdown-toggle > .icon,
-.categories .feeds .item:hover .dropdown-toggle > .icon,
-.categories .feeds .item.active .dropdown-toggle > .icon {
-	visibility: visible;
-}
-
-/*=== New article notification */
-#new-article {
-	display: none;
-}
-#new-article > a {
-	display: block;
-}
-
-/*=== Day indication */
-.day .name {
-	position: absolute;
-	right: 0;
-	width: 50%;
-	overflow: hidden;
-	white-space: nowrap;
-	text-overflow: ellipsis;
-}
-
-/*=== Feed article header and footer */
-.flux_header {
-	position: relative;
-}
-.flux .item {
-	line-height: 40px;
-	white-space: nowrap;
-}
-.flux .item.manage,
-.flux .item.link {
-	width: 40px;
-	text-align: center;
-}
-.flux .item.website {
-	width: 200px;
-}
-.flux.not_read .item.title,
-.flux.current .item.title {
-	font-weight: bold;
-}
-.flux:not(.current):hover .item.title {
-	position: absolute;
-	max-width: calc(100% - 320px);
-	background: #fff;
-}
-.flux .item.title a {
-	color: #000;
-	text-decoration: none;
-}
-.flux .item.date {
-	width: 145px;
-	text-align: right;
-}
-.flux .item > a {
-	display: block;
-}
-.flux .item > a {
-	display: block;
-	text-decoration: none;
-	white-space: nowrap;
-	text-overflow: ellipsis;
-	overflow: hidden;
-}
-.flux .item.share > a {
-	display: list-item;
-	list-style-position: inside;
-	list-style-type: decimal;
-}
-
-/*=== Feed article content */
-.hide_posts > .flux:not(.active) > .flux_content {
-	display: none;
-}
-.content {
-	min-height: 20em;
-	margin: auto;
-	line-height: 1.7em;
-	word-wrap: break-word;
-}
-.content.large {
-	max-width: 1000px;
-}
-.content.medium {
-	max-width: 800px;
-}
-.content.thin {
-	max-width: 550px;
-}
-.content ul,
-.content ol,
-.content dd {
-	margin: 0 0 0 15px;
-	padding: 0 0 5px 15px;
-}
-.content pre {
-	overflow: auto;
-}
-
-/*=== Notification and actualize notification */
-.notification {
-	position: absolute;
-	top: 1em;
-	left: 25%; right: 25%;
-	z-index: 10;
-	background: #fff;
-	border: 1px solid #aaa;
-}
-.notification.closed {
-	display: none;
-}
-.notification a.close {
-	position: absolute;
-	top: 0; bottom: 0;
-	right: 0;
-	display: inline-block;
-}
-
-#actualizeProgress {
-	position: fixed;
-}
-#actualizeProgress progress {
-	max-width: 100%;
-	vertical-align: middle;
-}
-#actualizeProgress .progress {
-	vertical-align: middle;
-}
-
-/*=== Navigation menu (for articles) */
-#nav_entries {
-	position: fixed;
-	bottom: 0; left: 0;
-	display: table;
-	width: 250px;
-	background: #fff;
-	table-layout: fixed;
-}
-#nav_entries .item {
-	display: table-cell;
-	width: 30%;
-}
-#nav_entries a {
-	display: block;
-}
-
-/*=== "Load more" part */
-#load_more {
-	min-height: 40px;
-}
-.loading {
-	background: url("loader.gif") center center no-repeat;
-	font-size: 0;
-}
-#bigMarkAsRead {
-	display: block;
-	padding: 3em 0;
-	text-align: center;
-}
-.bigTick {
-	font-size: 7em;
-	line-height: 1.6em;
-}
-
-/*=== Statistiques */
-.stat > table {
-	width: 100%;
-}
-
-/*=== GLOBAL VIEW */
-/*================*/
-/*=== Category boxes */
-#stream.global .box-category {
-	display: inline-block;
-	width: 19em;
-	max-width: 95%;
-	margin: 20px 10px;
-	border: 1px solid #ccc;
-	vertical-align: top;
-}
-#stream.global .category {
-	width: 100%;
-}
-#stream.global .btn {
-	display: block;
-}
-#stream.global .box-category .feeds {
-	display: block;
-	overflow: auto;
-}
-#stream.global .box-category .feed {
-	width: 19em;
-	max-width: 90%;
-}
-
-/*=== Panel */
-#overlay {
-	display: none;
-	position: fixed;
-	top: 0; bottom: 0;
-	left: 0; right: 0;
-	background: rgba(0, 0, 0, 0.9);
-}
-#panel {
-	display: none;
-	position: fixed;
-	top: 1em; bottom: 1em;
-	left: 2em; right: 2em;
-	overflow: auto;
-	background: #fff;
-}
-#panel .close {
-	position: fixed;
-	top: 0; bottom: 0;
-	left: 0; right: 0;
-	display: block;
-}
-#panel .close img {
-	display: none;
-}
-
-/*=== DIVERS */
-/*===========*/
-.nav-login,
-.nav_menu .search,
-.nav_menu .toggle_aside {
-	display: none;
-}
-
-.aside .toggle_aside {
-	position: absolute;
-	right: 0;
-	display: none;
-	width: 30px;
-	height: 30px;
-	line-height: 30px;
-	text-align: center;
-}
-
-/*=== MOBILE */
-/*===========*/
-@media(max-width: 840px) {
-	.header,
-	.aside .btn-important,
-	.aside .feeds .dropdown,
-	.flux_header .item.website span,
-	.item.date, .day .date,
-	.dropdown-menu > .no-mobile,
-	.no-mobile {
-		display: none;
-	}
-	.nav-login {
-		display: block;
-	}
-	.nav_menu .toggle_aside,
-	.aside .toggle_aside,
-	.nav_menu .search,
-	#panel .close img {
-		display: inline-block;
-	}
-
-	.aside {
-		position: fixed;
-		top: 0; bottom: 0;
-		left: 0;
-		width: 0;
-		overflow: hidden;
-		z-index: 100;
-	}
-	.aside:target {
-		width: 90%;
-		overflow: auto;
-	}
-	.aside .categories {
-		margin: 10px 0 75px;
-	}
-
-	.flux_header .item.website {
-		width: 40px;
-	}
-
-	.flux:not(.current):hover .item.title {
-		position: relative;
-		width: auto;
-		white-space: nowrap;
-	}
-
-	.notification {
-		top: 0;
-		left: 0;
-		right: 0;
-	}
-
-	#nav_entries {
-		width: 100%;
-	}
-
-	#stream.global .box-category {
-		margin: 10px 0;
-	}
-
-	#panel {
-		top: 0; bottom: 0;
-		left: 0; right: 0;
-	}
-	#panel .close {
-		top: 0; right: 0;
-		left: auto; bottom: auto;
-		display: inline-block;
-		width: 30px;
-		height: 30px;
-	}
-}
-
-/*=== PRINTER */
-/*============*/
-@media print {
-	.header, .aside,
-	.nav_menu, .day,
-	.flux_header,
-	.flux_content .bottom,
-	.pagination,
-	#nav_entries {
-		display: none;
-	}
-	html, body {
-		background: #fff;
-		color: #000;
-		font-family: Serif;
-	}
-	#global,
-	.flux_content {
-		display: block !important;
-	}
-	.flux_content .content {
-		width: 100% !important;
-	}
-	.flux_content .content a {
-		color: #000;
-	}
-	.flux_content .content a:after {
-		content: " [" attr(href) "] ";
-		font-style: italic;
-	}
-}

+ 33 - 7
p/themes/Flat/flat.css

@@ -15,7 +15,7 @@ html, body {
 }
 }
 
 
 /*=== Links */
 /*=== Links */
-a {
+a, button.as-link {
 	color: #2980b9;
 	color: #2980b9;
 	outline: none;
 	outline: none;
 }
 }
@@ -49,6 +49,7 @@ input, select, textarea {
 	background: #fff;
 	background: #fff;
 	border: none;
 	border: none;
 	border-bottom: 3px solid #ddd;
 	border-bottom: 3px solid #ddd;
+	border-left-color: #ddd;
 	color: #666;
 	color: #666;
 	border-radius: 5px;
 	border-radius: 5px;
 }
 }
@@ -155,10 +156,17 @@ form th {
 .stick .btn + .dropdown > .btn {
 .stick .btn + .dropdown > .btn {
 	border-radius: 0 5px 5px 0;
 	border-radius: 0 5px 5px 0;
 }
 }
+.stick .btn + .btn,
 .stick .btn + input,
 .stick .btn + input,
+.stick .btn + .dropdown > .btn,
+.stick input + .btn,
 .stick input + input,
 .stick input + input,
-.stick .dropdown + input {
-	border-left: 1px solid #ddd;
+.stick input + .dropdown > .btn,
+.stick .dropdown + .btn,
+.stick .dropdown + input,
+.stick .dropdown + .dropdown > .btn {
+	border-left-width: 1px;
+	border-left-style: solid;
 }
 }
 
 
 .btn {
 .btn {
@@ -175,6 +183,7 @@ form th {
 	border-radius: 5px;
 	border-radius: 5px;
 	border: none;
 	border: none;
 	border-bottom: 3px solid #2980b9;
 	border-bottom: 3px solid #2980b9;
+	border-left-color: #2980b9;
 	color: #fff;
 	color: #fff;
 }
 }
 a.btn {
 a.btn {
@@ -196,6 +205,7 @@ a.btn {
 	background: #e67e22;
 	background: #e67e22;
 	color: #fff;
 	color: #fff;
 	border-bottom: 3px solid #d35400;
 	border-bottom: 3px solid #d35400;
+	border-left-color: #d35400;
 }
 }
 .btn-important:hover,
 .btn-important:hover,
 .btn-important:active {
 .btn-important:active {
@@ -206,6 +216,7 @@ a.btn {
 	background: #e74c3c;
 	background: #e74c3c;
 	color: #fff;
 	color: #fff;
 	border-bottom: 3px solid #c0392b;
 	border-bottom: 3px solid #c0392b;
+	border-left-color: #c0392b;
 }
 }
 .btn-attention:hover,
 .btn-attention:hover,
 .btn-attention:active {
 .btn-attention:active {
@@ -327,17 +338,21 @@ a.btn {
 	padding: 0 25px;
 	padding: 0 25px;
 	line-height: 2.5em;
 	line-height: 2.5em;
 }
 }
-.dropdown-menu > .item > span {
-	padding: 0 25px;
+.dropdown-menu > .item > span,
+.dropdown-menu > .item > .as-link {
+	padding: 0 22px;
 	line-height: 2em;
 	line-height: 2em;
 }
 }
+.dropdown-menu > .item:hover {
+	background: #2980b9;
+	color: #fff;
+}
 .dropdown-menu > .item[aria-checked="true"] > a:before {
 .dropdown-menu > .item[aria-checked="true"] > a:before {
 	font-weight: bold;
 	font-weight: bold;
 	margin: 0 0 0 -14px;
 	margin: 0 0 0 -14px;
 }
 }
 .dropdown-menu > .item:hover > a {
 .dropdown-menu > .item:hover > a {
 	text-decoration: none;
 	text-decoration: none;
-	background: #2980b9;
 	color: #fff;
 	color: #fff;
 }
 }
 .dropdown-menu .input select,
 .dropdown-menu .input select,
@@ -844,7 +859,18 @@ a.btn {
 .stat > table td,
 .stat > table td,
 .stat > table th {
 .stat > table th {
 	border-bottom: 1px solid #ddd;
 	border-bottom: 1px solid #ddd;
-	text-align: center;
+}
+
+.stat > .horizontal-list {
+	margin: 0 0 5px;
+}
+.stat > .horizontal-list .item {
+	overflow: hidden;
+	white-space: nowrap;
+	text-overflow: ellipsis;
+}
+.stat > .horizontal-list .item:first-child {
+	width: 270px;
 }
 }
 
 
 /*=== LOGS */
 /*=== LOGS */

+ 1 - 1
p/themes/Flat/metadata.json

@@ -3,5 +3,5 @@
   "author": "Marien Fressinaud",
   "author": "Marien Fressinaud",
   "description": "Thème plat pour FreshRSS",
   "description": "Thème plat pour FreshRSS",
   "version": 0.2,
   "version": 0.2,
-  "files": ["template.css", "flat.css"]
+  "files": ["_template.css", "flat.css"]
 }
 }

+ 0 - 698
p/themes/Flat/template.css

@@ -1,698 +0,0 @@
-@charset "UTF-8";
-
-/*=== GENERAL */
-/*============*/
-html, body {
-	margin: 0;
-	padding: 0;
-	font-size: 100%;
-}
-
-/*=== Links */
-a {
-	text-decoration: none;
-}
-a:hover {
-	text-decoration: underline;
-}
-
-/*=== Lists */
-ul, ol, dd {
-	margin: 0;
-	padding: 0;
-}
-
-/*=== Titles */
-h1 {
-	margin: 0.6em 0 0.3em;
-	font-size: 1.5em;
-	line-height: 1.6em;
-}
-h2 {
-	margin: 0.5em 0 0.25em;
-	font-size: 1.3em;
-	line-height: 2em;
-}
-h3 {
-	margin: 0.5em 0 0.25em;
-	font-size: 1.1em;
-	line-height: 2em;
-}
-
-/*=== Paragraphs */
-p {
-	margin: 1em 0 0.5em;
-	font-size: 1em;
-}
-
-/*=== Images */
-img {
-	height: auto;
-	max-width: 100%;
-}
-img.favicon {
-	height: 16px;
-	width: 16px;
-	vertical-align: middle;
-}
-
-/*=== Videos */
-iframe, embed, object, video {
-	max-width: 100%;
-}
-
-/*=== Forms */
-legend {
-	display: block;
-	width: 100%;
-	clear: both;
-}
-label {
-	display: block;
-}
-input {
-	width: 180px;
-}
-textarea {
-	width: 300px;
-}
-input, select, textarea {
-	display: inline-block;
-	max-width: 100%;
-}
-input[type="radio"],
-input[type="checkbox"] {
-	width: 15px !important;
-	min-height: 15px !important;
-}
-input.extend:focus {
-	width: 300px;
-}
-
-/*=== COMPONENTS */
-/*===============*/
-/*=== Forms */
-.form-group:after {
-	content: "";
-	display: block;
-	clear: both;
-}
-.form-group.form-actions {
-	min-width: 250px;
-}
-.form-group .group-name {
-	display: block;
-	float: left;
-	width: 200px;
-}
-.form-group .group-controls {
-	min-width: 250px;
-	margin: 0 0 0 220px;
-}
-.form-group .group-controls .control {
-	display: block;
-}
-
-/*=== Buttons */
-.stick {
-	display: inline-block;
-	white-space: nowrap;
-}
-.btn,
-a.btn {
-	display: inline-block;
-	cursor: pointer;
-	overflow: hidden;
-}
-.btn-important {
-	font-weight: bold;
-}
-
-/*=== Navigation */
-.nav-list .nav-header,
-.nav-list .item {
-	display: block;
-}
-.nav-list .item,
-.nav-list .item > a {
-	display: block;
-	overflow: hidden;
-	white-space: nowrap;
-	text-overflow: ellipsis;
-}
-.nav-head {
-	display: block;
-}
-.nav-head .item {
-	display: inline-block;
-}
-
-/*=== Horizontal-list */
-.horizontal-list {
-	display: table;
-	table-layout: fixed;
-	width: 100%;
-}
-.horizontal-list .item {
-	display: table-cell;
-}
-
-/*=== Dropdown */
-.dropdown {
-	position: relative;
-	display: inline-block;
-}
-.dropdown-target {
-	display: none;
-}
-.dropdown-menu {
-	display: none;
-	min-width: 200px;
-	margin: 0;
-	position: absolute;
-	right: 0;
-	background: #fff;
-	border: 1px solid #aaa;
-}
-.dropdown-header {
-	display: block;
-}
-.dropdown-menu > .item {
-	display: block;
-}
-.dropdown-menu > .item > a,
-.dropdown-menu > .item > span {
-	display: block;
-}
-.dropdown-menu > .item[aria-checked="true"] > a:before {
-	content: '✓';
-}
-.dropdown-menu .input {
-	display: block;
-}
-.dropdown-menu .input select,
-.dropdown-menu .input input {
-	display: block;
-	max-width: 95%;
-}
-.dropdown-target:target ~ .dropdown-menu {
-	display: block;
-	z-index: 10;
-}
-.dropdown-close {
-	display: inline;
-}
-.dropdown-close a {
-	font-size: 0;
-	position: fixed;
-	top: 0; bottom: 0;
-	left: 0; right: 0;
-	display: block;
-	z-index: -10;
-}
-.separator {
-	display: block;
-	height: 0;
-	border-bottom: 1px solid #aaa;
-}
-
-/*=== Alerts */
-.alert {
-	display: block;
-	width: 90%;
-}
-.group-controls .alert {
-	width: 100%
-}
-.alert-head {
-	margin: 0;
-	font-weight: bold;
-}
-.alert ul {
-	margin: 5px 20px;
-}
-
-/*=== Icons */
-.icon {
-	display: inline-block;
-	width: 16px;
-	height: 16px;
-	vertical-align: middle;
-	line-height: 16px;
-}
-
-/*=== Pagination */
-.pagination {
-	display: table;
-	width: 100%;
-	margin: 0;
-	padding: 0;
-	table-layout: fixed;
-}
-.pagination .item {
-	display: table-cell;
-}
-.pagination .pager-first,
-.pagination .pager-previous,
-.pagination .pager-next,
-.pagination .pager-last {
-	width: 100px;
-}
-
-/*=== STRUCTURE */
-/*===============*/
-/*=== Header */
-.header {
-	display: table;
-	width: 100%;
-	table-layout: fixed;
-}
-.header > .item {
-	display: table-cell;
-}
-.header > .item.title {
-	width: 250px;
-	white-space: nowrap;
-}
-.header > .item.title h1 {
-	display: inline-block;
-}
-.header > .item.title .logo {
-	display: inline-block;
-	height: 32px;
-	width: 32px;
-	vertical-align: middle;
-}
-.header > .item.configure {
-	width: 100px;
-}
-
-/*=== Body */
-#global {
-	display: table;
-	width: 100%;
-	height: 100%;
-	table-layout: fixed;
-}
-.aside {
-	display: table-cell;
-	height: 100%;
-	width: 250px;
-	vertical-align: top;
-}
-.aside.aside_flux {
-	background: #fff;
-}
-
-/*=== Aside main page (categories) */
-.categories {
-	list-style: none;
-	margin: 0;
-}
-.state_unread li:not(.active)[data-unread="0"] {
-	display: none;
-}
-.category {
-	display: block;
-	overflow: hidden;
-	white-space: nowrap;
-	text-overflow: ellipsis;
-}
-.category .btn:not([data-unread="0"]):after {
-	content: attr(data-unread);
-}
-
-/*=== Aside main page (feeds) */
-.categories .feeds {
-	width: 100%;
-	list-style: none;
-}
-.categories .feeds:not(.active) {
-	display: none;
-}
-.categories .feeds .feed {
-	display: inline-block;
-	overflow: hidden;
-	white-space: nowrap;
-	text-overflow: ellipsis;
-	vertical-align: middle;
-}
-.categories .feeds .feed:not([data-unread="0"]):before {
-	content: "(" attr(data-unread) ") ";
-}
-.categories .feeds .dropdown-menu {
-	left: 0;
-}
-.categories .feeds .item .dropdown-toggle > .icon {
-	visibility: hidden;
-	cursor: pointer;
-	vertical-align: top;
-}
-.categories .feeds .item .dropdown-target:target ~ .dropdown-toggle > .icon,
-.categories .feeds .item:hover .dropdown-toggle > .icon,
-.categories .feeds .item.active .dropdown-toggle > .icon {
-	visibility: visible;
-}
-
-/*=== New article notification */
-#new-article {
-	display: none;
-}
-#new-article > a {
-	display: block;
-}
-
-/*=== Day indication */
-.day .name {
-	position: absolute;
-	right: 0;
-	width: 50%;
-	overflow: hidden;
-	white-space: nowrap;
-	text-overflow: ellipsis;
-}
-
-/*=== Feed article header and footer */
-.flux_header {
-	position: relative;
-}
-.flux .item {
-	line-height: 40px;
-	white-space: nowrap;
-}
-.flux .item.manage,
-.flux .item.link {
-	width: 40px;
-	text-align: center;
-}
-.flux .item.website {
-	width: 200px;
-}
-.flux.not_read .item.title,
-.flux.current .item.title {
-	font-weight: bold;
-}
-.flux:not(.current):hover .item.title {
-	position: absolute;
-	max-width: calc(100% - 320px);
-	background: #fff;
-}
-.flux .item.title a {
-	color: #000;
-	text-decoration: none;
-}
-.flux .item.date {
-	width: 145px;
-	text-align: right;
-}
-.flux .item > a {
-	display: block;
-}
-.flux .item > a {
-	display: block;
-	text-decoration: none;
-	white-space: nowrap;
-	text-overflow: ellipsis;
-	overflow: hidden;
-}
-.flux .item.share > a {
-	display: list-item;
-	list-style-position: inside;
-	list-style-type: decimal;
-}
-
-/*=== Feed article content */
-.hide_posts > .flux:not(.active) > .flux_content {
-	display: none;
-}
-.content {
-	min-height: 20em;
-	margin: auto;
-	line-height: 1.7em;
-	word-wrap: break-word;
-}
-.content.large {
-	max-width: 1000px;
-}
-.content.medium {
-	max-width: 800px;
-}
-.content.thin {
-	max-width: 550px;
-}
-.content ul,
-.content ol,
-.content dd {
-	margin: 0 0 0 15px;
-	padding: 0 0 5px 15px;
-}
-.content pre {
-	overflow: auto;
-}
-
-/*=== Notification and actualize notification */
-.notification {
-	position: absolute;
-	top: 1em;
-	left: 25%; right: 25%;
-	z-index: 10;
-	background: #fff;
-	border: 1px solid #aaa;
-}
-.notification.closed {
-	display: none;
-}
-.notification a.close {
-	position: absolute;
-	top: 0; bottom: 0;
-	right: 0;
-	display: inline-block;
-}
-
-#actualizeProgress {
-	position: fixed;
-}
-#actualizeProgress progress {
-	max-width: 100%;
-	vertical-align: middle;
-}
-#actualizeProgress .progress {
-	vertical-align: middle;
-}
-
-/*=== Navigation menu (for articles) */
-#nav_entries {
-	position: fixed;
-	bottom: 0; left: 0;
-	display: table;
-	width: 250px;
-	background: #fff;
-	table-layout: fixed;
-}
-#nav_entries .item {
-	display: table-cell;
-	width: 30%;
-}
-#nav_entries a {
-	display: block;
-}
-
-/*=== "Load more" part */
-#load_more {
-	min-height: 40px;
-}
-.loading {
-	background: url("loader.gif") center center no-repeat;
-	font-size: 0;
-}
-#bigMarkAsRead {
-	display: block;
-	padding: 3em 0;
-	text-align: center;
-}
-.bigTick {
-	font-size: 7em;
-	line-height: 1.6em;
-}
-
-/*=== Statistiques */
-.stat > table {
-	width: 100%;
-}
-
-/*=== GLOBAL VIEW */
-/*================*/
-/*=== Category boxes */
-#stream.global .box-category {
-	display: inline-block;
-	width: 19em;
-	max-width: 95%;
-	margin: 20px 10px;
-	border: 1px solid #ccc;
-	vertical-align: top;
-}
-#stream.global .category {
-	width: 100%;
-}
-#stream.global .btn {
-	display: block;
-}
-#stream.global .box-category .feeds {
-	display: block;
-	overflow: auto;
-}
-#stream.global .box-category .feed {
-	width: 19em;
-	max-width: 90%;
-}
-
-/*=== Panel */
-#overlay {
-	display: none;
-	position: fixed;
-	top: 0; bottom: 0;
-	left: 0; right: 0;
-	background: rgba(0, 0, 0, 0.9);
-}
-#panel {
-	display: none;
-	position: fixed;
-	top: 1em; bottom: 1em;
-	left: 2em; right: 2em;
-	overflow: auto;
-	background: #fff;
-}
-#panel .close {
-	position: fixed;
-	top: 0; bottom: 0;
-	left: 0; right: 0;
-	display: block;
-}
-#panel .close img {
-	display: none;
-}
-
-/*=== DIVERS */
-/*===========*/
-.nav-login,
-.nav_menu .search,
-.nav_menu .toggle_aside {
-	display: none;
-}
-
-.aside .toggle_aside {
-	position: absolute;
-	right: 0;
-	display: none;
-	width: 30px;
-	height: 30px;
-	line-height: 30px;
-	text-align: center;
-}
-
-/*=== MOBILE */
-/*===========*/
-@media(max-width: 840px) {
-	.header,
-	.aside .btn-important,
-	.aside .feeds .dropdown,
-	.flux_header .item.website span,
-	.item.date, .day .date,
-	.dropdown-menu > .no-mobile,
-	.no-mobile {
-		display: none;
-	}
-	.nav-login {
-		display: block;
-	}
-	.nav_menu .toggle_aside,
-	.aside .toggle_aside,
-	.nav_menu .search,
-	#panel .close img {
-		display: inline-block;
-	}
-
-	.aside {
-		position: fixed;
-		top: 0; bottom: 0;
-		left: 0;
-		width: 0;
-		overflow: hidden;
-		z-index: 100;
-	}
-	.aside:target {
-		width: 90%;
-		overflow: auto;
-	}
-	.aside .categories {
-		margin: 10px 0 75px;
-	}
-
-	.flux_header .item.website {
-		width: 40px;
-	}
-
-	.flux:not(.current):hover .item.title {
-		position: relative;
-		width: auto;
-		white-space: nowrap;
-	}
-
-	.notification {
-		top: 0;
-		left: 0;
-		right: 0;
-	}
-
-	#nav_entries {
-		width: 100%;
-	}
-
-	#stream.global .box-category {
-		margin: 10px 0;
-	}
-
-	#panel {
-		top: 0; bottom: 0;
-		left: 0; right: 0;
-	}
-	#panel .close {
-		top: 0; right: 0;
-		left: auto; bottom: auto;
-		display: inline-block;
-		width: 30px;
-		height: 30px;
-	}
-}
-
-/*=== PRINTER */
-/*============*/
-@media print {
-	.header, .aside,
-	.nav_menu, .day,
-	.flux_header,
-	.flux_content .bottom,
-	.pagination,
-	#nav_entries {
-		display: none;
-	}
-	html, body {
-		background: #fff;
-		color: #000;
-		font-family: Serif;
-	}
-	#global,
-	.flux_content {
-		display: block !important;
-	}
-	.flux_content .content {
-		width: 100% !important;
-	}
-	.flux_content .content a {
-		color: #000;
-	}
-	.flux_content .content a:after {
-		content: " [" attr(href) "] ";
-		font-style: italic;
-	}
-}

+ 1 - 1
p/themes/Origine/metadata.json

@@ -3,5 +3,5 @@
   "author": "Marien Fressinaud",
   "author": "Marien Fressinaud",
   "description": "Le thème par défaut pour FreshRSS",
   "description": "Le thème par défaut pour FreshRSS",
   "version": 0.2,
   "version": 0.2,
-  "files": ["template.css", "origine.css"]
+  "files": ["_template.css", "origine.css"]
 }
 }

+ 20 - 12
p/themes/Origine/origine.css

@@ -15,7 +15,7 @@ html, body {
 }
 }
 
 
 /*=== Links */
 /*=== Links */
-a {
+a, button.as-link {
 	color: #0062be;
 	color: #0062be;
 	outline: none;
 	outline: none;
 }
 }
@@ -364,8 +364,9 @@ a.btn {
 	padding: 0 25px;
 	padding: 0 25px;
 	line-height: 2.5em;
 	line-height: 2.5em;
 }
 }
-.dropdown-menu > .item > span {
-	padding: 0 25px;
+.dropdown-menu > .item > span,
+.dropdown-menu > .item > .as-link {
+	padding: 0 22px;
 	line-height: 2em;
 	line-height: 2em;
 }
 }
 .dropdown-menu > .item:hover {
 .dropdown-menu > .item:hover {
@@ -807,16 +808,12 @@ a.btn {
 	background: #fafafa;
 	background: #fafafa;
 }
 }
 #bigMarkAsRead:hover {
 #bigMarkAsRead:hover {
-	color: #000;
-	background: #ccc;
-	background: radial-gradient(circle at 50% -25% , #ccc 0%, #fafafa 50%);
-	background: -moz-radial-gradient(circle at 50% -25% , #ccc 0%, #fafafa 50%);
-	background: -webkit-radial-gradient(circle at 50% -25% , #ccc 0%, #fafafa 50%);
-	background: -o-radial-gradient(circle at 50% -25% , #ccc 0%, #fafafa 50%);
-	background: -ms-radial-gradient(circle at 50% -25% , #ccc 0%, #fafafa 50%);
+	color: #0062be;
+	background: #fff;
+	box-shadow: 0 -5px 10px #eee inset;
 }
 }
 #bigMarkAsRead:hover .bigTick {
 #bigMarkAsRead:hover .bigTick {
-	text-shadow: 0 0 10px #666;
+	text-shadow: 0 0 5px #0062be;
 }
 }
 
 
 /*=== Navigation menu (for articles) */
 /*=== Navigation menu (for articles) */
@@ -916,7 +913,18 @@ a.btn {
 .stat > table td,
 .stat > table td,
 .stat > table th {
 .stat > table th {
 	border-bottom: 1px solid #ddd;
 	border-bottom: 1px solid #ddd;
-	text-align: center;
+}
+
+.stat > .horizontal-list {
+	margin: 0 0 5px;
+}
+.stat > .horizontal-list .item {
+	overflow: hidden;
+	white-space: nowrap;
+	text-overflow: ellipsis;
+}
+.stat > .horizontal-list .item:first-child {
+	width: 270px;
 }
 }
 
 
 /*=== LOGS */
 /*=== LOGS */

+ 0 - 698
p/themes/Origine/template.css

@@ -1,698 +0,0 @@
-@charset "UTF-8";
-
-/*=== GENERAL */
-/*============*/
-html, body {
-	margin: 0;
-	padding: 0;
-	font-size: 100%;
-}
-
-/*=== Links */
-a {
-	text-decoration: none;
-}
-a:hover {
-	text-decoration: underline;
-}
-
-/*=== Lists */
-ul, ol, dd {
-	margin: 0;
-	padding: 0;
-}
-
-/*=== Titles */
-h1 {
-	margin: 0.6em 0 0.3em;
-	font-size: 1.5em;
-	line-height: 1.6em;
-}
-h2 {
-	margin: 0.5em 0 0.25em;
-	font-size: 1.3em;
-	line-height: 2em;
-}
-h3 {
-	margin: 0.5em 0 0.25em;
-	font-size: 1.1em;
-	line-height: 2em;
-}
-
-/*=== Paragraphs */
-p {
-	margin: 1em 0 0.5em;
-	font-size: 1em;
-}
-
-/*=== Images */
-img {
-	height: auto;
-	max-width: 100%;
-}
-img.favicon {
-	height: 16px;
-	width: 16px;
-	vertical-align: middle;
-}
-
-/*=== Videos */
-iframe, embed, object, video {
-	max-width: 100%;
-}
-
-/*=== Forms */
-legend {
-	display: block;
-	width: 100%;
-	clear: both;
-}
-label {
-	display: block;
-}
-input {
-	width: 180px;
-}
-textarea {
-	width: 300px;
-}
-input, select, textarea {
-	display: inline-block;
-	max-width: 100%;
-}
-input[type="radio"],
-input[type="checkbox"] {
-	width: 15px !important;
-	min-height: 15px !important;
-}
-input.extend:focus {
-	width: 300px;
-}
-
-/*=== COMPONENTS */
-/*===============*/
-/*=== Forms */
-.form-group:after {
-	content: "";
-	display: block;
-	clear: both;
-}
-.form-group.form-actions {
-	min-width: 250px;
-}
-.form-group .group-name {
-	display: block;
-	float: left;
-	width: 200px;
-}
-.form-group .group-controls {
-	min-width: 250px;
-	margin: 0 0 0 220px;
-}
-.form-group .group-controls .control {
-	display: block;
-}
-
-/*=== Buttons */
-.stick {
-	display: inline-block;
-	white-space: nowrap;
-}
-.btn,
-a.btn {
-	display: inline-block;
-	cursor: pointer;
-	overflow: hidden;
-}
-.btn-important {
-	font-weight: bold;
-}
-
-/*=== Navigation */
-.nav-list .nav-header,
-.nav-list .item {
-	display: block;
-}
-.nav-list .item,
-.nav-list .item > a {
-	display: block;
-	overflow: hidden;
-	white-space: nowrap;
-	text-overflow: ellipsis;
-}
-.nav-head {
-	display: block;
-}
-.nav-head .item {
-	display: inline-block;
-}
-
-/*=== Horizontal-list */
-.horizontal-list {
-	display: table;
-	table-layout: fixed;
-	width: 100%;
-}
-.horizontal-list .item {
-	display: table-cell;
-}
-
-/*=== Dropdown */
-.dropdown {
-	position: relative;
-	display: inline-block;
-}
-.dropdown-target {
-	display: none;
-}
-.dropdown-menu {
-	display: none;
-	min-width: 200px;
-	margin: 0;
-	position: absolute;
-	right: 0;
-	background: #fff;
-	border: 1px solid #aaa;
-}
-.dropdown-header {
-	display: block;
-}
-.dropdown-menu > .item {
-	display: block;
-}
-.dropdown-menu > .item > a,
-.dropdown-menu > .item > span {
-	display: block;
-}
-.dropdown-menu > .item[aria-checked="true"] > a:before {
-	content: '✓';
-}
-.dropdown-menu .input {
-	display: block;
-}
-.dropdown-menu .input select,
-.dropdown-menu .input input {
-	display: block;
-	max-width: 95%;
-}
-.dropdown-target:target ~ .dropdown-menu {
-	display: block;
-	z-index: 10;
-}
-.dropdown-close {
-	display: inline;
-}
-.dropdown-close a {
-	font-size: 0;
-	position: fixed;
-	top: 0; bottom: 0;
-	left: 0; right: 0;
-	display: block;
-	z-index: -10;
-}
-.separator {
-	display: block;
-	height: 0;
-	border-bottom: 1px solid #aaa;
-}
-
-/*=== Alerts */
-.alert {
-	display: block;
-	width: 90%;
-}
-.group-controls .alert {
-	width: 100%
-}
-.alert-head {
-	margin: 0;
-	font-weight: bold;
-}
-.alert ul {
-	margin: 5px 20px;
-}
-
-/*=== Icons */
-.icon {
-	display: inline-block;
-	width: 16px;
-	height: 16px;
-	vertical-align: middle;
-	line-height: 16px;
-}
-
-/*=== Pagination */
-.pagination {
-	display: table;
-	width: 100%;
-	margin: 0;
-	padding: 0;
-	table-layout: fixed;
-}
-.pagination .item {
-	display: table-cell;
-}
-.pagination .pager-first,
-.pagination .pager-previous,
-.pagination .pager-next,
-.pagination .pager-last {
-	width: 100px;
-}
-
-/*=== STRUCTURE */
-/*===============*/
-/*=== Header */
-.header {
-	display: table;
-	width: 100%;
-	table-layout: fixed;
-}
-.header > .item {
-	display: table-cell;
-}
-.header > .item.title {
-	width: 250px;
-	white-space: nowrap;
-}
-.header > .item.title h1 {
-	display: inline-block;
-}
-.header > .item.title .logo {
-	display: inline-block;
-	height: 32px;
-	width: 32px;
-	vertical-align: middle;
-}
-.header > .item.configure {
-	width: 100px;
-}
-
-/*=== Body */
-#global {
-	display: table;
-	width: 100%;
-	height: 100%;
-	table-layout: fixed;
-}
-.aside {
-	display: table-cell;
-	height: 100%;
-	width: 250px;
-	vertical-align: top;
-}
-.aside.aside_flux {
-	background: #fff;
-}
-
-/*=== Aside main page (categories) */
-.categories {
-	list-style: none;
-	margin: 0;
-}
-.state_unread li:not(.active)[data-unread="0"] {
-	display: none;
-}
-.category {
-	display: block;
-	overflow: hidden;
-	white-space: nowrap;
-	text-overflow: ellipsis;
-}
-.category .btn:not([data-unread="0"]):after {
-	content: attr(data-unread);
-}
-
-/*=== Aside main page (feeds) */
-.categories .feeds {
-	width: 100%;
-	list-style: none;
-}
-.categories .feeds:not(.active) {
-	display: none;
-}
-.categories .feeds .feed {
-	display: inline-block;
-	overflow: hidden;
-	white-space: nowrap;
-	text-overflow: ellipsis;
-	vertical-align: middle;
-}
-.categories .feeds .feed:not([data-unread="0"]):before {
-	content: "(" attr(data-unread) ") ";
-}
-.categories .feeds .dropdown-menu {
-	left: 0;
-}
-.categories .feeds .item .dropdown-toggle > .icon {
-	visibility: hidden;
-	cursor: pointer;
-	vertical-align: top;
-}
-.categories .feeds .item .dropdown-target:target ~ .dropdown-toggle > .icon,
-.categories .feeds .item:hover .dropdown-toggle > .icon,
-.categories .feeds .item.active .dropdown-toggle > .icon {
-	visibility: visible;
-}
-
-/*=== New article notification */
-#new-article {
-	display: none;
-}
-#new-article > a {
-	display: block;
-}
-
-/*=== Day indication */
-.day .name {
-	position: absolute;
-	right: 0;
-	width: 50%;
-	overflow: hidden;
-	white-space: nowrap;
-	text-overflow: ellipsis;
-}
-
-/*=== Feed article header and footer */
-.flux_header {
-	position: relative;
-}
-.flux .item {
-	line-height: 40px;
-	white-space: nowrap;
-}
-.flux .item.manage,
-.flux .item.link {
-	width: 40px;
-	text-align: center;
-}
-.flux .item.website {
-	width: 200px;
-}
-.flux.not_read .item.title,
-.flux.current .item.title {
-	font-weight: bold;
-}
-.flux:not(.current):hover .item.title {
-	position: absolute;
-	max-width: calc(100% - 320px);
-	background: #fff;
-}
-.flux .item.title a {
-	color: #000;
-	text-decoration: none;
-}
-.flux .item.date {
-	width: 145px;
-	text-align: right;
-}
-.flux .item > a {
-	display: block;
-}
-.flux .item > a {
-	display: block;
-	text-decoration: none;
-	white-space: nowrap;
-	text-overflow: ellipsis;
-	overflow: hidden;
-}
-.flux .item.share > a {
-	display: list-item;
-	list-style-position: inside;
-	list-style-type: decimal;
-}
-
-/*=== Feed article content */
-.hide_posts > .flux:not(.active) > .flux_content {
-	display: none;
-}
-.content {
-	min-height: 20em;
-	margin: auto;
-	line-height: 1.7em;
-	word-wrap: break-word;
-}
-.content.large {
-	max-width: 1000px;
-}
-.content.medium {
-	max-width: 800px;
-}
-.content.thin {
-	max-width: 550px;
-}
-.content ul,
-.content ol,
-.content dd {
-	margin: 0 0 0 15px;
-	padding: 0 0 5px 15px;
-}
-.content pre {
-	overflow: auto;
-}
-
-/*=== Notification and actualize notification */
-.notification {
-	position: absolute;
-	top: 1em;
-	left: 25%; right: 25%;
-	z-index: 10;
-	background: #fff;
-	border: 1px solid #aaa;
-}
-.notification.closed {
-	display: none;
-}
-.notification a.close {
-	position: absolute;
-	top: 0; bottom: 0;
-	right: 0;
-	display: inline-block;
-}
-
-#actualizeProgress {
-	position: fixed;
-}
-#actualizeProgress progress {
-	max-width: 100%;
-	vertical-align: middle;
-}
-#actualizeProgress .progress {
-	vertical-align: middle;
-}
-
-/*=== Navigation menu (for articles) */
-#nav_entries {
-	position: fixed;
-	bottom: 0; left: 0;
-	display: table;
-	width: 250px;
-	background: #fff;
-	table-layout: fixed;
-}
-#nav_entries .item {
-	display: table-cell;
-	width: 30%;
-}
-#nav_entries a {
-	display: block;
-}
-
-/*=== "Load more" part */
-#load_more {
-	min-height: 40px;
-}
-.loading {
-	background: url("loader.gif") center center no-repeat;
-	font-size: 0;
-}
-#bigMarkAsRead {
-	display: block;
-	padding: 3em 0;
-	text-align: center;
-}
-.bigTick {
-	font-size: 7em;
-	line-height: 1.6em;
-}
-
-/*=== Statistiques */
-.stat > table {
-	width: 100%;
-}
-
-/*=== GLOBAL VIEW */
-/*================*/
-/*=== Category boxes */
-#stream.global .box-category {
-	display: inline-block;
-	width: 19em;
-	max-width: 95%;
-	margin: 20px 10px;
-	border: 1px solid #ccc;
-	vertical-align: top;
-}
-#stream.global .category {
-	width: 100%;
-}
-#stream.global .btn {
-	display: block;
-}
-#stream.global .box-category .feeds {
-	display: block;
-	overflow: auto;
-}
-#stream.global .box-category .feed {
-	width: 19em;
-	max-width: 90%;
-}
-
-/*=== Panel */
-#overlay {
-	display: none;
-	position: fixed;
-	top: 0; bottom: 0;
-	left: 0; right: 0;
-	background: rgba(0, 0, 0, 0.9);
-}
-#panel {
-	display: none;
-	position: fixed;
-	top: 1em; bottom: 1em;
-	left: 2em; right: 2em;
-	overflow: auto;
-	background: #fff;
-}
-#panel .close {
-	position: fixed;
-	top: 0; bottom: 0;
-	left: 0; right: 0;
-	display: block;
-}
-#panel .close img {
-	display: none;
-}
-
-/*=== DIVERS */
-/*===========*/
-.nav-login,
-.nav_menu .search,
-.nav_menu .toggle_aside {
-	display: none;
-}
-
-.aside .toggle_aside {
-	position: absolute;
-	right: 0;
-	display: none;
-	width: 30px;
-	height: 30px;
-	line-height: 30px;
-	text-align: center;
-}
-
-/*=== MOBILE */
-/*===========*/
-@media(max-width: 840px) {
-	.header,
-	.aside .btn-important,
-	.aside .feeds .dropdown,
-	.flux_header .item.website span,
-	.item.date, .day .date,
-	.dropdown-menu > .no-mobile,
-	.no-mobile {
-		display: none;
-	}
-	.nav-login {
-		display: block;
-	}
-	.nav_menu .toggle_aside,
-	.aside .toggle_aside,
-	.nav_menu .search,
-	#panel .close img {
-		display: inline-block;
-	}
-
-	.aside {
-		position: fixed;
-		top: 0; bottom: 0;
-		left: 0;
-		width: 0;
-		overflow: hidden;
-		z-index: 100;
-	}
-	.aside:target {
-		width: 90%;
-		overflow: auto;
-	}
-	.aside .categories {
-		margin: 10px 0 75px;
-	}
-
-	.flux_header .item.website {
-		width: 40px;
-	}
-
-	.flux:not(.current):hover .item.title {
-		position: relative;
-		width: auto;
-		white-space: nowrap;
-	}
-
-	.notification {
-		top: 0;
-		left: 0;
-		right: 0;
-	}
-
-	#nav_entries {
-		width: 100%;
-	}
-
-	#stream.global .box-category {
-		margin: 10px 0;
-	}
-
-	#panel {
-		top: 0; bottom: 0;
-		left: 0; right: 0;
-	}
-	#panel .close {
-		top: 0; right: 0;
-		left: auto; bottom: auto;
-		display: inline-block;
-		width: 30px;
-		height: 30px;
-	}
-}
-
-/*=== PRINTER */
-/*============*/
-@media print {
-	.header, .aside,
-	.nav_menu, .day,
-	.flux_header,
-	.flux_content .bottom,
-	.pagination,
-	#nav_entries {
-		display: none;
-	}
-	html, body {
-		background: #fff;
-		color: #000;
-		font-family: Serif;
-	}
-	#global,
-	.flux_content {
-		display: block !important;
-	}
-	.flux_content .content {
-		width: 100% !important;
-	}
-	.flux_content .content a {
-		color: #000;
-	}
-	.flux_content .content a:after {
-		content: " [" attr(href) "] ";
-		font-style: italic;
-	}
-}

+ 4 - 0
p/themes/Pafat/README.md

@@ -0,0 +1,4 @@
+Pafat
+=====
+
+Thème Pafat pour FreshRSS

+ 7 - 0
p/themes/Pafat/icons/all.svg

@@ -0,0 +1,7 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
+<g transform="translate(-40.0002,-746)" fill="#FFF">
+<rect style="color:#FFF;" height="2.0002" width="9.9996" y="749" x="43"/>
+<rect style="color:#FFF;" height="2.0002" width="9.9996" y="753" x="43"/>
+<rect style="color:#FFF;" height="2.0002" width="9.9996" y="757" x="43"/>
+</g>
+</svg>

+ 5 - 0
p/themes/Pafat/icons/bookmark.svg

@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
+<g transform="translate(-41.000202,-397)">
+<path style="enable-background:accumulate;color:#000000;" d="m530.95,186.71c-0.77941,0.55189-3.1576-1.906-4.1125-1.9179-0.95532-0.0119-3.3949,2.3858-4.161,1.8149-0.76573-0.57072,0.83698-3.592,0.55319-4.5039-0.2839-0.91223-3.3182-2.4915-3.0119-3.3965,0.30617-0.90461,3.6749-0.31399,4.4544-0.86567,0.77986-0.5519,1.3442-3.9257,2.2995-3.914,0.95494,0.0116,1.4342,3.398,2.1998,3.9689,0.76588,0.57114,4.1489,0.0653,4.4331,0.97746,0.28402,0.9118-2.7885,2.414-3.0949,3.3186-0.30652,0.90489,1.22,3.966,0.44027,4.5182z" fill-rule="nonzero" transform="matrix(1.0472113,-0.00871584,0.00871584,1.0472113,-504.35434,220.15425)" fill="#FFF"/>
+</g>
+</svg>

+ 1 - 1
p/themes/Screwdriver/icons/down.svg → p/themes/Pafat/icons/down.svg

@@ -1,5 +1,5 @@
 <svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
 <svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
 <g transform="translate(-181.0002,-747)">
 <g transform="translate(-181.0002,-747)">
-<path style="block-progression:tb;color:#bebebe;direction:ltr;text-indent:0;text-align:start;enable-background:new;text-transform:none;" d="m195.03,751,0,1c-0.00091,0.0111,0.00059,0.021-0.00009,0.0312-0.0112,0.25496-0.12835,0.50994-0.31251,0.6875l-5.7188,6.2977-5.7188-6.2977c-0.18821-0.1881-0.28121-0.45346-0.28122-0.71875v-1h1c0.26531,0.00007,0.53059,0.0931,0.71873,0.28131l4.2812,4.829,4.2813-4.829c0.19464-0.21073,0.46925-0.30315,0.74998-0.2813z" fill-rule="nonzero" fill="#bebebe"/>
+<path style="block-progression:tb;color:#bebebe;direction:ltr;text-indent:0;text-align:start;enable-background:new;text-transform:none;" d="m195.03,751,0,1c-0.00091,0.0111,0.00059,0.021-0.00009,0.0312-0.0112,0.25496-0.12835,0.50994-0.31251,0.6875l-5.7188,6.2977-5.7188-6.2977c-0.18821-0.1881-0.28121-0.45346-0.28122-0.71875v-1h1c0.26531,0.00007,0.53059,0.0931,0.71873,0.28131l4.2812,4.829,4.2813-4.829c0.19464-0.21073,0.46925-0.30315,0.74998-0.2813z" fill-rule="nonzero" fill="#666"/>
 </g>
 </g>
 </svg>
 </svg>

+ 2 - 2
p/themes/Screwdriver/icons/icon.svg → p/themes/Pafat/icons/icon.svg

@@ -1,7 +1,7 @@
 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
 	<title>Logo FreshRSS</title>
 	<title>Logo FreshRSS</title>
-	<circle fill="#0062BE" cx="128" cy="128" r="33"/>
-	<g fill="none" stroke="#0062BE" stroke-width="24">
+	<circle fill="#C5C6CA" cx="128" cy="128" r="33"/>
+	<g fill="none" stroke="#C5C6CA" stroke-width="24">
 		<g stroke-opacity="0.3">
 		<g stroke-opacity="0.3">
 			<path d="M12,128 A116,116 0 1,1 128,244"/>
 			<path d="M12,128 A116,116 0 1,1 128,244"/>
 			<path d="M54,128 A74,74 0 1,1 128,202"/>
 			<path d="M54,128 A74,74 0 1,1 128,202"/>

Dosya farkı çok büyük olduğundan ihmal edildi
+ 4 - 0
p/themes/Pafat/icons/link.svg


+ 2 - 2
p/themes/Screwdriver/icons/login.svg → p/themes/Pafat/icons/login.svg

@@ -1,6 +1,6 @@
 <svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
 <svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
-<g transform="translate(-181.0002,-237)" fill="#bebebe">
-<path style="color:#bebebe;" d="m184,244c-0.554,0-1,0.446-1,1v0.53125,5.4688h12v-5.4688-0.53c0-0.554-0.446-1-1-1h-10z" fill-rule="nonzero"/>
+<g transform="translate(-181.0002,-237)" fill="#666">
+<path style="color:#666;" d="m184,244c-0.554,0-1,0.446-1,1v0.53125,5.4688h12v-5.4688-0.53c0-0.554-0.446-1-1-1h-10z" fill-rule="nonzero"/>
 <path style="baseline-shift:baseline;block-progression:tb;color:#bebebe;direction:ltr;text-indent:0;text-align:start;enable-background:accumulate;text-transform:none;" d="m188,238c-1.6447,0-3,1.3553-3,3v7c0,1.6447,1.3553,3,3,3h2c1.6447,0,3-1.3553,3-3v-7c0-1.6447-1.3553-3-3-3h-2zm0,2,2,0c0.5713,0,1,0.4287,1,1v7c0,0.5713-0.4287,1-1,1h-2c-0.5713,0-1-0.4287-1-1v-7c0-0.5713,0.4287-1,1-1z"/>
 <path style="baseline-shift:baseline;block-progression:tb;color:#bebebe;direction:ltr;text-indent:0;text-align:start;enable-background:accumulate;text-transform:none;" d="m188,238c-1.6447,0-3,1.3553-3,3v7c0,1.6447,1.3553,3,3,3h2c1.6447,0,3-1.3553,3-3v-7c0-1.6447-1.3553-3-3-3h-2zm0,2,2,0c0.5713,0,1,0.4287,1,1v7c0,0.5713-0.4287,1-1,1h-2c-0.5713,0-1-0.4287-1-1v-7c0-0.5713,0.4287-1,1-1z"/>
 </g>
 </g>
 </svg>
 </svg>

+ 2 - 2
p/themes/Screwdriver/icons/logout.svg → p/themes/Pafat/icons/logout.svg

@@ -1,6 +1,6 @@
 <svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
 <svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
-<g transform="translate(-201.0002,-237)" fill="#bebebe">
-<path style="color:#bebebe;" d="m204,246c-0.554,0-1,0.446-1,1v0.53125,5.4688h12v-5.4688-0.53c0-0.554-0.446-1-1-1h-10z" fill-rule="nonzero"/>
+<g transform="translate(-201.0002,-237)" fill="#666">
+<path style="color:#666;" d="m204,246c-0.554,0-1,0.446-1,1v0.53125,5.4688h12v-5.4688-0.53c0-0.554-0.446-1-1-1h-10z" fill-rule="nonzero"/>
 <path style="baseline-shift:baseline;block-progression:tb;color:#bebebe;direction:ltr;text-indent:0;text-align:start;enable-background:accumulate;text-transform:none;" d="m208,237c-1.6447,0-3,1.3553-3,3v3h2v-3c0-0.57129,0.42873-1,1-1h2c0.57127,0,1,0.42871,1,1v7h2v-7c0-1.6447-1.3553-3-3-3h-2z"/>
 <path style="baseline-shift:baseline;block-progression:tb;color:#bebebe;direction:ltr;text-indent:0;text-align:start;enable-background:accumulate;text-transform:none;" d="m208,237c-1.6447,0-3,1.3553-3,3v3h2v-3c0-0.57129,0.42873-1,1-1h2c0.57127,0,1,0.42871,1,1v7h2v-7c0-1.6447-1.3553-3-3-3h-2z"/>
 </g>
 </g>
 </svg>
 </svg>

+ 1 - 1
p/themes/Screwdriver/icons/next.svg → p/themes/Pafat/icons/next.svg

@@ -1,5 +1,5 @@
 <svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
 <svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
 <g transform="translate(-121.0002,-747)">
 <g transform="translate(-121.0002,-747)">
-<path style="block-progression:tb;color:#bebebe;direction:ltr;text-indent:0;text-align:start;enable-background:new;text-transform:none;" d="m125,749,1,0c0.0104-0.00012,0.0208-0.00046,0.0313,0,0.25495,0.0112,0.50987,0.12858,0.6875,0.3125l6.2977,5.7188-6.2977,5.7188c-0.18816,0.18819-0.45346,0.28125-0.71875,0.28125h-1v-1c0-0.26529,0.0931-0.53058,0.28125-0.71875l4.829-4.2812-4.829-4.2812c-0.21074-0.19463-0.30316-0.46925-0.28125-0.75z" fill-rule="nonzero" fill="#bebebe"/>
+<path style="block-progression:tb;color:#bebebe;direction:ltr;text-indent:0;text-align:start;enable-background:new;text-transform:none;" d="m125,749,1,0c0.0104-0.00012,0.0208-0.00046,0.0313,0,0.25495,0.0112,0.50987,0.12858,0.6875,0.3125l6.2977,5.7188-6.2977,5.7188c-0.18816,0.18819-0.45346,0.28125-0.71875,0.28125h-1v-1c0-0.26529,0.0931-0.53058,0.28125-0.71875l4.829-4.2812-4.829-4.2812c-0.21074-0.19463-0.30316-0.46925-0.28125-0.75z" fill-rule="nonzero" fill="#666"/>
 </g>
 </g>
 </svg>
 </svg>

Dosya farkı çok büyük olduğundan ihmal edildi
+ 2 - 0
p/themes/Pafat/icons/non-starred.svg


+ 5 - 0
p/themes/Pafat/icons/prev.svg

@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
+<g transform="translate(-301.0002,-747)">
+<path style="block-progression:tb;color:#666;direction:ltr;text-indent:0;text-align:start;enable-background:new;text-transform:none;" d="m313.01,749-1,0c-0.0104-0.00012-0.0208-0.00046-0.0313,0-0.25495,0.0112-0.50987,0.12858-0.6875,0.3125l-6.2977,5.7188,6.2977,5.7188c0.18816,0.18819,0.45346,0.28125,0.71875,0.28125h1v-1c0-0.26529-0.0931-0.53058-0.28125-0.71875l-4.829-4.2812,4.829-4.2812c0.21074-0.19463,0.30316-0.46925,0.28125-0.75z" fill-rule="nonzero" fill="#666"/>
+</g>
+</svg>

+ 5 - 0
p/themes/Pafat/icons/read.svg

@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="16.001" width="16">
+<g transform="translate(-60.99995,-296.9989)">
+<path opacity="1" style="baseline-shift:baseline;block-progression:tb;color:#000000;direction:ltr;text-indent:0;text-align:start;enable-background:accumulate;text-transform:none;" fill="#666" d="m68.875,297a1.0001,1.0001,0,0,0,-0.5,0.25l-4.9062,4a1.0001,1.0001,0,0,0,-0.0625,0.0312s-0.32587,0.29728-0.65625,0.75c-0.22334,0.30605-0.3527,0.8316-0.5,1.3125a1.0001,1.0001,0,0,0,-0.03125,0.0312,1.0001,1.0001,0,0,0,-0.21875,0.5625c-0.00051,0.0118,0.00036,0.0195,0,0.0312a1.0001,1.0001,0,0,0,0,0.0312,1.0001,1.0001,0,0,0,0,0.15625v7.8438a1.0001,1.0001,0,0,0,1,1h12a1.0001,1.0001,0,0,0,1,-1v-7.8438a1.0001,1.0001,0,0,0,0,-0.15625,1.0001,1.0001,0,0,0,-0.21875,-0.65625,1.0001,1.0001,0,0,0,-0.03125,-0.0312c-0.32774-1.1879-1.125-2-1.125-2a1.0001,1.0001,0,0,0,-0.0312,-0.0312l-4.969-4.02a1.0001,1.0001,0,0,0,-0.65625,-0.25,1.0001,1.0001,0,0,0,-0.0937,0zm0.125,2.2812,4.3125,3.5312,0.0312,0.0312c0.021,0.0255,0.18032,0.24952,0.34375,0.5l-4.6874,3.5312-4.6875-3.5312c0.0259-0.0394,0.0349-0.0872,0.0625-0.125,0.1908-0.26146,0.31874-0.41421,0.34375-0.4375l0.03125-0.0312,4.25-3.4688zm-5,5.0938,4.6875,3.5312,0.3125,0.21875,0.3125-0.21875,4.6875-3.5312,0,6.625-10,0,0-6.625z"/>
+</g>
+</svg>

+ 1 - 1
p/themes/Screwdriver/icons/share.svg → p/themes/Pafat/icons/share.svg

@@ -1,5 +1,5 @@
 <svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
 <svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
-<g fill="#bebebe" transform="translate(-581.0002,-196)">
+<g fill="#666" transform="translate(-581.0002,-196)">
 <path style="enable-background:new;color:#000000;" d="m291,178.03c0,1.0873-0.88144,1.9688-1.9688,1.9688-1.0873,0-1.9688-0.88144-1.9688-1.9688,0-1.0873,0.88144-1.9688,1.9688-1.9688,1.0873,0,1.9688,0.88144,1.9688,1.9688z" fill-rule="nonzero" transform="matrix(1.5079365,0,0,1.5079365,148.15963,-64.49107)"/>
 <path style="enable-background:new;color:#000000;" d="m291,178.03c0,1.0873-0.88144,1.9688-1.9688,1.9688-1.0873,0-1.9688-0.88144-1.9688-1.9688,0-1.0873,0.88144-1.9688,1.9688-1.9688,1.0873,0,1.9688,0.88144,1.9688,1.9688z" fill-rule="nonzero" transform="matrix(1.5079365,0,0,1.5079365,148.15963,-64.49107)"/>
 <path style="enable-background:new;color:#000000;" d="m291,178.03c0,1.0873-0.88144,1.9688-1.9688,1.9688-1.0873,0-1.9688-0.88144-1.9688-1.9688,0-1.0873,0.88144-1.9688,1.9688-1.9688,1.0873,0,1.9688,0.88144,1.9688,1.9688z" fill-rule="nonzero" transform="matrix(1.5079365,0,0,1.5079365,158.12818,-59.49107)"/>
 <path style="enable-background:new;color:#000000;" d="m291,178.03c0,1.0873-0.88144,1.9688-1.9688,1.9688-1.0873,0-1.9688-0.88144-1.9688-1.9688,0-1.0873,0.88144-1.9688,1.9688-1.9688,1.0873,0,1.9688,0.88144,1.9688,1.9688z" fill-rule="nonzero" transform="matrix(1.5079365,0,0,1.5079365,158.12818,-59.49107)"/>
 <path style="enable-background:new;color:#000000;" d="m291,178.03c0,1.0873-0.88144,1.9688-1.9688,1.9688-1.0873,0-1.9688-0.88144-1.9688-1.9688,0-1.0873,0.88144-1.9688,1.9688-1.9688,1.0873,0,1.9688,0.88144,1.9688,1.9688z" fill-rule="nonzero" transform="matrix(1.5079365,0,0,1.5079365,158.12818,-69.49107)"/>
 <path style="enable-background:new;color:#000000;" d="m291,178.03c0,1.0873-0.88144,1.9688-1.9688,1.9688-1.0873,0-1.9688-0.88144-1.9688-1.9688,0-1.0873,0.88144-1.9688,1.9688-1.9688,1.0873,0,1.9688,0.88144,1.9688,1.9688z" fill-rule="nonzero" transform="matrix(1.5079365,0,0,1.5079365,158.12818,-69.49107)"/>

+ 5 - 0
p/themes/Pafat/icons/starred.svg

@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
+<g transform="translate(-41.000202,-397)">
+<path style="enable-background:accumulate;color:#000000;" d="m530.95,186.71c-0.77941,0.55189-3.1576-1.906-4.1125-1.9179-0.95532-0.0119-3.3949,2.3858-4.161,1.8149-0.76573-0.57072,0.83698-3.592,0.55319-4.5039-0.2839-0.91223-3.3182-2.4915-3.0119-3.3965,0.30617-0.90461,3.6749-0.31399,4.4544-0.86567,0.77986-0.5519,1.3442-3.9257,2.2995-3.914,0.95494,0.0116,1.4342,3.398,2.1998,3.9689,0.76588,0.57114,4.1489,0.0653,4.4331,0.97746,0.28402,0.9118-2.7885,2.414-3.0949,3.3186-0.30652,0.90489,1.22,3.966,0.44027,4.5182z" fill-rule="nonzero" transform="matrix(1.0472113,-0.00871584,0.00871584,1.0472113,-504.35434,220.15425)" fill="#666"/>
+</g>
+</svg>

+ 1 - 1
p/themes/Screwdriver/icons/tag.svg → p/themes/Pafat/icons/tag.svg

@@ -1,5 +1,5 @@
 <svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
 <svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
 <g transform="translate(-141.0002,-807)">
 <g transform="translate(-141.0002,-807)">
-<path d="m149,809,0,13,4-4,4,4c0.0525-6.8494-0.0285-10.584,0-13z" fill="#bebebe"/>
+<path d="m149,809,0,13,4-4,4,4c0.0525-6.8494-0.0285-10.584,0-13z" fill="#666"/>
 </g>
 </g>
 </svg>
 </svg>

+ 6 - 0
p/themes/Pafat/icons/unread.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
+<g transform="translate(-40.99995,-297)" fill="#666">
+<path style="block-progression:tb;color:#000000;direction:ltr;text-indent:0;text-align:start;enable-background:accumulate;text-transform:none;" d="m43.781,301a1.0001,1.0001,0,0,0,-0.40625,1.7812l5,4,0.625,0.5,0.625-0.5,5-4a1.0005,1.0005,0,1,0,-1.25,-1.5625l-4.375,3.5-4.375-3.5a1.0001,1.0001,0,0,0,-0.844,-0.22z"/>
+<path style="block-progression:tb;color:#000000;direction:ltr;text-indent:0;text-align:start;enable-background:accumulate;text-transform:none;" d="M42.906,300a1.0001,1.0001,0,0,0,-0.906,1v9a1.0001,1.0001,0,0,0,1,1h12a1.0001,1.0001,0,0,0,1,-1v-9a1.0001,1.0001,0,0,0,-1,-1h-12a1.0001,1.0001,0,0,0,-0.09375,0zm1.094,2h10v7h-10v-7z"/>
+</g>
+</svg>

+ 5 - 0
p/themes/Pafat/icons/up.svg

@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
+<g transform="translate(-201.0002,-747)">
+<path style="block-progression:tb;color:#666;direction:ltr;text-indent:0;text-align:start;enable-background:new;text-transform:none;" d="m215.03,759,0-1c-0.00091-0.0111,0.00059-0.021-0.00009-0.0312-0.0112-0.25496-0.12835-0.50994-0.31251-0.6875l-5.7188-6.2977-5.7188,6.2977c-0.18821,0.1881-0.28121,0.45346-0.28122,0.71875v1h1c0.26531-0.00007,0.53059-0.0931,0.71873-0.28131l4.2812-4.829,4.2813,4.829c0.19464,0.21073,0.46925,0.30315,0.74998,0.2813z" fill-rule="nonzero" fill="#666"/>
+</g>
+</svg>

BIN
p/themes/Pafat/loader.gif


+ 7 - 0
p/themes/Pafat/metadata.json

@@ -0,0 +1,7 @@
+{
+  "name": "Pafat",
+  "author": "Plopoyop",
+  "description": "Un thème pour FreshRSS",
+  "version": 0.2,
+  "files": ["_template.css", "pafat.css"]
+}

+ 1084 - 0
p/themes/Pafat/pafat.css

@@ -0,0 +1,1084 @@
+@charset "UTF-8";
+
+/*=== FONTS */
+@font-face {
+	font-family: "OpenSans";
+	src: url("../fonts/openSans.woff") format("woff");
+}
+
+/*=== GENERAL */
+/*============*/
+html, body {
+	height: 100%;
+	font-family: "OpenSans", "Cantarell", "Helvetica", "Arial", sans-serif;
+	background: #fafafa;
+	color : #666;
+}
+
+/*=== Links */
+a {
+	color: #2980b9;
+	outline: none;
+}
+
+/*=== Forms */
+legend {
+	margin: 20px 0 5px;
+	padding: 5px 0;
+	border-bottom: 1px solid #ddd;
+	font-size: 1.4em;
+}
+label {
+	min-height: 25px;
+	padding: 5px 0;
+	cursor: pointer;
+}
+textarea {
+	width: 360px;
+	height: 100px;
+}
+input, select, textarea {
+	min-height: 25px;
+	padding: 1px;
+	background: #fdfdfd;
+	border: 1px solid #bbb;
+	border-radius: 3px;
+	color: #666;
+	line-height: 21px;
+	vertical-align: middle;
+}
+
+select{
+	height:29px;
+}
+option {
+	padding: 0 .5em;
+}
+input:focus, select:focus, textarea:focus {
+	 outline-color: #aaa;
+}
+
+input:invalid, select:invalid {
+	border-color: #f00;
+	box-shadow: 0 0 2px 2px #fdd inset;
+	 outline-color: #fdd;
+}
+input:disabled, select:disabled {
+	background: #eee;
+}
+input.extend {
+	transition: width 200ms linear;
+	-moz-transition: width 200ms linear;
+	-webkit-transition: width 200ms linear;
+	-o-transition: width 200ms linear;
+	-ms-transition: width 200ms linear;
+}
+
+/*=== Tables */
+table {
+	border-collapse: collapse;
+}
+
+tr, th, td {
+	padding: 0.5em;
+	border: 1px solid #ddd;
+}
+th {
+	background: #f6f6f6;
+}
+form td,
+form th {
+	font-weight: normal;
+	text-align: center;
+}
+
+/*=== COMPONENTS */
+/*===============*/
+/*=== Forms */
+.form-group.form-actions {
+	padding: 5px 0;
+	background: #f4f4f4;
+	border-top: 1px solid #ddd;
+}
+.form-group.form-actions .btn {
+	margin: 0 10px;
+}
+.form-group .group-name {
+	padding: 10px 0;
+	text-align: right;
+}
+.form-group .group-controls {
+	min-height: 25px;
+	padding: 5px 0;
+	margin : 10px 0 10px 220px;
+
+}
+.form-group table {
+	margin: 10px 0 0 220px;
+}
+
+/*=== Buttons */
+.stick {
+	vertical-align: middle;
+	font-size: 0;
+	min-width: 215px;
+}
+.stick input,
+.stick .btn {
+	border-radius: 0;
+}
+.stick .btn:first-child,
+.stick input:first-child {
+	border-radius: 3px 0 0 3px;
+}
+.stick .btn-important:first-child {
+	width:176px;
+}
+.stick .btn:last-child,
+.stick input:last-child {
+	border-radius: 0 3px 3px 0;
+}
+.stick .btn + .btn,
+.stick .btn + input,
+.stick .btn + .dropdown > .btn,
+.stick input + .btn,
+.stick input + input,
+.stick input + .dropdown > .btn,
+.stick .dropdown + .btn,
+.stick .dropdown + input,
+.stick .dropdown + .dropdown > .btn {
+	border-left: none;
+
+}	
+	
+.stick .btn + .dropdown > .btn {
+	border-left: none;
+	border-radius: 0 3px 3px 0;
+}
+
+.btn {
+	display: inline-block;
+	min-height: 29px;
+	min-width: 15px;
+	margin: 0;
+	padding: 1px 5px;
+	background: #fff;
+	border-radius: 3px;
+	border: 1px solid #aaa;
+	color: #666;
+	font-size: 0.9rem;
+	vertical-align: middle;
+	cursor: pointer;
+	overflow: hidden;
+}
+
+a.btn {
+	min-height: 25px;
+	line-height: 25px;
+}
+
+
+a.btn {
+	min-height: 25px;
+	line-height: 25px;
+}
+
+.read_all.btn {
+	height:29px;
+}
+
+.btn:hover {
+	background: #f0f0f0;
+	text-decoration: none;
+}
+
+
+.category.stick .btn {
+	background:#5bc0de;
+	color : #FFF;
+	border-color :#5bc0de;
+}
+
+.category.stick .btn:first-child:hover, .category.stick .btn:last-child:hover, .category.stick .btn.active:first-child, .category.stick.active .btn:last-child {
+	background:#39b3d7;
+	border-color : #39b3d7;
+}
+
+
+.btn.active,
+.btn:active,
+.dropdown-target:target ~ .btn.dropdown-toggle {
+	background: #eee;
+}
+
+.category.all > .btn  {
+	background: #428bca;
+	color : #FFF;
+	border-color : #428bca;
+}
+
+.category.all > .btn:hover  {
+	background: #3276b1;
+	border-color : #3276b1;
+}
+
+.category.favorites > .btn {
+	background:#f0ad4e;
+	border-color: #f0ad4e;
+	color : #fff;
+}
+
+.category.favorites > .btn:hover {
+	background: #ed9c28;
+	border-color : #ed9c28;
+	color : white;
+}
+
+.btn-important {
+	background: #5cb85c;
+	color: #fff;
+	border-color: #5cb85c;
+	font-weight: normal;
+}
+.btn-important:hover, .btn-important:active {
+	background:#47a447;
+	border-color : #47a447;
+	box-shadow: none;
+}
+
+.btn-attention {
+	background: #d9534f;
+	color: #fff;
+	border: 1px solid #d9534f;
+	outline-color : #aaa;
+}
+.btn-attention:hover {
+	background: #d2322d;
+	border-color : #d2322d;
+}
+.btn-attention:active {
+	background: #d2322d;
+	box-shadow: none;
+}
+
+/*=== Navigation */
+.nav-list .nav-header,
+.nav-list .item {
+	height: 2.5em;
+	line-height: 2.5em;
+	font-size: 0.9rem;
+}
+.nav-list .item:hover {
+	background: #fafafa;
+}
+.nav-list .item:hover a {
+	color: #003388;
+}
+.nav-list .item.active {
+	background: #3498DB;
+	color: #fff;
+}
+.nav-list .item.active a {
+	color: #fff;
+}
+.nav-list .disable {
+	color: #aaa;
+	background: #fafafa;
+	text-align: center;
+}
+.nav-list .item > a {
+	padding: 0 10px;
+}
+.nav-list a:hover {
+	text-decoration: none;
+}
+.nav-list .item.empty a {
+	color: #f39c12;
+}
+.nav-list .item.active.empty a {
+	color: #fff;
+	background: #f39c12;
+}
+.nav-list .item.error a {
+	color: #BD362F;
+}
+.nav-list .item.active.error a {
+	color: #fff;
+	background: #BD362F;
+}
+
+.nav-list .nav-header {
+	padding: 0 10px;
+	color: #888;
+	background: #f4f4f4;
+	border-bottom: 1px solid #ddd;
+	font-weight: bold;
+}
+
+.nav-list .nav-form {
+	padding: 3px;
+	text-align: center;
+}
+
+.nav-head {
+	margin: 0;
+	background: #fff;
+	background: linear-gradient(to bottom, #fff, #f0f0f0);
+	background: -moz-linear-gradient(top, #fff 0%, #f0f0f0 100%);
+	background: -webkit-linear-gradient(top, #fff 0%, #f0f0f0 100%);
+	background: -o-linear-gradient(top, #fff 0%, #f0f0f0 100%);
+	background: -ms-linear-gradient(top, #fff 0%, #f0f0f0 100%);
+	border-bottom: 1px solid #ddd;
+	text-align: right;
+}
+.nav-head .item {
+	padding: 5px 10px;
+	font-size: 0.9rem;
+	line-height: 1.5rem;
+}
+
+/*=== Horizontal-list */
+.horizontal-list {
+	margin: 0;
+	padding: 0;
+}
+.horizontal-list .item {
+	vertical-align: middle;
+}
+
+/*=== Dropdown */
+.dropdown-menu {
+	margin: 5px 0 0;
+	padding: 5px 0;
+	border: 1px solid #aaa;
+	border-radius: 5px;
+	font-size: 0.8rem;
+	text-align: left;
+}
+.dropdown-menu:after {
+	content: "";
+	position: absolute;
+	top: -6px;
+	right: 13px;
+	width: 10px;
+	height: 10px;
+	background: #fff;
+	border-top: 1px solid #aaa;
+	border-left: 1px solid #aaa;
+	z-index: -10;
+	transform: rotate(45deg);
+	-moz-transform: rotate(45deg);
+	-webkit-transform: rotate(45deg);
+	-ms-transform: rotate(45deg);
+}
+.dropdown-header {
+	padding: 0 5px 5px;
+	color: #888;
+	font-weight: bold;
+	text-align: left;
+}
+.dropdown-menu > .item {
+}
+
+.dropdown-menu > .item > a {
+	padding: 0 22px;
+	line-height: 2.5em;
+	color: #666;
+	font-size: 0.8rem;
+}
+
+.dropdown-menu > .item > span,
+.dropdown-menu > .item > .as-link {
+	padding: 0 22px;
+	line-height: 2em;
+	font-size: 0.8rem;
+}
+
+.dropdown-menu > .item:hover {
+	background: #eee;
+	color: #666;
+}
+.dropdown-menu > .item[aria-checked="true"] > a:before {
+	font-weight: bold;
+	margin: 0 0 0 -14px;
+}
+.dropdown-menu > .item:hover > a {
+	color: #666;
+	text-decoration: none;
+}
+.dropdown-menu .input select,
+.dropdown-menu .input input {
+	margin: 0 auto 5px;
+	padding: 2px 5px;
+	border-radius: 3px;
+}
+
+.separator {
+	margin: 5px 0;
+	border-bottom: 1px solid #ddd;
+}
+
+/*=== Alerts */
+.alert {
+	margin: 15px auto;
+	padding: 10px 15px;
+	background: #f4f4f4;
+	border: 1px solid #ccc;
+	border-right: 1px solid #aaa;
+	border-bottom: 1px solid #aaa;
+	border-radius: 5px;
+	color: #aaa;
+	font-size: 0.9em;
+}
+.alert-head {
+	font-size: 1.15em;
+}
+.alert > a {
+	color: inherit;
+	text-decoration: underline;
+}
+.alert-warn {
+	background: #ffe;
+	border: 1px solid #eeb;
+	color: #c95;
+}
+.alert-success {
+	background: #dfd;
+	border: 1px solid #cec;
+	color: #484;
+}
+.alert-error {
+	background: #fdd;
+	border: 1px solid #ecc;
+	color: #844;
+}
+
+/*=== Pagination */
+.pagination {
+	background: #fff;
+	text-align: center;
+	color: #41444f;
+	font-size: 0.8em;
+}
+.content .pagination {
+	margin: 0;
+	padding: 0;
+}
+.pagination .item.pager-current {
+	font-weight: bold;
+	font-size: 1.5em;
+}
+.pagination .item a {
+	display: block;
+	color: #41444f;
+	font-style: italic;
+	line-height: 3em;
+	text-decoration: none;
+}
+.pagination .item a:hover {
+	background: #ddd;
+}
+.pagination:first-child .item {
+	border-bottom: 1px solid #aaa;
+}
+.pagination:last-child .item {
+	border-top: 1px solid #aaa;
+}
+
+.pagination .loading,
+.pagination a:hover.loading {
+	background: url("loader.gif") center center no-repeat #fff;
+	font-size: 0;
+}
+
+/*=== STRUCTURE */
+/*===============*/
+/*=== Header */
+.header {
+	height: 85px;
+	background: #41444f;
+}
+.header > .item {
+	padding: 10px;
+	border-bottom: 1px solid #aaa;
+	vertical-align: middle;
+	text-align: center;
+}
+.header > .item.title{
+	width: 230px;
+}
+.header > .item.title h1 {
+	margin: 0.5em 0;
+}
+
+.header > .item.title h1 a, a.signin {
+	text-decoration: none;
+	color : #C5C6CA;
+}
+ 
+.header > .item.search input {
+	width: 230px;
+	height : 29px;
+	-moz-box-sizing: border-box;
+	-webkit-box-sizing: border-box;
+	box-sizing: border-box;
+}
+
+.header > .item.search button {
+	-moz-box-sizing: border-box;
+	-webkit-box-sizing: border-box;
+	box-sizing: border-box;
+	height : 29px;
+}
+
+.header .item.search input:focus {
+	width: 350px;
+}
+
+/*=== Body */
+#global {
+	height: calc(100% - 85px);
+}
+.aside {
+	border-right: 1px solid #aaa;
+	background: #fff;
+}
+.aside.aside_flux {
+	padding: 10px 0 50px;
+}
+
+/*=== Aside main page (categories) */
+.categories {
+	text-align: center;
+}
+.category {
+	width: 215px;
+	margin: 10px auto;
+	text-align: left;
+}
+.category .btn:first-child {
+	position: relative;
+	width: 203px;
+}
+.category.stick .btn:first-child {
+	width: 176px;
+}
+.category .btn:first-child:not([data-unread="0"]):after {
+	position: absolute;
+	top: 2px; right: 3px;
+	padding: 0px 3px;
+	border: 1px solid ;
+	border-radius: 3px;
+	font-size:10pt;
+	line-height : 20px;
+}
+
+/*=== Aside main page (feeds) */
+.categories .feeds .item.active {
+	background: #5cb85c;
+}
+.categories .feeds .item.active .feed {
+	color: #fff;
+}
+.categories .feeds .item.empty .feed {
+	color: #e67e22;
+}
+.categories .feeds .item.empty.active {
+	background: #e67e22;
+}
+.categories .feeds .item.empty.active .feed {
+	color: #fff;
+}
+.categories .feeds .item.error .feed {
+	color: #BD362F;
+}
+.categories .feeds .item .feed {
+	margin: 0;
+	width: 165px;
+	line-height: 3em;
+	font-size: 0.8em;
+	text-align: left;
+	text-decoration: none;
+}
+.categories .feeds .feed:not([data-unread="0"]) {
+	font-weight: bold;
+}
+.categories .feeds .dropdown-menu:after {
+	left: 2px;
+}
+.categories .feeds .item .dropdown-target:target ~ .dropdown-toggle > .icon,
+.categories .feeds .item:hover .dropdown-toggle > .icon,
+.categories .feeds .item.active .dropdown-toggle > .icon {
+	background-color: #fff;
+	border-radius: 3px;
+	vertical-align: middle;
+}
+
+/*=== Configuration pages */
+.post {
+	padding: 10px 50px;
+	font-size: 0.9em;
+}
+.post form {
+	margin: 10px 0;
+}
+.post.content {
+	max-width: 550px;
+}
+
+/*=== Prompt (centered) */
+.prompt {
+	text-align: center;
+}
+.prompt label {
+	text-align: left;
+}
+.prompt form {
+	margin: 10px auto 20px auto;
+	width: 200px;
+}
+.prompt input {
+	margin: 5px auto;
+	width: 100%;
+}
+.prompt p {
+	margin: 20px 0;
+}
+
+/*=== New article notification */
+#new-article {
+	background: #428bca;
+	text-align: center;
+	font-size: 0.9em;
+}
+#new-article:hover {
+	background: #3276b1;
+}
+#new-article > a {
+	line-height: 3em;
+	color: #fff;
+	font-weight: bold;
+}
+#new-article > a:hover {
+	text-decoration: none;
+}
+
+/*=== Day indication */
+.day {
+	padding: 0 10px;
+	font-weight: bold;
+	line-height: 3em;
+	background: #fff;
+	border-top: 1px solid #aaa;
+	border-bottom: 1px solid #aaa;
+	color : #666;
+}
+#new-article + .day {
+	border-top: none;
+}
+.day .name {
+	padding: 0 10px 0 0;
+	color : #666;
+	font-size: 1.8em;
+	opacity: 0.3;
+	font-style: italic;
+	text-align: right;
+}
+
+/*=== Index menu */
+.nav_menu {
+	background: #fafafa;
+	border-bottom: 1px solid #aaa;
+	text-align: center;
+	padding: 5px 0;
+}
+
+/*=== Feed articles */
+.flux {
+	border-left: 3px solid #5cb85c;
+	background: #fafafa;
+}
+.flux:hover {
+	background: #fff;
+}
+.flux.current {
+	border-left: 3px solid #39b3d7;
+}
+.flux.not_read {
+	border-left: 3px solid #d9534f;
+}
+.flux .item.title a, .flux.not_read:not(.current):hover .item.title {
+	color : #333;
+}
+.flux.favorite {
+	border-left: 2px solid #428bca;
+	background: #FFF6DA;
+}
+.flux.favorite:not(.current):hover .item.title {
+	background: #FFF6DA;
+}
+.flux.current {
+	background: #fff;
+}
+
+
+.flux_header {
+	border-top: 1px solid #ddd;
+	font-size: 0.8rem;
+	cursor: pointer;
+}
+.flux_header .title {
+	font-size: 0.9rem;
+}
+.flux .website .favicon {
+	padding: 5px;
+}
+.flux .date {
+	color: #666;
+	font-size: 0.7rem;
+}
+
+.flux .bottom {
+	font-size: 0.8rem;
+	text-align: center;
+}
+
+/*=== Content of feed articles */
+.content {
+	padding: 20px 10px;
+}
+.content > h1.title > a {
+	color: #333;
+}
+
+.content hr {
+	margin: 30px 10px;
+	height: 1px;
+	background: #ddd;
+	border: 0;
+	box-shadow: 0 2px 5px #ccc;
+}
+
+.content pre {
+	margin: 10px auto;
+	padding: 10px 20px;
+	overflow: auto;
+	background: #222;
+	color: #fff;
+	font-size: 0.9rem;
+	border-radius: 3px;
+}
+.content code {
+	padding: 2px 5px;
+	color: #dd1144;
+	background: #fafafa;
+	border: 1px solid #eee;
+	border-radius: 3px;
+}
+.content pre code {
+	background: transparent;
+	color: #fff;
+	border: none;
+}
+
+.content blockquote {
+	display: block;
+	margin: 0;
+	padding: 5px 20px;
+	border-top: 1px solid #ddd;
+	border-bottom: 1px solid #ddd;
+	background: #fafafa;
+	color: #41444f;
+}
+.content blockquote p {
+	margin: 0;
+}
+
+/*=== Notification and actualize notification */
+.notification {
+	padding: 0 0 0 5px;
+	text-align: center;
+	border: 1px solid #eeb;
+	border-radius: 3px;
+	box-shadow: 0 0 5px #ddd;
+	font-weight: bold;
+	font-size: 0.9em;
+	line-height: 3em;
+	z-index: 10;
+	vertical-align: middle;
+}
+.notification.good {
+	background: #ffe;
+	border: 1px solid #eeb;
+	color: #c95;
+}
+.notification.bad {
+	background: #fdd;
+	border: 1px solid #ecc;
+	color: #844;
+}
+.notification a.close {
+	padding: 0 15px;
+	line-height: 3em;
+}
+.notification.good a.close:hover {
+	background: #eeb;
+}
+.notification.bad a.close:hover {
+	background: #ecc;
+}
+
+.notification#actualizeProgress {
+	line-height: 2em;
+}
+
+/*=== "Load more" part */
+#bigMarkAsRead {
+	text-align: center;
+	text-decoration: none;	
+	color: #666;
+	background: #fafafa;
+}
+#bigMarkAsRead:hover {
+	color: #000;
+	background: #f0f0f0;
+}
+
+#bigMarkAsRead:hover .bigTick {
+/*	text-shadow: 0 0 10px #666;*/
+}
+
+/*=== Navigation menu (for articles) */
+#nav_entries {
+	margin: 0;
+	background: #fff;
+	border-top: 1px solid #ddd;
+	text-align: center;
+	line-height: 3em;
+	table-layout: fixed;
+}
+
+#nav_entries .item:hover {
+	background:#eee	;
+}
+/*=== READER VIEW */
+/*================*/
+#stream.reader .flux {
+	padding: 0 0 50px;
+	border: none;
+	background: #f0f0f0;
+	color: #41444f;
+}
+#stream.reader .flux .author {
+	margin: 0 0 10px;
+	font-size: 90%;
+	color: #666;
+}
+
+/*=== GLOBAL VIEW */
+/*================*/
+#stream.global .box-category {
+	background: #fff;
+	border:none;
+	text-align: left;
+}
+
+#stream.global .category {
+	margin: 0;
+}
+
+#stream.global .category:first-child {
+	margin: 0;
+}
+
+
+#stream.global .btn {
+	width: auto;
+	height: 2em;
+	margin: 0;
+	padding: 0 10px;
+	background: #f6f6f6;
+	border-bottom: 1px solid #aaa;
+	border-radius: 5px 5px 0 0;
+	line-height: 2em;
+	font-size: 1.2rem;
+}
+
+#stream.global .btn:not([data-unread="0"]) {
+	background: #5bc0de;
+	border-color : #5bc0de;
+	color: #fff;
+	font-weight: bold;
+	text-shadow: none;
+
+}
+
+
+#stream.global .btn:first-child:not([data-unread="0"]):after {
+	top: 0; right: 5px;
+	border: 0;
+	background: none;
+	color: #fff;
+	font-weight: bold;
+	box-shadow: none;
+	text-shadow: none;
+}
+
+#stream.global .box-category .feeds {
+	max-height: 250px;
+	width: 302px;
+	border : solid #aaa 1px;
+	border-top : none;
+}
+
+#stream.global .box-category .feeds .item {
+	padding: 2px 10px;
+	font-size: 0.9rem;
+}
+
+/*=== DIVERS */
+/*===========*/
+.aside.aside_feed .nav-form input,
+.aside.aside_feed .nav-form select {
+	width: 140px;
+}
+.aside.aside_feed .nav-form .dropdown .dropdown-menu {
+	right: -20px;
+}
+.aside.aside_feed .nav-form .dropdown .dropdown-menu:after {
+	right: 33px;
+}
+
+/*=== STATISTICS */
+/*===============*/
+.stat {
+	margin: 10px 0 20px;
+}
+
+.stat th,
+.stat td,
+.stat tr {
+	border: none;
+}
+.stat > table td,
+.stat > table th {
+	border-bottom: 1px solid #ddd;
+	text-align: center;
+}
+.stat > .horizontal-list {
+	margin: 0 0 5px;
+}
+.stat > .horizontal-list .item {
+	overflow: hidden;
+	white-space: nowrap;
+	text-overflow: ellipsis;
+}
+.stat > .horizontal-list .item:first-child {
+	width: 250px;
+}
+
+/*=== LOGS */
+/*=========*/
+.logs {
+	border: 1px solid #aaa;
+	border-radius: 5px;
+	overflow: hidden;
+}
+.log {
+	padding: 5px 10px;
+	background: #fafafa;
+	color: #41444f;
+	font-size: 0.8rem;
+}
+.log+.log {
+	border-top: 1px solid #aaa;
+}
+.log .date {
+	display: block;
+	font-weight: bold;
+}
+.log.error {
+	background: #fdd;
+	color: #844;
+}
+.log.warning {
+	background: #ffe;
+	color: #c95;
+}
+.log.notice {
+	background: #f4f4f4;
+	color: #aaa;
+}
+.log.debug {
+	background: #41444f;
+	color: #eee;
+}
+
+/*=== MOBILE */
+/*===========*/
+@media(max-width: 840px) {
+	.aside {
+		box-shadow: 3px 0 3px #aaa;
+		transition: width 200ms linear;
+		-moz-transition: width 200ms linear;
+		-webkit-transition: width 200ms linear;
+		-o-transition: width 200ms linear;
+		-ms-transition: width 200ms linear;
+	}
+	.aside .toggle_aside,
+	#panel .close {
+		position: absolute;
+		display: block;
+		top: 0; right: 0;
+		width: 30px;
+		height: 30px;
+		line-height: 30px;
+		text-align: center;
+		background: #f6f6f6;
+		border-left: 1px solid #ddd;
+		border-bottom: 1px solid #ddd;
+		border-radius: 0 0 0 5px;
+	}
+
+	.nav_menu .btn {
+		margin: 5px 10px;
+	}
+	.nav_menu .stick {
+		margin: 0 10px;
+	}
+	.nav_menu .stick .btn {
+		margin: 5px 0;
+	}
+	.nav_menu .search {
+		display: inline-block;
+		max-width: 97%;
+	}
+	.nav_menu .search input {
+		max-width: 97%;
+		width: 90px;
+	}
+	.nav_menu .search input:focus {
+		width: 400px;
+	}
+
+	.day .name {
+		font-size: 1.1rem;
+		text-shadow: none;
+	}
+
+	.pagination {
+		margin: 0 0 3.5em;
+	}
+
+	.notification a.close {
+		display: block;
+		left: 0;
+		background: transparent;
+	}
+	.notification a.close:hover {
+		opacity: 0.5;
+	}
+	.notification a.close .icon {
+		display: none;
+	}
+}

+ 0 - 5
p/themes/Screwdriver/icons/add.svg

@@ -1,5 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
-<g transform="translate(-60.0002,-726)">
-<path style="color:#666666;" fill="#666" d="m67,729,0,4-4,0,0,2,4,0,0,4,2,0,0-4,4,0,0-2-4,0,0-4-2,0z"/>
-</g>
-</svg>

+ 0 - 7
p/themes/Screwdriver/icons/all.svg

@@ -1,7 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
-<g transform="translate(-40.0002,-746)" fill="#bebebe">
-<rect style="color:#bebebe;" height="2.0002" width="9.9996" y="749" x="43"/>
-<rect style="color:#bebebe;" height="2.0002" width="9.9996" y="753" x="43"/>
-<rect style="color:#bebebe;" height="2.0002" width="9.9996" y="757" x="43"/>
-</g>
-</svg>

BIN
p/themes/Screwdriver/icons/apple-touch-icon.png


+ 0 - 6
p/themes/Screwdriver/icons/bookmark-add.svg

@@ -1,6 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
-<g transform="translate(-141.0002,-807)" fill="#bebebe">
-<path d="m143,807,0,13,4-4,4,4,0-4,0-1-2,0,0-4,2,0,0-4z"/>
-<path d="m152,810,0,2-2,0,0,2,2,0,0,2,2,0,0-2,2,0,0-2-2,0,0-2-2,0z"/>
-</g>
-</svg>

+ 5 - 60
p/themes/Screwdriver/icons/bookmark.svg

@@ -1,60 +1,5 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg
-   xmlns:dc="http://purl.org/dc/elements/1.1/"
-   xmlns:cc="http://creativecommons.org/ns#"
-   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-   xmlns:svg="http://www.w3.org/2000/svg"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   height="16"
-   width="16"
-   id="svg2"
-   version="1.1"
-   inkscape:version="0.48.4 r9939"
-   sodipodi:docname="bookmark.svg">
-  <metadata
-     id="metadata12">
-    <rdf:RDF>
-      <cc:Work
-         rdf:about="">
-        <dc:format>image/svg+xml</dc:format>
-        <dc:type
-           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
-      </cc:Work>
-    </rdf:RDF>
-  </metadata>
-  <defs
-     id="defs10" />
-  <sodipodi:namedview
-     pagecolor="#ffffff"
-     bordercolor="#666666"
-     borderopacity="1"
-     objecttolerance="10"
-     gridtolerance="10"
-     guidetolerance="10"
-     inkscape:pageopacity="0"
-     inkscape:pageshadow="2"
-     inkscape:window-width="1366"
-     inkscape:window-height="745"
-     id="namedview8"
-     showgrid="false"
-     inkscape:zoom="14.75"
-     inkscape:cx="-2.2033898"
-     inkscape:cy="8"
-     inkscape:window-x="0"
-     inkscape:window-y="0"
-     inkscape:window-maximized="1"
-     inkscape:current-layer="svg2" />
-  <g
-     transform="translate(-41.000202,-397)"
-     id="g4">
-    <path
-       style="enable-background:accumulate;color:#000000;fill:#d18104;fill-opacity:1"
-       d="m530.95,186.71c-0.77941,0.55189-3.1576-1.906-4.1125-1.9179-0.95532-0.0119-3.3949,2.3858-4.161,1.8149-0.76573-0.57072,0.83698-3.592,0.55319-4.5039-0.2839-0.91223-3.3182-2.4915-3.0119-3.3965,0.30617-0.90461,3.6749-0.31399,4.4544-0.86567,0.77986-0.5519,1.3442-3.9257,2.2995-3.914,0.95494,0.0116,1.4342,3.398,2.1998,3.9689,0.76588,0.57114,4.1489,0.0653,4.4331,0.97746,0.28402,0.9118-2.7885,2.414-3.0949,3.3186-0.30652,0.90489,1.22,3.966,0.44027,4.5182z"
-       fill-rule="nonzero"
-       transform="matrix(1.0472113,-0.00871584,0.00871584,1.0472113,-504.35434,220.15425)"
-       fill="#f1c40f"
-       id="path6" />
-  </g>
-</svg>
+<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
+<g transform="translate(-41.000202,-397)">
+<path style="color:#000000;enable-background:accumulate;" d="m530.95,186.71c-0.77941,0.55189-3.1576-1.906-4.1125-1.9179-0.95532-0.0119-3.3949,2.3858-4.161,1.8149-0.76573-0.57072,0.83698-3.592,0.55319-4.5039-0.2839-0.91223-3.3182-2.4915-3.0119-3.3965,0.30617-0.90461,3.6749-0.31399,4.4544-0.86567,0.77986-0.5519,1.3442-3.9257,2.2995-3.914,0.95494,0.0116,1.4342,3.398,2.1998,3.9689,0.76588,0.57114,4.1489,0.0653,4.4331,0.97746,0.28402,0.9118-2.7885,2.414-3.0949,3.3186-0.30652,0.90489,1.22,3.966,0.44027,4.5182z" fill-rule="nonzero" transform="matrix(1.0472113,-0.00871584,0.00871584,1.0472113,-504.35434,220.15425)" fill="#d18104"/>
+</g>
+</svg>

+ 0 - 7
p/themes/Screwdriver/icons/category-white.svg

@@ -1,7 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
-<g transform="translate(-442,-176)">
-<g transform="translate(234.0002,-820)">
-<path d="m208.53,997c-0.28913,0-0.53125,0.24212-0.53125,0.53125v13.938c0,0.2985,0.23264,0.5312,0.53125,0.5312h14.938c0.2986,0,0.53125-0.2326,0.53125-0.5312v-8.9376c0-0.2891-0.24212-0.5312-0.53125-0.5312h-12.469v7.5c0,0.277-0.223,0.5-0.5,0.5s-0.5-0.223-0.5-0.5v-8c0-0.277,0.223-0.5,0.5-0.5h2.9688,8.5312v-1.4062c0-0.3272-0.26666-0.5938-0.59375-0.5938h-7.4062v-1.4688c0-0.39-0.24-0.63-0.53-0.63z" fill="#FFF"/>
-</g>
-</g>
-</svg>

+ 0 - 7
p/themes/Screwdriver/icons/category.svg

@@ -1,7 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
-<g transform="translate(-442,-176)">
-<g transform="translate(234.0002,-820)">
-<path d="m208.53,997c-0.28913,0-0.53125,0.24212-0.53125,0.53125v13.938c0,0.2985,0.23264,0.5312,0.53125,0.5312h14.938c0.2986,0,0.53125-0.2326,0.53125-0.5312v-8.9376c0-0.2891-0.24212-0.5312-0.53125-0.5312h-12.469v7.5c0,0.277-0.223,0.5-0.5,0.5s-0.5-0.223-0.5-0.5v-8c0-0.277,0.223-0.5,0.5-0.5h2.9688,8.5312v-1.4062c0-0.3272-0.26666-0.5938-0.59375-0.5938h-7.4062v-1.4688c0-0.39-0.24-0.63-0.53-0.63z" fill="#666"/>
-</g>
-</g>
-</svg>

+ 0 - 7
p/themes/Screwdriver/icons/close.svg

@@ -1,7 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
-<g transform="translate(-60,-518)">
-<g transform="translate(19,-242)">
-<path style="block-progression:tb;color:#bebebe;direction:ltr;text-indent:0;text-align:start;enable-background:new;text-transform:none;" d="m45,764,1,0c0.01037-0.00012,0.02079-0.00046,0.03125,0,0.25495,0.0112,0.50987,0.12858,0.6875,0.3125l2.282,2.28,2.312-2.28c0.266-0.23,0.447-0.3,0.688-0.31h1v1c0,0.28647-0.03434,0.55065-0.25,0.75l-2.2812,2.2812,2.25,2.25c0.188,0.19,0.281,0.45,0.281,0.72v1h-1c-0.2653-0.00001-0.53059-0.0931-0.71875-0.28125l-2.281-2.28-2.281,2.28c-0.188,0.19-0.454,0.28-0.719,0.28h-1v-1c-0.000003-0.26529,0.09306-0.53058,0.28125-0.71875l2.2812-2.25-2.281-2.28c-0.21-0.19-0.303-0.47-0.281-0.75v-1z" fill-rule="nonzero" fill="#bebebe"/>
-</g>
-</g>
-</svg>

+ 0 - 5
p/themes/Screwdriver/icons/configure.svg

@@ -1,5 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
-<g transform="translate(-441.0002,-400.99999)">
-<path style="color:#666666;enable-background:accumulate;" d="m449,402c-0.22065,0-0.44081,0.0113-0.65625,0.0312l-0.40625,2.0938c-0.33446,0.0733-0.66305,0.17589-0.96875,0.3125l-1.5312-1.4688c-0.38863,0.23011-0.72695,0.51408-1.0625,0.8125l0.90625,1.9062c-0.22242,0.24899-0.42425,0.5225-0.59375,0.8125l-2.0938-0.28125c-0.17772,0.40877-0.30872,0.83637-0.40625,1.2812l1.8438,1c-0.0171,0.16809-0.0312,0.3274-0.0312,0.5s0.0142,0.33191,0.0312,0.5l-1.8438,1c0.0975,0.44488,0.22853,0.87248,0.40625,1.2812l2.0938-0.28125c0.1695,0.29,0.37133,0.56351,0.59375,0.8125l-0.90625,1.9062c0.33555,0.29842,0.67387,0.58239,1.0625,0.8125l1.5312-1.4688c0.3057,0.13661,0.63429,0.23916,0.96875,0.3125l0.40625,2.0938c0.21544,0.02,0.4356,0.0312,0.65625,0.0312s0.44081-0.0113,0.65625-0.0312l0.40625-2.0938c0.33446-0.0733,0.66305-0.17589,0.96875-0.3125l1.5312,1.4688c0.38863-0.23011,0.72695-0.51408,1.0625-0.8125l-0.90625-1.9062c0.22242-0.24899,0.42425-0.5225,0.59375-0.8125l2.0938,0.28125c0.17772-0.40877,0.30872-0.83637,0.40625-1.2812l-1.8438-1c0.0171-0.16809,0.0312-0.3274,0.0312-0.5s-0.0142-0.33191-0.0312-0.5l1.8438-1c-0.0975-0.44488-0.22853-0.87248-0.40625-1.2812l-2.0938,0.28125c-0.1695-0.29-0.37133-0.56351-0.59375-0.8125l0.90625-1.9062c-0.33555-0.29842-0.67387-0.58239-1.0625-0.8125l-1.5312,1.4688c-0.3057-0.13661-0.63429-0.23916-0.96875-0.3125l-0.40625-2.0938c-0.21544-0.02-0.4356-0.0312-0.65625-0.0312zm0,4c1.6568,0,3,1.3432,3,3s-1.3432,3-3,3-3-1.3432-3-3,1.3432-3,3-3z" fill-rule="nonzero" fill="#666"/>
-</g>
-</svg>

BIN
p/themes/Screwdriver/icons/favicon-16-32-48-64.ico


BIN
p/themes/Screwdriver/icons/favicon-256.png


+ 0 - 13
p/themes/Screwdriver/icons/favicon.svg

@@ -1,13 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
-	<title>Logo FreshRSS</title>
-	<circle fill="#FFF" cx="128" cy="128" r="128"/>
-	<circle fill="#0062BE" cx="128" cy="128" r="33"/>
-	<g fill="none" stroke="#0062BE" stroke-width="24">
-		<g stroke-opacity="0.3">
-			<path d="M12,128 A116,116 0 1,1 128,244"/>
-			<path d="M54,128 A74,74 0 1,1 128,202"/>
-		</g>
-		<path d="M128,12 A116,116 0 0,1 244,128"/>
-		<path d="M128,54 A74,74 0 0,1 202,128"/>
-	</g>
-</svg>

BIN
p/themes/Screwdriver/icons/grey.gif


+ 0 - 7
p/themes/Screwdriver/icons/help.svg

@@ -1,7 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
-<g transform="translate(-182,-490)" fill="#bebebe">
-<path style="block-progression:tb;color:#bebebe;direction:ltr;text-indent:0;text-align:start;enable-background:accumulate;text-transform:none;" d="m190,490c-4.4147,0-8,3.5853-8,8s3.5853,8,8,8,8-3.5853,8-8-3.5853-8-8-8zm0,2c3.3413,0,6,2.6587,6,6s-2.6587,6-6,6-6-2.6587-6-6,2.6587-6,6-6z"/>
-<path style="block-progression:tb;color:#bebebe;direction:ltr;text-indent:0;text-align:start;enable-background:accumulate;text-transform:none;" d="M189.34,495c-1.28,0-2.34,1.06-2.34,2.34v1.3125c0,1.2861,1.0576,2.3438,2.3438,2.3438h1.3125c1.29,0.01,2.35-1.05,2.35-2.33v-1.3125c0-1.29-1.06-2.35-2.34-2.35h-1.3125zm0,1,1.3125,0c0.74942,0,1.3438,0.59433,1.3438,1.3438v1.3125c0.01,0.76-0.58,1.35-1.33,1.35h-1.3125c-0.76,0-1.35-0.59-1.35-1.34v-1.3125c0-0.76,0.59-1.35,1.34-1.35z"/>
-<path d="m186.72,491.44c-1.5103,0.6073-2.6811,1.7985-3.2812,3.3125l3.75,1.875c0.25196-0.64029,0.74249-1.1706,1.375-1.4375l-1.8438-3.75zm6.5625,0-1.8438,3.75c0.63251,0.26694,1.123,0.79721,1.375,1.4375l3.75-1.875c-0.60015-1.514-1.7709-2.7052-3.2812-3.3125zm-6.0938,8-3.75,1.875c0.60709,1.4886,1.789,2.65,3.2812,3.25l1.875-3.75c-0.62682-0.25556-1.1433-0.75203-1.4062-1.375zm5.625,0c-0.26291,0.62297-0.77943,1.1194-1.4062,1.375l1.875,3.75c1.4923-0.60005,2.6742-1.7614,3.2812-3.25l-3.75-1.875z"/>
-</g>
-</svg>

+ 0 - 7
p/themes/Screwdriver/icons/key.svg

@@ -1,7 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(-340.99994,-257)" fill="#666666">
-<path style="block-progression:tb;color:#000000;direction:ltr;text-indent:0;text-align:start;enable-background:accumulate;text-transform:none;" d="m346,260c-2.7496,0-5,2.2504-5,5s2.2504,5,5,5c1.5862,0,2.9034-0.84459,3.8125-2h4.8438,0.75l0.21875-0.75,1.0312-4,0.3125-1.25h-1.2812-5.875c-0.90914-1.1554-2.2263-2-3.8125-2zm0,2c1.1158,0,2.0379,0.59507,2.5625,1.5l0.3125,0.5h0.5625,4.9688l-0.53125,2h-4.4375-0.5625l-0.3125,0.5c-0.52462,0.90493-1.4466,1.5-2.5625,1.5-1.6687,0-3-1.3313-3-3s1.3313-3,3-3z"/>
-<path opacity="0.35" style="enable-background:accumulate;color:#000000;" d="M355.5,265,350,265,349.44,267,355,267z" fill-rule="nonzero"/>
-<path style="enable-background:accumulate;color:#000000;" d="m346,265c0,0.55228-0.44772,1-1,1s-1-0.44772-1-1,0.44772-1,1-1,1,0.44772,1,1z" fill-rule="nonzero"/>
-</g>
-</svg>

Dosya farkı çok büyük olduğundan ihmal edildi
+ 0 - 4
p/themes/Screwdriver/icons/link.svg


Dosya farkı çok büyük olduğundan ihmal edildi
+ 0 - 2
p/themes/Screwdriver/icons/non-starred.svg


+ 0 - 5
p/themes/Screwdriver/icons/prev.svg

@@ -1,5 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
-<g transform="translate(-301.0002,-747)">
-<path style="block-progression:tb;color:#bebebe;direction:ltr;text-indent:0;text-align:start;enable-background:new;text-transform:none;" d="m313.01,749-1,0c-0.0104-0.00012-0.0208-0.00046-0.0313,0-0.25495,0.0112-0.50987,0.12858-0.6875,0.3125l-6.2977,5.7188,6.2977,5.7188c0.18816,0.18819,0.45346,0.28125,0.71875,0.28125h1v-1c0-0.26529-0.0931-0.53058-0.28125-0.71875l-4.829-4.2812,4.829-4.2812c0.21074-0.19463,0.30316-0.46925,0.28125-0.75z" fill-rule="nonzero" fill="#bebebe"/>
-</g>
-</svg>

+ 3 - 57
p/themes/Screwdriver/icons/read.svg

@@ -1,57 +1,3 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg
-   xmlns:dc="http://purl.org/dc/elements/1.1/"
-   xmlns:cc="http://creativecommons.org/ns#"
-   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-   xmlns:svg="http://www.w3.org/2000/svg"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   height="16.001"
-   width="16"
-   id="svg2"
-   version="1.1"
-   inkscape:version="0.48.4 r9939"
-   sodipodi:docname="read.svg">
-  <metadata
-     id="metadata12">
-    <rdf:RDF>
-      <cc:Work
-         rdf:about="">
-        <dc:format>image/svg+xml</dc:format>
-        <dc:type
-           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
-      </cc:Work>
-    </rdf:RDF>
-  </metadata>
-  <defs
-     id="defs10" />
-  <sodipodi:namedview
-     pagecolor="#ffffff"
-     bordercolor="#666666"
-     borderopacity="1"
-     objecttolerance="10"
-     gridtolerance="10"
-     guidetolerance="10"
-     inkscape:pageopacity="0"
-     inkscape:pageshadow="2"
-     inkscape:window-width="1366"
-     inkscape:window-height="745"
-     id="namedview8"
-     showgrid="false"
-     inkscape:zoom="14.749079"
-     inkscape:cx="-2.2040272"
-     inkscape:cy="8.0004997"
-     inkscape:window-x="0"
-     inkscape:window-y="0"
-     inkscape:window-maximized="1"
-     inkscape:current-layer="svg2" />
-  <g
-     transform="translate(-60.99995,-296.9989)"
-     id="g4" />
-  <path
-     style="fill:#cccccc;fill-opacity:1"
-     inkscape:connector-curvature="0"
-     d="m 8.0004996,3.2833392 c -3.433907,0 -6.410294,1.9996259 -7.87290101,4.9205634 1.46260701,2.9209364 4.43899401,4.9205624 7.87290101,4.9205624 3.4338474,0 6.4102344,-1.999626 7.8729014,-4.9205624 C 14.410824,5.2829651 11.434347,3.2833392 8.0004996,3.2833392 z m 3.8818634,2.6094965 c 0.925096,0.590068 1.709004,1.3804357 2.29781,2.3110669 -0.588806,0.9306312 -1.372744,1.7209988 -2.29784,2.3110964 -1.162392,0.741404 -2.5047194,1.133295 -3.8818334,1.133295 -1.377143,0 -2.719472,-0.391891 -3.881863,-1.133326 -0.925066,-0.5900366 -1.708974,-1.3804016 -2.29781,-2.3110654 0.588806,-0.9306638 1.372744,-1.7210288 2.29781,-2.3110669 0.06025,-0.038442 0.121108,-0.075682 0.182338,-0.1122479 -0.153123,0.4202145 -0.236925,0.873738 -0.236925,1.3469419 0,2.1740274 1.762423,3.9364493 3.93645,3.9364493 2.1740274,0 3.9364514,-1.7624219 3.9364514,-3.9364493 0,-0.4732039 -0.0838,-0.9267274 -0.236925,-1.3469745 0.0612,0.036566 0.122061,0.073839 0.182337,0.1122805 z M 8.0004996,6.6354719 c 0,0.8152761 -0.660894,1.4761705 -1.476168,1.4761705 -0.815275,0 -1.476169,-0.6608944 -1.476169,-1.4761705 0,-0.8152759 0.660894,-1.4761676 1.476169,-1.4761676 0.815274,0 1.476168,0.6608917 1.476168,1.4761676 z"
-     id="path3167" />
-</svg>
+<svg xmlns="http://www.w3.org/2000/svg" height="16.001" width="16">
+<path fill="#CCC" d="m8.0005,3.2833c-3.4339,0-6.4103,1.9996-7.8729,4.9206,1.4626,2.9209,4.439,4.9206,7.8729,4.9206,3.4338,0,6.4102-1.9996,7.8729-4.9206-1.462-2.9204-4.439-4.9201-7.8725-4.9201zm3.8819,2.6095c0.9251,0.59007,1.709,1.3804,2.2978,2.3111-0.58881,0.93063-1.3727,1.721-2.2978,2.3111-1.1624,0.7414-2.5047,1.1333-3.8818,1.1333s-2.7195-0.39189-3.8819-1.1333c-0.92507-0.59004-1.709-1.3804-2.2978-2.3111,0.58881-0.93066,1.3727-1.721,2.2978-2.3111,0.06025-0.038442,0.12111-0.075682,0.18234-0.11225-0.15312,0.42021-0.23692,0.87374-0.23692,1.3469,0,2.174,1.7624,3.9364,3.9364,3.9364s3.9365-1.7624,3.9365-3.9364c0-0.4732-0.0838-0.92673-0.23692-1.347,0.0612,0.036566,0.12206,0.073839,0.18234,0.11228zm-3.8815,0.7427c0,0.81528-0.66089,1.4762-1.4762,1.4762-0.81528,0-1.4762-0.66089-1.4762-1.4762,0-0.81528,0.66089-1.4762,1.4762-1.4762,0.81527,0,1.4762,0.66089,1.4762,1.4762z"/>
+</svg>

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor