mirror of https://gitlab.com/tildes/tildes.git
Shane Moore
6 years ago
committed by
Deimos
10 changed files with 302 additions and 9 deletions
-
4tildes/scss/modules/_form.scss
-
10tildes/scss/modules/_menu.scss
-
1tildes/scss/spectre-0.5.1/spectre.scss
-
1tildes/scss/styles.scss
-
31tildes/scss/themes/_theme_base.scss
-
30tildes/static/js/behaviors/autocomplete-chip-clear.js
-
126tildes/static/js/behaviors/autocomplete-input.js
-
68tildes/static/js/behaviors/autocomplete-menu-item.js
-
11tildes/static/js/behaviors/autocomplete-menu.js
-
15tildes/tildes/templates/macros/forms.jinja2
@ -0,0 +1,10 @@ |
|||
// Copyright (c) 2019 Tildes contributors <code@tildes.net> |
|||
// SPDX-License-Identifier: AGPL-3.0-or-later |
|||
|
|||
.menu { |
|||
.menu-item { |
|||
& > a:hover, & > a:focus { |
|||
background-color: transparent; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,30 @@ |
|||
// Copyright (c) 2019 Tildes contributors <code@tildes.net>
|
|||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|||
|
|||
$.onmount('[data-js-autocomplete-chip-clear]', function() { |
|||
function clearChip($chip) { |
|||
var $tagsHiddenInput = $('[data-js-autocomplete-hidden-input]'); |
|||
var $autocompleteInput = $('[data-js-autocomplete-input]'); |
|||
|
|||
var textToReplace = new RegExp($chip.text() + ','); |
|||
$tagsHiddenInput.val($tagsHiddenInput.val().replace(textToReplace, '')); |
|||
$chip.remove(); |
|||
$autocompleteInput.focus(); |
|||
} |
|||
|
|||
$(this).click(function(event) { |
|||
event.preventDefault(); |
|||
clearChip($(this).parent()); |
|||
}); |
|||
|
|||
$(this).keydown(function(event) { |
|||
switch (event.key) { |
|||
case 'Backspace': |
|||
event.preventDefault(); |
|||
clearChip($(this).parent()); |
|||
break; |
|||
default: |
|||
break; |
|||
} |
|||
}); |
|||
}); |
@ -0,0 +1,126 @@ |
|||
// 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(); |
|||
} |
|||
|
|||
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() === '') { |
|||
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()) && |
|||
!$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(); |
|||
}); |
|||
}); |
@ -0,0 +1,68 @@ |
|||
// Copyright (c) 2019 Tildes contributors <code@tildes.net>
|
|||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|||
|
|||
$.onmount('[data-js-autocomplete-menu-item]', function() { |
|||
function addChip($menuItem) { |
|||
var $autocompleteContainer = $menuItem.parents('[data-js-autocomplete-container]').first(); |
|||
var $clickedSuggestion = $menuItem.find('.tile > .tile-content').first(); |
|||
var clickedSuggestionText = $clickedSuggestion.html().trim(); |
|||
var $tagsHiddenInput = $('[data-js-autocomplete-hidden-input]'); |
|||
var $autocompleteInput = $("[data-js-autocomplete-input]"); |
|||
|
|||
if (!$tagsHiddenInput.val().includes(clickedSuggestionText + ',')) { |
|||
var $chips = $autocompleteContainer.find('[data-js-autocomplete-chips]').first(); |
|||
|
|||
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(clickedSuggestionText); |
|||
$chip.append(clearIcon); |
|||
|
|||
$chips.append($chip); |
|||
|
|||
$tagsHiddenInput.val($tagsHiddenInput.val() + clickedSuggestionText + ','); |
|||
} |
|||
|
|||
$autocompleteContainer.find('[data-js-autocomplete-input]').val(''); |
|||
$autocompleteContainer.find('[data-js-autocomplete-suggestions]').html(''); |
|||
$autocompleteInput.focus(); |
|||
|
|||
$.onmount(); |
|||
} |
|||
|
|||
$(this).click(function(event) { |
|||
event.preventDefault(); |
|||
addChip($(this), event); |
|||
}); |
|||
|
|||
$(this).keydown(function(event) { |
|||
switch (event.key) { |
|||
case 'Escape': |
|||
$('[data-js-autocomplete-menu]').parent().remove(); |
|||
break; |
|||
case 'Enter': |
|||
event.preventDefault(); |
|||
addChip($(this)); |
|||
break; |
|||
case 'ArrowDown': |
|||
event.preventDefault(); |
|||
var $nextActiveItem = $(this).parent().next(); |
|||
$nextActiveItem.children('[data-js-autocomplete-menu-item]').first().focus(); |
|||
break; |
|||
case 'ArrowUp': |
|||
event.preventDefault(); |
|||
var $nextActiveItem = $(this).parent().prev(); |
|||
$nextActiveItem.children('[data-js-autocomplete-menu-item]').first().focus(); |
|||
break; |
|||
default: |
|||
break; |
|||
} |
|||
}); |
|||
}); |
@ -0,0 +1,11 @@ |
|||
// Copyright (c) 2019 Tildes contributors <code@tildes.net>
|
|||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|||
|
|||
$.onmount('[data-js-autocomplete-menu]', function() { |
|||
var $autocompleteContainer = $(this).parents('[data-js-autocomplete-container]').first(); |
|||
var $chips = $autocompleteContainer.find('[data-js-autocomplete-chips]').first(); |
|||
|
|||
$(this).children('[data-js-autocomplete-menu-item]').each(function(index, $menuItem) { |
|||
$menuItem.setAttribute('tabindex', $chips.children().length + index); |
|||
}); |
|||
}); |
Write
Preview
Loading…
Cancel
Save
Reference in new issue