Added tag listing
This commit is contained in:
parent
7579d962ba
commit
49124298a2
12 changed files with 230 additions and 7 deletions
3
TODO
3
TODO
|
@ -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
|
||||
|
|
28
public_html/css/tag-list.css
Normal file
28
public_html/css/tag-list.css
Normal 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;
|
||||
}
|
|
@ -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 -->
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
5
public_html/templates/tag-list-item.tpl
Normal file
5
public_html/templates/tag-list-item.tpl
Normal file
|
@ -0,0 +1,5 @@
|
|||
<tr class="tag">
|
||||
<td>
|
||||
<%= tag.name %> (<%= tag.usages %>)
|
||||
</td>
|
||||
</tr>
|
18
public_html/templates/tag-list.tpl
Normal file
18
public_html/templates/tag-list.tpl
Normal 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>
|
45
src/Controllers/TagController.php
Normal file
45
src/Controllers/TagController.php
Normal 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()];
|
||||
}
|
||||
}
|
15
src/SearchServices/Filters/TagFilter.php
Normal file
15
src/SearchServices/Filters/TagFilter.php
Normal 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]);
|
||||
}
|
||||
}
|
37
src/SearchServices/Parsers/TagSearchParser.php
Normal file
37
src/SearchServices/Parsers/TagSearchParser.php
Normal 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();
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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),
|
||||
];
|
||||
}),
|
||||
];
|
||||
|
|
Loading…
Reference in a new issue