feat: unified preview eye icon component, enhanced search & preview
- Unify filter group and filter value preview icons into shared .filter-chip-wrapper + .chip-preview-btn component pattern - Remove old .toggle-count.clickable inline eye icon approach - Add dropdown-level event handler for preview buttons (dropdown appended to body, needs separate delegation) - Enhanced EntitySearchEngine with improved product condition resolution and preview data - Add EntityPreviewHandler for richer preview popovers - Various SCSS improvements for chips, groups, and list-preview Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -272,9 +272,9 @@
|
||||
!$(e.target).closest('.group-count-badge').length &&
|
||||
!$(e.target).closest('.group-modifiers').length &&
|
||||
!$(e.target).closest('.group-preview-badge').length &&
|
||||
!$(e.target).closest('.toggle-count.clickable').length &&
|
||||
!$(e.target).closest('.trait-total-count').length &&
|
||||
!$(e.target).closest('.chip-preview-holidays').length) {
|
||||
!$(e.target).closest('.chip-preview-holidays').length &&
|
||||
!$(e.target).closest('.chip-preview-btn').length) {
|
||||
self.hidePreviewPopover();
|
||||
// Also close holiday popover
|
||||
$('.holiday-preview-popover').remove();
|
||||
@@ -317,6 +317,31 @@
|
||||
}
|
||||
});
|
||||
|
||||
// Filter chip/group preview eye button (unified handler)
|
||||
this.$wrapper.on('click', '.chip-preview-btn', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
var $btn = $(this);
|
||||
|
||||
if ($btn.hasClass('popover-open')) {
|
||||
self.hidePreviewPopover();
|
||||
} else {
|
||||
var valueId = $btn.data('id');
|
||||
var valueType = $btn.data('type');
|
||||
var valueName = $btn.data('name');
|
||||
var groupId = $btn.data('groupId');
|
||||
|
||||
if (valueId) {
|
||||
// Value-level preview (specific attribute/feature value)
|
||||
self.showFilterValuePreviewPopover($btn, valueId, valueType, valueName, groupId);
|
||||
} else if (groupId) {
|
||||
// Group-level preview (entire attribute/feature group)
|
||||
self.showFilterGroupPreviewPopover($btn, groupId, valueType, valueName);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Group-level collapse toggle (click on group header or toggle icon)
|
||||
this.$wrapper.on('click', '.group-header', function(e) {
|
||||
if ($(e.target).closest('.btn-remove-group, .group-name-input').length) {
|
||||
@@ -1196,7 +1221,7 @@
|
||||
if (isSelected) {
|
||||
// Remove from pending selections
|
||||
self.pendingSelections = self.pendingSelections.filter(function(s) {
|
||||
return parseInt(s.id, 10) !== parseInt(id, 10);
|
||||
return String(s.id) !== String(id);
|
||||
});
|
||||
self.removeSelection($picker, id);
|
||||
$item.toggleClass('selected');
|
||||
@@ -1223,7 +1248,7 @@
|
||||
} else {
|
||||
// Add to pending selections
|
||||
var exists = self.pendingSelections.some(function(s) {
|
||||
return parseInt(s.id, 10) === parseInt(id, 10);
|
||||
return String(s.id) === String(id);
|
||||
});
|
||||
if (!exists) {
|
||||
self.pendingSelections.push({ id: id, name: name, data: $item.data() });
|
||||
@@ -1248,7 +1273,7 @@
|
||||
// Also remove from pending selections if dropdown is open
|
||||
if (self.pendingSelections) {
|
||||
self.pendingSelections = self.pendingSelections.filter(function(s) {
|
||||
return parseInt(s.id, 10) !== parseInt(id, 10);
|
||||
return String(s.id) !== String(id);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1375,7 +1400,7 @@
|
||||
|
||||
// Add to pending selections for Save button
|
||||
var exists = self.pendingSelections.some(function(s) {
|
||||
return parseInt(s.id, 10) === parseInt(id, 10);
|
||||
return String(s.id) === String(id);
|
||||
});
|
||||
if (!exists) {
|
||||
self.pendingSelections.push({
|
||||
@@ -1990,10 +2015,6 @@
|
||||
|
||||
// Toggle filter group - show values
|
||||
this.$dropdown.on('click', '.filter-group-toggle', function(e) {
|
||||
// Ignore clicks on the preview badge
|
||||
if ($(e.target).closest('.toggle-count.clickable').length) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
var $btn = $(this);
|
||||
var groupId = $btn.data('group-id');
|
||||
@@ -2010,20 +2031,26 @@
|
||||
}
|
||||
});
|
||||
|
||||
// Filter group toggle count badge click for preview popover
|
||||
this.$dropdown.on('click', '.filter-group-toggle .toggle-count.clickable', function(e) {
|
||||
e.stopPropagation();
|
||||
// Filter preview eye button (dropdown-level, since dropdown is appended to body)
|
||||
this.$dropdown.on('click', '.chip-preview-btn', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
var $badge = $(this);
|
||||
var groupId = $badge.data('groupId');
|
||||
var groupType = $badge.data('type');
|
||||
var groupName = $badge.data('groupName');
|
||||
var $btn = $(this);
|
||||
|
||||
if ($badge.hasClass('popover-open')) {
|
||||
if ($btn.hasClass('popover-open')) {
|
||||
self.hidePreviewPopover();
|
||||
} else {
|
||||
self.showFilterGroupPreviewPopover($badge, groupId, groupType, groupName);
|
||||
var valueId = $btn.data('id');
|
||||
var valueType = $btn.data('type');
|
||||
var valueName = $btn.data('name');
|
||||
var groupId = $btn.data('groupId');
|
||||
|
||||
if (valueId) {
|
||||
self.showFilterValuePreviewPopover($btn, valueId, valueType, valueName, groupId);
|
||||
} else if (groupId) {
|
||||
self.showFilterGroupPreviewPopover($btn, groupId, valueType, valueName);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2182,13 +2209,13 @@
|
||||
// If already pinned, unpin and close
|
||||
if ($wrapper.hasClass('pinned')) {
|
||||
$wrapper.removeClass('pinned');
|
||||
$wrapper.find('.material-icons').text('info_outline');
|
||||
$wrapper.find('.material-icons').text('info');
|
||||
$('.mpr-tooltip-fixed.pinned').remove();
|
||||
return;
|
||||
}
|
||||
|
||||
// Close any other pinned tooltips
|
||||
$('.mpr-info-wrapper.pinned').removeClass('pinned').find('.material-icons').text('info_outline');
|
||||
$('.mpr-info-wrapper.pinned').removeClass('pinned').find('.material-icons').text('info');
|
||||
$('.mpr-tooltip-fixed').remove();
|
||||
|
||||
var content = $wrapper.attr('data-tooltip');
|
||||
@@ -2208,7 +2235,7 @@
|
||||
// Close button click
|
||||
$closeBtn.on('click', function() {
|
||||
$wrapper.removeClass('pinned');
|
||||
$wrapper.find('.material-icons').text('info_outline');
|
||||
$wrapper.find('.material-icons').text('info');
|
||||
$tooltip.remove();
|
||||
});
|
||||
|
||||
@@ -2716,6 +2743,11 @@
|
||||
sort_dir: this.currentSort ? this.currentSort.dir : 'ASC'
|
||||
};
|
||||
|
||||
// Add product_selection_level if set
|
||||
if (this.config.productSelectionLevel && this.config.productSelectionLevel !== 'product') {
|
||||
requestData.product_selection_level = this.config.productSelectionLevel;
|
||||
}
|
||||
|
||||
// Add refine query if present
|
||||
if (this.refineQuery) {
|
||||
requestData.refine = this.refineQuery;
|
||||
@@ -3043,6 +3075,8 @@
|
||||
var isSelected = selectedIds.indexOf(String(item.id)) !== -1;
|
||||
var itemClass = 'dropdown-item' + (isSelected ? ' selected' : '');
|
||||
if (item.type === 'product') itemClass += ' result-item-product';
|
||||
if (item.is_combination) itemClass += ' is-combination';
|
||||
if (item.is_parent) itemClass += ' is-parent-product';
|
||||
|
||||
html += '<div class="' + itemClass + '" ';
|
||||
html += 'data-id="' + self.escapeAttr(item.id) + '" ';
|
||||
@@ -3050,6 +3084,7 @@
|
||||
if (item.image) html += ' data-image="' + self.escapeAttr(item.image) + '"';
|
||||
if (item.subtitle) html += ' data-subtitle="' + self.escapeAttr(item.subtitle) + '"';
|
||||
if (item.iso_code) html += ' data-iso="' + self.escapeAttr(item.iso_code) + '"';
|
||||
if (item.attributes) html += ' data-attributes="' + self.escapeAttr(item.attributes) + '"';
|
||||
html += '>';
|
||||
|
||||
html += '<span class="result-checkbox"><i class="icon-check"></i></span>';
|
||||
@@ -3786,6 +3821,7 @@
|
||||
if (!this.$dropdown || !this.filterableData) return;
|
||||
|
||||
var self = this;
|
||||
var previewLabel = self.config.trans && self.config.trans.preview || 'Preview';
|
||||
|
||||
// Render attribute group toggle buttons
|
||||
var $attrContainer = this.$dropdown.find('.filter-attributes-container');
|
||||
@@ -3793,12 +3829,17 @@
|
||||
|
||||
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" data-group-name="' + self.escapeAttr(group.name) + '">';
|
||||
var html = '<span class="filter-chip-wrapper">';
|
||||
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 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 += '<span class="toggle-count">(' + group.count + ')</span>';
|
||||
}
|
||||
html += '</button>';
|
||||
html += '<button type="button" class="chip-preview-btn" data-group-id="' + group.id + '" data-type="attribute" data-name="' + self.escapeAttr(group.name) + '" title="' + previewLabel + '">';
|
||||
html += '<i class="icon-eye"></i>';
|
||||
html += '</button>';
|
||||
html += '</span>';
|
||||
$attrContainer.append(html);
|
||||
});
|
||||
this.$dropdown.find('.filter-row-attributes').show();
|
||||
@@ -3810,12 +3851,17 @@
|
||||
|
||||
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" data-group-name="' + self.escapeAttr(group.name) + '">';
|
||||
var html = '<span class="filter-chip-wrapper">';
|
||||
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 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 += '<span class="toggle-count">(' + group.count + ')</span>';
|
||||
}
|
||||
html += '</button>';
|
||||
html += '<button type="button" class="chip-preview-btn" data-group-id="' + group.id + '" data-type="feature" data-name="' + self.escapeAttr(group.name) + '" title="' + previewLabel + '">';
|
||||
html += '<i class="icon-eye"></i>';
|
||||
html += '</button>';
|
||||
html += '</span>';
|
||||
$featContainer.append(html);
|
||||
});
|
||||
this.$dropdown.find('.filter-row-features').show();
|
||||
@@ -3853,6 +3899,7 @@
|
||||
var colorStyle = val.color ? ' style="--chip-color: ' + val.color + '"' : '';
|
||||
var colorClass = val.color ? ' has-color' : '';
|
||||
|
||||
html += '<span class="filter-chip-wrapper">';
|
||||
html += '<button type="button" class="filter-chip ' + chipClass + activeClass + colorClass + '" data-id="' + val.id + '" data-group-id="' + groupId + '"' + colorStyle + '>';
|
||||
if (val.color) {
|
||||
html += '<span class="chip-color-dot"></span>';
|
||||
@@ -3862,6 +3909,10 @@
|
||||
html += '<span class="chip-count">(' + val.count + ')</span>';
|
||||
}
|
||||
html += '</button>';
|
||||
html += '<button type="button" class="chip-preview-btn" data-id="' + val.id + '" data-group-id="' + groupId + '" data-type="' + type + '" data-name="' + self.escapeAttr(val.name) + '" title="' + (self.config.trans && self.config.trans.preview || 'Preview') + '">';
|
||||
html += '<i class="icon-eye"></i>';
|
||||
html += '</button>';
|
||||
html += '</span>';
|
||||
});
|
||||
|
||||
$valuesContainer.html(html);
|
||||
@@ -4378,16 +4429,20 @@
|
||||
console.log('[EntitySelector] Making bulk AJAX request for entities:', JSON.stringify(bulkRequest));
|
||||
|
||||
// Single bulk AJAX call for all entity types
|
||||
var bulkAjaxData = {
|
||||
ajax: 1,
|
||||
action: 'getTargetEntitiesByIdsBulk',
|
||||
trait: 'EntitySelector',
|
||||
entities: JSON.stringify(bulkRequest)
|
||||
};
|
||||
if (self.config.productSelectionLevel && self.config.productSelectionLevel !== 'product') {
|
||||
bulkAjaxData.product_selection_level = self.config.productSelectionLevel;
|
||||
}
|
||||
$.ajax({
|
||||
url: self.config.ajaxUrl,
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
ajax: 1,
|
||||
action: 'getTargetEntitiesByIdsBulk',
|
||||
trait: 'EntitySelector',
|
||||
entities: JSON.stringify(bulkRequest)
|
||||
},
|
||||
data: bulkAjaxData,
|
||||
success: function(response) {
|
||||
console.log('[EntitySelector] AJAX response:', response);
|
||||
if (!response.success || !response.entities) {
|
||||
@@ -4706,18 +4761,22 @@
|
||||
|
||||
// Handle entity_search type - load via AJAX
|
||||
var searchEntity = $picker.attr('data-search-entity') || blockType;
|
||||
var pickerAjaxData = {
|
||||
ajax: 1,
|
||||
action: 'getTargetEntitiesByIds',
|
||||
trait: 'EntitySelector',
|
||||
entity_type: searchEntity,
|
||||
ids: JSON.stringify(values)
|
||||
};
|
||||
if (this.config.productSelectionLevel && this.config.productSelectionLevel !== 'product') {
|
||||
pickerAjaxData.product_selection_level = this.config.productSelectionLevel;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: this.config.ajaxUrl,
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
ajax: 1,
|
||||
action: 'getTargetEntitiesByIds',
|
||||
trait: 'EntitySelector',
|
||||
entity_type: searchEntity,
|
||||
ids: JSON.stringify(values)
|
||||
},
|
||||
data: pickerAjaxData,
|
||||
success: function(response) {
|
||||
if (response.success && response.entities) {
|
||||
// Track which IDs were actually found (entities may have been deleted)
|
||||
@@ -7167,7 +7226,8 @@
|
||||
clearValidationError: function() {
|
||||
this.$wrapper.removeClass('has-validation-error');
|
||||
this.$wrapper.find('.trait-validation-error').remove();
|
||||
}
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
@@ -7760,7 +7820,7 @@
|
||||
class: 'mpr-info-wrapper',
|
||||
'data-tooltip': helpContent
|
||||
});
|
||||
$infoWrapper.append($('<i>', { class: 'material-icons', text: 'info_outline' }));
|
||||
$infoWrapper.append($('<i>', { class: 'material-icons', text: 'info' }));
|
||||
$placeholder.append($infoWrapper);
|
||||
}
|
||||
},
|
||||
@@ -8240,23 +8300,8 @@
|
||||
});
|
||||
}
|
||||
|
||||
// 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));
|
||||
|
||||
$popover.css({
|
||||
position: 'absolute',
|
||||
top: badgeOffset.top + badgeHeight + 8,
|
||||
left: leftPos,
|
||||
zIndex: 10000
|
||||
});
|
||||
// Position popover relative to badge (handles viewport overflow)
|
||||
this.positionPopover($popover, $badge);
|
||||
|
||||
// Show with transition
|
||||
$popover.addClass('show');
|
||||
@@ -8264,6 +8309,61 @@
|
||||
return $popover;
|
||||
},
|
||||
|
||||
/**
|
||||
* Position a popover relative to a trigger element.
|
||||
* Handles horizontal and vertical viewport overflow.
|
||||
* @param {jQuery} $popover - The popover element
|
||||
* @param {jQuery} $trigger - The trigger element to position against
|
||||
* @param {number} [zIndex=10000] - Optional z-index
|
||||
*/
|
||||
positionPopover: function($popover, $trigger, zIndex) {
|
||||
var triggerRect = $trigger[0].getBoundingClientRect();
|
||||
var scrollTop = $(window).scrollTop();
|
||||
var scrollLeft = $(window).scrollLeft();
|
||||
var popoverWidth = $popover.outerWidth();
|
||||
var popoverHeight = $popover.outerHeight();
|
||||
var windowWidth = $(window).width();
|
||||
var windowHeight = $(window).height();
|
||||
var gap = 8;
|
||||
|
||||
// Horizontal: center on trigger, then clamp to viewport
|
||||
var left = triggerRect.left + scrollLeft + (triggerRect.width / 2) - (popoverWidth / 2);
|
||||
left = Math.max(10, Math.min(left, windowWidth - popoverWidth - 10));
|
||||
|
||||
// Vertical: prefer below, flip above if it would overflow
|
||||
var top;
|
||||
var positionAbove = false;
|
||||
if (triggerRect.bottom + popoverHeight + gap > windowHeight - 10) {
|
||||
// Position above the trigger
|
||||
top = triggerRect.top + scrollTop - popoverHeight - gap;
|
||||
positionAbove = true;
|
||||
} else {
|
||||
// Position below the trigger
|
||||
top = triggerRect.bottom + scrollTop + gap;
|
||||
}
|
||||
|
||||
$popover.css({
|
||||
position: 'absolute',
|
||||
top: top,
|
||||
left: left,
|
||||
zIndex: zIndex || 10000
|
||||
});
|
||||
|
||||
// Toggle arrow direction class
|
||||
$popover.toggleClass('position-above', positionAbove);
|
||||
|
||||
// Determine horizontal arrow position class
|
||||
var triggerCenter = triggerRect.left + (triggerRect.width / 2);
|
||||
var popoverLeft = left;
|
||||
var popoverCenter = popoverLeft + (popoverWidth / 2);
|
||||
$popover.removeClass('position-left position-right');
|
||||
if (triggerCenter - popoverLeft < popoverWidth * 0.3) {
|
||||
$popover.addClass('position-right');
|
||||
} else if (triggerCenter - popoverLeft > popoverWidth * 0.7) {
|
||||
$popover.addClass('position-left');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Update popover after loading more items
|
||||
*/
|
||||
@@ -9228,6 +9328,144 @@
|
||||
});
|
||||
},
|
||||
|
||||
// =========================================================================
|
||||
// FILTER VALUE PREVIEW (individual attribute/feature value chip)
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* Show preview popover for a specific filter value (attribute or feature value)
|
||||
* @param {jQuery} $badge - The preview button on the chip
|
||||
* @param {number} valueId - The attribute/feature value ID
|
||||
* @param {string} valueType - 'attribute' or 'feature'
|
||||
* @param {string} valueName - Display name of the value
|
||||
* @param {number} groupId - The parent group ID
|
||||
*/
|
||||
showFilterValuePreviewPopover: function($badge, valueId, valueType, valueName, groupId) {
|
||||
var self = this;
|
||||
|
||||
this.hidePreviewPopover();
|
||||
|
||||
$badge.addClass('popover-open loading');
|
||||
this.$activeBadge = $badge;
|
||||
|
||||
$.ajax({
|
||||
url: this.config.ajaxUrl,
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
ajax: 1,
|
||||
action: 'previewFilterValueProducts',
|
||||
trait: 'EntitySelector',
|
||||
value_id: valueId,
|
||||
value_type: valueType,
|
||||
group_id: groupId,
|
||||
limit: 10
|
||||
},
|
||||
success: function(response) {
|
||||
$badge.removeClass('loading');
|
||||
|
||||
if (response.success) {
|
||||
self.createPreviewPopover({
|
||||
$badge: $badge,
|
||||
items: response.items || [],
|
||||
totalCount: response.count || 0,
|
||||
hasMore: response.hasMore || false,
|
||||
entityLabel: 'products',
|
||||
previewType: 'filter-value',
|
||||
context: { valueId: valueId, valueType: valueType, groupId: groupId, valueName: valueName },
|
||||
onLoadMore: function($btn) {
|
||||
self.loadMoreFilterValueItems($btn);
|
||||
},
|
||||
onFilter: function(query) {
|
||||
self.filterFilterValueItems(query);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$badge.removeClass('popover-open');
|
||||
self.$activeBadge = null;
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
$badge.removeClass('loading popover-open');
|
||||
self.$activeBadge = null;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* AJAX filter handler for filter value preview
|
||||
*/
|
||||
filterFilterValueItems: function(query) {
|
||||
var self = this;
|
||||
var ctx = this.previewContext;
|
||||
|
||||
if (!ctx || !ctx.valueId) {
|
||||
self.showFilterLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: this.config.ajaxUrl,
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
ajax: 1,
|
||||
action: 'previewFilterValueProducts',
|
||||
trait: 'EntitySelector',
|
||||
value_id: ctx.valueId,
|
||||
value_type: ctx.valueType,
|
||||
group_id: ctx.groupId,
|
||||
filter: query,
|
||||
limit: 20
|
||||
},
|
||||
success: function(response) {
|
||||
self.updatePreviewPopoverFiltered(response);
|
||||
},
|
||||
error: function() {
|
||||
self.showFilterLoading(false);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
loadMoreFilterValueItems: function($btn) {
|
||||
var self = this;
|
||||
var ctx = this.previewContext;
|
||||
|
||||
if (!ctx || !ctx.valueId) return;
|
||||
|
||||
var loadCount = this.previewLoadCount || 20;
|
||||
|
||||
var ajaxData = {
|
||||
ajax: 1,
|
||||
action: 'previewFilterValueProducts',
|
||||
trait: 'EntitySelector',
|
||||
value_id: ctx.valueId,
|
||||
value_type: ctx.valueType,
|
||||
group_id: ctx.groupId,
|
||||
limit: self.previewLoadedCount + loadCount
|
||||
};
|
||||
if (self.previewCurrentFilter) {
|
||||
ajaxData.filter = self.previewCurrentFilter;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: this.config.ajaxUrl,
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
data: ajaxData,
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
self.previewTotalCount = response.count;
|
||||
self.updatePreviewPopover(response.items || [], response.hasMore);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
$btn.removeClass('loading');
|
||||
$btn.find('i').removeClass('icon-spinner icon-spin').addClass('icon-plus');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// =========================================================================
|
||||
// CATEGORY ITEMS PREVIEW (products/pages in a category)
|
||||
// =========================================================================
|
||||
@@ -9565,28 +9803,9 @@
|
||||
self.switchToBlock(blockType);
|
||||
});
|
||||
|
||||
// Position popover
|
||||
// Position popover relative to badge (handles viewport overflow)
|
||||
$('body').append($popover);
|
||||
var badgeOffset = $badge.offset();
|
||||
var badgeHeight = $badge.outerHeight();
|
||||
var popoverWidth = $popover.outerWidth();
|
||||
|
||||
$popover.css({
|
||||
position: 'absolute',
|
||||
top: badgeOffset.top + badgeHeight + 5,
|
||||
left: badgeOffset.left - (popoverWidth / 2) + ($badge.outerWidth() / 2),
|
||||
zIndex: 10000
|
||||
});
|
||||
|
||||
// Adjust if off screen
|
||||
var windowWidth = $(window).width();
|
||||
var popoverRight = $popover.offset().left + popoverWidth;
|
||||
if (popoverRight > windowWidth - 10) {
|
||||
$popover.css('left', windowWidth - popoverWidth - 10);
|
||||
}
|
||||
if ($popover.offset().left < 10) {
|
||||
$popover.css('left', 10);
|
||||
}
|
||||
this.positionPopover($popover, $badge);
|
||||
|
||||
$popover.hide().fadeIn(150);
|
||||
},
|
||||
|
||||
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
Reference in New Issue
Block a user