Просмотр исходного кода

Add a query configuration page (#3366)

* Add a query configuration page

Before, there was no way to modify a user query. Thus you need to
create a new one and delete the old one afterward.
Now, every user query can be modified if needed. They have their
own configuration page on which it can be modified or deleted.

* Change drag and drop action on queries

Before, the drag and drop action needed to be validated by submitting
the form to be persisted.
Now, it's done automatically after the query is dropped to its final
location.
Alexis Degrugillier 5 лет назад
Родитель
Сommit
c5da4e56a6

+ 84 - 0
app/Controllers/configureController.php

@@ -280,6 +280,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
 		$category_dao = FreshRSS_Factory::createCategoryDao();
 		$feed_dao = FreshRSS_Factory::createFeedDao();
 		$tag_dao = FreshRSS_Factory::createTagDao();
+
 		if (Minz_Request::isPost()) {
 			$params = Minz_Request::param('queries', array());
 
@@ -304,9 +305,92 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
 			}
 		}
 
+		$this->view->categories = $category_dao->listCategories(false);
+		$this->view->feeds = $feed_dao->listFeeds();
+		$this->view->tags = $tag_dao->listTags();
+
+		$id = Minz_Request::param('id');
+		$this->view->displaySlider = false;
+		if (false !== $id) {
+			$this->view->displaySlider = true;
+			$this->view->query = $this->view->queries[$id];
+			$this->view->queryId = $id;
+		}
+
 		Minz_View::prependTitle(_t('conf.query.title') . ' · ');
 	}
 
