Added related tag suggesting on tag click
This commit is contained in:
parent
f4d0230166
commit
394c06a1c5
4 changed files with 146 additions and 5 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue