+ Can filter tags in tag cloud (GH-105)

This commit is contained in:
maxpozdeev 2025-02-21 12:20:27 +03:00
parent 722a0a401c
commit 7754719702
6 changed files with 82 additions and 19 deletions

View file

@ -86,6 +86,7 @@ var mytinytodo = window.mytinytodo = _mtt = {
previewtag: 0,
ajaxAnimation: 0,
newTaskCounter: 0,
searchTags: 0,
},
lang: {
@ -292,19 +293,42 @@ var mytinytodo = window.mytinytodo = _mtt = {
else {
$('#tagcloudAllLists').prop('checked', flag.showTagsFromAllLists).prop('disabled', false);
}
if(!_mtt.menus.tagcloud) _mtt.menus.tagcloud = new mttMenu('tagcloud', {
if (!_mtt.menus.tagcloud) _mtt.menus.tagcloud = new mttMenu('tagcloud', {
beforeShow: function(){
if(flag.tagsChanged) {
if (flag.tagsChanged) {
$('#tagcloudcontent').html('');
$('#tagcloudload').show();
loadTags(curList.id, function(){$('#tagcloudload').hide();});
loadTags(curList.id, function() {
$('#tagcloudload').hide();
document.getElementById('tagcloudSearch').value = '';
});
}
},
alignRight:true
alignRight: true,
onClose: function(){
document.getElementById('tagcloudSearch').value = '';
searchTags();
}
});
_mtt.menus.tagcloud.show(this);
});
$('#tagcloudSearch').keyup(function(event) {
if (event.keyCode == 27) return;
clearTimeout(_mtt.timers.searchTags);
_mtt.timers.searchTags = setTimeout(function(){searchTags()}, 400);
})
.keydown(function(event){
if (event.keyCode == 27) { // Cancel on Esc
if (this.value === '') return; //allow to close the popup
this.value = '';
clearTimeout(_mtt.timers.searchTags);
searchTags();
return false;
}
})
$('#tagcloudcancel').click(function(){
if(_mtt.menus.tagcloud) _mtt.menus.tagcloud.close();
});
@ -321,7 +345,10 @@ var mytinytodo = window.mytinytodo = _mtt = {
flag.showTagsFromAllLists = this.checked;
$('#tagcloudcontent').html('');
$('#tagcloudload').show();
loadTags(curList.id, function(){$('#tagcloudload').hide();});
loadTags(curList.id, function(){
$('#tagcloudload').hide();
$('#tagcloudSearch').val('');
});
});
$('#mtt-notes-show').click(function(e){
@ -1995,23 +2022,28 @@ function loadTags(listId, callback)
_mtt.db.request('tagCloud', {list:listId}, function(json){
if (!parseInt(json.total)) tagsList = [];
else tagsList = json.items;
let cloud = '';
tagsList.forEach( item => {
// item.tag is escaped with htmlspecialchars()
cloud += ` <span class="tag" data-tag="${item.tag}" data-tag-id="${item.id}">${item.tag}</span>`;
});
if (cloud == '') {
cloud = _mtt.lang.get('noTags');
}
else {
cloud = `<span class="tag" data-tag="^" data-tag-id="-1">${_mtt.lang.get('withoutTags')}</span>` + cloud;
}
$('#tagcloudcontent').html(cloud)
flag.tagsChanged = false;
setTagcloudContent(tagsList);
callback();
});
};
function setTagcloudContent(tags, isFiltered = false)
{
let cloud = '';
tags.forEach( item => {
// item.tag is escaped with htmlspecialchars()
cloud += ` <span class="tag" data-tag="${item.tag}" data-tag-id="${item.id}">${item.tag}</span>`;
});
if (cloud == '') {
cloud = _mtt.lang.get('noTags');
}
else if (!isFiltered) {
cloud = `<span class="tag" data-tag="^" data-tag-id="-1">${_mtt.lang.get('withoutTags')}</span>` + cloud;
}
$('#tagcloudcontent').html(cloud)
}
function cancelTagFilter(tagId, dontLoadTasks)
{
if(tagId) _mtt.filter.cancelTag(tagId);
@ -2026,6 +2058,22 @@ function addFilterTag(tag, tagId, exclude)
loadTasks();
};
function searchTags()
{
const filter = document.getElementById('tagcloudSearch').value.toLocaleLowerCase();
if (filter === '') {
setTagcloudContent(tagsList);
return;
}
const filtered = [];
tagsList.forEach( item => {
if (item.tagText.toLocaleLowerCase().search(filter) === -1)
return;
filtered.push(item);
});
setTagcloudContent(filtered, true);
}
function liveSearchToggle(toSearch, dontLoad)
{
if(toSearch)

View file

@ -975,6 +975,9 @@ textarea.form-input.inmax {
#tagcloudAllLists:disabled + label {
opacity: 0.6;
}
#tagcloudSearch {
margin-left: 0.5rem;
}
#tagcloudcancel span {
mask: var(--svg-closetag) no-repeat; -webkit-mask: var(--svg-closetag) no-repeat;
background-color: var(--color-btn-reduced);
@ -1358,7 +1361,9 @@ li.mtt-item-hidden { display:none; }
textarea.form-input.inmax { font-size: 14px; }
}
/* narrow screens */
/* ========== narrow screens =========*/
@media only screen and (max-width: 600px) {
#mtt { padding: 15px 8px 0px; }
@ -1400,6 +1405,10 @@ li.mtt-item-hidden { display:none; }
#toolbar.mtt-insearch .searchbox-c { width:100%; max-width:100%; }
#search { padding:5px 20px; border-radius:15px; }
#tagcloudSearch {
margin-top: 0.5rem;
}
.task-date {
white-space: nowrap;
overflow: hidden;

View file

@ -52,6 +52,7 @@ class TagsController extends ApiController {
{
$t['items'][] = array(
'tag' => htmlspecialchars($tag['name']),
'tagText' => (string)$tag['name'],
'id' => (int)$tag['id'],
'count' => $ac[$i],
'w' => $this->tagWeight($qmin, $ac[$i], $step)

View file

@ -42,6 +42,7 @@
"public_tasks": "Public Tasks",
"tagcloud": "Tags",
"tagfilter_cancel": "cancel filter",
"filterTags": "Filter tags",
"showTagsFromAllLists": "Show tags from all lists",
"sortByHand": "Sort by hand",
"sortByTitle": "Sort by title",

View file

@ -42,6 +42,7 @@
"public_tasks": "Опубликованные задачи",
"tagcloud": "Теги",
"tagfilter_cancel": "отменить фильтр по тегу",
"filterTags": "Фильтр тегов",
"showTagsFromAllLists": "Показать теги из всех списков",
"sortByHand": "Сортировка вручную",
"sortByTitle": "Сортировка по алфавиту",

View file

@ -253,7 +253,10 @@ $().ready(function(){
<div id="tagcloud" style="display:none">
<div class="actions">
<div><input id="tagcloudAllLists" type="checkbox"> <label for="tagcloudAllLists"><?php _e('showTagsFromAllLists');?></label></div>
<div class="filterbar">
<input id="tagcloudAllLists" type="checkbox"> <label for="tagcloudAllLists"><?php _e('showTagsFromAllLists');?></label>
<input type="text" class="form-input" id="tagcloudSearch" autocomplete="off" placeholder="<?php _e('filterTags');?>">
</div>
<div id="tagcloudcancel" class="mtt-img-button"><span></span></div>
</div>
<div class="content">