Added related tag suggesting on tag click

This commit is contained in:
Marcin Kurczewski 2014-03-10 01:15:33 +01:00
parent f4d0230166
commit 394c06a1c5
4 changed files with 146 additions and 5 deletions

View file

@ -320,6 +320,28 @@ ul.tagit input {
height: auto !important;
margin: -4px 0 !important;
}
.related-tags {
padding: 0.5em;
background: rgba(255,255,255,0.7);
border-radius: 3px;
margin: 0.4em 0 0.2em 0;
font-size: 95%;
}
.related-tags ul {
list-style-type: none;
margin: 0;
padding: 0;
display: block;
overflow: hidden;
}
.related-tags p {
float: left;
margin: 0 1em 0 0;
}
.related-tags li {
display: inline-block;
margin: 0 1em 0 0;
}
@ -427,7 +449,6 @@ blockquote>*:last-child {
}
.ui-state-default,
.ui-widget-content .ui-state-default,
.ui-widget-header .ui-state-default {
.ui-state-default a {
color: hsla(0,70%,45%,0.8) !important;
}

View file

@ -268,11 +268,52 @@ $(function()
});
});
function attachTagIt(element)
function attachTagIt(target)
{
var tagItOptions =
{
caseSensitive: false,
onTagClicked: function(e, ui)
{
var targetTagit = ui.tag.parents('.tagit');
options = { tag: ui.tagLabel };
if (targetTagit.siblings('.related-tags:eq(0)').data('for') == options.tag)
{
targetTagit.siblings('.related-tags').slideUp(function()
{
$(this).remove();
});
return;
}
$.getJSON('/tags-related?json', options, function(data)
{
var list = $('<ul>');
$.each(data.tags.slice(0, 10), function(i, tag)
{
var link = $('<a>');
link.attr('href', '#');
link.text('#' + tag.name);
link.click(function(e)
{
e.preventDefault();
target.tagit('createTag', tag.name);
});
list.append(link.wrap('<li/>').parent());
});
targetTagit.siblings('.related-tags').slideUp(function()
{
$(this).remove();
});
var div = $('<div>');
div.data('for', options.tag);
div.addClass('related-tags');
div.append('<p>Related tags:</p>');
div.append(list);
div.insertAfter(targetTagit).hide().slideDown();
});
},
autocomplete:
{
source:
@ -295,8 +336,8 @@ function attachTagIt(element)
}
};
tagItOptions.placeholderText = element.attr('placeholder');
element.tagit(tagItOptions);
tagItOptions.placeholderText = target.attr('placeholder');
target.tagit(tagItOptions);
}

View file

@ -66,6 +66,28 @@ class TagController
}, $tags));
}
/**
* @route /tags-related
*/
public function relatedAction()
{
PrivilegesHelper::confirmWithException(Privilege::ListTags);
$suppliedTag = InputHelper::get('tag');
$tags = TagSearchService::getRelatedTagRows($suppliedTag, 10, 1);
$this->context->transport->tags =
array_values(array_map(
function($tag)
{
return [
'name' => $tag['name'],
'count' => $tag['post_count']
];
}, $tags));
}
/**
* @route /tag/merge
*/

View file

@ -9,6 +9,63 @@ class TagSearchService extends AbstractSearchService
$stmt->addColumn(new Sql\AliasFunctor(new Sql\CountFunctor('post_tag.post_id'), 'post_count'));
}
public static function getRelatedTagRows($parentTagName, $limit)
{
$parentTagEntity = TagModel::findByName($parentTagName, false);
if (empty($parentTagEntity))
return [];
$parentTagId = $parentTagEntity->id;
//get tags that appear with selected tag along with their occurence frequency
$stmt = (new Sql\SelectStatement)
->setTable('tag')
->addColumn('tag.*')
->addColumn(new Sql\AliasFunctor(new Sql\CountFunctor('post_tag.post_id'), 'post_count'))
->addInnerJoin('post_tag', new Sql\EqualsFunctor('post_tag.tag_id', 'tag.id'))
->setGroupBy('tag.id')
->setOrderBy('post_count', Sql\SelectStatement::ORDER_DESC)
->setLimit($limit + 1, 0)
->setCriterion(new Sql\ExistsFunctor((new Sql\SelectStatement)
->setTable('post_tag pt2')
->setCriterion((new Sql\ConjunctionFunctor)
->add(new Sql\EqualsFunctor('pt2.post_id', 'post_tag.post_id'))
->add(new Sql\EqualsFunctor('pt2.tag_id', new Sql\Binding($parentTagId)))
)));
$rows1 = [];
foreach (Database::fetchAll($stmt) as $row)
$rows1[$row['id']] = $row;
//get the same tags, but this time - get global occurence frequency
$stmt = (new Sql\SelectStatement)
->setTable('tag')
->addColumn('tag.*')
->addColumn(new Sql\AliasFunctor(new Sql\CountFunctor('post_tag.post_id'), 'post_count'))
->addInnerJoin('post_tag', new Sql\EqualsFunctor('post_tag.tag_id', 'tag.id'))
->setCriterion(Sql\InFunctor::fromArray('tag.id', Sql\Binding::fromArray(array_keys($rows1))))
->setGroupBy('tag.id');
$rows2 = [];
foreach (Database::fetchAll($stmt) as $row)
$rows2[$row['id']] = $row;
$rows = [];
foreach ($rows1 as $i => $row)
{
//multiply own occurences by two because we are going to subtract them
$row['sort'] = $row['post_count'] * 2;
//subtract global occurencecount
$row['sort'] -= isset($rows2[$i]) ? $rows2[$i]['post_count'] : 0;
if ($row['id'] != $parentTagId)
$rows []= $row;
}
usort($rows, function($a, $b) { return intval($b['sort']) - intval($a['sort']); });
return $rows;
}
public static function getMostUsedTag()
{
$stmt = (new Sql\SelectStatement)