+	/**
+	 * Handles query configuration.
+	 * It displays the query configuration page and handles modifications
+	 * applied to the selected query.
+	 */
+	public function queryAction() {
+		$this->view->_layout(false);
+
+		$id = Minz_Request::param('id');
+		if (false === $id || !isset(FreshRSS_Context::$user_conf->queries[$id])) {
+			Minz_Error::error(404);
+			return;
+		}
+
+		$category_dao = FreshRSS_Factory::createCategoryDao();
+		$feed_dao = FreshRSS_Factory::createFeedDao();
+		$tag_dao = FreshRSS_Factory::createTagDao();
+
+		$query = new FreshRSS_UserQuery(FreshRSS_Context::$user_conf->queries[$id], $feed_dao, $category_dao, $tag_dao);
+		$this->view->query = $query;
+		$this->view->queryId = $id;
+		$this->view->categories = $category_dao->listCategories(false);
+		$this->view->feeds = $feed_dao->listFeeds();
+		$this->view->tags = $tag_dao->listTags();
+
+		if (Minz_Request::isPost()) {
+			$params = array_filter(Minz_Request::param('query', []));
+			if (!empty($params['search'])) {
+				$params['search'] = urldecode($params['search']);
+			}
+			if (!empty($params['state'])) {
+				$params['state'] = array_sum($params['state']);
+			}
+			$params['url'] = Minz_Url::display(['params' => $params]);
+			$name = Minz_Request::param('name', _t('conf.query.number', $id + 1));
+			if ('' === $name) {
+				$name = _t('conf.query.number', $id + 1);
+			}
+			$params['name'] = $name;
+
+			$queries = FreshRSS_Context::$user_conf->queries;
+			$queries[$id] = new FreshRSS_UserQuery($params, $feed_dao, $category_dao, $tag_dao);
+			FreshRSS_Context::$user_conf->queries = $queries;
+			FreshRSS_Context::$user_conf->save();
+
+			Minz_Request::good(_t('feedback.conf.updated'),
+			                   array('c' => 'configure', 'a' => 'queries', 'params' => ['id' => $id]));
+		}
+
+		Minz_View::prependTitle(_t('conf.query.title') . ' · ' . $query->getName() . ' · ');
+	}
+
+	/**
+	 * Handles query deletion
+	 */
+	public function deleteQueryAction() {
+		$id = Minz_Request::param('id');
+		if (false === $id || !isset(FreshRSS_Context::$user_conf->queries[$id])) {
+			Minz_Error::error(404);
+			return;
+		}
+
+		$queries = FreshRSS_Context::$user_conf->queries;
+		unset($queries[$id]);
+		FreshRSS_Context::$user_conf->queries = $queries;
+		FreshRSS_Context::$user_conf->save();
+
+		Minz_Request::good(_t('feedback.conf.updated'),
+			               array('c' => 'configure', 'a' => 'queries'));
+	}
+
 	/**
 	 * This action handles the creation of a user query.
 	 *

+ 11 - 1
app/i18n/cz/conf.php

@@ -65,12 +65,22 @@ return array(
 		'_' => 'Uživatelské dotazy',
 		'deprecated' => 'Tento dotaz již není platný. Odkazovaná kategorie nebo kanál byly smazány.',
 		'display' => 'Display user query results',	// TODO - Translation
-		'filter' => 'Filtr aplikován:',
+		'filter' => array(
+			'_' => 'Filtr aplikován:',
+			'categories' => 'Display by category',	// TODO - Translation
+			'feeds' => 'Display by feed',	// TODO - Translation
+			'order' => 'Sort by date',	// TODO - Translation
+			'search' => 'Expression',	// TODO - Translation
+			'state' => 'State',	// TODO - Translation
+			'tags' => 'Display by tag',	// TODO - Translation
+			'type' => 'Type',	// TODO - Translation
+		),
 		'get_all' => 'Zobrazit všechny články',
 		'get_category' => 'Zobrazit "%s" kategorii',
 		'get_favorite' => 'Zobrazit oblíbené články',
 		'get_feed' => 'Zobrazit "%s" článkek',
 		'get_tag' => 'Display "%s" label',	// TODO - Translation
+		'name' => 'Name',	// TODO - Translation
 		'no_filter' => 'Zrušit filtr',
 		'none' => 'Ještě jste nevytvořil žádný uživatelský dotaz.',
 		'number' => 'Dotaz n°%d',

+ 11 - 1
app/i18n/de/conf.php

@@ -65,12 +65,22 @@ return array(
 		'_' => 'Benutzerabfragen',
 		'deprecated' => 'Diese Abfrage ist nicht länger gültig. Die referenzierte Kategorie oder der Feed ist gelöscht worden.',
 		'display' => 'Zeige Abfrage Ergebnisse',
-		'filter' => 'Angewendeter Filter:',
+		'filter' => array(
+			'_' => 'Angewendeter Filter:',
+			'categories' => 'Display by category',	// TODO - Translation
+			'feeds' => 'Display by feed',	// TODO - Translation
+			'order' => 'Sort by date',	// TODO - Translation
+			'search' => 'Expression',	// TODO - Translation
+			'state' => 'State',	// TODO - Translation
+			'tags' => 'Display by tag',	// TODO - Translation
+			'type' => 'Type',	// TODO - Translation
+		),
 		'get_all' => 'Alle Artikel anzeigen',
 		'get_category' => 'Kategorie "%s" anzeigen',
 		'get_favorite' => 'Lieblingsartikel anzeigen',
 		'get_feed' => 'Feed "%s" anzeigen',
 		'get_tag' => 'Display "%s" label',	// TODO - Translation
+		'name' => 'Name',	// TODO - Translation
 		'no_filter' => 'Kein Filter',
 		'none' => 'Sie haben bisher keine Benutzerabfrage erstellt.',
 		'number' => 'Abfrage Nr. %d',

+ 11 - 1
app/i18n/en-us/conf.php

@@ -65,12 +65,22 @@ return array(
 		'_' => 'User queries',
 		'deprecated' => 'This query is no longer valid. The referenced category or feed has been deleted.',
 		'display' => 'Display user query results',
-		'filter' => 'Filter applied:',
+		'filter' => array(
+			'_' => 'Filter applied:',
+			'categories' => 'Display by category',
+			'feeds' => 'Display by feed',
+			'order' => 'Sort by date',
+			'search' => 'Expression',
+			'state' => 'State',
+			'tags' => 'Display by tag',
+			'type' => 'Type',
+		),
 		'get_all' => 'Display all articles',
 		'get_category' => 'Display "%s" category',
 		'get_favorite' => 'Display favorite articles',
 		'get_feed' => 'Display "%s" feed',
 		'get_tag' => 'Display "%s" label',
+		'name' => 'Name',
 		'no_filter' => 'No filter',
 		'none' => 'You haven’t created any user queries yet.',
 		'number' => 'Query n°%d',

+ 11 - 1
app/i18n/en/conf.php

@@ -65,12 +65,22 @@ return array(
 		'_' => 'User queries',
 		'deprecated' => 'This query is no longer valid. The referenced category or feed has been deleted.',
 		'display' => 'Display user query results',
-		'filter' => 'Filter applied:',
+		'filter' => array(
+			'_' => 'Filter applied:',
+			'categories' => 'Display by category',
+			'feeds' => 'Display by feed',
+			'order' => 'Sort by date',
+			'search' => 'Expression',
+			'state' => 'State',
+			'tags' => 'Display by tag',
+			'type' => 'Type',
+		),
 		'get_all' => 'Display all articles',
 		'get_category' => 'Display "%s" category',
 		'get_favorite' => 'Display favourite articles',
 		'get_feed' => 'Display "%s" feed',
 		'get_tag' => 'Display "%s" label',
+		'name' => 'Name',
 		'no_filter' => 'No filter',
 		'none' => 'You haven’t created any user queries yet.',
 		'number' => 'Query n°%d',

+ 11 - 1
app/i18n/es/conf.php

@@ -65,12 +65,22 @@ return array(
 		'_' => 'Consultas de usuario',
 		'deprecated' => 'Esta consulta ya no es válida. La categoría referenciada o fuente ha sido eliminada.',
 		'display' => 'Display user query results',	// TODO - Translation
-		'filter' => 'Filtro aplicado:',
+		'filter' => array(
+			'_' => 'Filtro aplicado:',
+			'categories' => 'Display by category',	// TODO - Translation
+			'feeds' => 'Display by feed',	// TODO - Translation
+			'order' => 'Sort by date',	// TODO - Translation
+			'search' => 'Expression',	// TODO - Translation
+			'state' => 'State',	// TODO - Translation
+			'tags' => 'Display by tag',	// TODO - Translation
+			'type' => 'Type',	// TODO - Translation
+		),
 		'get_all' => 'Mostrar todos los artículos',
 		'get_category' => 'Mostrar la categoría "%s"',
 		'get_favorite' => 'Mostrar artículos favoritos',
 		'get_feed' => 'Mostrar fuente "%s"',
 		'get_tag' => 'Display "%s" label',	// TODO - Translation
+		'name' => 'Name',	// TODO - Translation
 		'no_filter' => 'Sin filtro',
 		'none' => 'Todavía no has creado ninguna consulta de usuario.',
 		'number' => 'Consulta n° %d',

+ 11 - 1
app/i18n/fr/conf.php

@@ -65,12 +65,22 @@ return array(
 		'_' => 'Filtres utilisateurs',
 		'deprecated' => 'Ce filtre n’est plus valide. La catégorie ou le flux concerné a été supprimé.',
 		'display' => 'Afficher les résultats du filtre',
-		'filter' => 'Filtres appliqués :',
+		'filter' => array(
+			'_' => 'Filtres appliqués :',
+			'categories' => 'Afficher par catégorie',
+			'feeds' => 'Afficher par flux',
+			'order' => 'Tri par date',
+			'search' => 'Expression',
+			'state' => 'État',
+			'tags' => 'Afficher par étiquette',
+			'type' => 'Type',
+		),
 		'get_all' => 'Afficher tous les articles',
 		'get_category' => 'Afficher la catégorie "%s"',
 		'get_favorite' => 'Afficher les articles favoris',
 		'get_feed' => 'Afficher le flux "%s"',
 		'get_tag' => 'Afficher l’étiquette "%s"',
+		'name' => 'Nom',
 		'no_filter' => 'Aucun filtre appliqué',
 		'none' => 'Vous n’avez pas encore créé de filtre.',
 		'number' => 'Filtre n°%d',

+ 11 - 1
app/i18n/he/conf.php

@@ -65,12 +65,22 @@ return array(
 		'_' => 'שאילתות',
 		'deprecated' => 'שאילתה זו אינה בתוקף יותר, הפיד או הקטגוריה לייחוס נמחקו.',
 		'display' => 'Display user query results',	// TODO - Translation
-		'filter' => 'מסננים בשימוש:',
+		'filter' => array(
+			'_' => 'מסננים בשימוש:',
+			'categories' => 'Display by category',	// TODO - Translation
+			'feeds' => 'Display by feed',	// TODO - Translation
+			'order' => 'Sort by date',	// TODO - Translation
+			'search' => 'Expression',	// TODO - Translation
+			'state' => 'State',	// TODO - Translation
+			'tags' => 'Display by tag',	// TODO - Translation
+			'type' => 'Type',	// TODO - Translation
+		),
 		'get_all' => 'הצגת כל המאמרים',
 		'get_category' => 'הצגת קטגוריה "%s"',
 		'get_favorite' => 'הצגת מאמרים מועדפים',
 		'get_feed' => 'הצגת הזנה %s',
 		'get_tag' => 'Display "%s" label',	// TODO - Translation
+		'name' => 'Name',	// TODO - Translation
 		'no_filter' => 'ללא סינון',
 		'none' => 'אף שאילתה לא נוצרה עדיין.',
 		'number' => 'שאילתה מספר °%d',

+ 11 - 1
app/i18n/it/conf.php

@@ -65,12 +65,22 @@ return array(
 		'_' => 'Ricerche personali',
 		'deprecated' => 'Questa query non è più valida. La categoria o il feed di riferimento non stati cancellati.',
 		'display' => 'Display user query results',	// TODO - Translation
-		'filter' => 'Filtro applicato:',
+		'filter' => array(
+			'_' => 'Filtro applicato:',
+			'categories' => 'Display by category',	// TODO - Translation
+			'feeds' => 'Display by feed',	// TODO - Translation
+			'order' => 'Sort by date',	// TODO - Translation
+			'search' => 'Expression',	// TODO - Translation
+			'state' => 'State',	// TODO - Translation
+			'tags' => 'Display by tag',	// TODO - Translation
+			'type' => 'Type',	// TODO - Translation
+		),
 		'get_all' => 'Mostra tutti gli articoli',
 		'get_category' => 'Mostra la categoria "%s" ',
 		'get_favorite' => 'Mostra articoli preferiti',
 		'get_feed' => 'Mostra feed "%s" ',
 		'get_tag' => 'Display "%s" label',	// TODO - Translation
+		'name' => 'Name',	// TODO - Translation
 		'no_filter' => 'Nessun filtro',
 		'none' => 'Non hai creato nessuna ricerca personale.',
 		'number' => 'Ricerca n°%d',

+ 11 - 1
app/i18n/kr/conf.php

@@ -65,12 +65,22 @@ return array(
 		'_' => '사용자 쿼리',
 		'deprecated' => '이 쿼리는 더 이상 유효하지 않습니다. 해당하는 카테고리나 피드가 삭제되었습니다.',
 		'display' => '사용자 쿼리 결과 표시',
-		'filter' => '적용된 필터:',
+		'filter' => array(
+			'_' => 'Filter applied:',	// TODO - Translation
+			'categories' => 'Display by category',	// TODO - Translation
+			'feeds' => 'Display by feed',	// TODO - Translation
+			'order' => 'Sort by date',	// TODO - Translation
+			'search' => 'Expression',	// TODO - Translation
+			'state' => 'State',	// TODO - Translation
+			'tags' => 'Display by tag',	// TODO - Translation
+			'type' => 'Type',	// TODO - Translation
+		),
 		'get_all' => '모든 글 표시',
 		'get_category' => '"%s" 카테고리 표시',
 		'get_favorite' => '즐겨찾기에 등록된 글 표시',
 		'get_feed' => '"%s" 피드 표시',
 		'get_tag' => 'Display "%s" label',	// TODO - Translation
+		'name' => 'Name',	// TODO - Translation
 		'no_filter' => '필터가 없습니다',
 		'none' => '아직 사용자 쿼리를 만들지 않았습니다.',
 		'number' => '쿼리 #%d',

+ 11 - 1
app/i18n/nl/conf.php

@@ -65,12 +65,22 @@ return array(
 		'_' => 'Gebruikersquery\'s (informatie aanvragen)',
 		'deprecated' => 'Deze query (informatie aanvraag) is niet langer geldig. De bedoelde categorie of feed is al verwijderd.',
 		'display' => 'Queryresultaten weergeven',
-		'filter' => 'Filter toegepast:',
+		'filter' => array(
+			'_' => 'Filter toegepast:',
+			'categories' => 'Display by category',	// TODO - Translation
+			'feeds' => 'Display by feed',	// TODO - Translation
+			'order' => 'Sort by date',	// TODO - Translation
+			'search' => 'Expression',	// TODO - Translation
+			'state' => 'State',	// TODO - Translation
+			'tags' => 'Display by tag',	// TODO - Translation
+			'type' => 'Type',	// TODO - Translation
+		),
 		'get_all' => 'Toon alle artikelen',
 		'get_category' => 'Toon "%s" categorie',
 		'get_favorite' => 'Toon favoriete artikelen',
 		'get_feed' => 'Toon "%s" feed',
 		'get_tag' => 'Display "%s" label',	// TODO - Translation
+		'name' => 'Name',	// TODO - Translation
 		'no_filter' => 'Geen filter',
 		'none' => 'U hebt nog geen gebruikers query aangemaakt..',
 		'number' => 'Query n°%d',

+ 11 - 1
app/i18n/oc/conf.php

@@ -65,12 +65,22 @@ return array(
 		'_' => 'Filtres utilizaires',
 		'deprecated' => 'Aqueste filtre es pas valid. La categoria o lo flux concernit es estat suprimit.',
 		'display' => 'Mostrar los resultats del filtre',
-		'filter' => 'Filtres aplicats :',
+		'filter' => array(
+			'_' => 'Filtres aplicats :',
+			'categories' => 'Display by category',	// TODO - Translation
+			'feeds' => 'Display by feed',	// TODO - Translation
+			'order' => 'Sort by date',	// TODO - Translation
+			'search' => 'Expression',	// TODO - Translation
+			'state' => 'State',	// TODO - Translation
+			'tags' => 'Display by tag',	// TODO - Translation
+			'type' => 'Type',	// TODO - Translation
+		),
 		'get_all' => 'Mostrar totes los articles',
 		'get_category' => 'Mostrar la categoria « %s »',
 		'get_favorite' => 'Mostrar los articles favorits',
 		'get_feed' => 'Mostrar lo flux « %s »',
 		'get_tag' => 'Display "%s" label',	// TODO - Translation
+		'name' => 'Name',	// TODO - Translation
 		'no_filter' => 'Cap de filtre aplicat',
 		'none' => 'Avètz pas encara creat cap de filtre.',
 		'number' => 'Filtre n°%d',

+ 11 - 1
app/i18n/pl/conf.php

@@ -65,12 +65,22 @@ return array(
 		'_' => 'Zapisane zapytania',
 		'deprecated' => 'To zapytanie nie jest już poprawne. Kategoria lub kanał do którego się odnosi już nie istnieje.',
 		'display' => 'Pokaż wyniki dla tego zapytania',
-		'filter' => 'Zastosowane filtry:',
+		'filter' => array(
+			'_' => 'Zastosowane filtry:',
+			'categories' => 'Display by category',	// TODO - Translation
+			'feeds' => 'Display by feed',	// TODO - Translation
+			'order' => 'Sort by date',	// TODO - Translation
+			'search' => 'Expression',	// TODO - Translation
+			'state' => 'State',	// TODO - Translation
+			'tags' => 'Display by tag',	// TODO - Translation
+			'type' => 'Type',	// TODO - Translation
+		),
 		'get_all' => 'Wyświetlenie wszystkich wiadomości',
 		'get_category' => 'Wyświetlenie kategorii "%s"',
 		'get_favorite' => 'Wyświetlenie ulubionych wiadomości',
 		'get_feed' => 'Wyświetlenie kanału "%s"',
 		'get_tag' => 'Display "%s" label',	// TODO - Translation
+		'name' => 'Name',	// TODO - Translation
 		'no_filter' => 'Brak filtrów',
 		'none' => 'Nie zapisałeś jeszcze żadnego zapytania.',
 		'number' => 'Zapytanie nr %d',

+ 11 - 1
app/i18n/pt-br/conf.php

@@ -65,12 +65,22 @@ return array(
 		'_' => 'Queries do usuário',
 		'deprecated' => 'Esta não é mais válida. A categoria ou feed relacionado foi deletado.',
 		'display' => 'Exibir resultados da query do usuário',
-		'filter' => 'Filtro aplicado:',
+		'filter' => array(
+			'_' => 'Filtro aplicado:',
+			'categories' => 'Display by category',	// TODO - Translation
+			'feeds' => 'Display by feed',	// TODO - Translation
+			'order' => 'Sort by date',	// TODO - Translation
+			'search' => 'Expression',	// TODO - Translation
+			'state' => 'State',	// TODO - Translation
+			'tags' => 'Display by tag',	// TODO - Translation
+			'type' => 'Type',	// TODO - Translation
+		),
 		'get_all' => 'Mostrar todos os artigos',
 		'get_category' => 'Visualizar "%s" categoria',
 		'get_favorite' => 'Visualizar artigos favoritos',
 		'get_feed' => 'Visualizar "%s" feed',
 		'get_tag' => 'Display "%s" label',	// TODO - Translation
+		'name' => 'Name',	// TODO - Translation
 		'no_filter' => 'Sem filtro',
 		'none' => 'Você não criou nenhuma query de usuário ainda.',
 		'number' => 'Query n°%d',

+ 11 - 1
app/i18n/ru/conf.php

@@ -65,12 +65,22 @@ return array(
 		'_' => 'User queries',	// TODO - Translation
 		'deprecated' => 'This query is no longer valid. The referenced category or feed has been deleted.',	// TODO - Translation
 		'display' => 'Display user query results',	// TODO - Translation
-		'filter' => 'Filter applied:',	// TODO - Translation
+		'filter' => array(
+			'_' => 'Filter applied:',	// TODO - Translation
+			'categories' => 'Display by category',	// TODO - Translation
+			'feeds' => 'Display by feed',	// TODO - Translation
+			'order' => 'Sort by date',	// TODO - Translation
+			'search' => 'Expression',	// TODO - Translation
+			'state' => 'State',	// TODO - Translation
+			'tags' => 'Display by tag',	// TODO - Translation
+			'type' => 'Type',	// TODO - Translation
+		),
 		'get_all' => 'Display all articles',	// TODO - Translation
 		'get_category' => 'Display "%s" category',	// TODO - Translation
 		'get_favorite' => 'Display favorite articles',
 		'get_feed' => 'Display "%s" feed',	// TODO - Translation
 		'get_tag' => 'Display "%s" label',	// TODO - Translation
+		'name' => 'Name',	// TODO - Translation
 		'no_filter' => 'No filter',	// TODO - Translation
 		'none' => 'You haven’t created any user query yet.',
 		'number' => 'Query n°%d',	// TODO - Translation

+ 11 - 1
app/i18n/sk/conf.php

@@ -65,12 +65,22 @@ return array(
 		'_' => 'Dopyty používateľa',
 		'deprecated' => 'Tento dopyt už nie je platný. Kategória alebo kanál boli vymazané.',
 		'display' => 'Zobraziť výsledky dopytu používateľa',
-		'filter' => 'Použitý filter:',
+		'filter' => array(
+			'_' => 'Použitý filter:',
+			'categories' => 'Display by category',	// TODO - Translation
+			'feeds' => 'Display by feed',	// TODO - Translation
+			'order' => 'Sort by date',	// TODO - Translation
+			'search' => 'Expression',	// TODO - Translation
+			'state' => 'State',	// TODO - Translation
+			'tags' => 'Display by tag',	// TODO - Translation
+			'type' => 'Type',	// TODO - Translation
+		),
 		'get_all' => 'Zobraziť všetky články',
 		'get_category' => 'Zobraziť kategóriu "%s"',
 		'get_favorite' => 'Zobraziť obľúbené články',
 		'get_feed' => 'Zobraziť kanál "%s"',
 		'get_tag' => 'Display "%s" label',	// TODO - Translation
+		'name' => 'Name',	// TODO - Translation
 		'no_filter' => 'Žiadny filter',
 		'none' => 'Zatiaľ ste nevytvorili používateľský dopyt.',
 		'number' => 'Dopyt číslo %d',

+ 11 - 1
app/i18n/tr/conf.php

@@ -65,12 +65,22 @@ return array(
 		'_' => 'Kullanıcı sorguları',
 		'deprecated' => 'Bu sorgu artık geçerli değil. İlgili akış veya kategori silinmiş.',
 		'display' => 'Display user query results',	// TODO - Translation
-		'filter' => 'Filtre uygulandı:',
+		'filter' => array(
+			'_' => 'Filtre uygulandı:',
+			'categories' => 'Display by category',	// TODO - Translation
+			'feeds' => 'Display by feed',	// TODO - Translation
+			'order' => 'Sort by date',	// TODO - Translation
+			'search' => 'Expression',	// TODO - Translation
+			'state' => 'State',	// TODO - Translation
+			'tags' => 'Display by tag',	// TODO - Translation
+			'type' => 'Type',	// TODO - Translation
+		),
 		'get_all' => 'Tüm makaleleri göster',
 		'get_category' => '"%s" kategorisini göster',
 		'get_favorite' => 'Favori makaleleri göster',
 		'get_feed' => '"%s" akışını göster',
 		'get_tag' => 'Display "%s" label',	// TODO - Translation
+		'name' => 'Name',	// TODO - Translation
 		'no_filter' => 'Filtre yok',
 		'none' => 'Henüz hiç kullanıcı sorgusu oluşturmadınız.',
 		'number' => 'Sorgu n°%d',

+ 11 - 1
app/i18n/zh-cn/conf.php

@@ -65,12 +65,22 @@ return array(
 		'_' => '自定义查询',
 		'deprecated' => '此查询不再有效。相关的分类或订阅源已被删除。',
 		'display' => '显示查询结果',
-		'filter' => '生效的过滤器:',
+		'filter' => array(
+			'_' => '生效的过滤器:',
+			'categories' => 'Display by category',	// TODO - Translation
+			'feeds' => 'Display by feed',	// TODO - Translation
+			'order' => 'Sort by date',	// TODO - Translation
+			'search' => 'Expression',	// TODO - Translation
+			'state' => 'State',	// TODO - Translation
+			'tags' => 'Display by tag',	// TODO - Translation
+			'type' => 'Type',	// TODO - Translation
+		),
 		'get_all' => '显示所有文章',
 		'get_category' => '显示分类 "%s"',
 		'get_favorite' => '显示收藏文章',
 		'get_feed' => '显示订阅源 "%s"',
 		'get_tag' => 'Display "%s" label',	// TODO - Translation
+		'name' => 'Name',	// TODO - Translation
 		'no_filter' => '无过滤器',
 		'none' => '你未创建任何自定义查询。',
 		'number' => '查询 n°%d',

+ 15 - 29
app/views/configure/queries.phtml

@@ -14,30 +14,15 @@
 			</label>
 
 			<div class="group-controls">
+				<?= $query->getName() ?>
+				<a class="configure open-slider" href="<?= _url('configure', 'query', 'id', $key) ?>"><?= _i('configure') ?></a>
+				<input type="hidden" id="queries_<?= $key ?>_name" name="queries[<?= $key ?>][name]" value="<?= $query->getName() ?>"/>
 				<input type="hidden" id="queries_<?= $key ?>_url" name="queries[<?= $key ?>][url]" value="<?= $query->getUrl() ?>"/>
 				<input type="hidden" id="queries_<?= $key ?>_search" name="queries[<?= $key ?>][search]" value="<?= urlencode($query->getSearch()) ?>"/>
 				<input type="hidden" id="queries_<?= $key ?>_state" name="queries[<?= $key ?>][state]" value="<?= $query->getState() ?>"/>
 				<input type="hidden" id="queries_<?= $key ?>_order" name="queries[<?= $key ?>][order]" value="<?= $query->getOrder() ?>"/>
 				<input type="hidden" id="queries_<?= $key ?>_get" name="queries[<?= $key ?>][get]" value="<?= $query->getGet() ?>"/>
 
-				<div class="stick">
-					<input class="extend"
-					       type="text"
-					       id="queries_<?= $key ?>_name"
-					       name="queries[<?= $key ?>][name]"
-					       value="<?= $query->getName() ?>"
-					       data-leave-validation="<?= $query->getName() ?>"
-					/>
-
-					<a class="btn" href="<?= $query->getUrl() ?>" title="<?= _t('conf.query.display') ?>">
-						<?= _i('link') ?>
-					</a>
-
-					<a class="btn btn-attention remove" href="#" data-remove="query-group-<?= $key ?>" title="<?= _t('conf.query.remove') ?>">
-						<?= _i('close') ?>
-					</a>
-				</div>
-
 				<?php if (!$query->hasParameters()) { ?>
 				<div class="alert alert-warn">
 					<div class="alert-head"><?= _t('conf.query.no_filter') ?></div>
@@ -72,16 +57,17 @@
 			</div>
 		</div>
 		<?php } ?>
-
-		<?php if (count(FreshRSS_Context::$user_conf->queries) > 0) { ?>
-		<div class="form-group form-actions">
-			<div class="group-controls">
-				<button type="submit" class="btn btn-important"><?= _t('gen.action.submit') ?></button>
-			</div>
-		</div>
-		<?php } else { ?>
-		<p class="alert alert-warn"><span class="alert-head"><?= _t('gen.short.damn') ?></span> <?= _t('conf.query.none') ?></p>
-		<?php } ?>
 	</form>
+</div>
 
-</div>
+<?php $class = $this->displaySlider ? ' class="active"' : ''; ?>
+<a href="#" id="close-slider"<?= $class ?>>
+	<?= _i('close') ?>
+</a>
+<div id="slider"<?= $class ?>>
+<?php
+	if (isset($this->query)) {
+		$this->renderHelper('configure/query');
+	}
+?>
+</div>

+ 5 - 0
app/views/configure/query.phtml

@@ -0,0 +1,5 @@
+<?php
+
+if ($this->query) {
+	$this->renderHelper('configure/query');
+}

+ 91 - 0
app/views/helpers/configure/query.phtml

@@ -0,0 +1,91 @@
+<div class="post">
+	<h1><?= $this->query->getName() ?></h1>
+
+	<div>
+		<a href="<?= $this->query->getUrl() ?>"><?= _i('link') ?> <?= _t('gen.action.filter') ?></a>
+	</div>
+
+	<form method="post" action="<?= _url('configure', 'query', 'id', $this->queryId) ?>" autocomplete="off">
+		<input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
+
+		<div class="form-group">
+			<label class="group-name" for="name"><?= _t('conf.query.name') ?></label>
+			<div class="group-controls">
+				<input type="text" name="name" id="name" class="extend" value="<?= $this->query->getName()  ?>" />
+			</div>
+		</div>
+		<legend><?= _t('conf.query.filter') ?></legend>
+
+		<div class="form-group">
+			<label class="group-name" for=""><?= _t('conf.query.filter.search') ?></label>
+			<div class="group-controls">
+				<input type="text" id="query_search" name="query[search]"  class="extend" value="<?= urldecode($this->query->getSearch()) ?>"/>
+			</div>
+		</div>
+		<div class="form-group">
+			<label class="group-name" for=""><?= _t('conf.query.filter.state') ?></label>
+			<div class="group-controls">
+				<label class="checkbox" for="show_read">
+					<input type="checkbox" name="query[state][]" id="show_read" value="<?= FreshRSS_Entry::STATE_READ ?>" <?= FreshRSS_Entry::STATE_READ & $this->query->getState() ? 'checked="checked"' : ''?> />
+					<?= _t('index.menu.read') ?>
+				</label>
+				<label class="checkbox" for="show_not_read">
+					<input type="checkbox" name="query[state][]" id="show_not_read" value="<?= FreshRSS_Entry::STATE_NOT_READ ?>" <?= FreshRSS_Entry::STATE_NOT_READ & $this->query->getState() ? 'checked="checked"' : ''?> />
+					<?= _t('index.menu.unread') ?>
+				</label>
+				<label class="checkbox" for="show_favorite">
+					<input type="checkbox" name="query[state][]" id="show_favorite" value="<?= FreshRSS_Entry::STATE_FAVORITE ?>" <?= FreshRSS_Entry::STATE_FAVORITE & $this->query->getState() ? 'checked="checked"' : ''?> />
+					<?= _t('index.menu.starred') ?>
+				</label>
+				<label class="checkbox" for="show_not_favorite">
+					<input type="checkbox" name="query[state][]" id="show_not_favorite" value="<?= FreshRSS_Entry::STATE_NOT_FAVORITE ?>" <?= FreshRSS_Entry::STATE_NOT_FAVORITE & $this->query->getState() ? 'checked="checked"' : ''?> />
+					<?= _t('index.menu.non-starred') ?>
+				</label>
+			</div>
+		</div>
+		<div class="form-group">
+			<label class="group-name" for="query_get"><?= _t('conf.query.filter.type') ?></label>
+			<div class="group-controls">
+				<select name="query[get]" id="query_get" size="10">
+					<option value=""></option>
+					<option value="s" <?= 's' === $this->query->getGet() ? 'selected="selected"' : '' ?>><?= _t('conf.query.get_favorite') ?></option>
+					<optgroup label="<?= _t('conf.query.filter.categories') ?>">
+						<?php foreach ($this->categories as $category): ?>
+							<option value="c_<?= $category->id() ?>" <?= "c_{$category->id()}" === $this->query->getGet() ? 'selected="selected"' : '' ?>><?= $category->name() ?></option>
+						<?php endforeach?>
+					</optgroup>
+					<optgroup label="<?= _t('conf.query.filter.feeds') ?>">
+					<?php foreach ($this->feeds as $feed): ?>
+						<option value="f_<?= $feed->id() ?>" <?= "f_{$feed->id()}" === $this->query->getGet() ? 'selected="selected"' : '' ?>><?= $feed->name() ?></option>
+					<?php endforeach?>
+					</optgroup>
+					<optgroup label="<?= _t('conf.query.filter.tags') ?>">
+					<?php foreach ($this->tags as $tag): ?>
+						<option value="t_<?= $tag->id() ?>" <?= "t_{$tag->id()}" === $this->query->getGet() ? 'selected="selected"' : '' ?>><?= $tag->name() ?></option>
+					<?php endforeach?>
+					</optgroup>
+				</select>
+			</div>
+		</div>
+		<div class="form-group">
+			<label class="group-name" for=""><?= _t('conf.query.filter.order') ?></label>
+			<div class="group-controls">
+				<select name="query[order]" id="query_order">
+					<option value=""></option>
+					<option value="ASC" <?= 'ASC' === $this->query->getOrder() ? 'selected="selected"' : '' ?>><?= _t('conf.query.order_asc') ?></option>
+					<option value="DESC" <?= 'DESC' === $this->query->getOrder() ? 'selected="selected"' : '' ?>><?= _t('conf.query.order_desc') ?></option>
+				</select>
+			</div>
+		</div>
+
+		<div class="form-group form-actions">
+			<div class="group-controls">
+				<button class="btn btn-important"><?= _t('gen.action.submit') ?></button>
+				<button class="btn btn-attention confirm"
+					data-str-confirm="<?= _t('gen.js.confirm_action_feed_cat') ?>"
+					formaction="<?= _url('configure', 'deleteQuery', 'id', $this->queryId) ?>"
+					formmethod="post"><?= _t('gen.action.remove') ?></button>
+			</div>
+		</div>
+	</form>
+</div>

+ 9 - 1
cli/i18n/ignore/en-us.php

@@ -190,11 +190,19 @@ return array(
 	'conf.query._',
 	'conf.query.deprecated',
 	'conf.query.display',
-	'conf.query.filter',
+	'conf.query.filter._',
+	'conf.query.filter.categories',
+	'conf.query.filter.feeds',
+	'conf.query.filter.order',
+	'conf.query.filter.search',
+	'conf.query.filter.state',
+	'conf.query.filter.tags',
+	'conf.query.filter.type',
 	'conf.query.get_all',
 	'conf.query.get_category',
 	'conf.query.get_feed',
 	'conf.query.get_tag',
+	'conf.query.name',
 	'conf.query.no_filter',
 	'conf.query.none',
 	'conf.query.number',

+ 2 - 0
cli/i18n/ignore/fr.php

@@ -9,6 +9,8 @@ return array(
 	'admin.user.articles_and_size',
 	'conf.archiving.maintenance',
 	'conf.display.width.large',
+	'conf.query.filter.search',
+	'conf.query.filter.type',
 	'conf.sharing.blogotext',
 	'conf.sharing.diaspora',
 	'conf.sharing.facebook',

+ 1 - 0
p/scripts/user.query.js

@@ -73,6 +73,7 @@ const init_draggable = function() {
 		}
 		source.remove();
 		removeMarker();
+		configureQueries.submit();
 	});
 
 	// This is needed to work around a Firefox bug → https://bugzilla.mozilla.org/show_bug.cgi?id=800050