Feature: enhanced chips toolbar with sorting and load select
Chips toolbar improvements: - Filter input now uses all available space (flex: 1) - Added sort dropdown: Order added, Name A-Z, Name Z-A - Changed "Show X more" button to select dropdown pattern - Load 20, 50, 100, or All - Shows remaining count - Collapse button to return to default view Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -3923,20 +3923,27 @@
|
||||
$toolbar.addClass('has-chips');
|
||||
this.updateChipsToolbar($toolbar, totalCount, filteredCount, searchTerm);
|
||||
|
||||
// Update load more button
|
||||
// Update load more select dropdown
|
||||
var hiddenByPagination = filteredCount - visibleCount;
|
||||
if (hiddenByPagination > 0 && !isExpanded) {
|
||||
var moreText = (trans.show_more || 'Show {count} more').replace('{count}', hiddenByPagination);
|
||||
$loadMore.html(
|
||||
'<button type="button" class="btn-load-more">' +
|
||||
'<i class="icon-chevron-down"></i> ' + moreText +
|
||||
'</button>'
|
||||
).show();
|
||||
var loadText = trans.load || 'Load';
|
||||
var remainingText = (trans.remaining || '{count} remaining').replace('{count}', hiddenByPagination);
|
||||
var loadMoreHtml = '<span class="load-more-label">' + loadText + '</span>' +
|
||||
'<select class="load-more-select">' +
|
||||
'<option value="20">20</option>' +
|
||||
'<option value="50">50</option>' +
|
||||
'<option value="100">100</option>' +
|
||||
'<option value="all">' + (trans.all || 'All') + ' (' + hiddenByPagination + ')</option>' +
|
||||
'</select>' +
|
||||
'<span class="load-more-remaining">' + remainingText + '</span>';
|
||||
$loadMore.html(loadMoreHtml).show();
|
||||
} else if (isExpanded && filteredCount > (this.maxVisibleChips || 12)) {
|
||||
var lessText = trans.show_less || 'Show less';
|
||||
var collapseText = trans.collapse || 'Collapse';
|
||||
$loadMore.html(
|
||||
'<button type="button" class="btn-load-more">' +
|
||||
'<i class="icon-chevron-up"></i> ' + lessText +
|
||||
'<button type="button" class="btn-collapse-chips" style="' +
|
||||
'background:transparent;border:1px solid #dee2e6;border-radius:4px;' +
|
||||
'padding:0.25rem 0.75rem;font-size:12px;color:#6c757d;cursor:pointer;">' +
|
||||
'<i class="icon-chevron-up"></i> ' + collapseText +
|
||||
'</button>'
|
||||
).show();
|
||||
} else {
|
||||
@@ -3953,13 +3960,18 @@
|
||||
var trans = this.config.trans || {};
|
||||
var $picker = $chips.closest('.value-picker');
|
||||
|
||||
// Create wrapper structure - integrated filter toolbar
|
||||
// Create wrapper structure - integrated filter toolbar with sort
|
||||
var wrapperHtml = '<div class="chips-wrapper">' +
|
||||
'<div class="chips-toolbar">' +
|
||||
'<span class="chips-filter-group">' +
|
||||
'<i class="icon-search"></i>' +
|
||||
'<input type="text" class="chips-search-input" placeholder="' + (trans.filter || 'Filter') + '...">' +
|
||||
'<input type="text" class="chips-search-input" placeholder="' + (trans.filter_selected || 'Filter selected') + '...">' +
|
||||
'</span>' +
|
||||
'<select class="chips-sort-select" title="' + (trans.sort || 'Sort') + '">' +
|
||||
'<option value="added">' + (trans.sort_added || 'Order added') + '</option>' +
|
||||
'<option value="name_asc">' + (trans.sort_name_asc || 'Name A-Z') + '</option>' +
|
||||
'<option value="name_desc">' + (trans.sort_name_desc || 'Name Z-A') + '</option>' +
|
||||
'</select>' +
|
||||
'<span class="chips-count"></span>' +
|
||||
'<button type="button" class="btn-chips-clear" title="' + (trans.clear_all || 'Clear all') + '">' +
|
||||
'<i class="icon-trash"></i> <span class="clear-text">' + (trans.clear || 'Clear') + '</span>' +
|
||||
@@ -3994,6 +4006,12 @@
|
||||
}, 150);
|
||||
});
|
||||
|
||||
// Sort select
|
||||
$wrapper.on('change', '.chips-sort-select', function() {
|
||||
var sortBy = $(this).val();
|
||||
self.sortChips($chips, sortBy);
|
||||
});
|
||||
|
||||
// Clear all button
|
||||
$wrapper.on('click', '.btn-chips-clear', function() {
|
||||
var searchTerm = $wrapper.find('.chips-search-input').val() || '';
|
||||
@@ -4016,15 +4034,59 @@
|
||||
self.updateChipsVisibility($chips);
|
||||
});
|
||||
|
||||
// Load more / show less
|
||||
$wrapper.on('click', '.btn-load-more', function() {
|
||||
if ($chips.hasClass('chips-expanded')) {
|
||||
$chips.removeClass('chips-expanded');
|
||||
} else {
|
||||
// Load more select dropdown
|
||||
$wrapper.on('change', '.load-more-select', function() {
|
||||
var loadCount = $(this).val();
|
||||
if (loadCount === 'all') {
|
||||
$chips.addClass('chips-expanded');
|
||||
self.maxVisibleChips = 999999;
|
||||
} else {
|
||||
self.maxVisibleChips = (self.maxVisibleChips || 12) + parseInt(loadCount, 10);
|
||||
}
|
||||
self.updateChipsVisibility($chips);
|
||||
});
|
||||
|
||||
// Collapse button
|
||||
$wrapper.on('click', '.btn-collapse-chips', function() {
|
||||
$chips.removeClass('chips-expanded');
|
||||
self.maxVisibleChips = 12;
|
||||
self.updateChipsVisibility($chips);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Sort chips by specified criteria
|
||||
*/
|
||||
sortChips: function($chips, sortBy) {
|
||||
var $allChips = $chips.find('.entity-chip');
|
||||
if ($allChips.length < 2) return;
|
||||
|
||||
var sorted = $allChips.toArray().sort(function(a, b) {
|
||||
var $a = $(a);
|
||||
var $b = $(b);
|
||||
|
||||
switch (sortBy) {
|
||||
case 'name_asc':
|
||||
var nameA = ($a.find('.chip-name').text() || '').toLowerCase();
|
||||
var nameB = ($b.find('.chip-name').text() || '').toLowerCase();
|
||||
return nameA.localeCompare(nameB);
|
||||
case 'name_desc':
|
||||
var nameA2 = ($a.find('.chip-name').text() || '').toLowerCase();
|
||||
var nameB2 = ($b.find('.chip-name').text() || '').toLowerCase();
|
||||
return nameB2.localeCompare(nameA2);
|
||||
case 'added':
|
||||
default:
|
||||
// Keep original DOM order (order added)
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
// Re-append in sorted order
|
||||
$.each(sorted, function(i, chip) {
|
||||
$chips.append(chip);
|
||||
});
|
||||
|
||||
this.updateChipsVisibility($chips);
|
||||
},
|
||||
|
||||
updateChipsToolbar: function($toolbar, totalCount, filteredCount, searchTerm) {
|
||||
|
||||
2
assets/js/admin/entity-selector.min.js
vendored
2
assets/js/admin/entity-selector.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -145,20 +145,27 @@
|
||||
$toolbar.addClass('has-chips');
|
||||
this.updateChipsToolbar($toolbar, totalCount, filteredCount, searchTerm);
|
||||
|
||||
// Update load more button
|
||||
// Update load more select dropdown
|
||||
var hiddenByPagination = filteredCount - visibleCount;
|
||||
if (hiddenByPagination > 0 && !isExpanded) {
|
||||
var moreText = (trans.show_more || 'Show {count} more').replace('{count}', hiddenByPagination);
|
||||
$loadMore.html(
|
||||
'<button type="button" class="btn-load-more">' +
|
||||
'<i class="icon-chevron-down"></i> ' + moreText +
|
||||
'</button>'
|
||||
).show();
|
||||
var loadText = trans.load || 'Load';
|
||||
var remainingText = (trans.remaining || '{count} remaining').replace('{count}', hiddenByPagination);
|
||||
var loadMoreHtml = '<span class="load-more-label">' + loadText + '</span>' +
|
||||
'<select class="load-more-select">' +
|
||||
'<option value="20">20</option>' +
|
||||
'<option value="50">50</option>' +
|
||||
'<option value="100">100</option>' +
|
||||
'<option value="all">' + (trans.all || 'All') + ' (' + hiddenByPagination + ')</option>' +
|
||||
'</select>' +
|
||||
'<span class="load-more-remaining">' + remainingText + '</span>';
|
||||
$loadMore.html(loadMoreHtml).show();
|
||||
} else if (isExpanded && filteredCount > (this.maxVisibleChips || 12)) {
|
||||
var lessText = trans.show_less || 'Show less';
|
||||
var collapseText = trans.collapse || 'Collapse';
|
||||
$loadMore.html(
|
||||
'<button type="button" class="btn-load-more">' +
|
||||
'<i class="icon-chevron-up"></i> ' + lessText +
|
||||
'<button type="button" class="btn-collapse-chips" style="' +
|
||||
'background:transparent;border:1px solid #dee2e6;border-radius:4px;' +
|
||||
'padding:0.25rem 0.75rem;font-size:12px;color:#6c757d;cursor:pointer;">' +
|
||||
'<i class="icon-chevron-up"></i> ' + collapseText +
|
||||
'</button>'
|
||||
).show();
|
||||
} else {
|
||||
@@ -175,13 +182,18 @@
|
||||
var trans = this.config.trans || {};
|
||||
var $picker = $chips.closest('.value-picker');
|
||||
|
||||
// Create wrapper structure - integrated filter toolbar
|
||||
// Create wrapper structure - integrated filter toolbar with sort
|
||||
var wrapperHtml = '<div class="chips-wrapper">' +
|
||||
'<div class="chips-toolbar">' +
|
||||
'<span class="chips-filter-group">' +
|
||||
'<i class="icon-search"></i>' +
|
||||
'<input type="text" class="chips-search-input" placeholder="' + (trans.filter || 'Filter') + '...">' +
|
||||
'<input type="text" class="chips-search-input" placeholder="' + (trans.filter_selected || 'Filter selected') + '...">' +
|
||||
'</span>' +
|
||||
'<select class="chips-sort-select" title="' + (trans.sort || 'Sort') + '">' +
|
||||
'<option value="added">' + (trans.sort_added || 'Order added') + '</option>' +
|
||||
'<option value="name_asc">' + (trans.sort_name_asc || 'Name A-Z') + '</option>' +
|
||||
'<option value="name_desc">' + (trans.sort_name_desc || 'Name Z-A') + '</option>' +
|
||||
'</select>' +
|
||||
'<span class="chips-count"></span>' +
|
||||
'<button type="button" class="btn-chips-clear" title="' + (trans.clear_all || 'Clear all') + '">' +
|
||||
'<i class="icon-trash"></i> <span class="clear-text">' + (trans.clear || 'Clear') + '</span>' +
|
||||
@@ -216,6 +228,12 @@
|
||||
}, 150);
|
||||
});
|
||||
|
||||
// Sort select
|
||||
$wrapper.on('change', '.chips-sort-select', function() {
|
||||
var sortBy = $(this).val();
|
||||
self.sortChips($chips, sortBy);
|
||||
});
|
||||
|
||||
// Clear all button
|
||||
$wrapper.on('click', '.btn-chips-clear', function() {
|
||||
var searchTerm = $wrapper.find('.chips-search-input').val() || '';
|
||||
@@ -238,15 +256,59 @@
|
||||
self.updateChipsVisibility($chips);
|
||||
});
|
||||
|
||||
// Load more / show less
|
||||
$wrapper.on('click', '.btn-load-more', function() {
|
||||
if ($chips.hasClass('chips-expanded')) {
|
||||
$chips.removeClass('chips-expanded');
|
||||
} else {
|
||||
// Load more select dropdown
|
||||
$wrapper.on('change', '.load-more-select', function() {
|
||||
var loadCount = $(this).val();
|
||||
if (loadCount === 'all') {
|
||||
$chips.addClass('chips-expanded');
|
||||
self.maxVisibleChips = 999999;
|
||||
} else {
|
||||
self.maxVisibleChips = (self.maxVisibleChips || 12) + parseInt(loadCount, 10);
|
||||
}
|
||||
self.updateChipsVisibility($chips);
|
||||
});
|
||||
|
||||
// Collapse button
|
||||
$wrapper.on('click', '.btn-collapse-chips', function() {
|
||||
$chips.removeClass('chips-expanded');
|
||||
self.maxVisibleChips = 12;
|
||||
self.updateChipsVisibility($chips);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Sort chips by specified criteria
|
||||
*/
|
||||
sortChips: function($chips, sortBy) {
|
||||
var $allChips = $chips.find('.entity-chip');
|
||||
if ($allChips.length < 2) return;
|
||||
|
||||
var sorted = $allChips.toArray().sort(function(a, b) {
|
||||
var $a = $(a);
|
||||
var $b = $(b);
|
||||
|
||||
switch (sortBy) {
|
||||
case 'name_asc':
|
||||
var nameA = ($a.find('.chip-name').text() || '').toLowerCase();
|
||||
var nameB = ($b.find('.chip-name').text() || '').toLowerCase();
|
||||
return nameA.localeCompare(nameB);
|
||||
case 'name_desc':
|
||||
var nameA2 = ($a.find('.chip-name').text() || '').toLowerCase();
|
||||
var nameB2 = ($b.find('.chip-name').text() || '').toLowerCase();
|
||||
return nameB2.localeCompare(nameA2);
|
||||
case 'added':
|
||||
default:
|
||||
// Keep original DOM order (order added)
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
// Re-append in sorted order
|
||||
$.each(sorted, function(i, chip) {
|
||||
$chips.append(chip);
|
||||
});
|
||||
|
||||
this.updateChipsVisibility($chips);
|
||||
},
|
||||
|
||||
updateChipsToolbar: function($toolbar, totalCount, filteredCount, searchTerm) {
|
||||
|
||||
@@ -34,11 +34,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Filter input styled as a search chip
|
||||
// Filter input styled as a search chip - takes available space
|
||||
.chips-filter-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
flex: 1; // Take available space
|
||||
min-width: 0; // Allow shrinking
|
||||
padding: 0.25rem 0.5rem;
|
||||
background: $es-white;
|
||||
border: 1px solid $es-border-color;
|
||||
@@ -63,8 +65,8 @@
|
||||
input.chips-search-input[type="text"] {
|
||||
flex: 1 !important;
|
||||
min-width: 60px !important;
|
||||
max-width: 120px !important;
|
||||
width: auto !important;
|
||||
max-width: none !important; // No max - use available space
|
||||
width: 100% !important;
|
||||
height: auto !important;
|
||||
padding: 0.125rem 0 !important;
|
||||
border: none !important;
|
||||
@@ -86,6 +88,34 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Sort dropdown for chips
|
||||
.chips-sort-select,
|
||||
select.chips-sort-select {
|
||||
appearance: none;
|
||||
padding: 0.25rem 1.5rem 0.25rem 0.5rem !important;
|
||||
border: 1px solid $es-border-color !important;
|
||||
border-radius: $es-radius-full !important;
|
||||
background: $es-white url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3E%3Cpath fill='%23666' d='M0 2l4 4 4-4z'/%3E%3C/svg%3E") no-repeat right 0.5rem center !important;
|
||||
background-size: 8px !important;
|
||||
font-size: 11px !important;
|
||||
color: $es-text-secondary;
|
||||
cursor: pointer;
|
||||
transition: all $es-transition-fast;
|
||||
height: auto !important;
|
||||
min-height: 0 !important;
|
||||
line-height: 1.2 !important;
|
||||
|
||||
&:hover {
|
||||
border-color: $es-primary !important;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: none !important;
|
||||
border-color: $es-primary !important;
|
||||
box-shadow: 0 0 0 2px rgba($es-primary, 0.1) !important;
|
||||
}
|
||||
}
|
||||
|
||||
// Count badge - smaller, pill style
|
||||
.chips-count {
|
||||
display: inline-flex;
|
||||
@@ -167,36 +197,54 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Load more button
|
||||
// Load more section with select dropdown
|
||||
.chips-load-more {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: $es-spacing-sm;
|
||||
padding: $es-spacing-sm $es-spacing-md;
|
||||
background: $es-white;
|
||||
border-top: 1px solid $es-border-color;
|
||||
background: transparent;
|
||||
border-top: 1px dashed $es-border-color;
|
||||
|
||||
.btn-load-more {
|
||||
@include button-reset;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
padding: 0.5rem 1rem;
|
||||
color: $es-white;
|
||||
font-size: $es-font-size-sm;
|
||||
font-weight: $es-font-weight-semibold;
|
||||
background: $es-primary;
|
||||
border-radius: $es-radius-sm;
|
||||
.load-more-label {
|
||||
font-size: $es-font-size-xs;
|
||||
color: $es-text-muted;
|
||||
}
|
||||
|
||||
.load-more-select,
|
||||
select.load-more-select {
|
||||
appearance: none;
|
||||
padding: 0.25rem 1.75rem 0.25rem 0.5rem !important;
|
||||
border: 1px solid $es-border-color !important;
|
||||
border-radius: $es-radius-sm !important;
|
||||
background: $es-white url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3E%3Cpath fill='%23666' d='M0 2l4 4 4-4z'/%3E%3C/svg%3E") no-repeat right 0.5rem center !important;
|
||||
background-size: 8px !important;
|
||||
font-size: $es-font-size-xs !important;
|
||||
font-weight: $es-font-weight-medium;
|
||||
color: $es-primary;
|
||||
cursor: pointer;
|
||||
transition: all $es-transition-fast;
|
||||
height: auto !important;
|
||||
min-height: 0 !important;
|
||||
line-height: 1.3 !important;
|
||||
|
||||
&:hover {
|
||||
background: $es-primary-hover;
|
||||
border-color: $es-primary !important;
|
||||
background-color: $es-primary-light !important;
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: 12px;
|
||||
&:focus {
|
||||
outline: none !important;
|
||||
border-color: $es-primary !important;
|
||||
box-shadow: 0 0 0 2px rgba($es-primary, 0.1) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.load-more-remaining {
|
||||
font-size: $es-font-size-xs;
|
||||
color: $es-text-muted;
|
||||
}
|
||||
}
|
||||
|
||||
// Individual chip
|
||||
|
||||
Reference in New Issue
Block a user