Tag list: use awesomplete for tag auto completion

This commit is contained in:
ArthurHoaro 2017-03-28 20:11:07 +02:00
parent aa4797ba36
commit 82e3bb5f06
3 changed files with 69 additions and 3 deletions

View file

@ -1098,6 +1098,10 @@ form[name="linkform"].page-form {
color: #7f7f7f; color: #7f7f7f;
} }
#taglist .rename-tag-form {
display: none;
}
#taglist .delete-tag { #taglist .delete-tag {
color: #ac2925; color: #ac2925;
display: none; display: none;

View file

@ -418,6 +418,9 @@ window.onload = function () {
* *
* TODO: support error code in the backend for AJAX requests * TODO: support error code in the backend for AJAX requests
*/ */
var existingTags = document.querySelector('input[name="taglist"]').value.split(' ');
var awesomepletes = [];
// Display/Hide rename form // Display/Hide rename form
var renameTagButtons = document.querySelectorAll('.rename-tag'); var renameTagButtons = document.querySelectorAll('.rename-tag');
[].forEach.call(renameTagButtons, function(rename) { [].forEach.call(renameTagButtons, function(rename) {
@ -425,7 +428,12 @@ window.onload = function () {
event.preventDefault(); event.preventDefault();
var block = findParent(event.target, 'div', {'class': 'tag-list-item'}); var block = findParent(event.target, 'div', {'class': 'tag-list-item'});
var form = block.querySelector('.rename-tag-form'); var form = block.querySelector('.rename-tag-form');
form.style.display = form.style.display == 'none' ? 'block' : 'none'; if (form.style.display == 'none' || form.style.display == '') {
form.style.display = 'block';
} else {
form.style.display = 'none';
}
block.querySelector('input').focus();
}); });
}); });
@ -454,10 +462,18 @@ window.onload = function () {
block.setAttribute('data-tag', totag); block.setAttribute('data-tag', totag);
input.setAttribute('name', totag); input.setAttribute('name', totag);
input.setAttribute('value', totag); input.setAttribute('value', totag);
input.parentNode.style.display = 'none'; findParent(input, 'div', {'class': 'rename-tag-form'}).style.display = 'none';
block.querySelector('a.tag-link').innerHTML = htmlEntities(totag); block.querySelector('a.tag-link').innerHTML = htmlEntities(totag);
block.querySelector('a.tag-link').setAttribute('href', '?searchtags='+ encodeURIComponent(totag)); block.querySelector('a.tag-link').setAttribute('href', '?searchtags='+ encodeURIComponent(totag));
block.querySelector('a.rename-tag').setAttribute('href', '?do=changetag&fromtag='+ encodeURIComponent(totag)); block.querySelector('a.rename-tag').setAttribute('href', '?do=changetag&fromtag='+ encodeURIComponent(totag));
// Refresh awesomplete values
for (var key in existingTags) {
if (existingTags[key] == fromtag) {
existingTags[key] = totag;
}
}
awesomepletes = updateAwesompleteList('.rename-tag-input', existingTags, awesomepletes);
} }
}; };
xhr.send('renametag=1&fromtag='+ encodeURIComponent(fromtag) +'&totag='+ encodeURIComponent(totag) +'&token='+ token); xhr.send('renametag=1&fromtag='+ encodeURIComponent(fromtag) +'&totag='+ encodeURIComponent(totag) +'&token='+ token);
@ -468,6 +484,7 @@ window.onload = function () {
// Validate input with enter key // Validate input with enter key
var renameTagInputs = document.querySelectorAll('.rename-tag-input'); var renameTagInputs = document.querySelectorAll('.rename-tag-input');
[].forEach.call(renameTagInputs, function(rename) { [].forEach.call(renameTagInputs, function(rename) {
rename.addEventListener('keypress', function(event) { rename.addEventListener('keypress', function(event) {
if (event.keyCode === 13) { // enter if (event.keyCode === 13) { // enter
findParent(event.target, 'div', {'class': 'tag-list-item'}).querySelector('.validate-rename-tag').click(); findParent(event.target, 'div', {'class': 'tag-list-item'}).querySelector('.validate-rename-tag').click();
@ -497,8 +514,19 @@ window.onload = function () {
} }
}); });
}); });
updateAwesompleteList('.rename-tag-input', document.querySelector('input[name="taglist"]').value.split(' '), awesomepletes);
}; };
/**
* Find a parent element according to its tag and its attributes
*
* @param element Element where to start the search
* @param tagName Expected parent tag name
* @param attributes Associative array of expected attributes (name=>value).
*
* @returns Found element or null.
*/
function findParent(element, tagName, attributes) function findParent(element, tagName, attributes)
{ {
while (element) { while (element) {
@ -522,6 +550,9 @@ function findParent(element, tagName, attributes)
return null; return null;
} }
/**
* Ajax request to refresh the CSRF token.
*/
function refreshToken() function refreshToken()
{ {
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
@ -533,6 +564,33 @@ function refreshToken()
xhr.send(); xhr.send();
} }
/**
* Update awesomplete list of tag for all elements matching the given selector
*
* @param selector CSS selector
* @param tags Array of tags
* @param instances List of existing awesomplete instances
*/
function updateAwesompleteList(selector, tags, instances)
{
// First load: create Awesomplete instances
if (instances.length == 0) {
var elements = document.querySelectorAll(selector);
[].forEach.call(elements, function (element) {
instances.push(new Awesomplete(
element,
{'list': tags}
));
});
} else {
// Update awesomplete tag list
for (var key in instances) {
instances[key].list = tags;
}
}
return instances;
}
/** /**
* html_entities in JS * html_entities in JS
* *

View file

@ -57,7 +57,7 @@ <h2 class="window-title">{'Tag list'|t} - {$countTags} {'tags'|t}</h2>
{/loop} {/loop}
</div> </div>
{if="isLoggedIn()===true"} {if="isLoggedIn()===true"}
<div class="rename-tag-form pure-u-1" style="display:none;"> <div class="rename-tag-form pure-u-1">
<input type="text" name="{$key}" value="{$key}" class="rename-tag-input" /> <input type="text" name="{$key}" value="{$key}" class="rename-tag-input" />
<a href="#" class="validate-rename-tag"><i class="fa fa-check"></i></a> <a href="#" class="validate-rename-tag"><i class="fa fa-check"></i></a>
</div> </div>
@ -74,6 +74,10 @@ <h2 class="window-title">{'Tag list'|t} - {$countTags} {'tags'|t}</h2>
</div> </div>
</div> </div>
{if="isLoggedIn()===true"}
<input type="hidden" name="taglist" value="{loop="$tags"}{$key} {/loop}"
{/if}
{include="tag.sort"} {include="tag.sort"}
{include="page.footer"} {include="page.footer"}