فهرست منبع

Add category order (#2592)

* Add category order

Each category has a new 'priority' attribute. It is used to sort categories in
views. Categories with the same priority are sorted alphabetically. Categories
with no priority are displayed after those with one.

For example, if we have the following categories:
- A (priority: 2)
- B (no priority)
- C (priority: 1)
- D (priority: 2)
- E (no priority)
- F (priority: 1)

They will be displayed in the following order:
- C
- F
- A
- D
- B
- E

See #190

* Shorten help text

It took too much room and will not be so necessary once we have drag &
drop
Alexis Degrugillier 6 سال پیش
والد
کامیت
f6e10579f2

+ 1 - 1
app/Controllers/indexController.php

@@ -173,7 +173,7 @@ class FreshRSS_index_Controller extends Minz_ActionController {
 	private function updateContext() {
 		if (empty(FreshRSS_Context::$categories)) {
 			$catDAO = FreshRSS_Factory::createCategoryDao();
-			FreshRSS_Context::$categories = $catDAO->listCategories();
+			FreshRSS_Context::$categories = $catDAO->listSortedCategories();
 		}
 
 		// Update number of read / unread variables.

+ 4 - 1
app/Controllers/subscriptionController.php

@@ -19,7 +19,7 @@ class FreshRSS_subscription_Controller extends Minz_ActionController {
 
 		$catDAO->checkDefault();
 		$feedDAO->updateTTL();
-		$this->view->categories = $catDAO->listCategories(false);
+		$this->view->categories = $catDAO->listSortedCategories(false);
 		$this->view->default_category = $catDAO->getDefault();
 	}
 
@@ -216,6 +216,9 @@ class FreshRSS_subscription_Controller extends Minz_ActionController {
 				]);
 			}
 
+			$position = Minz_Request::param('position');
+			$category->_attributes('position', '' === $position ? null : (int) $position);
+
 			$values = [
 				'name' => Minz_Request::param('name', ''),
 				'attributes' => $category->attributes(),

+ 2 - 2
app/Models/Category.php

@@ -98,14 +98,14 @@ class FreshRSS_Category extends Minz_Model {
 	}
 
 	public function _attributes($key, $value) {
-		if ($key == '') {
+		if ('' == $key) {
 			if (is_string($value)) {
 				$value = json_decode($value, true);
 			}
 			if (is_array($value)) {
 				$this->attributes = $value;
 			}
-		} elseif ($value === null) {
+		} elseif (null === $value) {
 			unset($this->attributes[$key]);
 		} else {
 			$this->attributes[$key] = $value;

+ 25 - 0
app/Models/CategoryDAO.php

@@ -201,6 +201,29 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable
 		}
 	}
 
+	public function listSortedCategories($prePopulateFeeds = true, $details = false) {
+		$categories = $this->listCategories($prePopulateFeeds, $details);
+
+		if (!is_array($categories)) {
+			return $categories;
+		}
+
+		usort($categories, function ($a, $b) {
+			$aPosition = $a->attributes('position');
+			$bPosition = $b->attributes('position');
+			if ($aPosition === $bPosition) {
+				return ($a->name() < $b->name()) ? -1 : 1;
+			} elseif (null === $aPosition) {
+				return 1;
+			} elseif (null === $bPosition) {
+				return -1;
+			}
+			return ($aPosition < $bPosition) ? -1 : 1;
+		});
+
+		return $categories;
+	}
+
 	public function listCategories($prePopulateFeeds = true, $details = false) {
 		if ($prePopulateFeeds) {
 			$sql = 'SELECT c.id AS c_id, c.name AS c_name, c.attributes AS c_attributes, '
@@ -343,6 +366,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable
 					$feedDao->daoToFeed($feedsDao, $previousLine['c_id'])
 				);
 				$cat->_id($previousLine['c_id']);
+				$cat->_attributes('', $previousLine['c_attributes']);
 				$list[$previousLine['c_id']] = $cat;
 
 				$feedsDao = array();	//Prepare for next category
@@ -359,6 +383,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable
 				$feedDao->daoToFeed($feedsDao, $previousLine['c_id'])
 			);
 			$cat->_id($previousLine['c_id']);
+			$cat->_attributes('', $previousLine['c_attributes']);
 			$list[$previousLine['c_id']] = $cat;
 		}
 

+ 2 - 0
app/i18n/cz/sub.php

@@ -17,6 +17,8 @@ return array(
 		'empty' => 'Vyprázdit kategorii',
 		'information' => 'Informace',
 		'new' => 'Nová kategorie',
+		'position' => 'Display position',	//TODO - Translation
+		'position_help' => 'To control category sort order',	//TODO - Translation
 		'title' => 'Název',
 	),
 	'feed' => array(

+ 2 - 0
app/i18n/de/sub.php

@@ -17,6 +17,8 @@ return array(
 		'empty' => 'Leere Kategorie',
 		'information' => 'Information',
 		'new' => 'Neue Kategorie',
+		'position' => 'Display position',	//TODO - Translation
+		'position_help' => 'To control category sort order',	//TODO - Translation
 		'title' => 'Titel',
 	),
 	'feed' => array(

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

@@ -17,6 +17,8 @@ return array(
 		'empty' => 'Empty category',
 		'information' => 'Information',
 		'new' => 'New category',
+		'position' => 'Display position',
+		'position_help' => 'To control category sort order',
 		'title' => 'Title',
 	),
 	'feed' => array(

+ 2 - 0
app/i18n/es/sub.php

@@ -17,6 +17,8 @@ return array(
 		'empty' => 'Vaciar categoría',
 		'information' => 'Información',
 		'new' => 'Nueva categoría',
+		'position' => 'Display position',	//TODO - Translation
+		'position_help' => 'To control category sort order',	//TODO - Translation
 		'title' => 'Título',
 	),
 	'feed' => array(

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

@@ -17,6 +17,8 @@ return array(
 		'empty' => 'Catégorie vide',
 		'information' => 'Informations',
 		'new' => 'Nouvelle catégorie',
+		'position' => 'Position d’affichage',
+		'position_help' => 'Pour contrôler l’ordre de tri des catégories',
 		'title' => 'Titre',
 	),
 	'feed' => array(

+ 2 - 0
app/i18n/he/sub.php

@@ -17,6 +17,8 @@ return array(
 		'empty' => 'Empty category',	//TODO - Translation
 		'information' => 'מידע',
 		'new' => 'קטגוריה חדשה',
+		'position' => 'Display position',	//TODO - Translation
+		'position_help' => 'To control category sort order',	//TODO - Translation
 		'title' => 'כותרת',
 	),
 	'feed' => array(

+ 2 - 0
app/i18n/it/sub.php

@@ -17,6 +17,8 @@ return array(
 		'empty' => 'Categoria vuota',
 		'information' => 'Informazioni',
 		'new' => 'Nuova categoria',
+		'position' => 'Display position',	//TODO - Translation
+		'position_help' => 'To control category sort order',	//TODO - Translation
 		'title' => 'Titolo',
 	),
 	'feed' => array(

+ 2 - 0
app/i18n/kr/sub.php

@@ -17,6 +17,8 @@ return array(
 		'empty' => '빈 카테고리',
 		'information' => '정보',
 		'new' => '새 카테고리',
+		'position' => 'Display position',	//TODO - Translation
+		'position_help' => 'To control category sort order',	//TODO - Translation
 		'title' => '제목',
 	),
 	'feed' => array(

+ 2 - 0
app/i18n/nl/sub.php

@@ -17,6 +17,8 @@ return array(
 		'empty' => 'Lege categorie',
 		'information' => 'Informatie',
 		'new' => 'Nieuwe categorie',
+		'position' => 'Display position',	//TODO - Translation
+		'position_help' => 'To control category sort order',	//TODO - Translation
 		'title' => 'Titel',
 	),
 	'feed' => array(

+ 2 - 0
app/i18n/oc/sub.php

@@ -16,6 +16,8 @@ return array(
 		'empty' => 'Categoria voida',
 		'information' => 'Informacions',
 		'new' => 'Nòva categoria',
+		'position' => 'Display position',	//TODO - Translation
+		'position_help' => 'To control category sort order',	//TODO - Translation
 		'title' => 'Títol',
 	),
 	'feed' => array(

+ 2 - 0
app/i18n/pt-br/sub.php

@@ -17,6 +17,8 @@ return array(
 		'empty' => 'Categoria vazia',
 		'information' => 'Informações',
 		'new' => 'Nova categoria',
+		'position' => 'Display position',	//TODO - Translation
+		'position_help' => 'To control category sort order',	//TODO - Translation
 		'title' => 'Título',
 	),
 	'feed' => array(

+ 2 - 0
app/i18n/ru/sub.php

@@ -17,6 +17,8 @@ return array(
 		'empty' => 'Empty category',	//TODO - Translation
 		'information' => 'Information',	//TODO - Translation
 		'new' => 'New category',	//TODO - Translation
+		'position' => 'Display position',	//TODO - Translation
+		'position_help' => 'To control category sort order',	//TODO - Translation
 		'title' => 'Title',	//TODO - Translation
 	),
 	'feed' => array(

+ 2 - 0
app/i18n/sk/sub.php

@@ -16,6 +16,8 @@ return array(
 		'empty' => 'Prázdna kategória',
 		'information' => 'Informácia',
 		'new' => 'Nová kategória',
+		'position' => 'Display position',	//TODO - Translation
+		'position_help' => 'To control category sort order',	//TODO - Translation
 		'title' => 'Názov',
 	),
 	'feed' => array(

+ 2 - 0
app/i18n/tr/sub.php

@@ -17,6 +17,8 @@ return array(
 		'empty' => 'Boş kategori',
 		'information' => 'Bilgi',
 		'new' => 'Yeni kategori',
+		'position' => 'Display position',	//TODO - Translation
+		'position_help' => 'To control category sort order',	//TODO - Translation
 		'title' => 'Başlık',
 	),
 	'feed' => array(

+ 2 - 0
app/i18n/zh-cn/sub.php

@@ -17,6 +17,8 @@ return array(
 		'empty' => '空分类',
 		'information' => '信息',
 		'new' => '新分类',
+		'position' => 'Display position',	//TODO - Translation
+		'position_help' => 'To control category sort order',	//TODO - Translation
 		'title' => '标题',
 	),
 	'feed' => array(

+ 2 - 1
app/layout/aside_feed.phtml

@@ -63,11 +63,12 @@
 		<?php
 			foreach ($this->categories as $cat) {
 				$feeds = $cat->feeds();
+				$position = $cat->attributes('position');
 				if (!empty($feeds)) {
 					$c_active = FreshRSS_Context::isCurrentGet('c_' . $cat->id());
 					$c_show = $c_active || FreshRSS_Context::$user_conf->display_categories;
 		?>
-		<li class="tree-folder category<?= $c_active ? ' active' : '' ?>" data-unread="<?= $cat->nbNotRead() ?>">
+		<li class="tree-folder category<?= $c_active ? ' active' : '' ?>"<?= null === $position ? '' : "data-position='$position'" ?> data-unread="<?= $cat->nbNotRead() ?>">
 			<div class="tree-folder-title">
 				<a class="dropdown-toggle" href="#"><?= _i($c_show ? 'up' : 'down') ?></a>
 				<a class="title<?= $cat->hasFeedsWithError() ? ' error' : '' ?>" data-unread="<?= format_number($cat->nbNotRead()) ?>" href="<?= _url('index', $actual_view, 'get', 'c_' . $cat->id()) ?>"><?= $cat->name() ?></a>

+ 7 - 0
app/views/helpers/category/update.phtml

@@ -17,6 +17,13 @@
 				?> />
 			</div>
 		</div>
+		<div class="form-group">
+			<label class="group-name" for="position"><?= _t('sub.category.position') ?></label>
+			<div class="group-controls">
+				<input type="number" name="position" id="position" min="1" value="<?= $this->category->attributes('position') ?>" />
+				<?= _i('help') ?> <?= _t('sub.category.position_help') ?>
+			</div>
+		</div>
 
 		<div class="form-group form-actions">
 			<div class="group-controls">