Added tag listing

This commit is contained in:
Marcin Kurczewski 2014-10-06 21:16:59 +02:00
parent 7579d962ba
commit 49124298a2
12 changed files with 230 additions and 7 deletions

3
TODO
View file

@ -29,9 +29,6 @@ everything related to tags:
- automatic removal of unused tags in backend
- tags.json refresh when editing post
- basic tags
- listing
- sort alphabetically
- sort by time of addition
- mass tag
- merging
- tag editing

View file

@ -0,0 +1,28 @@
#tag-list {
text-align: center;
}
#tag-list ul {
list-style-type: none;
padding: 0;
margin: 0;
}
#ta-list ul.order {
margin: -0.5em -0.5em 0.5em -0.5em;
}
#tag-list ul.order li {
display: inline-block;
margin: 0 0.5em;
}
#tag-list ul.order a {
cursor: pointer;
display: inline-block;
padding: 0.2em 0.5em;
}
#tag-list table {
min-width: 20em;
text-align: left;
margin: 1em auto;
}

View file

@ -39,6 +39,7 @@
<link rel="stylesheet" type="text/css" href="/css/history.css"/>
<link rel="stylesheet" type="text/css" href="/css/comments.css"/>
<link rel="stylesheet" type="text/css" href="/css/tags.css"/>
<link rel="stylesheet" type="text/css" href="/css/tag-list.css"/>
<!-- /build -->
<!-- build:remove -->

View file

@ -2,27 +2,94 @@ var App = App || {};
App.Presenters = App.Presenters || {};
App.Presenters.TagListPresenter = function(
_,
jQuery,
util,
promise,
pagerPresenter,
topNavigationPresenter) {
var $el = jQuery('#content');
var templates = {};
function init(args, loaded) {
topNavigationPresenter.select('tags');
topNavigationPresenter.changeTitle('Tags');
render();
promise.wait(
util.promiseTemplate('tag-list'),
util.promiseTemplate('tag-list-item'))
.then(function(listTemplate, listItemTemplate) {
templates.list = listTemplate;
templates.listItem = listItemTemplate;
render();
loaded();
pagerPresenter.init({
baseUri: '#/tags',
backendUri: '/tags',
$target: $el.find('.pagination-target'),
updateCallback: function(data, clear) {
renderTags(data.entities, clear);
},
},
function() {
reinit(args, function() {});
});
});
}
function reinit(args, loaded) {
loaded();
var searchArgs = util.parseComplexRouteArgs(args.searchArgs);
searchArgs.order = searchArgs.order || 'name,asc';
searchArgs.page = parseInt(searchArgs.page) || 1;
updateActiveOrder(searchArgs.order);
pagerPresenter.reinit({
page: searchArgs.page,
searchParams: {
order: searchArgs.order}});
}
function deinit() {
pagerPresenter.deinit();
}
function render() {
$el.html('Tag list placeholder');
$el.html(templates.list());
}
function updateActiveOrder(activeOrder) {
$el.find('.order li a').removeClass('active');
$el.find('.order [href*="' + activeOrder + '"]').addClass('active');
}
function renderTags(tags, clear) {
var $target = $el.find('.tags');
if (clear) {
$target.empty();
}
_.each(tags, function(tag) {
var $item = jQuery(templates.listItem({
tag: tag,
formatRelativeTime: util.formatRelativeTime,
}));
$target.append($item);
});
}
return {
init: init,
reinit: reinit,
deinit: deinit,
render: render,
};
};
App.DI.register('tagListPresenter', ['jQuery', 'topNavigationPresenter'], App.Presenters.TagListPresenter);
App.DI.register('tagListPresenter', ['_', 'jQuery', 'util', 'promise', 'pagerPresenter', 'topNavigationPresenter'], App.Presenters.TagListPresenter);

View file

