diff options
| author | 2018-02-24 12:02:16 +0100 | |
|---|---|---|
| committer | 2018-02-24 12:02:16 +0100 | |
| commit | 5ebeb9e3e5d46195a83211140c1d28d58be19b2a (patch) | |
| tree | 6b93ae52a1206b6045087f893dde67a04b4e1bda | |
| parent | 889888f20eb6f3dd476b78c0f59672f7c7962354 (diff) | |
| parent | 294f9336ad0f315574c74d6b527b1bb8a280f3c6 (diff) | |
Merge pull request #1786 from FreshRSS/dev1.10.0
FreshRSS 1.10.0
123 files changed, 1168 insertions, 271 deletions
diff --git a/.travis.yml b/.travis.yml index 7bfefd8ce..0217b61c5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,18 +5,20 @@ php: - '5.6' - '7.0' - '7.1' + - '7.2' - hhvm - nightly install: # newest version without https://github.com/squizlabs/PHP_CodeSniffer/pull/1404 - - pear install PHP_CodeSniffer-3.0.0RC4 + - composer global require squizlabs/php_codesniffer "<=3.0.0RC4" script: - phpenv rehash - | if [[ $VALIDATE_STANDARD == yes ]]; then - phpcs . --standard=phpcs.xml --warning-severity=0 --extensions=php -p + COMPOSER_BIN=$(composer global config --absolute bin-dir) + $COMPOSER_BIN/phpcs . --standard=phpcs.xml --warning-severity=0 --extensions=php -p fi - | if [[ $CHECK_TRANSLATION == yes ]]; then @@ -29,18 +31,11 @@ env: matrix: fast_finish: true include: + # PHP 5.3 only runs on Ubuntu 12.04 (precise), not 14.04 (trusty) - php: "5.3" dist: precise - - php: "7.1" + - php: "7.2" env: CHECK_TRANSLATION=yes VALIDATE_STANDARD=no allow_failures: - # PHP 5.3 only runs on Ubuntu 12.04 (precise), not 14.04 (trusty) - - php: "5.3" - dist: precise - - php: "5.4" - - php: "5.5" - - php: "5.6" - - php: "7.0" - - php: hhvm - - php: nightly - env: CHECK_TRANSLATION=yes VALIDATE_STANDARD=no + - dist: precise diff --git a/CHANGELOG.md b/CHANGELOG.md index 05aa1cffe..88f6fa129 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,31 @@ # FreshRSS changelog +## 2018-02-24 FreshRSS 1.10.0 + +* API + * Add compatibility with FeedMe 3.5.3+ on Android [#1774](https://github.com/FreshRSS/FreshRSS/pull/1774) +* Features + * Ability to pause feeds, and to hide them from categories [#1750](https://github.com/FreshRSS/FreshRSS/pull/1750) + * Ability for the admin to reset a user’s password [#960](https://github.com/FreshRSS/FreshRSS/issues/960) +* Security + * Allow HTTP Auth login with `REDIRECT_REMOTE_USER` when using Apache internal redirect [#1772](https://github.com/FreshRSS/FreshRSS/pull/1772) +* UI + * New icons for marking as favourite and marking as read in the Reading View [#603](https://github.com/FreshRSS/FreshRSS/issues/603) + * Add shortcuts to switch views [#1755](https://github.com/FreshRSS/FreshRSS/pull/1755) +* Bug fixing + * Fix login bug when HTTP `REMOTE_USER` changes (used by YunoHost) [#1756](https://github.com/FreshRSS/FreshRSS/pull/1756) + * Fix warning in PHP 7.2 [#1739](https://github.com/FreshRSS/FreshRSS/pull/1739) +* Extensions + * Allow extensions to define their own reading view [#1714](https://github.com/FreshRSS/FreshRSS/pull/1714) +* I18n + * Updated Chinese [#1769](https://github.com/FreshRSS/FreshRSS/pull/1769) + * Updated Dutch [#1792](https://github.com/FreshRSS/FreshRSS/pull/1792) + * Updated Korean [#1776](https://github.com/FreshRSS/FreshRSS/pull/1776) +* Misc. + * More sites in `force-https.default.txt` [#1745](https://github.com/FreshRSS/FreshRSS/pull/1745) + * Trim URLs when adding new feeds [#1778](https://github.com/FreshRSS/FreshRSS/pull/1778) + + ## 2017-12-17 FreshRSS 1.9.0 * Features diff --git a/CREDITS.md b/CREDITS.md index afe4b13b2..e7e7c97a8 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -19,6 +19,7 @@ People are sorted by name so please keep this order. * [danc](https://github.com/danc): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=danc), [Web](http://tintouli.free.fr/) * [David Souza](https://github.com/araujo0205): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:araujo0205), [Web](http://davidsouza.tech/) * [dswd](https://github.com/dswd): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:dswd) +* [Django Janny](https://github.com/keltroth): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:keltroth) * [ealdraed](https://github.com/ealdraed): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=ealdraed) * [Frans de Jonge](https://github.com/Frenzie): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=Frenzie), [Web](http://fransdejonge.com/) * [gsongsong](https://github.com/gsongsong): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:gsongsong) @@ -26,6 +27,7 @@ People are sorted by name so please keep this order. * [Guillaume Hayot](https://github.com/postblue): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:postblue), [Web](https://postblue.info/) * [hckweb](https://github.com/hckweb): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=hckweb) * [hoilc](https://github.com/hoilc): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:hoilc) +* [Jan van den Berg](https://github.com/jan-vandenberg): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:jan-vandenberg), [Web](https://j11g.com/) * [Jaussoin Timothée](https://github.com/edhelas): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=edhelas), [Web](http://edhelas.movim.eu/) * [jlefler](https://github.com/jlefler): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:jlefler) * [Jonas Östanbäck](https://github.com/cez81): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=cez81) @@ -37,8 +39,10 @@ People are sorted by name so please keep this order. * [Marien Fressinaud](https://github.com/marienfressinaud): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=marienfressinaud), [Web](https://marienfressinaud.fr/) * [Melvyn Laïly](https://github.com/yaurthek): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=yaurthek), [Web](http://x2a.yt/) * [MSZ](https://github.com/mszkb): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=mszkb) +* [Nico B](https://github.com/youknow0): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:youknow0) * [Nicolas Elie](https://github.com/nicolaselie): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=nicolaselie) * [Nicolas Lœuillet](https://github.com/nicosomb): [contributions](https://github.com/FreshRSS/documentation/commits?author=nicosomb), [Web](http://www.loeuillet.org/) +* [Nicola Spanti](https://github.com/RyDroid): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:RyDroid), [Web](http://www.nicola-spanti.info/) * [Olivier Dossmann](https://github.com/blankoworld): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=blankoworld), [Web](https://olivier.dossmann.net) * [plopoyop](https://github.com/plopoyop): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=plopoyop) * [Paulius Šukys](https://github.com/psukys): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:psukys), [Web](http://sukys.eu) diff --git a/README.fr.md b/README.fr.md index b888f7738..4421f92f0 100644 --- a/README.fr.md +++ b/README.fr.md @@ -177,6 +177,7 @@ Tout client supportant une API de type Google Reader. Sélection : * Android * [News+](https://play.google.com/store/apps/details?id=com.noinnion.android.newsplus) avec [News+ Google Reader extension](https://play.google.com/store/apps/details?id=com.noinnion.android.newsplus.extension.google_reader) (Propriétaire) + * [FeedMe 3.5.3+](https://play.google.com/store/apps/details?id=com.seazon.feedme) (Propriétaire) * [EasyRSS](https://github.com/Alkarex/EasyRSS) (Libre, [F-Droid](https://f-droid.org/fr/packages/org.freshrss.easyrss/)) * GNU/Linux * [FeedReader 2.0+](https://jangernert.github.io/FeedReader/) (Libre) @@ -183,6 +183,7 @@ Any client supporting a Google Reader-like API. Selection: * Android * [News+](https://play.google.com/store/apps/details?id=com.noinnion.android.newsplus) with [News+ Google Reader extension](https://play.google.com/store/apps/details?id=com.noinnion.android.newsplus.extension.google_reader) (Closed source) + * [FeedMe 3.5.3+](https://play.google.com/store/apps/details?id=com.seazon.feedme) (Closed source) * [EasyRSS](https://github.com/Alkarex/EasyRSS) (Open source, [F-Droid](https://f-droid.org/packages/org.freshrss.easyrss/)) * GNU/Linux * [FeedReader 2.0+](https://jangernert.github.io/FeedReader/) (Open source) diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 9d2ee450c..d34b5d59d 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -55,6 +55,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { FreshRSS_Context::$user_conf->bottomline_date = Minz_Request::param('bottomline_date', false); FreshRSS_Context::$user_conf->bottomline_link = Minz_Request::param('bottomline_link', false); FreshRSS_Context::$user_conf->html5_notif_timeout = Minz_Request::param('html5_notif_timeout', 0); + FreshRSS_Context::$user_conf->show_nav_buttons = Minz_Request::param('show_nav_buttons', false); FreshRSS_Context::$user_conf->save(); Minz_Session::_param('language', FreshRSS_Context::$user_conf->language); @@ -170,7 +171,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { 'm', 'n', 'o', 'p', 'page_down', 'page_up', 'q', 'r', 'return', 'right', 's', 'space', 't', 'tab', 'u', 'up', 'v', 'w', 'x', 'y', 'z', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', - 'f10', 'f11', 'f12'); + 'f10', 'f11', 'f12', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0'); $this->view->list_keys = $list_keys; if (Minz_Request::isPost()) { @@ -204,16 +205,13 @@ class FreshRSS_configure_Controller extends Minz_ActionController { * 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 + * - refresh frequency (default: 0) */ public function archivingAction() { if (Minz_Request::isPost()) { FreshRSS_Context::$user_conf->old_entries = Minz_Request::param('old_entries', 3); FreshRSS_Context::$user_conf->keep_history_default = Minz_Request::param('keep_history_default', 0); - FreshRSS_Context::$user_conf->ttl_default = Minz_Request::param('ttl_default', -2); + FreshRSS_Context::$user_conf->ttl_default = Minz_Request::param('ttl_default', FreshRSS_Feed::TTL_DEFAULT); FreshRSS_Context::$user_conf->save(); invalidateHttpCache(); diff --git a/app/Controllers/entryController.php b/app/Controllers/entryController.php index bd8b65b2b..9c6b248a9 100755 --- a/app/Controllers/entryController.php +++ b/app/Controllers/entryController.php @@ -177,9 +177,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { foreach ($feeds as $feed) { $feed_history = $feed->keepHistory(); - if ($feed_history == -2) { - // TODO: -2 must be a constant! - // -2 means we take the default value from configuration + if (FreshRSS_Feed::KEEP_HISTORY_DEFAULT === $feed_history) { $feed_history = FreshRSS_Context::$user_conf->keep_history_default; } diff --git a/app/Controllers/extensionController.php b/app/Controllers/extensionController.php index bb846e921..311fd2e96 100644 --- a/app/Controllers/extensionController.php +++ b/app/Controllers/extensionController.php @@ -240,7 +240,7 @@ class FreshRSS_extension_Controller extends Minz_ActionController { $res = recursive_unlink($ext->getPath()); if ($res) { Minz_Request::good(_t('feedback.extensions.removed', $ext_name), - $url_redirect); + $url_redirect); } else { Minz_Request::bad(_t('feedback.extensions.cannot_delete', $ext_name), $url_redirect); diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index fff20f798..7f66b10db 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -24,6 +24,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { Minz_Error::error(403); } } + $this->updateTTL(); } /** @@ -44,6 +45,8 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $catDAO = new FreshRSS_CategoryDAO(); + $url = trim($url); + $cat = null; if ($new_cat_name != '') { $new_cat_id = $catDAO->addCategory(array('name' => $new_cat_name)); @@ -282,11 +285,11 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $mtime = 0; $ttl = $feed->ttl(); - if ($ttl == -1) { + if ($ttl < FreshRSS_Feed::TTL_DEFAULT) { continue; //Feed refresh is disabled } if ((!$simplePiePush) && (!$feed_id) && - ($feed->lastUpdate() + 10 >= time() - ($ttl == -2 ? FreshRSS_Context::$user_conf->ttl_default : $ttl))) { + ($feed->lastUpdate() + 10 >= time() - ($ttl == FreshRSS_Feed::TTL_DEFAULT ? FreshRSS_Context::$user_conf->ttl_default : $ttl))) { //Too early to refresh from source, but check whether the feed was updated by another user $mtime = $feed->cacheModifiedTime(); if ($feed->lastUpdate() + 10 >= $mtime) { @@ -316,10 +319,8 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feed_history = $feed->keepHistory(); if ($isNewFeed) { - $feed_history = -1; //∞ - } elseif ($feed_history == -2) { - // TODO: -2 must be a constant! - // -2 means we take the default value from configuration + $feed_history = FreshRSS_Feed::KEEP_HISTORY_INFINITE; + } elseif (FreshRSS_Feed::KEEP_HISTORY_DEFAULT === $feed_history) { $feed_history = FreshRSS_Context::$user_conf->keep_history_default; } $needFeedCacheRefresh = false; @@ -639,4 +640,14 @@ class FreshRSS_feed_Controller extends Minz_ActionController { Minz_Request::bad(_t('feedback.sub.feed.error'), $redirect_url); } } + + /** + * This method update TTL values for feeds if needed. + * It changes the old default value (-2) to the new default value (0). + * It changes the old disabled value (-1) to the default disabled value. + */ + private function updateTTL() { + $feedDAO = FreshRSS_Factory::createFeedDao(); + $feedDAO->updateTTL(); + } } diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index e8dde36fa..e3dbd4664 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -203,7 +203,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { $entryDAO = FreshRSS_Factory::createEntryDao(); $get = FreshRSS_Context::currentGet(true); - if (count($get) > 1) { + if (is_array($get)) { $type = $get[0]; $id = $get[1]; } else { diff --git a/app/Controllers/subscriptionController.php b/app/Controllers/subscriptionController.php index 6af048b84..37efd3b57 100644 --- a/app/Controllers/subscriptionController.php +++ b/app/Controllers/subscriptionController.php @@ -15,8 +15,10 @@ class FreshRSS_subscription_Controller extends Minz_ActionController { } $catDAO = new FreshRSS_CategoryDAO(); + $feedDAO = new FreshRSS_FeedDAO(); $catDAO->checkDefault(); + $feedDAO->updateTTL(); $this->view->categories = $catDAO->listCategories(false); $this->view->default_category = $catDAO->getDefault(); } @@ -55,7 +57,7 @@ class FreshRSS_subscription_Controller extends Minz_ActionController { * - display in main stream (default: 0) * - HTTP authentication * - number of article to retain (default: -2) - * - refresh frequency (default: -2) + * - refresh frequency (default: 0) * Default values are empty strings unless specified. */ public function feedAction() { @@ -87,6 +89,12 @@ class FreshRSS_subscription_Controller extends Minz_ActionController { $cat = intval(Minz_Request::param('category', 0)); + $mute = Minz_Request::param('mute', false); + $ttl = intval(Minz_Request::param('ttl', FreshRSS_Feed::TTL_DEFAULT)); + if ($mute && FreshRSS_Feed::TTL_DEFAULT === $ttl) { + $ttl = FreshRSS_Context::$user_conf->ttl_default; + } + $values = array( 'name' => Minz_Request::param('name', ''), 'description' => sanitizeHTML(Minz_Request::param('description', '', true)), @@ -94,10 +102,10 @@ class FreshRSS_subscription_Controller extends Minz_ActionController { 'url' => checkUrl(Minz_Request::param('url', '')), 'category' => $cat, 'pathEntries' => Minz_Request::param('path_entries', ''), - 'priority' => intval(Minz_Request::param('priority', 0)), + 'priority' => intval(Minz_Request::param('priority', FreshRSS_Feed::PRIORITY_MAIN_STREAM)), 'httpAuth' => $httpAuth, - 'keep_history' => intval(Minz_Request::param('keep_history', -2)), - 'ttl' => intval(Minz_Request::param('ttl', -2)), + 'keep_history' => intval(Minz_Request::param('keep_history', FreshRSS_Feed::KEEP_HISTORY_DEFAULT)), + 'ttl' => $ttl * ($mute ? -1 : 1), ); invalidateHttpCache(); diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index 2a1d43d9e..2dad6a3f0 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -44,29 +44,54 @@ class FreshRSS_user_Controller extends Minz_ActionController { return preg_match('/^' . self::USERNAME_PATTERN . '$/', $username) === 1; } - public static function updateContextUser($passwordPlain, $apiPasswordPlain, $userConfigUpdated = array()) { + public static function updateUser($user, $passwordPlain, $apiPasswordPlain, $userConfigUpdated = array()) { + $userConfig = get_user_configuration($user); if ($passwordPlain != '') { $passwordHash = self::hashPassword($passwordPlain); - FreshRSS_Context::$user_conf->passwordHash = $passwordHash; + $userConfig->passwordHash = $passwordHash; } if ($apiPasswordPlain != '') { $apiPasswordHash = self::hashPassword($apiPasswordPlain); - FreshRSS_Context::$user_conf->apiPasswordHash = $apiPasswordHash; + $userConfig->apiPasswordHash = $apiPasswordHash; } if (is_array($userConfigUpdated)) { foreach ($userConfigUpdated as $configName => $configValue) { if ($configValue !== null) { - FreshRSS_Context::$user_conf->_param($configName, $configValue); + $userConfig->_param($configName, $configValue); } } } - $ok = FreshRSS_Context::$user_conf->save(); + $ok = $userConfig->save(); return $ok; } + public function updateAction() { + if (Minz_Request::isPost()) { + $passwordPlain = Minz_Request::param('newPasswordPlain', '', true); + Minz_Request::_param('newPasswordPlain'); //Discard plain-text password ASAP + $_POST['newPasswordPlain'] = ''; + + $apiPasswordPlain = Minz_Request::param('apiPasswordPlain', '', true); + + $username = Minz_Request::param('username'); + $ok = self::updateUser($username, $passwordPlain, $apiPasswordPlain, array( + 'token' => Minz_Request::param('token', null), + )); + + if ($ok) { + Minz_Request::good(_t('feedback.user.updated', $username), + array('c' => 'user', 'a' => 'manage')); + } else { + Minz_Request::bad(_t('feedback.user.updated.error', $username), + array('c' => 'user', 'a' => 'manage')); + } + + } + } + /** * This action displays the user profile page. */ @@ -84,7 +109,7 @@ class FreshRSS_user_Controller extends Minz_ActionController { $apiPasswordPlain = Minz_Request::param('apiPasswordPlain', '', true); - $ok = self::updateContextUser($passwordPlain, $apiPasswordPlain, array( + $ok = self::updateUser(Minz_Session::param('currentUser'), $passwordPlain, $apiPasswordPlain, array( 'token' => Minz_Request::param('token', null), )); @@ -110,19 +135,18 @@ class FreshRSS_user_Controller extends Minz_ActionController { Minz_View::prependTitle(_t('admin.user.title') . ' · '); - // Get the correct current user. - $username = Minz_Request::param('u', Minz_Session::param('currentUser')); - if (!FreshRSS_UserDAO::exist($username)) { - $username = Minz_Session::param('currentUser'); - } - $this->view->current_user = $username; + $this->view->current_user = Minz_Request::param('u'); - // Get information about the current user. - $entryDAO = FreshRSS_Factory::createEntryDao($this->view->current_user); - $this->view->nb_articles = $entryDAO->count(); + $this->view->nb_articles = 0; + $this->view->size_user = 0; + if ($this->view->current_user) { + // Get information about the current user. + $entryDAO = FreshRSS_Factory::createEntryDao($this->view->current_user); + $this->view->nb_articles = $entryDAO->count(); - $databaseDAO = FreshRSS_Factory::createDatabaseDAO(); - $this->view->size_user = $databaseDAO->size(); + $databaseDAO = FreshRSS_Factory::createDatabaseDAO(); + $this->view->size_user = $databaseDAO->size(); + } } public static function createUser($new_user_name, $passwordPlain, $apiPasswordPlain, $userConfig = array(), $insertDefaultFeeds = true) { diff --git a/app/Models/Auth.php b/app/Models/Auth.php index 4de058999..32b673b6d 100644 --- a/app/Models/Auth.php +++ b/app/Models/Auth.php @@ -13,6 +13,11 @@ class FreshRSS_Auth { * This method initializes authentication system. */ public static function init() { + if (Minz_Session::param('REMOTE_USER', '') !== httpAuthUser()) { + //HTTP REMOTE_USER has changed + self::removeAccess(); + } + self::$login_ok = Minz_Session::param('loginOk', false); $current_user = Minz_Session::param('currentUser', ''); if ($current_user === '') { @@ -58,6 +63,7 @@ class FreshRSS_Auth { $login_ok = $current_user != ''; if ($login_ok) { Minz_Session::_param('currentUser', $current_user); + Minz_Session::_param('REMOTE_USER', $current_user); } return $login_ok; case 'none': diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php index f219c275f..68db17db3 100644 --- a/app/Models/CategoryDAO.php +++ b/app/Models/CategoryDAO.php @@ -106,13 +106,14 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable public function listCategories($prePopulateFeeds = true, $details = false) { if ($prePopulateFeeds) { $sql = 'SELECT c.id AS c_id, c.name AS c_name, ' - . ($details ? 'f.* ' : 'f.id, f.name, f.url, f.website, f.priority, f.error, f.`cache_nbEntries`, f.`cache_nbUnreads` ') + . ($details ? 'f.* ' : 'f.id, f.name, f.url, f.website, f.priority, f.error, f.`cache_nbEntries`, f.`cache_nbUnreads`, f.ttl ') . 'FROM `' . $this->prefix . 'category` c ' . 'LEFT OUTER JOIN `' . $this->prefix . 'feed` f ON f.category=c.id ' + . 'WHERE f.priority >= :priority_normal ' . 'GROUP BY f.id, c_id ' . 'ORDER BY c.name, f.name'; $stm = $this->bd->prepare($sql); - $stm->execute(); + $stm->execute(array(':priority_normal' => FreshRSS_Feed::PRIORITY_NORMAL)); return self::daoToCategoryPrepopulated($stm->fetchAll(PDO::FETCH_ASSOC)); } else { $sql = 'SELECT * FROM `' . $this->prefix . 'category` ORDER BY name'; diff --git a/app/Models/ConfigurationSetter.php b/app/Models/ConfigurationSetter.php index ca4709903..ad703dfc5 100644 --- a/app/Models/ConfigurationSetter.php +++ b/app/Models/ConfigurationSetter.php @@ -81,7 +81,7 @@ class FreshRSS_ConfigurationSetter { private function _keep_history_default(&$data, $value) { $value = intval($value); - $data['keep_history_default'] = $value >= -1 ? $value : 0; + $data['keep_history_default'] = $value >= FreshRSS_Feed::KEEP_HISTORY_INFINITE ? $value : 0; } // It works for system config too! @@ -154,7 +154,7 @@ class FreshRSS_ConfigurationSetter { private function _ttl_default(&$data, $value) { $value = intval($value); - $data['ttl_default'] = $value >= -1 ? $value : 3600; + $data['ttl_default'] = $value > FreshRSS_Feed::TTL_DEFAULT ? $value : 3600; } private function _view_mode(&$data, $value) { @@ -184,6 +184,10 @@ class FreshRSS_ConfigurationSetter { $data['mark_updated_article_unread'] = $this->handleBool($value); } + private function _show_nav_buttons(&$data, $value) { + $data['show_nav_buttons'] = $this->handleBool($value); + } + private function _display_categories(&$data, $value) { $data['display_categories'] = $this->handleBool($value); } diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index e8b6dcdae..70135e7a0 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -628,10 +628,12 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $firstId = $order === 'DESC' ? '9000000000'. '000000' : '0'; }*/ if ($firstId !== '') { - $search .= 'AND ' . $alias . 'id ' . ($order === 'DESC' ? '<=' : '>=') . $firstId . ' '; + $search .= 'AND ' . $alias . 'id ' . ($order === 'DESC' ? '<=' : '>=') . ' ? '; + $values[] = $firstId; } if ($date_min > 0) { - $search .= 'AND ' . $alias . 'id >= ' . $date_min . '000000 '; + $search .= 'AND ' . $alias . 'id >= ? '; + $values[] = $date_min . '000000'; } if ($filter) { if ($filter->getMinDate()) { @@ -726,23 +728,23 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $values = array(); switch ($type) { case 'a': - $where .= 'f.priority > 0 '; - $joinFeed = true; + $where .= 'f.priority > ' . FreshRSS_Feed::PRIORITY_NORMAL . ' '; break; case 's': //Deprecated: use $state instead - $where .= 'e.is_favorite=1 '; + $where .= 'f.priority >= ' . FreshRSS_Feed::PRIORITY_NORMAL . ' '; + $where .= 'AND e.is_favorite=1 '; break; case 'c': - $where .= 'f.category=? '; + $where .= 'f.priority >= ' . FreshRSS_Feed::PRIORITY_NORMAL . ' '; + $where .= 'AND f.category=? '; $values[] = intval($id); - $joinFeed = true; break; case 'f': $where .= 'e.id_feed=? '; $values[] = intval($id); break; case 'A': - $where .= '1=1 '; + $where .= 'f.priority >= ' . FreshRSS_Feed::PRIORITY_NORMAL . ' '; break; default: throw new FreshRSS_EntriesGetter_Exception('Bad type in Entry->listByType: [' . $type . ']!'); @@ -752,7 +754,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { return array(array_merge($values, $searchValues), 'SELECT e.id FROM `' . $this->prefix . 'entry` e ' - . ($joinFeed ? 'INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed=f.id ' : '') + . 'INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id ' . 'WHERE ' . $where . $search . 'ORDER BY e.id ' . $order @@ -781,6 +783,23 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { return self::daoToEntries($stm->fetchAll(PDO::FETCH_ASSOC)); } + public function listByIds($ids, $order = 'DESC') { + if (count($ids) < 1) { + return array(); + } + + $sql = 'SELECT id, guid, title, author, ' + . ($this->isCompressed() ? 'UNCOMPRESS(content_bin) AS content' : 'content') + . ', link, date, is_read, is_favorite, id_feed, tags ' + . 'FROM `' . $this->prefix . 'entry` ' + . 'WHERE id IN (' . str_repeat('?,', count($ids) - 1). '?) ' + . 'ORDER BY id ' . $order; + + $stm = $this->bd->prepare($sql); + $stm->execute($ids); + return self::daoToEntries($stm->fetchAll(PDO::FETCH_ASSOC)); + } + public function listIdsWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0) { //For API list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filter, $date_min); @@ -873,12 +892,28 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { } public function countUnreadReadFavorites() { - $sql = 'SELECT c FROM (' - . 'SELECT COUNT(id) AS c, 1 as o FROM `' . $this->prefix . 'entry` WHERE is_favorite=1 ' - . 'UNION SELECT COUNT(id) AS c, 2 AS o FROM `' . $this->prefix . 'entry` WHERE is_favorite=1 AND is_read=0' - . ') u ORDER BY o'; + $sql = <<<SQL + SELECT c + FROM ( + SELECT COUNT(e1.id) AS c + , 1 AS o + FROM `{$this->prefix}entry` AS e1 + JOIN `{$this->prefix}feed` AS f1 ON e1.id_feed = f1.id + WHERE e1.is_favorite = 1 + AND f1.priority >= :priority_normal + UNION + SELECT COUNT(e2.id) AS c + , 2 AS o + FROM `{$this->prefix}entry` AS e2 + JOIN `{$this->prefix}feed` AS f2 ON e2.id_feed = f2.id + WHERE e2.is_favorite = 1 + AND e2.is_read = 0 + AND f2.priority >= :priority_normal + ) u +ORDER BY o +SQL; $stm = $this->bd->prepare($sql); - $stm->execute(); + $stm->execute(array(':priority_normal' => FreshRSS_Feed::PRIORITY_NORMAL)); $res = $stm->fetchAll(PDO::FETCH_COLUMN, 0); $all = empty($res[0]) ? 0 : $res[0]; $unread = empty($res[1]) ? 0 : $res[1]; diff --git a/app/Models/Feed.php b/app/Models/Feed.php index 560f7415d..13ab13df9 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -1,6 +1,15 @@ <?php class FreshRSS_Feed extends Minz_Model { + const PRIORITY_MAIN_STREAM = 10; + const PRIORITY_NORMAL = 0; + const PRIORITY_ARCHIVED = -10; + + const TTL_DEFAULT = 0; + + const KEEP_HISTORY_DEFAULT = -2; + const KEEP_HISTORY_INFINITE = -1; + private $id = 0; private $url; private $category = 1; @@ -11,12 +20,13 @@ class FreshRSS_Feed extends Minz_Model { private $website = ''; private $description = ''; private $lastUpdate = 0; - private $priority = 10; + private $priority = self::PRIORITY_MAIN_STREAM; private $pathEntries = ''; private $httpAuth = ''; private $error = false; - private $keep_history = -2; - private $ttl = -2; + private $keep_history = self::KEEP_HISTORY_DEFAULT; + private $ttl = self::TTL_DEFAULT; + private $mute = false; private $hash = null; private $lockPath = ''; private $hubUrl = ''; @@ -104,9 +114,12 @@ class FreshRSS_Feed extends Minz_Model { public function ttl() { return $this->ttl; } + public function mute() { + return $this->mute; + } // public function ttlExpire() { // $ttl = $this->ttl; - // if ($ttl == -2) { //Default + // if ($ttl == self::TTL_DEFAULT) { //Default // $ttl = FreshRSS_Context::$user_conf->ttl_default; // } // if ($ttl == -1) { //Never @@ -198,8 +211,7 @@ class FreshRSS_Feed extends Minz_Model { $this->lastUpdate = $value; } public function _priority($value) { - $value = intval($value); - $this->priority = $value >= 0 ? $value : 10; + $this->priority = intval($value); } public function _pathEntries($value) { $this->pathEntries = $value; @@ -213,14 +225,14 @@ class FreshRSS_Feed extends Minz_Model { public function _keepHistory($value) { $value = intval($value); $value = min($value, 1000000); - $value = max($value, -2); + $value = max($value, self::KEEP_HISTORY_DEFAULT); $this->keep_history = $value; } public function _ttl($value) { $value = intval($value); $value = min($value, 100000000); - $value = max($value, -2); - $this->ttl = $value; + $this->ttl = abs($value); + $this->mute = $value < self::TTL_DEFAULT; } public function _nbNotRead($value) { $this->nbNotRead = intval($value); diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index 0de6d98be..011b3d112 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -18,7 +18,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { ttl ) VALUES - (?, ?, ?, ?, ?, ?, 10, ?, 0, -2, -2)'; + (?, ?, ?, ?, ?, ?, 10, ?, 0, ?, ?)'; $stm = $this->bd->prepare($sql); $valuesTmp['url'] = safe_ascii($valuesTmp['url']); @@ -32,6 +32,8 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { substr($valuesTmp['description'], 0, 1023), $valuesTmp['lastUpdate'], base64_encode($valuesTmp['httpAuth']), + FreshRSS_Feed::KEEP_HISTORY_DEFAULT, + FreshRSS_Feed::TTL_DEFAULT, ); if ($stm && $stm->execute($values)) { @@ -249,18 +251,14 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { * Use $defaultCacheDuration == -1 to return all feeds, without filtering them by TTL. */ public function listFeedsOrderUpdate($defaultCacheDuration = 3600) { + $this->updateTTL(); $sql = 'SELECT id, url, name, website, `lastUpdate`, `pathEntries`, `httpAuth`, keep_history, ttl ' . 'FROM `' . $this->prefix . 'feed` ' - . ($defaultCacheDuration < 0 ? '' : 'WHERE ttl <> -1 AND `lastUpdate` < (' . (time() + 60) . '-(CASE WHEN ttl=-2 THEN ' . intval($defaultCacheDuration) . ' ELSE ttl END)) ') + . ($defaultCacheDuration < 0 ? '' : 'WHERE ttl >= ' . FreshRSS_Feed::TTL_DEFAULT + . ' AND `lastUpdate` < (' . (time() + 60) . '-(CASE WHEN ttl=' . FreshRSS_Feed::TTL_DEFAULT . ' THEN ' . intval($defaultCacheDuration) . ' ELSE ttl END)) ') . 'ORDER BY `lastUpdate`'; $stm = $this->bd->prepare($sql); - if (!($stm && $stm->execute())) { - $sql2 = 'ALTER TABLE `' . $this->prefix . 'feed` ADD COLUMN ttl INT NOT NULL DEFAULT -2'; //v0.7.3 - $stm = $this->bd->prepare($sql2); - $stm->execute(); - $stm = $this->bd->prepare($sql); - $stm->execute(); - } + $stm->execute(); return self::daoToFeed($stm->fetchAll(PDO::FETCH_ASSOC)); } @@ -409,8 +407,8 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $myFeed->_pathEntries(isset($dao['pathEntries']) ? $dao['pathEntries'] : ''); $myFeed->_httpAuth(isset($dao['httpAuth']) ? base64_decode($dao['httpAuth']) : ''); $myFeed->_error(isset($dao['error']) ? $dao['error'] : 0); - $myFeed->_keepHistory(isset($dao['keep_history']) ? $dao['keep_history'] : -2); - $myFeed->_ttl(isset($dao['ttl']) ? $dao['ttl'] : -2); + $myFeed->_keepHistory(isset($dao['keep_history']) ? $dao['keep_history'] : FreshRSS_Feed::KEEP_HISTORY_DEFAULT); + $myFeed->_ttl(isset($dao['ttl']) ? $dao['ttl'] : FreshRSS_Feed::TTL_DEFAULT); $myFeed->_nbNotRead(isset($dao['cache_nbUnreads']) ? $dao['cache_nbUnreads'] : 0); $myFeed->_nbEntries(isset($dao['cache_nbEntries']) ? $dao['cache_nbEntries'] : 0); if (isset($dao['id'])) { @@ -421,4 +419,20 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { return $list; } + + public function updateTTL() { + $sql = <<<SQL +UPDATE `{$this->prefix}feed` + SET ttl = :new_value + WHERE ttl = :old_value +SQL; + $stm = $this->bd->prepare($sql); + if (!($stm && $stm->execute(array(':new_value' => FreshRSS_Feed::TTL_DEFAULT, ':old_value' => -2)))) { + $sql2 = 'ALTER TABLE `' . $this->prefix . 'feed` ADD COLUMN ttl INT NOT NULL DEFAULT ' . FreshRSS_Feed::TTL_DEFAULT; //v0.7.3 + $stm = $this->bd->prepare($sql2); + $stm->execute(); + } else { + $stm->execute(array(':new_value' => -3600, ':old_value' => -1)); + } + } } diff --git a/app/Models/ReadingMode.php b/app/Models/ReadingMode.php new file mode 100644 index 000000000..06af1704c --- /dev/null +++ b/app/Models/ReadingMode.php @@ -0,0 +1,148 @@ +<?php + +/** + * Manage the reading modes in FreshRSS. + */ +class FreshRSS_ReadingMode { + + /** + * @var string + */ + protected $id; + /** + * @var string + */ + protected $name; + /** + * @var string + */ + protected $title; + /** + * @var string[] + */ + protected $urlParams; + /** + * @var bool + */ + protected $isActive = false; + + /** + * ReadingMode constructor. + * @param string $id + * @param string $title + * @param string[] $urlParams + * @param bool $active + */ + public function __construct($id, $title, $urlParams, $active) { + $this->id = $id; + $this->name = _i($id); + $this->title = $title; + $this->urlParams = $urlParams; + $this->isActive = $active; + } + + /** + * @return string + */ + public function getId() { + return $this->id; + } + + /** + * @return string + */ + public function getName() { + return $this->name; + } + + /** + * @param string $name + * @return FreshRSS_ReadingMode + */ + public function setName($name) { + $this->name = $name; + return $this; + } + + /** + * @return string + */ + public function getTitle() { + return $this->title; + } + + /** + * @param string $title + * @return FreshRSS_ReadingMode + */ + public function setTitle($title) { + $this->title = $title; + return $this; + } + + /** + * @return string + */ + public function getUrlParams() { + return $this->urlParams; + } + + /** + * @param string $urlParams + * @return FreshRSS_ReadingMode + */ + public function setUrlParams($urlParams) { + $this->urlParams = $urlParams; + return $this; + } + + /** + * @return bool + */ + public function isActive() { + return $this->isActive; + } + + /** + * @param bool $isActive + * @return FreshRSS_ReadingMode + */ + public function setIsActive($isActive) { + $this->isActive = $isActive; + return $this; + } + + /** + * Returns the built-in reading modes. + * return ReadingMode[] + */ + public static function getReadingModes() { + $actualView = Minz_Request::actionName(); + $defaultCtrl = Minz_Request::defaultControllerName(); + $isDefaultCtrl = Minz_Request::controllerName() === $defaultCtrl; + $urlOutput = Minz_Request::currentRequest(); + + $readingModes = array( + new FreshRSS_ReadingMode( + "view-normal", + _t('index.menu.normal_view'), + array_merge($urlOutput, array('c' => $defaultCtrl, 'a' => 'normal')), + ($isDefaultCtrl && $actualView === 'normal') + ), + new FreshRSS_ReadingMode( + "view-global", + _t('index.menu.global_view'), + array_merge($urlOutput, array('c' => $defaultCtrl, 'a' => 'global')), + ($isDefaultCtrl && $actualView === 'global') + ), + new FreshRSS_ReadingMode( + "view-reader", + _t('index.menu.reader_view'), + array_merge($urlOutput, array('c' => $defaultCtrl, 'a' => 'reader')), + ($isDefaultCtrl && $actualView === 'reader') + ), + ); + + return $readingModes; + } +} diff --git a/app/SQL/install.sql.mysql.php b/app/SQL/install.sql.mysql.php index 09defd452..b94a24298 100644 --- a/app/SQL/install.sql.mysql.php +++ b/app/SQL/install.sql.mysql.php @@ -23,7 +23,7 @@ CREATE TABLE IF NOT EXISTS `%1$sfeed` ( `httpAuth` varchar(511) DEFAULT NULL, `error` boolean DEFAULT 0, `keep_history` MEDIUMINT NOT NULL DEFAULT -2, -- v0.7 - `ttl` INT NOT NULL DEFAULT -2, -- v0.7.3 + `ttl` INT NOT NULL DEFAULT 0, -- v0.7.3 `cache_nbEntries` int DEFAULT 0, -- v0.7 `cache_nbUnreads` int DEFAULT 0, -- v0.7 PRIMARY KEY (`id`), diff --git a/app/SQL/install.sql.pgsql.php b/app/SQL/install.sql.pgsql.php index 4cfeb2517..23afdb783 100644 --- a/app/SQL/install.sql.pgsql.php +++ b/app/SQL/install.sql.pgsql.php @@ -21,7 +21,7 @@ $SQL_CREATE_TABLES = array( "httpAuth" VARCHAR(511) DEFAULT NULL, "error" smallint DEFAULT 0, "keep_history" INT NOT NULL DEFAULT -2, - "ttl" INT NOT NULL DEFAULT -2, + "ttl" INT NOT NULL DEFAULT 0, "cache_nbEntries" INT DEFAULT 0, "cache_nbUnreads" INT DEFAULT 0, FOREIGN KEY ("category") REFERENCES "%1$scategory" ("id") ON DELETE SET NULL ON UPDATE CASCADE diff --git a/app/SQL/install.sql.sqlite.php b/app/SQL/install.sql.sqlite.php index d485e2120..d8e670bc8 100644 --- a/app/SQL/install.sql.sqlite.php +++ b/app/SQL/install.sql.sqlite.php @@ -20,7 +20,7 @@ $SQL_CREATE_TABLES = array( `httpAuth` varchar(511) DEFAULT NULL, `error` boolean DEFAULT 0, `keep_history` MEDIUMINT NOT NULL DEFAULT -2, - `ttl` INT NOT NULL DEFAULT -2, + `ttl` INT NOT NULL DEFAULT 0, `cache_nbEntries` int DEFAULT 0, `cache_nbUnreads` int DEFAULT 0, FOREIGN KEY (`category`) REFERENCES `category`(`id`) ON DELETE SET NULL ON UPDATE CASCADE, diff --git a/app/i18n/cz/admin.php b/app/i18n/cz/admin.php index dbfebd4c9..d414ffd07 100644 --- a/app/i18n/cz/admin.php +++ b/app/i18n/cz/admin.php @@ -175,12 +175,15 @@ return array( 'user' => array( 'articles_and_size' => '%s článků (%s)', 'create' => 'Vytvořit nového uživatele', + 'delete_users' => 'Delete user', // TODO 'language' => 'Jazyk', 'number' => 'Zatím je vytvořen %d účet', 'numbers' => 'Zatím je vytvořeno %d účtů', 'password_form' => 'Heslo<br /><small>(pro přihlášení webovým formulářem)</small>', 'password_format' => 'Alespoň 7 znaků', + 'selected' => 'Selected user', // TODO 'title' => 'Správa uživatelů', + 'update_users' => 'Update user', // TODO 'user_list' => 'Seznam uživatelů', 'username' => 'Přihlašovací jméno', 'users' => 'Uživatelé', diff --git a/app/i18n/cz/conf.php b/app/i18n/cz/conf.php index 9a4410679..649724e80 100644 --- a/app/i18n/cz/conf.php +++ b/app/i18n/cz/conf.php @@ -37,6 +37,7 @@ return array( 'no_limit' => 'Bez limitu', 'thin' => 'Tenká', ), + 'show_nav_buttons' => 'Show the navigation buttons', //TODO ), 'query' => array( '_' => 'Uživatelské dotazy', @@ -148,6 +149,7 @@ return array( 'collapse_article' => 'Srolovat', 'first_article' => 'Skočit na první článek', 'focus_search' => 'Hledání', + 'global_view' => 'Switch to global view', // TODO 'help' => 'Zobrazit documentaci', 'javascript' => 'Pro použití zkratek musí být povolen JavaScript', 'last_article' => 'Skočit na poslední článek', @@ -157,13 +159,17 @@ return array( 'navigation' => 'Navigace', 'navigation_help' => 'Pomocí přepínače "Shift" fungují navigační zkratky v rámci kanálů.<br/>Pomocí přepínače "Alt" fungují v rámci kategorií.', 'next_article' => 'Skočit na další článek', + 'normal_view' => 'Switch to normal view', // TODO 'other_action' => 'Ostatní akce', 'previous_article' => 'Skočit na předchozí článek', + 'reading_view' => 'Switch to reading view', // TODO + 'rss_view' => 'Open RSS view in a new tab', // TODO 'see_on_website' => 'Navštívit původní webovou stránku', 'shift_for_all_read' => '+ <code>shift</code> označí vše jako přečtené', 'title' => 'Zkratky', 'user_filter' => 'Aplikovat uživatelské filtry', 'user_filter_help' => 'Je-li nastaven pouze jeden filtr, bude použit. Další filtry jsou dostupné pomocí jejich čísla.', + 'views' => 'Views', // TODO ), 'user' => array( 'articles_and_size' => '%s článků (%s)', diff --git a/app/i18n/cz/feedback.php b/app/i18n/cz/feedback.php index f7b8d8c73..22eaf77f7 100644 --- a/app/i18n/cz/feedback.php +++ b/app/i18n/cz/feedback.php @@ -101,6 +101,10 @@ return array( '_' => 'Uživatel %s byl smazán', 'error' => 'Uživatele %s nelze smazat', ), + 'updated' => array( + '_' => 'User %s has been updated', // TODO + 'error' => 'User %s has not been updated', // TODO + ), ), 'profile' => array( 'error' => 'Váš profil nelze změnit', diff --git a/app/i18n/cz/gen.php b/app/i18n/cz/gen.php index fcddf452c..288be61ec 100644 --- a/app/i18n/cz/gen.php +++ b/app/i18n/cz/gen.php @@ -19,6 +19,7 @@ return array( 'see_website' => 'Navštívit WWW stránku', 'submit' => 'Odeslat', 'truncate' => 'Smazat všechny články', + 'update' => 'Update', // TODO ), 'auth' => array( 'email' => 'Email', diff --git a/app/i18n/cz/sub.php b/app/i18n/cz/sub.php index 807c249d3..ec77be317 100644 --- a/app/i18n/cz/sub.php +++ b/app/i18n/cz/sub.php @@ -32,12 +32,18 @@ return array( 'description' => 'Popis', 'empty' => 'Kanál je prázdný. Ověřte prosím zda je ještě autorem udržován.', 'error' => 'Vyskytl se problém s kanálem. Ověřte že je vždy dostupný, prosím, a poté jej aktualizujte.', - 'in_main_stream' => 'Zobrazit ve “Všechny kanály”', 'informations' => 'Informace', 'keep_history' => 'Zachovat tento minimální počet článků', 'moved_category_deleted' => 'Po smazání kategorie budou v ní obsažené kanály automaticky přesunuty do <em>%s</em>.', + 'mute' => 'mute', // TODO 'no_selected' => 'Nejsou označeny žádné kanály.', 'number_entries' => '%d článků', + 'priority' => array( + '_' => 'Visibility', // TODO + 'archived' => 'Do not show (archived)', // TODO + 'main_stream' => 'Zobrazit ve “Všechny kanály”', + 'normal' => 'Show in its category', // TODO + ), 'stats' => 'Statistika', 'think_to_add' => 'Můžete přidat kanály.', 'title' => 'Název', diff --git a/app/i18n/de/admin.php b/app/i18n/de/admin.php index bb2c9352d..45bf2de68 100644 --- a/app/i18n/de/admin.php +++ b/app/i18n/de/admin.php @@ -175,12 +175,15 @@ return array( 'user' => array( 'articles_and_size' => '%s Artikel (%s)', 'create' => 'Neuen Benutzer erstellen', + 'delete_users' => 'Delete user', // TODO 'language' => 'Sprache', 'number' => 'Es wurde bis jetzt %d Account erstellt', 'numbers' => 'Es wurden bis jetzt %d Accounts erstellt', 'password_form' => 'Passwort<br /><small>(für die Anmeldemethode per Webformular)</small>', 'password_format' => 'mindestens 7 Zeichen', + 'selected' => 'Selected user', // TODO 'title' => 'Benutzer verwalten', + 'update_users' => 'Update user', // TODO 'user_list' => 'Liste der Benutzer', 'username' => 'Nutzername', 'users' => 'Benutzer', diff --git a/app/i18n/de/conf.php b/app/i18n/de/conf.php index ac7c08e98..9f1edffb9 100644 --- a/app/i18n/de/conf.php +++ b/app/i18n/de/conf.php @@ -37,6 +37,7 @@ return array( 'no_limit' => 'Keine Begrenzung', 'thin' => 'Klein', ), + 'show_nav_buttons' => 'Show the navigation buttons', //TODO ), 'query' => array( '_' => 'Benutzerabfragen', @@ -148,6 +149,7 @@ return array( 'collapse_article' => 'Einklappen', 'first_article' => 'Zum ersten Artikel springen', 'focus_search' => 'Auf das Suchfeld zugreifen', + 'global_view' => 'Switch to global view', // TODO 'help' => 'Dokumentation anzeigen', 'javascript' => 'JavaScript muss aktiviert sein, um Tastaturkürzel benutzen zu können', 'last_article' => 'Zum letzten Artikel springen', @@ -157,13 +159,17 @@ return array( 'navigation' => 'Navigation', 'navigation_help' => 'Mit der "Umschalttaste" finden die Tastenkombination auf Feeds Anwendung.<br/>Mit der "Alt-Taste" finden die Tastenkombination auf Kategorien Anwendung.', 'next_article' => 'Zum nächsten Artikel springen', + 'normal_view' => 'Switch to normal view', // TODO 'other_action' => 'Andere Aktionen', 'previous_article' => 'Zum vorherigen Artikel springen', + 'reading_view' => 'Switch to reading view', // TODO + 'rss_view' => 'Open RSS view in a new tab', // TODO 'see_on_website' => 'Auf der Original-Webseite ansehen', 'shift_for_all_read' => '+ <code>Umschalttaste</code>, um alle Artikel als gelesen zu markieren.', 'title' => 'Tastenkombination', 'user_filter' => 'Auf Benutzerfilter zugreifen', 'user_filter_help' => 'Wenn es nur einen Benutzerfilter gibt, wird dieser verwendet. Ansonsten sind die Filter über ihre Nummer erreichbar.', + 'views' => 'Views', // TODO ), 'user' => array( 'articles_and_size' => '%s Artikel (%s)', diff --git a/app/i18n/de/feedback.php b/app/i18n/de/feedback.php index e2e9a71ba..0ac6efefc 100644 --- a/app/i18n/de/feedback.php +++ b/app/i18n/de/feedback.php @@ -101,6 +101,10 @@ return array( '_' => 'Der Benutzer %s ist gelöscht worden', 'error' => 'Der Benutzer %s kann nicht gelöscht werden', ), + 'updated' => array( + '_' => 'User %s has been updated', // TODO + 'error' => 'User %s has not been updated', // TODO + ), ), 'profile' => array( 'error' => 'Ihr Profil kann nicht geändert werden', diff --git a/app/i18n/de/gen.php b/app/i18n/de/gen.php index bed49a4a4..8df0b1f07 100644 --- a/app/i18n/de/gen.php +++ b/app/i18n/de/gen.php @@ -19,6 +19,7 @@ return array( 'see_website' => 'Webseite ansehen', 'submit' => 'Abschicken', 'truncate' => 'Alle Artikel löschen', + 'update' => 'Update', // TODO ), 'auth' => array( 'email' => 'E-Mail-Adresse', diff --git a/app/i18n/de/sub.php b/app/i18n/de/sub.php index 4ffef4302..6d41d0e5a 100644 --- a/app/i18n/de/sub.php +++ b/app/i18n/de/sub.php @@ -32,12 +32,18 @@ return array( 'description' => 'Beschreibung', 'empty' => 'Dieser Feed ist leer. Bitte stellen Sie sicher, dass er noch gepflegt wird.', 'error' => 'Dieser Feed ist auf ein Problem gestoßen. Bitte stellen Sie sicher, dass er immer lesbar ist und aktualisieren Sie ihn dann.', - 'in_main_stream' => 'In Haupt-Feeds zeigen', 'informations' => 'Information', 'keep_history' => 'Minimale Anzahl an Artikeln, die behalten wird', 'moved_category_deleted' => 'Wenn Sie eine Kategorie entfernen, werden deren Feeds automatisch in die Kategorie <em>%s</em> eingefügt.', + 'mute' => 'mute', // TODO 'no_selected' => 'Kein Feed ausgewählt.', 'number_entries' => '%d Artikel', + 'priority' => array( + '_' => 'Visibility', // TODO + 'archived' => 'Do not show (archived)', // TODO + 'main_stream' => 'In Haupt-Feeds zeigen', + 'normal' => 'Show in its category', // TODO + ), 'stats' => 'Statistiken', 'think_to_add' => 'Sie können Feeds hinzufügen.', 'title' => 'Titel', diff --git a/app/i18n/en/admin.php b/app/i18n/en/admin.php index 187b66a8c..1f857dbab 100644 --- a/app/i18n/en/admin.php +++ b/app/i18n/en/admin.php @@ -175,12 +175,15 @@ return array( 'user' => array( 'articles_and_size' => '%s articles (%s)', 'create' => 'Create new user', + 'delete_users' => 'Delete user', 'language' => 'Language', 'number' => 'There is %d account created', 'numbers' => 'There are %d accounts created', 'password_form' => 'Password<br /><small>(for the Web-form login method)</small>', 'password_format' => 'At least 7 characters', + 'selected' => 'Selected user', 'title' => 'Manage users', + 'update_users' => 'Update user', 'user_list' => 'List of users', 'username' => 'Username', 'users' => 'Users', diff --git a/app/i18n/en/conf.php b/app/i18n/en/conf.php index e4eeb74b7..60231b825 100644 --- a/app/i18n/en/conf.php +++ b/app/i18n/en/conf.php @@ -37,6 +37,7 @@ return array( 'no_limit' => 'No limit', 'thin' => 'Thin', ), + 'show_nav_buttons' => 'Show the navigation buttons', ), 'query' => array( '_' => 'User queries', @@ -148,6 +149,7 @@ return array( 'collapse_article' => 'Collapse', 'first_article' => 'Skip to the first article', 'focus_search' => 'Access search box', + 'global_view' => 'Switch to global view', 'help' => 'Display documentation', 'javascript' => 'JavaScript must be enabled in order to use shortcuts', 'last_article' => 'Skip to the last article', @@ -157,13 +159,17 @@ return array( 'navigation' => 'Navigation', 'navigation_help' => 'With the "Shift" modifier, navigation shortcuts apply on feeds.<br/>With the "Alt" modifier, navigation shortcuts apply on categories.', 'next_article' => 'Skip to the next article', + 'normal_view' => 'Switch to normal view', 'other_action' => 'Other actions', 'previous_article' => 'Skip to the previous article', + 'reading_view' => 'Switch to reading view', + 'rss_view' => 'Open RSS view in a new tab', 'see_on_website' => 'See on original website', 'shift_for_all_read' => '+ <code>shift</code> to mark all articles as read', 'title' => 'Shortcuts', 'user_filter' => 'Access user filters', 'user_filter_help' => 'If there is only one user filter, it is used. Otherwise, filters are accessible by their number.', + 'views' => 'Views', ), 'user' => array( 'articles_and_size' => '%s articles (%s)', diff --git a/app/i18n/en/feedback.php b/app/i18n/en/feedback.php index 334d9a8f5..ad7f87fd9 100644 --- a/app/i18n/en/feedback.php +++ b/app/i18n/en/feedback.php @@ -101,6 +101,10 @@ return array( '_' => 'User %s has been deleted', 'error' => 'User %s cannot be deleted', ), + 'updated' => array( + '_' => 'User %s has been updated', + 'error' => 'User %s has not been updated', + ), ), 'profile' => array( 'error' => 'Your profile cannot be modified', diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index ac48e3486..82cd4da72 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -19,6 +19,7 @@ return array( 'see_website' => 'See website', 'submit' => 'Submit', 'truncate' => 'Delete all articles', + 'update' => 'Update', ), 'auth' => array( 'email' => 'Email address', diff --git a/app/i18n/en/index.php b/app/i18n/en/index.php index a4686de4e..29dccc9ed 100644 --- a/app/i18n/en/index.php +++ b/app/i18n/en/index.php @@ -41,18 +41,18 @@ return array( 'mark_cat_read' => 'Mark category as read', 'mark_feed_read' => 'Mark feed as read', 'newer_first' => 'Newer first', - 'non-starred' => 'Show all but favourites', + 'non-starred' => 'Show non-favourites', 'normal_view' => 'Normal view', 'older_first' => 'Oldest first', 'queries' => 'User queries', - 'read' => 'Show only read', + 'read' => 'Show read', 'reader_view' => 'Reading view', 'rss_view' => 'RSS feed', 'search_short' => 'Search', - 'starred' => 'Show only favourites', + 'starred' => 'Show favourites', 'stats' => 'Statistics', 'subscription' => 'Subscriptions management', - 'unread' => 'Show only unread', + 'unread' => 'Show unread', ), 'share' => 'Share', 'tag' => array( diff --git a/app/i18n/en/sub.php b/app/i18n/en/sub.php index 47b15ae7a..b9bae7955 100644 --- a/app/i18n/en/sub.php +++ b/app/i18n/en/sub.php @@ -32,12 +32,18 @@ return array( 'description' => 'Description', 'empty' => 'This feed is empty. Please verify that it is still maintained.', 'error' => 'This feed has encountered a problem. Please verify that it is always reachable then update it.', - 'in_main_stream' => 'Show in main stream', 'informations' => 'Information', 'keep_history' => 'Minimum number of articles to keep', 'moved_category_deleted' => 'When you delete a category, its feeds are automatically classified under <em>%s</em>.', + 'mute' => 'mute', 'no_selected' => 'No feed selected.', 'number_entries' => '%d articles', + 'priority' => array( + '_' => 'Visibility', + 'archived' => 'Do not show (archived)', + 'main_stream' => 'Show in main stream', + 'normal' => 'Show in its category', + ), 'stats' => 'Statistics', 'think_to_add' => 'You may add some feeds.', 'title' => 'Title', diff --git a/app/i18n/es/admin.php b/app/i18n/es/admin.php index 93b1e6e5c..2884721c7 100755 --- a/app/i18n/es/admin.php +++ b/app/i18n/es/admin.php @@ -175,12 +175,15 @@ return array( 'user' => array( 'articles_and_size' => '%s articles (%s)', 'create' => 'Crear nuevo usuario', + 'delete_users' => 'Delete user', // TODO 'language' => 'Idioma', 'number' => 'Hay %d cuenta creada', 'numbers' => 'Hay %d cuentas creadas', 'password_form' => 'Contraseña<br /><small>(para el método de identificación por formulario web)</small>', 'password_format' => 'Mínimo de 7 caracteres', + 'selected' => 'Selected user', // TODO 'title' => 'Administrar usuarios', + 'update_users' => 'Update user', // TODO 'user_list' => 'Lista de usuarios', 'username' => 'Nombre de usuario', 'users' => 'Usuarios', diff --git a/app/i18n/es/conf.php b/app/i18n/es/conf.php index aad5cc66d..65858fefe 100755 --- a/app/i18n/es/conf.php +++ b/app/i18n/es/conf.php @@ -37,6 +37,7 @@ return array( 'no_limit' => 'Sin límite', 'thin' => 'Estrecho', ), + 'show_nav_buttons' => 'Show the navigation buttons', //TODO ), 'query' => array( '_' => 'Consultas de usuario', @@ -148,6 +149,7 @@ return array( 'collapse_article' => 'Contraer', 'first_article' => 'Saltar al primer artículo', 'focus_search' => 'Acceso a la casilla de búsqueda', + 'global_view' => 'Switch to global view', // TODO 'help' => 'Mostrar documentación', 'javascript' => 'JavaScript debe estar activado para poder usar atajos de teclado', 'last_article' => 'Saltar al último artículo', @@ -157,13 +159,17 @@ return array( 'navigation' => 'Navegación', 'navigation_help' => 'Con el modificador "Mayúsculas" es posible usar los atajos de teclado en las fuentes.<br/>Con el modificador "Alt" es posible aplicar los atajos de teclado en las categorías.', 'next_article' => 'Saltar al siguiente artículo', + 'normal_view' => 'Switch to normal view', // TODO 'other_action' => 'Otras acciones', 'previous_article' => 'Saltar al artículo anterior', + 'reading_view' => 'Switch to reading view', // TODO + 'rss_view' => 'Open RSS view in a new tab', // TODO 'see_on_website' => 'Ver en la web original', 'shift_for_all_read' => '+ <code>mayúsculas</code> para marcar todos los artículos como leídos', 'title' => 'Atajos de teclado', 'user_filter' => 'Acceso a filtros de usuario', 'user_filter_help' => 'Si solo hay un filtro de usuario, ese será el que se use. En caso contrario, los filtros están accesibles por su númeración.', + 'views' => 'Views', // TODO ), 'user' => array( 'articles_and_size' => '%s artículos (%s)', diff --git a/app/i18n/es/feedback.php b/app/i18n/es/feedback.php index 136e70179..7b23f1a8d 100755 --- a/app/i18n/es/feedback.php +++ b/app/i18n/es/feedback.php @@ -101,6 +101,10 @@ return array( '_' => 'El usuario %s ha sido eliminado', 'error' => 'El usuario %s no ha podido ser eliminado', ), + 'updated' => array( + '_' => 'User %s has been updated', // TODO + 'error' => 'User %s has not been updated', // TODO + ), ), 'profile' => array( 'error' => 'Tu perfil no puede ser modificado', diff --git a/app/i18n/es/gen.php b/app/i18n/es/gen.php index 32fbcdaee..fe495a63f 100755 --- a/app/i18n/es/gen.php +++ b/app/i18n/es/gen.php @@ -19,6 +19,7 @@ return array( 'see_website' => 'Ver web', 'submit' => 'Enviar', 'truncate' => 'Borrar todos los artículos', + 'update' => 'Update', // TODO ), 'auth' => array( 'email' => 'Correo electrónico', diff --git a/app/i18n/es/sub.php b/app/i18n/es/sub.php index 72eb06eb7..091c1e3e3 100755 --- a/app/i18n/es/sub.php +++ b/app/i18n/es/sub.php @@ -27,12 +27,18 @@ return array( 'description' => 'Descripción', 'empty' => 'La fuente está vacía. Por favor, verifica que siga activa.', 'error' => 'Hay un problema con esta fuente. Por favor, veritica que esté disponible y prueba de nuevo.', - 'in_main_stream' => 'Mostrar en salida principal', 'informations' => 'Información', 'keep_history' => 'Número mínimo de artículos a conservar', 'moved_category_deleted' => 'Al borrar una categoría todas sus fuentes pasan automáticamente a la categoría <em>%s</em>.', + 'mute' => 'mute', // TODO 'no_selected' => 'No hay funentes seleccionadas.', 'number_entries' => '%d artículos', + 'priority' => array( + '_' => 'Visibility', // TODO + 'archived' => 'Do not show (archived)', // TODO + 'main_stream' => 'Mostrar en salida principal', + 'normal' => 'Show in its category', // TODO + ), 'stats' => 'Estadísticas', 'think_to_add' => 'Puedes añadir fuentes.', 'title' => 'Título', diff --git a/app/i18n/fr/admin.php b/app/i18n/fr/admin.php index b2bc48209..6c582d719 100644 --- a/app/i18n/fr/admin.php +++ b/app/i18n/fr/admin.php @@ -175,12 +175,15 @@ return array( 'user' => array( 'articles_and_size' => '%s articles (%s)', 'create' => 'Créer un nouvel utilisateur', + 'delete_users' => 'Supprimer un utilisateur', 'language' => 'Langue', 'number' => '%d compte a déjà été créé', 'numbers' => '%d comptes ont déjà été créés', 'password_form' => 'Mot de passe<br /><small>(pour connexion par formulaire)</small>', 'password_format' => '7 caractères minimum', + 'selected' => 'Utilisateur sélectionné', 'title' => 'Gestion des utilisateurs', + 'update_users' => 'Mettre à jour un utilisateur', 'user_list' => 'Liste des utilisateurs', 'username' => 'Nom d’utilisateur', 'users' => 'Utilisateurs', diff --git a/app/i18n/fr/conf.php b/app/i18n/fr/conf.php index 0c8188623..b4c39e1ca 100644 --- a/app/i18n/fr/conf.php +++ b/app/i18n/fr/conf.php @@ -37,6 +37,7 @@ return array( 'no_limit' => 'Pas de limite', 'thin' => 'Fine', ), + 'show_nav_buttons' => 'Afficher les boutons de navigation', ), 'query' => array( '_' => 'Filtres utilisateurs', @@ -148,6 +149,7 @@ return array( 'collapse_article' => 'Refermer', 'first_article' => 'Passer au premier article', 'focus_search' => 'Accéder à la recherche', + 'global_view' => 'Basculer vers la vue globale', 'help' => 'Afficher la documentation', 'javascript' => 'Le JavaScript doit être activé pour pouvoir profiter des raccourcis.', 'last_article' => 'Passer au dernier article', @@ -157,13 +159,17 @@ return array( 'navigation' => 'Navigation', 'navigation_help' => 'Avec le modificateur "Shift", les raccourcis de navigation s’appliquent aux flux.<br/>Avec le modificateur "Alt", les raccourcis de navigation s’appliquent aux catégories.', 'next_article' => 'Passer à l’article suivant', + 'normal_view' => 'Basculer vers la vue normale', 'other_action' => 'Autres actions', 'previous_article' => 'Passer à l’article précédent', + 'reading_view' => 'Basculer vers la vue lecture', + 'rss_view' => 'Ouvrir le flux RSS dans un nouvel onglet', 'see_on_website' => 'Voir sur le site d’origine', 'shift_for_all_read' => '+ <code>shift</code> pour marquer tous les articles comme lus', 'title' => 'Raccourcis', '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.', + 'views' => 'Vues', ), 'user' => array( 'articles_and_size' => '%s articles (%s)', diff --git a/app/i18n/fr/feedback.php b/app/i18n/fr/feedback.php index aa19cd02b..1abf1b518 100644 --- a/app/i18n/fr/feedback.php +++ b/app/i18n/fr/feedback.php @@ -101,6 +101,10 @@ return array( '_' => 'L’utilisateur %s a été supprimé.', 'error' => 'L’utilisateur %s ne peut pas être supprimé.', ), + 'updated' => array( + '_' => 'L’utilisateur %s a été mis à jour', + 'error' => 'L’utilisateur %s n’a pas été mis à jour', + ), ), 'profile' => array( 'error' => 'Votre profil n’a pas pu être mis à jour', diff --git a/app/i18n/fr/gen.php b/app/i18n/fr/gen.php index 61a24602a..beb578543 100644 --- a/app/i18n/fr/gen.php +++ b/app/i18n/fr/gen.php @@ -19,6 +19,7 @@ return array( 'see_website' => 'Voir le site', 'submit' => 'Valider', 'truncate' => 'Supprimer tous les articles', + 'update' => 'Mettre à jour', ), 'auth' => array( 'email' => 'Adresse courriel', diff --git a/app/i18n/fr/index.php b/app/i18n/fr/index.php index 62eedc280..0a3a4abb3 100644 --- a/app/i18n/fr/index.php +++ b/app/i18n/fr/index.php @@ -41,7 +41,7 @@ return array( 'mark_cat_read' => 'Marquer la catégorie comme lue', 'mark_feed_read' => 'Marquer le flux comme lu', 'newer_first' => 'Plus récents en premier', - 'non-starred' => 'Afficher tout sauf les favoris', + 'non-starred' => 'Afficher les non-favoris', 'normal_view' => 'Vue normale', 'older_first' => 'Plus anciens en premier', 'queries' => 'Filtres utilisateurs', diff --git a/app/i18n/fr/sub.php b/app/i18n/fr/sub.php index 607863c8f..04be55aa5 100644 --- a/app/i18n/fr/sub.php +++ b/app/i18n/fr/sub.php @@ -32,12 +32,18 @@ return array( 'description' => 'Description', 'empty' => 'Ce flux est vide. Veuillez vérifier qu’il est toujours maintenu.', 'error' => 'Ce flux a rencontré un problème. Veuillez vérifier qu’il est toujours accessible puis actualisez-le.', - 'in_main_stream' => 'Afficher dans le flux principal', 'informations' => 'Informations', 'keep_history' => 'Nombre minimum d’articles à conserver', 'moved_category_deleted' => 'Lors de la suppression d’une catégorie, ses flux seront automatiquement classés dans <em>%s</em>.', + 'mute' => 'muet', 'no_selected' => 'Aucun flux sélectionné.', 'number_entries' => '%d articles', + 'priority' => array( + '_' => 'Visibilité', + 'archived' => 'Ne pas afficher (archivé)', + 'main_stream' => 'Afficher dans le flux principal', + 'normal' => 'Afficher dans sa catégorie', + ), 'stats' => 'Statistiques', 'think_to_add' => 'Vous pouvez ajouter des flux.', 'title' => 'Titre', diff --git a/app/i18n/he/admin.php b/app/i18n/he/admin.php index b7c83c828..2840213c9 100644 --- a/app/i18n/he/admin.php +++ b/app/i18n/he/admin.php @@ -175,12 +175,15 @@ return array( 'user' => array( 'articles_and_size' => '%s articles (%s)', // @todo 'create' => 'יצירת משתמש חדש', + 'delete_users' => 'Delete user', // TODO 'language' => 'שפה', 'number' => 'There is %d account created', // @todo 'numbers' => 'There are %d accounts created', // @todo 'password_form' => 'סיסמה<br /><small>(לשימוש בטפוס ההרשמה)</small>', 'password_format' => 'At least 7 characters', // @todo + 'selected' => 'Selected user', // TODO 'title' => 'Manage users', // @todo + 'update_users' => 'Update user', // TODO 'user_list' => 'רשימת משתמשים', 'username' => 'שם משתמש', 'users' => 'משתמשים', diff --git a/app/i18n/he/conf.php b/app/i18n/he/conf.php index ba9985d45..50d1936a8 100644 --- a/app/i18n/he/conf.php +++ b/app/i18n/he/conf.php @@ -37,6 +37,7 @@ return array( 'no_limit' => 'ללא הגבלה', 'thin' => 'צר', ), + 'show_nav_buttons' => 'Show the navigation buttons', //TODO ), 'query' => array( '_' => 'שאילתות', @@ -145,6 +146,7 @@ return array( 'collapse_article' => 'כיווץ', 'first_article' => 'דילוג למאמר הראשון', 'focus_search' => 'גישה לתיבת החיפוש', + 'global_view' => 'Switch to global view', // TODO 'help' => 'הצגת התיעוד', 'javascript' => 'חובה להפעיל JavaScript על מנת לעשות שימוש בקיצורי דרך', 'last_article' => 'דילוג למאמר האחרון', @@ -154,13 +156,17 @@ return array( 'navigation' => 'ניווט', 'navigation_help' => 'בעזרת מקש השיפט קיצורי דרך חלים על הזנות .<br/>עם מקש האלט הם חלים על קטגוריות.', 'next_article' => 'דילוג למאמר הבא', + 'normal_view' => 'Switch to normal view', // TODO 'other_action' => 'פעולות אחרות', 'previous_article' => 'דילוג למאמר הקודם', + 'reading_view' => 'Switch to reading view', // TODO + 'rss_view' => 'Open RSS view in a new tab', // TODO 'see_on_website' => 'ראו את המקור באתר', 'shift_for_all_read' => '+ <code>shift</code> על מנת לסמן את כל המאמרים כנקראו', 'title' => 'קיצורי דרך', 'user_filter' => 'גישה למססנים', 'user_filter_help' => 'אם יש רק מזנן אחד הוא יהיה בשימוש. אחרת המסננים ישמשו על בסיס המספר שלהם.', + 'views' => 'Views', // TODO ), 'user' => array( 'articles_and_size' => '%s articles (%s)', // @todo diff --git a/app/i18n/he/feedback.php b/app/i18n/he/feedback.php index 9a72b2ba0..f773ff270 100644 --- a/app/i18n/he/feedback.php +++ b/app/i18n/he/feedback.php @@ -102,6 +102,10 @@ return array( '_' => 'המשתמש %s נמחק', 'error' => 'User %s cannot be deleted', // @todo ), + 'updated' => array( + '_' => 'User %s has been updated', // TODO + 'error' => 'User %s has not been updated', // TODO + ), ), 'profile' => array( 'error' => 'Your profile cannot be modified', // @todo diff --git a/app/i18n/he/gen.php b/app/i18n/he/gen.php index cacc8eaed..c4262ab66 100644 --- a/app/i18n/he/gen.php +++ b/app/i18n/he/gen.php @@ -19,6 +19,7 @@ return array( 'see_website' => 'ראו אתר', 'submit' => 'אישור', 'truncate' => 'מחיקת כל המאמרים', + 'update' => 'Update', // TODO ), 'auth' => array( 'email' => 'Email address', // @todo diff --git a/app/i18n/he/sub.php b/app/i18n/he/sub.php index 333de0edf..849a1d5bd 100644 --- a/app/i18n/he/sub.php +++ b/app/i18n/he/sub.php @@ -32,12 +32,18 @@ return array( 'description' => 'תיאור', 'empty' => 'הזנה זו ריקה. אנא ודאו שהיא עדיין מתוחזקת.', 'error' => 'הזנה זו נתקלה בשגיאה, אנא ודאו שהיא תקינה ואז נסו שנית.', - 'in_main_stream' => 'הצגה בזרם המרכזי', 'informations' => 'מידע', 'keep_history' => 'מסםר מינימלי של מאמרים לשמור', 'moved_category_deleted' => 'כאשר הקטגוריה נמחקת ההזנות שבתוכה אוטומטית מקוטלגות תחת <em>%s</em>.', + 'mute' => 'mute', // TODO 'no_selected' => 'אף הזנה לא נבחרה.', 'number_entries' => '%d מאמרים', + 'priority' => array( + '_' => 'Visibility', // TODO + 'archived' => 'Do not show (archived)', // TODO + 'main_stream' => 'הצגה בזרם המרכזי', + 'normal' => 'Show in its category', // TODO + ), 'stats' => 'סטטיסטיקות', 'think_to_add' => 'ניתן להוסיף הזנות חדשות.', 'title' => 'כותרת', diff --git a/app/i18n/it/admin.php b/app/i18n/it/admin.php index 0248d9317..a3034777f 100644 --- a/app/i18n/it/admin.php +++ b/app/i18n/it/admin.php @@ -175,12 +175,15 @@ return array( 'user' => array( 'articles_and_size' => '%s articoli (%s)', 'create' => 'Crea nuovo utente', + 'delete_users' => 'Delete user', // TODO 'language' => 'Lingua', 'number' => ' %d profilo utente creato', 'numbers' => 'Sono presenti %d profili utente', 'password_form' => 'Password<br /><small>(per il login classico)</small>', 'password_format' => 'Almeno 7 caratteri', + 'selected' => 'Selected user', // TODO 'title' => 'Gestione utenti', + 'update_users' => 'Update user', // TODO 'user_list' => 'Lista utenti', 'username' => 'Nome utente', 'users' => 'Utenti', diff --git a/app/i18n/it/conf.php b/app/i18n/it/conf.php index 15837ae8a..9e20236f1 100644 --- a/app/i18n/it/conf.php +++ b/app/i18n/it/conf.php @@ -37,6 +37,7 @@ return array( 'no_limit' => 'Nessun limite', 'thin' => 'Stretto', ), + 'show_nav_buttons' => 'Show the navigation buttons', //TODO ), 'query' => array( '_' => 'Ricerche personali', @@ -148,6 +149,7 @@ return array( 'collapse_article' => 'Collassa articoli', 'first_article' => 'Salta al primo articolo', 'focus_search' => 'Modulo di ricerca', + 'global_view' => 'Switch to global view', // TODO 'help' => 'Mostra documentazione', 'javascript' => 'JavaScript deve essere abilitato per poter usare i comandi da tastiera', 'last_article' => 'Salta all ultimo articolo', @@ -157,13 +159,17 @@ return array( 'navigation' => 'Navigazione', 'navigation_help' => 'Con il tasto "Shift" i comandi di navigazione verranno applicati ai feeds.<br/>Con il tasto "Alt" i comandi di navigazione verranno applicati alle categorie.', 'next_article' => 'Salta al contenuto successivo', + 'normal_view' => 'Switch to normal view', // TODO 'other_action' => 'Altre azioni', 'previous_article' => 'Salta al contenuto precedente', + 'reading_view' => 'Switch to reading view', // TODO + 'rss_view' => 'Open RSS view in a new tab', // TODO 'see_on_website' => 'Vai al sito fonte', 'shift_for_all_read' => '+ <code>shift</code> per segnare tutti gli articoli come letti', 'title' => 'Comandi da tastiera', 'user_filter' => 'Accedi alle ricerche personali', 'user_filter_help' => 'Se è presente una sola ricerca personale verrà usata quella, altrimenti usare anche il numero associato.', + 'views' => 'Views', // TODO ), 'user' => array( 'articles_and_size' => '%s articoli (%s)', diff --git a/app/i18n/it/feedback.php b/app/i18n/it/feedback.php index 8f3cf3ed6..d702eb448 100644 --- a/app/i18n/it/feedback.php +++ b/app/i18n/it/feedback.php @@ -101,6 +101,10 @@ return array( '_' => 'Utente %s cancellato', 'error' => 'Utente %s non cancellato', ), + 'updated' => array( + '_' => 'User %s has been updated', // TODO + 'error' => 'User %s has not been updated', // TODO + ), ), 'profile' => array( 'error' => 'Il tuo profilo non può essere modificato', diff --git a/app/i18n/it/gen.php b/app/i18n/it/gen.php index ccc8c0e7c..d4f83735a 100644 --- a/app/i18n/it/gen.php +++ b/app/i18n/it/gen.php @@ -19,6 +19,7 @@ return array( 'see_website' => 'Vai al sito', 'submit' => 'Conferma', 'truncate' => 'Cancella tutti gli articoli', + 'update' => 'Update', // TODO ), 'auth' => array( 'email' => 'Indirizzo email', diff --git a/app/i18n/it/sub.php b/app/i18n/it/sub.php index fe18855fb..698e64481 100644 --- a/app/i18n/it/sub.php +++ b/app/i18n/it/sub.php @@ -32,12 +32,18 @@ return array( 'description' => 'Descrizione', 'empty' => 'Questo feed non contiene articoli. Per favore verifica il sito direttamente.', 'error' => 'Questo feed ha generato un errore. Per favore verifica se ancora disponibile.', - 'in_main_stream' => 'Mostra in homepage', 'informations' => 'Informazioni', 'keep_history' => 'Numero minimo di articoli da mantenere', 'moved_category_deleted' => 'Cancellando una categoria i feed al suo interno verranno classificati automaticamente come <em>%s</em>.', + 'mute' => 'mute', // TODO 'no_selected' => 'Nessun feed selezionato.', 'number_entries' => '%d articoli', + 'priority' => array( + '_' => 'Visibility', // TODO + 'archived' => 'Do not show (archived)', // TODO + 'main_stream' => 'Mostra in homepage', // TODO + 'normal' => 'Show in its category', // TODO + ), 'stats' => 'Statistiche', 'think_to_add' => 'Aggiungi feed.', 'title' => 'Titolo', diff --git a/app/i18n/kr/admin.php b/app/i18n/kr/admin.php index 9781fb640..f9e9c9a8e 100644 --- a/app/i18n/kr/admin.php +++ b/app/i18n/kr/admin.php @@ -112,13 +112,13 @@ return array( ), 'title' => '확장 기능', 'user' => '사용자 확장 기능', - 'community' => 'Available community extensions', // @todo translate - 'name' => 'Name', // @todo translate - 'version' => 'Version', // @todo translate - 'description' => 'Description', // @todo translate - 'author' => 'Author', // @todo translate - 'latest' => 'Installed', // @todo translate - 'update' => 'Update available', // @todo translate + 'community' => '사용 가능한 커뮤니티 확장 기능들', + 'name' => '이름', + 'version' => '버전', + 'description' => '설명', + 'author' => '제작자', + 'latest' => '설치됨', + 'update' => '업데이트 있음', ), 'stats' => array( '_' => '통계', @@ -175,12 +175,15 @@ return array( 'user' => array( 'articles_and_size' => '%s 개의 글 (%s)', 'create' => '새 사용자 생성', + 'delete_users' => 'Delete user', // TODO 'language' => '언어', 'number' => '%d 개의 계정이 생성되었습니다', 'numbers' => '%d 개의 계정이 생성되었습니다', 'password_form' => '암호<br /><small>(웹폼 로그인 방식 사용시)</small>', 'password_format' => '7 글자 이상이어야 합니다', + 'selected' => 'Selected user', // TODO 'title' => '사용자 관리', + 'update_users' => 'Update user', // TODO 'user_list' => '사용자 목록', 'username' => '사용자 이름', 'users' => '전체 사용자', diff --git a/app/i18n/kr/conf.php b/app/i18n/kr/conf.php index 35d412078..31b042f57 100644 --- a/app/i18n/kr/conf.php +++ b/app/i18n/kr/conf.php @@ -37,6 +37,7 @@ return array( 'no_limit' => '제한 없음', 'thin' => '얇음', ), + 'show_nav_buttons' => 'Show the navigation buttons', //TODO ), 'query' => array( '_' => '사용자 쿼리', @@ -148,6 +149,7 @@ return array( 'collapse_article' => '접기', 'first_article' => '첫 글 보기', 'focus_search' => '검색창 사용하기', + 'global_view' => '전체 모드로 전환', 'help' => '도움말 보기', 'javascript' => '단축키를 사용하기 위해선 자바스크립트를 사용하도록 설정하여야 합니다', 'last_article' => '마지막 글 보기', @@ -157,13 +159,17 @@ return array( 'navigation' => '탐색', 'navigation_help' => '"Shift" 키를 누른 상태에선 탐색 단축키가 피드에 적용됩니다.<br/>"Alt" 키를 누른 상태에선 탐색 단축키가 카테고리에 적용됩니다.', 'next_article' => '다음 글 보기', + 'normal_view' => '일반 모드로 전환', 'other_action' => '다른 동작', 'previous_article' => '이전 글 보기', + 'reading_view' => '읽기 모드로 전환', + 'rss_view' => '새 탭에서 RSS 피드 열기', 'see_on_website' => '글이 게재된 웹사이트에서 보기', 'shift_for_all_read' => '+ <code>shift</code>를 누른 상태에선 모두 읽음으로 표시', 'title' => '단축키', 'user_filter' => '사용자 필터 사용하기', 'user_filter_help' => '사용자 필터가 하나만 설정되어 있다면 해당 필터를 사용하고, 그렇지 않다면 필터를 번호로 선택할 수 있습니다.', + 'views' => '표시', ), 'user' => array( 'articles_and_size' => '%s 개의 글 (%s)', diff --git a/app/i18n/kr/feedback.php b/app/i18n/kr/feedback.php index a70923761..bccf1aac0 100644 --- a/app/i18n/kr/feedback.php +++ b/app/i18n/kr/feedback.php @@ -51,7 +51,7 @@ return array( 'zip_error' => 'ZIP 파일을 불러오는 동안 문제가 발생했습니다.', ), 'sub' => array( - 'actualize' => 'Updating', + 'actualize' => '피드를 가져오는 중입니다', 'category' => array( 'created' => '%s 카테고리가 생성되었습니다.', 'deleted' => '카테고리가 삭제되었습니다.', @@ -101,6 +101,10 @@ return array( '_' => '%s 사용자를 삭제했습니다', 'error' => '%s 사용자를 삭제할 수 없습니다', ), + 'updated' => array( + '_' => 'User %s has been updated', // TODO + 'error' => 'User %s has not been updated', // TODO + ), ), 'profile' => array( 'error' => '프로필을 변경할 수 없습니다', diff --git a/app/i18n/kr/gen.php b/app/i18n/kr/gen.php index 8997ba14b..4fb6c92ff 100644 --- a/app/i18n/kr/gen.php +++ b/app/i18n/kr/gen.php @@ -19,6 +19,7 @@ return array( 'see_website' => '웹사이트 열기', 'submit' => '설정 저장', 'truncate' => '모든 글 삭제', + 'update' => 'Update', // TODO ), 'auth' => array( 'email' => '메일 주소', diff --git a/app/i18n/kr/sub.php b/app/i18n/kr/sub.php index b8f2385b3..e11d4588f 100644 --- a/app/i18n/kr/sub.php +++ b/app/i18n/kr/sub.php @@ -2,8 +2,8 @@ return array( 'api' => array( - 'documentation' => 'Copy the following URL to use it within an external tool.',// TODO - 'title' => 'API',// TODO + 'documentation' => '외부 도구에서 API를 사용하기 위해서 아래 URL을 사용하세요.', + 'title' => 'API', ), 'bookmarklet' => array( 'documentation' => '이 버튼을 즐겨찾기 막대로 끌어다 놓거나 마우스 오른쪽 클릭으로 나타나는 메뉴에서 "이 링크를 즐겨찾기에 추가"를 선택하세요. 그리고 피드를 구독하길 원하는 페이지에서 "구독하기" 버튼을 클릭하세요.', @@ -32,12 +32,18 @@ return array( 'description' => '설명', 'empty' => '이 피드는 비어있습니다. 피드가 계속 운영되고 있는지 확인하세요.', 'error' => '이 피드에 문제가 발생했습니다. 이 피드에 접근 권한이 있는지 확인하세요.', - 'in_main_stream' => '메인 스트림에 표시하기', 'informations' => '정보', 'keep_history' => '최소 유지 글 개수', 'moved_category_deleted' => '카테고리를 삭제하면, 해당 카테고리 아래에 있던 피드들은 자동적으로 <em>%s</em> 아래로 분류됩니다.', + 'mute' => '무기한 새로고침 금지', 'no_selected' => '선택된 피드가 없습니다.', 'number_entries' => '%d 개의 글', + 'priority' => array( + '_' => '표시', + 'archived' => '표시하지 않음 (보관됨)', + 'main_stream' => '메인 스트림에 표시하기', + 'normal' => '피드가 속한 카테고리에만 표시하기', + ), 'stats' => '통계', 'think_to_add' => '피드를 추가할 수 있습니다.', 'title' => '제목', diff --git a/app/i18n/nl/admin.php b/app/i18n/nl/admin.php index 384242b4d..cbdfd6978 100644 --- a/app/i18n/nl/admin.php +++ b/app/i18n/nl/admin.php @@ -175,6 +175,7 @@ return array( 'user' => array( 'articles_and_size' => '%s artikelen (%s)', 'create' => 'Creëer nieuwe gebruiker', + 'delete_users' => 'Delete user', // TODO 'language' => 'Taal', 'number' => 'Er is %d accounts gemaakt', 'numbers' => 'Er zijn %d accounts gemaakt', @@ -185,7 +186,9 @@ return array( 'help' => '0 betekent dat er geen accountlimiet is', 'number' => 'Max aantal accounts', ), + 'selected' => 'Selected user', // TODO 'title' => 'Beheer gebruikers', + 'update_users' => 'Update user', // TODO 'user_list' => 'Lijst van gebruikers ', 'username' => 'Gebruikersnaam', 'users' => 'Gebruikers', diff --git a/app/i18n/nl/conf.php b/app/i18n/nl/conf.php index e4db5ec3d..360e1c5e7 100644 --- a/app/i18n/nl/conf.php +++ b/app/i18n/nl/conf.php @@ -37,6 +37,7 @@ return array( 'no_limit' => 'Geen limiet', 'thin' => 'Smal', ), + 'show_nav_buttons' => 'Show the navigation buttons', //TODO ), 'query' => array( '_' => 'Gebruikers queries (informatie aanvragen)', @@ -148,6 +149,7 @@ return array( 'collapse_article' => 'Inklappen', 'first_article' => 'Spring naar eerste artikel', 'focus_search' => 'Toegang zoek venster', + 'global_view' => 'Switch to global view', // TODO 'help' => 'Toon documentatie', 'javascript' => 'JavaScript moet geactiveerd zijn om verwijzingen te gebruiken', 'last_article' => 'Spring naar laatste artikel', @@ -157,13 +159,17 @@ return array( 'navigation' => 'Navigatie', 'navigation_help' => 'Met de "Shift" toets, kunt u navigatie verwijzingen voor feeds gebruiken.<br/>Met de "Alt" toets, kunt u navigatie verwijzingen voor categoriën gebruiken.', 'next_article' => 'Spring naar volgende artikel', + 'normal_view' => 'Switch to normal view', // TODO 'other_action' => 'Andere acties', 'previous_article' => 'Spring naar vorige artikel', + 'reading_view' => 'Switch to reading view', // TODO + 'rss_view' => 'Open RSS view in a new tab', // TODO 'see_on_website' => 'Bekijk op originale website', 'shift_for_all_read' => '+ <code>shift</code> om alle artikelen als gelezen te markeren', 'title' => 'Verwijzingen', 'user_filter' => 'Toegang gebruikers filters', 'user_filter_help' => 'Als er slechts één gebruikers filter s, dan wordt deze gebruikt. Anders zijn ze toegankelijk met hun nummer.', + 'views' => 'Views', // TODO ), 'user' => array( 'articles_and_size' => '%s artikelen (%s)', diff --git a/app/i18n/nl/feedback.php b/app/i18n/nl/feedback.php index cf1274767..3fabc97b8 100644 --- a/app/i18n/nl/feedback.php +++ b/app/i18n/nl/feedback.php @@ -101,6 +101,10 @@ return array( '_' => 'Gebruiker %s is verwijderd', 'error' => 'Gebruiker %s kan niet worden verwijderd', ), + 'updated' => array( + '_' => 'User %s has been updated', // TODO + 'error' => 'User %s has not been updated', // TODO + ), 'set_registration' => 'Het maximale aantal accounts is vernieuwd.', ), 'profile' => array( diff --git a/app/i18n/nl/gen.php b/app/i18n/nl/gen.php index 3215bdfec..ea3e720b4 100644 --- a/app/i18n/nl/gen.php +++ b/app/i18n/nl/gen.php @@ -19,6 +19,7 @@ return array( 'see_website' => 'Bekijk website', 'submit' => 'Opslaan', 'truncate' => 'Verwijder alle artikelen', + 'update' => 'Update', // TODO ), 'auth' => array( 'email' => 'Email adres', diff --git a/app/i18n/nl/sub.php b/app/i18n/nl/sub.php index ce446778c..6b1ac268b 100644 --- a/app/i18n/nl/sub.php +++ b/app/i18n/nl/sub.php @@ -2,7 +2,7 @@ /* Dutch translation by Wanabo. http://www.nieuwskop.be */ return array( 'api' => array( - 'documentation' => 'Kopieer de volgende URL om hem in een externe toepassing te gebruiken.', + 'documentation' => 'Kopieer de volgende URL om deze in een externe toepassing te gebruiken.', 'title' => 'API', ), 'bookmarklet' => array( @@ -32,12 +32,18 @@ return array( 'description' => 'Omschrijving', 'empty' => 'Deze feed is leeg. Controleer of deze nog actueel is.', 'error' => 'Deze feed heeft problemen. Verifieer a.u.b het doeladres en actualiseer het.', - 'in_main_stream' => 'Zichtbaar in het overzicht', 'informations' => 'Informatie', 'keep_history' => 'Minimum aantal artikelen om te houden', 'moved_category_deleted' => 'Als u een categorie verwijderd, worden de feeds automatisch geclassificeerd onder <em>%s</em>.', + 'mute' => 'mute', // TODO 'no_selected' => 'Geen feed geselecteerd.', 'number_entries' => '%d artikelen', + 'priority' => array( + '_' => 'Visibility', // TODO + 'archived' => 'Do not show (archived)', // TODO + 'main_stream' => 'Zichtbaar in het overzicht', + 'normal' => 'Show in its category', // TODO + ), 'pubsubhubbub' => 'Directe notificaties met PubSubHubbub', 'stats' => 'Statistieken', 'think_to_add' => 'Voeg wat feeds toe.', @@ -49,13 +55,13 @@ return array( 'website' => 'Website URL', ), 'firefox' => array( - 'documentation' => 'Volg de stappen die <a href="https://developer.mozilla.org/en-US/Firefox/Releases/2/Adding_feed_readers_to_Firefox#Adding_a_new_feed_reader_manually">hier</a> beschreven wordem om FreshRSS aan de Firefox-nieuwslezerlijst toe te voegen.', + 'documentation' => 'Volg de stappen die <a href="https://developer.mozilla.org/en-US/Firefox/Releases/2/Adding_feed_readers_to_Firefox#Adding_a_new_feed_reader_manually">hier</a> beschreven worden om FreshRSS aan de Firefox-nieuwslezerlijst toe te voegen.', 'title' => 'Firefox-nieuwslezer', ), 'import_export' => array( 'export' => 'Exporteer', 'export_opml' => 'Exporteer lijst van feeds (OPML)', - 'export_starred' => 'Exporteer je fovorieten', + 'export_starred' => 'Exporteer je favorieten', 'feed_list' => 'Lijst van %s artikelen', 'file_to_import' => 'Bestand om te importeren<br />(OPML, JSON of ZIP)', 'file_to_import_no_zip' => 'Bestand om te importeren<br />(OPML of JSON)', diff --git a/app/i18n/pt-br/admin.php b/app/i18n/pt-br/admin.php index e62718e80..16aa027a8 100644 --- a/app/i18n/pt-br/admin.php +++ b/app/i18n/pt-br/admin.php @@ -175,12 +175,15 @@ return array( 'user' => array( 'articles_and_size' => '%s artigos (%s)', 'create' => 'Criar novo usuário', + 'delete_users' => 'Delete user', // TODO 'language' => 'Idioma', 'number' => 'Há %d conta criada', 'numbers' => 'Há %d contas criadas', 'password_form' => 'Senha<br /><small>(para o login pelo método do formulário)</small>', 'password_format' => 'Ao menos 7 caracteres', + 'selected' => 'Selected user', // TODO 'title' => 'Gerenciar usuários', + 'update_users' => 'Update user', // TODO 'user_list' => 'Lista de usuários', 'username' => 'Usuário', 'users' => 'Usuários', diff --git a/app/i18n/pt-br/conf.php b/app/i18n/pt-br/conf.php index 4eaf599db..71b6afb20 100644 --- a/app/i18n/pt-br/conf.php +++ b/app/i18n/pt-br/conf.php @@ -37,6 +37,7 @@ return array( 'no_limit' => 'Sem lmite', 'thin' => 'Fino', ), + 'show_nav_buttons' => 'Show the navigation buttons', //TODO ), 'query' => array( '_' => 'Queries do usuário', @@ -148,6 +149,7 @@ return array( 'collapse_article' => 'Fechar', 'first_article' => 'Ir para o primeiro artigo', 'focus_search' => 'Acessar a caixa de busca', + 'global_view' => 'Switch to global view', // TODO 'help' => 'Mostrar documentação', 'javascript' => 'JavaScript deve ser habilitado para utilizar atalhos', 'last_article' => 'Ir para o último artigo', @@ -157,13 +159,17 @@ return array( 'navigation' => 'Navegação', 'navigation_help' => 'Com o modificador "Shift", atalhos de navegação aplicam aos feeds.<br/>Com o "Alt" modificador, atalhos de navegação aplicam as categorias.', 'next_article' => 'Pule para o próximo artigo', + 'normal_view' => 'Switch to normal view', // TODO 'other_action' => 'Outras ações', 'previous_article' => 'Pule para o artigo anterior', + 'reading_view' => 'Switch to reading view', // TODO + 'rss_view' => 'Open RSS view in a new tab', // TODO 'see_on_website' => 'Visualize o site original', 'shift_for_all_read' => '+ <code>shift</code> para marcar todos os artigos como lido', 'title' => 'Atalhos', 'user_filter' => 'Acesse filtros de usuário', 'user_filter_help' => 'Se há apenas um filtro, ele é utilizado. Caso contrário, os filtros serão acessíveis pelos seus números.', + 'views' => 'Views', // TODO ), 'user' => array( 'articles_and_size' => '%s artigos (%s)', diff --git a/app/i18n/pt-br/feedback.php b/app/i18n/pt-br/feedback.php index 0959ad38e..932bb72b1 100644 --- a/app/i18n/pt-br/feedback.php +++ b/app/i18n/pt-br/feedback.php @@ -101,6 +101,10 @@ return array( '_' => 'Usuário %s foi deletado', 'error' => 'Usuário %s não pode ser deletado', ), + 'updated' => array( + '_' => 'User %s has been updated', // TODO + 'error' => 'User %s has not been updated', // TODO + ), ), 'profile' => array( 'error' => 'Your profile cannot be modified', diff --git a/app/i18n/pt-br/gen.php b/app/i18n/pt-br/gen.php index 4bc8535d6..fa1532787 100644 --- a/app/i18n/pt-br/gen.php +++ b/app/i18n/pt-br/gen.php @@ -19,6 +19,7 @@ return array( 'see_website' => 'Ver o site', 'submit' => 'Enviar', 'truncate' => 'Deletar todos os artigos', + 'update' => 'Update', // TODO ), 'auth' => array( 'email' => 'Endereço de e-mail', diff --git a/app/i18n/pt-br/sub.php b/app/i18n/pt-br/sub.php index 4249dcabf..09dde718f 100644 --- a/app/i18n/pt-br/sub.php +++ b/app/i18n/pt-br/sub.php @@ -32,12 +32,18 @@ return array( 'description' => 'Descrição', 'empty' => 'Este feed está vazio. Por favor verifique ele ainda é mantido.', 'error' => 'Este feed encontra-se com problema. Por favor verifique se ele ainda está disponível e atualize-o.', - 'in_main_stream' => 'Mostrar na tela principal', 'informations' => 'Informações', 'keep_history' => 'Número mínimo de artigos para manter', 'moved_category_deleted' => 'Quando você deleta uma categoria, seus feeds são automaticamente classificados como <em>%s</em>.', + 'mute' => 'mute', // TODO 'no_selected' => 'Nenhum feed selecionado.', 'number_entries' => '%d artigos', + 'priority' => array( + '_' => 'Visibility', // TODO + 'archived' => 'Do not show (archived)', // TODO + 'main_stream' => 'Mostrar na tela principal', + 'normal' => 'Show in its category', // TODO + ), 'stats' => 'Estatísticas', 'think_to_add' => 'Você deve adicionar alguns feeds.', 'title' => 'Título', diff --git a/app/i18n/ru/admin.php b/app/i18n/ru/admin.php index d877c5006..4f5e937d7 100644 --- a/app/i18n/ru/admin.php +++ b/app/i18n/ru/admin.php @@ -175,12 +175,15 @@ return array( 'user' => array( 'articles_and_size' => '%s статей (%s)', 'create' => 'Создать нового пользователя', + 'delete_users' => 'Delete user', // TODO 'language' => 'Язык', 'number' => 'На данный момент создан %d аккаунт', 'numbers' => 'На данный момент аккаунтов создано: %d', 'password_form' => 'Пароль<br /><small>(для входа через Веб-форму)</small>', 'password_format' => 'Минимум 7 символов', + 'selected' => 'Selected user', // TODO 'title' => 'Управление пользователями', + 'update_users' => 'Update user', // TODO 'user_list' => 'Список пользователей', 'username' => 'Имя пользователя', 'users' => 'Пользователи', diff --git a/app/i18n/ru/conf.php b/app/i18n/ru/conf.php index 9c61754ae..15109dd15 100644 --- a/app/i18n/ru/conf.php +++ b/app/i18n/ru/conf.php @@ -37,6 +37,7 @@ return array( 'no_limit' => 'No limit', 'thin' => 'Thin', ), + 'show_nav_buttons' => 'Show the navigation buttons', //TODO ), 'query' => array( '_' => 'User queries', @@ -148,6 +149,7 @@ return array( 'collapse_article' => 'Collapse', 'first_article' => 'Skip to the first article', 'focus_search' => 'Access search box', + 'global_view' => 'Switch to global view', // TODO 'help' => 'Display documentation', 'javascript' => 'JavaScript must be enabled in order to use shortcuts', 'last_article' => 'Skip to the last article', @@ -157,13 +159,17 @@ return array( 'navigation' => 'Navigation', 'navigation_help' => 'With the "Shift" modifier, navigation shortcuts apply on feeds.<br/>With the "Alt" modifier, navigation shortcuts apply on categories.', 'next_article' => 'Skip to the next article', + 'normal_view' => 'Switch to normal view', // TODO 'other_action' => 'Other actions', 'previous_article' => 'Skip to the previous article', + 'reading_view' => 'Switch to reading view', // TODO + 'rss_view' => 'Open RSS view in a new tab', // TODO 'see_on_website' => 'See on original website', 'shift_for_all_read' => '+ <code>shift</code> to mark all articles as read', 'title' => 'Shortcuts', '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.', + 'views' => 'Views', // TODO ), 'user' => array( 'articles_and_size' => '%s articles (%s)', diff --git a/app/i18n/ru/feedback.php b/app/i18n/ru/feedback.php index ffebd6dc9..9416ed878 100644 --- a/app/i18n/ru/feedback.php +++ b/app/i18n/ru/feedback.php @@ -101,6 +101,10 @@ return array( '_' => 'User %s has been deleted', //TODO 'error' => 'User %s cannot be deleted', //TODO ), + 'updated' => array( + '_' => 'User %s has been updated', // TODO + 'error' => 'User %s has not been updated', // TODO + ), ), 'profile' => array( 'error' => 'Your profile cannot be modified', //TODO diff --git a/app/i18n/ru/gen.php b/app/i18n/ru/gen.php index cc7e8765c..6f9020695 100644 --- a/app/i18n/ru/gen.php +++ b/app/i18n/ru/gen.php @@ -19,6 +19,7 @@ return array( 'see_website' => 'See website', 'submit' => 'Submit', 'truncate' => 'Delete all articles', + 'update' => 'Update', // TODO ), 'auth' => array( 'email' => 'Email address', diff --git a/app/i18n/ru/sub.php b/app/i18n/ru/sub.php index 6a5530de0..9e360630a 100644 --- a/app/i18n/ru/sub.php +++ b/app/i18n/ru/sub.php @@ -32,12 +32,18 @@ return array( 'description' => 'Description',// TODO 'empty' => 'This feed is empty. Please verify that it is still maintained.',// TODO 'error' => 'This feed has encountered a problem. Please verify that it is always reachable then actualize it.',// TODO - 'in_main_stream' => 'Show in main stream',// TODO 'informations' => 'Information',// TODO 'keep_history' => 'Minimum number of articles to keep',// TODO 'moved_category_deleted' => 'When you delete a category, its feeds are automatically classified under <em>%s</em>.',// TODO + 'mute' => 'mute', // TODO 'no_selected' => 'No feed selected.',// TODO 'number_entries' => '%d articles',// TODO + 'priority' => array( + '_' => 'Visibility', // TODO + 'archived' => 'Do not show (archived)', // TODO + 'main_stream' => 'Show in main stream', // TODO + 'normal' => 'Show in its category', // TODO + ), 'stats' => 'Statistics',// TODO 'think_to_add' => 'You may add some feeds.',// TODO 'title' => 'Title',// TODO diff --git a/app/i18n/tr/admin.php b/app/i18n/tr/admin.php index aa3aad7b7..f982bf644 100644 --- a/app/i18n/tr/admin.php +++ b/app/i18n/tr/admin.php @@ -175,12 +175,15 @@ return array( 'user' => array( 'articles_and_size' => '%s makale (%s)', 'create' => 'Yeni kullanıcı oluştur', + 'delete_users' => 'Delete user', // TODO 'language' => 'Dil', 'number' => 'Oluşturulmuş %d hesap var', 'numbers' => 'Oluşturulmuş %d hesap var', 'password_form' => 'Şifre<br /><small>(Tarayıcı girişi için)</small>', 'password_format' => 'En az 7 karakter', + 'selected' => 'Selected user', // TODO 'title' => 'Kullanıcıları yönet', + 'update_users' => 'Update user', // TODO 'user_list' => 'Kullanıcı listesi', 'username' => 'Kullanıcı adı', 'users' => 'Kullanıcılar', diff --git a/app/i18n/tr/conf.php b/app/i18n/tr/conf.php index e4c094be2..596adaf9a 100644 --- a/app/i18n/tr/conf.php +++ b/app/i18n/tr/conf.php @@ -37,6 +37,7 @@ return array( 'no_limit' => 'Sınırsız', 'thin' => 'Zayıf', ), + 'show_nav_buttons' => 'Show the navigation buttons', //TODO ), 'query' => array( '_' => 'Kullanıcı sorguları', @@ -148,6 +149,7 @@ return array( 'collapse_article' => 'Kapat', 'first_article' => 'İlk makaleyi atla', 'focus_search' => 'Arama kutusuna eriş', + 'global_view' => 'Switch to global view', // TODO 'help' => 'Dokümantasyonu göster', 'javascript' => 'Kısayolları kullanabilmek için JavaScript aktif olmalıdır', 'last_article' => 'Son makaleyi atla', @@ -157,13 +159,17 @@ return array( 'navigation' => 'Genel eylemler', 'navigation_help' => '"Shift" tuşu ile kısayollar akışlar için geçerli olur.<br/>"Alt" tuşu ile kısayollar kategoriler için geçerli olur.', 'next_article' => 'Sonraki makaleye geç', + 'normal_view' => 'Switch to normal view', // TODO 'other_action' => 'Diğer eylemler', 'previous_article' => 'Önceki makaleye geç', + 'reading_view' => 'Switch to reading view', // TODO + 'rss_view' => 'Open RSS view in a new tab', // TODO 'see_on_website' => 'Orijinal sitede göster', 'shift_for_all_read' => '+ <code>shift</code> tuşu ile tüm makaleler okundu olarak işaretlenir', 'title' => 'Kısayollar', 'user_filter' => 'Kullanıcı filtrelerine eriş', 'user_filter_help' => 'Eğer tek filtre varsa o kullanılır. Yoksa filtrelerin kendi numaralarıyla kullanılır.', + 'views' => 'Views', // TODO ), 'user' => array( 'articles_and_size' => '%s makale (%s)', diff --git a/app/i18n/tr/feedback.php b/app/i18n/tr/feedback.php index be79630be..8f40e7d85 100644 --- a/app/i18n/tr/feedback.php +++ b/app/i18n/tr/feedback.php @@ -101,6 +101,10 @@ return array( '_' => '%s kullanıcısı silindi', 'error' => '%s kullanıcısı silinemedi', ), + 'updated' => array( + '_' => 'User %s has been updated', // TODO + 'error' => 'User %s has not been updated', // TODO + ), ), 'profile' => array( 'error' => 'Profiliniz düzenlenemedi', diff --git a/app/i18n/tr/gen.php b/app/i18n/tr/gen.php index dcfd12c01..293502e74 100644 --- a/app/i18n/tr/gen.php +++ b/app/i18n/tr/gen.php @@ -19,6 +19,7 @@ return array( 'see_website' => 'Siteyi gör', 'submit' => 'Onayla', 'truncate' => 'Tüm makaleleri sil', + 'update' => 'Update', // TODO ), 'auth' => array( 'email' => 'Email adresleri', diff --git a/app/i18n/tr/sub.php b/app/i18n/tr/sub.php index 0bbaeec5b..871731158 100644 --- a/app/i18n/tr/sub.php +++ b/app/i18n/tr/sub.php @@ -32,12 +32,18 @@ return array( 'description' => 'Tanım', 'empty' => 'Bu akış boş. Lütfen akışın aktif olduğuna emin olun.', 'error' => 'Bu akışda bir hatayla karşılaşıldı. Lütfen akışın sürekli ulaşılabilir olduğuna emin olun.', - 'in_main_stream' => 'Ana akışda göster', 'informations' => 'Bilgi', 'keep_history' => 'En az tutulacak makale sayısı', 'moved_category_deleted' => 'Bir kategoriyi silerseniz, içerisindeki akışlar <em>%s</em> içerisine yerleşir.', + 'mute' => 'mute', // TODO 'no_selected' => 'Hiçbir akış seçilmedi.', 'number_entries' => '%d makale', + 'priority' => array( + '_' => 'Visibility', // TODO + 'archived' => 'Do not show (archived)', // TODO + 'main_stream' => 'Ana akışda göster', + 'normal' => 'Show in its category', // TODO + ), 'stats' => 'İstatistikler', 'think_to_add' => 'Akış ekleyebilirsiniz.', 'title' => 'Başlık', diff --git a/app/i18n/zh-cn/admin.php b/app/i18n/zh-cn/admin.php index ca18bf63d..1072dc972 100644 --- a/app/i18n/zh-cn/admin.php +++ b/app/i18n/zh-cn/admin.php @@ -112,13 +112,13 @@ return array( ), 'title' => '扩展', 'user' => '用户扩展', - 'community' => 'Available community extensions', // @todo translate - 'name' => 'Name', // @todo translate - 'version' => 'Version', // @todo translate - 'description' => 'Description', // @todo translate - 'author' => 'Author', // @todo translate - 'latest' => 'Installed', // @todo translate - 'update' => 'Update available', // @todo translate + 'community' => '可用的社区扩展', + 'name' => '名称', + 'version' => '版本', + 'description' => '描述', + 'author' => '作者', + 'latest' => '已安装', + 'update' => '更新可用', ), 'stats' => array( '_' => '统计', @@ -175,12 +175,15 @@ return array( 'user' => array( 'articles_and_size' => '%s 篇文章 (%s)', 'create' => '创建新用户', + 'delete_users' => 'Delete user', // TODO 'language' => '语言', 'number' => '已有 %d 个帐户', 'numbers' => '已有 %d 个帐户', 'password_form' => '密码<br /><small>(用于 Web-form 登录方式)</small>', 'password_format' => '至少 7 个字符', + 'selected' => 'Selected user', // TODO 'title' => '用户管理', + 'update_users' => 'Update user', // TODO 'user_list' => '用户列表', 'username' => '用户名', 'users' => '用户', diff --git a/app/i18n/zh-cn/conf.php b/app/i18n/zh-cn/conf.php index 1b52ac38f..2e068be42 100644 --- a/app/i18n/zh-cn/conf.php +++ b/app/i18n/zh-cn/conf.php @@ -37,6 +37,7 @@ return array( 'no_limit' => '无限制', 'thin' => '小', ), + 'show_nav_buttons' => 'Show the navigation buttons', //TODO ), 'query' => array( '_' => '自定义查询', @@ -148,6 +149,7 @@ return array( 'collapse_article' => '收起文章', 'first_article' => '跳转到第一篇文章', 'focus_search' => '聚焦到搜索框', + 'global_view' => '切换到全屏视图', 'help' => '显示帮助文档', 'javascript' => '若要使用快捷键,必须启用 JavaScript', 'last_article' => '跳转到最后一篇文章', @@ -157,13 +159,17 @@ return array( 'navigation' => '浏览', 'navigation_help' => '搭配 "Shift" 键,浏览快捷键将生效于 RSS 源。<br/>搭配 "Alt" 键,浏览快捷键将生效于分类。', 'next_article' => '跳转到下一篇文章', + 'normal_view' => '切换到普通视图', 'other_action' => '其他操作', 'previous_article' => '跳转到上一篇文章', + 'reading_view' => '切换到阅读视图', + 'rss_view' => '在新标签中打开 RSS 视图', 'see_on_website' => '在原网站上查看', 'shift_for_all_read' => '+ <code>shift</code> 可以将全部文章设为已读', 'title' => '快捷键', 'user_filter' => '显示自定义查询', 'user_filter_help' => '如果有多个自定义过滤器,则会按照它们的编号依次访问。', + 'views' => '视图', ), 'user' => array( 'articles_and_size' => '%s 篇文章 (%s)', diff --git a/app/i18n/zh-cn/feedback.php b/app/i18n/zh-cn/feedback.php index 4ec833668..a005de0ce 100644 --- a/app/i18n/zh-cn/feedback.php +++ b/app/i18n/zh-cn/feedback.php @@ -101,6 +101,10 @@ return array( '_' => '用户 %s 已删除', 'error' => '用户 %s 删除失败', ), + 'updated' => array( + '_' => 'User %s has been updated', // TODO + 'error' => 'User %s has not been updated', // TODO + ), ), 'profile' => array( 'error' => '你的帐户修改失败', diff --git a/app/i18n/zh-cn/gen.php b/app/i18n/zh-cn/gen.php index caaa388c7..241fce13b 100644 --- a/app/i18n/zh-cn/gen.php +++ b/app/i18n/zh-cn/gen.php @@ -19,6 +19,7 @@ return array( 'see_website' => '查看网站', 'submit' => '提交', 'truncate' => '删除所有文章', + 'update' => 'Update', // TODO ), 'auth' => array( 'email' => 'Email 地址', @@ -42,18 +43,18 @@ return array( ), ), 'date' => array( - 'Apr' => '\\A\\p\\r\\i\\l', - 'Aug' => '\\A\\u\\g\\u\\s\\t', - 'Dec' => '\\D\\e\\c\\e\\m\\b\\e\\r', - 'Feb' => '\\F\\e\\b\\r\\u\\a\\r\\y', - 'Jan' => '\\J\\a\\n\\u\\a\\r\\y', - 'Jul' => '\\J\\u\\l\\y', - 'Jun' => '\\J\\u\\n\\e', - 'Mar' => '\\M\\a\\r\\c\\h', - 'May' => '\\M\\a\\y', - 'Nov' => '\\N\\o\\v\\e\\m\\b\\e\\r', - 'Oct' => '\\O\\c\\t\\o\\b\\e\\r', - 'Sep' => '\\S\\e\\p\\t\\e\\m\\b\\e\\r', + 'Apr' => '\\四\\月', + 'Aug' => '\\八\\月', + 'Dec' => '\\十\\二\\月', + 'Feb' => '\\二\\月', + 'Jan' => '\\一\\月', + 'Jul' => '\\七\\月', + 'Jun' => '\\六\\月', + 'Mar' => '\\三\\月', + 'May' => '\\五\\月', + 'Nov' => '\\十\\一\\月', + 'Oct' => '\\十\\月', + 'Sep' => '\\九\\月', 'apr' => '四月', 'april' => '四月', 'aug' => '八月', @@ -159,7 +160,7 @@ return array( 'previous' => '上一页', ), 'share' => array( - 'Known' => 'Known based sites', + 'Known' => '基于 Known 的站点', 'blogotext' => 'Blogotext', 'diaspora' => 'Diaspora*', 'email' => 'Email', @@ -169,7 +170,7 @@ return array( 'jdh' => 'Journal du hacker', 'mastodon' => 'Mastodon', 'movim' => 'Movim', - 'print' => 'Print', + 'print' => '打印', 'shaarli' => 'Shaarli', 'twitter' => 'Twitter', 'wallabag' => 'wallabag v1', diff --git a/app/i18n/zh-cn/index.php b/app/i18n/zh-cn/index.php index 0d6e8e82d..6729524f5 100644 --- a/app/i18n/zh-cn/index.php +++ b/app/i18n/zh-cn/index.php @@ -41,18 +41,18 @@ return array( 'mark_cat_read' => '此分类设为已读', 'mark_feed_read' => '此源设为已读', 'newer_first' => '由新到旧', - 'non-starred' => '不显示收藏', + 'non-starred' => '显示未收藏', 'normal_view' => '普通视图', 'older_first' => '由旧到新', 'queries' => '自定义查询', - 'read' => '只显示已读', + 'read' => '显示已读', 'reader_view' => '阅读视图', 'rss_view' => 'RSS 源', 'search_short' => '搜索', - 'starred' => '只显示收藏', + 'starred' => '显示收藏', 'stats' => '统计', 'subscription' => '订阅管理', - 'unread' => '只显示未读', + 'unread' => '显示未读', ), 'share' => '分享', 'tag' => array( diff --git a/app/i18n/zh-cn/sub.php b/app/i18n/zh-cn/sub.php index 026f436d7..bf73f82c4 100644 --- a/app/i18n/zh-cn/sub.php +++ b/app/i18n/zh-cn/sub.php @@ -32,12 +32,18 @@ return array( 'description' => '描述', 'empty' => '此源为空。请确认它是否正常更新。', 'error' => '此源遇到一些问题。请在确认是否能正常访问后重试。', - 'in_main_stream' => '在首页中显示', 'informations' => '信息', 'keep_history' => '至少保存的文章数', 'moved_category_deleted' => '删除分类时,其中的 RSS 源会自动归类到 <em>%s</em>', + 'mute' => '暂停', 'no_selected' => '未选择 RSS 源。', 'number_entries' => '%d 篇文章', + 'priority' => array( + '_' => '可见性', + 'archived' => '不显示 (存档)', + 'main_stream' => '在首页中显示', + 'normal' => '在分类中显示', + ), 'stats' => '统计', 'think_to_add' => '你可以添加一些 RSS 源。', 'title' => '标题', diff --git a/app/layout/aside_feed.phtml b/app/layout/aside_feed.phtml index 3e1ee44dd..97c0fb0d9 100644 --- a/app/layout/aside_feed.phtml +++ b/app/layout/aside_feed.phtml @@ -53,7 +53,7 @@ foreach ($feeds as $feed) { $f_active = FreshRSS_Context::isCurrentGet('f_' . $feed->id()); ?> - <li id="f_<?php echo $feed->id(); ?>" class="item feed<?php echo $f_active ? ' active' : ''; ?><?php echo $feed->inError() ? ' error' : ''; ?><?php echo $feed->nbEntries() <= 0 ? ' empty' : ''; ?>" data-unread="<?php echo $feed->nbNotRead(); ?>" data-priority="<?php echo $feed->priority(); ?>"> + <li id="f_<?php echo $feed->id(); ?>" class="item feed<?php echo $f_active ? ' active' : '', $feed->mute() ? ' mute' : ''; ?><?php echo $feed->inError() ? ' error' : ''; ?><?php echo $feed->nbEntries() <= 0 ? ' empty' : ''; ?>" data-unread="<?php echo $feed->nbNotRead(); ?>" data-priority="<?php echo $feed->priority(); ?>"> <div class="dropdown no-mobile"> <div class="dropdown-target"></div> <a class="dropdown-toggle" data-fweb="<?php echo $feed->website(); ?>"><?php echo _i('configure'); ?></a> diff --git a/app/layout/nav_menu.phtml b/app/layout/nav_menu.phtml index 2bc693e5d..ab82c723f 100644 --- a/app/layout/nav_menu.phtml +++ b/app/layout/nav_menu.phtml @@ -131,20 +131,19 @@ <?php $url_output = Minz_Request::currentRequest(); ?> <div class="stick" id="nav_menu_views"> - <?php $url_output['a'] = 'normal'; ?> - <a class="view_normal btn <?php echo $actual_view == 'normal'? 'active' : ''; ?>" title="<?php echo _t('index.menu.normal_view'); ?>" href="<?php echo Minz_Url::display($url_output); ?>"> - <?php echo _i("view-normal"); ?> - </a> - - <?php $url_output['a'] = 'global'; ?> - <a class="view_global btn <?php echo $actual_view == 'global'? 'active' : ''; ?>" title="<?php echo _t('index.menu.global_view'); ?>" href="<?php echo Minz_Url::display($url_output); ?>"> - <?php echo _i("view-global"); ?> - </a> - - <?php $url_output['a'] = 'reader'; ?> - <a class="view_reader btn <?php echo $actual_view == 'reader'? 'active' : ''; ?>" title="<?php echo _t('index.menu.reader_view'); ?>" href="<?php echo Minz_Url::display($url_output); ?>"> - <?php echo _i("view-reader"); ?> - </a> + <?php + $readingModes = FreshRSS_ReadingMode::getReadingModes(); + $readingModes = Minz_ExtensionManager::callHook('nav_reading_modes', $readingModes); + + /** @var FreshRSS_ReadingMode $mode */ + foreach ($readingModes as $mode) { + ?> + <a class="<?php echo $mode->getId(); ?> btn <?php if ($mode->isActive()) { echo 'active'; } ?>" title="<?php echo $mode->getTitle(); ?>" href="<?php echo Minz_Url::display($mode->getUrlParams()); ?>"> + <?php echo $mode->getName(); ?> + </a> + <?php + } + ?> <?php $url_output['a'] = 'rss'; @@ -156,7 +155,7 @@ $url_output['params']['hours'] = FreshRSS_Context::$user_conf->since_hours_posts_per_rss; } ?> - <a class="view_rss btn" target="_blank" rel="noreferrer" title="<?php echo _t('index.menu.rss_view'); ?>" href="<?php echo Minz_Url::display($url_output); ?>"> + <a class="view-rss btn" target="_blank" rel="noreferrer" title="<?php echo _t('index.menu.rss_view'); ?>" href="<?php echo Minz_Url::display($url_output); ?>"> <?php echo _i('rss'); ?> </a> </div> diff --git a/app/views/configure/archiving.phtml b/app/views/configure/archiving.phtml index 2254f5dba..09be55fd9 100644 --- a/app/views/configure/archiving.phtml +++ b/app/views/configure/archiving.phtml @@ -19,7 +19,7 @@ <label class="group-name" for="keep_history_default"><?php echo _t('conf.archiving.keep_history_by_feed'); ?></label> <div class="group-controls"> <select class="number" name="keep_history_default" id="keep_history_default" required="required" data-leave-validation="<?php echo FreshRSS_Context::$user_conf->keep_history_default; ?>"><?php - foreach (array('' => '', 0 => '0', 10 => '10', 50 => '50', 100 => '100', 500 => '500', 1000 => '1 000', 5000 => '5 000', 10000 => '10 000', -1 => '∞') as $v => $t) { + foreach (array('' => '', 0 => '0', 10 => '10', 50 => '50', 100 => '100', 500 => '500', 1000 => '1 000', 5000 => '5 000', 10000 => '10 000', FreshRSS_Feed::KEEP_HISTORY_INFINITE => '∞') as $v => $t) { echo '<option value="' . $v . (FreshRSS_Context::$user_conf->keep_history_default == $v ? '" selected="selected' : '') . '">' . $t . ' </option>'; } ?></select> (<?php echo _t('gen.short.by_default'); ?>) @@ -34,7 +34,7 @@ 3600 => '1h', 5400 => '1.5h', 7200 => '2h', 10800 => '3h', 14400 => '4h', 18800 => '5h', 21600 => '6h', 25200 => '7h', 28800 => '8h', 36000 => '10h', 43200 => '12h', 64800 => '18h', 86400 => '1d', 129600 => '1.5d', 172800 => '2d', 259200 => '3d', 345600 => '4d', 432000 => '5d', 518400 => '6d', - 604800 => '1wk', -1 => '∞') as $v => $t) { + 604800 => '1wk') as $v => $t) { echo '<option value="' . $v . (FreshRSS_Context::$user_conf->ttl_default == $v ? '" selected="selected' : '') . '">' . $t . '</option>'; if (FreshRSS_Context::$user_conf->ttl_default == $v) { $found = true; diff --git a/app/views/configure/display.phtml b/app/views/configure/display.phtml index 62ecc1080..414fd2cd6 100644 --- a/app/views/configure/display.phtml +++ b/app/views/configure/display.phtml @@ -106,7 +106,7 @@ </tbody> </table><br /> </div> - + <div class="form-group"> <label class="group-name" for="html5_notif_timeout"><?php echo _t('conf.display.notif_html5.timeout'); ?></label> <div class="group-controls"> @@ -114,6 +114,15 @@ </div> </div> + <div class="form-group"> + <div class="group-controls"> + <label class="checkbox" for="show_nav_buttons"> + <input type="checkbox" name="show_nav_buttons" id="show_nav_buttons" value="1"<?php echo FreshRSS_Context::$user_conf->show_nav_buttons ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->show_nav_buttons; ?>"/> + <?php echo _t('conf.display.show_nav_buttons'); ?> + </label> + </div> + </div> + <div class="form-group form-actions"> <div class="group-controls"> <button type="submit" class="btn btn-important"><?php echo _t('gen.action.submit'); ?></button> diff --git a/app/views/configure/shortcut.phtml b/app/views/configure/shortcut.phtml index dceeb17de..66db6a5d4 100644 --- a/app/views/configure/shortcut.phtml +++ b/app/views/configure/shortcut.phtml @@ -17,6 +17,36 @@ <noscript><p class="alert alert-error"><?php echo _t('conf.shortcut.javascript'); ?></p></noscript> + <legend><?php echo _t('conf.shortcut.views'); ?></legend> + + <div class="form-group"> + <label class="group-name" for="normal_view_shortcut"><?php echo _t('conf.shortcut.normal_view'); ?></label> + <div class="group-controls"> + <input type="text" id="normal_view_shortcut" name="shortcuts[normal_view]" list="keys" value="<?php echo $s['normal_view']; ?>" data-leave-validation="<?php echo $s['normal_view']; ?>"/> + </div> + </div> + + <div class="form-group"> + <label class="group-name" for="global_view_shortcut"><?php echo _t('conf.shortcut.global_view'); ?></label> + <div class="group-controls"> + <input type="text" id="global_view_shortcut" name="shortcuts[global_view]" list="keys" value="<?php echo $s['global_view']; ?>" data-leave-validation="<?php echo $s['global_view']; ?>"/> + </div> + </div> + + <div class="form-group"> + <label class="group-name" for="reading_view_shortcut"><?php echo _t('conf.shortcut.reading_view'); ?></label> + <div class="group-controls"> + <input type="text" id="reading_view_shortcut" name="shortcuts[reading_view]" list="keys" value="<?php echo $s['reading_view']; ?>" data-leave-validation="<?php echo $s['reading_view']; ?>"/> + </div> + </div> + + <div class="form-group"> + <label class="group-name" for="rss_view_shortcut"><?php echo _t('conf.shortcut.rss_view'); ?></label> + <div class="group-controls"> + <input type="text" id="rss_view_shortcut" name="shortcuts[rss_view]" list="keys" value="<?php echo $s['rss_view']; ?>" data-leave-validation="<?php echo $s['rss_view']; ?>"/> + </div> + </div> + <legend><?php echo _t('conf.shortcut.navigation'); ?></legend> <p class="alert alert-warn"><?php echo _t('conf.shortcut.navigation_help');?></p> diff --git a/app/views/helpers/feed/update.phtml b/app/views/helpers/feed/update.phtml index bf87a255a..d379c5df8 100644 --- a/app/views/helpers/feed/update.phtml +++ b/app/views/helpers/feed/update.phtml @@ -65,12 +65,13 @@ </div> </div> <div class="form-group"> - <label class="group-name" for="priority"><?php echo _t('sub.feed.in_main_stream'); ?></label> + <label class="group-name" for="priority"><?php echo _t('sub.feed.priority'); ?></label> <div class="group-controls"> - <label class="checkbox" for="priority"> - <input type="checkbox" name="priority" id="priority" value="10"<?php echo $this->feed->priority() > 0 ? ' checked="checked"' : ''; ?> /> - <?php echo _t('gen.short.yes'); ?> - </label> + <select name="priority" id="priority"> + <option value='<?php echo FreshRSS_Feed::PRIORITY_MAIN_STREAM;?>' <?php if (FreshRSS_Feed::PRIORITY_MAIN_STREAM === $this->feed->priority()) {echo 'selected="selected"';}?>><?php echo _t('sub.feed.priority.main_stream'); ?></option> + <option value='<?php echo FreshRSS_Feed::PRIORITY_NORMAL;?>' <?php if (FreshRSS_Feed::PRIORITY_NORMAL === $this->feed->priority()) {echo 'selected="selected"';}?>><?php echo _t('sub.feed.priority.normal'); ?></option> + <option value='<?php echo FreshRSS_Feed::PRIORITY_ARCHIVED;?>' <?php if (FreshRSS_Feed::PRIORITY_ARCHIVED === $this->feed->priority()) {echo 'selected="selected"';}?>><?php echo _t('sub.feed.priority.archived'); ?></option> + </select> </div> </div> @@ -100,7 +101,7 @@ <label class="group-name" for="keep_history"><?php echo _t('sub.feed.keep_history'); ?></label> <div class="group-controls"> <select class="number" name="keep_history" id="keep_history" required="required"><?php - foreach (array('' => '', -2 => _t('gen.short.by_default'), 0 => '0', 10 => '10', 50 => '50', 100 => '100', 500 => '500', 1000 => '1 000', 5000 => '5 000', 10000 => '10 000', -1 => '∞') as $v => $t) { + foreach (array('' => '', FreshRSS_Feed::KEEP_HISTORY_DEFAULT => _t('gen.short.by_default'), 0 => '0', 10 => '10', 50 => '50', 100 => '100', 500 => '500', 1000 => '1 000', 5000 => '5 000', 10000 => '10 000', FreshRSS_Feed::KEEP_HISTORY_INFINITE => '∞') as $v => $t) { echo '<option value="' . $v . ($this->feed->keepHistory() === $v ? '" selected="selected' : '') . '">' . $t . '</option>'; } ?></select> @@ -111,11 +112,11 @@ <div class="group-controls"> <select class="number" name="ttl" id="ttl" required="required"><?php $found = false; - foreach (array(-2 => _t('gen.short.by_default'), 900 => '15min', 1200 => '20min', 1500 => '25min', 1800 => '30min', 2700 => '45min', + foreach (array(FreshRSS_Feed::TTL_DEFAULT => _t('gen.short.by_default'), 900 => '15min', 1200 => '20min', 1500 => '25min', 1800 => '30min', 2700 => '45min', 3600 => '1h', 5400 => '1.5h', 7200 => '2h', 10800 => '3h', 14400 => '4h', 18800 => '5h', 21600 => '6h', 25200 => '7h', 28800 => '8h', 36000 => '10h', 43200 => '12h', 64800 => '18h', 86400 => '1d', 129600 => '1.5d', 172800 => '2d', 259200 => '3d', 345600 => '4d', 432000 => '5d', 518400 => '6d', - 604800 => '1wk', 1209600 => '2wk', 1814400 => '3wk', 2419200 => '4wk', 2629744 => '1mo', -1 => '∞') as $v => $t) { + 604800 => '1wk', 1209600 => '2wk', 1814400 => '3wk', 2419200 => '4wk', 2629744 => '1mo') as $v => $t) { echo '<option value="' . $v . ($this->feed->ttl() === $v ? '" selected="selected' : '') . '">' . $t . '</option>'; if ($this->feed->ttl() == $v) { $found = true; @@ -125,6 +126,10 @@ echo '<option value="' . intval($this->feed->ttl()) . '" selected="selected">' . intval($this->feed->ttl()) . 's</option>'; } ?></select> + <label for="mute"> + <input type="checkbox" name="mute" id="mute" value="1"<?php echo $this->feed->mute() ? ' checked="checked"' : ''; ?> /> + <?php echo _t('sub.feed.mute'); ?> + </label> </div> </div> <div class="form-group"> diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index 2da53b679..1b9b614d2 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -35,6 +35,10 @@ echo htmlspecialchars(json_encode(array( 'user_filter' => @$s['user_filter'], 'help' => @$s['help'], 'close_dropdown' => @$s['close_dropdown'], + 'normal_view' => @$s['normal_view'], + 'global_view' => @$s['global_view'], + 'reading_view' => @$s['reading_view'], + 'rss_view' => @$s['rss_view'], ), 'url' => array( 'index' => _url('index', 'index'), diff --git a/app/views/index/global.phtml b/app/views/index/global.phtml index f35732c8f..2f25b6dc2 100644 --- a/app/views/index/global.phtml +++ b/app/views/index/global.phtml @@ -37,7 +37,7 @@ $empty = $feed->nbEntries() === 0 ? ' empty' : ''; $url_base['params']['get'] = 'f_' . $feed->id(); ?> - <li id="f_<?php echo $feed->id(); ?>" class="item feed<?php echo $error, $empty; ?>" data-unread="<?php echo $feed->nbNotRead(); ?>" data-priority="<?php echo $feed->priority(); ?>"> + <li id="f_<?php echo $feed->id(); ?>" class="item feed<?php echo $error, $empty, $feed->mute() ? ' mute' : ''; ?>" data-unread="<?php echo $feed->nbNotRead(); ?>" data-priority="<?php echo $feed->priority(); ?>"> <img class="favicon" src="<?php echo $feed->favicon(); ?>" alt="✇" /> <a class="item-title" data-unread="<?php echo format_number($feed->nbNotRead()); ?>" href="<?php echo Minz_Url::display($url_base); ?>"><?php echo $feed->name(); ?></a> </li> diff --git a/app/views/index/normal.phtml b/app/views/index/normal.phtml index ba48b2501..c7cab2d3f 100644 --- a/app/views/index/normal.phtml +++ b/app/views/index/normal.phtml @@ -83,7 +83,7 @@ if (!empty($this->entries)) { $this->renderHelper('pagination'); ?></div> -<?php $this->partial('nav_entries'); ?> +<?php if (FreshRSS_Context::$user_conf->show_nav_buttons) $this->partial('nav_entries'); ?> <?php } else { ?> <div id="stream" class="prompt alert alert-warn normal"> diff --git a/app/views/index/reader.phtml b/app/views/index/reader.phtml index f2af75af0..eb6613b28 100644 --- a/app/views/index/reader.phtml +++ b/app/views/index/reader.phtml @@ -18,11 +18,25 @@ if (!empty($this->entries)) { <?php $feed = FreshRSS_CategoryDAO::findFeed($this->categories, $item->feed()); //We most likely already have the feed object in cache if (empty($feed)) $feed = $item->feed(true); + $favoriteUrl = array('c' => 'entry', 'a' => 'bookmark', 'params' => array('id' => $item->id())); + if ($item->isFavorite()) { + $favoriteUrl['params']['is_favorite'] = 0; + } + $readUrl = array('c' => 'entry', 'a' => 'read', 'params' => array('id' => $item->id())); + if ($item->isRead()) { + $readUrl['params']['is_read'] = 0; + } ?> - <a target="_blank" rel="noreferrer" class="go_website" href="<?php echo $item->link(); ?>"> + <a class="read" href="<?php echo Minz_Url::display($readUrl); ?>"> + <?php echo _i($item->isRead() ? 'read' : 'unread'); ?> + </a> + <a class="bookmark" href="<?php echo Minz_Url::display($favoriteUrl); ?>"> + <?php echo _i($item->isFavorite() ? 'starred' : 'non-starred'); ?> + </a> + <a href="<?php echo _url('index', 'reader', 'get', 'f_' . $feed->id()); ?>"> <img class="favicon" src="<?php echo $feed->favicon(); ?>" alt="✇" /> <span><?php echo $feed->name(); ?></span> </a> - <h1 class="title"><?php echo $item->title(); ?></h1> + <h1 class="title"><a target="_blank" rel="noreferrer" class="go_website" href="<?php echo $item->link(); ?>"><?php echo $item->title(); ?></a></h1> <div class="author"><?php $author = $item->author(); diff --git a/app/views/subscription/index.phtml b/app/views/subscription/index.phtml index 48f760d3e..26af0bd7c 100644 --- a/app/views/subscription/index.phtml +++ b/app/views/subscription/index.phtml @@ -125,7 +125,7 @@ $error = $feed->inError() ? ' error' : ''; $empty = $feed->nbEntries() == 0 ? ' empty' : ''; ?> - <li class="item feed<?php echo $error, $empty; ?>" + <li class="item feed<?php echo $error, $empty, $feed->mute() ? ' mute': ''; ?>" draggable="true" data-feed-id="<?php echo $feed->id(); ?>" dropzone="move"> diff --git a/app/views/user/manage.phtml b/app/views/user/manage.phtml index 793a3a0bd..26838fcc1 100644 --- a/app/views/user/manage.phtml +++ b/app/views/user/manage.phtml @@ -46,14 +46,51 @@ </div> </form> + <form method="post" action="<?php echo _url('user', 'update'); ?>"> + <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" /> + <legend><?php echo _t('admin.user.update_users'); ?></legend> + + <div class="form-group"> + <label class="group-name" for="current_user"><?php echo _t('admin.user.selected'); ?></label> + <div class="group-controls"> + <select id="current_user" class="select-change" name="username"> + <option selected="selected"> </option> + <?php foreach (listUsers() as $username) { ?> + <option value="<?php echo $username; ?>"><?php echo $username; ?></option> + <?php } ?> + </select> + </div> + </div> + + <div class="form-group"> + <label class="group-name" for="newPasswordPlain"><?php echo _t('admin.user.password_form'); ?></label> + <div class="group-controls"> + <div class="stick"> + <input type="password" id="newPasswordPlain" name="newPasswordPlain" autocomplete="off" pattern=".{7,}" <?php echo cryptAvailable() ? '' : 'disabled="disabled" '; ?>/> + <a class="btn toggle-password" data-toggle="newPasswordPlain"><?php echo _i('key'); ?></a> + </div> + <?php echo _i('help'); ?> <?php echo _t('conf.profile.password_format'); ?> + <noscript><b><?php echo _t('gen.js.should_be_activated'); ?></b></noscript> + </div> + </div> + + <div class="form-group form-actions"> + <div class="group-controls"> + <button type="submit" class="btn btn-important"><?php echo _t('gen.action.update'); ?></button> + <button type="reset" class="btn"><?php echo _t('gen.action.cancel'); ?></button> + </div> + </div> + </form> + <form method="post" action="<?php echo _url('user', 'delete'); ?>"> <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" /> - <legend><?php echo _t('admin.user.users'); ?></legend> + <legend><?php echo _t('admin.user.delete_users'); ?></legend> <div class="form-group"> - <label class="group-name" for="user-list"><?php echo _t('admin.user.user_list'); ?></label> + <label class="group-name" for="user-list"><?php echo _t('admin.user.selected'); ?></label> <div class="group-controls"> <select id="user-list" class="select-change" name="username"> + <option selected="selected"> </option> <?php foreach (listUsers() as $username) { ?> <option data-url="<?php echo _url('user', 'manage', 'u', $username); ?>" <?php echo $this->current_user === $username ? 'selected="selected"' : ''; ?> value="<?php echo $username; ?>"><?php echo $username; ?></option> <?php } ?> diff --git a/cli/i18n/ignore/kr.php b/cli/i18n/ignore/kr.php new file mode 100644 index 000000000..24cfbc86a --- /dev/null +++ b/cli/i18n/ignore/kr.php @@ -0,0 +1,40 @@ +<?php + +return array( + 'conf.sharing.blogotext', + 'conf.sharing.diaspora', + 'conf.sharing.facebook', + 'conf.sharing.g+', + 'conf.sharing.shaarli', + 'conf.sharing.twitter', + 'conf.sharing.wallabag', + 'gen.lang.cz', + 'gen.lang.de', + 'gen.lang.en', + 'gen.lang.es', + 'gen.lang.fr', + 'gen.lang.he', + 'gen.lang.it', + 'gen.lang.kr', + 'gen.lang.nl', + 'gen.lang.pt-br', + 'gen.lang.ru', + 'gen.lang.tr', + 'gen.lang.zh-cn', + 'gen.freshrss._', + 'gen.share.Known', + 'gen.share.blogotext', + 'gen.share.diaspora', + 'gen.share.facebook', + 'gen.share.g+', + 'gen.share.gnusocial', + 'gen.share.jdh', + 'gen.share.mastodon', + 'gen.share.movim', + 'gen.share.shaarli', + 'gen.share.twitter', + 'gen.share.wallabag', + 'gen.share.wallabagv2', + 'index.about.agpl3', + 'sub.api.title', +); diff --git a/cli/i18n/ignore/nl.php b/cli/i18n/ignore/nl.php new file mode 100644 index 000000000..4013bc89e --- /dev/null +++ b/cli/i18n/ignore/nl.php @@ -0,0 +1,49 @@ +<?php + +return array( + 'conf.sharing.blogotext', + 'conf.sharing.diaspora', + 'conf.sharing.email', + 'conf.sharing.facebook', + 'conf.sharing.g+', + 'conf.sharing.print', + 'conf.sharing.shaarli', + 'conf.sharing.twitter', + 'conf.sharing.wallabag', + 'gen.date.Apr', + 'gen.date.Dec', + 'gen.date.Nov', + 'gen.date.Sep', + 'gen.freshrss._', + 'gen.lang.cz', + 'gen.lang.de', + 'gen.lang.en', + 'gen.lang.es', + 'gen.lang.fr', + 'gen.lang.it', + 'gen.lang.kr', + 'gen.lang.nl', + 'gen.lang.pt-br', + 'gen.lang.ru', + 'gen.lang.tr', + 'gen.lang.zh-cn', + 'gen.share.blogotext', + 'gen.share.diaspora', + 'gen.share.facebook', + 'gen.share.email', + 'gen.share.g+', + 'gen.share.mastodon', + 'gen.share.movim', + 'gen.share.print', + 'gen.share.shaarli', + 'gen.share.twitter', + 'gen.share.wallabag', + 'gen.share.wallabagv2', + 'gen.share.jdh', + 'gen.share.gnusocial', + 'index.about.agpl3', + 'index.about.website', + 'index.about.version', + 'sub.api.title', + 'sub.bookmarklet.title', +); diff --git a/cli/i18n/ignore/zh-cn.php b/cli/i18n/ignore/zh-cn.php new file mode 100644 index 000000000..c00ac79d3 --- /dev/null +++ b/cli/i18n/ignore/zh-cn.php @@ -0,0 +1,41 @@ +<?php + +return array( + 'conf.sharing.blogotext', + 'conf.sharing.diaspora', + 'conf.sharing.email', + 'conf.sharing.facebook', + 'conf.sharing.g+', + 'conf.sharing.shaarli', + 'conf.sharing.twitter', + 'conf.sharing.wallabag', + 'gen.lang.cz', + 'gen.lang.de', + 'gen.lang.en', + 'gen.lang.es', + 'gen.lang.fr', + 'gen.lang.he', + 'gen.lang.it', + 'gen.lang.kr', + 'gen.lang.nl', + 'gen.lang.pt-br', + 'gen.lang.ru', + 'gen.lang.tr', + 'gen.lang.zh-cn', + 'gen.share.blogotext', + 'gen.share.diaspora', + 'gen.share.email', + 'gen.share.facebook', + 'gen.share.g+', + 'gen.share.gnusocial', + 'gen.share.jdh', + 'gen.share.mastodon', + 'gen.share.movim', + 'gen.share.shaarli', + 'gen.share.twitter', + 'gen.share.wallabag', + 'gen.share.wallabagv2', + 'index.about.agpl3', + 'sub.api.title', + 'gen.freshrss._', +); diff --git a/cli/update-user.php b/cli/update-user.php index 4529b8531..7eb3e81ff 100755 --- a/cli/update-user.php +++ b/cli/update-user.php @@ -7,7 +7,8 @@ $username = cliInitUser($options['user']); echo 'FreshRSS updating user “', $username, "”…\n"; -$ok = FreshRSS_user_Controller::updateContextUser( +$ok = FreshRSS_user_Controller::updateUser( + $username, empty($options['password']) ? '' : $options['password'], empty($options['api_password']) ? '' : $options['api_password'], $values); diff --git a/config-user.default.php b/config-user.default.php index 40ab49570..5e67d8d9b 100644 --- a/config-user.default.php +++ b/config-user.default.php @@ -56,6 +56,10 @@ return array ( 'user_filter' => 'u', 'help' => 'f1', 'close_dropdown' => 'escape', + 'normal_view' => '1', + 'global_view' => '2', + 'reading_view' => '3', + 'rss_view' => '4', ), 'topline_read' => true, 'topline_favorite' => true, @@ -72,5 +76,6 @@ return array ( 'queries' => array ( ), 'html5_notif_timeout' => 0, + 'show_nav_buttons' => true, 'extensions_enabled' => array(), ); diff --git a/constants.php b/constants.php index c18c2d94d..f33e2d63e 100644 --- a/constants.php +++ b/constants.php @@ -2,7 +2,7 @@ //NB: Do not edit; use ./constants.local.php instead. //<Not customisable> -define('FRESHRSS_VERSION', '1.9.0'); +define('FRESHRSS_VERSION', '1.10.0'); define('FRESHRSS_WEBSITE', 'https://freshrss.org'); define('FRESHRSS_WIKI', 'https://freshrss.github.io/FreshRSS/'); diff --git a/docs/en/index.md b/docs/en/index.md index a0c97a0d9..59cbdc296 100644 --- a/docs/en/index.md +++ b/docs/en/index.md @@ -1,19 +1,19 @@  -FreshRSS is a RSS aggregator and reader. It gives you possibility to read and follow several news website at a glance without the need to go from a website to another. +FreshRSS is an RSS aggregator and reader. It allows you to read and follow several news websites at a glance without the need to browse from one website to another. FreshRSS has a lot of features including: - RSS and Atom aggregation - Mark article as favorite if you liked it or if you want to read it later -- Filter and search functionalities are working together to find easily articles -- Statistics help you to know the frequency of publishing of all the websites you are following +- Filter and search functionality helps to easily find articles +- Statistics to show you the publishing frequency all the websites you follow - Import/export of your feeds into OPML format - Several themes created by the community - "Google Reader"-like API to connect Android applications -- The application is "responsive" which means it adapts to small screens so you can bring articles in your pocket -- Self-hosted: code is free (under AGPL3 licence) and so you can host your own instance of FreshRSS -- Multi-users so you can host your friends and your family +- The application is "responsive," which means it adapts to small screens so you can bring articles in your pocket +- Self-hosted: the code is free (under AGPL3 licence), so you can host your own instance of FreshRSS +- Multi-user, so you can also host for your friends and family - And a lot more! This documentation is split into four sections: diff --git a/docs/en/users/03_Main_view.md b/docs/en/users/03_Main_view.md index 53b0beaf2..adb62c7ec 100644 --- a/docs/en/users/03_Main_view.md +++ b/docs/en/users/03_Main_view.md @@ -45,9 +45,9 @@ This is the most straightforward since you have a public instance; there is noth 0 * * * * curl 'https://your.server.net/FreshRSS/p/i/?c=feed&a=actualize' ``` -### Form or Persona authentication +### Form authentication -In those cases, if you configure the application to allow anonymous reading, you can also allow anonymous user to update feeds (“Allow anonymous refresh of the articles”). +If you configure the application to allow anonymous reading, you can also allow anonymous users to update feeds (“Allow anonymous refresh of the articles”).  @@ -96,14 +96,14 @@ This update occurs on the selected feed only. To trigger it, you need to click o While the number of articles stored by FreshRSS increase, it is important to have efficient filters to display only a subset of the articles. There is several methods with different criterion. Most of the time, those methods can be combined. -##By category +## By category -It is the easiest method. The only thing to do is clicking on the category title in the side panel. There is two special categories on top of that panel: +This is the easiest method. You only need to click on the category title in the side panel. There are two special categories on top of that panel: * *Main feed* which displays only articles from feeds marked as available in that category * *Favourites* which displays only articles marked as favourites -##By feed +## By feed There is several methods to filter articles by feed: @@ -114,7 +114,7 @@ There is several methods to filter articles by feed:  -##By status +## By status Each article has two attributes, which can be combined. The first attribute indicates if the article was read or not. The second attribute indicates if the article was marked as favorite or not. @@ -128,11 +128,11 @@ Starting with version 0.8, all attribute filters are visible as toggle icons. Th By default, this filter displays only unread articles -##By content +## By content It is possible to filter articles by their content by inputting a string in the search field. -##With the search field +## With the search field It is possible to use the search field to further refine results: diff --git a/docs/en/users/06_Mobile_access.md b/docs/en/users/06_Mobile_access.md index 3472172b0..166985585 100644 --- a/docs/en/users/06_Mobile_access.md +++ b/docs/en/users/06_Mobile_access.md @@ -46,6 +46,7 @@ This page assumes you have completed the [server setup](../admins/02_Installatio 7. Pick a client supporting a Google Reader-like API. Selection: * Android * [News+](https://play.google.com/store/apps/details?id=com.noinnion.android.newsplus) with [News+ Google Reader extension](https://play.google.com/store/apps/details?id=com.noinnion.android.newsplus.extension.google_reader) (Closed source) + * [FeedMe 3.5.3+](https://play.google.com/store/apps/details?id=com.seazon.feedme) (Closed source) * [EasyRSS](https://github.com/Alkarex/EasyRSS) (Open source, [F-Droid](https://f-droid.org/packages/org.freshrss.easyrss/)) * Linux * [FeedReader 2.0+](https://jangernert.github.io/FeedReader/) (Open source) diff --git a/docs/en/users/07_Frequently_Asked_Questions.md b/docs/en/users/07_Frequently_Asked_Questions.md index 6391c55f5..427da7bd9 100644 --- a/docs/en/users/07_Frequently_Asked_Questions.md +++ b/docs/en/users/07_Frequently_Asked_Questions.md @@ -4,10 +4,10 @@ We may not have answered all of your questions in the previous sections. The FAQ Of course, ```/i``` has a purpose! We used it for performance and usability: -* it allows to serve icons, images, styles and scripts without cookies. Whitout that trick, those files will be downloaded more often, specially when the form or the Personna authentications are used. Also, HTTP requests will be heavier. +* It allows for serving icons, images, styles and scripts without cookies. Without that trick, those files would be downloaded more often, especially when form authentication is used. Also, HTTP requests would be heavier. * ```./p/``` public root can be served without any HTTP access restrictions. Whereas it could be implemented in ```./p/i/```. -* It spares from having problems while serving public resources like ```favicon.ico```, ```robots.txt```, etc. -* It allows to display the logo instead of a white page while hitting a restriction or a delay during the loading process. +* It avoids problems while serving public resources like ```favicon.ico```, ```robots.txt```, etc. +* It allows the logo to be displayed instead of a white page while hitting a restriction or a delay during the loading process. ## Why robots.txt is located in a sub-folder? @@ -28,8 +28,8 @@ Here are the steps to follow: 1. __Verify SimplePie validation__ with the [SimplePie on-line tool](http://simplepie.org/demo/ "SimplePie official demo"). If it is not recognized, there is nothing we can do. 1. __Verify FreshRSS integration__ with the [demo](http://demo.freshrss.org "FreshRSS official demo"). If it is not working, you need to [create an issue on Github](https://github.com/FreshRSS/FreshRSS/issues/new "Create an issue for FreshRSS") so we can have a look at it. If it is working, there is probably something fishy with the hosting server. -Here is a list of feed which don't work: +Here is a list of feeds which don't work: * http://foulab.org/fr/rss/Foulab_News: is not a W3C valid feed (November 2014) * http://eu.battle.net/hearthstone/fr/feed/news: is not a W3C valid feed (Novembre 2014) -* http://webseriesmag.blogs.liberation.fr/we/atom.xml: is not working for the user but succeed on all the described validations (November 2014)
\ No newline at end of file +* http://webseriesmag.blogs.liberation.fr/we/atom.xml: is not working for the user but succeed on all the described validations (November 2014) diff --git a/docs/fr/users/03_Main_view.md b/docs/fr/users/03_Main_view.md index 744141b7d..ebf782136 100644 --- a/docs/fr/users/03_Main_view.md +++ b/docs/fr/users/03_Main_view.md @@ -45,7 +45,7 @@ C’est le cas le plus simple, puisque votre instance est publique, vous n’ave 0 * * * * curl 'https://votre.serveur.net/FreshRSS/p/i/?c=feed&a=actualize' ``` -##### Authentification par formulaire ou Persona +##### Authentification par formulaire Dans ces cas-là, si vous avez autorisé la lecture anonyme des articles, vous pouvez aussi permettre à n’importe qui de rafraîchir vos flux (« Autoriser le rafraîchissement anonyme des flux »). diff --git a/docs/fr/users/06_Mobile_access.md b/docs/fr/users/06_Mobile_access.md index 185c94098..8ef3d038a 100644 --- a/docs/fr/users/06_Mobile_access.md +++ b/docs/fr/users/06_Mobile_access.md @@ -44,6 +44,7 @@ Tout client supportant une API de type Google Reader. Sélection : * Android * [News+](https://play.google.com/store/apps/details?id=com.noinnion.android.newsplus) avec [News+ Google Reader extension](https://play.google.com/store/apps/details?id=com.noinnion.android.newsplus.extension.google_reader) (Propriétaire) + * [FeedMe 3.5.3+](https://play.google.com/store/apps/details?id=com.seazon.feedme) (Propriétaire) * [EasyRSS](https://github.com/Alkarex/EasyRSS) (Libre, F-Droid) * Linux * [FeedReader 2.0+](https://jangernert.github.io/FeedReader/) (Libre) diff --git a/docs/fr/users/07_Frequently_Asked_Questions.md b/docs/fr/users/07_Frequently_Asked_Questions.md index 9dc80b2e4..1f4d059ce 100644 --- a/docs/fr/users/07_Frequently_Asked_Questions.md +++ b/docs/fr/users/07_Frequently_Asked_Questions.md @@ -4,7 +4,7 @@ Il est possible que nous n'ayons pas répondu à toutes vos questions dans les p Bien entendu, le ```/i``` n'est pas là pour faire joli ! Il s'agit d'une question de performances et de praticité : -* Cela permet de servir les icônes, images, styles, scripts sans cookie. Sans cela, ces fichiers seraient souvent re-téléchargés, en particulier lorsque Persona ou le formulaire de connexion sont utilisés. De plus, les requêtes vers ces ressources seraient plus lourdes. +* Cela permet de servir les icônes, images, styles, scripts sans cookie. Sans cela, ces fichiers seraient souvent re-téléchargés, en particulier lorsque le formulaire de connexion est utilisé. De plus, les requêtes vers ces ressources seraient plus lourdes. * La racine publique ```./p/``` peut être servie sans restriction d'accès HTTP (qui peut avantageusement être mise en place dans ```./p/i/```). * Cela permet d'éviter des problèmes pour des fichiers qui doivent être publics pour bien fonctionner, comme ```favicon.ico```, ```robots.txt```, etc. * Cela permet aussi d'avoir un logo FreshRSS plutôt qu'une page blanche pour accueillir l'utilisateur par exemple dans le cas de la restriction d'accès HTTP ou lors de l'attente du chargement plus lourd du reste de l'interface. diff --git a/docs/index.md b/docs/index.md index 9afdcec38..86a660d16 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,6 +1,6 @@ -# Welcome on FreshRSS documentation center! +# Welcome to the FreshRSS documentation! -This documentation is under construction. If you want to contribute, [find us on GitHub](https://github.com/FreshRSS/FreshRSS). +This documentation is still under construction. If you want to contribute, you can [find us on GitHub](https://github.com/FreshRSS/FreshRSS). - [English documentation](./en/index.md) - [Documentation française](./fr/index.md) diff --git a/force-https.default.txt b/force-https.default.txt index 044620098..cae2d4ef2 100644 --- a/force-https.default.txt +++ b/force-https.default.txt @@ -1,7 +1,20 @@ +creativecommons.org dailymotion.com +debian.org +facebook.com feedburner.com +fsf.org +fsfe.org +github.com +gitlab.com +gnu.org gravatar.com gstatic.com +kernel.org +lwn.net tumblr.com +twitter.com +vimeo.com +wikipedia.org wordpress.com youtube.com diff --git a/lib/Minz/ExtensionManager.php b/lib/Minz/ExtensionManager.php index 02a99701f..10c49a8b6 100644 --- a/lib/Minz/ExtensionManager.php +++ b/lib/Minz/ExtensionManager.php @@ -31,6 +31,10 @@ class Minz_ExtensionManager { 'list' => array(), 'signature' => 'NoneToNone', ), + 'nav_reading_modes' => array( // function($readingModes = array) -> array | null + 'list' => array(), + 'signature' => 'OneToOne', + ), ); private static $ext_to_hooks = array(); diff --git a/lib/lib_rss.php b/lib/lib_rss.php index e9c4da049..215c4c362 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -364,7 +364,15 @@ function get_user_configuration($username) { function httpAuthUser() { - return isset($_SERVER['REMOTE_USER']) ? $_SERVER['REMOTE_USER'] : ''; + if (isset($_SERVER['REMOTE_USER'])) { + return $_SERVER['REMOTE_USER']; + } + + if (isset($_SERVER['REDIRECT_REMOTE_USER'])) { + return $_SERVER['REDIRECT_REMOTE_USER']; + } + + return ''; } function cryptAvailable() { diff --git a/p/api/greader.php b/p/api/greader.php index 99304f4ec..b1546192e 100644 --- a/p/api/greader.php +++ b/p/api/greader.php @@ -216,9 +216,13 @@ function token($conf) { function checkToken($conf, $token) { //http://code.google.com/p/google-reader-api/wiki/ActionToken $user = Minz_Session::param('currentUser', '_'); + if ($user !== '_' && $token == '') { + return true; //FeedMe //TODO: Check security consequences + } if ($token === str_pad(sha1(FreshRSS_Context::$system_conf->salt . $user . $conf->apiPasswordHash), 57, 'Z')) { return true; } + Minz_Log::warning('Invalid POST token: ' . $token, API_LOG); unauthorized(); } @@ -261,11 +265,13 @@ function subscriptionList() { $pdo = new MyPDO(); $stm = $pdo->prepare('SELECT f.id, f.name, f.url, f.website, c.id as c_id, c.name as c_name FROM `%_feed` f - INNER JOIN `%_category` c ON c.id = f.category'); - $stm->execute(); + INNER JOIN `%_category` c ON c.id = f.category AND f.priority >= :priority_normal'); + $stm->execute(array(':priority_normal' => FreshRSS_Feed::PRIORITY_NORMAL)); $res = $stm->fetchAll(PDO::FETCH_ASSOC); $salt = FreshRSS_Context::$system_conf->salt; + $faviconsUrl = Minz_Url::display('/f.php?', '', true); + $faviconsUrl = str_replace('/api/greader.php/reader/api/0/subscription', '', $faviconsUrl); //Security if base_url is not set properly $subscriptions = array(); foreach ($res as $line) { @@ -282,7 +288,7 @@ function subscriptionList() { //'firstitemmsec' => 0, 'url' => $line['url'], 'htmlUrl' => $line['website'], - 'iconUrl' => Minz_Url::display('/f.php?' . hash('crc32b', $salt . $line['url']), '', true), + 'iconUrl' => $faviconsUrl . hash('crc32b', $salt . $line['url']), ); } @@ -324,6 +330,9 @@ function subscriptionEdit($streamNames, $titles, $action, $add = '', $remove = ' $addCatId = 1; //Default category } $feedDAO = FreshRSS_Factory::createFeedDao(); + if (!is_array($streamNames) || count($streamNames) < 1) { + badRequest(); + } for ($i = count($streamNames) - 1; $i >= 0; $i--) { $streamName = $streamNames[$i]; //feed/http://example.net/sample.xml ; feed/338 if (strpos($streamName, 'feed/') === 0) { @@ -435,6 +444,51 @@ function unreadCount() { //http://blog.martindoms.com/2009/10/16/using-the-googl exit(); } +function entriesToArray($entries) { + $items = array(); + foreach ($entries as $entry) { + $f_id = $entry->feed(); + if (isset($arrayFeedCategoryNames[$f_id])) { + $c_name = $arrayFeedCategoryNames[$f_id]['c_name']; + $f_name = $arrayFeedCategoryNames[$f_id]['name']; + } else { + $c_name = '_'; + $f_name = '_'; + } + $item = array( + 'id' => /*'tag:google.com,2005:reader/item/' .*/ dec2hex($entry->id()), //64-bit hexa http://code.google.com/p/google-reader-api/wiki/ItemId + 'crawlTimeMsec' => substr($entry->id(), 0, -3), + 'timestampUsec' => '' . $entry->id(), //EasyRSS + 'published' => $entry->date(true), + 'title' => $entry->title(), + 'summary' => array('content' => $entry->content()), + 'alternate' => array( + array('href' => htmlspecialchars_decode($entry->link(), ENT_QUOTES)), + ), + 'categories' => array( + 'user/-/state/com.google/reading-list', + 'user/-/label/' . $c_name, + ), + 'origin' => array( + 'streamId' => 'feed/' . $f_id, + 'title' => $f_name, //EasyRSS + //'htmlUrl' => $line['f_website'], + ), + ); + if ($entry->author() != '') { + $item['author'] = $entry->author(); + } + if ($entry->isRead()) { + $item['categories'][] = 'user/-/state/com.google/read'; + } + if ($entry->isFavorite()) { + $item['categories'][] = 'user/-/state/com.google/starred'; + } + $items[] = $item; + } + return $items; +} + function streamContents($path, $include_target, $start_time, $count, $order, $exclude_target, $continuation) { //http://code.google.com/p/pyrfeed/wiki/GoogleReaderAPI //http://blog.martindoms.com/2009/10/16/using-the-google-reader-api-part-2/#feed @@ -476,57 +530,18 @@ function streamContents($path, $include_target, $start_time, $count, $order, $ex break; } - if (!empty($continuation)) { + if ($continuation != '') { $count++; //Shift by one element } $entryDAO = FreshRSS_Factory::createEntryDao(); $entries = $entryDAO->listWhere($type, $include_target, $state, $order === 'o' ? 'ASC' : 'DESC', $count, $continuation, new FreshRSS_Search(''), $start_time); - $items = array(); - foreach ($entries as $entry) { - $f_id = $entry->feed(); - if (isset($arrayFeedCategoryNames[$f_id])) { - $c_name = $arrayFeedCategoryNames[$f_id]['c_name']; - $f_name = $arrayFeedCategoryNames[$f_id]['name']; - } else { - $c_name = '_'; - $f_name = '_'; - } - $item = array( - 'id' => /*'tag:google.com,2005:reader/item/' .*/ dec2hex($entry->id()), //64-bit hexa http://code.google.com/p/google-reader-api/wiki/ItemId - 'crawlTimeMsec' => substr($entry->id(), 0, -3), - 'timestampUsec' => '' . $entry->id(), //EasyRSS - 'published' => $entry->date(true), - 'title' => $entry->title(), - 'summary' => array('content' => $entry->content()), - 'alternate' => array( - array('href' => htmlspecialchars_decode($entry->link(), ENT_QUOTES)), - ), - 'categories' => array( - 'user/-/state/com.google/reading-list', - 'user/-/label/' . $c_name, - ), - 'origin' => array( - 'streamId' => 'feed/' . $f_id, - 'title' => $f_name, //EasyRSS - //'htmlUrl' => $line['f_website'], - ), - ); - if ($entry->author() != '') { - $item['author'] = $entry->author(); - } - if ($entry->isRead()) { - $item['categories'][] = 'user/-/state/com.google/read'; - } - if ($entry->isFavorite()) { - $item['categories'][] = 'user/-/state/com.google/starred'; - } - $items[] = $item; - } + $items = entriesToArray($entries); - if (!empty($continuation)) { + if ($continuation != '') { array_shift($items); //Discard first element that was already sent in the previous response + $count--; } $response = array( @@ -534,15 +549,18 @@ function streamContents($path, $include_target, $start_time, $count, $order, $ex 'updated' => time(), 'items' => $items, ); - if ((count($entries) >= $count) && (!empty($entry))) { - $response['continuation'] = $entry->id(); + if (count($entries) >= $count) { + $entry = end($entries); + if ($entry != false) { + $response['continuation'] = $entry->id(); + } } echo json_encode($response), "\n"; exit(); } -function streamContentsItemsIds($streamId, $start_time, $count, $order, $exclude_target) { +function streamContentsItemsIds($streamId, $start_time, $count, $order, $exclude_target, $continuation) { //http://code.google.com/p/google-reader-api/wiki/ApiStreamItemsIds //http://code.google.com/p/pyrfeed/wiki/GoogleReaderAPI //http://blog.martindoms.com/2009/10/16/using-the-google-reader-api-part-2/#feed @@ -572,8 +590,17 @@ function streamContentsItemsIds($streamId, $start_time, $count, $order, $exclude break; } + if ($continuation != '') { + $count++; //Shift by one element + } + $entryDAO = FreshRSS_Factory::createEntryDao(); - $ids = $entryDAO->listIdsWhere($type, $id, $state, $order === 'o' ? 'ASC' : 'DESC', $count, '', new FreshRSS_Search(''), $start_time); + $ids = $entryDAO->listIdsWhere($type, $id, $state, $order === 'o' ? 'ASC' : 'DESC', $count, $continuation, new FreshRSS_Search(''), $start_time); + + if ($continuation != '') { + array_shift($ids); //Discard first element that was already sent in the previous response + $count--; + } if (empty($ids)) { //For News+ bug https://github.com/noinnion/newsplus/issues/84#issuecomment-57834632 $ids[] = 0; @@ -585,9 +612,39 @@ function streamContentsItemsIds($streamId, $start_time, $count, $order, $exclude ); } - echo json_encode(array( + $response = array( 'itemRefs' => $itemRefs, - )), "\n"; + ); + if (count($ids) >= $count) { + $id = end($ids); + if ($id != false) { + $response['continuation'] = $id; + } + } + + echo json_encode($response), "\n"; + exit(); +} + +function streamContentsItems($e_ids, $order) { + header('Content-Type: application/json; charset=UTF-8'); + + foreach ($e_ids as $i => $e_id) { + $e_ids[$i] = hex2dec(basename($e_id)); //Strip prefix 'tag:google.com,2005:reader/item/' + } + + $entryDAO = FreshRSS_Factory::createEntryDao(); + $entries = $entryDAO->listByIds($e_ids, $order === 'o' ? 'ASC' : 'DESC'); + + $items = entriesToArray($entries); + + $response = array( + 'id' => 'user/-/state/com.google/reading-list', + 'updated' => time(), + 'items' => $items, + ); + + echo json_encode($response), "\n"; exit(); } @@ -673,9 +730,6 @@ function markAllAsRead($streamId, $olderThanId) { exit('OK'); } -//Minz_Log::debug('----------------------------------------------------------------', API_LOG); -//Minz_Log::debug(debugInfo(), API_LOG); - $pathInfo = empty($_SERVER['PATH_INFO']) ? '/Error' : urldecode($_SERVER['PATH_INFO']); $pathInfos = explode('/', $pathInfo); @@ -683,6 +737,10 @@ Minz_Configuration::register('system', DATA_PATH . '/config.php', FRESHRSS_PATH . '/config.default.php'); FreshRSS_Context::$system_conf = Minz_Configuration::get('system'); + +//Minz_Log::debug('----------------------------------------------------------------', API_LOG); +//Minz_Log::debug(debugInfo(), API_LOG); + if (!FreshRSS_Context::$system_conf->api_enabled) { serviceUnavailable(); } @@ -726,7 +784,10 @@ if (count($pathInfos) < 3) { * all items in a timestamp range, it will have a continuation attribute. * The same request can be re-issued with the value of that attribute put * in this parameter to get more items */ - $continuation = isset($_GET['c']) ? $_GET['c'] : ''; + $continuation = isset($_GET['c']) ? trim($_GET['c']) : ''; + if (!ctype_digit($continuation)) { + $continuation = ''; + } if (isset($pathInfos[5]) && $pathInfos[5] === 'contents' && isset($pathInfos[6])) { if (isset($pathInfos[7])) { if ($pathInfos[6] === 'feed') { @@ -755,7 +816,10 @@ if (count($pathInfos) < 3) { * be repeated to fetch the item IDs from multiple streams at once * (more efficient from a backend perspective than multiple requests). */ $streamId = $_GET['s']; - streamContentsItemsIds($streamId, $start_time, $count, $order, $exclude_target); + streamContentsItemsIds($streamId, $start_time, $count, $order, $exclude_target, $continuation); + } else if ($pathInfos[6] === 'contents' && isset($_POST['i'])) { //FeedMe + $e_ids = multiplePosts('i'); //item IDs + streamContentsItems($e_ids, $order); } } break; @@ -775,16 +839,16 @@ if (count($pathInfos) < 3) { subscriptionList($_GET['output']); break; case 'edit': - if (isset($_POST['s']) && isset($_POST['ac'])) { + if (isset($_REQUEST['s']) && isset($_REQUEST['ac'])) { //StreamId to operate on. The parameter may be repeated to edit multiple subscriptions at once - $streamNames = multiplePosts('s'); + $streamNames = empty($_POST['s']) && isset($_GET['s']) ? array($_GET['s']) : multiplePosts('s'); /* Title to use for the subscription. For the `subscribe` action, * if not specified then the feed's current title will be used. Can * be used with the `edit` action to rename a subscription */ - $titles = multiplePosts('t'); - $action = $_POST['ac']; //Action to perform on the given StreamId. Possible values are `subscribe`, `unsubscribe` and `edit` - $add = isset($_POST['a']) ? $_POST['a'] : ''; //StreamId to add the subscription to (generally a user label) - $remove = isset($_POST['r']) ? $_POST['r'] : ''; //StreamId to remove the subscription from (generally a user label) + $titles = empty($_POST['t']) && isset($_GET['t']) ? array($_GET['t']) : multiplePosts('t'); + $action = $_REQUEST['ac']; //Action to perform on the given StreamId. Possible values are `subscribe`, `unsubscribe` and `edit` + $add = isset($_REQUEST['a']) ? $_REQUEST['a'] : ''; //StreamId to add the subscription to (generally a user label) + $remove = isset($_REQUEST['r']) ? $_REQUEST['r'] : ''; //StreamId to remove the subscription from (generally a user label) subscriptionEdit($streamNames, $titles, $action, $add, $remove); } break; diff --git a/p/i/index.php b/p/i/index.php index a1212b570..ff7fcafdd 100755 --- a/p/i/index.php +++ b/p/i/index.php @@ -26,7 +26,7 @@ if (file_exists(DATA_PATH . '/do-install.txt')) { } else { session_cache_limiter(''); Minz_Session::init('FreshRSS'); - Minz_Session::_param('keepAlive', 1); //For Persona + Minz_Session::_param('keepAlive', 1); //To prevent the PHP session from expiring if (!file_exists(DATA_PATH . '/no-cache.txt')) { require(LIB_PATH . '/http-conditional.php'); diff --git a/p/scripts/main.js b/p/scripts/main.js index ce8070008..f8d20767a 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -704,6 +704,29 @@ function init_shortcuts() { 'disable_in_input': true }); + shortcut.add(shortcuts.normal_view, function () { + $('#nav_menu_views .view-normal').get(0).click(); + }, { + 'disable_in_input': true + }); + + shortcut.add(shortcuts.global_view, function () { + $('#nav_menu_views .view-global').get(0).click(); + }, { + 'disable_in_input': true + }); + + shortcut.add(shortcuts.reading_view, function () { + $('#nav_menu_views .view-reader').get(0).click(); + }, { + 'disable_in_input': true + }); + + shortcut.add(shortcuts.rss_view, function () { + $('#nav_menu_views .view-rss').get(0).click(); + }, { + 'disable_in_input': true + }); } function init_stream(divStream) { diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css index e5e1bca05..72487ca17 100644 --- a/p/themes/base-theme/template.css +++ b/p/themes/base-theme/template.css @@ -71,6 +71,9 @@ img.favicon { width: 16px; vertical-align: middle; } +.feed.mute::before { + content: '🔇'; +} /*=== Videos */ iframe, embed, object, video { |
