mirror of https://gitlab.com/tildes/tildes.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
153 lines
6.3 KiB
153 lines
6.3 KiB
// Copyright (c) 2019 Tildes contributors <code@tildes.net>
|
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
$.onmount('[data-js-autocomplete-input]', function() {
|
|
function addChip($input) {
|
|
var $autocompleteContainer = $input.parents('[data-js-autocomplete-container]').first();
|
|
var $chips = $autocompleteContainer.find('[data-js-autocomplete-chips]').first();
|
|
var $tagsHiddenInput = $('[data-js-autocomplete-hidden-input]');
|
|
|
|
$input.val().split(',').map(function(tag) {
|
|
return tag.trim();
|
|
}).filter(function(tag) {
|
|
return tag !== '';
|
|
}).forEach(function(tag) {
|
|
if (!$tagsHiddenInput.val().match(new RegExp('(^|,)' + tag + ','))) {
|
|
var clearIcon = document.createElement('a');
|
|
clearIcon.classList.add('btn');
|
|
clearIcon.classList.add('btn-clear');
|
|
clearIcon.setAttribute('data-js-autocomplete-chip-clear', '');
|
|
clearIcon.setAttribute('aria-label', 'Close');
|
|
clearIcon.setAttribute('role', 'button');
|
|
clearIcon.setAttribute('tabindex', $chips.children().length);
|
|
|
|
var $chip = $(document.createElement('div'));
|
|
$chip.addClass('chip');
|
|
$chip.html(tag);
|
|
$chip.append(clearIcon);
|
|
|
|
$chips.append($chip);
|
|
|
|
$tagsHiddenInput.val($tagsHiddenInput.val() + tag + ',');
|
|
}
|
|
});
|
|
$autocompleteContainer.find('[data-js-autocomplete-input]').val('');
|
|
$autocompleteContainer.find('[data-js-autocomplete-suggestions]').html('');
|
|
|
|
$.onmount();
|
|
}
|
|
|
|
// initialization (won't repeat on re-mounts because it removes the name attr)
|
|
if ($(this).attr("name")) {
|
|
// move the "tags" name to the hidden input (so the form works without JS)
|
|
$(this).removeAttr("name");
|
|
$("[data-js-autocomplete-hidden-input]").attr("name", "tags");
|
|
|
|
// attach an event handler to the form that will add the input's value to
|
|
// the end of the tags list before submitting (to include any tag that's
|
|
// still in the input and wasn't converted to a chip)
|
|
$(this).closest("form").on("beforeSend.ic", function(evt, elt, data, settings, xhr, requestId) {
|
|
$autocompleteInput = $(elt).find("[data-js-autocomplete-input]").first();
|
|
if (!$autocompleteInput.val()) {
|
|
return;
|
|
}
|
|
|
|
var dataPieces = settings.data.split("&");
|
|
for (i = 0; i < dataPieces.length; i++) {
|
|
if (dataPieces[i].indexOf("tags=") === 0) {
|
|
dataPieces[i] += $autocompleteInput.val();
|
|
break;
|
|
}
|
|
}
|
|
settings.data = dataPieces.join("&");
|
|
});
|
|
}
|
|
|
|
if ($(this).val() !== '') {
|
|
addChip($(this));
|
|
}
|
|
|
|
$(this).focus(function(event) {
|
|
var $autocompleteContainer = $(this).parents('[data-js-autocomplete-container]').first();
|
|
var $chips = $autocompleteContainer.find('[data-js-autocomplete-chips]').first();
|
|
|
|
$chips.children().removeClass('active');
|
|
});
|
|
|
|
$(this).keydown(function(event) {
|
|
switch (event.key) {
|
|
case 'Escape':
|
|
$('[data-js-autocomplete-menu]').remove();
|
|
$(this).blur();
|
|
break;
|
|
case ',':
|
|
case 'Enter':
|
|
event.preventDefault();
|
|
addChip($(this));
|
|
break;
|
|
case 'ArrowDown':
|
|
event.preventDefault();
|
|
var $autocompleteMenu = $('[data-js-autocomplete-menu]').first();
|
|
var $nextActiveItem = $autocompleteMenu.children('.menu-item').first();
|
|
$nextActiveItem.children('[data-js-autocomplete-menu-item]').first().focus();
|
|
break;
|
|
case 'ArrowUp':
|
|
event.preventDefault();
|
|
var $autocompleteMenu = $('[data-js-autocomplete-menu]').first();
|
|
var $nextActiveItem = $autocompleteMenu.children('.menu-item').last();
|
|
$nextActiveItem.children('[data-js-autocomplete-menu-item]').first().focus();
|
|
break;
|
|
case 'Backspace':
|
|
if ($(this).val() === '') {
|
|
event.preventDefault();
|
|
var $autocompleteContainer = $(this).parents('[data-js-autocomplete-container]').first();
|
|
var $chips = $autocompleteContainer.find('[data-js-autocomplete-chips]').first();
|
|
var $tagsHiddenInput = $("[data-js-autocomplete-hidden-input]");
|
|
var $lastChip = $chips.children().last();
|
|
|
|
$(this).blur();
|
|
if (!$lastChip.hasClass('active')) {
|
|
$lastChip.addClass("active");
|
|
$lastChip.children('[data-js-autocomplete-chip-clear]').first().focus();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
});
|
|
|
|
$(this).keyup(function(event) {
|
|
var $this = $(this);
|
|
var $autocompleteMenu = $('[data-js-autocomplete-menu]');
|
|
if ($autocompleteMenu) {
|
|
$autocompleteMenu.remove();
|
|
}
|
|
if ($this.val() === '') {
|
|
return;
|
|
}
|
|
var $tagsHiddenInput = $('[data-js-autocomplete-hidden-input]');
|
|
var suggestions = $this.data('js-autocomplete-input').filter(function(suggestion) {
|
|
return suggestion.startsWith($this.val().toLowerCase()) &&
|
|
!$tagsHiddenInput.val().match(new RegExp('(^|,)' + suggestion + ','));
|
|
});
|
|
if (suggestions.length === 0) {
|
|
return;
|
|
}
|
|
var $autocompleteSuggestions = $('[data-js-autocomplete-suggestions]');
|
|
$autocompleteMenu = $('<ol class="menu" data-js-autocomplete-menu>');
|
|
|
|
suggestions.forEach(function(suggestion) {
|
|
$autocompleteMenu.append(
|
|
'<li class="menu-item">' +
|
|
'<a href="#" data-js-autocomplete-menu-item>' +
|
|
'<div class="tile tile-centered">' +
|
|
'<div class="tile-content">' +
|
|
suggestion +
|
|
'</div>' +
|
|
'</div>' +
|
|
'</a>' +
|
|
'</li>');
|
|
});
|
|
$autocompleteSuggestions.append($autocompleteMenu);
|
|
$.onmount();
|
|
});
|
|
});
|