Added tag searching

This commit is contained in:
Marcin Kurczewski 2014-10-16 18:21:55 +02:00
parent bf58207950
commit b7f077df9b
6 changed files with 154 additions and 63 deletions

View file

@ -1,12 +1,25 @@
#tag-list {
min-width: 15em;
max-width: 40em;
margin: 0 auto;
text-align: center;
}
#tag-list form {
float: left;
white-space: nowrap;
}
#tag-list ul {
float: right;
list-style-type: none;
padding: 0;
margin: 0;
}
#tag-list .search:after {
display: block;
content: '';
clear: both;
}
#ta-list ul.order {
margin: -0.5em -0.5em 0.5em -0.5em;
@ -21,13 +34,13 @@
}
#tag-list table {
min-width: 20em;
width: 100%;
text-align: left;
margin: 1em auto;
}
#tag-list th,
#tag-list td {
#tag-list th:not(:last-child),
#tag-list td:not(:last-child) {
padding-right: 1.5em;
}
@ -43,3 +56,10 @@
#tag-list .usages {
text-align: center;
}
@media all and (max-width: 40em) {
#tag-list .implications,
#tag-list .suggestions {
display: none;
}
}

View file

@ -11,11 +11,16 @@ App.Presenters.TagListPresenter = function(
topNavigationPresenter) {
var $el = jQuery('#content');
var $searchInput;
var templates = {};
function init(params, loaded) {
var params;
function init(_params, loaded) {
topNavigationPresenter.select('tags');
topNavigationPresenter.changeTitle('Tags');
params = _params;
params.query = params.query || {};
promise.wait(
util.promiseTemplate('tag-list'),
@ -44,7 +49,8 @@ App.Presenters.TagListPresenter = function(
});
}
function reinit(params, loaded) {
function reinit(_params, loaded) {
params = _params;
params.query = params.query || {};
params.query.order = params.query.order || 'name,asc';
updateActiveOrder(params.query.order);
@ -55,7 +61,12 @@ App.Presenters.TagListPresenter = function(
$el.find('table a').eq(0).focus();
});
keyboard.keyup('q', function() {
$searchInput.eq(0).focus().select();
});
loaded();
softRender();
}
function deinit() {
@ -64,6 +75,33 @@ App.Presenters.TagListPresenter = function(
function render() {
$el.html(templates.list());
$searchInput = $el.find('input[name=query]');
$searchInput.keydown(searchInputKeyPressed);
$el.find('form').submit(searchFormSubmitted);
softRender();
}
function softRender() {
$searchInput.val(params.query.query);
}
function searchInputKeyPressed(e) {
if (e.which !== KEY_RETURN) {
return;
}
updateSearch();
}
function searchFormSubmitted(e) {
e.preventDefault();
updateSearch();
}
function updateSearch() {
$searchInput.blur();
params.query.query = $searchInput.val().trim();
pagerPresenter.setQuery(params.query);
}
function updateActiveOrder(activeOrder) {

View file

@ -1,4 +1,10 @@
<div id="tag-list">
<div class="search">
<form>
<input type="text" name="query" placeholder="Search tags..."/>
<button type="submit" name="search">Search</button>
</form>
<ul class="order">
<li>
<a class="big-button" href="#/tags/order=name,asc">Tags</a>
@ -10,6 +16,7 @@
<a class="big-button" href="#/tags/order=usage_count,desc">Popular</a>
</li>
</ul>
</div>
<div class="pagination-target">
<table class="tags">

View file

@ -5,6 +5,8 @@ use Szurubooru\Dao\EntityConverters\TagEntityConverter;
use Szurubooru\DatabaseConnection;
use Szurubooru\Entities\Entity;
use Szurubooru\Entities\Tag;
use Szurubooru\SearchServices\Filters\TagFilter;
use Szurubooru\SearchServices\Requirements\Requirement;
class TagDao extends AbstractDao implements ICrudDao
{
@ -67,6 +69,52 @@ class TagDao extends AbstractDao implements ICrudDao
$this->deleteBy('usages', 0);
}
public function export()
{
$exported = [];
foreach ($this->fpdo->from('tags') as $arrayEntity)
{
$exported[$arrayEntity['id']] = [
'name' => $arrayEntity['name'],
'usages' => intval($arrayEntity['usages']),
'banned' => boolval($arrayEntity['banned'])
];
}
//upgrades on old databases
try
{
$relations = iterator_to_array($this->fpdo->from('tagRelations'));
}
catch (\Exception $e)
{
$relations = [];
}
foreach ($relations as $arrayEntity)
{
$key1 = $arrayEntity['tag1id'];
$key2 = $arrayEntity['tag2id'];
$type = intval($arrayEntity['type']);
if ($type === self::TAG_RELATION_IMPLICATION)
$target = 'implications';
elseif ($type === self::TAG_RELATION_SUGGESTION)
$target = 'suggestions';
else
continue;
if (!isset($exported[$key1]) or !isset($exported[$key2]))
continue;
if (!isset($exported[$key1][$target]))
$exported[$key1][$target] = [];
$exported[$key1][$target][] = $exported[$key2]['name'];
}
return array_values($exported);
}
protected function afterLoad(Entity $tag)
{
$tag->setLazyLoader(
@ -90,6 +138,22 @@ class TagDao extends AbstractDao implements ICrudDao
$this->syncSuggestedTags($tag);
}
protected function decorateQueryFromRequirement($query, Requirement $requirement)
{
if ($requirement->getType() === TagFilter::REQUIREMENT_PARTIAL_TAG_NAME)
{
$sql = 'INSTR(LOWER(tags.name), LOWER(?)) > 0';
if ($requirement->isNegated())
$sql = 'NOT ' . $sql;
$query->where($sql, $requirement->getValue()->getValue());
return;
}
parent::decorateQueryFromRequirement($query, $requirement);
}
private function findImpliedTags(Tag $tag)
{
return $this->findRelatedTagsByType($tag, self::TAG_RELATION_IMPLICATION);
@ -138,52 +202,6 @@ class TagDao extends AbstractDao implements ICrudDao
}
}
public function export()
{
$exported = [];
foreach ($this->fpdo->from('tags') as $arrayEntity)
{
$exported[$arrayEntity['id']] = [
'name' => $arrayEntity['name'],
'usages' => intval($arrayEntity['usages']),
'banned' => boolval($arrayEntity['banned'])
];
}
//upgrades on old databases
try
{
$relations = iterator_to_array($this->fpdo->from('tagRelations'));
}
catch (\Exception $e)
{
$relations = [];
}
foreach ($relations as $arrayEntity)
{
$key1 = $arrayEntity['tag1id'];
$key2 = $arrayEntity['tag2id'];
$type = intval($arrayEntity['type']);
if ($type === self::TAG_RELATION_IMPLICATION)
$target = 'implications';
elseif ($type === self::TAG_RELATION_SUGGESTION)
$target = 'suggestions';
else
continue;
if (!isset($exported[$key1]) or !isset($exported[$key2]))
continue;
if (!isset($exported[$key1][$target]))
$exported[$key1][$target] = [];
$exported[$key1][$target][] = $exported[$key2]['name'];
}
return array_values($exported);
}
private function findRelatedTagsByType(Tag $tag, $type)
{
$tagId = $tag->getId();

View file

@ -8,6 +8,8 @@ class TagFilter extends BasicFilter implements IFilter
const ORDER_CREATION_TIME = 'creationTime';
const ORDER_USAGE_COUNT = 'usages';
const REQUIREMENT_PARTIAL_TAG_NAME = 'partialTagName';
public function __construct()
{
$this->setOrder([self::ORDER_ID => self::ORDER_DESC]);

View file

@ -3,6 +3,8 @@ namespace Szurubooru\SearchServices\Parsers;
use Szurubooru\NotSupportedException;
use Szurubooru\SearchServices\Filters\IFilter;
use Szurubooru\SearchServices\Filters\TagFilter;
use Szurubooru\SearchServices\Requirements\Requirement;
use Szurubooru\SearchServices\Requirements\RequirementSingleValue;
use Szurubooru\SearchServices\Tokens\NamedSearchToken;
use Szurubooru\SearchServices\Tokens\SearchToken;
@ -15,7 +17,11 @@ class TagSearchParser extends AbstractSearchParser
protected function decorateFilterFromToken(IFilter $filter, SearchToken $token)
{
throw new NotSupportedException();
$requirement = new Requirement();
$requirement->setType(TagFilter::REQUIREMENT_PARTIAL_TAG_NAME);
$requirement->setValue(new RequirementSingleValue($token->getValue()));
$requirement->setNegated($token->isNegated());
$filter->addRequirement($requirement);
}
protected function decorateFilterFromNamedToken(IFilter $filter, NamedSearchToken $namedToken)