diff options
author | ArthurHoaro <arthur@hoa.ro> | 2017-03-25 15:59:01 +0100 |
---|---|---|
committer | ArthurHoaro <arthur@hoa.ro> | 2017-05-25 15:25:04 +0200 |
commit | aa4797ba3679b847adc895e2f817ac058779a171 (patch) | |
tree | d854a1ab8748911dd10e8bced31a2d9b80ccf57b /tpl/default/js | |
parent | bc988eb0420156219fdeb7af684fff37c8b33f4b (diff) | |
download | Shaarli-aa4797ba3679b847adc895e2f817ac058779a171.tar.gz Shaarli-aa4797ba3679b847adc895e2f817ac058779a171.tar.zst Shaarli-aa4797ba3679b847adc895e2f817ac058779a171.zip |
Adds a taglist view with edit/delete buttons
* The tag list can be sort alphabetically or by most used tag
* Edit/Delete are perform using AJAX, or fallback to 'do=changetag' page
* New features aren't backported to vintage theme
Diffstat (limited to 'tpl/default/js')
-rw-r--r-- | tpl/default/js/shaarli.js | 136 |
1 files changed, 135 insertions, 1 deletions
diff --git a/tpl/default/js/shaarli.js b/tpl/default/js/shaarli.js index ceb1d1b8..e19e9001 100644 --- a/tpl/default/js/shaarli.js +++ b/tpl/default/js/shaarli.js | |||
@@ -412,8 +412,139 @@ window.onload = function () { | |||
412 | } | 412 | } |
413 | }); | 413 | }); |
414 | } | 414 | } |
415 | |||
416 | /** | ||
417 | * Tag list operations | ||
418 | * | ||
419 | * TODO: support error code in the backend for AJAX requests | ||
420 | */ | ||
421 | // Display/Hide rename form | ||
422 | var renameTagButtons = document.querySelectorAll('.rename-tag'); | ||
423 | [].forEach.call(renameTagButtons, function(rename) { | ||
424 | rename.addEventListener('click', function(event) { | ||
425 | event.preventDefault(); | ||
426 | var block = findParent(event.target, 'div', {'class': 'tag-list-item'}); | ||
427 | var form = block.querySelector('.rename-tag-form'); | ||
428 | form.style.display = form.style.display == 'none' ? 'block' : 'none'; | ||
429 | }); | ||
430 | }); | ||
431 | |||
432 | // Rename a tag with an AJAX request | ||
433 | var renameTagSubmits = document.querySelectorAll('.validate-rename-tag'); | ||
434 | [].forEach.call(renameTagSubmits, function(rename) { | ||
435 | rename.addEventListener('click', function(event) { | ||
436 | event.preventDefault(); | ||
437 | var block = findParent(event.target, 'div', {'class': 'tag-list-item'}); | ||
438 | var input = block.querySelector('.rename-tag-input'); | ||
439 | var totag = input.value.replace('/"/g', '\\"'); | ||
440 | if (totag.trim() == '') { | ||
441 | return; | ||
442 | } | ||
443 | var fromtag = block.getAttribute('data-tag'); | ||
444 | var token = document.getElementById('token').value; | ||
445 | |||
446 | xhr = new XMLHttpRequest(); | ||
447 | xhr.open('POST', '?do=changetag'); | ||
448 | xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); | ||
449 | xhr.onload = function() { | ||
450 | if (xhr.status !== 200) { | ||
451 | alert('An error occurred. Return code: '+ xhr.status); | ||
452 | location.reload(); | ||
453 | } else { | ||
454 | block.setAttribute('data-tag', totag); | ||
455 | input.setAttribute('name', totag); | ||
456 | input.setAttribute('value', totag); | ||
457 | input.parentNode.style.display = 'none'; | ||
458 | block.querySelector('a.tag-link').innerHTML = htmlEntities(totag); | ||
459 | block.querySelector('a.tag-link').setAttribute('href', '?searchtags='+ encodeURIComponent(totag)); | ||
460 | block.querySelector('a.rename-tag').setAttribute('href', '?do=changetag&fromtag='+ encodeURIComponent(totag)); | ||
461 | } | ||
462 | }; | ||
463 | xhr.send('renametag=1&fromtag='+ encodeURIComponent(fromtag) +'&totag='+ encodeURIComponent(totag) +'&token='+ token); | ||
464 | refreshToken(); | ||
465 | }); | ||
466 | }); | ||
467 | |||
468 | // Validate input with enter key | ||
469 | var renameTagInputs = document.querySelectorAll('.rename-tag-input'); | ||
470 | [].forEach.call(renameTagInputs, function(rename) { | ||
471 | rename.addEventListener('keypress', function(event) { | ||
472 | if (event.keyCode === 13) { // enter | ||
473 | findParent(event.target, 'div', {'class': 'tag-list-item'}).querySelector('.validate-rename-tag').click(); | ||
474 | } | ||
475 | }); | ||
476 | }); | ||
477 | |||
478 | // Delete a tag with an AJAX query (alert popup confirmation) | ||
479 | var deleteTagButtons = document.querySelectorAll('.delete-tag'); | ||
480 | [].forEach.call(deleteTagButtons, function(rename) { | ||
481 | rename.style.display = 'inline'; | ||
482 | rename.addEventListener('click', function(event) { | ||
483 | event.preventDefault(); | ||
484 | var block = findParent(event.target, 'div', {'class': 'tag-list-item'}); | ||
485 | var tag = block.getAttribute('data-tag'); | ||
486 | var token = document.getElementById('token').value; | ||
487 | |||
488 | if (confirm('Are you sure you want to delete the tag "'+ tag +'"?')) { | ||
489 | xhr = new XMLHttpRequest(); | ||
490 | xhr.open('POST', '?do=changetag'); | ||
491 | xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); | ||
492 | xhr.onload = function() { | ||
493 | block.remove(); | ||
494 | }; | ||
495 | xhr.send(encodeURI('deletetag=1&fromtag='+ tag +'&token='+ token)); | ||
496 | refreshToken(); | ||
497 | } | ||
498 | }); | ||
499 | }); | ||
415 | }; | 500 | }; |
416 | 501 | ||
502 | function findParent(element, tagName, attributes) | ||
503 | { | ||
504 | while (element) { | ||
505 | if (element.tagName.toLowerCase() == tagName) { | ||
506 | var match = true; | ||
507 | for (var key in attributes) { | ||
508 | if (! element.hasAttribute(key) | ||
509 | || (attributes[key] != '' && element.getAttribute(key).indexOf(attributes[key]) == -1) | ||
510 | ) { | ||
511 | match = false; | ||
512 | break; | ||
513 | } | ||
514 | } | ||
515 | |||
516 | if (match) { | ||
517 | return element; | ||
518 | } | ||
519 | } | ||
520 | element = element.parentElement; | ||
521 | } | ||
522 | return null; | ||
523 | } | ||
524 | |||
525 | function refreshToken() | ||
526 | { | ||
527 | var xhr = new XMLHttpRequest(); | ||
528 | xhr.open('GET', '?do=token'); | ||
529 | xhr.onload = function() { | ||
530 | var token = document.getElementById('token'); | ||
531 | token.setAttribute('value', xhr.responseText); | ||
532 | }; | ||
533 | xhr.send(); | ||
534 | } | ||
535 | |||
536 | /** | ||
537 | * html_entities in JS | ||
538 | * | ||
539 | * @see http://stackoverflow.com/questions/18749591/encode-html-entities-in-javascript | ||
540 | */ | ||
541 | function htmlEntities(str) | ||
542 | { | ||
543 | return str.replace(/[\u00A0-\u9999<>\&]/gim, function(i) { | ||
544 | return '&#'+i.charCodeAt(0)+';'; | ||
545 | }); | ||
546 | } | ||
547 | |||
417 | function activateFirefoxSocial(node) { | 548 | function activateFirefoxSocial(node) { |
418 | var loc = location.href; | 549 | var loc = location.href; |
419 | var baseURL = loc.substring(0, loc.lastIndexOf("/")); | 550 | var baseURL = loc.substring(0, loc.lastIndexOf("/")); |
@@ -445,8 +576,11 @@ function activateFirefoxSocial(node) { | |||
445 | * @param currentContinent Current selected continent | 576 | * @param currentContinent Current selected continent |
446 | * @param reset Set to true to reset the selected value | 577 | * @param reset Set to true to reset the selected value |
447 | */ | 578 | */ |
448 | function hideTimezoneCities(cities, currentContinent, reset = false) { | 579 | function hideTimezoneCities(cities, currentContinent) { |
449 | var first = true; | 580 | var first = true; |
581 | if (reset == null) { | ||
582 | reset = false; | ||
583 | } | ||
450 | [].forEach.call(cities, function (option) { | 584 | [].forEach.call(cities, function (option) { |
451 | if (option.getAttribute('data-continent') != currentContinent) { | 585 | if (option.getAttribute('data-continent') != currentContinent) { |
452 | option.className = 'hidden'; | 586 | option.className = 'hidden'; |