diff options
author | ArthurHoaro <arthur@hoa.ro> | 2017-03-28 20:11:07 +0200 |
---|---|---|
committer | ArthurHoaro <arthur@hoa.ro> | 2017-05-25 15:25:04 +0200 |
commit | 82e3bb5f06dc531ee1080a0313833791a1c1f3c7 (patch) | |
tree | 228456f9b4d95d03e97fc9bc1b5004aa599f95ee | |
parent | aa4797ba3679b847adc895e2f817ac058779a171 (diff) | |
download | Shaarli-82e3bb5f06dc531ee1080a0313833791a1c1f3c7.tar.gz Shaarli-82e3bb5f06dc531ee1080a0313833791a1c1f3c7.tar.zst Shaarli-82e3bb5f06dc531ee1080a0313833791a1c1f3c7.zip |
Tag list: use awesomplete for tag auto completion
-rw-r--r-- | tpl/default/css/shaarli.css | 4 | ||||
-rw-r--r-- | tpl/default/js/shaarli.js | 62 | ||||
-rw-r--r-- | tpl/default/tag.list.html | 6 |
3 files changed, 69 insertions, 3 deletions
diff --git a/tpl/default/css/shaarli.css b/tpl/default/css/shaarli.css index 2eda5df4..28920648 100644 --- a/tpl/default/css/shaarli.css +++ b/tpl/default/css/shaarli.css | |||
@@ -1098,6 +1098,10 @@ form[name="linkform"].page-form { | |||
1098 | color: #7f7f7f; | 1098 | color: #7f7f7f; |
1099 | } | 1099 | } |
1100 | 1100 | ||
1101 | #taglist .rename-tag-form { | ||
1102 | display: none; | ||
1103 | } | ||
1104 | |||
1101 | #taglist .delete-tag { | 1105 | #taglist .delete-tag { |
1102 | color: #ac2925; | 1106 | color: #ac2925; |
1103 | display: none; | 1107 | display: none; |
diff --git a/tpl/default/js/shaarli.js b/tpl/default/js/shaarli.js index e19e9001..4ebb7815 100644 --- a/tpl/default/js/shaarli.js +++ b/tpl/default/js/shaarli.js | |||
@@ -418,6 +418,9 @@ window.onload = function () { | |||
418 | * | 418 | * |
419 | * TODO: support error code in the backend for AJAX requests | 419 | * TODO: support error code in the backend for AJAX requests |
420 | */ | 420 | */ |
421 | var existingTags = document.querySelector('input[name="taglist"]').value.split(' '); | ||
422 | var awesomepletes = []; | ||
423 | |||
421 | // Display/Hide rename form | 424 | // Display/Hide rename form |
422 | var renameTagButtons = document.querySelectorAll('.rename-tag'); | 425 | var renameTagButtons = document.querySelectorAll('.rename-tag'); |
423 | [].forEach.call(renameTagButtons, function(rename) { | 426 | [].forEach.call(renameTagButtons, function(rename) { |
@@ -425,7 +428,12 @@ window.onload = function () { | |||
425 | event.preventDefault(); | 428 | event.preventDefault(); |
426 | var block = findParent(event.target, 'div', {'class': 'tag-list-item'}); | 429 | var block = findParent(event.target, 'div', {'class': 'tag-list-item'}); |
427 | var form = block.querySelector('.rename-tag-form'); | 430 | var form = block.querySelector('.rename-tag-form'); |
428 | form.style.display = form.style.display == 'none' ? 'block' : 'none'; | 431 | if (form.style.display == 'none' || form.style.display == '') { |
432 | form.style.display = 'block'; | ||
433 | } else { | ||
434 | form.style.display = 'none'; | ||
435 | } | ||
436 | block.querySelector('input').focus(); | ||
429 | }); | 437 | }); |
430 | }); | 438 | }); |
431 | 439 | ||
@@ -454,10 +462,18 @@ window.onload = function () { | |||
454 | block.setAttribute('data-tag', totag); | 462 | block.setAttribute('data-tag', totag); |
455 | input.setAttribute('name', totag); | 463 | input.setAttribute('name', totag); |
456 | input.setAttribute('value', totag); | 464 | input.setAttribute('value', totag); |
457 | input.parentNode.style.display = 'none'; | 465 | findParent(input, 'div', {'class': 'rename-tag-form'}).style.display = 'none'; |
458 | block.querySelector('a.tag-link').innerHTML = htmlEntities(totag); | 466 | block.querySelector('a.tag-link').innerHTML = htmlEntities(totag); |
459 | block.querySelector('a.tag-link').setAttribute('href', '?searchtags='+ encodeURIComponent(totag)); | 467 | block.querySelector('a.tag-link').setAttribute('href', '?searchtags='+ encodeURIComponent(totag)); |
460 | block.querySelector('a.rename-tag').setAttribute('href', '?do=changetag&fromtag='+ encodeURIComponent(totag)); | 468 | block.querySelector('a.rename-tag').setAttribute('href', '?do=changetag&fromtag='+ encodeURIComponent(totag)); |
469 | |||
470 | // Refresh awesomplete values | ||
471 | for (var key in existingTags) { | ||
472 | if (existingTags[key] == fromtag) { | ||
473 | existingTags[key] = totag; | ||
474 | } | ||
475 | } | ||
476 | awesomepletes = updateAwesompleteList('.rename-tag-input', existingTags, awesomepletes); | ||
461 | } | 477 | } |
462 | }; | 478 | }; |
463 | xhr.send('renametag=1&fromtag='+ encodeURIComponent(fromtag) +'&totag='+ encodeURIComponent(totag) +'&token='+ token); | 479 | xhr.send('renametag=1&fromtag='+ encodeURIComponent(fromtag) +'&totag='+ encodeURIComponent(totag) +'&token='+ token); |
@@ -468,6 +484,7 @@ window.onload = function () { | |||
468 | // Validate input with enter key | 484 | // Validate input with enter key |
469 | var renameTagInputs = document.querySelectorAll('.rename-tag-input'); | 485 | var renameTagInputs = document.querySelectorAll('.rename-tag-input'); |
470 | [].forEach.call(renameTagInputs, function(rename) { | 486 | [].forEach.call(renameTagInputs, function(rename) { |
487 | |||
471 | rename.addEventListener('keypress', function(event) { | 488 | rename.addEventListener('keypress', function(event) { |
472 | if (event.keyCode === 13) { // enter | 489 | if (event.keyCode === 13) { // enter |
473 | findParent(event.target, 'div', {'class': 'tag-list-item'}).querySelector('.validate-rename-tag').click(); | 490 | findParent(event.target, 'div', {'class': 'tag-list-item'}).querySelector('.validate-rename-tag').click(); |
@@ -497,8 +514,19 @@ window.onload = function () { | |||
497 | } | 514 | } |
498 | }); | 515 | }); |
499 | }); | 516 | }); |
517 | |||
518 | updateAwesompleteList('.rename-tag-input', document.querySelector('input[name="taglist"]').value.split(' '), awesomepletes); | ||
500 | }; | 519 | }; |
501 | 520 | ||
521 | /** | ||
522 | * Find a parent element according to its tag and its attributes | ||
523 | * | ||
524 | * @param element Element where to start the search | ||
525 | * @param tagName Expected parent tag name | ||
526 | * @param attributes Associative array of expected attributes (name=>value). | ||
527 | * | ||
528 | * @returns Found element or null. | ||
529 | */ | ||
502 | function findParent(element, tagName, attributes) | 530 | function findParent(element, tagName, attributes) |
503 | { | 531 | { |
504 | while (element) { | 532 | while (element) { |
@@ -522,6 +550,9 @@ function findParent(element, tagName, attributes) | |||
522 | return null; | 550 | return null; |
523 | } | 551 | } |
524 | 552 | ||
553 | /** | ||
554 | * Ajax request to refresh the CSRF token. | ||
555 | */ | ||
525 | function refreshToken() | 556 | function refreshToken() |
526 | { | 557 | { |
527 | var xhr = new XMLHttpRequest(); | 558 | var xhr = new XMLHttpRequest(); |
@@ -534,6 +565,33 @@ function refreshToken() | |||
534 | } | 565 | } |
535 | 566 | ||
536 | /** | 567 | /** |
568 | * Update awesomplete list of tag for all elements matching the given selector | ||
569 | * | ||
570 | * @param selector CSS selector | ||
571 | * @param tags Array of tags | ||
572 | * @param instances List of existing awesomplete instances | ||
573 | */ | ||
574 | function updateAwesompleteList(selector, tags, instances) | ||
575 | { | ||
576 | // First load: create Awesomplete instances | ||
577 | if (instances.length == 0) { | ||
578 | var elements = document.querySelectorAll(selector); | ||
579 | [].forEach.call(elements, function (element) { | ||
580 | instances.push(new Awesomplete( | ||
581 | element, | ||
582 | {'list': tags} | ||
583 | )); | ||
584 | }); | ||
585 | } else { | ||
586 | // Update awesomplete tag list | ||
587 | for (var key in instances) { | ||
588 | instances[key].list = tags; | ||
589 | } | ||
590 | } | ||
591 | return instances; | ||
592 | } | ||
593 | |||
594 | /** | ||
537 | * html_entities in JS | 595 | * html_entities in JS |
538 | * | 596 | * |
539 | * @see http://stackoverflow.com/questions/18749591/encode-html-entities-in-javascript | 597 | * @see http://stackoverflow.com/questions/18749591/encode-html-entities-in-javascript |
diff --git a/tpl/default/tag.list.html b/tpl/default/tag.list.html index 98971051..62e2e7c6 100644 --- a/tpl/default/tag.list.html +++ b/tpl/default/tag.list.html | |||
@@ -57,7 +57,7 @@ | |||
57 | {/loop} | 57 | {/loop} |
58 | </div> | 58 | </div> |
59 | {if="isLoggedIn()===true"} | 59 | {if="isLoggedIn()===true"} |
60 | <div class="rename-tag-form pure-u-1" style="display:none;"> | 60 | <div class="rename-tag-form pure-u-1"> |
61 | <input type="text" name="{$key}" value="{$key}" class="rename-tag-input" /> | 61 | <input type="text" name="{$key}" value="{$key}" class="rename-tag-input" /> |
62 | <a href="#" class="validate-rename-tag"><i class="fa fa-check"></i></a> | 62 | <a href="#" class="validate-rename-tag"><i class="fa fa-check"></i></a> |
63 | </div> | 63 | </div> |
@@ -74,6 +74,10 @@ | |||
74 | </div> | 74 | </div> |
75 | </div> | 75 | </div> |
76 | 76 | ||
77 | {if="isLoggedIn()===true"} | ||
78 | <input type="hidden" name="taglist" value="{loop="$tags"}{$key} {/loop}" | ||
79 | {/if} | ||
80 | |||
77 | {include="tag.sort"} | 81 | {include="tag.sort"} |
78 | 82 | ||
79 | {include="page.footer"} | 83 | {include="page.footer"} |