Add clickable preview popover to filter group toggles
- Add showFilterGroupPreviewPopover method in _preview.js - Make toggle-count badges clickable with data attributes - Add event binding for .toggle-count.clickable in _events.js - Add hover/active/loading styles for clickable toggle-count - Requires previewFilterGroupProducts AJAX handler in PHP backend Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -91,6 +91,23 @@
|
||||
}
|
||||
});
|
||||
|
||||
// Filter group toggle count badge click for preview popover
|
||||
$(document).on('click', '.filter-group-toggle .toggle-count.clickable', function(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
var $badge = $(this);
|
||||
var groupId = $badge.data('groupId');
|
||||
var groupType = $badge.data('type');
|
||||
var groupName = $badge.data('groupName');
|
||||
|
||||
if ($badge.hasClass('popover-open')) {
|
||||
self.hidePreviewPopover();
|
||||
} else {
|
||||
self.showFilterGroupPreviewPopover($badge, groupId, groupType, groupName);
|
||||
}
|
||||
});
|
||||
|
||||
// Close popover when clicking outside
|
||||
$(document).on('click', function(e) {
|
||||
if (!$(e.target).closest('.target-preview-popover').length &&
|
||||
@@ -98,7 +115,8 @@
|
||||
!$(e.target).closest('.condition-match-count').length &&
|
||||
!$(e.target).closest('.group-count-badge').length &&
|
||||
!$(e.target).closest('.group-modifiers').length &&
|
||||
!$(e.target).closest('.group-preview-badge').length) {
|
||||
!$(e.target).closest('.group-preview-badge').length &&
|
||||
!$(e.target).closest('.toggle-count.clickable').length) {
|
||||
self.hidePreviewPopover();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -161,10 +161,10 @@
|
||||
|
||||
if (this.filterableData.attributes && this.filterableData.attributes.length > 0) {
|
||||
this.filterableData.attributes.forEach(function(group) {
|
||||
var html = '<button type="button" class="filter-group-toggle" data-group-id="' + group.id + '" data-type="attribute">';
|
||||
var html = '<button type="button" class="filter-group-toggle" data-group-id="' + group.id + '" data-type="attribute" data-group-name="' + self.escapeAttr(group.name) + '">';
|
||||
html += '<span class="toggle-name">' + group.name + '</span>';
|
||||
if (group.count !== undefined) {
|
||||
html += '<span class="toggle-count"><i class="icon-eye"></i> (' + group.count + ')</span>';
|
||||
html += '<span class="toggle-count clickable" data-group-id="' + group.id + '" data-type="attribute" data-group-name="' + self.escapeAttr(group.name) + '"><i class="icon-eye"></i> ' + group.count + '</span>';
|
||||
}
|
||||
html += '</button>';
|
||||
$attrContainer.append(html);
|
||||
@@ -178,10 +178,10 @@
|
||||
|
||||
if (this.filterableData.features && this.filterableData.features.length > 0) {
|
||||
this.filterableData.features.forEach(function(group) {
|
||||
var html = '<button type="button" class="filter-group-toggle" data-group-id="' + group.id + '" data-type="feature">';
|
||||
var html = '<button type="button" class="filter-group-toggle" data-group-id="' + group.id + '" data-type="feature" data-group-name="' + self.escapeAttr(group.name) + '">';
|
||||
html += '<span class="toggle-name">' + group.name + '</span>';
|
||||
if (group.count !== undefined) {
|
||||
html += '<span class="toggle-count"><i class="icon-eye"></i> (' + group.count + ')</span>';
|
||||
html += '<span class="toggle-count clickable" data-group-id="' + group.id + '" data-type="feature" data-group-name="' + self.escapeAttr(group.name) + '"><i class="icon-eye"></i> ' + group.count + '</span>';
|
||||
}
|
||||
html += '</button>';
|
||||
$featContainer.append(html);
|
||||
|
||||
@@ -650,6 +650,118 @@
|
||||
price = parseFloat(price) || 0;
|
||||
}
|
||||
return price.toFixed(2) + ' €';
|
||||
},
|
||||
|
||||
/**
|
||||
* Show preview popover for filter group toggle (attribute/feature groups)
|
||||
*/
|
||||
showFilterGroupPreviewPopover: function($badge, groupId, groupType, groupName) {
|
||||
var self = this;
|
||||
|
||||
this.hidePreviewPopover();
|
||||
|
||||
$badge.addClass('popover-open loading');
|
||||
this.$activeBadge = $badge;
|
||||
|
||||
var trans = this.config.trans || {};
|
||||
var entityLabelPlural = 'products';
|
||||
|
||||
// Fetch products matching this attribute/feature group
|
||||
$.ajax({
|
||||
url: this.config.ajaxUrl,
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
ajax: 1,
|
||||
action: 'previewFilterGroupProducts',
|
||||
trait: 'EntitySelector',
|
||||
group_id: groupId,
|
||||
group_type: groupType,
|
||||
limit: 10
|
||||
},
|
||||
success: function(response) {
|
||||
$badge.removeClass('loading');
|
||||
|
||||
if (response.success) {
|
||||
var items = response.items || [];
|
||||
var totalCount = response.count || 0;
|
||||
var hasMore = response.hasMore || false;
|
||||
|
||||
self.showFilterGroupItemsPopover($badge, items, totalCount, hasMore, entityLabelPlural, groupName, groupType);
|
||||
} else {
|
||||
$badge.removeClass('popover-open');
|
||||
self.$activeBadge = null;
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
$badge.removeClass('loading popover-open');
|
||||
self.$activeBadge = null;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Show popover for filter group preview items
|
||||
*/
|
||||
showFilterGroupItemsPopover: function($badge, items, totalCount, hasMore, entityLabel, groupName, groupType) {
|
||||
var self = this;
|
||||
var trans = this.config.trans || {};
|
||||
|
||||
var typeLabel = groupType === 'attribute' ? (trans.attribute || 'Attribute') : (trans.feature || 'Feature');
|
||||
var html = '<div class="target-preview-popover preview-type-filter-group">';
|
||||
|
||||
html += '<div class="preview-header">';
|
||||
html += '<span class="preview-count">' + totalCount + ' ' + entityLabel + '</span>';
|
||||
html += '<button type="button" class="preview-close"><i class="icon-times"></i></button>';
|
||||
html += '</div>';
|
||||
|
||||
if (items.length > 0) {
|
||||
html += '<div class="preview-list">';
|
||||
html += this.renderPreviewItems(items);
|
||||
html += '</div>';
|
||||
|
||||
if (hasMore) {
|
||||
var remaining = totalCount - items.length;
|
||||
html += '<div class="preview-footer">';
|
||||
html += '<span class="preview-more-info">+ ' + remaining + ' ' + (trans.more || 'more') + '</span>';
|
||||
html += '</div>';
|
||||
}
|
||||
} else {
|
||||
html += '<div class="preview-empty">' + (trans.no_preview || 'No items to preview') + '</div>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
|
||||
var $popover = $(html);
|
||||
$('body').append($popover);
|
||||
|
||||
$popover.find('.preview-close').on('click', function() {
|
||||
self.hidePreviewPopover();
|
||||
});
|
||||
|
||||
// Position popover below badge
|
||||
var badgeOffset = $badge.offset();
|
||||
var badgeHeight = $badge.outerHeight();
|
||||
var badgeWidth = $badge.outerWidth();
|
||||
var popoverWidth = $popover.outerWidth();
|
||||
|
||||
var leftPos = badgeOffset.left + (badgeWidth / 2) - (popoverWidth / 2);
|
||||
var minLeft = 10;
|
||||
var maxLeft = $(window).width() - popoverWidth - 10;
|
||||
leftPos = Math.max(minLeft, Math.min(leftPos, maxLeft));
|
||||
|
||||
var topPos = badgeOffset.top + badgeHeight + 8;
|
||||
|
||||
$popover.css({
|
||||
position: 'absolute',
|
||||
top: topPos,
|
||||
left: leftPos,
|
||||
zIndex: 10000
|
||||
});
|
||||
|
||||
$popover.addClass('show');
|
||||
|
||||
this.$previewPopover = $popover;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user