Changed behavior of post list tabs
Before: each one linked to separate page that contained "static" search. After: each one links to generic search that is aware of current search. Example: if you searched for "snow" and clicked "upvoted", you would see all upvoted posts ever regardless of what you just searched for. After this change, you will see upvoted posts that have tag "snow". Now, if you go back to "all posts", you will see again all posts tagged with "snow" with or without the upvotes. Similarly if you click favorites, favmin:1 will be appended to your search. In order to totally reset your search, click "browse". Additionally, typing favmin:1 and scoremin:1 manually now selects proper tab. Previously tabs were marked only if you clicked the tab. Unfortunately, all of this had to happen at expense of URLs like /upvoted and /random - now everything is represented with plain /posts/.
This commit is contained in:
parent
ea5a07b509
commit
b97726f6ff
6 changed files with 128 additions and 88 deletions
|
@ -70,21 +70,6 @@ class PostController extends AbstractController
|
|||
$this->redirect($url);
|
||||
}
|
||||
|
||||
public function favoritesView($page = 1)
|
||||
{
|
||||
$this->listView('favmin:1', $page, 'favorites');
|
||||
}
|
||||
|
||||
public function upvotedView($page = 1)
|
||||
{
|
||||
$this->listView('scoremin:1', $page, 'upvoted');
|
||||
}
|
||||
|
||||
public function randomView($page = 1)
|
||||
{
|
||||
$this->listView('order:random', $page, 'random');
|
||||
}
|
||||
|
||||
public function toggleTagAction($identifier, $tag, $enable)
|
||||
{
|
||||
Access::assert(new Privilege(
|
||||
|
|
|
@ -5,11 +5,41 @@ abstract class AbstractSearchParser
|
|||
{
|
||||
protected $statement;
|
||||
|
||||
public function decorate($statement, $filterString)
|
||||
public function disassembleTokens($searchString)
|
||||
{
|
||||
return preg_split('/\s+/', $searchString);
|
||||
}
|
||||
|
||||
public function assembleTokens($tokens)
|
||||
{
|
||||
return implode(' ', $tokens);
|
||||
}
|
||||
|
||||
public function addTokenToSearchString($searchString, $token)
|
||||
{
|
||||
$tokensToInclude = is_array($token)
|
||||
? $token
|
||||
: [$token];
|
||||
$tokens = $this->disassembleTokens($searchString);
|
||||
$newTokens = array_filter(array_unique(array_merge($tokens, $tokensToInclude)));
|
||||
return $this->assembleTokens($newTokens);
|
||||
}
|
||||
|
||||
public function removeTokenFromSearchString($searchString, $token)
|
||||
{
|
||||
$tokensToExclude = is_array($token)
|
||||
? $token
|
||||
: [$token];
|
||||
$tokens = $this->disassembleTokens($searchString);
|
||||
$newTokens = array_diff($tokens, $tokensToExclude);
|
||||
return $this->assembleTokens($newTokens);
|
||||
}
|
||||
|
||||
public function decorate($statement, $searchString)
|
||||
{
|
||||
$this->statement = $statement;
|
||||
|
||||
$tokens = preg_split('/\s+/', $filterString);
|
||||
$tokens = $this->disassembleTokens($searchString);
|
||||
$tokens = array_filter($tokens);
|
||||
$tokens = array_unique($tokens);
|
||||
$this->processSetup($tokens);
|
||||
|
|
|
@ -3,38 +3,7 @@ use \Chibi\Sql as Sql;
|
|||
|
||||
abstract class AbstractSearchService
|
||||
{
|
||||
protected static function getModelClassName()
|
||||
{
|
||||
$searchServiceClassName = get_called_class();
|
||||
$modelClassName = str_replace('SearchService', 'Model', $searchServiceClassName);
|
||||
return $modelClassName;
|
||||
}
|
||||
|
||||
protected static function getParserClassName()
|
||||
{
|
||||
$searchServiceClassName = get_called_class();
|
||||
$parserClassName = str_replace('SearchService', 'SearchParser', $searchServiceClassName);
|
||||
return $parserClassName;
|
||||
}
|
||||
|
||||
protected static function decorateParser($stmt, $searchQuery)
|
||||
{
|
||||
$parserClassName = self::getParserClassName();
|
||||
(new $parserClassName)->decorate($stmt, $searchQuery);
|
||||
}
|
||||
|
||||
protected static function decorateCustom($stmt)
|
||||
{
|
||||
}
|
||||
|
||||
protected static function decoratePager($stmt, $perPage, $page)
|
||||
{
|
||||
if ($perPage === null)
|
||||
return;
|
||||
$stmt->setLimit(
|
||||
new Sql\Binding($perPage),
|
||||
new Sql\Binding(($page - 1) * $perPage));
|
||||
}
|
||||
protected static $parser;
|
||||
|
||||
public static function getEntities($searchQuery, $perPage = null, $page = 1)
|
||||
{
|
||||
|
@ -44,7 +13,7 @@ abstract class AbstractSearchService
|
|||
$stmt = Sql\Statements::select();
|
||||
$stmt->setColumn($table . '.*');
|
||||
$stmt->setTable($table);
|
||||
static::decorateParser($stmt, $searchQuery);
|
||||
static::decorateFromParser($stmt, $searchQuery);
|
||||
static::decorateCustom($stmt);
|
||||
static::decoratePager($stmt, $perPage, $page);
|
||||
|
||||
|
@ -60,7 +29,7 @@ abstract class AbstractSearchService
|
|||
|
||||
$innerStmt = Sql\Statements::select();
|
||||
$innerStmt->setTable($table);
|
||||
static::decorateParser($innerStmt, $searchQuery);
|
||||
static::decorateFromParser($innerStmt, $searchQuery);
|
||||
static::decorateCustom($innerStmt);
|
||||
$innerStmt->resetOrderBy();
|
||||
|
||||
|
@ -70,4 +39,45 @@ abstract class AbstractSearchService
|
|||
|
||||
return Core::getDatabase()->fetchOne($stmt)['count'];
|
||||
}
|
||||
|
||||
public static function getParser()
|
||||
{
|
||||
$parserClassName = self::getParserClassName();
|
||||
if (self::$parser == null)
|
||||
self::$parser = new $parserClassName();
|
||||
return self::$parser;
|
||||
}
|
||||
|
||||
protected static function getModelClassName()
|
||||
{
|
||||
$searchServiceClassName = get_called_class();
|
||||
$modelClassName = str_replace('SearchService', 'Model', $searchServiceClassName);
|
||||
return $modelClassName;
|
||||
}
|
||||
|
||||
protected static function decorateFromParser($stmt, $searchQuery)
|
||||
{
|
||||
self::getParser()->decorate($stmt, $searchQuery);
|
||||
}
|
||||
|
||||
protected static function decorateCustom($stmt)
|
||||
{
|
||||
}
|
||||
|
||||
protected static function decoratePager($stmt, $perPage, $page)
|
||||
{
|
||||
if ($perPage === null)
|
||||
return;
|
||||
$stmt->setLimit(
|
||||
new Sql\Binding($perPage),
|
||||
new Sql\Binding(($page - 1) * $perPage));
|
||||
}
|
||||
|
||||
private static function getParserClassName()
|
||||
{
|
||||
$searchServiceClassName = get_called_class();
|
||||
$parserClassName = str_replace('SearchService', 'SearchParser', $searchServiceClassName);
|
||||
return $parserClassName;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ class PostSearchService extends AbstractSearchService
|
|||
$innerStmt = Sql\Statements::select();
|
||||
$innerStmt->setColumn('post.id');
|
||||
$innerStmt->setTable('post');
|
||||
self::decorateParser($innerStmt, $searchQuery);
|
||||
self::decorateFromParser($innerStmt, $searchQuery);
|
||||
$stmt = Sql\Statements::insert();
|
||||
$stmt->setTable('post_search');
|
||||
$stmt->setSource(['post_id'], $innerStmt);
|
||||
|
|
|
@ -63,13 +63,6 @@ class Router extends \Chibi\Routing\Router
|
|||
$this->register(['PostController', 'listView'], 'GET', '/{source}/{query}/{additionalInfo}/{page}', $postValidation);
|
||||
$this->register(['PostController', 'listRedirectAction'], 'POST', '/{source}-redirect', $postValidation);
|
||||
|
||||
$this->register(['PostController', 'randomView'], 'GET', '/random', $postValidation);
|
||||
$this->register(['PostController', 'randomView'], 'GET', '/random/{page}', $postValidation);
|
||||
$this->register(['PostController', 'favoritesView'], 'GET', '/favorites', $postValidation);
|
||||
$this->register(['PostController', 'favoritesView'], 'GET', '/favorites/{page}', $postValidation);
|
||||
$this->register(['PostController', 'upvotedView'], 'GET', '/upvoted', $postValidation);
|
||||
$this->register(['PostController', 'upvotedView'], 'GET', '/upvoted/{page}', $postValidation);
|
||||
|
||||
$this->register(['PostController', 'genericView'], 'GET', '/post/{identifier}', $postValidation);
|
||||
$this->register(['PostController', 'fileView'], 'GET', '/post/{name}/retrieve', $postValidation);
|
||||
$this->register(['PostController', 'thumbnailView'], 'GET', '/post/{name}/thumb', $postValidation);
|
||||
|
|
|
@ -1,59 +1,81 @@
|
|||
<?php
|
||||
$this->assets->setSubTitle('posts');
|
||||
$searchQuery = isset($this->context->transport->searchQuery)
|
||||
? htmlspecialchars($this->context->transport->searchQuery)
|
||||
: '';
|
||||
|
||||
$parser = PostSearchService::getParser();
|
||||
$newSearchQuery = PostSearchService::getParser()->removeTokenFromSearchString(
|
||||
$searchQuery,
|
||||
['favmin:1', 'scoremin:1', 'order:random']);
|
||||
|
||||
$tabs = [];
|
||||
$activeTab = 0;
|
||||
if (Access::check(new Privilege(Privilege::ListPosts)))
|
||||
$tabs []= ['All posts', Core::getRouter()->linkTo(['PostController', 'listView'])];
|
||||
|
||||
if (Access::check(new Privilege(Privilege::ListPosts)))
|
||||
{
|
||||
$tabs []= ['Random', Core::getRouter()->linkTo(['PostController', 'randomView'])];
|
||||
if ($this->context->source == 'random')
|
||||
$activeTab = count($tabs) - 1;
|
||||
$tabs []= [
|
||||
'title' => 'All posts',
|
||||
'active' => function() { return true; },
|
||||
'link' => Core::getRouter()->linkTo(
|
||||
['PostController', 'listView'],
|
||||
!trim($newSearchQuery) ? [] : ['query' => $newSearchQuery])];
|
||||
|
||||
$tabs []= ['Favorites', Core::getRouter()->linkTo(['PostController', 'favoritesView'])];
|
||||
if ($this->context->source == 'favorites')
|
||||
$activeTab = count($tabs) - 1;
|
||||
$tabs []= [
|
||||
'title' => 'Random',
|
||||
'active' => function() use ($searchQuery) { return strpos($searchQuery, 'order:random') !== false; },
|
||||
'link' => Core::getRouter()->linkTo(
|
||||
['PostController', 'listView'],
|
||||
['query' => $parser->addTokenToSearchString($newSearchQuery, 'order:random')])];
|
||||
|
||||
$tabs []= ['Upvoted', Core::getRouter()->linkTo(['PostController', 'upvotedView'])];
|
||||
if ($this->context->source == 'upvoted')
|
||||
$activeTab = count($tabs) - 1;
|
||||
$tabs []= [
|
||||
'title' => 'Favorites',
|
||||
'active' => function() use ($searchQuery) { return strpos($searchQuery, 'favmin:1') !== false; },
|
||||
'link' => Core::getRouter()->linkTo(
|
||||
['PostController', 'listView'],
|
||||
['query' => $parser->addTokenToSearchString($newSearchQuery, 'favmin:1')])];
|
||||
|
||||
$tabs []= [
|
||||
'title' => 'Upvoted',
|
||||
'active' => function() use ($searchQuery) { return strpos($searchQuery, 'scoremin:1') !== false; },
|
||||
'link' => Core::getRouter()->linkTo(
|
||||
['PostController', 'listView'],
|
||||
['query' => $parser->addTokenToSearchString($newSearchQuery, 'scoremin:1')])];
|
||||
}
|
||||
|
||||
if (Access::check(new Privilege(Privilege::MassTag)))
|
||||
{
|
||||
$tabs []= ['Mass tag', Core::getRouter()->linkTo(['PostController', 'listView'], [
|
||||
'source' => 'mass-tag',
|
||||
'query' => isset($this->context->transport->searchQuery)
|
||||
? htmlspecialchars($this->context->transport->searchQuery)
|
||||
: '',
|
||||
'page' => isset($this->context->transport->paginator)
|
||||
? $this->context->transport->paginator->page
|
||||
: 1])];
|
||||
|
||||
if ($this->context->source == 'mass-tag')
|
||||
$activeTab = count($tabs) - 1;
|
||||
$tabs []= [
|
||||
'title' => 'Mass tag',
|
||||
'active' => function() { return $this->context->source == 'mass-tag'; },
|
||||
'link' => Core::getRouter()->linkTo(['PostController', 'listView'], [
|
||||
'source' => 'mass-tag',
|
||||
'query' => $searchQuery,
|
||||
'page' => isset($this->context->transport->paginator)
|
||||
? $this->context->transport->paginator->page
|
||||
: 1])];
|
||||
}
|
||||
|
||||
$activeTab = null;
|
||||
foreach ($tabs as $key => $tab)
|
||||
if ($tab['active']())
|
||||
$activeTab = $key;
|
||||
?>
|
||||
|
||||
<nav class="tabs">
|
||||
<ul>
|
||||
<?php foreach ($tabs as $i => $tab): ?>
|
||||
<?php foreach ($tabs as $key => $tab): ?>
|
||||
<?php
|
||||
list($name, $url) = $tab;
|
||||
$classes = [];
|
||||
$classes []= TextCaseConverter::convert($name,
|
||||
$classes []= TextCaseConverter::convert($tab['title'],
|
||||
TextCaseConverter::BLANK_CASE,
|
||||
TextCaseConverter::SPINAL_CASE);
|
||||
if ($i == $activeTab)
|
||||
if ($key == $activeTab)
|
||||
$classes []= 'selected';
|
||||
?>
|
||||
|
||||
<li class="<?= join(' ', $classes) ?>">
|
||||
<a href="<?= $url ?>">
|
||||
<?= $name ?>
|
||||
<a href="<?= $tab['link'] ?>">
|
||||
<?= $tab['title'] ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php endforeach ?>
|
||||
|
|
Loading…
Reference in a new issue