@ -24,7 +24,7 @@ App.Presenters.UserPresenter = function(
function init(args, loaded) {
promise.wait(util.promiseTemplate('user'))
.then(function(template, response) {
.then(function(template) {
$messages = $el.find('.messages');
templates.user = template;
reinit(args, loaded);

View file

@ -0,0 +1,5 @@
<tr class="tag">
<td>
<%= tag.name %> (<%= tag.usages %>)
</td>
</tr>

View file

@ -0,0 +1,18 @@
<div id="tag-list">
<ul class="order">
<li>
<a class="big-button" href="#/tags/order=name,asc">Tags</a>
</li>
<li>
<a class="big-button" href="#/tags/order=creation_time,desc">Recent</a>
</li>
<li>
<a class="big-button" href="#/tags/order=usage_count,desc">Popular</a>
</li>
</ul>
<div class="pagination-target">
<table class="tags">
</table>
</div>
</div>

View file

@ -0,0 +1,45 @@
<?php
namespace Szurubooru\Controllers;
final class TagController extends AbstractController
{
private $privilegeService;
private $tagService;
private $tagViewProxy;
private $tagSearchParser;
private $inputReader;
public function __construct(
\Szurubooru\Services\PrivilegeService $privilegeService,
\Szurubooru\Services\TagService $tagService,
\Szurubooru\Controllers\ViewProxies\TagViewProxy $tagViewProxy,
\Szurubooru\SearchServices\Parsers\TagSearchParser $tagSearchParser,
\Szurubooru\Helpers\InputReader $inputReader)
{
$this->privilegeService = $privilegeService;
$this->tagService = $tagService;
$this->tagViewProxy = $tagViewProxy;
$this->tagSearchParser = $tagSearchParser;
$this->inputReader = $inputReader;
}
public function registerRoutes(\Szurubooru\Router $router)
{
$router->get('/api/tags', [$this, 'getTags']);
}
public function getTags()
{
$this->privilegeService->assertPrivilege(\Szurubooru\Privilege::LIST_TAGS);
$filter = $this->tagSearchParser->createFilterFromInputReader($this->inputReader);
$filter->setPageSize(50);
$result = $this->tagService->getFiltered($filter);
$entities = $this->tagViewProxy->fromArray($result->getEntities());
return [
'data' => $entities,
'pageSize' => $result->getPageSize(),
'totalRecords' => $result->getTotalRecords()];
}
}

View file

@ -0,0 +1,15 @@
<?php
namespace Szurubooru\SearchServices\Filters;
class TagFilter extends BasicFilter implements IFilter
{
const ORDER_ID = 'id';
const ORDER_NAME = 'name';
const ORDER_CREATION_TIME = 'creationTime';
const ORDER_USAGE_COUNT = 'usages';
public function __construct()
{
$this->setOrder([self::ORDER_ID => self::ORDER_DESC]);
}
}

View file

@ -0,0 +1,37 @@
<?php
namespace Szurubooru\SearchServices\Parsers;
class TagSearchParser extends AbstractSearchParser
{
protected function createFilter()
{
return new \Szurubooru\SearchServices\Filters\TagFilter;
}
protected function decorateFilterFromToken($filter, $token)
{
throw new \Szurubooru\NotSupportedException();
}
protected function decorateFilterFromNamedToken($filter, $namedToken)
{
throw new \Szurubooru\NotSupportedException();
}
protected function getOrderColumn($token)
{
if ($token === 'id')
return \Szurubooru\SearchServices\Filters\TagFilter::ORDER_ID;
elseif ($token === 'name')
return \Szurubooru\SearchServices\Filters\TagFilter::ORDER_NAME;
elseif ($token === 'creation_time')
return \Szurubooru\SearchServices\Filters\TagFilter::ORDER_CREATION_TIME;
elseif ($token === 'usage_count')
return \Szurubooru\SearchServices\Filters\TagFilter::ORDER_USAGE_COUNT;
throw new \Szurubooru\NotSupportedException();
}
}

View file

@ -17,6 +17,15 @@ class TagService
$this->timeService = $timeService;
}
public function getFiltered(\Szurubooru\SearchServices\Filters\TagFilter $filter)
{
$transactionFunc = function() use ($filter)
{
return $this->tagDao->findFiltered($filter);
};
return $this->transactionManager->rollback($transactionFunc);
}
public function createTags(array $tags)
{
$transactionFunc = function() use ($tags)

View file

@ -49,6 +49,7 @@ return [
$container->get(\Szurubooru\Controllers\FavoritesController::class),
$container->get(\Szurubooru\Controllers\ScoreController::class),
$container->get(\Szurubooru\Controllers\CommentController::class),
$container->get(\Szurubooru\Controllers\TagController::class),
];
}),
];