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
-
29tildes/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