diff --git a/assets/assets/css/admin/entity-selector.css b/assets/assets/css/admin/entity-selector.css new file mode 100644 index 0000000..59cf08e --- /dev/null +++ b/assets/assets/css/admin/entity-selector.css @@ -0,0 +1,10903 @@ +@charset "UTF-8"; +/** + * Entity Selector Styles + * @package prestashop-entity-selector + * @version 2.0.0 + * + * Compiles to: assets/css/admin/entity-selector.css + */ +/** + * Entity Selector Variables + * Bootstrap 4 compatible values for PrestaShop admin theme + * + * Imports shared variables from prestashop-admin package + * and maps them to $es-* prefixed aliases for this package + */ +/** + * MPR Admin Variables + * @package prestashop-admin + * + * Color token system: + * - PS theme vars (--primary, --danger, etc.) → set by PrestaShop admin theme + * - MPR tokens (--mpr-*) → set here as defaults, overridable per module/theme + * + * Usage in SCSS: var(--token, $fallback) + * The $fallback SCSS vars below ensure compilation succeeds even without :root. + */ +/** + * Entity Selector Styles + * @package prestashop-entity-selector + * @version 2.0.0 + * + * Compiles to: assets/css/admin/entity-selector.css + */ +/** + * Entity Selector Mixins + * Reusable patterns - prefer Bootstrap utilities in HTML where possible + */ +@keyframes spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} +@keyframes spin-pulse { + 0% { + transform: rotate(0deg); + opacity: 1; + } + 50% { + opacity: 0.4; + } + 100% { + transform: rotate(360deg); + opacity: 1; + } +} +.es-spin { + animation: spin 1s linear infinite; +} + +.es-spin-pulse { + animation: spin-pulse 1s ease-in-out infinite; +} + +/** + * Entity Selector Styles + * @package prestashop-entity-selector + * @version 2.0.0 + * + * Compiles to: assets/css/admin/entity-selector.css + */ +/** + * Form Integration Styles + * Handles PrestaShop admin form layout overrides + */ +.target-conditions-trait, +.target-conditions-trait *, +.entity-selector-trait, +.entity-selector-trait *, +.method-dropdown-menu, +.method-dropdown-menu *, +.target-preview-popover, +.target-preview-popover * { + border-style: solid; + border-width: 0; + border-color: #dee2e6; +} + +.form-group:has(.entity-selector-trait:not(.layout-form-group)), +.form-group:has(.target-conditions-trait:not(.layout-form-group)), +.form-group:has(.condition-trait:not(.layout-form-group)) { + display: block; +} +.form-group:has(.entity-selector-trait:not(.layout-form-group)) > .control-label, +.form-group:has(.target-conditions-trait:not(.layout-form-group)) > .control-label, +.form-group:has(.condition-trait:not(.layout-form-group)) > .control-label { + display: none; +} +.form-group:has(.entity-selector-trait:not(.layout-form-group)) > .col-lg-8, +.form-group:has(.target-conditions-trait:not(.layout-form-group)) > .col-lg-8, +.form-group:has(.condition-trait:not(.layout-form-group)) > .col-lg-8 { + width: 100%; + max-width: 100%; + padding-left: 1rem; + padding-right: 1rem; + flex: 0 0 100% !important; +} + +.form-group.condition-trait-fullwidth { + display: block; +} +.form-group.condition-trait-fullwidth > .control-label { + display: none; +} +.form-group.condition-trait-fullwidth > .col-lg-8 { + width: 100%; + max-width: 100%; + padding-left: 1rem; + padding-right: 1rem; + flex: 0 0 100% !important; +} + +.form-group:has(.layout-form-group) > .control-label { + display: flex !important; +} + +.panel:has(.target-search-dropdown.show), +.card:has(.target-search-dropdown.show), +.form-wrapper:has(.target-search-dropdown.show), +.panel-body:has(.target-search-dropdown.show), +.card-body:has(.target-search-dropdown.show), +.form-group:has(.target-search-dropdown.show), +.col-lg-8:has(.target-search-dropdown.show), +.col-lg-12:has(.target-search-dropdown.show) { + overflow: visible !important; +} + +.target-conditions-trait:has(.target-search-dropdown.show), +.entity-selector-trait:has(.target-search-dropdown.show), +.condition-trait-body:has(.target-search-dropdown.show), +.target-block-content:has(.target-search-dropdown.show), +.target-block-groups:has(.target-search-dropdown.show), +.target-group:has(.target-search-dropdown.show), +.target-group-body:has(.target-search-dropdown.show), +.target-search-wrapper:has(.target-search-dropdown.show) { + overflow: visible !important; +} + +.target-conditions-trait.layout-embedded, +.entity-selector-trait.layout-embedded { + background: transparent; + border: none; + border-radius: 0; +} +.target-conditions-trait.layout-embedded .groups-container, +.entity-selector-trait.layout-embedded .groups-container { + padding: 0; +} +.target-conditions-trait.layout-embedded .block-body, +.entity-selector-trait.layout-embedded .block-body { + padding: 0; +} +.target-conditions-trait.layout-embedded .block-footer, +.entity-selector-trait.layout-embedded .block-footer { + border-top: none; + padding: 0.5rem 0 0; +} +.target-conditions-trait.layout-embedded .selection-group, +.entity-selector-trait.layout-embedded .selection-group { + background: #ffffff; + border: 1px solid #e2e8f0; + border-radius: 0.25rem; +} +.target-conditions-trait.layout-embedded .selection-group .group-header, +.entity-selector-trait.layout-embedded .selection-group .group-header { + background: #f8fafc; + border-bottom-color: #e2e8f0; + padding: 0.25rem 0.5rem; + border-radius: 0.25rem 0.25rem 0 0; +} +.target-conditions-trait.layout-embedded .selection-group .group-body, +.entity-selector-trait.layout-embedded .selection-group .group-body { + padding: 0.75rem; +} +.target-conditions-trait.layout-embedded .selection-group .group-include, +.entity-selector-trait.layout-embedded .selection-group .group-include { + padding: 0.25rem; + margin-bottom: 0.5rem; +} +.target-conditions-trait.layout-embedded .selection-group .group-modifiers, +.entity-selector-trait.layout-embedded .selection-group .group-modifiers { + padding: 0.25rem 0.5rem; + margin: 0.5rem -0.5rem -0.5rem; +} +.target-conditions-trait.layout-embedded .groups-empty-state, +.entity-selector-trait.layout-embedded .groups-empty-state { + padding: 1rem; +} +.target-conditions-trait.layout-embedded .btn-add-group, +.entity-selector-trait.layout-embedded .btn-add-group { + padding: 0.375rem 0.625rem; + font-size: 0.75rem; +} + +/** + * Entity Selector Styles + * @package prestashop-entity-selector + * @version 2.0.0 + * + * Compiles to: assets/css/admin/entity-selector.css + */ +/** + * Responsive Styles + * Media query adjustments for different screen sizes + */ +@media (max-width: 991px) { + .target-conditions-trait .condition-trait-header, + .entity-selector-trait .condition-trait-header { + flex-direction: column; + align-items: flex-start; + gap: 0.5rem; + } + .target-conditions-trait .trait-header-right, + .entity-selector-trait .trait-header-right { + width: 100%; + justify-content: flex-end; + } + .target-conditions-trait .target-block-tabs, + .entity-selector-trait .target-block-tabs { + flex-wrap: wrap; + } +} +@media (max-width: 767px) { + .target-conditions-trait .target-block-tab, + .entity-selector-trait .target-block-tab { + padding: 0.5rem; + font-size: 0.75rem; + } + .target-conditions-trait .target-group-header, + .entity-selector-trait .target-group-header { + flex-direction: column; + align-items: flex-start; + } + .target-conditions-trait .target-search-dropdown, + .entity-selector-trait .target-search-dropdown { + width: 100% !important; + left: 0 !important; + right: 0 !important; + } + .target-conditions-trait .dropdown-results-grid, + .entity-selector-trait .dropdown-results-grid { + grid-template-columns: 1fr !important; + } +} +@media (min-width: 1600px) { + .target-conditions-trait .dropdown-results-grid.view-grid-3, + .entity-selector-trait .dropdown-results-grid.view-grid-3 { + grid-template-columns: repeat(4, 1fr); + } +} +/** + * Entity Selector Styles + * @package prestashop-entity-selector + * @version 2.0.0 + * + * Compiles to: assets/css/admin/entity-selector.css + */ +/** + * Entity Selector - Main Component Styles + * Wrapper, header, body, tabs, blocks + */ +.target-conditions-trait, +.entity-selector-trait { + position: relative; + overflow: visible; + background: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.3rem; +} +.target-conditions-trait .material-icons, +.entity-selector-trait .material-icons { + font-size: 18px !important; +} +.target-conditions-trait .condition-trait-header, +.entity-selector-trait .condition-trait-header { + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; + gap: 1rem; + padding: 0.875rem 1rem; + background: #f8f9fa; + border-bottom: 1px solid #dee2e6; + border-radius: 0.3rem 0.3rem 0 0; + cursor: pointer; + user-select: none; + transition: background-color 0.15s ease-in-out; +} +.target-conditions-trait .condition-trait-header:hover, +.entity-selector-trait .condition-trait-header:hover { + background: #e9ecef; +} +.target-conditions-trait .trait-header-left, +.entity-selector-trait .trait-header-left { + display: flex; + align-items: center; + gap: 0.75rem; + min-width: 0; + flex: 1; +} +.target-conditions-trait .trait-icon, +.entity-selector-trait .trait-icon { + font-size: 1.125rem; + color: #6c757d; + flex-shrink: 0; +} +.target-conditions-trait .trait-title-group, +.entity-selector-trait .trait-title-group { + display: flex; + flex-direction: column; + gap: 0.125rem; + min-width: 0; +} +.target-conditions-trait .trait-title, +.entity-selector-trait .trait-title { + font-size: 0.875rem; + font-weight: 600; + color: #212529; + white-space: nowrap; +} +.target-conditions-trait .trait-subtitle, +.entity-selector-trait .trait-subtitle { + font-size: 0.75rem; + color: #6c757d; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.target-conditions-trait .trait-total-count, +.entity-selector-trait .trait-total-count { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.25rem; + min-width: 20px; + height: 20px; + padding: 0 0.5rem; + background: #25b9d7; + color: #ffffff; + font-size: 0.75rem; + font-weight: 600; + border-radius: 50rem; + cursor: pointer; + transition: all 0.15s ease-in-out; + flex-shrink: 0; +} +.target-conditions-trait .trait-total-count:hover, +.entity-selector-trait .trait-total-count:hover { + transform: scale(1.05); + box-shadow: 0 2px 8px rgba(37, 185, 215, 0.4); +} +.target-conditions-trait .trait-total-count:focus, +.entity-selector-trait .trait-total-count:focus { + outline: none; + box-shadow: 0 0 0 2px rgba(37, 185, 215, 0.3), 0 2px 8px rgba(37, 185, 215, 0.4); +} +.target-conditions-trait .trait-total-count.loading, +.entity-selector-trait .trait-total-count.loading { + cursor: wait; +} +.target-conditions-trait .trait-total-count.loading i, +.entity-selector-trait .trait-total-count.loading i { + font-size: 10px; + animation: spin 0.6s linear infinite; +} +.target-conditions-trait .trait-total-count.loading:hover, +.entity-selector-trait .trait-total-count.loading:hover { + transform: none; + box-shadow: none; +} +.target-conditions-trait .trait-total-count.inactive, .target-conditions-trait .trait-total-count.no-matches, +.entity-selector-trait .trait-total-count.inactive, +.entity-selector-trait .trait-total-count.no-matches { + background: #94a3b8; + cursor: default; +} +.target-conditions-trait .trait-total-count.inactive:hover, .target-conditions-trait .trait-total-count.no-matches:hover, +.entity-selector-trait .trait-total-count.inactive:hover, +.entity-selector-trait .trait-total-count.no-matches:hover { + transform: none; + box-shadow: none; +} +.target-conditions-trait .trait-total-count.popover-open, +.entity-selector-trait .trait-total-count.popover-open { + background: rgb(29.5119047619, 147.5595238095, 171.4880952381); + box-shadow: 0 2px 8px rgba(37, 185, 215, 0.4); +} +.target-conditions-trait .trait-total-count i, +.entity-selector-trait .trait-total-count i { + font-size: 10px; + line-height: 1; + opacity: 0.8; +} +.target-conditions-trait .trait-total-count:hover i, +.entity-selector-trait .trait-total-count:hover i { + opacity: 1; +} +.target-conditions-trait .trait-total-count .preview-count, +.entity-selector-trait .trait-total-count .preview-count { + font-weight: 700; +} +.target-conditions-trait .trait-total-count, +.entity-selector-trait .trait-total-count { + margin-left: 0.5rem; +} +.target-conditions-trait .trait-show-all-toggle, +.entity-selector-trait .trait-show-all-toggle { + display: inline-flex; + align-items: center; + gap: 0.5rem; + margin-right: 0.75rem; + padding: 0.25rem 0.5rem; + border-radius: 0.2rem; + cursor: pointer; + user-select: none; + transition: background-color 0.15s ease-in-out; +} +.target-conditions-trait .trait-show-all-toggle:hover, +.entity-selector-trait .trait-show-all-toggle:hover { + background: rgba(0, 0, 0, 0.05); +} +.target-conditions-trait .trait-show-all-toggle .toggle-label, +.entity-selector-trait .trait-show-all-toggle .toggle-label { + font-size: 0.75rem; + font-weight: 500; + color: #6c757d; +} +.target-conditions-trait .trait-show-all-toggle .show-all-checkbox, +.entity-selector-trait .trait-show-all-toggle .show-all-checkbox { + display: none; +} +.target-conditions-trait .trait-show-all-toggle .toggle-slider, +.entity-selector-trait .trait-show-all-toggle .toggle-slider { + position: relative; + width: 36px; + height: 20px; + background: #cbd5e1; + border-radius: 50rem; + transition: background-color 0.2s ease-in-out; +} +.target-conditions-trait .trait-show-all-toggle .toggle-slider::after, +.entity-selector-trait .trait-show-all-toggle .toggle-slider::after { + content: ""; + position: absolute; + top: 2px; + left: 2px; + width: 16px; + height: 16px; + background: #ffffff; + border-radius: 50%; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); + transition: transform 0.2s ease-in-out; +} +.target-conditions-trait .trait-show-all-toggle .show-all-checkbox:checked + .toggle-slider, +.entity-selector-trait .trait-show-all-toggle .show-all-checkbox:checked + .toggle-slider { + background: #70b580; +} +.target-conditions-trait .trait-show-all-toggle .show-all-checkbox:checked + .toggle-slider::after, +.entity-selector-trait .trait-show-all-toggle .show-all-checkbox:checked + .toggle-slider::after { + transform: translateX(16px); +} +.target-conditions-trait.has-validation-error, +.entity-selector-trait.has-validation-error { + border-color: #dc3545; + box-shadow: 0 0 0 3px rgba(220, 53, 69, 0.1); +} +.target-conditions-trait.has-validation-error .condition-trait-header, +.entity-selector-trait.has-validation-error .condition-trait-header { + border-bottom-color: #dc3545; +} +.target-conditions-trait .trait-validation-error, +.entity-selector-trait .trait-validation-error { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.625rem 1rem; + background: #f8d7da; + color: #b91c1c; + font-size: 0.875rem; + font-weight: 500; + border-bottom: 1px solid #fecaca; +} +.target-conditions-trait .trait-validation-error i, +.entity-selector-trait .trait-validation-error i { + color: #dc3545; +} +.target-conditions-trait.trait-required .trait-title::after, +.entity-selector-trait.trait-required .trait-title::after { + content: " *"; + color: #dc3545; +} +.target-conditions-trait .condition-trait-body, +.entity-selector-trait .condition-trait-body { + padding: 0; + background: #ffffff; + border-radius: 0 0 0.3rem 0.3rem; +} +.target-conditions-trait .target-block-tabs, +.entity-selector-trait .target-block-tabs { + display: flex; + flex-wrap: wrap; + gap: 0; + padding: 0; + background: #f1f5f9; + border-bottom: 1px solid #dee2e6; +} +.target-conditions-trait .target-block-tab, +.entity-selector-trait .target-block-tab { + position: relative; + display: flex; + align-items: center; + gap: 0.5rem; + flex: none; + min-width: 0; + padding: 0.625rem 1rem; + margin-bottom: -1px; + background: transparent; + border: 0; + border-bottom: 2px solid transparent; + color: #6c757d; + font-size: 0.875rem; + font-weight: 500; + cursor: pointer; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .target-block-tab:hover, +.entity-selector-trait .target-block-tab:hover { + background: #e2e8f0; + color: #334155; +} +.target-conditions-trait .target-block-tab.active, +.entity-selector-trait .target-block-tab.active { + background: #ffffff; + border-bottom-color: #06b6d4; + color: #25b9d7; +} +.target-conditions-trait .target-block-tab i.material-icons, +.entity-selector-trait .target-block-tab i.material-icons { + font-size: 18px !important; +} +.target-conditions-trait .target-block-tab .tab-label, +.entity-selector-trait .target-block-tab .tab-label { + white-space: nowrap; +} +.target-conditions-trait .target-block-tab .tab-badge, +.entity-selector-trait .target-block-tab .tab-badge { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.25rem; + min-width: 20px; + height: 20px; + padding: 0 0.5rem; + background: #25b9d7; + color: #ffffff; + font-size: 0.75rem; + font-weight: 600; + border-radius: 50rem; + cursor: pointer; + transition: all 0.15s ease-in-out; + flex-shrink: 0; +} +.target-conditions-trait .target-block-tab .tab-badge:hover, +.entity-selector-trait .target-block-tab .tab-badge:hover { + transform: scale(1.05); + box-shadow: 0 2px 8px rgba(37, 185, 215, 0.4); +} +.target-conditions-trait .target-block-tab .tab-badge:focus, +.entity-selector-trait .target-block-tab .tab-badge:focus { + outline: none; + box-shadow: 0 0 0 2px rgba(37, 185, 215, 0.3), 0 2px 8px rgba(37, 185, 215, 0.4); +} +.target-conditions-trait .target-block-tab .tab-badge.loading, +.entity-selector-trait .target-block-tab .tab-badge.loading { + cursor: wait; +} +.target-conditions-trait .target-block-tab .tab-badge.loading i, +.entity-selector-trait .target-block-tab .tab-badge.loading i { + font-size: 10px; + animation: spin 0.6s linear infinite; +} +.target-conditions-trait .target-block-tab .tab-badge.loading:hover, +.entity-selector-trait .target-block-tab .tab-badge.loading:hover { + transform: none; + box-shadow: none; +} +.target-conditions-trait .target-block-tab .tab-badge.inactive, .target-conditions-trait .target-block-tab .tab-badge.no-matches, +.entity-selector-trait .target-block-tab .tab-badge.inactive, +.entity-selector-trait .target-block-tab .tab-badge.no-matches { + background: #94a3b8; + cursor: default; +} +.target-conditions-trait .target-block-tab .tab-badge.inactive:hover, .target-conditions-trait .target-block-tab .tab-badge.no-matches:hover, +.entity-selector-trait .target-block-tab .tab-badge.inactive:hover, +.entity-selector-trait .target-block-tab .tab-badge.no-matches:hover { + transform: none; + box-shadow: none; +} +.target-conditions-trait .target-block-tab .tab-badge.popover-open, +.entity-selector-trait .target-block-tab .tab-badge.popover-open { + background: rgb(29.5119047619, 147.5595238095, 171.4880952381); + box-shadow: 0 2px 8px rgba(37, 185, 215, 0.4); +} +.target-conditions-trait .target-block-tab .tab-badge i, +.entity-selector-trait .target-block-tab .tab-badge i { + font-size: 10px; + line-height: 1; + opacity: 0.8; +} +.target-conditions-trait .target-block-tab .tab-badge:hover i, +.entity-selector-trait .target-block-tab .tab-badge:hover i { + opacity: 1; +} +.target-conditions-trait .target-block-tab .tab-badge .preview-count, +.entity-selector-trait .target-block-tab .tab-badge .preview-count { + font-weight: 700; +} +.target-conditions-trait .target-block-tab.has-data:not(.active) .tab-badge, +.entity-selector-trait .target-block-tab.has-data:not(.active) .tab-badge { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.25rem; + min-width: 20px; + height: 20px; + padding: 0 0.5rem; + background: #94a3b8; + color: #ffffff; + font-size: 0.75rem; + font-weight: 600; + border-radius: 50rem; + cursor: pointer; + transition: all 0.15s ease-in-out; + flex-shrink: 0; +} +.target-conditions-trait .target-block-tab.has-data:not(.active) .tab-badge:hover, +.entity-selector-trait .target-block-tab.has-data:not(.active) .tab-badge:hover { + transform: scale(1.05); + box-shadow: 0 2px 8px rgba(148, 163, 184, 0.4); +} +.target-conditions-trait .target-block-tab.has-data:not(.active) .tab-badge:focus, +.entity-selector-trait .target-block-tab.has-data:not(.active) .tab-badge:focus { + outline: none; + box-shadow: 0 0 0 2px rgba(148, 163, 184, 0.3), 0 2px 8px rgba(148, 163, 184, 0.4); +} +.target-conditions-trait .target-block-tab.has-data:not(.active) .tab-badge.loading, +.entity-selector-trait .target-block-tab.has-data:not(.active) .tab-badge.loading { + cursor: wait; +} +.target-conditions-trait .target-block-tab.has-data:not(.active) .tab-badge.loading i, +.entity-selector-trait .target-block-tab.has-data:not(.active) .tab-badge.loading i { + font-size: 10px; + animation: spin 0.6s linear infinite; +} +.target-conditions-trait .target-block-tab.has-data:not(.active) .tab-badge.loading:hover, +.entity-selector-trait .target-block-tab.has-data:not(.active) .tab-badge.loading:hover { + transform: none; + box-shadow: none; +} +.target-conditions-trait .target-block-tab.has-data:not(.active) .tab-badge.inactive, .target-conditions-trait .target-block-tab.has-data:not(.active) .tab-badge.no-matches, +.entity-selector-trait .target-block-tab.has-data:not(.active) .tab-badge.inactive, +.entity-selector-trait .target-block-tab.has-data:not(.active) .tab-badge.no-matches { + background: #94a3b8; + cursor: default; +} +.target-conditions-trait .target-block-tab.has-data:not(.active) .tab-badge.inactive:hover, .target-conditions-trait .target-block-tab.has-data:not(.active) .tab-badge.no-matches:hover, +.entity-selector-trait .target-block-tab.has-data:not(.active) .tab-badge.inactive:hover, +.entity-selector-trait .target-block-tab.has-data:not(.active) .tab-badge.no-matches:hover { + transform: none; + box-shadow: none; +} +.target-conditions-trait .target-block-tab.has-data:not(.active) .tab-badge.popover-open, +.entity-selector-trait .target-block-tab.has-data:not(.active) .tab-badge.popover-open { + background: rgb(117.3426966292, 136.6404494382, 163.6573033708); + box-shadow: 0 2px 8px rgba(148, 163, 184, 0.4); +} +.target-conditions-trait .target-block-tab.has-data:not(.active) .tab-badge i, +.entity-selector-trait .target-block-tab.has-data:not(.active) .tab-badge i { + font-size: 10px; + line-height: 1; + opacity: 0.8; +} +.target-conditions-trait .target-block-tab.has-data:not(.active) .tab-badge:hover i, +.entity-selector-trait .target-block-tab.has-data:not(.active) .tab-badge:hover i { + opacity: 1; +} +.target-conditions-trait .target-block-tab.has-data:not(.active) .tab-badge .preview-count, +.entity-selector-trait .target-block-tab.has-data:not(.active) .tab-badge .preview-count { + font-weight: 700; +} +.target-conditions-trait .entity-selector-tabs-row, +.entity-selector-trait .entity-selector-tabs-row { + display: flex; + align-items: stretch; + background: #f1f5f9; + border-bottom: 1px solid #dee2e6; + border-radius: 0.3rem 0.3rem 0 0; +} +.target-conditions-trait .entity-selector-tabs-row .target-block-tabs, +.entity-selector-trait .entity-selector-tabs-row .target-block-tabs { + flex: 1; + border-bottom: 0; + border-radius: 0.3rem 0 0 0; +} +.target-conditions-trait .entity-selector-actions:not(.btn-toggle-blocks), +.entity-selector-trait .entity-selector-actions:not(.btn-toggle-blocks) { + display: flex; + align-items: center; + padding: 0.25rem 1rem; + border-left: 1px solid #dee2e6; +} +.target-conditions-trait .entity-selector-actions:not(.btn-toggle-blocks) .btn-toggle-groups, +.entity-selector-trait .entity-selector-actions:not(.btn-toggle-blocks) .btn-toggle-groups { + display: flex; + align-items: center; + justify-content: center; + width: 34px; + height: 34px; + padding: 0; + background: #ffffff; + border: 1px solid #94a3b8; + border-radius: 0.25rem; + color: #334155; + cursor: pointer; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .entity-selector-actions:not(.btn-toggle-blocks) .btn-toggle-groups:hover, +.entity-selector-trait .entity-selector-actions:not(.btn-toggle-blocks) .btn-toggle-groups:hover { + background: rgba(37, 185, 215, 0.1); + color: #25b9d7; + border-color: #25b9d7; +} +.target-conditions-trait .entity-selector-actions:not(.btn-toggle-blocks) .btn-toggle-groups .material-icons, +.entity-selector-trait .entity-selector-actions:not(.btn-toggle-blocks) .btn-toggle-groups .material-icons { + font-size: 18px !important; +} +.target-conditions-trait .entity-selector-actions.btn-toggle-blocks, +.entity-selector-trait .entity-selector-actions.btn-toggle-blocks { + display: flex; + align-items: center; + justify-content: center; + padding: 0 1rem; + background: #f1f5f9; + border-left: 1px solid #dee2e6; + color: #94a3b8; + cursor: pointer; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .entity-selector-actions.btn-toggle-blocks:hover, +.entity-selector-trait .entity-selector-actions.btn-toggle-blocks:hover { + background: #e2e8f0; + color: #25b9d7; +} +.target-conditions-trait .entity-selector-actions.btn-toggle-blocks .material-icons, +.entity-selector-trait .entity-selector-actions.btn-toggle-blocks .material-icons { + font-size: 20px !important; +} +.target-conditions-trait .entity-selector-trait:not(.blocks-collapsed) .entity-selector-actions.btn-toggle-blocks, +.entity-selector-trait .entity-selector-trait:not(.blocks-collapsed) .entity-selector-actions.btn-toggle-blocks { + background: rgba(37, 185, 215, 0.1); + border-left-color: #25b9d7; + color: #25b9d7; +} +.target-conditions-trait .target-block-container, +.entity-selector-trait .target-block-container { + display: none; +} +.target-conditions-trait .target-block-container.active, +.entity-selector-trait .target-block-container.active { + display: block; +} +.target-conditions-trait .target-block-content, +.entity-selector-trait .target-block-content { + padding: 1rem; +} +.target-conditions-trait .target-block-groups, +.entity-selector-trait .target-block-groups { + display: flex; + flex-direction: column; + gap: 1rem; +} +.target-conditions-trait .target-block-header, +.entity-selector-trait .target-block-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 0.5rem 1rem; + background: #f8f9fa; + border-bottom: 1px solid #dee2e6; +} +.target-conditions-trait .target-block-empty, +.entity-selector-trait .target-block-empty { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 0.5rem; + padding: 2rem; + text-align: center; + color: #6c757d; +} +.target-conditions-trait .target-block-empty i, +.entity-selector-trait .target-block-empty i { + font-size: 2rem !important; + opacity: 0.5; +} +.target-conditions-trait .target-block-empty p, +.entity-selector-trait .target-block-empty p { + margin: 0; + font-size: 0.875rem; +} +.target-conditions-trait .trait-collapse-toggle, +.target-conditions-trait .collapse-toggle, +.entity-selector-trait .trait-collapse-toggle, +.entity-selector-trait .collapse-toggle { + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + color: #6c757d; + cursor: pointer; + transition: transform 0.2s ease-in-out; +} +.target-conditions-trait .trait-collapse-toggle.collapsed, +.target-conditions-trait .collapse-toggle.collapsed, +.entity-selector-trait .trait-collapse-toggle.collapsed, +.entity-selector-trait .collapse-toggle.collapsed { + transform: rotate(-90deg); +} +.target-conditions-trait .trait-header-right, +.entity-selector-trait .trait-header-right { + display: flex; + align-items: center; + gap: 0.5rem; +} +.target-conditions-trait.collapsed .condition-trait-body, +.entity-selector-trait.collapsed .condition-trait-body { + display: none; +} +.target-conditions-trait.collapsed .condition-trait-header, +.entity-selector-trait.collapsed .condition-trait-header { + border-radius: 0.3rem; +} + +.target-conditions-trait.single-mode .target-block-tabs, +.entity-selector-trait.single-mode .target-block-tabs { + display: none; +} +.target-conditions-trait.single-mode .target-block-container, +.entity-selector-trait.single-mode .target-block-container { + display: block; +} + +.target-conditions-trait .header-actions, +.entity-selector-trait .header-actions { + display: flex; + align-items: center; + gap: 0.25rem; +} +.target-conditions-trait .header-action-btn, +.entity-selector-trait .header-action-btn { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .header-action-btn:focus, +.entity-selector-trait .header-action-btn:focus { + outline: none; +} +.target-conditions-trait .header-action-btn, +.entity-selector-trait .header-action-btn { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + font-size: 0.75rem; + font-weight: 500; + color: #6c757d; + background: transparent; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .header-action-btn:hover, +.entity-selector-trait .header-action-btn:hover { + background: #e2e8f0; + color: #495057; +} +.target-conditions-trait .header-action-btn i, +.entity-selector-trait .header-action-btn i { + font-size: 14px !important; +} + +/** + * Entity Selector Styles + * @package prestashop-entity-selector + * @version 2.0.0 + * + * Compiles to: assets/css/admin/entity-selector.css + */ +/** + * Entity Item - Shared Base Component + * Unified styling for entity items in chips, lists, and previews + * + * Variants: + * - .entity-item (base) - default list-row style + * - .entity-item.chip-style - pill/chip style (compact) + * - .entity-item.card-style - card/grid style + */ +.entity-item { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem; + background: #ffffff; + border-radius: 0.2rem; + transition: background 0.15s ease-in-out; +} +.entity-item:hover { + background: #e9ecef; +} +.entity-item.clickable { + cursor: pointer; +} +.entity-item.selected { + background: rgba(37, 185, 215, 0.1); +} + +.entity-item-image { + flex-shrink: 0; + width: 32px; + height: 32px; + object-fit: cover; + border-radius: 0.2rem; + background: #f1f5f9; +} + +.entity-item-image--sm { + width: 20px; + height: 20px; + border-radius: 50%; +} + +.entity-item-image--lg { + width: 48px; + height: 48px; +} + +.entity-item-no-image { + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + width: 32px; + height: 32px; + background: #f1f5f9; + color: #6c757d; + border-radius: 0.2rem; + font-size: 0.875rem; +} +.entity-item-no-image--sm { + width: 20px; + height: 20px; + font-size: 10px; + border-radius: 50%; +} + +.entity-item-info { + flex: 1; + min-width: 0; + display: flex; + flex-direction: column; + gap: 0.125rem; +} + +.entity-item-name { + font-size: 0.875rem; + font-weight: 500; + color: #212529; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.entity-item-meta { + font-size: 0.75rem; + color: #6c757d; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.entity-item-badge { + flex-shrink: 0; + padding: 0.125rem 0.5rem; + font-size: 0.75rem; + font-weight: 500; + background: #f1f5f9; + color: #6c757d; + border-radius: 0.2rem; +} + +.entity-item-price { + flex-shrink: 0; + font-size: 0.875rem; + font-weight: 600; + color: #25b9d7; +} + +.entity-item-action { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.entity-item-action:focus { + outline: none; +} +.entity-item-action { + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + width: 20px; + height: 20px; + color: #6c757d; + border-radius: 50%; + transition: all 0.15s ease-in-out; +} +.entity-item-action:hover { + background: rgba(0, 0, 0, 0.1); + color: #dc3545; +} +.entity-item-action i { + font-size: 10px; +} + +.entity-item.chip-style { + display: inline-flex; + gap: 0.375rem; + padding: 0.25rem 0.5rem; + background: #f1f5f9; + border-radius: 50rem; +} +.entity-item.chip-style:hover { + background: #e2e8f0; +} +.entity-item.chip-style .entity-item-image { + width: 20px; + height: 20px; + border-radius: 50%; +} +.entity-item.chip-style .entity-item-no-image { + width: 20px; + height: 20px; + font-size: 10px; + border-radius: 50%; +} +.entity-item.chip-style .entity-item-info { + flex-direction: row; + align-items: center; + gap: 0.25rem; +} +.entity-item.chip-style .entity-item-name { + font-size: 0.75rem; +} +.entity-item.chip-style .entity-item-meta { + display: none; +} +.entity-item.chip-style .entity-item-action { + width: 16px; + height: 16px; + margin-left: 0.125rem; +} + +.entity-item.list-style { + padding: 0.5rem 0; + background: transparent; + border-bottom: 1px solid #dee2e6; + border-radius: 0; +} +.entity-item.list-style:last-child { + border-bottom: none; +} +.entity-item.list-style:hover { + background: #e9ecef; +} + +.entity-items-container { + display: flex; + flex-direction: column; + background: #f8fafc; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + overflow: hidden; +} + +.entity-items-toolbar { + display: none; + align-items: center; + flex-wrap: nowrap; + gap: 0.5rem; + padding: 0.5rem 1rem; + padding-bottom: 0; + background: transparent; +} +.entity-items-toolbar.has-items { + display: flex; +} + +.entity-items-filter { + all: unset; + display: block; + flex: 1 1 auto; + min-width: 80px; + width: auto; + height: auto; + padding: 0.2rem 0.5rem 0.2rem 1.5rem; + background: #ffffff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.35-4.35'/%3E%3C/svg%3E") no-repeat 0.375rem center; + background-size: 10px; + border: 1px solid #cbd5e1; + border-radius: 0.2rem; + font-size: 11px; + line-height: 1.4; + color: #212529; + box-sizing: border-box; + transition: all 0.15s ease-in-out; +} +.entity-items-filter::placeholder { + color: #6c757d; + font-size: 11px; +} +.entity-items-filter:focus { + outline: none; + border-color: #25b9d7; + box-shadow: 0 0 0 2px rgba(37, 185, 215, 0.1); +} + +.entity-items-sort { + all: unset; + flex: 0 0 auto; + padding: 0.2rem 1.25rem 0.2rem 0.5rem; + border: 1px solid #dee2e6; + border-radius: 0.2rem; + background: #ffffff 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.375rem center; + background-size: 8px; + font-size: 10px; + line-height: 1.4; + color: #495057; + cursor: pointer; + box-sizing: border-box; + white-space: nowrap; +} +.entity-items-sort:hover { + border-color: #25b9d7; +} +.entity-items-sort:focus { + outline: none; + border-color: #25b9d7; + box-shadow: 0 0 0 2px rgba(37, 185, 215, 0.1); +} + +.entity-items-count { + display: inline-flex; + align-items: center; + flex-shrink: 0; + gap: 0.125rem; + padding: 0.2rem 0.5rem; + background: #e2e8f0; + color: #495057; + font-size: 10px; + font-weight: 600; + border-radius: 0.2rem; + white-space: nowrap; + line-height: 1.4; +} +.entity-items-count.has-filter { + background: #cffafe; + color: #0e7490; +} + +.entity-items-clear { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.entity-items-clear:focus { + outline: none; +} +.entity-items-clear { + display: inline-flex; + align-items: center; + flex-shrink: 0; + gap: 0.25rem; + padding: 0.2rem 0.5rem; + color: #dc3545; + font-size: 10px; + font-weight: 500; + background: rgba(220, 53, 69, 0.1); + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; + white-space: nowrap; + line-height: 1.4; +} +.entity-items-clear:hover { + background: #dc3545; + color: #ffffff; +} +.entity-items-clear i { + font-size: 9px; + flex-shrink: 0; +} + +.entity-items-list { + display: flex; + flex-wrap: wrap; + gap: 0.25rem; + padding: 0.5rem 1rem 1rem; + min-height: 40px; + max-height: 300px; + overflow-y: auto; +} +.entity-items-list::-webkit-scrollbar { + width: 6px; + height: 6px; +} +.entity-items-list::-webkit-scrollbar-track { + background: #f8f9fa; + border-radius: 3px; +} +.entity-items-list::-webkit-scrollbar-thumb { + background: #dee2e6; + border-radius: 3px; +} +.entity-items-list::-webkit-scrollbar-thumb:hover { + background: #ced4da; +} +.entity-items-list:empty { + display: none; +} +.entity-items-list.list-layout { + flex-direction: column; + flex-wrap: nowrap; + gap: 0; + padding: 0.5rem; +} + +.entity-items-load-more { + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + padding: 0.5rem 1rem; + background: transparent; + border-top: 1px dashed #dee2e6; +} +.entity-items-load-more .load-more-label { + font-size: 0.75rem; + color: #6c757d; +} +.entity-items-load-more .load-more-select { + appearance: none; + padding: 0.25rem 1.75rem 0.25rem 0.5rem; + border: 1px solid #dee2e6; + border-radius: 0.2rem; + background: #ffffff 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; + background-size: 8px; + font-size: 0.75rem; + font-weight: 500; + color: #25b9d7; + cursor: pointer; + transition: all 0.15s ease-in-out; + height: auto; + min-height: 0; + line-height: 1.3; +} +.entity-items-load-more .load-more-select:hover { + border-color: #25b9d7; + background-color: rgba(37, 185, 215, 0.1); +} +.entity-items-load-more .load-more-select:focus { + outline: none; + border-color: #25b9d7; + box-shadow: 0 0 0 2px rgba(37, 185, 215, 0.1); +} +.entity-items-load-more .load-more-remaining { + font-size: 0.75rem; + color: #6c757d; +} +.entity-items-load-more .load-more-remaining .remaining-count { + font-weight: 600; + color: #495057; +} +.entity-items-load-more .btn-load-more { + display: flex; + align-items: center; + justify-content: center; + padding: 0.25rem; + margin: 0; + border: none; + color: #25b9d7; + background: rgba(37, 185, 215, 0.1); + border-radius: 0.2rem; + cursor: pointer; + transition: all 0.15s ease-in-out; + font: inherit; +} +.entity-items-load-more .btn-load-more i { + font-size: 14px; +} +.entity-items-load-more .btn-load-more:hover { + background: rgba(37, 185, 215, 0.2); +} +.entity-items-load-more .btn-load-more.loading { + cursor: wait; +} +.entity-items-load-more .btn-load-more.loading i { + animation: spin 0.6s linear infinite; +} + +.entity-items-empty { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 0.5rem; + padding: 2rem; + text-align: center; + color: #6c757d; +} +.entity-items-empty i { + font-size: 2rem; + opacity: 0.5; +} +.entity-items-empty p { + margin: 0; + font-size: 0.875rem; +} + +.entity-items-loading { + display: flex; + align-items: center; + justify-content: center; + padding: 2rem; + color: #6c757d; +} +.entity-items-loading i { + font-size: 20px; + animation: spin 0.6s linear infinite; +} + +/** + * Entity Selector Styles + * @package prestashop-entity-selector + * @version 2.0.0 + * + * Compiles to: assets/css/admin/entity-selector.css + */ +/** + * Search Dropdown Component + * Includes search input, filter panel, results grid + */ +.target-conditions-trait .target-search-wrapper, +.entity-selector-trait .target-search-wrapper { + position: relative; +} +.target-conditions-trait .target-search-dropdown, +.entity-selector-trait .target-search-dropdown { + position: absolute; + z-index: 1000; + background: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.3rem; + box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.175); + display: none; + width: 600px; + max-width: calc(100vw - 40px); +} +.target-conditions-trait .target-search-dropdown.show, +.entity-selector-trait .target-search-dropdown.show { + display: block; +} +.target-conditions-trait .dropdown-header, +.entity-selector-trait .dropdown-header { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 1rem; + background: #f8f9fa; + border-bottom: 1px solid #dee2e6; + border-radius: 0.3rem 0.3rem 0 0; +} +.target-conditions-trait .dropdown-search-input, +.entity-selector-trait .dropdown-search-input { + width: 100%; + padding: 0.5rem 1rem; + font-size: 0.875rem; + line-height: 1.5; + color: #212529; + background-color: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +.target-conditions-trait .dropdown-search-input:focus, +.entity-selector-trait .dropdown-search-input:focus { + border-color: #25b9d7; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(37, 185, 215, 0.25); +} +.target-conditions-trait .dropdown-search-input::placeholder, +.entity-selector-trait .dropdown-search-input::placeholder { + color: #adb5bd; +} +.target-conditions-trait .dropdown-search-input, +.entity-selector-trait .dropdown-search-input { + flex: 1; + padding: 0.5rem 1rem; +} +.target-conditions-trait .dropdown-close-btn, +.entity-selector-trait .dropdown-close-btn { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .dropdown-close-btn:focus, +.entity-selector-trait .dropdown-close-btn:focus { + outline: none; +} +.target-conditions-trait .dropdown-close-btn, +.entity-selector-trait .dropdown-close-btn { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + color: #6c757d; + border-radius: 0.25rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .dropdown-close-btn:hover, +.entity-selector-trait .dropdown-close-btn:hover { + background: #e2e8f0; + color: #495057; +} +.target-conditions-trait .dropdown-controls, +.entity-selector-trait .dropdown-controls { + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.5rem; + padding: 0.5rem 1rem; + background: #ffffff; + border-bottom: 1px solid #dee2e6; +} +.target-conditions-trait .dropdown-controls-left, +.target-conditions-trait .dropdown-controls-right, +.entity-selector-trait .dropdown-controls-left, +.entity-selector-trait .dropdown-controls-right { + display: flex; + align-items: center; + gap: 0.5rem; +} +.target-conditions-trait .view-mode-btn, +.entity-selector-trait .view-mode-btn { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .view-mode-btn:focus, +.entity-selector-trait .view-mode-btn:focus { + outline: none; +} +.target-conditions-trait .view-mode-btn, +.entity-selector-trait .view-mode-btn { + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + color: #6c757d; + background: transparent; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .view-mode-btn:hover, +.entity-selector-trait .view-mode-btn:hover { + background: #f1f5f9; + color: #495057; +} +.target-conditions-trait .view-mode-btn.active, +.entity-selector-trait .view-mode-btn.active { + background: #25b9d7; + color: #ffffff; +} +.target-conditions-trait .dropdown-results-count, +.entity-selector-trait .dropdown-results-count { + font-size: 0.75rem; + color: #6c757d; +} +.target-conditions-trait .dropdown-body, +.entity-selector-trait .dropdown-body { + max-height: 400px; + overflow-y: auto; +} +.target-conditions-trait .dropdown-body::-webkit-scrollbar, +.entity-selector-trait .dropdown-body::-webkit-scrollbar { + width: 6px; + height: 6px; +} +.target-conditions-trait .dropdown-body::-webkit-scrollbar-track, +.entity-selector-trait .dropdown-body::-webkit-scrollbar-track { + background: #f8f9fa; + border-radius: 3px; +} +.target-conditions-trait .dropdown-body::-webkit-scrollbar-thumb, +.entity-selector-trait .dropdown-body::-webkit-scrollbar-thumb { + background: #dee2e6; + border-radius: 3px; +} +.target-conditions-trait .dropdown-body::-webkit-scrollbar-thumb:hover, +.entity-selector-trait .dropdown-body::-webkit-scrollbar-thumb:hover { + background: #ced4da; +} +.target-conditions-trait .dropdown-results, +.entity-selector-trait .dropdown-results { + padding: 0 0.5rem; +} +.target-conditions-trait .results-count, +.entity-selector-trait .results-count { + font-size: 0.75rem; + color: #6c757d; + padding: 0.25rem 0.5rem; +} +.target-conditions-trait .results-header, +.entity-selector-trait .results-header { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.25rem 1rem; + background: #f1f5f9; + border-bottom: 1px solid #dee2e6; + font-size: 0.75rem; + font-weight: 600; + color: #495057; +} +.target-conditions-trait .dropdown-results-grid, +.entity-selector-trait .dropdown-results-grid { + display: grid; + gap: 0.5rem; +} +.target-conditions-trait .dropdown-results-grid.view-list, +.entity-selector-trait .dropdown-results-grid.view-list { + grid-template-columns: 1fr; +} +.target-conditions-trait .dropdown-results-grid.view-grid-2, +.entity-selector-trait .dropdown-results-grid.view-grid-2 { + grid-template-columns: repeat(2, 1fr); +} +.target-conditions-trait .dropdown-results-grid.view-grid-3, +.entity-selector-trait .dropdown-results-grid.view-grid-3 { + grid-template-columns: repeat(3, 1fr); +} +.target-conditions-trait .dropdown-result-item, +.entity-selector-trait .dropdown-result-item { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 0; + background: #ffffff; + border: none; + border-bottom: 1px solid #dee2e6; + border-radius: 0; + cursor: pointer; + transition: background 0.15s ease-in-out; +} +.target-conditions-trait .dropdown-result-item:last-child, +.entity-selector-trait .dropdown-result-item:last-child { + border-bottom: none; +} +.target-conditions-trait .dropdown-result-item:hover, +.entity-selector-trait .dropdown-result-item:hover { + background: #e9ecef; +} +.target-conditions-trait .dropdown-result-item.selected, +.entity-selector-trait .dropdown-result-item.selected { + background: rgba(37, 185, 215, 0.1); +} +.target-conditions-trait .dropdown-result-item.disabled, +.entity-selector-trait .dropdown-result-item.disabled { + opacity: 0.5; + cursor: not-allowed; +} +.target-conditions-trait .dropdown-result-item.disabled:hover, +.entity-selector-trait .dropdown-result-item.disabled:hover { + background: #ffffff; +} +.target-conditions-trait .result-item-image, +.target-conditions-trait .result-image, +.entity-selector-trait .result-item-image, +.entity-selector-trait .result-image { + flex-shrink: 0; + width: 40px; + height: 40px; + overflow: hidden; + border-radius: 0.2rem; + background: #f1f5f9; +} +.target-conditions-trait .result-item-image img, +.target-conditions-trait .result-image img, +.entity-selector-trait .result-item-image img, +.entity-selector-trait .result-image img { + width: 100%; + height: 100%; + object-fit: cover; +} +.target-conditions-trait .result-item-image.result-flag, +.target-conditions-trait .result-image.result-flag, +.entity-selector-trait .result-item-image.result-flag, +.entity-selector-trait .result-image.result-flag { + width: 32px; + height: 24px; + border-radius: 2px; + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1); + background: transparent; +} +.target-conditions-trait .result-item-image.result-flag img, +.target-conditions-trait .result-image.result-flag img, +.entity-selector-trait .result-item-image.result-flag img, +.entity-selector-trait .result-image.result-flag img { + object-fit: contain; +} +.target-conditions-trait .result-item-image.result-flag .flag-fallback, +.target-conditions-trait .result-image.result-flag .flag-fallback, +.entity-selector-trait .result-item-image.result-flag .flag-fallback, +.entity-selector-trait .result-image.result-flag .flag-fallback { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + background: linear-gradient(135deg, #e8eaed 0%, #dadce0 100%); + font-size: 14px; + color: #5f6368; +} +.target-conditions-trait .result-icon, +.entity-selector-trait .result-icon { + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + width: 40px; + height: 40px; + background: #f1f5f9; + border-radius: 0.2rem; + color: #6c757d; +} +.target-conditions-trait .result-icon i, +.entity-selector-trait .result-icon i { + font-size: 16px; +} +.target-conditions-trait .result-item-info, +.target-conditions-trait .result-info, +.entity-selector-trait .result-item-info, +.entity-selector-trait .result-info { + flex: 1; + min-width: 0; +} +.target-conditions-trait .result-item-name, +.target-conditions-trait .result-name, +.entity-selector-trait .result-item-name, +.entity-selector-trait .result-name { + font-size: 0.875rem; + font-weight: 500; + color: #212529; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.target-conditions-trait .result-item-meta, +.target-conditions-trait .result-subtitle, +.entity-selector-trait .result-item-meta, +.entity-selector-trait .result-subtitle { + font-size: 0.75rem; + color: #6c757d; +} +.target-conditions-trait .subtitle-line, +.entity-selector-trait .subtitle-line { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.target-conditions-trait .subtitle-line-primary, +.entity-selector-trait .subtitle-line-primary { + color: #495057; +} +.target-conditions-trait .subtitle-line-secondary, +.entity-selector-trait .subtitle-line-secondary { + color: #6c757d; + font-size: 11px; +} +.target-conditions-trait .result-col, +.entity-selector-trait .result-col { + flex-shrink: 0; + width: 70px; + text-align: right; + font-size: 0.75rem; +} +.target-conditions-trait .result-col-price, +.entity-selector-trait .result-col-price { + color: #495057; +} +.target-conditions-trait .result-col-sale, +.entity-selector-trait .result-col-sale { + color: #dc3545; + font-weight: 600; +} +.target-conditions-trait .result-col-stock .col-value.stock-ok, +.entity-selector-trait .result-col-stock .col-value.stock-ok { + color: #70b580; +} +.target-conditions-trait .result-col-stock .col-value.stock-low, +.entity-selector-trait .result-col-stock .col-value.stock-low { + color: #fab000; +} +.target-conditions-trait .result-col-stock .col-value.stock-out, +.entity-selector-trait .result-col-stock .col-value.stock-out { + color: #dc3545; +} +.target-conditions-trait .result-col-sales, +.entity-selector-trait .result-col-sales { + color: #6c757d; +} +.target-conditions-trait .col-value, +.entity-selector-trait .col-value { + display: block; +} +.target-conditions-trait .result-item-checkbox, +.target-conditions-trait .result-checkbox, +.entity-selector-trait .result-item-checkbox, +.entity-selector-trait .result-checkbox { + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + width: 18px; + height: 18px; + border: 2px solid #ced4da; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .result-item-checkbox i, +.target-conditions-trait .result-checkbox i, +.entity-selector-trait .result-item-checkbox i, +.entity-selector-trait .result-checkbox i { + display: none; + font-size: 10px; + color: #ffffff; +} +.dropdown-result-item.selected .target-conditions-trait .result-item-checkbox, .dropdown-item.selected .target-conditions-trait .result-item-checkbox, +.dropdown-result-item.selected .target-conditions-trait .result-checkbox, +.dropdown-item.selected .target-conditions-trait .result-checkbox, +.dropdown-result-item.selected .entity-selector-trait .result-item-checkbox, +.dropdown-item.selected .entity-selector-trait .result-item-checkbox, +.dropdown-result-item.selected .entity-selector-trait .result-checkbox, +.dropdown-item.selected .entity-selector-trait .result-checkbox { + background: #25b9d7; + border-color: #25b9d7; +} +.dropdown-result-item.selected .target-conditions-trait .result-item-checkbox i, .dropdown-item.selected .target-conditions-trait .result-item-checkbox i, +.dropdown-result-item.selected .target-conditions-trait .result-checkbox i, +.dropdown-item.selected .target-conditions-trait .result-checkbox i, +.dropdown-result-item.selected .entity-selector-trait .result-item-checkbox i, +.dropdown-item.selected .entity-selector-trait .result-item-checkbox i, +.dropdown-result-item.selected .entity-selector-trait .result-checkbox i, +.dropdown-item.selected .entity-selector-trait .result-checkbox i { + display: block; +} +.target-conditions-trait .result-item-product, +.entity-selector-trait .result-item-product { + display: flex; + align-items: center; + gap: 0.5rem; +} +.target-conditions-trait .no-results, +.entity-selector-trait .no-results { + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + padding: 2rem; + color: #6c757d; + font-size: 0.875rem; +} +.target-conditions-trait .no-results i, +.entity-selector-trait .no-results i { + font-size: 1.25rem; + opacity: 0.5; +} +.target-conditions-trait .dropdown-empty, +.entity-selector-trait .dropdown-empty { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 0.5rem; + padding: 2rem; + text-align: center; + color: #6c757d; +} +.target-conditions-trait .dropdown-empty i, +.entity-selector-trait .dropdown-empty i { + font-size: 2rem; + opacity: 0.5; +} +.target-conditions-trait .dropdown-empty p, +.entity-selector-trait .dropdown-empty p { + margin: 0; + font-size: 0.875rem; +} +.target-conditions-trait .dropdown-loading, +.entity-selector-trait .dropdown-loading { + display: flex; + align-items: center; + justify-content: center; + padding: 2rem; + color: #6c757d; +} +.target-conditions-trait .dropdown-loading i, +.entity-selector-trait .dropdown-loading i { + font-size: 1.5rem; + animation: spin 1s linear infinite; +} +.target-conditions-trait .dropdown-footer, +.entity-selector-trait .dropdown-footer { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; + padding: 0.5rem 1rem; + background: #f8fafc; + border-top: 1px solid #dee2e6; + border-radius: 0 0 0.3rem 0.3rem; +} +.target-conditions-trait .dropdown-footer-left, +.entity-selector-trait .dropdown-footer-left { + display: flex; + align-items: center; + gap: 0.25rem; + font-size: 0.75rem; + color: #6c757d; +} +.target-conditions-trait .dropdown-footer-left .load-label, +.entity-selector-trait .dropdown-footer-left .load-label { + color: #6c757d; +} +.target-conditions-trait .dropdown-footer-left .load-more-select, +.target-conditions-trait .dropdown-footer-left select.load-more-select, +.entity-selector-trait .dropdown-footer-left .load-more-select, +.entity-selector-trait .dropdown-footer-left select.load-more-select { + appearance: none; + padding: 0.25rem 1.5rem 0.25rem 0.5rem; + border: 1px solid #dee2e6; + border-radius: 0.2rem; + background: #ffffff 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.4rem center; + background-size: 8px; + font-size: 0.75rem; + color: #495057; + cursor: pointer; + min-width: 55px; +} +.target-conditions-trait .dropdown-footer-left .load-more-select:hover, +.target-conditions-trait .dropdown-footer-left select.load-more-select:hover, +.entity-selector-trait .dropdown-footer-left .load-more-select:hover, +.entity-selector-trait .dropdown-footer-left select.load-more-select:hover { + border-color: #25b9d7; +} +.target-conditions-trait .dropdown-footer-left .load-more-select:focus, +.target-conditions-trait .dropdown-footer-left select.load-more-select:focus, +.entity-selector-trait .dropdown-footer-left .load-more-select:focus, +.entity-selector-trait .dropdown-footer-left select.load-more-select:focus { + outline: none; + border-color: #25b9d7; +} +.target-conditions-trait .dropdown-footer-left .remaining-text, +.entity-selector-trait .dropdown-footer-left .remaining-text { + color: #6c757d; +} +.target-conditions-trait .dropdown-footer-left .remaining-text strong, +.entity-selector-trait .dropdown-footer-left .remaining-text strong { + color: #495057; + font-weight: 600; +} +.target-conditions-trait .dropdown-footer-left .btn-load-all, +.entity-selector-trait .dropdown-footer-left .btn-load-all { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .dropdown-footer-left .btn-load-all:focus, +.entity-selector-trait .dropdown-footer-left .btn-load-all:focus { + outline: none; +} +.target-conditions-trait .dropdown-footer-left .btn-load-all, +.entity-selector-trait .dropdown-footer-left .btn-load-all { + padding: 0.25rem 0.5rem; + font-size: 0.75rem; + color: #25b9d7; + background: transparent; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .dropdown-footer-left .btn-load-all:hover, +.entity-selector-trait .dropdown-footer-left .btn-load-all:hover { + background: rgba(37, 185, 215, 0.1); +} +.target-conditions-trait .dropdown-footer-right, +.entity-selector-trait .dropdown-footer-right { + display: flex; + align-items: center; + gap: 0.5rem; +} +.target-conditions-trait .dropdown-action-btn, +.entity-selector-trait .dropdown-action-btn { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .dropdown-action-btn:focus, +.entity-selector-trait .dropdown-action-btn:focus { + outline: none; +} +.target-conditions-trait .dropdown-action-btn, +.entity-selector-trait .dropdown-action-btn { + display: inline-flex; + align-items: center; + gap: 0.375rem; + padding: 0.375rem 0.75rem; + font-size: 0.75rem; + font-weight: 500; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .dropdown-action-btn .btn-shortcut, +.entity-selector-trait .dropdown-action-btn .btn-shortcut { + font-size: 10px; + padding: 0.125rem 0.25rem; + background: rgba(0, 0, 0, 0.08); + border-radius: 3px; + font-weight: 400; +} +.target-conditions-trait .dropdown-action-btn.btn-cancel, +.entity-selector-trait .dropdown-action-btn.btn-cancel { + color: #495057; + background: #ffffff; + border: 1px solid #dee2e6; +} +.target-conditions-trait .dropdown-action-btn.btn-cancel:hover, +.entity-selector-trait .dropdown-action-btn.btn-cancel:hover { + background: #f1f5f9; + border-color: #ced4da; +} +.target-conditions-trait .dropdown-action-btn.btn-apply, .target-conditions-trait .dropdown-action-btn.btn-save, +.entity-selector-trait .dropdown-action-btn.btn-apply, +.entity-selector-trait .dropdown-action-btn.btn-save { + color: #ffffff; + background: #25b9d7; + border: 1px solid #25b9d7; +} +.target-conditions-trait .dropdown-action-btn.btn-apply:hover, .target-conditions-trait .dropdown-action-btn.btn-save:hover, +.entity-selector-trait .dropdown-action-btn.btn-apply:hover, +.entity-selector-trait .dropdown-action-btn.btn-save:hover { + background: #1a9ab7; + border-color: #1a9ab7; +} +.target-conditions-trait .dropdown-action-btn.btn-apply .btn-shortcut, .target-conditions-trait .dropdown-action-btn.btn-save .btn-shortcut, +.entity-selector-trait .dropdown-action-btn.btn-apply .btn-shortcut, +.entity-selector-trait .dropdown-action-btn.btn-save .btn-shortcut { + background: rgba(255, 255, 255, 0.2); +} +.target-conditions-trait .dropdown-load-more, +.entity-selector-trait .dropdown-load-more { + display: none; +} +.target-conditions-trait .load-more-controls, +.entity-selector-trait .load-more-controls { + display: none; +} +.target-conditions-trait .dropdown-filter-panel, +.entity-selector-trait .dropdown-filter-panel { + padding: 1rem; + background: #f8fafc; + border-bottom: 1px solid #dee2e6; +} +.target-conditions-trait .filter-panel-header, +.entity-selector-trait .filter-panel-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 0.5rem; +} +.target-conditions-trait .filter-panel-title, +.entity-selector-trait .filter-panel-title { + font-size: 0.875rem; + font-weight: 600; + color: #212529; +} +.target-conditions-trait .filter-panel-toggle, +.entity-selector-trait .filter-panel-toggle { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .filter-panel-toggle:focus, +.entity-selector-trait .filter-panel-toggle:focus { + outline: none; +} +.target-conditions-trait .filter-panel-toggle, +.entity-selector-trait .filter-panel-toggle { + font-size: 0.75rem; + color: #25b9d7; +} +.target-conditions-trait .filter-panel-toggle:hover, +.entity-selector-trait .filter-panel-toggle:hover { + text-decoration: underline; +} +.target-conditions-trait .filter-panel-content, +.entity-selector-trait .filter-panel-content { + display: grid; + gap: 0.5rem; + grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); +} +.target-conditions-trait .filter-group, +.entity-selector-trait .filter-group { + display: flex; + flex-direction: column; + gap: 0.25rem; +} +.target-conditions-trait .filter-label, +.entity-selector-trait .filter-label { + font-size: 0.75rem; + font-weight: 500; + color: #495057; +} +.target-conditions-trait .filter-select, +.target-conditions-trait .filter-input, +.entity-selector-trait .filter-select, +.entity-selector-trait .filter-input { + width: 100%; + padding: 0.5rem 1rem; + font-size: 0.875rem; + line-height: 1.5; + color: #212529; + background-color: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +.target-conditions-trait .filter-select:focus, +.target-conditions-trait .filter-input:focus, +.entity-selector-trait .filter-select:focus, +.entity-selector-trait .filter-input:focus { + border-color: #25b9d7; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(37, 185, 215, 0.25); +} +.target-conditions-trait .filter-select::placeholder, +.target-conditions-trait .filter-input::placeholder, +.entity-selector-trait .filter-select::placeholder, +.entity-selector-trait .filter-input::placeholder { + color: #adb5bd; +} +.target-conditions-trait .filter-select, +.target-conditions-trait .filter-input, +.entity-selector-trait .filter-select, +.entity-selector-trait .filter-input { + padding: 0.375rem 0.5rem; + font-size: 0.75rem; +} + +.target-conditions-trait .category-tree, +.entity-selector-trait .category-tree { + padding: 0.5rem; +} +.target-conditions-trait .tree-loading, +.entity-selector-trait .tree-loading { + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + padding: 2rem; + color: #6c757d; + font-size: 0.875rem; +} +.target-conditions-trait .tree-loading i, +.entity-selector-trait .tree-loading i { + animation: spin 0.6s linear infinite; +} +.target-conditions-trait .tree-item, +.entity-selector-trait .tree-item { + display: flex; + align-items: center; + gap: 0.25rem; + padding: 0.375rem 0.5rem; + border-radius: 0.2rem; + cursor: pointer; + transition: background-color 0.15s ease-in-out; +} +.target-conditions-trait .tree-item:hover, +.entity-selector-trait .tree-item:hover { + background: #e9ecef; +} +.target-conditions-trait .tree-item.selected, +.entity-selector-trait .tree-item.selected { + background: rgba(37, 185, 215, 0.1); +} +.target-conditions-trait .tree-item.selected .tree-checkbox, +.entity-selector-trait .tree-item.selected .tree-checkbox { + background: #25b9d7; + border-color: #25b9d7; +} +.target-conditions-trait .tree-item.selected .tree-checkbox i, +.entity-selector-trait .tree-item.selected .tree-checkbox i { + display: block; +} +.target-conditions-trait .tree-info, +.entity-selector-trait .tree-info { + display: flex; + align-items: center; + gap: 0.25rem; + flex: 1; + min-width: 0; +} +.target-conditions-trait .tree-name, +.entity-selector-trait .tree-name { + font-size: 0.875rem; + color: #212529; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.target-conditions-trait .tree-subtitle, +.entity-selector-trait .tree-subtitle { + font-size: 0.75rem; + color: #6c757d; +} +.target-conditions-trait .category-tree-item, +.entity-selector-trait .category-tree-item { + padding: 0.25rem 0; +} +.target-conditions-trait .category-tree-node, +.entity-selector-trait .category-tree-node { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.25rem 0.5rem; + border-radius: 0.2rem; + cursor: pointer; + transition: background-color 0.15s ease-in-out; +} +.target-conditions-trait .category-tree-node:hover, +.entity-selector-trait .category-tree-node:hover { + background: #e9ecef; +} +.target-conditions-trait .category-tree-node.selected, +.entity-selector-trait .category-tree-node.selected { + background: rgba(37, 185, 215, 0.1); +} +.target-conditions-trait .category-tree-toggle, +.entity-selector-trait .category-tree-toggle { + display: flex; + align-items: center; + justify-content: center; + width: 16px; + height: 16px; + color: #6c757d; + transition: transform 0.15s ease-in-out; +} +.target-conditions-trait .category-tree-toggle.expanded, +.entity-selector-trait .category-tree-toggle.expanded { + transform: rotate(90deg); +} +.target-conditions-trait .category-tree-toggle.empty, +.entity-selector-trait .category-tree-toggle.empty { + visibility: hidden; +} +.target-conditions-trait .category-tree-checkbox, +.entity-selector-trait .category-tree-checkbox { + flex-shrink: 0; + width: 16px; + height: 16px; + border: 2px solid #ced4da; + border-radius: 3px; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .category-tree-checkbox.checked, +.entity-selector-trait .category-tree-checkbox.checked { + background: #25b9d7; + border-color: #25b9d7; +} +.target-conditions-trait .category-tree-checkbox.checked::after, +.entity-selector-trait .category-tree-checkbox.checked::after { + content: "✓"; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + color: #ffffff; + font-size: 10px; +} +.target-conditions-trait .category-tree-checkbox.indeterminate, +.entity-selector-trait .category-tree-checkbox.indeterminate { + background: #25b9d7; + border-color: #25b9d7; +} +.target-conditions-trait .category-tree-checkbox.indeterminate::after, +.entity-selector-trait .category-tree-checkbox.indeterminate::after { + content: "−"; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + color: #ffffff; + font-size: 10px; +} +.target-conditions-trait .category-tree-name, +.entity-selector-trait .category-tree-name { + flex: 1; + font-size: 0.875rem; + color: #212529; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.target-conditions-trait .category-tree-count, +.entity-selector-trait .category-tree-count { + font-size: 0.75rem; + color: #6c757d; +} +.target-conditions-trait .category-tree-children, +.entity-selector-trait .category-tree-children { + margin-left: 24px; +} +.target-conditions-trait .search-history-list, +.entity-selector-trait .search-history-list { + padding: 0.5rem; +} +.target-conditions-trait .history-item, +.entity-selector-trait .history-item { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem; + border-radius: 0.2rem; + cursor: pointer; + transition: background-color 0.15s ease-in-out; +} +.target-conditions-trait .history-item:hover, +.entity-selector-trait .history-item:hover { + background: #e9ecef; +} +.target-conditions-trait .history-item > i, +.entity-selector-trait .history-item > i { + color: #6c757d; + font-size: 14px; +} +.target-conditions-trait .history-query, +.entity-selector-trait .history-query { + flex: 1; + font-size: 0.875rem; + color: #212529; +} +.target-conditions-trait .btn-delete-history, +.entity-selector-trait .btn-delete-history { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .btn-delete-history:focus, +.entity-selector-trait .btn-delete-history:focus { + outline: none; +} +.target-conditions-trait .btn-delete-history, +.entity-selector-trait .btn-delete-history { + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + color: #6c757d; + border-radius: 0.2rem; + opacity: 0; + transition: all 0.15s ease-in-out; +} +.history-item:hover .target-conditions-trait .btn-delete-history, +.history-item:hover .entity-selector-trait .btn-delete-history { + opacity: 1; +} +.target-conditions-trait .btn-delete-history:hover, +.entity-selector-trait .btn-delete-history:hover { + background: #f8d7da; + color: #dc3545; +} +.target-conditions-trait .btn-delete-history i, +.entity-selector-trait .btn-delete-history i { + font-size: 12px; +} +.target-conditions-trait .filter-panel, +.entity-selector-trait .filter-panel { + display: none; + padding: 1rem; + background: #f8fafc; + border-bottom: 1px solid #dee2e6; +} +.target-conditions-trait .filter-panel.show, +.entity-selector-trait .filter-panel.show { + display: block; +} +.target-conditions-trait .filter-row, +.entity-selector-trait .filter-row { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 0.5rem; + margin-bottom: 0.5rem; +} +.target-conditions-trait .filter-row:last-child, +.entity-selector-trait .filter-row:last-child { + margin-bottom: 0; +} +.target-conditions-trait .view-mode-select, +.entity-selector-trait .view-mode-select { + width: 100%; + padding: 0.5rem 1rem; + font-size: 0.875rem; + line-height: 1.5; + color: #212529; + background-color: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +.target-conditions-trait .view-mode-select:focus, +.entity-selector-trait .view-mode-select:focus { + border-color: #25b9d7; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(37, 185, 215, 0.25); +} +.target-conditions-trait .view-mode-select::placeholder, +.entity-selector-trait .view-mode-select::placeholder { + color: #adb5bd; +} +.target-conditions-trait .view-mode-select, +.entity-selector-trait .view-mode-select { + padding: 0.25rem 0.5rem; + font-size: 0.75rem; + min-width: 80px; +} + +body > .target-search-dropdown, +.target-search-dropdown { + position: absolute; + z-index: 1000; + background: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.3rem; + box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.175); + display: none; + width: 600px; + max-width: calc(100vw - 40px); +} +body > .target-search-dropdown.show, +.target-search-dropdown.show { + display: block; +} +body > .target-search-dropdown .dropdown-header, +.target-search-dropdown .dropdown-header { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 1rem; + background: #f8f9fa; + border-bottom: 1px solid #dee2e6; + border-radius: 0.3rem 0.3rem 0 0; + flex-wrap: wrap; +} +body > .target-search-dropdown .results-count, +.target-search-dropdown .results-count { + font-size: 0.875rem; + font-weight: 600; + color: #212529; + white-space: nowrap; +} +body > .target-search-dropdown .dropdown-actions, +.target-search-dropdown .dropdown-actions { + display: flex; + align-items: center; + gap: 0.25rem; + flex-wrap: wrap; + flex: 1; + justify-content: flex-end; +} +body > .target-search-dropdown .btn-select-all, +body > .target-search-dropdown .btn-clear-selection, +.target-search-dropdown .btn-select-all, +.target-search-dropdown .btn-clear-selection { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +body > .target-search-dropdown .btn-select-all:focus, +body > .target-search-dropdown .btn-clear-selection:focus, +.target-search-dropdown .btn-select-all:focus, +.target-search-dropdown .btn-clear-selection:focus { + outline: none; +} +body > .target-search-dropdown .btn-select-all, +body > .target-search-dropdown .btn-clear-selection, +.target-search-dropdown .btn-select-all, +.target-search-dropdown .btn-clear-selection { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + font-size: 0.75rem; + color: #495057; + background: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.2rem; + cursor: pointer; + transition: all 0.15s ease-in-out; +} +body > .target-search-dropdown .btn-select-all:hover, +body > .target-search-dropdown .btn-clear-selection:hover, +.target-search-dropdown .btn-select-all:hover, +.target-search-dropdown .btn-clear-selection:hover { + background: #e9ecef; + border-color: #cbd5e1; +} +body > .target-search-dropdown .btn-select-all kbd, +body > .target-search-dropdown .btn-clear-selection kbd, +.target-search-dropdown .btn-select-all kbd, +.target-search-dropdown .btn-clear-selection kbd { + font-size: 0.65rem; + padding: 0.125rem 0.25rem; + background: #f1f5f9; + border-radius: 2px; + color: #6c757d; +} +body > .target-search-dropdown .sort-controls, +.target-search-dropdown .sort-controls { + display: flex; + align-items: center; +} +body > .target-search-dropdown .sort-field-select, +.target-search-dropdown .sort-field-select { + width: 100%; + padding: 0.5rem 1rem; + font-size: 0.875rem; + line-height: 1.5; + color: #212529; + background-color: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +body > .target-search-dropdown .sort-field-select:focus, +.target-search-dropdown .sort-field-select:focus { + border-color: #25b9d7; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(37, 185, 215, 0.25); +} +body > .target-search-dropdown .sort-field-select::placeholder, +.target-search-dropdown .sort-field-select::placeholder { + color: #adb5bd; +} +body > .target-search-dropdown .sort-field-select, +.target-search-dropdown .sort-field-select { + padding: 0.25rem 0.5rem; + font-size: 0.75rem; + min-width: 80px; + height: 28px; + border-radius: 0.2rem 0 0 0.2rem; + border-right: none; +} +body > .target-search-dropdown .btn-sort-dir, +.target-search-dropdown .btn-sort-dir { + display: flex; + align-items: center; + justify-content: center; + width: 38px; + min-width: 38px; + flex-shrink: 0; + height: 28px; + padding: 0; + margin: 0; + color: #6c757d; + background: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0 0.2rem 0.2rem 0; + cursor: pointer; + transition: all 0.15s ease-in-out; +} +body > .target-search-dropdown .btn-sort-dir i, +.target-search-dropdown .btn-sort-dir i { + font-size: 14px; +} +body > .target-search-dropdown .btn-sort-dir:hover, +.target-search-dropdown .btn-sort-dir:hover { + background: #e9ecef; + color: #212529; +} +body > .target-search-dropdown .btn-sort-dir.active, +.target-search-dropdown .btn-sort-dir.active { + background: rgba(37, 185, 215, 0.1); + border-color: #25b9d7; + color: #25b9d7; +} +body > .target-search-dropdown .view-mode-select, +.target-search-dropdown .view-mode-select { + width: 100%; + padding: 0.5rem 1rem; + font-size: 0.875rem; + line-height: 1.5; + color: #212529; + background-color: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +body > .target-search-dropdown .view-mode-select:focus, +.target-search-dropdown .view-mode-select:focus { + border-color: #25b9d7; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(37, 185, 215, 0.25); +} +body > .target-search-dropdown .view-mode-select::placeholder, +.target-search-dropdown .view-mode-select::placeholder { + color: #adb5bd; +} +body > .target-search-dropdown .view-mode-select, +.target-search-dropdown .view-mode-select { + padding: 0.25rem 0.5rem; + font-size: 0.75rem; + min-width: 80px; + margin-left: 0.25rem; +} +body > .target-search-dropdown .btn-toggle-filters, +body > .target-search-dropdown .btn-show-history, +.target-search-dropdown .btn-toggle-filters, +.target-search-dropdown .btn-show-history { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + min-width: 32px; + flex-shrink: 0; + height: 28px; + padding: 0; + margin: 0; + color: #6c757d; + background: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.2rem; + cursor: pointer; + transition: all 0.15s ease-in-out; +} +body > .target-search-dropdown .btn-toggle-filters i, +body > .target-search-dropdown .btn-show-history i, +.target-search-dropdown .btn-toggle-filters i, +.target-search-dropdown .btn-show-history i { + font-size: 14px; +} +body > .target-search-dropdown .btn-toggle-filters:hover, +body > .target-search-dropdown .btn-show-history:hover, +.target-search-dropdown .btn-toggle-filters:hover, +.target-search-dropdown .btn-show-history:hover { + background: #e9ecef; + color: #212529; +} +body > .target-search-dropdown .btn-toggle-filters.active, +body > .target-search-dropdown .btn-show-history.active, +.target-search-dropdown .btn-toggle-filters.active, +.target-search-dropdown .btn-show-history.active { + background: rgba(37, 185, 215, 0.1); + border-color: #25b9d7; + color: #25b9d7; +} +body > .target-search-dropdown .refine-compact, +.target-search-dropdown .refine-compact { + display: flex; + align-items: center; +} +body > .target-search-dropdown .refine-compact .btn-refine-negate, +.target-search-dropdown .refine-compact .btn-refine-negate { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + min-width: 32px; + flex-shrink: 0; + height: 28px; + padding: 0; + margin: 0; + color: #6c757d; + background: #ffffff; + border: 1px solid #dee2e6; + border-right: none; + border-radius: 0.2rem 0 0 0.2rem; + cursor: pointer; + transition: all 0.15s ease-in-out; +} +body > .target-search-dropdown .refine-compact .btn-refine-negate:hover, +.target-search-dropdown .refine-compact .btn-refine-negate:hover { + background: #e9ecef; + color: #212529; +} +body > .target-search-dropdown .refine-compact .btn-refine-negate.active, +.target-search-dropdown .refine-compact .btn-refine-negate.active { + background: #f8d7da; + color: #dc3545; + border-color: #dc3545; +} +body > .target-search-dropdown .refine-compact .refine-input, +.target-search-dropdown .refine-compact .refine-input { + width: 100%; + padding: 0.5rem 1rem; + font-size: 0.875rem; + line-height: 1.5; + color: #212529; + background-color: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +body > .target-search-dropdown .refine-compact .refine-input:focus, +.target-search-dropdown .refine-compact .refine-input:focus { + border-color: #25b9d7; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(37, 185, 215, 0.25); +} +body > .target-search-dropdown .refine-compact .refine-input::placeholder, +.target-search-dropdown .refine-compact .refine-input::placeholder { + color: #adb5bd; +} +body > .target-search-dropdown .refine-compact .refine-input, +.target-search-dropdown .refine-compact .refine-input { + width: 100px; + padding: 0.25rem 0.5rem; + font-size: 0.75rem; + border-radius: 0 0.2rem 0.2rem 0; +} +body > .target-search-dropdown .refine-compact .btn-clear-refine, +.target-search-dropdown .refine-compact .btn-clear-refine { + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + padding: 0; + margin: 0; + margin-left: -1px; + color: #6c757d; + background: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0 0.2rem 0.2rem 0; + cursor: pointer; + transition: all 0.15s ease-in-out; +} +body > .target-search-dropdown .refine-compact .btn-clear-refine:hover, +.target-search-dropdown .refine-compact .btn-clear-refine:hover { + background: #e9ecef; + color: #212529; +} +body > .target-search-dropdown .filter-panel, +.target-search-dropdown .filter-panel { + display: none; + padding: 1rem; + background: #f8fafc; + border-bottom: 1px solid #dee2e6; +} +body > .target-search-dropdown .filter-panel.show, +.target-search-dropdown .filter-panel.show { + display: block; +} +body > .target-search-dropdown .filter-row, +.target-search-dropdown .filter-row { + display: flex; + align-items: center; + gap: 0.5rem; + flex-wrap: wrap; + margin-bottom: 0.5rem; +} +body > .target-search-dropdown .filter-row:last-child, +.target-search-dropdown .filter-row:last-child { + margin-bottom: 0; +} +body > .target-search-dropdown .filter-label, +.target-search-dropdown .filter-label { + display: inline-flex; + align-items: center; + gap: 0.25rem; + font-size: 0.75rem; + color: #495057; + cursor: pointer; +} +body > .target-search-dropdown .filter-label input[type=checkbox], +.target-search-dropdown .filter-label input[type=checkbox] { + margin: 0; +} +body > .target-search-dropdown .filter-price-range, +.target-search-dropdown .filter-price-range { + display: flex; + align-items: center; + gap: 0.25rem; +} +body > .target-search-dropdown .filter-price-range .filter-price-label, +.target-search-dropdown .filter-price-range .filter-price-label { + font-size: 0.75rem; + color: #6c757d; +} +body > .target-search-dropdown .filter-price-range .filter-price-min, +body > .target-search-dropdown .filter-price-range .filter-price-max, +.target-search-dropdown .filter-price-range .filter-price-min, +.target-search-dropdown .filter-price-range .filter-price-max { + width: 100%; + padding: 0.5rem 1rem; + font-size: 0.875rem; + line-height: 1.5; + color: #212529; + background-color: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +body > .target-search-dropdown .filter-price-range .filter-price-min:focus, +body > .target-search-dropdown .filter-price-range .filter-price-max:focus, +.target-search-dropdown .filter-price-range .filter-price-min:focus, +.target-search-dropdown .filter-price-range .filter-price-max:focus { + border-color: #25b9d7; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(37, 185, 215, 0.25); +} +body > .target-search-dropdown .filter-price-range .filter-price-min::placeholder, +body > .target-search-dropdown .filter-price-range .filter-price-max::placeholder, +.target-search-dropdown .filter-price-range .filter-price-min::placeholder, +.target-search-dropdown .filter-price-range .filter-price-max::placeholder { + color: #adb5bd; +} +body > .target-search-dropdown .filter-price-range .filter-price-min, +body > .target-search-dropdown .filter-price-range .filter-price-max, +.target-search-dropdown .filter-price-range .filter-price-min, +.target-search-dropdown .filter-price-range .filter-price-max { + width: 70px; + padding: 0.25rem 0.5rem; + font-size: 0.75rem; +} +body > .target-search-dropdown .filter-price-range .filter-price-sep, +.target-search-dropdown .filter-price-range .filter-price-sep { + color: #6c757d; +} +body > .target-search-dropdown .btn-clear-filters, +.target-search-dropdown .btn-clear-filters { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +body > .target-search-dropdown .btn-clear-filters:focus, +.target-search-dropdown .btn-clear-filters:focus { + outline: none; +} +body > .target-search-dropdown .btn-clear-filters, +.target-search-dropdown .btn-clear-filters { + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + color: #6c757d; + border-radius: 0.2rem; + cursor: pointer; + margin-left: auto; +} +body > .target-search-dropdown .btn-clear-filters:hover, +.target-search-dropdown .btn-clear-filters:hover { + background: #e2e8f0; + color: #212529; +} +body > .target-search-dropdown .filter-row-multi, +.target-search-dropdown .filter-row-multi { + flex-direction: column; + align-items: stretch; + gap: 0.5rem; +} +body > .target-search-dropdown .filter-subrow, +.target-search-dropdown .filter-subrow { + display: flex; + align-items: center; + gap: 0.5rem; + flex-wrap: wrap; +} +body > .target-search-dropdown .filter-range-group, +body > .target-search-dropdown .filter-date-group, +body > .target-search-dropdown .filter-select-group, +.target-search-dropdown .filter-range-group, +.target-search-dropdown .filter-date-group, +.target-search-dropdown .filter-select-group { + display: flex; + align-items: center; + gap: 0.25rem; +} +body > .target-search-dropdown .filter-range-label, +body > .target-search-dropdown .filter-date-label, +body > .target-search-dropdown .filter-select-label, +body > .target-search-dropdown .filter-row-label, +.target-search-dropdown .filter-range-label, +.target-search-dropdown .filter-date-label, +.target-search-dropdown .filter-select-label, +.target-search-dropdown .filter-row-label { + font-size: 0.75rem; + color: #6c757d; + white-space: nowrap; +} +body > .target-search-dropdown .filter-range-label i, +body > .target-search-dropdown .filter-date-label i, +body > .target-search-dropdown .filter-select-label i, +body > .target-search-dropdown .filter-row-label i, +.target-search-dropdown .filter-range-label i, +.target-search-dropdown .filter-date-label i, +.target-search-dropdown .filter-select-label i, +.target-search-dropdown .filter-row-label i { + margin-right: 0.25rem; +} +body > .target-search-dropdown .filter-range-sep, +.target-search-dropdown .filter-range-sep { + color: #6c757d; +} +body > .target-search-dropdown .filter-product-count-min, +body > .target-search-dropdown .filter-product-count-max, +body > .target-search-dropdown .filter-sales-min, +body > .target-search-dropdown .filter-sales-max, +body > .target-search-dropdown .filter-turnover-min, +body > .target-search-dropdown .filter-turnover-max, +body > .target-search-dropdown .filter-date-add-from, +body > .target-search-dropdown .filter-date-add-to, +body > .target-search-dropdown .filter-last-product-from, +body > .target-search-dropdown .filter-last-product-to, +.target-search-dropdown .filter-product-count-min, +.target-search-dropdown .filter-product-count-max, +.target-search-dropdown .filter-sales-min, +.target-search-dropdown .filter-sales-max, +.target-search-dropdown .filter-turnover-min, +.target-search-dropdown .filter-turnover-max, +.target-search-dropdown .filter-date-add-from, +.target-search-dropdown .filter-date-add-to, +.target-search-dropdown .filter-last-product-from, +.target-search-dropdown .filter-last-product-to { + width: 100%; + padding: 0.5rem 1rem; + font-size: 0.875rem; + line-height: 1.5; + color: #212529; + background-color: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +body > .target-search-dropdown .filter-product-count-min:focus, +body > .target-search-dropdown .filter-product-count-max:focus, +body > .target-search-dropdown .filter-sales-min:focus, +body > .target-search-dropdown .filter-sales-max:focus, +body > .target-search-dropdown .filter-turnover-min:focus, +body > .target-search-dropdown .filter-turnover-max:focus, +body > .target-search-dropdown .filter-date-add-from:focus, +body > .target-search-dropdown .filter-date-add-to:focus, +body > .target-search-dropdown .filter-last-product-from:focus, +body > .target-search-dropdown .filter-last-product-to:focus, +.target-search-dropdown .filter-product-count-min:focus, +.target-search-dropdown .filter-product-count-max:focus, +.target-search-dropdown .filter-sales-min:focus, +.target-search-dropdown .filter-sales-max:focus, +.target-search-dropdown .filter-turnover-min:focus, +.target-search-dropdown .filter-turnover-max:focus, +.target-search-dropdown .filter-date-add-from:focus, +.target-search-dropdown .filter-date-add-to:focus, +.target-search-dropdown .filter-last-product-from:focus, +.target-search-dropdown .filter-last-product-to:focus { + border-color: #25b9d7; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(37, 185, 215, 0.25); +} +body > .target-search-dropdown .filter-product-count-min::placeholder, +body > .target-search-dropdown .filter-product-count-max::placeholder, +body > .target-search-dropdown .filter-sales-min::placeholder, +body > .target-search-dropdown .filter-sales-max::placeholder, +body > .target-search-dropdown .filter-turnover-min::placeholder, +body > .target-search-dropdown .filter-turnover-max::placeholder, +body > .target-search-dropdown .filter-date-add-from::placeholder, +body > .target-search-dropdown .filter-date-add-to::placeholder, +body > .target-search-dropdown .filter-last-product-from::placeholder, +body > .target-search-dropdown .filter-last-product-to::placeholder, +.target-search-dropdown .filter-product-count-min::placeholder, +.target-search-dropdown .filter-product-count-max::placeholder, +.target-search-dropdown .filter-sales-min::placeholder, +.target-search-dropdown .filter-sales-max::placeholder, +.target-search-dropdown .filter-turnover-min::placeholder, +.target-search-dropdown .filter-turnover-max::placeholder, +.target-search-dropdown .filter-date-add-from::placeholder, +.target-search-dropdown .filter-date-add-to::placeholder, +.target-search-dropdown .filter-last-product-from::placeholder, +.target-search-dropdown .filter-last-product-to::placeholder { + color: #adb5bd; +} +body > .target-search-dropdown .filter-product-count-min, +body > .target-search-dropdown .filter-product-count-max, +body > .target-search-dropdown .filter-sales-min, +body > .target-search-dropdown .filter-sales-max, +body > .target-search-dropdown .filter-turnover-min, +body > .target-search-dropdown .filter-turnover-max, +body > .target-search-dropdown .filter-date-add-from, +body > .target-search-dropdown .filter-date-add-to, +body > .target-search-dropdown .filter-last-product-from, +body > .target-search-dropdown .filter-last-product-to, +.target-search-dropdown .filter-product-count-min, +.target-search-dropdown .filter-product-count-max, +.target-search-dropdown .filter-sales-min, +.target-search-dropdown .filter-sales-max, +.target-search-dropdown .filter-turnover-min, +.target-search-dropdown .filter-turnover-max, +.target-search-dropdown .filter-date-add-from, +.target-search-dropdown .filter-date-add-to, +.target-search-dropdown .filter-last-product-from, +.target-search-dropdown .filter-last-product-to { + width: 70px; + padding: 0.25rem 0.5rem; + font-size: 0.75rem; +} +body > .target-search-dropdown .filter-depth-select, +body > .target-search-dropdown .filter-attribute-group-select, +body > .target-search-dropdown .filter-feature-group-select, +.target-search-dropdown .filter-depth-select, +.target-search-dropdown .filter-attribute-group-select, +.target-search-dropdown .filter-feature-group-select { + width: 100%; + padding: 0.5rem 1rem; + font-size: 0.875rem; + line-height: 1.5; + color: #212529; + background-color: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +body > .target-search-dropdown .filter-depth-select:focus, +body > .target-search-dropdown .filter-attribute-group-select:focus, +body > .target-search-dropdown .filter-feature-group-select:focus, +.target-search-dropdown .filter-depth-select:focus, +.target-search-dropdown .filter-attribute-group-select:focus, +.target-search-dropdown .filter-feature-group-select:focus { + border-color: #25b9d7; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(37, 185, 215, 0.25); +} +body > .target-search-dropdown .filter-depth-select::placeholder, +body > .target-search-dropdown .filter-attribute-group-select::placeholder, +body > .target-search-dropdown .filter-feature-group-select::placeholder, +.target-search-dropdown .filter-depth-select::placeholder, +.target-search-dropdown .filter-attribute-group-select::placeholder, +.target-search-dropdown .filter-feature-group-select::placeholder { + color: #adb5bd; +} +body > .target-search-dropdown .filter-depth-select, +body > .target-search-dropdown .filter-attribute-group-select, +body > .target-search-dropdown .filter-feature-group-select, +.target-search-dropdown .filter-depth-select, +.target-search-dropdown .filter-attribute-group-select, +.target-search-dropdown .filter-feature-group-select { + padding: 0.25rem 0.5rem; + font-size: 0.75rem; + min-width: 100px; +} +body > .target-search-dropdown .filter-attributes-container, +body > .target-search-dropdown .filter-features-container, +body > .target-search-dropdown .filter-values-container, +.target-search-dropdown .filter-attributes-container, +.target-search-dropdown .filter-features-container, +.target-search-dropdown .filter-values-container { + display: flex; + flex-wrap: wrap; + gap: 0.25rem; +} +body > .target-search-dropdown .filter-group-toggle, +.target-search-dropdown .filter-group-toggle { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +body > .target-search-dropdown .filter-group-toggle:focus, +.target-search-dropdown .filter-group-toggle:focus { + outline: none; +} +body > .target-search-dropdown .filter-group-toggle, +.target-search-dropdown .filter-group-toggle { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + font-size: 0.75rem; + color: #495057; + background: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.2rem; + cursor: pointer; + transition: all 0.15s ease-in-out; +} +body > .target-search-dropdown .filter-group-toggle:hover, +.target-search-dropdown .filter-group-toggle:hover { + background: #e9ecef; + border-color: #cbd5e1; +} +body > .target-search-dropdown .filter-group-toggle.active, +.target-search-dropdown .filter-group-toggle.active { + background: rgba(37, 185, 215, 0.1); + border-color: #25b9d7; + color: #25b9d7; +} +body > .target-search-dropdown .filter-group-toggle.active .toggle-count, +.target-search-dropdown .filter-group-toggle.active .toggle-count { + color: #25b9d7; +} +body > .target-search-dropdown .filter-group-toggle.has-selection, +.target-search-dropdown .filter-group-toggle.has-selection { + border-color: #70b580; + background: rgba(112, 181, 128, 0.05); +} +body > .target-search-dropdown .filter-group-toggle.has-selection .toggle-count, +.target-search-dropdown .filter-group-toggle.has-selection .toggle-count { + color: #70b580; + font-weight: 600; +} +body > .target-search-dropdown .filter-group-toggle .toggle-name, +.target-search-dropdown .filter-group-toggle .toggle-name { + font-weight: 500; +} +body > .target-search-dropdown .filter-group-toggle .toggle-count, +.target-search-dropdown .filter-group-toggle .toggle-count { + display: inline-flex; + align-items: center; + gap: 0.125rem; + color: #6c757d; + font-size: 0.65rem; +} +body > .target-search-dropdown .filter-group-toggle .toggle-count i, +.target-search-dropdown .filter-group-toggle .toggle-count i { + font-size: 10px; + color: #25b9d7; +} +body > .target-search-dropdown .filter-group-toggle .toggle-count.clickable, +.target-search-dropdown .filter-group-toggle .toggle-count.clickable { + cursor: pointer; + padding: 0.125rem 0.25rem; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +body > .target-search-dropdown .filter-group-toggle .toggle-count.clickable:hover, +.target-search-dropdown .filter-group-toggle .toggle-count.clickable:hover { + background: rgba(37, 185, 215, 0.1); + color: #25b9d7; +} +body > .target-search-dropdown .filter-group-toggle .toggle-count.clickable:hover i, +.target-search-dropdown .filter-group-toggle .toggle-count.clickable:hover i { + color: #25b9d7; +} +body > .target-search-dropdown .filter-group-toggle .toggle-count.clickable.popover-open, +.target-search-dropdown .filter-group-toggle .toggle-count.clickable.popover-open { + background: #25b9d7; + color: #ffffff; +} +body > .target-search-dropdown .filter-group-toggle .toggle-count.clickable.popover-open i, +.target-search-dropdown .filter-group-toggle .toggle-count.clickable.popover-open i { + color: #ffffff; +} +body > .target-search-dropdown .filter-group-toggle .toggle-count.clickable.loading i, +.target-search-dropdown .filter-group-toggle .toggle-count.clickable.loading i { + animation: spin 0.6s linear infinite; +} +body > .target-search-dropdown .filter-chip, body > .target-search-dropdown .filter-attr-chip, +body > .target-search-dropdown .filter-feat-chip, +.target-search-dropdown .filter-chip, +.target-search-dropdown .filter-attr-chip, +.target-search-dropdown .filter-feat-chip { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +body > .target-search-dropdown .filter-chip:focus, +.target-search-dropdown .filter-chip:focus, +.target-search-dropdown .filter-attr-chip:focus, +.target-search-dropdown .filter-feat-chip:focus { + outline: none; +} +body > .target-search-dropdown .filter-chip, body > .target-search-dropdown .filter-attr-chip, +body > .target-search-dropdown .filter-feat-chip, +.target-search-dropdown .filter-chip, +.target-search-dropdown .filter-attr-chip, +.target-search-dropdown .filter-feat-chip { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + font-size: 0.75rem; + color: #495057; + background: #f1f5f9; + border: 1px solid transparent; + border-radius: 0.2rem; + cursor: pointer; + transition: all 0.15s ease-in-out; +} +body > .target-search-dropdown .filter-chip:hover, +.target-search-dropdown .filter-chip:hover, +.target-search-dropdown .filter-attr-chip:hover, +.target-search-dropdown .filter-feat-chip:hover { + background: #e2e8f0; +} +body > .target-search-dropdown .filter-chip.active, +.target-search-dropdown .filter-chip.active, +.target-search-dropdown .active.filter-attr-chip, +.target-search-dropdown .active.filter-feat-chip { + background: #25b9d7; + color: #ffffff; +} +body > .target-search-dropdown .filter-row-values, +.target-search-dropdown .filter-row-values { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem; + background: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.2rem; +} +body > .target-search-dropdown .filter-row-values .filter-values-container, +.target-search-dropdown .filter-row-values .filter-values-container { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 0.25rem; + flex: 1; +} +body > .target-search-dropdown .filter-row-values .filter-values-label, +.target-search-dropdown .filter-row-values .filter-values-label { + font-size: 0.75rem; + font-weight: 600; + color: #495057; + white-space: nowrap; +} +body > .target-search-dropdown .filter-row-values .btn-close-values, +.target-search-dropdown .filter-row-values .btn-close-values { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +body > .target-search-dropdown .filter-row-values .btn-close-values:focus, +.target-search-dropdown .filter-row-values .btn-close-values:focus { + outline: none; +} +body > .target-search-dropdown .filter-row-values .btn-close-values, +.target-search-dropdown .filter-row-values .btn-close-values { + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + width: 20px; + height: 20px; + color: #6c757d; + border-radius: 0.2rem; +} +body > .target-search-dropdown .filter-row-values .btn-close-values:hover, +.target-search-dropdown .filter-row-values .btn-close-values:hover { + background: #e2e8f0; + color: #212529; +} +body > .target-search-dropdown .chip-name, +.target-search-dropdown .chip-name { + font-weight: 500; +} +body > .target-search-dropdown .chip-count, +.target-search-dropdown .chip-count { + font-size: 0.6rem; + color: #6c757d; + margin-left: 0.125rem; +} +body > .target-search-dropdown .filter-chip.active .chip-count, +.target-search-dropdown .filter-chip.active .chip-count, +.target-search-dropdown .active.filter-attr-chip .chip-count, +.target-search-dropdown .active.filter-feat-chip .chip-count { + color: rgba(255, 255, 255, 0.8); +} +body > .target-search-dropdown .dropdown-content, +.target-search-dropdown .dropdown-content { + max-height: 400px; + overflow-y: auto; +} +body > .target-search-dropdown .dropdown-content::-webkit-scrollbar, +.target-search-dropdown .dropdown-content::-webkit-scrollbar { + width: 6px; + height: 6px; +} +body > .target-search-dropdown .dropdown-content::-webkit-scrollbar-track, +.target-search-dropdown .dropdown-content::-webkit-scrollbar-track { + background: #f8f9fa; + border-radius: 3px; +} +body > .target-search-dropdown .dropdown-content::-webkit-scrollbar-thumb, +.target-search-dropdown .dropdown-content::-webkit-scrollbar-thumb { + background: #dee2e6; + border-radius: 3px; +} +body > .target-search-dropdown .dropdown-content::-webkit-scrollbar-thumb:hover, +.target-search-dropdown .dropdown-content::-webkit-scrollbar-thumb:hover { + background: #ced4da; +} +body > .target-search-dropdown .dropdown-items, +.target-search-dropdown .dropdown-items { + display: flex; + flex-direction: column; + gap: 0.25rem; + padding: 0.5rem; +} +body > .target-search-dropdown .item-checkbox, +.target-search-dropdown .item-checkbox { + flex-shrink: 0; + width: 16px; + height: 16px; + border: 2px solid #ced4da; + border-radius: 3px; + transition: all 0.15s ease-in-out; +} +.dropdown-item.selected body > .target-search-dropdown .item-checkbox, +.dropdown-item.selected .target-search-dropdown .item-checkbox { + background: #25b9d7; + border-color: #25b9d7; +} +body > .target-search-dropdown .item-image, +.target-search-dropdown .item-image { + flex-shrink: 0; + width: 40px; + height: 40px; + object-fit: cover; + border-radius: 0.2rem; + background: #f1f5f9; +} +body > .target-search-dropdown .item-info, +.target-search-dropdown .item-info { + flex: 1; + min-width: 0; +} +body > .target-search-dropdown .item-name, +.target-search-dropdown .item-name { + font-size: 0.875rem; + font-weight: 500; + color: #212529; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +body > .target-search-dropdown .item-meta, +.target-search-dropdown .item-meta { + font-size: 0.75rem; + color: #6c757d; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +body > .target-search-dropdown .dropdown-footer, +.target-search-dropdown .dropdown-footer { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; + padding: 0.5rem 1rem; + background: #f8fafc; + border-top: 1px solid #dee2e6; + border-radius: 0 0 0.3rem 0.3rem; +} +body > .target-search-dropdown .dropdown-footer-left, +.target-search-dropdown .dropdown-footer-left { + display: flex; + align-items: center; + gap: 0.25rem; + font-size: 0.75rem; + color: #6c757d; +} +body > .target-search-dropdown .dropdown-footer-left .load-label, +.target-search-dropdown .dropdown-footer-left .load-label { + color: #6c757d; +} +body > .target-search-dropdown .dropdown-footer-left .load-more-select, +body > .target-search-dropdown .dropdown-footer-left select.load-more-select, +.target-search-dropdown .dropdown-footer-left .load-more-select, +.target-search-dropdown .dropdown-footer-left select.load-more-select { + appearance: none; + padding: 0.25rem 1.5rem 0.25rem 0.5rem; + border: 1px solid #dee2e6; + border-radius: 0.2rem; + background: #ffffff 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.4rem center; + background-size: 8px; + font-size: 0.75rem; + color: #495057; + cursor: pointer; + min-width: 55px; +} +body > .target-search-dropdown .dropdown-footer-left .load-more-select:hover, +body > .target-search-dropdown .dropdown-footer-left select.load-more-select:hover, +.target-search-dropdown .dropdown-footer-left .load-more-select:hover, +.target-search-dropdown .dropdown-footer-left select.load-more-select:hover { + border-color: #25b9d7; +} +body > .target-search-dropdown .dropdown-footer-left .load-more-select:focus, +body > .target-search-dropdown .dropdown-footer-left select.load-more-select:focus, +.target-search-dropdown .dropdown-footer-left .load-more-select:focus, +.target-search-dropdown .dropdown-footer-left select.load-more-select:focus { + outline: none; + border-color: #25b9d7; +} +body > .target-search-dropdown .dropdown-footer-left .remaining-text, +.target-search-dropdown .dropdown-footer-left .remaining-text { + color: #6c757d; +} +body > .target-search-dropdown .dropdown-footer-left .remaining-text strong, +.target-search-dropdown .dropdown-footer-left .remaining-text strong { + color: #495057; + font-weight: 600; +} +body > .target-search-dropdown .dropdown-footer-right, +.target-search-dropdown .dropdown-footer-right { + display: flex; + align-items: center; + gap: 0.5rem; +} +body > .target-search-dropdown .dropdown-action-btn, +.target-search-dropdown .dropdown-action-btn { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +body > .target-search-dropdown .dropdown-action-btn:focus, +.target-search-dropdown .dropdown-action-btn:focus { + outline: none; +} +body > .target-search-dropdown .dropdown-action-btn, +.target-search-dropdown .dropdown-action-btn { + display: inline-flex; + align-items: center; + gap: 0.375rem; + padding: 0.375rem 0.75rem; + font-size: 0.75rem; + font-weight: 500; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; + white-space: nowrap; +} +body > .target-search-dropdown .dropdown-action-btn .btn-shortcut, +.target-search-dropdown .dropdown-action-btn .btn-shortcut { + font-size: 10px; + padding: 0.125rem 0.25rem; + background: rgba(0, 0, 0, 0.08); + border-radius: 3px; + font-weight: 400; +} +body > .target-search-dropdown .dropdown-action-btn.btn-cancel, +.target-search-dropdown .dropdown-action-btn.btn-cancel { + color: #495057; + background: #ffffff; + border: 1px solid #dee2e6; +} +body > .target-search-dropdown .dropdown-action-btn.btn-cancel:hover, +.target-search-dropdown .dropdown-action-btn.btn-cancel:hover { + background: #f1f5f9; + border-color: #ced4da; +} +body > .target-search-dropdown .dropdown-action-btn.btn-apply, body > .target-search-dropdown .dropdown-action-btn.btn-save, +.target-search-dropdown .dropdown-action-btn.btn-apply, +.target-search-dropdown .dropdown-action-btn.btn-save { + color: #ffffff; + background: #25b9d7; + border: 1px solid #25b9d7; +} +body > .target-search-dropdown .dropdown-action-btn.btn-apply:hover, body > .target-search-dropdown .dropdown-action-btn.btn-save:hover, +.target-search-dropdown .dropdown-action-btn.btn-apply:hover, +.target-search-dropdown .dropdown-action-btn.btn-save:hover { + background: #1a9ab7; + border-color: #1a9ab7; +} +body > .target-search-dropdown .dropdown-action-btn.btn-apply .btn-shortcut, body > .target-search-dropdown .dropdown-action-btn.btn-save .btn-shortcut, +.target-search-dropdown .dropdown-action-btn.btn-apply .btn-shortcut, +.target-search-dropdown .dropdown-action-btn.btn-save .btn-shortcut { + background: rgba(255, 255, 255, 0.2); +} +body > .target-search-dropdown .dropdown-footer-info, +.target-search-dropdown .dropdown-footer-info { + font-size: 0.75rem; + color: #6c757d; +} +body > .target-search-dropdown .btn-cancel-dropdown, +.target-search-dropdown .btn-cancel-dropdown { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +body > .target-search-dropdown .btn-cancel-dropdown:focus, +.target-search-dropdown .btn-cancel-dropdown:focus { + outline: none; +} +body > .target-search-dropdown .btn-cancel-dropdown, +.target-search-dropdown .btn-cancel-dropdown { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.375rem 0.75rem; + font-size: 0.875rem; + color: #ffffff; + background: #25b9d7; + border: 1px solid #25b9d7; + border-radius: 0.2rem; + cursor: pointer; +} +body > .target-search-dropdown .btn-cancel-dropdown:hover, +.target-search-dropdown .btn-cancel-dropdown:hover { + background: #1a9ab7; + border-color: #1a9ab7; +} +body > .target-search-dropdown .btn-cancel-dropdown i, +.target-search-dropdown .btn-cancel-dropdown i { + font-size: 10px; +} +body > .target-search-dropdown .btn-cancel-dropdown kbd, +.target-search-dropdown .btn-cancel-dropdown kbd { + font-size: 0.65rem; + padding: 0.125rem 0.25rem; + background: rgba(255, 255, 255, 0.2); + border-radius: 2px; + color: rgba(255, 255, 255, 0.8); +} +body > .target-search-dropdown .filter-chips-row, +.target-search-dropdown .filter-chips-row { + display: flex; + flex-wrap: wrap; + gap: 0.25rem; + padding: 0.25rem 1rem; + border-bottom: 1px solid #dee2e6; +} +body > .target-search-dropdown .filter-chip, body > .target-search-dropdown .filter-attr-chip, +body > .target-search-dropdown .filter-feat-chip, +.target-search-dropdown .filter-chip, +.target-search-dropdown .filter-attr-chip, +.target-search-dropdown .filter-feat-chip { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + font-size: 0.75rem; + font-weight: 500; + background: #e9ecef; + color: #495057; + border-radius: 50rem; +} +body > .target-search-dropdown .filter-chip .chip-remove, +.target-search-dropdown .filter-chip .chip-remove, +.target-search-dropdown .filter-attr-chip .chip-remove, +.target-search-dropdown .filter-feat-chip .chip-remove { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +body > .target-search-dropdown .filter-chip .chip-remove:focus, +.target-search-dropdown .filter-chip .chip-remove:focus, +.target-search-dropdown .filter-attr-chip .chip-remove:focus, +.target-search-dropdown .filter-feat-chip .chip-remove:focus { + outline: none; +} +body > .target-search-dropdown .filter-chip .chip-remove, +.target-search-dropdown .filter-chip .chip-remove, +.target-search-dropdown .filter-attr-chip .chip-remove, +.target-search-dropdown .filter-feat-chip .chip-remove { + display: flex; + align-items: center; + justify-content: center; + width: 14px; + height: 14px; + font-size: 10px; + color: #6c757d; + border-radius: 50%; +} +body > .target-search-dropdown .filter-chip .chip-remove:hover, +.target-search-dropdown .filter-chip .chip-remove:hover, +.target-search-dropdown .filter-attr-chip .chip-remove:hover, +.target-search-dropdown .filter-feat-chip .chip-remove:hover { + background: rgba(0, 0, 0, 0.1); + color: #dc3545; +} +body > .target-search-dropdown .dropdown-empty, +body > .target-search-dropdown .dropdown-loading, +.target-search-dropdown .dropdown-empty, +.target-search-dropdown .dropdown-loading { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 2rem; + text-align: center; + color: #6c757d; + font-size: 0.875rem; +} +body > .target-search-dropdown .dropdown-empty i, +body > .target-search-dropdown .dropdown-loading i, +.target-search-dropdown .dropdown-empty i, +.target-search-dropdown .dropdown-loading i { + font-size: 2rem; + opacity: 0.5; + margin-bottom: 0.5rem; +} +body > .target-search-dropdown .search-history-panel, +.target-search-dropdown .search-history-panel { + display: none; + padding: 0.5rem; + background: #ffffff; + border-bottom: 1px solid #dee2e6; +} +body > .target-search-dropdown .search-history-panel.show, +.target-search-dropdown .search-history-panel.show { + display: block; +} +body > .target-search-dropdown .history-item, +.target-search-dropdown .history-item { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.25rem 0.5rem; + border-radius: 0.2rem; + cursor: pointer; + transition: background 0.15s ease-in-out; +} +body > .target-search-dropdown .history-item:hover, +.target-search-dropdown .history-item:hover { + background: #e9ecef; +} +body > .target-search-dropdown .history-item i, +.target-search-dropdown .history-item i { + color: #6c757d; + font-size: 0.875rem; +} +body > .target-search-dropdown .history-item span, +.target-search-dropdown .history-item span { + flex: 1; + font-size: 0.875rem; + color: #212529; +} +body > .target-search-dropdown .history-item .btn-remove-history, +body > .target-search-dropdown .history-item .btn-delete-history, +.target-search-dropdown .history-item .btn-remove-history, +.target-search-dropdown .history-item .btn-delete-history { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +body > .target-search-dropdown .history-item .btn-remove-history:focus, +body > .target-search-dropdown .history-item .btn-delete-history:focus, +.target-search-dropdown .history-item .btn-remove-history:focus, +.target-search-dropdown .history-item .btn-delete-history:focus { + outline: none; +} +body > .target-search-dropdown .history-item .btn-remove-history, +body > .target-search-dropdown .history-item .btn-delete-history, +.target-search-dropdown .history-item .btn-remove-history, +.target-search-dropdown .history-item .btn-delete-history { + display: flex; + align-items: center; + justify-content: center; + width: 20px; + height: 20px; + color: #6c757d; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +body > .target-search-dropdown .history-item .btn-remove-history:hover, +body > .target-search-dropdown .history-item .btn-delete-history:hover, +.target-search-dropdown .history-item .btn-remove-history:hover, +.target-search-dropdown .history-item .btn-delete-history:hover { + background: #e2e8f0; + color: #dc3545; +} +body > .target-search-dropdown .search-history-list, +.target-search-dropdown .search-history-list { + display: flex; + flex-direction: column; + gap: 0.25rem; +} +body > .target-search-dropdown .results-header, +.target-search-dropdown .results-header { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.25rem 1rem; + background: #f1f5f9; + border-bottom: 1px solid #dee2e6; + font-size: 0.75rem; + font-weight: 600; + color: #495057; +} +body > .target-search-dropdown .results-header .header-spacer, +.target-search-dropdown .results-header .header-spacer { + width: 58px; + flex-shrink: 0; +} +body > .target-search-dropdown .results-header .header-col, +.target-search-dropdown .results-header .header-col { + flex-shrink: 0; + width: 70px; + text-align: right; +} +body > .target-search-dropdown .results-header .header-col-name, +.target-search-dropdown .results-header .header-col-name { + flex: 1; + text-align: left; +} +body > .target-search-dropdown .dropdown-results, +.target-search-dropdown .dropdown-results { + padding: 0 0.5rem; + background: #ffffff; + min-height: 200px; +} +body > .target-search-dropdown .dropdown-item, +.target-search-dropdown .dropdown-item { + position: relative; + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 0; + background: #ffffff; + border: none; + border-bottom: 1px solid #dee2e6; + border-radius: 0; + cursor: pointer; + transition: background 0.15s ease-in-out; +} +body > .target-search-dropdown .dropdown-item:last-child, +.target-search-dropdown .dropdown-item:last-child { + border-bottom: none; +} +body > .target-search-dropdown .dropdown-item:hover, +.target-search-dropdown .dropdown-item:hover { + background: #e9ecef; +} +body > .target-search-dropdown .dropdown-item.selected, +.target-search-dropdown .dropdown-item.selected { + background: rgba(37, 185, 215, 0.1); +} +body > .target-search-dropdown .dropdown-item.selected .result-checkbox, +.target-search-dropdown .dropdown-item.selected .result-checkbox { + background: #25b9d7; + border-color: #25b9d7; + color: #ffffff; +} +body > .target-search-dropdown .dropdown-item.selected .result-checkbox i, +.target-search-dropdown .dropdown-item.selected .result-checkbox i { + display: block; +} +body > .target-search-dropdown .dropdown-item.disabled, +.target-search-dropdown .dropdown-item.disabled { + opacity: 0.5; + cursor: not-allowed; +} +body > .target-search-dropdown .result-checkbox, +.target-search-dropdown .result-checkbox { + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + width: 18px; + height: 18px; + background: #ffffff; + border: 2px solid #ced4da; + border-radius: 3px; + transition: all 0.15s ease-in-out; +} +body > .target-search-dropdown .result-checkbox i, +.target-search-dropdown .result-checkbox i { + display: none; + font-size: 10px; +} +body > .target-search-dropdown.view-cols-2 .dropdown-results, +.target-search-dropdown.view-cols-2 .dropdown-results { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 0; + padding: 0; + border-top: 1px solid #dee2e6; + border-left: 1px solid #dee2e6; +} +body > .target-search-dropdown.view-cols-3 .dropdown-results, +.target-search-dropdown.view-cols-3 .dropdown-results { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 0; + padding: 0; + border-top: 1px solid #dee2e6; + border-left: 1px solid #dee2e6; +} +body > .target-search-dropdown.view-cols-4 .dropdown-results, +.target-search-dropdown.view-cols-4 .dropdown-results { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 0; + padding: 0; + border-top: 1px solid #dee2e6; + border-left: 1px solid #dee2e6; +} +body > .target-search-dropdown.view-cols-5 .dropdown-results, +.target-search-dropdown.view-cols-5 .dropdown-results { + display: grid; + grid-template-columns: repeat(5, 1fr); + gap: 0; + padding: 0; + border-top: 1px solid #dee2e6; + border-left: 1px solid #dee2e6; +} +body > .target-search-dropdown.view-cols-6 .dropdown-results, +.target-search-dropdown.view-cols-6 .dropdown-results { + display: grid; + grid-template-columns: repeat(6, 1fr); + gap: 0; + padding: 0; + border-top: 1px solid #dee2e6; + border-left: 1px solid #dee2e6; +} +body > .target-search-dropdown.view-cols-7 .dropdown-results, +.target-search-dropdown.view-cols-7 .dropdown-results { + display: grid; + grid-template-columns: repeat(7, 1fr); + gap: 0; + padding: 0; + border-top: 1px solid #dee2e6; + border-left: 1px solid #dee2e6; +} +body > .target-search-dropdown.view-cols-8 .dropdown-results, +.target-search-dropdown.view-cols-8 .dropdown-results { + display: grid; + grid-template-columns: repeat(8, 1fr); + gap: 0; + padding: 0; + border-top: 1px solid #dee2e6; + border-left: 1px solid #dee2e6; +} +body > .target-search-dropdown.view-cols-2 .dropdown-item, body > .target-search-dropdown.view-cols-3 .dropdown-item, body > .target-search-dropdown.view-cols-4 .dropdown-item, body > .target-search-dropdown.view-cols-5 .dropdown-item, body > .target-search-dropdown.view-cols-6 .dropdown-item, body > .target-search-dropdown.view-cols-7 .dropdown-item, body > .target-search-dropdown.view-cols-8 .dropdown-item, +.target-search-dropdown.view-cols-2 .dropdown-item, +.target-search-dropdown.view-cols-3 .dropdown-item, +.target-search-dropdown.view-cols-4 .dropdown-item, +.target-search-dropdown.view-cols-5 .dropdown-item, +.target-search-dropdown.view-cols-6 .dropdown-item, +.target-search-dropdown.view-cols-7 .dropdown-item, +.target-search-dropdown.view-cols-8 .dropdown-item { + flex-direction: column; + align-items: center; + text-align: center; + padding: 0.5rem; + border: none; + border-right: 1px solid #dee2e6; + border-bottom: 1px solid #dee2e6; + border-radius: 0; +} +body > .target-search-dropdown.view-cols-2 .dropdown-item .result-checkbox, body > .target-search-dropdown.view-cols-3 .dropdown-item .result-checkbox, body > .target-search-dropdown.view-cols-4 .dropdown-item .result-checkbox, body > .target-search-dropdown.view-cols-5 .dropdown-item .result-checkbox, body > .target-search-dropdown.view-cols-6 .dropdown-item .result-checkbox, body > .target-search-dropdown.view-cols-7 .dropdown-item .result-checkbox, body > .target-search-dropdown.view-cols-8 .dropdown-item .result-checkbox, +.target-search-dropdown.view-cols-2 .dropdown-item .result-checkbox, +.target-search-dropdown.view-cols-3 .dropdown-item .result-checkbox, +.target-search-dropdown.view-cols-4 .dropdown-item .result-checkbox, +.target-search-dropdown.view-cols-5 .dropdown-item .result-checkbox, +.target-search-dropdown.view-cols-6 .dropdown-item .result-checkbox, +.target-search-dropdown.view-cols-7 .dropdown-item .result-checkbox, +.target-search-dropdown.view-cols-8 .dropdown-item .result-checkbox { + position: absolute; + top: 0.25rem; + left: 0.25rem; +} +body > .target-search-dropdown.view-cols-2 .dropdown-item .result-image, +body > .target-search-dropdown.view-cols-2 .dropdown-item .result-icon, body > .target-search-dropdown.view-cols-3 .dropdown-item .result-image, +body > .target-search-dropdown.view-cols-3 .dropdown-item .result-icon, body > .target-search-dropdown.view-cols-4 .dropdown-item .result-image, +body > .target-search-dropdown.view-cols-4 .dropdown-item .result-icon, body > .target-search-dropdown.view-cols-5 .dropdown-item .result-image, +body > .target-search-dropdown.view-cols-5 .dropdown-item .result-icon, body > .target-search-dropdown.view-cols-6 .dropdown-item .result-image, +body > .target-search-dropdown.view-cols-6 .dropdown-item .result-icon, body > .target-search-dropdown.view-cols-7 .dropdown-item .result-image, +body > .target-search-dropdown.view-cols-7 .dropdown-item .result-icon, body > .target-search-dropdown.view-cols-8 .dropdown-item .result-image, +body > .target-search-dropdown.view-cols-8 .dropdown-item .result-icon, +.target-search-dropdown.view-cols-2 .dropdown-item .result-image, +.target-search-dropdown.view-cols-2 .dropdown-item .result-icon, +.target-search-dropdown.view-cols-3 .dropdown-item .result-image, +.target-search-dropdown.view-cols-3 .dropdown-item .result-icon, +.target-search-dropdown.view-cols-4 .dropdown-item .result-image, +.target-search-dropdown.view-cols-4 .dropdown-item .result-icon, +.target-search-dropdown.view-cols-5 .dropdown-item .result-image, +.target-search-dropdown.view-cols-5 .dropdown-item .result-icon, +.target-search-dropdown.view-cols-6 .dropdown-item .result-image, +.target-search-dropdown.view-cols-6 .dropdown-item .result-icon, +.target-search-dropdown.view-cols-7 .dropdown-item .result-image, +.target-search-dropdown.view-cols-7 .dropdown-item .result-icon, +.target-search-dropdown.view-cols-8 .dropdown-item .result-image, +.target-search-dropdown.view-cols-8 .dropdown-item .result-icon { + width: 48px; + height: 48px; + margin-bottom: 0.25rem; +} +body > .target-search-dropdown.view-cols-2 .dropdown-item .result-info, body > .target-search-dropdown.view-cols-3 .dropdown-item .result-info, body > .target-search-dropdown.view-cols-4 .dropdown-item .result-info, body > .target-search-dropdown.view-cols-5 .dropdown-item .result-info, body > .target-search-dropdown.view-cols-6 .dropdown-item .result-info, body > .target-search-dropdown.view-cols-7 .dropdown-item .result-info, body > .target-search-dropdown.view-cols-8 .dropdown-item .result-info, +.target-search-dropdown.view-cols-2 .dropdown-item .result-info, +.target-search-dropdown.view-cols-3 .dropdown-item .result-info, +.target-search-dropdown.view-cols-4 .dropdown-item .result-info, +.target-search-dropdown.view-cols-5 .dropdown-item .result-info, +.target-search-dropdown.view-cols-6 .dropdown-item .result-info, +.target-search-dropdown.view-cols-7 .dropdown-item .result-info, +.target-search-dropdown.view-cols-8 .dropdown-item .result-info { + width: 100%; +} +body > .target-search-dropdown.view-cols-2 .dropdown-item .result-name, body > .target-search-dropdown.view-cols-3 .dropdown-item .result-name, body > .target-search-dropdown.view-cols-4 .dropdown-item .result-name, body > .target-search-dropdown.view-cols-5 .dropdown-item .result-name, body > .target-search-dropdown.view-cols-6 .dropdown-item .result-name, body > .target-search-dropdown.view-cols-7 .dropdown-item .result-name, body > .target-search-dropdown.view-cols-8 .dropdown-item .result-name, +.target-search-dropdown.view-cols-2 .dropdown-item .result-name, +.target-search-dropdown.view-cols-3 .dropdown-item .result-name, +.target-search-dropdown.view-cols-4 .dropdown-item .result-name, +.target-search-dropdown.view-cols-5 .dropdown-item .result-name, +.target-search-dropdown.view-cols-6 .dropdown-item .result-name, +.target-search-dropdown.view-cols-7 .dropdown-item .result-name, +.target-search-dropdown.view-cols-8 .dropdown-item .result-name { + font-size: 0.75rem; + line-height: 1.3; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} +body > .target-search-dropdown.view-cols-2 .dropdown-item .result-subtitle, body > .target-search-dropdown.view-cols-3 .dropdown-item .result-subtitle, body > .target-search-dropdown.view-cols-4 .dropdown-item .result-subtitle, body > .target-search-dropdown.view-cols-5 .dropdown-item .result-subtitle, body > .target-search-dropdown.view-cols-6 .dropdown-item .result-subtitle, body > .target-search-dropdown.view-cols-7 .dropdown-item .result-subtitle, body > .target-search-dropdown.view-cols-8 .dropdown-item .result-subtitle, +.target-search-dropdown.view-cols-2 .dropdown-item .result-subtitle, +.target-search-dropdown.view-cols-3 .dropdown-item .result-subtitle, +.target-search-dropdown.view-cols-4 .dropdown-item .result-subtitle, +.target-search-dropdown.view-cols-5 .dropdown-item .result-subtitle, +.target-search-dropdown.view-cols-6 .dropdown-item .result-subtitle, +.target-search-dropdown.view-cols-7 .dropdown-item .result-subtitle, +.target-search-dropdown.view-cols-8 .dropdown-item .result-subtitle { + display: none; +} +body > .target-search-dropdown.view-cols-2 .dropdown-item .result-col, body > .target-search-dropdown.view-cols-3 .dropdown-item .result-col, body > .target-search-dropdown.view-cols-4 .dropdown-item .result-col, body > .target-search-dropdown.view-cols-5 .dropdown-item .result-col, body > .target-search-dropdown.view-cols-6 .dropdown-item .result-col, body > .target-search-dropdown.view-cols-7 .dropdown-item .result-col, body > .target-search-dropdown.view-cols-8 .dropdown-item .result-col, +.target-search-dropdown.view-cols-2 .dropdown-item .result-col, +.target-search-dropdown.view-cols-3 .dropdown-item .result-col, +.target-search-dropdown.view-cols-4 .dropdown-item .result-col, +.target-search-dropdown.view-cols-5 .dropdown-item .result-col, +.target-search-dropdown.view-cols-6 .dropdown-item .result-col, +.target-search-dropdown.view-cols-7 .dropdown-item .result-col, +.target-search-dropdown.view-cols-8 .dropdown-item .result-col { + display: none; +} +body > .target-search-dropdown.view-cols-2 .dropdown-item .result-grid-info, body > .target-search-dropdown.view-cols-3 .dropdown-item .result-grid-info, body > .target-search-dropdown.view-cols-4 .dropdown-item .result-grid-info, body > .target-search-dropdown.view-cols-5 .dropdown-item .result-grid-info, body > .target-search-dropdown.view-cols-6 .dropdown-item .result-grid-info, body > .target-search-dropdown.view-cols-7 .dropdown-item .result-grid-info, body > .target-search-dropdown.view-cols-8 .dropdown-item .result-grid-info, +.target-search-dropdown.view-cols-2 .dropdown-item .result-grid-info, +.target-search-dropdown.view-cols-3 .dropdown-item .result-grid-info, +.target-search-dropdown.view-cols-4 .dropdown-item .result-grid-info, +.target-search-dropdown.view-cols-5 .dropdown-item .result-grid-info, +.target-search-dropdown.view-cols-6 .dropdown-item .result-grid-info, +.target-search-dropdown.view-cols-7 .dropdown-item .result-grid-info, +.target-search-dropdown.view-cols-8 .dropdown-item .result-grid-info { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 0.25rem; + margin-top: 0.25rem; + font-size: 0.65rem; +} +body > .target-search-dropdown.view-cols-2 .dropdown-item .result-grid-info .grid-price, body > .target-search-dropdown.view-cols-3 .dropdown-item .result-grid-info .grid-price, body > .target-search-dropdown.view-cols-4 .dropdown-item .result-grid-info .grid-price, body > .target-search-dropdown.view-cols-5 .dropdown-item .result-grid-info .grid-price, body > .target-search-dropdown.view-cols-6 .dropdown-item .result-grid-info .grid-price, body > .target-search-dropdown.view-cols-7 .dropdown-item .result-grid-info .grid-price, body > .target-search-dropdown.view-cols-8 .dropdown-item .result-grid-info .grid-price, +.target-search-dropdown.view-cols-2 .dropdown-item .result-grid-info .grid-price, +.target-search-dropdown.view-cols-3 .dropdown-item .result-grid-info .grid-price, +.target-search-dropdown.view-cols-4 .dropdown-item .result-grid-info .grid-price, +.target-search-dropdown.view-cols-5 .dropdown-item .result-grid-info .grid-price, +.target-search-dropdown.view-cols-6 .dropdown-item .result-grid-info .grid-price, +.target-search-dropdown.view-cols-7 .dropdown-item .result-grid-info .grid-price, +.target-search-dropdown.view-cols-8 .dropdown-item .result-grid-info .grid-price { + color: #212529; + font-weight: 600; +} +body > .target-search-dropdown.view-cols-2 .dropdown-item .result-grid-info .grid-stock, body > .target-search-dropdown.view-cols-3 .dropdown-item .result-grid-info .grid-stock, body > .target-search-dropdown.view-cols-4 .dropdown-item .result-grid-info .grid-stock, body > .target-search-dropdown.view-cols-5 .dropdown-item .result-grid-info .grid-stock, body > .target-search-dropdown.view-cols-6 .dropdown-item .result-grid-info .grid-stock, body > .target-search-dropdown.view-cols-7 .dropdown-item .result-grid-info .grid-stock, body > .target-search-dropdown.view-cols-8 .dropdown-item .result-grid-info .grid-stock, +.target-search-dropdown.view-cols-2 .dropdown-item .result-grid-info .grid-stock, +.target-search-dropdown.view-cols-3 .dropdown-item .result-grid-info .grid-stock, +.target-search-dropdown.view-cols-4 .dropdown-item .result-grid-info .grid-stock, +.target-search-dropdown.view-cols-5 .dropdown-item .result-grid-info .grid-stock, +.target-search-dropdown.view-cols-6 .dropdown-item .result-grid-info .grid-stock, +.target-search-dropdown.view-cols-7 .dropdown-item .result-grid-info .grid-stock, +.target-search-dropdown.view-cols-8 .dropdown-item .result-grid-info .grid-stock { + color: #6c757d; +} +body > .target-search-dropdown.view-cols-2 .dropdown-item .result-grid-info .grid-stock.stock-out, body > .target-search-dropdown.view-cols-3 .dropdown-item .result-grid-info .grid-stock.stock-out, body > .target-search-dropdown.view-cols-4 .dropdown-item .result-grid-info .grid-stock.stock-out, body > .target-search-dropdown.view-cols-5 .dropdown-item .result-grid-info .grid-stock.stock-out, body > .target-search-dropdown.view-cols-6 .dropdown-item .result-grid-info .grid-stock.stock-out, body > .target-search-dropdown.view-cols-7 .dropdown-item .result-grid-info .grid-stock.stock-out, body > .target-search-dropdown.view-cols-8 .dropdown-item .result-grid-info .grid-stock.stock-out, +.target-search-dropdown.view-cols-2 .dropdown-item .result-grid-info .grid-stock.stock-out, +.target-search-dropdown.view-cols-3 .dropdown-item .result-grid-info .grid-stock.stock-out, +.target-search-dropdown.view-cols-4 .dropdown-item .result-grid-info .grid-stock.stock-out, +.target-search-dropdown.view-cols-5 .dropdown-item .result-grid-info .grid-stock.stock-out, +.target-search-dropdown.view-cols-6 .dropdown-item .result-grid-info .grid-stock.stock-out, +.target-search-dropdown.view-cols-7 .dropdown-item .result-grid-info .grid-stock.stock-out, +.target-search-dropdown.view-cols-8 .dropdown-item .result-grid-info .grid-stock.stock-out { + color: #dc3545; +} +body > .target-search-dropdown.view-cols-2 .dropdown-item .result-grid-info .grid-stock.stock-low, body > .target-search-dropdown.view-cols-3 .dropdown-item .result-grid-info .grid-stock.stock-low, body > .target-search-dropdown.view-cols-4 .dropdown-item .result-grid-info .grid-stock.stock-low, body > .target-search-dropdown.view-cols-5 .dropdown-item .result-grid-info .grid-stock.stock-low, body > .target-search-dropdown.view-cols-6 .dropdown-item .result-grid-info .grid-stock.stock-low, body > .target-search-dropdown.view-cols-7 .dropdown-item .result-grid-info .grid-stock.stock-low, body > .target-search-dropdown.view-cols-8 .dropdown-item .result-grid-info .grid-stock.stock-low, +.target-search-dropdown.view-cols-2 .dropdown-item .result-grid-info .grid-stock.stock-low, +.target-search-dropdown.view-cols-3 .dropdown-item .result-grid-info .grid-stock.stock-low, +.target-search-dropdown.view-cols-4 .dropdown-item .result-grid-info .grid-stock.stock-low, +.target-search-dropdown.view-cols-5 .dropdown-item .result-grid-info .grid-stock.stock-low, +.target-search-dropdown.view-cols-6 .dropdown-item .result-grid-info .grid-stock.stock-low, +.target-search-dropdown.view-cols-7 .dropdown-item .result-grid-info .grid-stock.stock-low, +.target-search-dropdown.view-cols-8 .dropdown-item .result-grid-info .grid-stock.stock-low { + color: #fab000; +} +body > .target-search-dropdown.view-cols-2 .dropdown-item .result-grid-info .grid-discount, body > .target-search-dropdown.view-cols-3 .dropdown-item .result-grid-info .grid-discount, body > .target-search-dropdown.view-cols-4 .dropdown-item .result-grid-info .grid-discount, body > .target-search-dropdown.view-cols-5 .dropdown-item .result-grid-info .grid-discount, body > .target-search-dropdown.view-cols-6 .dropdown-item .result-grid-info .grid-discount, body > .target-search-dropdown.view-cols-7 .dropdown-item .result-grid-info .grid-discount, body > .target-search-dropdown.view-cols-8 .dropdown-item .result-grid-info .grid-discount, +.target-search-dropdown.view-cols-2 .dropdown-item .result-grid-info .grid-discount, +.target-search-dropdown.view-cols-3 .dropdown-item .result-grid-info .grid-discount, +.target-search-dropdown.view-cols-4 .dropdown-item .result-grid-info .grid-discount, +.target-search-dropdown.view-cols-5 .dropdown-item .result-grid-info .grid-discount, +.target-search-dropdown.view-cols-6 .dropdown-item .result-grid-info .grid-discount, +.target-search-dropdown.view-cols-7 .dropdown-item .result-grid-info .grid-discount, +.target-search-dropdown.view-cols-8 .dropdown-item .result-grid-info .grid-discount { + color: #70b580; + font-weight: 500; +} +body > .target-search-dropdown.view-cols-2 .results-header, body > .target-search-dropdown.view-cols-3 .results-header, body > .target-search-dropdown.view-cols-4 .results-header, body > .target-search-dropdown.view-cols-5 .results-header, body > .target-search-dropdown.view-cols-6 .results-header, body > .target-search-dropdown.view-cols-7 .results-header, body > .target-search-dropdown.view-cols-8 .results-header, +.target-search-dropdown.view-cols-2 .results-header, +.target-search-dropdown.view-cols-3 .results-header, +.target-search-dropdown.view-cols-4 .results-header, +.target-search-dropdown.view-cols-5 .results-header, +.target-search-dropdown.view-cols-6 .results-header, +.target-search-dropdown.view-cols-7 .results-header, +.target-search-dropdown.view-cols-8 .results-header { + display: none; +} +body > .target-search-dropdown.view-cols-2 .dropdown-results .dropdown-item:nth-child(2n), +.target-search-dropdown.view-cols-2 .dropdown-results .dropdown-item:nth-child(2n) { + border-right: none; +} +body > .target-search-dropdown.view-cols-3 .dropdown-results .dropdown-item:nth-child(3n), +.target-search-dropdown.view-cols-3 .dropdown-results .dropdown-item:nth-child(3n) { + border-right: none; +} +body > .target-search-dropdown.view-cols-4 .dropdown-results .dropdown-item:nth-child(4n), +.target-search-dropdown.view-cols-4 .dropdown-results .dropdown-item:nth-child(4n) { + border-right: none; +} +body > .target-search-dropdown.view-cols-5 .dropdown-results .dropdown-item:nth-child(5n), +.target-search-dropdown.view-cols-5 .dropdown-results .dropdown-item:nth-child(5n) { + border-right: none; +} +body > .target-search-dropdown.view-cols-6 .dropdown-results .dropdown-item:nth-child(6n), +.target-search-dropdown.view-cols-6 .dropdown-results .dropdown-item:nth-child(6n) { + border-right: none; +} +body > .target-search-dropdown.view-cols-7 .dropdown-results .dropdown-item:nth-child(7n), +.target-search-dropdown.view-cols-7 .dropdown-results .dropdown-item:nth-child(7n) { + border-right: none; +} +body > .target-search-dropdown.view-cols-8 .dropdown-results .dropdown-item:nth-child(8n), +.target-search-dropdown.view-cols-8 .dropdown-results .dropdown-item:nth-child(8n) { + border-right: none; +} +body > .target-search-dropdown.view-cols-5 .dropdown-item .result-image, +body > .target-search-dropdown.view-cols-5 .dropdown-item .result-icon, body > .target-search-dropdown.view-cols-6 .dropdown-item .result-image, +body > .target-search-dropdown.view-cols-6 .dropdown-item .result-icon, body > .target-search-dropdown.view-cols-7 .dropdown-item .result-image, +body > .target-search-dropdown.view-cols-7 .dropdown-item .result-icon, body > .target-search-dropdown.view-cols-8 .dropdown-item .result-image, +body > .target-search-dropdown.view-cols-8 .dropdown-item .result-icon, +.target-search-dropdown.view-cols-5 .dropdown-item .result-image, +.target-search-dropdown.view-cols-5 .dropdown-item .result-icon, +.target-search-dropdown.view-cols-6 .dropdown-item .result-image, +.target-search-dropdown.view-cols-6 .dropdown-item .result-icon, +.target-search-dropdown.view-cols-7 .dropdown-item .result-image, +.target-search-dropdown.view-cols-7 .dropdown-item .result-icon, +.target-search-dropdown.view-cols-8 .dropdown-item .result-image, +.target-search-dropdown.view-cols-8 .dropdown-item .result-icon { + width: 40px; + height: 40px; +} +body > .target-search-dropdown.view-cols-5 .dropdown-item .result-name, body > .target-search-dropdown.view-cols-6 .dropdown-item .result-name, body > .target-search-dropdown.view-cols-7 .dropdown-item .result-name, body > .target-search-dropdown.view-cols-8 .dropdown-item .result-name, +.target-search-dropdown.view-cols-5 .dropdown-item .result-name, +.target-search-dropdown.view-cols-6 .dropdown-item .result-name, +.target-search-dropdown.view-cols-7 .dropdown-item .result-name, +.target-search-dropdown.view-cols-8 .dropdown-item .result-name { + font-size: 0.65rem; +} +body > .target-search-dropdown .result-item-product, +.target-search-dropdown .result-item-product { + display: flex; + align-items: center; + gap: 0.5rem; + flex: 1; + min-width: 0; +} +body > .target-search-dropdown .result-item-image, +body > .target-search-dropdown .result-image, +.target-search-dropdown .result-item-image, +.target-search-dropdown .result-image { + flex-shrink: 0; + width: 40px; + height: 40px; + overflow: hidden; + border-radius: 0.2rem; + background: #f1f5f9; +} +body > .target-search-dropdown .result-item-image img, +body > .target-search-dropdown .result-image img, +.target-search-dropdown .result-item-image img, +.target-search-dropdown .result-image img { + width: 100%; + height: 100%; + object-fit: cover; +} +body > .target-search-dropdown .result-icon, +.target-search-dropdown .result-icon { + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + width: 40px; + height: 40px; + background: #f1f5f9; + border-radius: 0.2rem; + color: #6c757d; +} +body > .target-search-dropdown .result-icon i, +.target-search-dropdown .result-icon i { + font-size: 16px; +} +body > .target-search-dropdown .result-item-info, +body > .target-search-dropdown .result-info, +.target-search-dropdown .result-item-info, +.target-search-dropdown .result-info { + flex: 1; + min-width: 0; +} +body > .target-search-dropdown .result-item-name, +body > .target-search-dropdown .result-name, +.target-search-dropdown .result-item-name, +.target-search-dropdown .result-name { + font-size: 0.875rem; + font-weight: 500; + color: #212529; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +body > .target-search-dropdown .result-item-meta, +body > .target-search-dropdown .result-subtitle, +.target-search-dropdown .result-item-meta, +.target-search-dropdown .result-subtitle { + font-size: 0.75rem; + color: #6c757d; +} +body > .target-search-dropdown .subtitle-line, +.target-search-dropdown .subtitle-line { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +body > .target-search-dropdown .subtitle-line-primary, +.target-search-dropdown .subtitle-line-primary { + color: #495057; +} +body > .target-search-dropdown .subtitle-line-secondary, +.target-search-dropdown .subtitle-line-secondary { + color: #6c757d; + font-size: 11px; +} +body > .target-search-dropdown .result-col, +.target-search-dropdown .result-col { + flex-shrink: 0; + width: 70px; + text-align: right; + font-size: 0.75rem; +} +body > .target-search-dropdown .result-col-price, +.target-search-dropdown .result-col-price { + color: #495057; +} +body > .target-search-dropdown .result-col-sale, +.target-search-dropdown .result-col-sale { + color: #dc3545; + font-weight: 600; +} +body > .target-search-dropdown .result-col-stock .col-value.stock-ok, +.target-search-dropdown .result-col-stock .col-value.stock-ok { + color: #70b580; +} +body > .target-search-dropdown .result-col-stock .col-value.stock-low, +.target-search-dropdown .result-col-stock .col-value.stock-low { + color: #fab000; +} +body > .target-search-dropdown .result-col-stock .col-value.stock-out, +.target-search-dropdown .result-col-stock .col-value.stock-out { + color: #dc3545; +} +body > .target-search-dropdown .result-col-sales, +.target-search-dropdown .result-col-sales { + color: #6c757d; +} +body > .target-search-dropdown .col-value, +.target-search-dropdown .col-value { + display: block; +} +body > .target-search-dropdown .result-item-checkbox, +body > .target-search-dropdown .result-checkbox, +.target-search-dropdown .result-item-checkbox, +.target-search-dropdown .result-checkbox { + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + width: 18px; + height: 18px; + border: 2px solid #ced4da; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +body > .target-search-dropdown .result-item-checkbox i, +body > .target-search-dropdown .result-checkbox i, +.target-search-dropdown .result-item-checkbox i, +.target-search-dropdown .result-checkbox i { + display: none; + font-size: 10px; + color: #ffffff; +} +.dropdown-result-item.selected body > .target-search-dropdown .result-item-checkbox, .dropdown-item.selected body > .target-search-dropdown .result-item-checkbox, +.dropdown-result-item.selected body > .target-search-dropdown .result-checkbox, +.dropdown-item.selected body > .target-search-dropdown .result-checkbox, +.dropdown-result-item.selected .target-search-dropdown .result-item-checkbox, +.dropdown-item.selected .target-search-dropdown .result-item-checkbox, +.dropdown-result-item.selected .target-search-dropdown .result-checkbox, +.dropdown-item.selected .target-search-dropdown .result-checkbox { + background: #25b9d7; + border-color: #25b9d7; +} +.dropdown-result-item.selected body > .target-search-dropdown .result-item-checkbox i, .dropdown-item.selected body > .target-search-dropdown .result-item-checkbox i, +.dropdown-result-item.selected body > .target-search-dropdown .result-checkbox i, +.dropdown-item.selected body > .target-search-dropdown .result-checkbox i, +.dropdown-result-item.selected .target-search-dropdown .result-item-checkbox i, +.dropdown-item.selected .target-search-dropdown .result-item-checkbox i, +.dropdown-result-item.selected .target-search-dropdown .result-checkbox i, +.dropdown-item.selected .target-search-dropdown .result-checkbox i { + display: block; +} +body > .target-search-dropdown .no-results, +.target-search-dropdown .no-results { + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + padding: 2rem; + color: #6c757d; + font-size: 0.875rem; +} +body > .target-search-dropdown .no-results i, +.target-search-dropdown .no-results i { + font-size: 1.25rem; + opacity: 0.5; +} +body > .target-search-dropdown .load-more-controls, +.target-search-dropdown .load-more-controls { + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + padding: 0.5rem 1rem; + font-size: 0.75rem; + color: #6c757d; +} +body > .target-search-dropdown .load-more-controls .load-more-label, +body > .target-search-dropdown .load-more-controls .load-more-of, +.target-search-dropdown .load-more-controls .load-more-label, +.target-search-dropdown .load-more-controls .load-more-of { + white-space: nowrap; +} +body > .target-search-dropdown .load-more-controls .remaining-count, +.target-search-dropdown .load-more-controls .remaining-count { + font-weight: 600; + color: #495057; +} +body > .target-search-dropdown .load-more-controls .load-more-select, +.target-search-dropdown .load-more-controls .load-more-select { + width: 100%; + padding: 0.5rem 1rem; + font-size: 0.875rem; + line-height: 1.5; + color: #212529; + background-color: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +body > .target-search-dropdown .load-more-controls .load-more-select:focus, +.target-search-dropdown .load-more-controls .load-more-select:focus { + border-color: #25b9d7; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(37, 185, 215, 0.25); +} +body > .target-search-dropdown .load-more-controls .load-more-select::placeholder, +.target-search-dropdown .load-more-controls .load-more-select::placeholder { + color: #adb5bd; +} +body > .target-search-dropdown .load-more-controls .load-more-select, +.target-search-dropdown .load-more-controls .load-more-select { + padding: 0.25rem 0.5rem; + font-size: 0.75rem; + min-width: 60px; +} +body > .target-search-dropdown .load-more-controls .btn-load-more, +.target-search-dropdown .load-more-controls .btn-load-more { + display: flex; + align-items: center; + justify-content: center; + padding: 0.25rem; + margin: 0; + border: none; + color: #25b9d7; + background: rgba(37, 185, 215, 0.1) !important; + border-radius: 0.2rem; + cursor: pointer; + transition: all 0.15s ease-in-out; + font: inherit; +} +body > .target-search-dropdown .load-more-controls .btn-load-more i, +.target-search-dropdown .load-more-controls .btn-load-more i { + font-size: 14px; +} +body > .target-search-dropdown .load-more-controls .btn-load-more:hover, +.target-search-dropdown .load-more-controls .btn-load-more:hover { + background: rgba(37, 185, 215, 0.2) !important; +} +body > .target-search-dropdown .dropdown-load-more, +.target-search-dropdown .dropdown-load-more { + display: flex; + justify-content: center; + padding: 1rem; + border-top: 1px solid #dee2e6; +} +body > .target-search-dropdown .dropdown-load-more .load-more-btn, +.target-search-dropdown .dropdown-load-more .load-more-btn { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +body > .target-search-dropdown .dropdown-load-more .load-more-btn:focus, +.target-search-dropdown .dropdown-load-more .load-more-btn:focus { + outline: none; +} +body > .target-search-dropdown .dropdown-load-more .load-more-btn, +.target-search-dropdown .dropdown-load-more .load-more-btn { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.5rem 1rem; + font-size: 0.875rem; + font-weight: 500; + color: #25b9d7; + background: rgba(37, 185, 215, 0.1); + border-radius: 0.25rem; + transition: all 0.15s ease-in-out; +} +body > .target-search-dropdown .dropdown-load-more .load-more-btn:hover, +.target-search-dropdown .dropdown-load-more .load-more-btn:hover { + background: rgba(37, 185, 215, 0.2); +} +body > .target-search-dropdown .dropdown-load-more .load-more-btn.loading, +.target-search-dropdown .dropdown-load-more .load-more-btn.loading { + opacity: 0.7; + cursor: wait; +} +body > .target-search-dropdown .dropdown-body, +.target-search-dropdown .dropdown-body { + max-height: 400px; + overflow-y: auto; +} +body > .target-search-dropdown .dropdown-body::-webkit-scrollbar, +.target-search-dropdown .dropdown-body::-webkit-scrollbar { + width: 6px; + height: 6px; +} +body > .target-search-dropdown .dropdown-body::-webkit-scrollbar-track, +.target-search-dropdown .dropdown-body::-webkit-scrollbar-track { + background: #f8f9fa; + border-radius: 3px; +} +body > .target-search-dropdown .dropdown-body::-webkit-scrollbar-thumb, +.target-search-dropdown .dropdown-body::-webkit-scrollbar-thumb { + background: #dee2e6; + border-radius: 3px; +} +body > .target-search-dropdown .dropdown-body::-webkit-scrollbar-thumb:hover, +.target-search-dropdown .dropdown-body::-webkit-scrollbar-thumb:hover { + background: #ced4da; +} +body > .target-search-dropdown .tree-container, +.target-search-dropdown .tree-container { + padding: 0.5rem; +} +body > .target-search-dropdown .tree-loading, +.target-search-dropdown .tree-loading { + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + padding: 2rem; + color: #6c757d; + font-size: 0.875rem; +} +body > .target-search-dropdown .tree-loading i, +.target-search-dropdown .tree-loading i { + animation: spin 0.6s linear infinite; +} +body > .target-search-dropdown .tree-item, +.target-search-dropdown .tree-item { + display: flex; + align-items: center; + gap: 0.25rem; + padding: 0.375rem 0.5rem; + border-radius: 0.2rem; + cursor: pointer; + transition: background-color 0.15s ease-in-out; +} +body > .target-search-dropdown .tree-item:hover, +.target-search-dropdown .tree-item:hover { + background: #e9ecef; +} +body > .target-search-dropdown .tree-item.selected, +.target-search-dropdown .tree-item.selected { + background: rgba(37, 185, 215, 0.1); +} +body > .target-search-dropdown .tree-item.selected .tree-checkbox, +.target-search-dropdown .tree-item.selected .tree-checkbox { + background: #25b9d7; + border-color: #25b9d7; +} +body > .target-search-dropdown .tree-item.selected .tree-checkbox i, +.target-search-dropdown .tree-item.selected .tree-checkbox i { + display: block; +} +body > .target-search-dropdown .tree-info, +.target-search-dropdown .tree-info { + display: flex; + align-items: center; + gap: 0.25rem; + flex: 1; + min-width: 0; +} +body > .target-search-dropdown .tree-name, +.target-search-dropdown .tree-name { + font-size: 0.875rem; + color: #212529; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +body > .target-search-dropdown .tree-subtitle, +.target-search-dropdown .tree-subtitle { + font-size: 0.75rem; + color: #6c757d; +} + +.target-search-dropdown .dropdown-results { + max-height: 400px; + overflow-y: auto; + padding: 0 0.5rem; +} +.target-search-dropdown .dropdown-results::-webkit-scrollbar { + width: 6px; + height: 6px; +} +.target-search-dropdown .dropdown-results::-webkit-scrollbar-track { + background: #f8f9fa; + border-radius: 3px; +} +.target-search-dropdown .dropdown-results::-webkit-scrollbar-thumb { + background: #dee2e6; + border-radius: 3px; +} +.target-search-dropdown .dropdown-results::-webkit-scrollbar-thumb:hover { + background: #ced4da; +} +.target-search-dropdown .results-header { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.25rem 1rem; + background: #f1f5f9; + border-bottom: 1px solid #dee2e6; + font-size: 0.75rem; + font-weight: 600; + color: #495057; +} +.target-search-dropdown .results-header .header-spacer { + width: 58px; + flex-shrink: 0; +} +.target-search-dropdown .results-header .header-col { + flex-shrink: 0; + width: 70px; + text-align: right; +} +.target-search-dropdown .results-header .header-col-name { + flex: 1; + text-align: left; +} +.target-search-dropdown:not(.view-list) .results-header, .target-search-dropdown.view-tree .results-header { + display: none; +} +.target-search-dropdown .result-item-product { + display: flex; + align-items: center; + gap: 0.5rem; + flex: 1; + min-width: 0; +} +.target-search-dropdown .result-col { + flex-shrink: 0; + width: 70px; + text-align: right; + font-size: 0.75rem; +} +.target-search-dropdown .result-col-price { + color: #495057; +} +.target-search-dropdown .result-col-sale { + color: #dc3545; + font-weight: 600; +} +.target-search-dropdown .result-col-stock .col-value.stock-ok { + color: #70b580; +} +.target-search-dropdown .result-col-stock .col-value.stock-low { + color: #fab000; +} +.target-search-dropdown .result-col-stock .col-value.stock-out { + color: #dc3545; +} +.target-search-dropdown .result-col-sales { + color: #6c757d; +} +.target-search-dropdown .dropdown-item { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0; + border: none; + border-bottom: 1px solid #dee2e6; + border-radius: 0; + cursor: pointer; + transition: background-color 0.15s ease-in-out; +} +.target-search-dropdown .dropdown-item:last-child { + border-bottom: none; +} +.target-search-dropdown .dropdown-item:hover { + background: #e9ecef; +} +.target-search-dropdown .dropdown-item.selected { + background: rgba(37, 185, 215, 0.1); +} +.target-search-dropdown .result-checkbox { + flex-shrink: 0; + display: flex; + align-items: center; + justify-content: center; + width: 18px; + height: 18px; + border: 2px solid #ced4da; + border-radius: 3px; + transition: all 0.15s ease-in-out; +} +.target-search-dropdown .result-checkbox i { + font-size: 10px; + color: transparent; +} +.dropdown-item.selected .target-search-dropdown .result-checkbox { + background: #25b9d7; + border-color: #25b9d7; +} +.dropdown-item.selected .target-search-dropdown .result-checkbox i { + color: #ffffff; +} +.target-search-dropdown .result-image { + flex-shrink: 0; + width: 40px; + height: 40px; + overflow: hidden; + border-radius: 0.2rem; + background: #f1f5f9; +} +.target-search-dropdown .result-image img { + width: 100%; + height: 100%; + object-fit: cover; +} +.target-search-dropdown .result-icon { + flex-shrink: 0; + display: flex; + align-items: center; + justify-content: center; + width: 40px; + height: 40px; + background: #f1f5f9; + border-radius: 0.2rem; +} +.target-search-dropdown .result-icon i { + font-size: 16px; + color: #6c757d; +} +.target-search-dropdown .result-info { + flex: 1; + min-width: 0; +} +.target-search-dropdown .result-name { + font-size: 0.875rem; + font-weight: 500; + color: #212529; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.target-search-dropdown .result-subtitle { + font-size: 0.75rem; + color: #6c757d; +} +.target-search-dropdown .subtitle-line { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.target-search-dropdown .subtitle-line-primary { + color: #495057; +} +.target-search-dropdown .subtitle-line-secondary { + color: #6c757d; + font-size: 11px; +} +.target-search-dropdown[class*=view-cols-] .result-col, .target-search-dropdown.view-tree .result-col { + display: none; +} +.target-search-dropdown .entity-search-box { + display: flex; + align-items: center; + gap: 0.5rem; + width: 100%; + padding: 0.5rem 1rem; + background: #ffffff; + border: none; + border-bottom: 1px solid #dee2e6; + border-radius: 0; +} +.target-search-dropdown .entity-search-box .entity-search-icon { + color: #6c757d; + flex-shrink: 0; + margin-left: 0.25rem; +} +.target-search-dropdown .entity-search-box input.entity-search-input, +.target-search-dropdown .entity-search-box input.entity-search-input[type=text] { + flex: 1; + min-width: 0; + width: auto !important; + max-width: none !important; + height: auto; + padding: 0; + margin: 0; + border: none !important; + outline: none; + background: transparent !important; + font-size: 0.875rem; + color: #212529; + box-shadow: none !important; +} +.target-search-dropdown .entity-search-box input.entity-search-input::placeholder, +.target-search-dropdown .entity-search-box input.entity-search-input[type=text]::placeholder { + color: #6c757d; +} +.target-search-dropdown .entity-search-box input.entity-search-input:focus, +.target-search-dropdown .entity-search-box input.entity-search-input[type=text]:focus { + border: none !important; + box-shadow: none !important; + outline: none; +} +.target-search-dropdown .entity-search-box .search-loading { + color: #6c757d; +} + +body > .target-search-dropdown .dropdown-item { + border: none; + border-radius: 0; +} +body > .target-search-dropdown .dropdown-item:not(:last-child) { + border-bottom: 1px solid #dee2e6; +} + +@keyframes spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} +/** + * Entity Selector Styles + * @package prestashop-entity-selector + * @version 2.0.0 + * + * Compiles to: assets/css/admin/entity-selector.css + */ +/** + * Chips Component + * Entity chips, selection pills, tags + */ +.target-conditions-trait .chips-wrapper, +.entity-selector-trait .chips-wrapper { + display: flex; + flex-direction: column; + margin-top: 0.5rem; + background: #f8fafc; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + overflow: hidden; +} +.target-conditions-trait .chips-toolbar, +.entity-selector-trait .chips-toolbar { + display: none; + align-items: center; + flex-wrap: nowrap; + gap: 0.5rem; + padding: 0.5rem 1rem; + padding-bottom: 0; + background: transparent; +} +.target-conditions-trait .chips-toolbar.has-chips, +.entity-selector-trait .chips-toolbar.has-chips { + display: flex; +} +.target-conditions-trait .chips-toolbar input[type=text].chips-search-input, +.entity-selector-trait .chips-toolbar input[type=text].chips-search-input { + all: unset; + display: block; + flex: 1 1 auto; + min-width: 80px; + width: auto; + height: auto; + padding: 0.2rem 0.5rem 0.2rem 1.5rem; + background: #ffffff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.35-4.35'/%3E%3C/svg%3E") no-repeat 0.375rem center; + background-size: 10px; + border: 1px solid #cbd5e1; + border-radius: 0.2rem; + font-size: 11px; + line-height: 1.4; + color: #212529; + box-sizing: border-box; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .chips-toolbar input[type=text].chips-search-input::placeholder, +.entity-selector-trait .chips-toolbar input[type=text].chips-search-input::placeholder { + color: #6c757d; + font-size: 11px; +} +.target-conditions-trait .chips-toolbar input[type=text].chips-search-input:focus, +.entity-selector-trait .chips-toolbar input[type=text].chips-search-input:focus { + outline: none; + border-color: #25b9d7; + box-shadow: 0 0 0 2px rgba(37, 185, 215, 0.1); +} +.target-conditions-trait .chips-toolbar select.chips-sort-select, +.entity-selector-trait .chips-toolbar select.chips-sort-select { + all: unset; + flex: 0 0 auto; + padding: 0.2rem 1.25rem 0.2rem 0.5rem; + border: 1px solid #dee2e6; + border-radius: 0.2rem; + background: #ffffff 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.375rem center; + background-size: 8px; + font-size: 10px; + line-height: 1.4; + color: #495057; + cursor: pointer; + box-sizing: border-box; + white-space: nowrap; +} +.target-conditions-trait .chips-toolbar select.chips-sort-select:hover, +.entity-selector-trait .chips-toolbar select.chips-sort-select:hover { + border-color: #25b9d7; +} +.target-conditions-trait .chips-toolbar select.chips-sort-select:focus, +.entity-selector-trait .chips-toolbar select.chips-sort-select:focus { + outline: none; + border-color: #25b9d7; + box-shadow: 0 0 0 2px rgba(37, 185, 215, 0.1); +} +.target-conditions-trait .chips-count, +.entity-selector-trait .chips-count { + display: inline-flex; + align-items: center; + flex-shrink: 0; + gap: 0.125rem; + padding: 0.2rem 0.5rem; + background: #e2e8f0; + color: #495057; + font-size: 10px; + font-weight: 600; + border-radius: 0.2rem; + white-space: nowrap; + line-height: 1.4; +} +.target-conditions-trait .chips-count.has-filter, +.entity-selector-trait .chips-count.has-filter { + background: #cffafe; + color: #0e7490; +} +.target-conditions-trait .chips-count .count-filtered, +.entity-selector-trait .chips-count .count-filtered { + font-weight: 700; +} +.target-conditions-trait .chips-count .count-separator, +.entity-selector-trait .chips-count .count-separator { + opacity: 0.6; + margin: 0 0.125rem; +} +.target-conditions-trait .chips-actions, +.entity-selector-trait .chips-actions { + display: flex; + align-items: center; + gap: 0.25rem; + margin-left: auto; +} +.target-conditions-trait .btn-chips-clear, +.entity-selector-trait .btn-chips-clear { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .btn-chips-clear:focus, +.entity-selector-trait .btn-chips-clear:focus { + outline: none; +} +.target-conditions-trait .btn-chips-clear, +.entity-selector-trait .btn-chips-clear { + display: inline-flex; + align-items: center; + flex-shrink: 0; + gap: 0.25rem; + padding: 0.2rem 0.5rem; + color: #dc3545; + font-size: 10px; + font-weight: 500; + background: rgba(220, 53, 69, 0.1); + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; + white-space: nowrap; + line-height: 1.4; +} +.target-conditions-trait .btn-chips-clear:hover, +.entity-selector-trait .btn-chips-clear:hover { + background: #dc3545; + color: #ffffff; +} +.target-conditions-trait .btn-chips-clear i, +.entity-selector-trait .btn-chips-clear i { + font-size: 9px; + flex-shrink: 0; +} +@media (max-width: 480px) { + .target-conditions-trait .btn-chips-clear .clear-text, + .entity-selector-trait .btn-chips-clear .clear-text { + display: none; + } +} +.target-conditions-trait .entity-chips, +.entity-selector-trait .entity-chips { + display: flex; + flex-wrap: wrap; + gap: 0.25rem; + padding: 0.5rem 1rem 1rem; + min-height: 40px; + max-height: 300px; + overflow-y: auto; +} +.target-conditions-trait .entity-chips:empty, +.entity-selector-trait .entity-chips:empty { + display: none; +} +.target-conditions-trait .chips-load-more, +.entity-selector-trait .chips-load-more { + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + padding: 0.5rem 1rem; + background: transparent; + border-top: 1px dashed #dee2e6; +} +.target-conditions-trait .chips-load-more .load-more-label, +.entity-selector-trait .chips-load-more .load-more-label { + font-size: 0.75rem; + color: #6c757d; +} +.target-conditions-trait .chips-load-more .load-more-select, +.target-conditions-trait .chips-load-more select.load-more-select, +.entity-selector-trait .chips-load-more .load-more-select, +.entity-selector-trait .chips-load-more select.load-more-select { + appearance: none; + padding: 0.25rem 1.75rem 0.25rem 0.5rem !important; + border: 1px solid #dee2e6 !important; + border-radius: 0.2rem !important; + background: #ffffff 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: 0.75rem !important; + font-weight: 500; + color: #25b9d7; + cursor: pointer; + transition: all 0.15s ease-in-out; + height: auto !important; + min-height: 0 !important; + line-height: 1.3 !important; +} +.target-conditions-trait .chips-load-more .load-more-select:hover, +.target-conditions-trait .chips-load-more select.load-more-select:hover, +.entity-selector-trait .chips-load-more .load-more-select:hover, +.entity-selector-trait .chips-load-more select.load-more-select:hover { + border-color: #25b9d7 !important; + background-color: rgba(37, 185, 215, 0.1) !important; +} +.target-conditions-trait .chips-load-more .load-more-select:focus, +.target-conditions-trait .chips-load-more select.load-more-select:focus, +.entity-selector-trait .chips-load-more .load-more-select:focus, +.entity-selector-trait .chips-load-more select.load-more-select:focus { + outline: none !important; + border-color: #25b9d7 !important; + box-shadow: 0 0 0 2px rgba(37, 185, 215, 0.1) !important; +} +.target-conditions-trait .chips-load-more .load-more-remaining, +.entity-selector-trait .chips-load-more .load-more-remaining { + font-size: 0.75rem; + color: #6c757d; +} +.target-conditions-trait .entity-chip, +.entity-selector-trait .entity-chip { + display: inline-flex; + align-items: center; + gap: 0.375rem; + padding: 0.25rem 0.5rem; + background: #f1f5f9; + color: #495057; + font-size: 0.75rem; + font-weight: 500; + border-radius: 50rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .entity-chip:hover, +.entity-selector-trait .entity-chip:hover { + background: #e2e8f0; +} +.target-conditions-trait .entity-chip.has-image, +.entity-selector-trait .entity-chip.has-image { + padding-left: 0.25rem; +} +.target-conditions-trait .entity-chip.chip-filtered-out, .target-conditions-trait .entity-chip.chip-paginated-out, +.entity-selector-trait .entity-chip.chip-filtered-out, +.entity-selector-trait .entity-chip.chip-paginated-out { + display: none; +} +.target-conditions-trait .chip-image, +.entity-selector-trait .chip-image { + width: 20px; + height: 20px; + object-fit: cover; + border-radius: 50%; + flex-shrink: 0; +} +.target-conditions-trait .chip-icon, +.entity-selector-trait .chip-icon { + display: flex; + align-items: center; + justify-content: center; + font-size: 12px; + color: #6c757d; + flex-shrink: 0; +} +.target-conditions-trait .chip-icon img, +.entity-selector-trait .chip-icon img { + width: 20px; + height: 20px; + object-fit: cover; + border-radius: 0.2rem; +} +.target-conditions-trait .chip-flag, +.entity-selector-trait .chip-flag { + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; +} +.target-conditions-trait .chip-flag img, +.entity-selector-trait .chip-flag img { + width: 18px; + height: 12px; + object-fit: cover; + border-radius: 2px; + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1); +} +.target-conditions-trait .chip-flag .flag-fallback, +.entity-selector-trait .chip-flag .flag-fallback { + width: 18px; + height: 12px; + display: inline-flex; + align-items: center; + justify-content: center; + background: linear-gradient(135deg, #e8eaed 0%, #dadce0 100%); + border-radius: 2px; + font-size: 10px; + color: #5f6368; +} +.target-conditions-trait .chip-preview-holidays, +.entity-selector-trait .chip-preview-holidays { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .chip-preview-holidays:focus, +.entity-selector-trait .chip-preview-holidays:focus { + outline: none; +} +.target-conditions-trait .chip-preview-holidays, +.entity-selector-trait .chip-preview-holidays { + display: flex; + align-items: center; + justify-content: center; + width: 18px; + height: 18px; + color: #25b9d7; + border-radius: 50%; + flex-shrink: 0; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .chip-preview-holidays:hover, +.entity-selector-trait .chip-preview-holidays:hover { + background: rgba(37, 185, 215, 0.15); + color: rgb(29.5119047619, 147.5595238095, 171.4880952381); +} +.target-conditions-trait .chip-preview-holidays i.material-icons, +.entity-selector-trait .chip-preview-holidays i.material-icons { + font-size: 14px !important; +} +.target-conditions-trait .chip-text, +.target-conditions-trait .chip-name, +.entity-selector-trait .chip-text, +.entity-selector-trait .chip-name { + word-break: break-word; +} +.target-conditions-trait .chip-remove, +.entity-selector-trait .chip-remove { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .chip-remove:focus, +.entity-selector-trait .chip-remove:focus { + outline: none; +} +.target-conditions-trait .chip-remove, +.entity-selector-trait .chip-remove { + display: flex; + align-items: center; + justify-content: center; + width: 16px; + height: 16px; + margin-left: 0.125rem; + color: #6c757d; + border-radius: 50%; + flex-shrink: 0; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .chip-remove:hover, +.entity-selector-trait .chip-remove:hover { + background: rgba(0, 0, 0, 0.1); + color: #dc3545; +} +.target-conditions-trait .chip-remove i, +.entity-selector-trait .chip-remove i { + font-size: 10px; +} +.target-conditions-trait .entity-chip.chip-primary, +.entity-selector-trait .entity-chip.chip-primary { + background: rgba(37, 185, 215, 0.1); + color: #25b9d7; +} +.target-conditions-trait .entity-chip.chip-primary:hover, +.entity-selector-trait .entity-chip.chip-primary:hover { + background: rgba(37, 185, 215, 0.2); +} +.target-conditions-trait .entity-chip.chip-success, +.entity-selector-trait .entity-chip.chip-success { + background: #d4edda; + color: #1e7e34; +} +.target-conditions-trait .entity-chip.chip-success:hover, +.entity-selector-trait .entity-chip.chip-success:hover { + background: rgba(112, 181, 128, 0.2); +} +.target-conditions-trait .entity-chip.chip-danger, +.entity-selector-trait .entity-chip.chip-danger { + background: #f8d7da; + color: #dc3545; +} +.target-conditions-trait .entity-chip.chip-danger:hover, +.entity-selector-trait .entity-chip.chip-danger:hover { + background: rgba(220, 53, 69, 0.2); +} +.target-conditions-trait .entity-chip.chip-warning, +.entity-selector-trait .entity-chip.chip-warning { + background: #fff3cd; + color: rgb(148, 104.192, 0); +} +.target-conditions-trait .entity-chip.chip-warning:hover, +.entity-selector-trait .entity-chip.chip-warning:hover { + background: rgba(250, 176, 0, 0.3); +} +.target-conditions-trait .entity-chip.loading, +.target-conditions-trait .entity-chip-loading, +.entity-selector-trait .entity-chip.loading, +.entity-selector-trait .entity-chip-loading { + opacity: 0.7; +} +.target-conditions-trait .entity-chip.loading .chip-remove, +.target-conditions-trait .entity-chip-loading .chip-remove, +.entity-selector-trait .entity-chip.loading .chip-remove, +.entity-selector-trait .entity-chip-loading .chip-remove { + display: none; +} +.target-conditions-trait .entity-chip.loading .chip-icon i, +.target-conditions-trait .entity-chip-loading .chip-icon i, +.entity-selector-trait .entity-chip.loading .chip-icon i, +.entity-selector-trait .entity-chip-loading .chip-icon i { + animation: spin 0.6s linear infinite; +} +.target-conditions-trait .entity-chip.chip-hidden, +.entity-selector-trait .entity-chip.chip-hidden { + display: none; +} +.target-conditions-trait .entity-chips.chips-collapsed, +.target-conditions-trait .entity-chips.chips-expanded, +.entity-selector-trait .entity-chips.chips-collapsed, +.entity-selector-trait .entity-chips.chips-expanded { + position: relative; +} +.target-conditions-trait .chips-show-more-toggle, +.entity-selector-trait .chips-show-more-toggle { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + color: #25b9d7; + font-size: 0.75rem; + font-weight: 500; + cursor: pointer; + transition: color 0.15s ease-in-out; +} +.target-conditions-trait .chips-show-more-toggle:hover, +.entity-selector-trait .chips-show-more-toggle:hover { + color: #1a9ab7; +} +.target-conditions-trait .chips-show-more-toggle i, +.entity-selector-trait .chips-show-more-toggle i { + font-size: 10px; +} +.target-conditions-trait .chips-more, +.entity-selector-trait .chips-more { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.25rem 0.5rem; + background: #e2e8f0; + color: #495057; + font-size: 0.75rem; + font-weight: 600; + border-radius: 50rem; + cursor: pointer; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .chips-more:hover, +.entity-selector-trait .chips-more:hover { + background: #cbd5e1; +} +.target-conditions-trait .chip-add-btn, +.entity-selector-trait .chip-add-btn { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .chip-add-btn:focus, +.entity-selector-trait .chip-add-btn:focus { + outline: none; +} +.target-conditions-trait .chip-add-btn, +.entity-selector-trait .chip-add-btn { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + background: transparent; + color: #25b9d7; + font-size: 0.75rem; + font-weight: 500; + border: 1px dashed #25b9d7; + border-radius: 50rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .chip-add-btn:hover, +.entity-selector-trait .chip-add-btn:hover { + background: rgba(37, 185, 215, 0.1); +} +.target-conditions-trait .chip-add-btn i, +.entity-selector-trait .chip-add-btn i { + font-size: 10px; +} +.target-conditions-trait .entity-chips.inline, +.entity-selector-trait .entity-chips.inline { + display: inline-flex; + padding: 0; + min-height: auto; +} +.target-conditions-trait .entity-chips.inline .entity-chip, +.entity-selector-trait .entity-chips.inline .entity-chip { + padding: 0.125rem 0.375rem; + font-size: 11px; +} +.target-conditions-trait .selected-chips-container, +.entity-selector-trait .selected-chips-container { + display: flex; + flex-direction: column; + gap: 0.25rem; +} +.target-conditions-trait .selected-chips-label, +.entity-selector-trait .selected-chips-label { + font-size: 0.75rem; + font-weight: 500; + color: #6c757d; +} +.target-conditions-trait .entity-chip.chip-pattern, +.entity-selector-trait .entity-chip.chip-pattern { + background: #fef3c7; + color: #92400e; + font-family: monospace; +} +.target-conditions-trait .entity-chip.chip-pattern:hover, +.entity-selector-trait .entity-chip.chip-pattern:hover { + background: #fde68a; +} +.target-conditions-trait .entity-chip.chip-pattern .chip-icon, +.entity-selector-trait .entity-chip.chip-pattern .chip-icon { + color: #d97706; +} +.target-conditions-trait .entity-chip.chip-range, +.target-conditions-trait .range-chip, +.entity-selector-trait .entity-chip.chip-range, +.entity-selector-trait .range-chip { + display: inline-flex; + align-items: center; + gap: 0.375rem; + padding: 0.25rem 0.5rem; + background: #ecfeff; + color: #0891b2; + font-size: 0.75rem; + font-weight: 500; + border-radius: 50rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .entity-chip.chip-range:hover, +.target-conditions-trait .range-chip:hover, +.entity-selector-trait .entity-chip.chip-range:hover, +.entity-selector-trait .range-chip:hover { + background: #cffafe; +} +.target-conditions-trait .range-chip-text, +.entity-selector-trait .range-chip-text { + font-family: monospace; +} +.target-conditions-trait .btn-remove-range, +.entity-selector-trait .btn-remove-range { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .btn-remove-range:focus, +.entity-selector-trait .btn-remove-range:focus { + outline: none; +} +.target-conditions-trait .btn-remove-range, +.entity-selector-trait .btn-remove-range { + display: flex; + align-items: center; + justify-content: center; + width: 16px; + height: 16px; + color: #0891b2; + border-radius: 50%; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .btn-remove-range:hover, +.entity-selector-trait .btn-remove-range:hover { + background: rgba(0, 0, 0, 0.1); + color: #dc3545; +} +.target-conditions-trait .btn-remove-range i, +.entity-selector-trait .btn-remove-range i { + font-size: 10px; +} +.target-conditions-trait .multi-range-chips, +.entity-selector-trait .multi-range-chips { + display: flex; + flex-wrap: wrap; + gap: 0.25rem; + margin-bottom: 0.25rem; +} +.target-conditions-trait .multi-range-chips:empty, +.entity-selector-trait .multi-range-chips:empty { + display: none; +} +.target-conditions-trait .pattern-chips, +.entity-selector-trait .pattern-chips { + display: flex; + flex-wrap: wrap; + gap: 0.25rem; + padding: 0.5rem 0; + min-height: 32px; +} +.target-conditions-trait .pattern-chips:empty::before, +.entity-selector-trait .pattern-chips:empty::before { + content: attr(data-placeholder); + color: #6c757d; + font-size: 0.75rem; + font-style: italic; +} +.target-conditions-trait .pattern-tag, +.entity-selector-trait .pattern-tag { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + background: #fef3c7; + color: #92400e; + font-size: 0.75rem; + font-weight: 500; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .pattern-tag:hover, +.entity-selector-trait .pattern-tag:hover { + background: #fde68a; +} +.target-conditions-trait .pattern-tag.case-sensitive .case-icon, +.entity-selector-trait .pattern-tag.case-sensitive .case-icon { + color: #70b580; + font-weight: 700; +} +.target-conditions-trait .pattern-tag.draft-tag, +.entity-selector-trait .pattern-tag.draft-tag { + background: #ffffff; + border: 1px solid #dee2e6; + padding: 0; + flex: 1; + min-width: 150px; +} +.target-conditions-trait .pattern-tag.draft-tag:hover, +.entity-selector-trait .pattern-tag.draft-tag:hover { + background: #ffffff; +} +.target-conditions-trait .pattern-tag.draft-tag .pattern-input, +.entity-selector-trait .pattern-tag.draft-tag .pattern-input { + flex: 1; + min-width: 100px; + padding: 0.375rem; + border: 0; + background: transparent; + font-size: 0.875rem; + font-family: inherit; +} +.target-conditions-trait .pattern-tag.draft-tag .pattern-input:focus, +.entity-selector-trait .pattern-tag.draft-tag .pattern-input:focus { + outline: none; +} +.target-conditions-trait .pattern-tag.draft-tag .pattern-input::placeholder, +.entity-selector-trait .pattern-tag.draft-tag .pattern-input::placeholder { + color: #6c757d; + font-style: italic; +} +.target-conditions-trait .pattern-tag-text, +.entity-selector-trait .pattern-tag-text { + font-family: monospace; + max-width: 200px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.target-conditions-trait .btn-toggle-case, +.entity-selector-trait .btn-toggle-case { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .btn-toggle-case:focus, +.entity-selector-trait .btn-toggle-case:focus { + outline: none; +} +.target-conditions-trait .btn-toggle-case, +.entity-selector-trait .btn-toggle-case { + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + color: #6c757d; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .btn-toggle-case:hover, +.entity-selector-trait .btn-toggle-case:hover { + background: rgba(0, 0, 0, 0.1); +} +.target-conditions-trait .case-icon, +.entity-selector-trait .case-icon { + font-size: 11px; + font-weight: 600; + font-family: monospace; +} +.target-conditions-trait .btn-remove-pattern, +.entity-selector-trait .btn-remove-pattern { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .btn-remove-pattern:focus, +.entity-selector-trait .btn-remove-pattern:focus { + outline: none; +} +.target-conditions-trait .btn-remove-pattern, +.entity-selector-trait .btn-remove-pattern { + display: flex; + align-items: center; + justify-content: center; + width: 18px; + height: 18px; + color: #d97706; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .btn-remove-pattern:hover, +.entity-selector-trait .btn-remove-pattern:hover { + background: rgba(0, 0, 0, 0.1); + color: #dc3545; +} +.target-conditions-trait .btn-remove-pattern i, +.entity-selector-trait .btn-remove-pattern i { + font-size: 10px; +} +.target-conditions-trait .btn-add-pattern, +.entity-selector-trait .btn-add-pattern { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .btn-add-pattern:focus, +.entity-selector-trait .btn-add-pattern:focus { + outline: none; +} +.target-conditions-trait .btn-add-pattern, +.entity-selector-trait .btn-add-pattern { + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + color: #25b9d7; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .btn-add-pattern:hover, +.entity-selector-trait .btn-add-pattern:hover { + background: rgba(37, 185, 215, 0.1); +} +.target-conditions-trait .btn-add-pattern i, +.entity-selector-trait .btn-add-pattern i { + font-size: 12px; +} +.target-conditions-trait .pattern-match-count, +.entity-selector-trait .pattern-match-count { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0 0.375rem; + color: #6c757d; + font-size: 0.75rem; + cursor: pointer; +} +.target-conditions-trait .pattern-match-count.count-zero, +.entity-selector-trait .pattern-match-count.count-zero { + color: #fab000; +} +.target-conditions-trait .pattern-match-count.count-found, +.entity-selector-trait .pattern-match-count.count-found { + color: #70b580; +} +.target-conditions-trait .pattern-match-count .count-value, +.entity-selector-trait .pattern-match-count .count-value { + font-weight: 600; +} +.target-conditions-trait .pattern-input-row, +.entity-selector-trait .pattern-input-row { + display: flex; + align-items: stretch; + gap: 0.25rem; +} + +.holiday-preview-popover { + position: absolute; + z-index: 10001; + width: 320px; + max-width: 90vw; + background: #ffffff; + border-radius: 0.3rem; + box-shadow: 0 1.5rem 4rem rgba(0, 0, 0, 0.2); + overflow: hidden; +} +.holiday-preview-popover .popover-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.5rem; + padding: 0.5rem 1rem; + background: #f8f9fa; + border-bottom: 1px solid #dee2e6; +} +.holiday-preview-popover .popover-title { + display: flex; + align-items: center; + gap: 0.5rem; + font-size: 0.875rem; + font-weight: 600; + color: #212529; +} +.holiday-preview-popover .popover-flag { + border-radius: 2px; + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1); +} +.holiday-preview-popover .popover-close { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.holiday-preview-popover .popover-close:focus { + outline: none; +} +.holiday-preview-popover .popover-close { + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + color: #6c757d; + border-radius: 0.25rem; + transition: all 0.15s ease-in-out; +} +.holiday-preview-popover .popover-close:hover { + background: #e2e8f0; + color: #495057; +} +.holiday-preview-popover .popover-close i.material-icons { + font-size: 18px !important; +} +.holiday-preview-popover .popover-body { + max-height: 350px; + overflow-y: auto; + padding: 0.5rem; +} +.holiday-preview-popover .popover-body::-webkit-scrollbar { + width: 6px; + height: 6px; +} +.holiday-preview-popover .popover-body::-webkit-scrollbar-track { + background: #f8f9fa; + border-radius: 3px; +} +.holiday-preview-popover .popover-body::-webkit-scrollbar-thumb { + background: #dee2e6; + border-radius: 3px; +} +.holiday-preview-popover .popover-body::-webkit-scrollbar-thumb:hover { + background: #ced4da; +} +.holiday-preview-popover .holiday-preview-loading { + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + padding: 2rem 0; + color: #6c757d; + font-size: 0.875rem; +} +.holiday-preview-popover .holiday-preview-loading i.material-icons { + font-size: 20px !important; +} +.holiday-preview-popover .holiday-preview-loading .es-spin { + animation: spin 1s linear infinite; +} +.holiday-preview-popover .holiday-preview-empty { + text-align: center; + padding: 2rem 0; + color: #6c757d; +} +.holiday-preview-popover .holiday-preview-empty i.material-icons { + font-size: 48px !important; + opacity: 0.4; + margin-bottom: 0.5rem; + display: block; +} +.holiday-preview-popover .holiday-preview-empty p { + margin: 0; + font-size: 0.875rem; +} +.holiday-preview-popover .holiday-list { + display: flex; + flex-direction: column; + gap: 0.25rem; +} +.holiday-preview-popover .holiday-item { + display: flex; + align-items: flex-start; + gap: 1rem; + padding: 0.5rem 1rem; + background: #f8fafc; + border-radius: 0.25rem; + border-left: 3px solid #70b580; +} +.holiday-preview-popover .holiday-item.holiday-type-bank, .holiday-preview-popover .holiday-item.holiday-type-bank-holiday { + border-left-color: #17a2b8; +} +.holiday-preview-popover .holiday-item.holiday-type-observance { + border-left-color: #fab000; +} +.holiday-preview-popover .holiday-item.holiday-type-regional, .holiday-preview-popover .holiday-item.holiday-type-local-holiday { + border-left-color: #8b5cf6; +} +.holiday-preview-popover .holiday-date { + flex-shrink: 0; + min-width: 80px; +} +.holiday-preview-popover .holiday-date .holiday-day { + display: block; + font-size: 0.875rem; + font-weight: 600; + color: #212529; +} +.holiday-preview-popover .holiday-date .holiday-weekday { + display: block; + font-size: 0.75rem; + color: #6c757d; +} +.holiday-preview-popover .holiday-info { + flex: 1; + min-width: 0; +} +.holiday-preview-popover .holiday-country-flag { + vertical-align: middle; + margin-right: 0.25rem; + border-radius: 2px; + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1); +} +.holiday-preview-popover .holiday-name { + display: inline; + font-size: 0.875rem; + color: #212529; + word-wrap: break-word; +} +.holiday-preview-popover .holiday-type-badge { + display: inline-block; + margin-left: 0.5rem; + padding: 0.125rem 0.375rem; + font-size: 10px; + font-weight: 500; + text-transform: capitalize; + background: #e2e8f0; + color: #495057; + border-radius: 0.2rem; + vertical-align: middle; +} +.holiday-preview-popover .holiday-preview-note { + margin-top: 1rem; + font-size: 0.75rem; + color: #6c757d; + text-align: center; +} +.holiday-preview-popover .popover-filter { + display: flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 1rem; + border-bottom: 1px solid #dee2e6; + background: #f8fafc; +} +.holiday-preview-popover .popover-filter i.material-icons { + font-size: 18px !important; + color: #6c757d; +} +.holiday-preview-popover .popover-filter .holiday-filter-input { + flex: 1; + border: none; + background: transparent; + font-size: 0.875rem; + color: #212529; + outline: none; + padding: 0.25rem 0; +} +.holiday-preview-popover .popover-filter .holiday-filter-input::placeholder { + color: #6c757d; +} + +@keyframes spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} +#content.bootstrap .target-conditions-trait .chips-wrapper .chips-toolbar input[type=text].chips-search-input.chips-search-input, +#content.bootstrap .entity-selector-trait .chips-wrapper .chips-toolbar input[type=text].chips-search-input.chips-search-input, +#content .bootstrap .target-conditions-trait .chips-wrapper .chips-toolbar input[type=text].chips-search-input.chips-search-input, +#content .bootstrap .entity-selector-trait .chips-wrapper .chips-toolbar input[type=text].chips-search-input.chips-search-input, +.bootstrap #content .target-conditions-trait .chips-wrapper .chips-toolbar input[type=text].chips-search-input.chips-search-input, +.bootstrap #content .entity-selector-trait .chips-wrapper .chips-toolbar input[type=text].chips-search-input.chips-search-input { + all: unset; + display: block; + flex: 1 1 auto; + min-width: 80px; + width: auto; + height: auto; + padding: 0.2rem 0.5rem 0.2rem 1.5rem; + background: #ffffff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.35-4.35'/%3E%3C/svg%3E") no-repeat 0.375rem center; + background-size: 10px; + border: 1px solid #cbd5e1; + border-radius: 0.2rem; + font-size: 11px; + line-height: 1.4; + color: #212529; + box-sizing: border-box; + transition: all 0.15s ease-in-out; +} +#content.bootstrap .target-conditions-trait .chips-wrapper .chips-toolbar input[type=text].chips-search-input.chips-search-input::placeholder, +#content.bootstrap .entity-selector-trait .chips-wrapper .chips-toolbar input[type=text].chips-search-input.chips-search-input::placeholder, +#content .bootstrap .target-conditions-trait .chips-wrapper .chips-toolbar input[type=text].chips-search-input.chips-search-input::placeholder, +#content .bootstrap .entity-selector-trait .chips-wrapper .chips-toolbar input[type=text].chips-search-input.chips-search-input::placeholder, +.bootstrap #content .target-conditions-trait .chips-wrapper .chips-toolbar input[type=text].chips-search-input.chips-search-input::placeholder, +.bootstrap #content .entity-selector-trait .chips-wrapper .chips-toolbar input[type=text].chips-search-input.chips-search-input::placeholder { + color: #6c757d; + font-size: 11px; +} +#content.bootstrap .target-conditions-trait .chips-wrapper .chips-toolbar input[type=text].chips-search-input.chips-search-input:focus, +#content.bootstrap .entity-selector-trait .chips-wrapper .chips-toolbar input[type=text].chips-search-input.chips-search-input:focus, +#content .bootstrap .target-conditions-trait .chips-wrapper .chips-toolbar input[type=text].chips-search-input.chips-search-input:focus, +#content .bootstrap .entity-selector-trait .chips-wrapper .chips-toolbar input[type=text].chips-search-input.chips-search-input:focus, +.bootstrap #content .target-conditions-trait .chips-wrapper .chips-toolbar input[type=text].chips-search-input.chips-search-input:focus, +.bootstrap #content .entity-selector-trait .chips-wrapper .chips-toolbar input[type=text].chips-search-input.chips-search-input:focus { + outline: none; + border-color: #25b9d7; + box-shadow: 0 0 0 2px rgba(37, 185, 215, 0.1); +} +#content.bootstrap .target-conditions-trait .chips-wrapper .chips-toolbar select.chips-sort-select.chips-sort-select, +#content.bootstrap .entity-selector-trait .chips-wrapper .chips-toolbar select.chips-sort-select.chips-sort-select, +#content .bootstrap .target-conditions-trait .chips-wrapper .chips-toolbar select.chips-sort-select.chips-sort-select, +#content .bootstrap .entity-selector-trait .chips-wrapper .chips-toolbar select.chips-sort-select.chips-sort-select, +.bootstrap #content .target-conditions-trait .chips-wrapper .chips-toolbar select.chips-sort-select.chips-sort-select, +.bootstrap #content .entity-selector-trait .chips-wrapper .chips-toolbar select.chips-sort-select.chips-sort-select { + all: unset; + flex: 0 0 auto; + padding: 0.2rem 1.25rem 0.2rem 0.5rem; + border: 1px solid #dee2e6; + border-radius: 0.2rem; + background: #ffffff 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.375rem center; + background-size: 8px; + font-size: 10px; + line-height: 1.4; + color: #495057; + cursor: pointer; + box-sizing: border-box; + white-space: nowrap; + height: auto; +} +#content.bootstrap .target-conditions-trait .chips-wrapper .chips-toolbar select.chips-sort-select.chips-sort-select:hover, +#content.bootstrap .entity-selector-trait .chips-wrapper .chips-toolbar select.chips-sort-select.chips-sort-select:hover, +#content .bootstrap .target-conditions-trait .chips-wrapper .chips-toolbar select.chips-sort-select.chips-sort-select:hover, +#content .bootstrap .entity-selector-trait .chips-wrapper .chips-toolbar select.chips-sort-select.chips-sort-select:hover, +.bootstrap #content .target-conditions-trait .chips-wrapper .chips-toolbar select.chips-sort-select.chips-sort-select:hover, +.bootstrap #content .entity-selector-trait .chips-wrapper .chips-toolbar select.chips-sort-select.chips-sort-select:hover { + border-color: #25b9d7; +} +#content.bootstrap .target-conditions-trait .chips-wrapper .chips-toolbar select.chips-sort-select.chips-sort-select:focus, +#content.bootstrap .entity-selector-trait .chips-wrapper .chips-toolbar select.chips-sort-select.chips-sort-select:focus, +#content .bootstrap .target-conditions-trait .chips-wrapper .chips-toolbar select.chips-sort-select.chips-sort-select:focus, +#content .bootstrap .entity-selector-trait .chips-wrapper .chips-toolbar select.chips-sort-select.chips-sort-select:focus, +.bootstrap #content .target-conditions-trait .chips-wrapper .chips-toolbar select.chips-sort-select.chips-sort-select:focus, +.bootstrap #content .entity-selector-trait .chips-wrapper .chips-toolbar select.chips-sort-select.chips-sort-select:focus { + outline: none; + border-color: #25b9d7; + box-shadow: 0 0 0 2px rgba(37, 185, 215, 0.1); +} + +/** + * Entity Selector Styles + * @package prestashop-entity-selector + * @version 2.0.0 + * + * Compiles to: assets/css/admin/entity-selector.css + */ +/** + * Groups Component + * Selection groups, include/exclude sections, method selectors + */ +.target-conditions-trait .target-group, +.entity-selector-trait .target-group { + background: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.3rem; + overflow: hidden; +} +.target-conditions-trait .target-group-header, +.entity-selector-trait .target-group-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; + padding: 0.5rem 1rem; + background: #f8f9fa; + border-bottom: 1px solid #dee2e6; +} +.target-conditions-trait .target-group-title, +.entity-selector-trait .target-group-title { + display: flex; + align-items: center; + gap: 0.5rem; + font-size: 0.875rem; + font-weight: 600; + color: #212529; +} +.target-conditions-trait .target-group-title .group-number, +.entity-selector-trait .target-group-title .group-number { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 20px; + height: 20px; + padding: 0 0.25rem; + background: #25b9d7; + color: #ffffff; + font-size: 0.75rem; + font-weight: 700; + border-radius: 50rem; +} +.target-conditions-trait .target-group-actions, +.entity-selector-trait .target-group-actions { + display: flex; + align-items: center; + gap: 0.25rem; +} +.target-conditions-trait .group-action-btn, +.entity-selector-trait .group-action-btn { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .group-action-btn:focus, +.entity-selector-trait .group-action-btn:focus { + outline: none; +} +.target-conditions-trait .group-action-btn, +.entity-selector-trait .group-action-btn { + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + color: #6c757d; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .group-action-btn:hover, +.entity-selector-trait .group-action-btn:hover { + background: #e2e8f0; + color: #495057; +} +.target-conditions-trait .group-action-btn.danger:hover, +.entity-selector-trait .group-action-btn.danger:hover { + background: #f8d7da; + color: #dc3545; +} +.target-conditions-trait .target-group-body, +.target-conditions-trait .group-body, +.entity-selector-trait .target-group-body, +.entity-selector-trait .group-body { + padding: 1rem; +} +.target-conditions-trait .include-section, +.entity-selector-trait .include-section { + margin-bottom: 1rem; +} +.target-conditions-trait .section-label, +.entity-selector-trait .section-label { + display: flex; + align-items: center; + gap: 0.25rem; + margin-bottom: 0.5rem; + font-size: 0.75rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.05em; +} +.target-conditions-trait .section-label.label-include, +.entity-selector-trait .section-label.label-include { + color: #1e7e34; +} +.target-conditions-trait .section-label.label-include i, +.entity-selector-trait .section-label.label-include i { + color: #70b580; +} +.target-conditions-trait .section-label.label-exclude, +.entity-selector-trait .section-label.label-exclude { + color: #dc3545; +} +.target-conditions-trait .section-label.label-exclude i, +.entity-selector-trait .section-label.label-exclude i { + color: #dc3545; +} +.target-conditions-trait .method-selector, +.entity-selector-trait .method-selector { + display: flex; + align-items: center; + gap: 0.5rem; + margin-bottom: 0.5rem; +} +.target-conditions-trait .method-selector-wrapper, +.entity-selector-trait .method-selector-wrapper { + flex: 1; + position: relative; +} +.target-conditions-trait .method-select, +.entity-selector-trait .method-select { + width: 100%; + padding: 0.5rem 1rem; + font-size: 0.875rem; + line-height: 1.5; + color: #212529; + background-color: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +.target-conditions-trait .method-select:focus, +.entity-selector-trait .method-select:focus { + border-color: #25b9d7; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(37, 185, 215, 0.25); +} +.target-conditions-trait .method-select::placeholder, +.entity-selector-trait .method-select::placeholder { + color: #adb5bd; +} +.target-conditions-trait .method-select, +.entity-selector-trait .method-select { + padding-right: 2rem; + cursor: pointer; + appearance: none; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E"); + background-position: right 0.5rem center; + background-repeat: no-repeat; + background-size: 1.5em 1.5em; +} +.target-conditions-trait .method-help-btn, +.entity-selector-trait .method-help-btn { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .method-help-btn:focus, +.entity-selector-trait .method-help-btn:focus { + outline: none; +} +.target-conditions-trait .method-help-btn, +.entity-selector-trait .method-help-btn { + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + color: #6c757d; + border-radius: 50rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .method-help-btn:hover, +.entity-selector-trait .method-help-btn:hover { + background: #f1f5f9; + color: #25b9d7; +} +.target-conditions-trait .value-picker, +.entity-selector-trait .value-picker { + position: relative; +} +.target-conditions-trait .value-picker-trigger, +.entity-selector-trait .value-picker-trigger { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .value-picker-trigger:focus, +.entity-selector-trait .value-picker-trigger:focus { + outline: none; +} +.target-conditions-trait .value-picker-trigger, +.entity-selector-trait .value-picker-trigger { + display: flex; + align-items: center; + gap: 0.5rem; + width: 100%; + padding: 0.5rem 1rem; + background: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + color: #6c757d; + font-size: 0.875rem; + text-align: left; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .value-picker-trigger:hover, +.entity-selector-trait .value-picker-trigger:hover { + border-color: #cbd5e1; +} +.target-conditions-trait .value-picker-trigger:focus, +.entity-selector-trait .value-picker-trigger:focus { + border-color: #25b9d7; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(37, 185, 215, 0.25); +} +.target-conditions-trait .value-picker-trigger i, +.entity-selector-trait .value-picker-trigger i { + color: #adb5bd; +} +.target-conditions-trait .pattern-input-wrapper, +.entity-selector-trait .pattern-input-wrapper { + position: relative; +} +.target-conditions-trait .pattern-input, +.entity-selector-trait .pattern-input { + width: 100%; + padding: 0.5rem 1rem; + font-size: 0.875rem; + line-height: 1.5; + color: #212529; + background-color: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +.target-conditions-trait .pattern-input:focus, +.entity-selector-trait .pattern-input:focus { + border-color: #25b9d7; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(37, 185, 215, 0.25); +} +.target-conditions-trait .pattern-input::placeholder, +.entity-selector-trait .pattern-input::placeholder { + color: #adb5bd; +} +.target-conditions-trait .pattern-input, +.entity-selector-trait .pattern-input { + font-family: monospace; +} +.target-conditions-trait .pattern-add-btn, +.entity-selector-trait .pattern-add-btn { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .pattern-add-btn:focus, +.entity-selector-trait .pattern-add-btn:focus { + outline: none; +} +.target-conditions-trait .pattern-add-btn, +.entity-selector-trait .pattern-add-btn { + position: absolute; + right: 0.25rem; + top: 50%; + transform: translateY(-50%); + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + color: #25b9d7; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .pattern-add-btn:hover, +.entity-selector-trait .pattern-add-btn:hover { + background: rgba(37, 185, 215, 0.1); +} +.target-conditions-trait .multi-range-container, +.entity-selector-trait .multi-range-container { + display: flex; + flex-direction: column; + gap: 0.5rem; +} +.target-conditions-trait .range-row, +.entity-selector-trait .range-row { + display: flex; + align-items: center; + gap: 0.5rem; +} +.target-conditions-trait .range-input, +.entity-selector-trait .range-input { + width: 100%; + padding: 0.5rem 1rem; + font-size: 0.875rem; + line-height: 1.5; + color: #212529; + background-color: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +.target-conditions-trait .range-input:focus, +.entity-selector-trait .range-input:focus { + border-color: #25b9d7; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(37, 185, 215, 0.25); +} +.target-conditions-trait .range-input::placeholder, +.entity-selector-trait .range-input::placeholder { + color: #adb5bd; +} +.target-conditions-trait .range-input, +.entity-selector-trait .range-input { + width: 100px; + text-align: center; +} +.target-conditions-trait .range-separator, +.entity-selector-trait .range-separator { + color: #6c757d; + font-size: 0.875rem; +} +.target-conditions-trait .range-remove-btn, +.entity-selector-trait .range-remove-btn { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .range-remove-btn:focus, +.entity-selector-trait .range-remove-btn:focus { + outline: none; +} +.target-conditions-trait .range-remove-btn, +.entity-selector-trait .range-remove-btn { + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + color: #6c757d; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .range-remove-btn:hover, +.entity-selector-trait .range-remove-btn:hover { + background: #f8d7da; + color: #dc3545; +} +.target-conditions-trait .range-add-btn, +.entity-selector-trait .range-add-btn { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .range-add-btn:focus, +.entity-selector-trait .range-add-btn:focus { + outline: none; +} +.target-conditions-trait .range-add-btn, +.entity-selector-trait .range-add-btn { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + color: #25b9d7; + font-size: 0.75rem; + font-weight: 500; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .range-add-btn:hover, +.entity-selector-trait .range-add-btn:hover { + background: rgba(37, 185, 215, 0.1); +} +.target-conditions-trait .multi-select-tiles, +.entity-selector-trait .multi-select-tiles { + display: flex; + flex-wrap: wrap; + gap: 0.25rem; +} +.target-conditions-trait .multi-select-tile, +.entity-selector-trait .multi-select-tile { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .multi-select-tile:focus, +.entity-selector-trait .multi-select-tile:focus { + outline: none; +} +.target-conditions-trait .multi-select-tile, +.entity-selector-trait .multi-select-tile { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.375rem 0.75rem; + background: #f1f5f9; + color: #495057; + font-size: 0.75rem; + font-weight: 500; + border: 1px solid transparent; + border-radius: 50rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .multi-select-tile:hover, +.entity-selector-trait .multi-select-tile:hover { + background: #e2e8f0; +} +.target-conditions-trait .multi-select-tile.selected, +.entity-selector-trait .multi-select-tile.selected { + background: rgba(37, 185, 215, 0.1); + color: #25b9d7; + border-color: #25b9d7; +} +.target-conditions-trait .exclude-section, +.entity-selector-trait .exclude-section { + margin-top: 1rem; + padding-top: 1rem; + border-top: 1px dashed #dee2e6; +} +.target-conditions-trait .exclude-rows, +.entity-selector-trait .exclude-rows { + display: flex; + flex-direction: column; + gap: 0.5rem; +} +.target-conditions-trait .exclude-row-content, +.entity-selector-trait .exclude-row-content { + flex: 1; +} +.target-conditions-trait .exclude-remove-btn, +.entity-selector-trait .exclude-remove-btn { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .exclude-remove-btn:focus, +.entity-selector-trait .exclude-remove-btn:focus { + outline: none; +} +.target-conditions-trait .exclude-remove-btn, +.entity-selector-trait .exclude-remove-btn { + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + color: #6c757d; + border-radius: 0.2rem; + flex-shrink: 0; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .exclude-remove-btn:hover, +.entity-selector-trait .exclude-remove-btn:hover { + background: #f8d7da; + color: #dc3545; +} +.target-conditions-trait .add-exclude-btn, +.entity-selector-trait .add-exclude-btn { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .add-exclude-btn:focus, +.entity-selector-trait .add-exclude-btn:focus { + outline: none; +} +.target-conditions-trait .add-exclude-btn, +.entity-selector-trait .add-exclude-btn { + display: inline-flex; + align-items: center; + gap: 0.25rem; + margin-top: 0.5rem; + padding: 0.25rem 0.5rem; + color: #dc3545; + font-size: 0.75rem; + font-weight: 500; + border: 1px dashed #dc3545; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .add-exclude-btn:hover, +.entity-selector-trait .add-exclude-btn:hover { + background: #f8d7da; +} +.target-conditions-trait .btn-add-group, +.entity-selector-trait .btn-add-group { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .btn-add-group:focus, +.entity-selector-trait .btn-add-group:focus { + outline: none; +} +.target-conditions-trait .btn-add-group, +.entity-selector-trait .btn-add-group { + display: inline-flex; + align-items: center; + gap: 0.375rem; + padding: 0.5rem 0.875rem; + color: #25b9d7; + font-size: 0.875rem; + font-weight: 500; + background: rgba(37, 185, 215, 0.05); + border: 1px dashed #25b9d7; + border-radius: 0.375rem; + cursor: pointer; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .btn-add-group:hover, +.entity-selector-trait .btn-add-group:hover { + background: rgba(37, 185, 215, 0.1); +} +.target-conditions-trait .btn-add-group i, +.entity-selector-trait .btn-add-group i { + font-size: 12px; +} +.target-conditions-trait .block-footer, +.entity-selector-trait .block-footer { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 1rem; + border-top: 1px solid #dee2e6; +} +.target-conditions-trait .block-body, +.entity-selector-trait .block-body { + padding: 0; +} +.target-conditions-trait .groups-container, +.entity-selector-trait .groups-container { + padding: 1rem; +} +.target-conditions-trait .groups-empty-state, +.entity-selector-trait .groups-empty-state { + display: flex; + align-items: center; + justify-content: center; + padding: 2rem; + color: #6c757d; + font-size: 0.875rem; +} +.target-conditions-trait .selection-group, +.entity-selector-trait .selection-group { + background: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.3rem; + margin-bottom: 1rem; +} +.target-conditions-trait .selection-group:last-child, +.entity-selector-trait .selection-group:last-child { + margin-bottom: 0; +} +.target-conditions-trait .selection-group.collapsed .group-body, +.entity-selector-trait .selection-group.collapsed .group-body { + display: none; +} +.target-conditions-trait .selection-group.collapsed .group-collapse-toggle i, +.entity-selector-trait .selection-group.collapsed .group-collapse-toggle i { + transform: rotate(-90deg); +} +.target-conditions-trait .group-header, +.entity-selector-trait .group-header { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 1rem; + background: #f8f9fa; + border-bottom: 1px solid #dee2e6; + border-radius: 0.3rem 0.3rem 0 0; + cursor: pointer; +} +.target-conditions-trait .group-header.group-header-single, +.entity-selector-trait .group-header.group-header-single { + padding: 0.25rem 1rem; + background: transparent; + border-bottom: none; +} +.target-conditions-trait .group-collapse-toggle, +.entity-selector-trait .group-collapse-toggle { + display: flex; + align-items: center; + justify-content: center; + width: 24px; + color: #6c757d; +} +.target-conditions-trait .group-collapse-toggle i, +.entity-selector-trait .group-collapse-toggle i { + font-size: 20px !important; + transition: transform 0.15s ease-in-out; +} +.target-conditions-trait .group-name-wrapper, +.entity-selector-trait .group-name-wrapper { + flex: 1; + display: flex; + align-items: center; + gap: 0.5rem; +} +.target-conditions-trait .group-name-input, +.entity-selector-trait .group-name-input { + flex: 1; + padding: 0.25rem 0.5rem; + font-size: 0.875rem; + font-weight: 600; + color: #212529; + background: transparent; + border: 1px solid transparent; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .group-name-input:hover, .target-conditions-trait .group-name-input:focus, +.entity-selector-trait .group-name-input:hover, +.entity-selector-trait .group-name-input:focus { + background: #ffffff; + border-color: #dee2e6; + outline: none; +} +.target-conditions-trait .group-name-input::placeholder, +.entity-selector-trait .group-name-input::placeholder { + color: #6c757d; + font-weight: 500; +} +.target-conditions-trait .group-count-badge, +.entity-selector-trait .group-count-badge { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.25rem; + min-width: 20px; + height: 20px; + padding: 0 0.5rem; + background: #25b9d7; + color: #ffffff; + font-size: 0.75rem; + font-weight: 600; + border-radius: 50rem; + cursor: pointer; + transition: all 0.15s ease-in-out; + flex-shrink: 0; +} +.target-conditions-trait .group-count-badge:hover, +.entity-selector-trait .group-count-badge:hover { + transform: scale(1.05); + box-shadow: 0 2px 8px rgba(37, 185, 215, 0.4); +} +.target-conditions-trait .group-count-badge:focus, +.entity-selector-trait .group-count-badge:focus { + outline: none; + box-shadow: 0 0 0 2px rgba(37, 185, 215, 0.3), 0 2px 8px rgba(37, 185, 215, 0.4); +} +.target-conditions-trait .group-count-badge.loading, +.entity-selector-trait .group-count-badge.loading { + cursor: wait; +} +.target-conditions-trait .group-count-badge.loading i, +.entity-selector-trait .group-count-badge.loading i { + font-size: 10px; + animation: spin 0.6s linear infinite; +} +.target-conditions-trait .group-count-badge.loading:hover, +.entity-selector-trait .group-count-badge.loading:hover { + transform: none; + box-shadow: none; +} +.target-conditions-trait .group-count-badge.inactive, .target-conditions-trait .group-count-badge.no-matches, +.entity-selector-trait .group-count-badge.inactive, +.entity-selector-trait .group-count-badge.no-matches { + background: #94a3b8; + cursor: default; +} +.target-conditions-trait .group-count-badge.inactive:hover, .target-conditions-trait .group-count-badge.no-matches:hover, +.entity-selector-trait .group-count-badge.inactive:hover, +.entity-selector-trait .group-count-badge.no-matches:hover { + transform: none; + box-shadow: none; +} +.target-conditions-trait .group-count-badge.popover-open, +.entity-selector-trait .group-count-badge.popover-open { + background: rgb(29.5119047619, 147.5595238095, 171.4880952381); + box-shadow: 0 2px 8px rgba(37, 185, 215, 0.4); +} +.target-conditions-trait .group-count-badge i, +.entity-selector-trait .group-count-badge i { + font-size: 10px; + line-height: 1; + opacity: 0.8; +} +.target-conditions-trait .group-count-badge:hover i, +.entity-selector-trait .group-count-badge:hover i { + opacity: 1; +} +.target-conditions-trait .group-count-badge .preview-count, +.entity-selector-trait .group-count-badge .preview-count { + font-weight: 700; +} +.target-conditions-trait .btn-remove-group, +.entity-selector-trait .btn-remove-group { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .btn-remove-group:focus, +.entity-selector-trait .btn-remove-group:focus { + outline: none; +} +.target-conditions-trait .btn-remove-group, +.entity-selector-trait .btn-remove-group { + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + color: #6c757d; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .btn-remove-group:hover, +.entity-selector-trait .btn-remove-group:hover { + background: #f8d7da; + color: #dc3545; +} +.target-conditions-trait .group-include, +.entity-selector-trait .group-include { + margin-bottom: 1rem; + padding: 0.5rem; + background: rgba(112, 181, 128, 0.03); + border: 1px solid rgba(112, 181, 128, 0.2); + border-radius: 0.25rem; +} +.target-conditions-trait .section-row, +.entity-selector-trait .section-row { + display: flex; + flex-direction: column; + gap: 0.5rem; +} +.target-conditions-trait .method-selector-wrapper, +.entity-selector-trait .method-selector-wrapper { + display: flex; + align-items: center; + gap: 0.5rem; +} +.target-conditions-trait .method-info-placeholder, +.entity-selector-trait .method-info-placeholder { + display: flex; + align-items: center; + min-width: 20px; +} +.target-conditions-trait .include-method-select, +.target-conditions-trait .exclude-method-select, +.entity-selector-trait .include-method-select, +.entity-selector-trait .exclude-method-select { + flex: 1; + width: 100%; + padding: 0.5rem 1rem; + font-size: 0.875rem; + line-height: 1.5; + color: #212529; + background-color: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +.target-conditions-trait .include-method-select:focus, +.target-conditions-trait .exclude-method-select:focus, +.entity-selector-trait .include-method-select:focus, +.entity-selector-trait .exclude-method-select:focus { + border-color: #25b9d7; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(37, 185, 215, 0.25); +} +.target-conditions-trait .include-method-select::placeholder, +.target-conditions-trait .exclude-method-select::placeholder, +.entity-selector-trait .include-method-select::placeholder, +.entity-selector-trait .exclude-method-select::placeholder { + color: #adb5bd; +} +.target-conditions-trait .include-method-select, +.target-conditions-trait .exclude-method-select, +.entity-selector-trait .include-method-select, +.entity-selector-trait .exclude-method-select { + cursor: pointer; +} +.target-conditions-trait .selector-locked .include-method-select, +.entity-selector-trait .selector-locked .include-method-select { + opacity: 0.7; + cursor: not-allowed; +} +.target-conditions-trait .lock-indicator, +.entity-selector-trait .lock-indicator { + display: inline-flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + color: #fab000; + cursor: help; +} +.target-conditions-trait .lock-indicator i, +.entity-selector-trait .lock-indicator i { + font-size: 16px !important; +} +.target-conditions-trait .lock-indicator .mpr-tooltip, +.entity-selector-trait .lock-indicator .mpr-tooltip { + display: none; + position: absolute; + bottom: calc(100% + 8px); + left: 50%; + transform: translateX(-50%); + padding: 0.25rem 0.5rem; + background: #1e293b; + color: #ffffff; + font-size: 0.75rem; + font-weight: 400; + white-space: nowrap; + border-radius: 0.2rem; + z-index: 100; +} +.target-conditions-trait .lock-indicator:hover .mpr-tooltip, +.entity-selector-trait .lock-indicator:hover .mpr-tooltip { + display: block; +} +.target-conditions-trait .group-excludes, +.entity-selector-trait .group-excludes { + margin-top: 1rem; +} +.target-conditions-trait .except-separator, +.entity-selector-trait .except-separator { + display: flex; + align-items: center; + gap: 0.5rem; + margin: 0 0 0.5rem 0; +} +.target-conditions-trait .except-separator::before, .target-conditions-trait .except-separator::after, +.entity-selector-trait .except-separator::before, +.entity-selector-trait .except-separator::after { + content: ""; + flex: 1; + height: 1px; + background: rgba(220, 53, 69, 0.3); +} +.target-conditions-trait .except-label, +.entity-selector-trait .except-label { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.75rem; + background: #f8d7da; + color: #dc3545; + font-size: 0.75rem; + font-weight: 600; + border-radius: 50rem; + white-space: nowrap; + flex-shrink: 0; +} +.target-conditions-trait .except-label i, +.entity-selector-trait .except-label i { + font-size: 12px !important; +} +.target-conditions-trait .exclude-rows-container, +.entity-selector-trait .exclude-rows-container { + display: flex; + flex-direction: column; + gap: 0.5rem; +} +.target-conditions-trait .exclude-row, +.entity-selector-trait .exclude-row { + display: flex; + flex-direction: column; + padding: 0.5rem; + background: rgba(220, 53, 69, 0.03); + border: 1px solid rgba(220, 53, 69, 0.15); + border-radius: 0.25rem; +} +.target-conditions-trait .exclude-row .value-picker, +.entity-selector-trait .exclude-row .value-picker { + width: 100%; + margin-top: 0.5rem; +} +.target-conditions-trait .exclude-header-row, +.entity-selector-trait .exclude-header-row { + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.5rem; + width: 100%; +} +.target-conditions-trait .exclude-header-row .method-selector-wrapper, +.entity-selector-trait .exclude-header-row .method-selector-wrapper { + flex: 1; +} +.target-conditions-trait .exclude-header-row .btn-remove-exclude-row, +.entity-selector-trait .exclude-header-row .btn-remove-exclude-row { + flex-shrink: 0; + margin-left: auto; +} +.target-conditions-trait .btn-remove-exclude-row, +.entity-selector-trait .btn-remove-exclude-row { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .btn-remove-exclude-row:focus, +.entity-selector-trait .btn-remove-exclude-row:focus { + outline: none; +} +.target-conditions-trait .btn-remove-exclude-row, +.entity-selector-trait .btn-remove-exclude-row { + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + color: #6c757d; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .btn-remove-exclude-row:hover, +.entity-selector-trait .btn-remove-exclude-row:hover { + background: #f8d7da; + color: #dc3545; +} +.target-conditions-trait .btn-add-exclude, +.target-conditions-trait .btn-add-another-exclude, +.entity-selector-trait .btn-add-exclude, +.entity-selector-trait .btn-add-another-exclude { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .btn-add-exclude:focus, +.target-conditions-trait .btn-add-another-exclude:focus, +.entity-selector-trait .btn-add-exclude:focus, +.entity-selector-trait .btn-add-another-exclude:focus { + outline: none; +} +.target-conditions-trait .btn-add-exclude, +.target-conditions-trait .btn-add-another-exclude, +.entity-selector-trait .btn-add-exclude, +.entity-selector-trait .btn-add-another-exclude { + display: inline-flex; + align-items: center; + gap: 0.25rem; + margin-top: 0.5rem; + padding: 0.375rem 0.625rem; + color: #dc3545; + font-size: 0.75rem; + font-weight: 500; + background: transparent; + border: 1px dashed rgba(220, 53, 69, 0.5); + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .btn-add-exclude:hover, +.target-conditions-trait .btn-add-another-exclude:hover, +.entity-selector-trait .btn-add-exclude:hover, +.entity-selector-trait .btn-add-another-exclude:hover { + background: #f8d7da; + border-color: #dc3545; +} +.target-conditions-trait .btn-add-exclude i, +.target-conditions-trait .btn-add-another-exclude i, +.entity-selector-trait .btn-add-exclude i, +.entity-selector-trait .btn-add-another-exclude i { + font-size: 12px !important; +} +.target-conditions-trait .group-modifiers, +.entity-selector-trait .group-modifiers { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 1rem; + padding: 0.5rem 1rem; + margin: 1rem -1rem -1rem; + background: #f8fafc; + border-top: 1px solid #dee2e6; + border-radius: 0 0 0.3rem 0.3rem; +} +.target-conditions-trait .modifier-inline, +.entity-selector-trait .modifier-inline { + display: inline-flex; + align-items: center; + gap: 0.375rem; + flex-shrink: 0; +} +.target-conditions-trait .group-modifier-limit, +.entity-selector-trait .group-modifier-limit { + width: 50px; + max-width: 50px; + min-width: 50px; + height: 26px; + padding: 0 0.375rem; + font-size: 0.75rem; + text-align: center; + border: 1px solid #dee2e6; + border-radius: 0.2rem; + box-sizing: border-box; +} +.target-conditions-trait .group-modifier-limit:focus, +.entity-selector-trait .group-modifier-limit:focus { + border-color: #25b9d7; + outline: none; +} +.target-conditions-trait .modifier-sort, +.entity-selector-trait .modifier-sort { + gap: 0; +} +.target-conditions-trait .modifier-sort .modifier-label, +.entity-selector-trait .modifier-sort .modifier-label { + margin-right: 0.375rem; +} +.target-conditions-trait .modifier-sort .group-modifier-sort, +.entity-selector-trait .modifier-sort .group-modifier-sort { + width: auto; + height: 26px; + padding: 0 1.25rem 0 0.5rem; + font-size: 0.75rem; + border: 1px solid #dee2e6; + border-radius: 0.2rem 0 0 0.2rem; + border-right: none; + cursor: pointer; + box-sizing: border-box; +} +.target-conditions-trait .modifier-sort .group-modifier-sort:focus, +.entity-selector-trait .modifier-sort .group-modifier-sort:focus { + border-color: #25b9d7; + outline: none; + position: relative; + z-index: 1; +} +.target-conditions-trait .modifier-sort .btn-sort-dir, +.entity-selector-trait .modifier-sort .btn-sort-dir { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .modifier-sort .btn-sort-dir:focus, +.entity-selector-trait .modifier-sort .btn-sort-dir:focus { + outline: none; +} +.target-conditions-trait .modifier-sort .btn-sort-dir, +.entity-selector-trait .modifier-sort .btn-sort-dir { + display: flex; + align-items: center; + justify-content: center; + width: 26px; + height: 26px; + color: #6c757d; + background: #f1f5f9; + border: 1px solid #dee2e6; + border-radius: 0 0.2rem 0.2rem 0; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .modifier-sort .btn-sort-dir:hover, +.entity-selector-trait .modifier-sort .btn-sort-dir:hover { + background: #e2e8f0; + color: #495057; +} +.target-conditions-trait .modifier-sort .btn-sort-dir i, +.entity-selector-trait .modifier-sort .btn-sort-dir i { + font-size: 14px !important; +} +.target-conditions-trait .group-modifier-sort, +.entity-selector-trait .group-modifier-sort { + height: 26px; + padding: 0 0.5rem; + font-size: 0.75rem; + border: 1px solid #dee2e6; + border-radius: 0.2rem; + cursor: pointer; +} +.target-conditions-trait .group-modifier-sort:focus, +.entity-selector-trait .group-modifier-sort:focus { + border-color: #25b9d7; + outline: none; +} +.target-conditions-trait .btn-sort-dir, +.entity-selector-trait .btn-sort-dir { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .btn-sort-dir:focus, +.entity-selector-trait .btn-sort-dir:focus { + outline: none; +} +.target-conditions-trait .btn-sort-dir, +.entity-selector-trait .btn-sort-dir { + display: flex; + align-items: center; + justify-content: center; + width: 26px; + height: 26px; + color: #6c757d; + border: 1px solid #dee2e6; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .btn-sort-dir:hover, +.entity-selector-trait .btn-sort-dir:hover { + background: #f1f5f9; + color: #495057; +} +.target-conditions-trait .group-preview-badge, +.entity-selector-trait .group-preview-badge { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + background: #f1f5f9; + color: #6c757d; + font-size: 0.75rem; + font-weight: 500; + border-radius: 50rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .group-preview-badge.clickable, +.entity-selector-trait .group-preview-badge.clickable { + cursor: pointer; +} +.target-conditions-trait .group-preview-badge.clickable:hover, +.entity-selector-trait .group-preview-badge.clickable:hover { + background: rgba(37, 185, 215, 0.1); + color: #25b9d7; +} +.target-conditions-trait .group-separator, +.entity-selector-trait .group-separator { + display: flex; + align-items: center; + justify-content: center; + padding: 0.5rem 0; + color: #6c757d; + font-size: 0.75rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.1em; +} +.target-conditions-trait .group-separator::before, .target-conditions-trait .group-separator::after, +.entity-selector-trait .group-separator::before, +.entity-selector-trait .group-separator::after { + content: ""; + flex: 1; + height: 1px; + background: #dee2e6; + margin: 0 1rem; +} +.target-conditions-trait .group-modifiers, +.entity-selector-trait .group-modifiers { + display: flex; + flex-wrap: wrap; + gap: 1rem; + padding-top: 1rem; + margin-top: 1rem; + border-top: 1px solid #dee2e6; +} +.target-conditions-trait .modifier-group, +.entity-selector-trait .modifier-group { + display: flex; + align-items: center; + gap: 0.5rem; +} +.target-conditions-trait .modifier-label, +.entity-selector-trait .modifier-label { + font-size: 0.75rem; + font-weight: 500; + color: #6c757d; + white-space: nowrap; +} +.target-conditions-trait .modifier-input, +.entity-selector-trait .modifier-input { + width: 100%; + padding: 0.5rem 1rem; + font-size: 0.875rem; + line-height: 1.5; + color: #212529; + background-color: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +.target-conditions-trait .modifier-input:focus, +.entity-selector-trait .modifier-input:focus { + border-color: #25b9d7; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(37, 185, 215, 0.25); +} +.target-conditions-trait .modifier-input::placeholder, +.entity-selector-trait .modifier-input::placeholder { + color: #adb5bd; +} +.target-conditions-trait .modifier-input, +.entity-selector-trait .modifier-input { + width: 80px; + padding: 0.25rem 0.5rem; + font-size: 0.75rem; +} +.target-conditions-trait .modifier-select, +.entity-selector-trait .modifier-select { + width: 100%; + padding: 0.5rem 1rem; + font-size: 0.875rem; + line-height: 1.5; + color: #212529; + background-color: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +.target-conditions-trait .modifier-select:focus, +.entity-selector-trait .modifier-select:focus { + border-color: #25b9d7; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(37, 185, 215, 0.25); +} +.target-conditions-trait .modifier-select::placeholder, +.entity-selector-trait .modifier-select::placeholder { + color: #adb5bd; +} +.target-conditions-trait .modifier-select, +.entity-selector-trait .modifier-select { + width: auto; + padding: 0.25rem 1.5rem 0.25rem 0.5rem; + font-size: 0.75rem; + cursor: pointer; + appearance: none; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E"); + background-position: right 0.25rem center; + background-repeat: no-repeat; + background-size: 1.25em 1.25em; +} +.target-conditions-trait .condition-match-count, +.entity-selector-trait .condition-match-count { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.125rem 0.375rem; + background: #f1f5f9; + color: #6c757d; + font-size: 0.75rem; + font-weight: 500; + border-radius: 50rem; + cursor: pointer; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .condition-match-count:hover, +.entity-selector-trait .condition-match-count:hover { + background: #e2e8f0; +} +.target-conditions-trait .condition-match-count.has-results, +.entity-selector-trait .condition-match-count.has-results { + background: rgba(37, 185, 215, 0.1); + color: #25b9d7; +} +.target-conditions-trait .condition-match-count.country-holidays, +.entity-selector-trait .condition-match-count.country-holidays { + background: rgba(139, 92, 246, 0.1); + color: #8b5cf6; +} +.target-conditions-trait .condition-match-count.country-holidays:hover, +.entity-selector-trait .condition-match-count.country-holidays:hover { + background: rgba(139, 92, 246, 0.2); +} +.target-conditions-trait .condition-match-count.country-holidays.clickable, +.entity-selector-trait .condition-match-count.country-holidays.clickable { + background: rgba(139, 92, 246, 0.15); +} +.target-conditions-trait .condition-match-count i, +.entity-selector-trait .condition-match-count i { + font-size: 12px !important; +} + +/** + * Entity Selector Styles + * @package prestashop-entity-selector + * @version 2.0.0 + * + * Compiles to: assets/css/admin/entity-selector.css + */ +/** + * Value Picker Component + * Search boxes, input types, range inputs + */ +.target-conditions-trait .value-picker, +.entity-selector-trait .value-picker { + padding: 0.5rem 0; +} +.target-conditions-trait .value-picker[style*="display: none"], .target-conditions-trait .value-picker[style*="display:none"], +.entity-selector-trait .value-picker[style*="display: none"], +.entity-selector-trait .value-picker[style*="display:none"] { + padding: 0; +} +.target-conditions-trait .entity-search-box, +.entity-selector-trait .entity-search-box { + position: relative; + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.25rem; + background: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .entity-search-box:focus-within, +.entity-selector-trait .entity-search-box:focus-within { + border-color: #25b9d7; + box-shadow: 0 0 0 2px rgba(37, 185, 215, 0.1); +} +.target-conditions-trait .chips-wrapper + .entity-search-box, +.entity-selector-trait .chips-wrapper + .entity-search-box { + margin-top: 1rem; +} +.target-conditions-trait .entity-search-icon, +.entity-selector-trait .entity-search-icon { + color: #6c757d; + font-size: 14px; + flex-shrink: 0; + margin-left: 0.25rem; +} +.target-conditions-trait input.entity-search-input, +.target-conditions-trait input.entity-search-input[type=text], +.entity-selector-trait input.entity-search-input, +.entity-selector-trait input.entity-search-input[type=text] { + padding: 0; + margin: 0; + background: none; + border: none; + font: inherit; + color: inherit; +} +.target-conditions-trait input.entity-search-input:focus, +.target-conditions-trait input.entity-search-input[type=text]:focus, +.entity-selector-trait input.entity-search-input:focus, +.entity-selector-trait input.entity-search-input[type=text]:focus { + outline: none; +} +.target-conditions-trait input.entity-search-input, +.target-conditions-trait input.entity-search-input[type=text], +.entity-selector-trait input.entity-search-input, +.entity-selector-trait input.entity-search-input[type=text] { + flex: 1; + min-width: 0; + width: auto !important; + max-width: none !important; + padding: 0.375rem; + font-size: 0.875rem; + color: #212529; + border: none !important; + background: transparent !important; + box-shadow: none !important; +} +.target-conditions-trait input.entity-search-input::placeholder, +.target-conditions-trait input.entity-search-input[type=text]::placeholder, +.entity-selector-trait input.entity-search-input::placeholder, +.entity-selector-trait input.entity-search-input[type=text]::placeholder { + color: #6c757d; +} +.target-conditions-trait input.entity-search-input:focus, +.target-conditions-trait input.entity-search-input[type=text]:focus, +.entity-selector-trait input.entity-search-input:focus, +.entity-selector-trait input.entity-search-input[type=text]:focus { + border: none !important; + box-shadow: none !important; + outline: none; +} +.target-conditions-trait .search-loading, +.entity-selector-trait .search-loading { + display: flex; + align-items: center; + justify-content: center; + color: #25b9d7; +} +.target-conditions-trait .search-loading i, +.entity-selector-trait .search-loading i { + animation: spin 0.6s linear infinite; +} +.target-conditions-trait .btn-browse-tree, +.entity-selector-trait .btn-browse-tree { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .btn-browse-tree:focus, +.entity-selector-trait .btn-browse-tree:focus { + outline: none; +} +.target-conditions-trait .btn-browse-tree, +.entity-selector-trait .btn-browse-tree { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + margin-left: auto; + color: #25b9d7; + background: rgba(37, 185, 215, 0.1); + border-radius: 0.2rem; + flex-shrink: 0; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .btn-browse-tree:hover, +.entity-selector-trait .btn-browse-tree:hover { + background: #25b9d7; + color: #ffffff; +} +.target-conditions-trait .btn-browse-tree i, +.entity-selector-trait .btn-browse-tree i { + font-size: 14px; +} +.target-conditions-trait .numeric-range-box, +.target-conditions-trait .multi-range-input-row, +.entity-selector-trait .numeric-range-box, +.entity-selector-trait .multi-range-input-row { + display: flex; + align-items: center; + gap: 0.25rem; +} +.target-conditions-trait .range-min-input, +.target-conditions-trait .range-max-input, +.entity-selector-trait .range-min-input, +.entity-selector-trait .range-max-input { + width: 100%; + padding: 0.5rem 1rem; + font-size: 0.875rem; + line-height: 1.5; + color: #212529; + background-color: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +.target-conditions-trait .range-min-input:focus, +.target-conditions-trait .range-max-input:focus, +.entity-selector-trait .range-min-input:focus, +.entity-selector-trait .range-max-input:focus { + border-color: #25b9d7; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(37, 185, 215, 0.25); +} +.target-conditions-trait .range-min-input::placeholder, +.target-conditions-trait .range-max-input::placeholder, +.entity-selector-trait .range-min-input::placeholder, +.entity-selector-trait .range-max-input::placeholder { + color: #adb5bd; +} +.target-conditions-trait .range-min-input, +.target-conditions-trait .range-max-input, +.entity-selector-trait .range-min-input, +.entity-selector-trait .range-max-input { + width: 100px; + padding: 0.5rem; + text-align: center; + font-size: 0.875rem; +} +.target-conditions-trait .range-min-input::-webkit-inner-spin-button, .target-conditions-trait .range-min-input::-webkit-outer-spin-button, +.target-conditions-trait .range-max-input::-webkit-inner-spin-button, +.target-conditions-trait .range-max-input::-webkit-outer-spin-button, +.entity-selector-trait .range-min-input::-webkit-inner-spin-button, +.entity-selector-trait .range-min-input::-webkit-outer-spin-button, +.entity-selector-trait .range-max-input::-webkit-inner-spin-button, +.entity-selector-trait .range-max-input::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; +} +.target-conditions-trait .range-min-input, +.target-conditions-trait .range-max-input, +.entity-selector-trait .range-min-input, +.entity-selector-trait .range-max-input { + -moz-appearance: textfield; +} +.target-conditions-trait .range-separator, +.entity-selector-trait .range-separator { + color: #6c757d; + font-size: 0.875rem; + font-weight: 500; +} +.target-conditions-trait .btn-add-range, +.entity-selector-trait .btn-add-range { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .btn-add-range:focus, +.entity-selector-trait .btn-add-range:focus { + outline: none; +} +.target-conditions-trait .btn-add-range, +.entity-selector-trait .btn-add-range { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + color: #ffffff; + background: #25b9d7; + border-radius: 0.25rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .btn-add-range:hover, +.entity-selector-trait .btn-add-range:hover { + background: #1a9ab7; +} +.target-conditions-trait .btn-add-range i, +.entity-selector-trait .btn-add-range i { + font-size: 12px; +} +.target-conditions-trait .multi-range-container, +.entity-selector-trait .multi-range-container { + display: flex; + flex-direction: column; + gap: 0.5rem; +} +.target-conditions-trait .date-range-box, +.entity-selector-trait .date-range-box { + display: flex; + align-items: center; + gap: 0.25rem; +} +.target-conditions-trait .date-from-input, +.target-conditions-trait .date-to-input, +.entity-selector-trait .date-from-input, +.entity-selector-trait .date-to-input { + width: 100%; + padding: 0.5rem 1rem; + font-size: 0.875rem; + line-height: 1.5; + color: #212529; + background-color: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +.target-conditions-trait .date-from-input:focus, +.target-conditions-trait .date-to-input:focus, +.entity-selector-trait .date-from-input:focus, +.entity-selector-trait .date-to-input:focus { + border-color: #25b9d7; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(37, 185, 215, 0.25); +} +.target-conditions-trait .date-from-input::placeholder, +.target-conditions-trait .date-to-input::placeholder, +.entity-selector-trait .date-from-input::placeholder, +.entity-selector-trait .date-to-input::placeholder { + color: #adb5bd; +} +.target-conditions-trait .date-from-input, +.target-conditions-trait .date-to-input, +.entity-selector-trait .date-from-input, +.entity-selector-trait .date-to-input { + width: 140px; + padding: 0.5rem; + font-size: 0.875rem; +} +.target-conditions-trait .multi-select-tiles, +.entity-selector-trait .multi-select-tiles { + display: flex; + flex-wrap: wrap; + gap: 0.25rem; +} +.target-conditions-trait .tile-option, +.entity-selector-trait .tile-option { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .tile-option:focus, +.entity-selector-trait .tile-option:focus { + outline: none; +} +.target-conditions-trait .tile-option, +.entity-selector-trait .tile-option { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.375rem 0.75rem; + color: #6c757d; + background: transparent; + border: 1px dashed #dee2e6; + border-radius: 100px; + font-size: 0.75rem; + font-weight: 400; + cursor: pointer; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .tile-option:hover, +.entity-selector-trait .tile-option:hover { + color: #495057; + border-color: #94a3b8; + border-style: solid; +} +.target-conditions-trait .tile-option.selected, +.entity-selector-trait .tile-option.selected { + color: #25b9d7; + background: rgba(37, 185, 215, 0.1); + border: 1px solid #25b9d7; + font-weight: 500; +} +.target-conditions-trait .tile-option i, +.entity-selector-trait .tile-option i { + font-size: 11px; + opacity: 0.6; +} +.target-conditions-trait .tile-option.selected i, +.entity-selector-trait .tile-option.selected i { + opacity: 1; +} +.target-conditions-trait .tile-label, +.entity-selector-trait .tile-label { + white-space: nowrap; +} +.target-conditions-trait .select-input-box, +.entity-selector-trait .select-input-box { + display: inline-block; +} +.target-conditions-trait .select-value-input, +.entity-selector-trait .select-value-input { + width: 100%; + padding: 0.5rem 1rem; + font-size: 0.875rem; + line-height: 1.5; + color: #212529; + background-color: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +.target-conditions-trait .select-value-input:focus, +.entity-selector-trait .select-value-input:focus { + border-color: #25b9d7; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(37, 185, 215, 0.25); +} +.target-conditions-trait .select-value-input::placeholder, +.entity-selector-trait .select-value-input::placeholder { + color: #adb5bd; +} +.target-conditions-trait .select-value-input, +.entity-selector-trait .select-value-input { + padding: 0.5rem 1rem; + font-size: 0.875rem; + min-width: 150px; +} +.target-conditions-trait .boolean-input-box, +.entity-selector-trait .boolean-input-box { + display: inline-flex; + align-items: center; + padding: 0.5rem 1rem; + background: #d4edda; + color: #1e7e34; + border-radius: 0.25rem; + font-size: 0.875rem; + font-weight: 500; +} +.target-conditions-trait .boolean-label, +.entity-selector-trait .boolean-label { + display: flex; + align-items: center; + gap: 0.25rem; +} +.target-conditions-trait .boolean-label::before, +.entity-selector-trait .boolean-label::before { + content: "✓"; + font-weight: bold; +} +.target-conditions-trait .condition-match-count, +.entity-selector-trait .condition-match-count { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.25rem; + min-width: 20px; + height: 20px; + padding: 0 0.5rem; + background: #25b9d7; + color: #ffffff; + font-size: 0.75rem; + font-weight: 600; + border-radius: 50rem; + cursor: pointer; + transition: all 0.15s ease-in-out; + flex-shrink: 0; +} +.target-conditions-trait .condition-match-count:hover, +.entity-selector-trait .condition-match-count:hover { + transform: scale(1.05); + box-shadow: 0 2px 8px rgba(37, 185, 215, 0.4); +} +.target-conditions-trait .condition-match-count:focus, +.entity-selector-trait .condition-match-count:focus { + outline: none; + box-shadow: 0 0 0 2px rgba(37, 185, 215, 0.3), 0 2px 8px rgba(37, 185, 215, 0.4); +} +.target-conditions-trait .condition-match-count.loading, +.entity-selector-trait .condition-match-count.loading { + cursor: wait; +} +.target-conditions-trait .condition-match-count.loading i, +.entity-selector-trait .condition-match-count.loading i { + font-size: 10px; + animation: spin 0.6s linear infinite; +} +.target-conditions-trait .condition-match-count.loading:hover, +.entity-selector-trait .condition-match-count.loading:hover { + transform: none; + box-shadow: none; +} +.target-conditions-trait .condition-match-count.inactive, .target-conditions-trait .condition-match-count.no-matches, +.entity-selector-trait .condition-match-count.inactive, +.entity-selector-trait .condition-match-count.no-matches { + background: #94a3b8; + cursor: default; +} +.target-conditions-trait .condition-match-count.inactive:hover, .target-conditions-trait .condition-match-count.no-matches:hover, +.entity-selector-trait .condition-match-count.inactive:hover, +.entity-selector-trait .condition-match-count.no-matches:hover { + transform: none; + box-shadow: none; +} +.target-conditions-trait .condition-match-count.popover-open, +.entity-selector-trait .condition-match-count.popover-open { + background: rgb(29.5119047619, 147.5595238095, 171.4880952381); + box-shadow: 0 2px 8px rgba(37, 185, 215, 0.4); +} +.target-conditions-trait .condition-match-count i, +.entity-selector-trait .condition-match-count i { + font-size: 10px; + line-height: 1; + opacity: 0.8; +} +.target-conditions-trait .condition-match-count:hover i, +.entity-selector-trait .condition-match-count:hover i { + opacity: 1; +} +.target-conditions-trait .condition-match-count .preview-count, +.entity-selector-trait .condition-match-count .preview-count { + font-weight: 700; +} +.target-conditions-trait .condition-match-count, +.entity-selector-trait .condition-match-count { + margin-left: 0.5rem; +} + +/** + * Entity Selector Styles + * @package prestashop-entity-selector + * @version 2.0.0 + * + * Compiles to: assets/css/admin/entity-selector.css + */ +/** + * Modal Component + * Preview modals, confirmation dialogs + */ +.mpr-modal-backdrop { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); + z-index: 1050; + opacity: 0; + transition: opacity 0.2s ease-in-out; +} +.mpr-modal-backdrop.show { + opacity: 1; +} + +.mpr-modal { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%) scale(0.95); + z-index: 1051; + width: 90%; + max-width: 600px; + max-height: 90vh; + background: #ffffff; + border-radius: 0.5rem; + box-shadow: 0 1.5rem 4rem rgba(0, 0, 0, 0.2); + opacity: 0; + transition: all 0.2s ease-in-out; + overflow: hidden; + display: flex; + flex-direction: column; +} +.mpr-modal.show { + opacity: 1; + transform: translate(-50%, -50%) scale(1); +} +.mpr-modal.modal-sm { + max-width: 400px; +} +.mpr-modal.modal-lg { + max-width: 800px; +} +.mpr-modal.modal-xl { + max-width: 1000px; +} +.mpr-modal.modal-fullscreen { + width: 95%; + max-width: none; + height: 90vh; + max-height: none; +} + +.mpr-modal-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; + padding: 1rem 1.5rem; + background: #f8f9fa; + border-bottom: 1px solid #dee2e6; + flex-shrink: 0; +} + +.mpr-modal-title { + font-size: 1rem; + font-weight: 600; + color: #212529; + margin: 0; +} + +.mpr-modal-close { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.mpr-modal-close:focus { + outline: none; +} +.mpr-modal-close { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + color: #6c757d; + border-radius: 0.25rem; + transition: all 0.15s ease-in-out; +} +.mpr-modal-close:hover { + background: #e2e8f0; + color: #495057; +} +.mpr-modal-close i { + font-size: 1.125rem; +} + +.mpr-modal-body { + flex: 1; + overflow-y: auto; + padding: 1.5rem; +} +.mpr-modal-body::-webkit-scrollbar { + width: 6px; + height: 6px; +} +.mpr-modal-body::-webkit-scrollbar-track { + background: #f8f9fa; + border-radius: 3px; +} +.mpr-modal-body::-webkit-scrollbar-thumb { + background: #dee2e6; + border-radius: 3px; +} +.mpr-modal-body::-webkit-scrollbar-thumb:hover { + background: #ced4da; +} + +.mpr-modal-footer { + display: flex; + align-items: center; + justify-content: flex-end; + gap: 0.5rem; + padding: 1rem 1.5rem; + background: #f8f9fa; + border-top: 1px solid #dee2e6; + flex-shrink: 0; +} + +.mpr-modal-btn { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.mpr-modal-btn:focus { + outline: none; +} +.mpr-modal-btn { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.25rem; + padding: 0.5rem 1rem; + font-size: 0.875rem; + font-weight: 500; + border-radius: 0.25rem; + transition: all 0.15s ease-in-out; +} +.mpr-modal-btn.btn-secondary { + color: #495057; + background: #f1f5f9; +} +.mpr-modal-btn.btn-secondary:hover { + background: #e2e8f0; +} +.mpr-modal-btn.btn-primary { + color: #ffffff; + background: #25b9d7; +} +.mpr-modal-btn.btn-primary:hover { + background: #1a9ab7; +} +.mpr-modal-btn.btn-danger { + color: #ffffff; + background: #dc3545; +} +.mpr-modal-btn.btn-danger:hover { + background: rgb(189.2151898734, 32.7848101266, 47.7721518987); +} +.mpr-modal-btn:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.popover-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.5rem; + padding: 0.5rem 1rem; + background: #f8f9fa; + border-bottom: 1px solid #dee2e6; + border-radius: 0.3rem 0.3rem 0 0; +} + +.popover-title { + font-size: 0.875rem; + font-weight: 600; + color: #212529; +} + +.popover-close { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.popover-close:focus { + outline: none; +} +.popover-close { + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + color: #6c757d; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +.popover-close:hover { + background: #e2e8f0; + color: #495057; +} + +.popover-body { + max-height: 300px; + overflow-y: auto; + padding: 0.5rem; +} +.popover-body::-webkit-scrollbar { + width: 6px; + height: 6px; +} +.popover-body::-webkit-scrollbar-track { + background: #f8f9fa; + border-radius: 3px; +} +.popover-body::-webkit-scrollbar-thumb { + background: #dee2e6; + border-radius: 3px; +} +.popover-body::-webkit-scrollbar-thumb:hover { + background: #ced4da; +} + +.popover-footer { + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.5rem; + padding: 0.5rem 1rem; + background: #f8f9fa; + border-top: 1px solid #dee2e6; + border-radius: 0 0 0.3rem 0.3rem; +} + +.popover-info { + font-size: 0.75rem; + color: #6c757d; +} + +.popover-load-more { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.popover-load-more:focus { + outline: none; +} +.popover-load-more { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + font-size: 0.75rem; + font-weight: 500; + color: #25b9d7; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +.popover-load-more:hover { + background: rgba(37, 185, 215, 0.1); +} + +.popover-arrow { + position: absolute; + width: 12px; + height: 12px; + background: #ffffff; + border: 1px solid #dee2e6; + transform: rotate(45deg); +} +.popover-arrow.arrow-top { + top: -7px; + left: 50%; + margin-left: -6px; + border-right: none; + border-bottom: none; +} +.popover-arrow.arrow-bottom { + bottom: -7px; + left: 50%; + margin-left: -6px; + border-left: none; + border-top: none; +} + +#mpr-holiday-preview-modal { + display: none; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 1050; +} +#mpr-holiday-preview-modal.show { + display: flex; + align-items: center; + justify-content: center; +} +#mpr-holiday-preview-modal .mpr-modal-backdrop { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); + cursor: pointer; +} +#mpr-holiday-preview-modal .mpr-modal-dialog { + position: relative; + width: 90%; + max-width: 480px; + max-height: 80vh; + background: #ffffff; + border-radius: 0.3rem; + box-shadow: 0 1.5rem 4rem rgba(0, 0, 0, 0.2); + display: flex; + flex-direction: column; + overflow: hidden; +} +#mpr-holiday-preview-modal .mpr-modal-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; + padding: 1rem 1.5rem; + background: #f8f9fa; + border-bottom: 1px solid #dee2e6; + flex-shrink: 0; +} +#mpr-holiday-preview-modal .mpr-modal-title { + display: flex; + align-items: center; + gap: 0.5rem; + font-size: 1rem; + font-weight: 600; + color: #212529; + margin: 0; +} +#mpr-holiday-preview-modal .mpr-modal-title i.material-icons { + font-size: 20px !important; + color: #25b9d7; +} +#mpr-holiday-preview-modal .mpr-modal-close { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +#mpr-holiday-preview-modal .mpr-modal-close:focus { + outline: none; +} +#mpr-holiday-preview-modal .mpr-modal-close { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + color: #6c757d; + border-radius: 0.25rem; + transition: all 0.15s ease-in-out; +} +#mpr-holiday-preview-modal .mpr-modal-close:hover { + background: #e2e8f0; + color: #495057; +} +#mpr-holiday-preview-modal .mpr-modal-close i { + font-size: 18px; +} +#mpr-holiday-preview-modal .mpr-modal-body { + flex: 1; + overflow-y: auto; + padding: 1.5rem; +} +#mpr-holiday-preview-modal .mpr-modal-body::-webkit-scrollbar { + width: 6px; + height: 6px; +} +#mpr-holiday-preview-modal .mpr-modal-body::-webkit-scrollbar-track { + background: #f8f9fa; + border-radius: 3px; +} +#mpr-holiday-preview-modal .mpr-modal-body::-webkit-scrollbar-thumb { + background: #dee2e6; + border-radius: 3px; +} +#mpr-holiday-preview-modal .mpr-modal-body::-webkit-scrollbar-thumb:hover { + background: #ced4da; +} +#mpr-holiday-preview-modal .holiday-preview-loading { + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + padding: 2rem 0; + color: #6c757d; + font-size: 0.875rem; +} +#mpr-holiday-preview-modal .holiday-preview-loading i { + font-size: 1.125rem; +} +#mpr-holiday-preview-modal .holiday-preview-empty { + text-align: center; + padding: 2rem 0; + color: #6c757d; +} +#mpr-holiday-preview-modal .holiday-preview-empty i.material-icons { + font-size: 48px !important; + opacity: 0.5; + margin-bottom: 1rem; +} +#mpr-holiday-preview-modal .holiday-preview-empty p { + margin: 0 0 0.25rem; +} +#mpr-holiday-preview-modal .holiday-preview-empty .hint { + font-size: 0.75rem; + color: #6c757d; +} +#mpr-holiday-preview-modal .holiday-list { + display: flex; + flex-direction: column; + gap: 0.5rem; +} +#mpr-holiday-preview-modal .holiday-item { + display: flex; + align-items: flex-start; + gap: 1rem; + padding: 0.5rem 1rem; + background: #f8fafc; + border-radius: 0.25rem; + border-left: 3px solid #70b580; +} +#mpr-holiday-preview-modal .holiday-item.holiday-type-bank { + border-left-color: #17a2b8; +} +#mpr-holiday-preview-modal .holiday-item.holiday-type-observance { + border-left-color: #fab000; +} +#mpr-holiday-preview-modal .holiday-item.holiday-type-regional { + border-left-color: #8b5cf6; +} +#mpr-holiday-preview-modal .holiday-date { + flex-shrink: 0; + min-width: 100px; +} +#mpr-holiday-preview-modal .holiday-date .holiday-day { + display: block; + font-size: 0.875rem; + font-weight: 600; + color: #212529; +} +#mpr-holiday-preview-modal .holiday-date .holiday-weekday { + display: block; + font-size: 0.75rem; + color: #6c757d; +} +#mpr-holiday-preview-modal .holiday-info { + flex: 1; + min-width: 0; +} +#mpr-holiday-preview-modal .holiday-name { + display: block; + font-size: 0.875rem; + color: #212529; + word-wrap: break-word; +} +#mpr-holiday-preview-modal .holiday-type-badge { + display: inline-block; + margin-top: 0.25rem; + padding: 0.125rem 0.375rem; + font-size: 10px; + font-weight: 500; + text-transform: capitalize; + background: #e2e8f0; + color: #495057; + border-radius: 0.2rem; +} +#mpr-holiday-preview-modal .holiday-preview-note { + margin-top: 1rem; + font-size: 0.75rem; + color: #6c757d; + text-align: center; +} + +/** + * Entity Selector Styles + * @package prestashop-entity-selector + * @version 2.0.0 + * + * Compiles to: assets/css/admin/entity-selector.css + */ +/** + * List Preview Component + * Popover and modal views for entity preview + * + * Uses shared entity-item base for item styling. + * This file only contains popover/modal container styles. + */ +.target-preview-popover, +.target-list-preview-popover { + position: absolute; + z-index: 10000; + min-width: 320px; + max-width: 480px; + background: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.3rem; + box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.175); + overflow: hidden; +} +.target-preview-popover::before, +.target-list-preview-popover::before { + content: ""; + position: absolute; + top: -8px; + left: 50%; + transform: translateX(-50%); + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-bottom: 8px solid #dee2e6; +} +.target-preview-popover::after, +.target-list-preview-popover::after { + content: ""; + position: absolute; + top: -6px; + left: 50%; + transform: translateX(-50%); + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; +} +.target-preview-popover.position-right::before, .target-preview-popover.position-right::after, +.target-list-preview-popover.position-right::before, +.target-list-preview-popover.position-right::after { + left: 20px; + transform: none; +} +.target-preview-popover.position-left::before, .target-preview-popover.position-left::after, +.target-list-preview-popover.position-left::before, +.target-list-preview-popover.position-left::after { + left: auto; + right: 20px; + transform: none; +} + +.preview-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 0.5rem 1rem; + background: #f8f9fa; + border-bottom: 1px solid #dee2e6; +} +.preview-header .preview-title { + font-size: 0.875rem; + font-weight: 600; + color: #212529; +} +.preview-header .preview-close { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.preview-header .preview-close:focus { + outline: none; +} +.preview-header .preview-close { + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + color: #6c757d; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +.preview-header .preview-close:hover { + background: #e2e8f0; + color: #212529; +} + +.preview-tabs { + display: flex; + flex-wrap: wrap; + gap: 0; + padding: 0; + background: #f8fafc; + border-bottom: 1px solid #dee2e6; +} + +.preview-tab { + display: flex; + align-items: center; + gap: 0.375rem; + padding: 0.5rem 0.75rem; + background: transparent; + border: 0; + border-bottom: 2px solid transparent; + margin-bottom: -1px; + color: #6c757d; + font-size: 0.75rem; + font-weight: 500; + cursor: pointer; + transition: all 0.15s ease-in-out; + white-space: nowrap; +} +.preview-tab:hover { + background: #f1f5f9; + color: #495057; +} +.preview-tab.active { + background: #ffffff; + border-bottom-color: #25b9d7; + color: #25b9d7; +} +.preview-tab i { + font-size: 12px; +} + +.preview-filter { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 1rem; + background: #ffffff; + border-bottom: 1px solid #dee2e6; +} +.preview-filter i { + color: #6c757d; + font-size: 12px; +} +.preview-filter .preview-filter-input { + all: unset; + flex: 1; + padding: 0.25rem 0; + font-size: 0.75rem; + color: #212529; + box-sizing: border-box; +} +.preview-filter .preview-filter-input::placeholder { + color: #6c757d; +} + +.preview-contents { + max-height: 350px; + overflow: hidden; +} + +.preview-content { + display: none; + max-height: 350px; + overflow-y: auto; +} +.preview-content::-webkit-scrollbar { + width: 6px; + height: 6px; +} +.preview-content::-webkit-scrollbar-track { + background: #f8f9fa; + border-radius: 3px; +} +.preview-content::-webkit-scrollbar-thumb { + background: #dee2e6; + border-radius: 3px; +} +.preview-content::-webkit-scrollbar-thumb:hover { + background: #ced4da; +} +.preview-content.active { + display: block; +} + +.preview-items { + display: flex; + flex-direction: column; + padding: 0.25rem 0.5rem; +} + +.preview-item { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem; + background: #ffffff; + border-radius: 0.2rem; + transition: background 0.15s ease-in-out; +} +.preview-item:hover { + background: #e9ecef; +} +.preview-item[data-id] { + cursor: pointer; +} + +.preview-item-image { + flex-shrink: 0; + width: 32px; + height: 32px; + object-fit: cover; + border-radius: 0.2rem; + background: #f1f5f9; +} + +.preview-item-no-image { + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + width: 32px; + height: 32px; + background: #f1f5f9; + color: #6c757d; + border-radius: 0.2rem; + font-size: 0.875rem; +} + +.preview-item-info { + flex: 1; + min-width: 0; + display: flex; + flex-direction: column; + gap: 0.125rem; +} + +.preview-item-name { + font-size: 0.875rem; + font-weight: 500; + color: #212529; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.preview-item-ref, +.preview-item-meta { + font-size: 0.75rem; + color: #6c757d; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.preview-item-price { + flex-shrink: 0; + padding: 0.25rem 0.5rem; + font-size: 0.75rem; + font-weight: 600; + color: #25b9d7; + background: rgba(37, 185, 215, 0.1); + border-radius: 0.2rem; +} + +.preview-footer { + padding: 0.5rem 1rem; + background: #f8fafc; + border-top: 1px solid #dee2e6; +} + +.load-more-controls { + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + font-size: 0.75rem; + color: #6c757d; +} +.load-more-controls .load-more-label { + white-space: nowrap; +} +.load-more-controls .load-more-select { + appearance: none; + padding: 0.25rem 1.75rem 0.25rem 0.5rem; + border: 1px solid #dee2e6; + border-radius: 0.2rem; + background: #ffffff 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; + background-size: 8px; + font-size: 0.75rem; + font-weight: 500; + color: #25b9d7; + cursor: pointer; + transition: all 0.15s ease-in-out; + height: auto; + min-height: 0; + line-height: 1.3; +} +.load-more-controls .load-more-select:hover { + border-color: #25b9d7; + background-color: rgba(37, 185, 215, 0.1); +} +.load-more-controls .load-more-select:focus { + outline: none; + border-color: #25b9d7; + box-shadow: 0 0 0 2px rgba(37, 185, 215, 0.1); +} +.load-more-controls .load-more-of { + white-space: nowrap; +} +.load-more-controls .remaining-count { + font-weight: 600; + color: #495057; +} +.load-more-controls .btn-load-more { + display: flex; + align-items: center; + justify-content: center; + padding: 0.25rem; + margin: 0; + border: none; + color: #25b9d7; + background: rgba(37, 185, 215, 0.1); + border-radius: 0.2rem; + cursor: pointer; + transition: all 0.15s ease-in-out; + font: inherit; +} +.load-more-controls .btn-load-more i { + font-size: 14px; +} +.load-more-controls .btn-load-more:hover { + background: rgba(37, 185, 215, 0.2); +} +.load-more-controls .btn-load-more.loading { + cursor: wait; +} +.load-more-controls .btn-load-more.loading i { + animation: spin 0.6s linear infinite; +} + +.preview-empty { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 0.5rem; + padding: 2rem; + text-align: center; + color: #6c757d; +} +.preview-empty i { + font-size: 2rem; + opacity: 0.5; +} +.preview-empty p { + margin: 0; + font-size: 0.875rem; +} + +.preview-loading { + display: flex; + align-items: center; + justify-content: center; + padding: 2rem; + color: #6c757d; +} +.preview-loading i { + font-size: 20px; + color: #25b9d7; + animation: spin 0.6s linear infinite; +} + +.total-preview-popover { + min-width: 240px; + max-width: 320px; +} +.total-preview-popover .preview-popover-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; + padding: 0.5rem 1rem; + background: #f8f9fa; + border-bottom: 1px solid #dee2e6; +} +.total-preview-popover .preview-popover-header .preview-popover-title { + font-weight: 600; + color: #212529; + font-size: 0.875rem; +} +.total-preview-popover .preview-popover-header .preview-popover-count { + flex-shrink: 0; + font-size: 0.75rem; + font-weight: 500; + color: #6c757d; + background: #e2e8f0; + padding: 0.125rem 0.5rem; + border-radius: 0.2rem; +} +.total-preview-popover .preview-popover-body { + padding: 0.25rem 0; +} +.total-preview-popover .total-summary-list { + list-style: none; + margin: 0; + padding: 0; +} +.total-preview-popover .total-summary-item { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 1rem; + cursor: pointer; + transition: background-color 0.15s ease; +} +.total-preview-popover .total-summary-item:hover { + background: #f8fafc; +} +.total-preview-popover .total-summary-item i { + width: 18px; + text-align: center; + color: #6c757d; + font-size: 14px; +} +.total-preview-popover .total-summary-item .summary-item-label { + flex: 1; + font-size: 0.875rem; + color: #212529; +} +.total-preview-popover .total-summary-item .summary-item-count { + font-size: 0.875rem; + font-weight: 600; + color: #25b9d7; + background: rgba(37, 185, 215, 0.1); + padding: 2px 8px; + border-radius: 0.2rem; +} + +.trait-total-count { + cursor: pointer; + transition: all 0.15s ease; +} +.trait-total-count:hover { + opacity: 0.8; +} +.trait-total-count.popover-open { + opacity: 0.9; +} + +.mpr-dropdown-preview { + display: none; + position: absolute; + top: 100%; + left: 50%; + transform: translateX(-50%); + margin-top: 6px; + z-index: 1000; + padding: 0.625rem 0.75rem; + background: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.3rem; + box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.175); + font-size: 12px; + text-align: left; + text-transform: none; + font-weight: normal; + white-space: nowrap; +} +.mpr-dropdown-preview.is-open { + display: block; +} + +.mpr-dropdown-preview__item { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.375rem 0; + color: #666; + line-height: 1.4; +} +.mpr-dropdown-preview__item:not(:last-child) { + margin-bottom: 0.25rem; + padding-bottom: 0.5rem; + border-bottom: 1px solid rgba(222, 226, 230, 0.5); +} +.mpr-dropdown-preview__item > .material-icons, +.mpr-dropdown-preview__item > i:first-child { + flex-shrink: 0; + width: 16px; + font-size: 14px !important; + color: #999; + text-align: center; +} + +.mpr-dropdown-preview__muted { + color: #999; +} + +.mpr-dropdown-preview__schedule { + display: inline; +} + +.mpr-dropdown-preview__schedule-row { + display: inline; +} +.mpr-dropdown-preview__schedule-row:not(:last-child)::after { + content: ","; + margin-right: 0.5rem; +} + +.mpr-dropdown-preview__day { + color: #666; +} + +.mpr-dropdown-preview__hours { + color: #25b9d7; + font-weight: 500; + margin-left: 0.25rem; +} + +.mpr-badge--preview { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.25rem; + position: relative; + min-width: 20px; + height: 20px; + padding: 0 0.5rem; + font-size: 0.75rem; + font-weight: 600; + border-radius: 50rem; + cursor: pointer; + text-transform: none; +} +.mpr-badge--preview .material-icons { + font-size: 12px !important; + line-height: 1; + opacity: 0.8; +} + +.mpr-badge--preview-primary { + background: #25b9d7; + color: #ffffff; +} + +.mpr-badge--preview-success { + background: #d4edda; + color: #155724; +} + +.mpr-badge--preview-warning { + background: #fff3cd; + color: #856404; +} + +.mpr-badge--preview-muted { + background: #e2e8f0; + color: #6c757d; +} + +/** + * Entity Selector Styles + * @package prestashop-entity-selector + * @version 2.0.0 + * + * Compiles to: assets/css/admin/entity-selector.css + */ +/** + * Schedule Conditions Component + * DateTime picker, weekly timeline, holidays + */ +.schedule-conditions-trait { + background: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.3rem; +} + +.schedule-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; + padding: 0.875rem 1rem; + background: #f8f9fa; + border-bottom: 1px solid #dee2e6; + border-radius: 0.3rem 0.3rem 0 0; + cursor: pointer; + user-select: none; + transition: background-color 0.15s ease-in-out; +} +.schedule-header:hover { + background: #e9ecef; +} + +.schedule-title { + display: flex; + align-items: center; + gap: 0.75rem; + font-size: 0.875rem; + font-weight: 600; + color: #212529; +} +.schedule-title i { + color: #6c757d; +} + +.schedule-body { + padding: 1rem; +} + +.schedule-section { + margin-bottom: 1.5rem; +} +.schedule-section:last-child { + margin-bottom: 0; +} + +.schedule-section-title { + display: flex; + align-items: center; + gap: 0.5rem; + margin-bottom: 0.5rem; + font-size: 0.875rem; + font-weight: 600; + color: #212529; +} +.schedule-section-title i { + color: #6c757d; +} + +.schedule-section-description { + margin-bottom: 1rem; + font-size: 0.75rem; + color: #6c757d; +} + +.datetime-range { + display: flex; + flex-wrap: wrap; + gap: 1rem; +} + +.datetime-field { + flex: 1; + min-width: 200px; +} + +.datetime-label { + display: block; + margin-bottom: 0.25rem; + font-size: 0.75rem; + font-weight: 500; + color: #495057; +} + +.datetime-input { + width: 100%; + padding: 0.5rem 1rem; + font-size: 0.875rem; + line-height: 1.5; + color: #212529; + background-color: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +.datetime-input:focus { + border-color: #25b9d7; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(37, 185, 215, 0.25); +} +.datetime-input::placeholder { + color: #adb5bd; +} + +.weekly-schedule { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.day-row { + display: flex; + align-items: center; + gap: 1rem; + padding: 0.5rem; + background: #f8fafc; + border-radius: 0.25rem; +} +.day-row.disabled { + opacity: 0.5; +} + +.day-toggle { + display: flex; + align-items: center; + gap: 0.5rem; + min-width: 100px; +} + +.day-checkbox { + width: 18px; + height: 18px; + cursor: pointer; +} + +.day-name { + font-size: 0.875rem; + font-weight: 500; + color: #212529; +} + +.timeline-slider { + flex: 1; + position: relative; + height: 24px; + background: #e2e8f0; + border-radius: 50rem; + cursor: pointer; +} + +.timeline-fill { + position: absolute; + top: 0; + height: 100%; + background: #25b9d7; + border-radius: 50rem; + transition: all 0.15s ease-in-out; +} + +.timeline-handle { + position: absolute; + top: 50%; + width: 16px; + height: 16px; + background: #ffffff; + border: 2px solid #25b9d7; + border-radius: 50%; + transform: translate(-50%, -50%); + cursor: grab; + box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075); + transition: box-shadow 0.15s ease-in-out; +} +.timeline-handle:hover { + box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); +} +.timeline-handle:active { + cursor: grabbing; +} +.timeline-handle.handle-start { + z-index: 2; +} +.timeline-handle.handle-end { + z-index: 1; +} + +.day-times { + display: flex; + align-items: center; + gap: 0.25rem; + min-width: 120px; + font-size: 0.75rem; + font-family: monospace; + color: #495057; +} + +.time-separator { + color: #6c757d; +} + +.holiday-section { + padding: 1rem; + background: #f8fafc; + border-radius: 0.25rem; +} + +.holiday-toggle { + display: flex; + align-items: center; + gap: 0.5rem; + margin-bottom: 1rem; +} + +.holiday-checkbox { + width: 18px; + height: 18px; + cursor: pointer; +} + +.holiday-label { + font-size: 0.875rem; + font-weight: 500; + color: #212529; +} + +.holiday-countries { + display: flex; + flex-wrap: wrap; + gap: 0.25rem; +} + +.holiday-country-chip { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + font-size: 0.75rem; + font-weight: 500; + background: #e9ecef; + color: #495057; + border-radius: 50rem; +} +.holiday-country-chip .chip-remove { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.holiday-country-chip .chip-remove:focus { + outline: none; +} +.holiday-country-chip .chip-remove { + display: flex; + align-items: center; + justify-content: center; + width: 14px; + height: 14px; + font-size: 10px; + color: #6c757d; + border-radius: 50%; +} +.holiday-country-chip .chip-remove:hover { + background: rgba(0, 0, 0, 0.1); + color: #dc3545; +} +.holiday-country-chip { + cursor: pointer; +} +.holiday-country-chip.selected { + background: rgba(37, 185, 215, 0.1); + color: #25b9d7; +} + +.server-time { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 1rem; + background: #d1ecf1; + border-radius: 0.25rem; + font-size: 0.75rem; + color: #17a2b8; +} +.server-time i { + font-size: 0.875rem; +} +.server-time .time-value { + font-family: monospace; + font-weight: 600; +} + +.schedule-summary { + display: flex; + flex-direction: column; + gap: 0.25rem; + padding: 1rem; + background: #f8fafc; + border-radius: 0.25rem; + font-size: 0.875rem; + color: #495057; +} +.schedule-summary .summary-item { + display: flex; + align-items: center; + gap: 0.5rem; +} +.schedule-summary .summary-item i { + color: #70b580; + font-size: 0.875rem; +} +.schedule-summary .summary-item.inactive i { + color: #6c757d; +} + +.schedule-conditions-trait.collapsed .schedule-body { + display: none; +} +.schedule-conditions-trait.collapsed .schedule-header { + border-radius: 0.3rem; +} + +.schedule-toggle-row { + display: flex; + align-items: center; + background: #f1f5f9; + border: 1px solid #dee2e6; + border-radius: 0.3rem; +} +.schedule-toggle-row .schedule-toggle-switch { + padding: 0.5rem 1rem; +} +.schedule-toggle-row .schedule-toggle-actions { + padding: 0.5rem 1rem; + border-left: 1px solid #dee2e6; + cursor: pointer; + transition: background-color 0.15s ease-in-out; +} +.schedule-toggle-row .schedule-toggle-actions:hover { + background: #e2e8f0; +} +.schedule-toggle-row .schedule-toggle-actions .material-icons { + color: #94a3b8; + font-size: 20px !important; +} + +.schedule-summary-badges { + display: flex; + align-items: center; + gap: 0.5rem; + margin-left: auto; + padding: 0 0.5rem; +} + +.schedule-badge { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + background: #e2e8f0; + color: #475569; + font-size: 0.75rem; + font-weight: 500; + border-radius: 50rem; + white-space: nowrap; +} +.schedule-badge .material-icons { + font-size: 14px !important; + opacity: 0.7; +} + +.schedule-holidays .section-hint { + margin-top: 1rem; +} + +/** + * Entity Selector Styles + * @package prestashop-entity-selector + * @version 2.0.0 + * + * Compiles to: assets/css/admin/entity-selector.css + */ +/** + * Tips Box Component + * Pro tips and help information display + */ +.target-conditions-trait .target-tips-box, +.entity-selector-trait .target-tips-box { + margin: 1.5rem 1rem 1rem; + border: 1px solid #dee2e6; + border-radius: 0.3rem; + overflow: hidden; + background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%); +} +.target-conditions-trait .tips-header, +.entity-selector-trait .tips-header { + display: flex; + align-items: center; + gap: 0.625rem; + padding: 1rem 1.5rem; + cursor: pointer; + user-select: none; + transition: background-color 0.15s ease-in-out; +} +.target-conditions-trait .tips-header:hover, +.entity-selector-trait .tips-header:hover { + background: rgba(0, 0, 0, 0.02); +} +.target-conditions-trait .tips-header > i:first-child, +.entity-selector-trait .tips-header > i:first-child { + font-size: 1rem; + color: #fab000; +} +.target-conditions-trait .tips-header > span, +.entity-selector-trait .tips-header > span { + flex: 1; + font-size: 13px; + font-weight: 600; + color: #475569; +} +.target-conditions-trait .tips-toggle, +.entity-selector-trait .tips-toggle { + font-size: 0.75rem; + color: #94a3b8; + transition: transform 0.2s; +} +.target-conditions-trait .target-tips-box.expanded .tips-toggle, +.entity-selector-trait .target-tips-box.expanded .tips-toggle { + transform: rotate(180deg); +} +.target-conditions-trait .target-tips-box.expanded .tips-content, +.entity-selector-trait .target-tips-box.expanded .tips-content { + display: block; +} +.target-conditions-trait .tips-content, +.entity-selector-trait .tips-content { + display: none; + padding: 0 1.5rem 1.5rem; +} +.target-conditions-trait .tips-grid, +.entity-selector-trait .tips-grid { + display: grid; + gap: 1rem; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); +} +.target-conditions-trait .tip-item, +.entity-selector-trait .tip-item { + display: flex; + gap: 1rem; + padding: 1rem; + background: #ffffff; + border-radius: 0.25rem; + border: 1px solid #dee2e6; +} +.target-conditions-trait .tip-icon, +.entity-selector-trait .tip-icon { + flex-shrink: 0; + width: 2rem; + height: 2rem; + display: flex; + align-items: center; + justify-content: center; + background: rgba(37, 185, 215, 0.1); + border-radius: 0.25rem; + color: #25b9d7; + font-size: 0.875rem; +} +.target-conditions-trait .tip-text, +.entity-selector-trait .tip-text { + flex: 1; + min-width: 0; +} +.target-conditions-trait .tip-text strong, +.entity-selector-trait .tip-text strong { + display: block; + font-size: 0.75rem; + font-weight: 600; + color: #334155; + margin-bottom: 0.25rem; +} +.target-conditions-trait .tip-text p, +.entity-selector-trait .tip-text p { + font-size: 11px; + color: #6c757d; + line-height: 1.625; + margin: 0; +} +.target-conditions-trait .tips-footer, +.entity-selector-trait .tips-footer { + margin-top: 1rem; + padding: 0.625rem 1rem; + background: #ffffff; + border-radius: 0.25rem; + border: 1px dashed #dee2e6; + font-size: 11px; + color: #6c757d; + line-height: 1.625; +} +.target-conditions-trait .tips-footer i, +.entity-selector-trait .tips-footer i { + color: #25b9d7; + margin-right: 0.25rem; +} + +/** + * Entity Selector Styles + * @package prestashop-entity-selector + * @version 2.0.0 + * + * Compiles to: assets/css/admin/entity-selector.css + */ +/** + * Condition Trait Base Styles + * Shared styling for all condition trait components + */ +.condition-trait { + background: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.3rem; + margin-bottom: 1.5rem; +} +.condition-trait:last-child { + margin-bottom: 0; +} + +.condition-trait.collapsed .condition-trait-header { + border-bottom-color: transparent; + border-radius: 0.3rem; +} +.condition-trait.collapsed .collapse-icon { + transform: rotate(180deg); +} + +.condition-trait-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1.5rem; + flex-wrap: wrap; + padding: 0.875rem 1.5rem; + background: #f8fafc; + border-bottom: 1px solid #dee2e6; + border-radius: 0.3rem 0.3rem 0 0; + cursor: pointer; + transition: background-color 0.15s ease-in-out; +} +.condition-trait-header:hover { + background: #f1f5f9; +} + +.trait-header-left { + display: flex; + align-items: center; + gap: 1rem; + min-width: 0; + flex: 1; +} + +.trait-icon { + font-size: 1.125rem; + color: #6c757d; + flex-shrink: 0; +} + +.trait-title-group { + display: flex; + flex-direction: column; + gap: 0.125rem; + min-width: 0; +} + +.trait-title { + font-size: 0.875rem; + font-weight: 600; + color: #1e293b; + white-space: nowrap; +} + +.trait-subtitle { + font-size: 0.75rem; + color: #6c757d; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.trait-summary { + display: inline-flex; + align-items: center; + gap: 0.375rem; + padding: 0.25rem 0.625rem; + font-size: 0.75rem; + font-weight: 500; + color: #25b9d7; + background: rgba(37, 185, 215, 0.08); + border-radius: 50rem; + white-space: nowrap; + margin-left: 1rem; + flex-shrink: 0; + max-width: 320px; + overflow: hidden; + text-overflow: ellipsis; +} +.trait-summary:empty { + display: none; +} + +.trait-header-right { + display: flex; + align-items: center; + gap: 1rem; + flex-shrink: 0; + margin-left: auto; +} + +.trait-header-actions { + display: flex; + align-items: center; + gap: 0.5rem; +} + +.collapse-icon { + display: inline-flex; + align-items: center; + justify-content: center; + width: 1.5rem; + height: 1.5rem; + font-size: 0.875rem; + color: #6c757d; + cursor: pointer; + transition: all 0.2s; + border-radius: 0.2rem; + background: transparent; +} +.collapse-icon:hover { + color: #25b9d7; + background: rgba(37, 185, 215, 0.08); +} + +.trait-show-all-toggle { + display: inline-flex; + align-items: center; + gap: 0.25rem; + font-size: 0.75rem; + color: #25b9d7; + cursor: pointer; +} +.trait-show-all-toggle:hover { + text-decoration: underline; +} + +.trait-total-count { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.25rem; + min-width: 20px; + height: 20px; + padding: 0 0.5rem; + background: #25b9d7; + color: #ffffff; + font-size: 0.75rem; + font-weight: 600; + border-radius: 50rem; + cursor: pointer; + transition: all 0.15s ease-in-out; + flex-shrink: 0; +} +.trait-total-count:hover { + transform: scale(1.05); + box-shadow: 0 2px 8px rgba(37, 185, 215, 0.4); +} +.trait-total-count:focus { + outline: none; + box-shadow: 0 0 0 2px rgba(37, 185, 215, 0.3), 0 2px 8px rgba(37, 185, 215, 0.4); +} +.trait-total-count.loading { + cursor: wait; +} +.trait-total-count.loading i { + font-size: 10px; + animation: spin 0.6s linear infinite; +} +.trait-total-count.loading:hover { + transform: none; + box-shadow: none; +} +.trait-total-count.inactive, .trait-total-count.no-matches { + background: #94a3b8; + cursor: default; +} +.trait-total-count.inactive:hover, .trait-total-count.no-matches:hover { + transform: none; + box-shadow: none; +} +.trait-total-count.popover-open { + background: rgb(29.5119047619, 147.5595238095, 171.4880952381); + box-shadow: 0 2px 8px rgba(37, 185, 215, 0.4); +} +.trait-total-count i { + font-size: 10px; + line-height: 1; + opacity: 0.8; +} +.trait-total-count:hover i { + opacity: 1; +} +.trait-total-count .preview-count { + font-weight: 700; +} + +.trait-required { + color: #dc3545; + font-size: 0.75rem; +} + +.trait-validation-error { + color: #dc3545; + font-size: 0.75rem; + margin-top: 0.25rem; +} + +.trait-toggle { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.trait-toggle:focus { + outline: none; +} +.trait-toggle { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.375rem 0.75rem; + font-size: 0.75rem; + font-weight: 500; + color: #495057; + background: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.25rem; + transition: all 0.15s ease-in-out; +} +.trait-toggle:hover { + background: #f8fafc; + border-color: #dee2e6; +} +.trait-toggle.active { + color: #25b9d7; + border-color: #25b9d7; + background: rgba(37, 185, 215, 0.1); +} + +.condition-trait-body { + padding: 1.5rem; + border-radius: 0 0 0.3rem 0.3rem; + background: #ffffff; + animation: slideDown 0.2s ease-out; +} + +.condition-trait.collapsed .condition-trait-body { + display: none; +} + +.schedule-section, +.context-section { + margin-bottom: 1.25rem; + padding-bottom: 1.25rem; + border-bottom: 1px solid #f1f5f9; +} +.schedule-section:last-child, +.context-section:last-child { + margin-bottom: 0; + padding-bottom: 0; + border-bottom: 0; +} + +.section-label { + display: flex; + align-items: center; + gap: 0.5rem; + font-size: 13px; + font-weight: 600; + color: #475569; + margin-bottom: 1rem; +} +.section-label i { + font-size: 0.875rem; + color: #94a3b8; + margin-right: 0.25rem; +} + +.section-hint { + margin-top: 0.5rem; + font-size: 11px; + color: #94a3b8; +} + +.form-group.condition-trait-fullwidth { + display: block !important; +} +.form-group.condition-trait-fullwidth > .control-label { + display: none !important; +} +.form-group.condition-trait-fullwidth > .col-lg-8, +.form-group.condition-trait-fullwidth > .col-lg-8.col-lg-offset-3 { + width: 100% !important; + max-width: 100% !important; + flex: 0 0 100% !important; + padding-left: 1.5rem !important; + padding-right: 1.5rem !important; + margin: 0 !important; + margin-left: 0 !important; +} + +.condition-traits-group-label { + font-size: 0.875rem; + font-weight: 600; + color: #334155; + margin-bottom: 1rem; +} + +.condition-traits-wrapper { + display: flex; + flex-direction: column; + gap: 1rem; +} + +.entity-selector-collapse-header { + padding: 0; + margin-bottom: 0.5rem; +} +.entity-selector-collapse-header .btn-collapse-toggle { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0; + background: none; + border: none; + color: #25b9d7; + font-size: 0.875rem; + cursor: pointer; + transition: color 0.15s ease-in-out; +} +.entity-selector-collapse-header .btn-collapse-toggle:hover { + color: #1a9ab7; +} +.entity-selector-collapse-header .btn-collapse-toggle .collapse-icon { + font-size: 1.25rem; + transition: transform 0.2s; +} +.entity-selector-collapse-header .btn-collapse-toggle .collapse-label { + font-weight: 500; +} + +@keyframes slideDown { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} +/** + * Entity Selector Styles + * @package prestashop-entity-selector + * @version 2.0.0 + * + * Compiles to: assets/css/admin/entity-selector.css + */ +/** + * Combination Attributes Picker Component + * Product attribute combination selection styles + */ +.target-conditions-trait .combination-attributes-picker, +.entity-selector-trait .combination-attributes-picker { + display: flex; + flex-direction: column; + gap: 0.625rem; +} +.target-conditions-trait .combination-mode-toggle, +.entity-selector-trait .combination-mode-toggle { + display: inline-flex; + gap: 0.25rem; + padding: 0.125rem; + background: #f1f5f9; + border-radius: 0.25rem; + margin-bottom: 0.5rem; +} +.target-conditions-trait .combination-mode-option, +.entity-selector-trait .combination-mode-option { + display: flex; + align-items: center; + gap: 0.25rem; + cursor: pointer; + font-size: 11px; + color: #6c757d; + padding: 0.25rem 0.625rem; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .combination-mode-option input[type=radio], +.entity-selector-trait .combination-mode-option input[type=radio] { + display: none; +} +.target-conditions-trait .combination-mode-option .mode-label, +.entity-selector-trait .combination-mode-option .mode-label { + user-select: none; +} +.target-conditions-trait .combination-mode-option:hover, +.entity-selector-trait .combination-mode-option:hover { + color: #25b9d7; + background: rgba(37, 185, 215, 0.1); +} +.target-conditions-trait .combination-mode-option:has(input[type=radio]:checked), +.entity-selector-trait .combination-mode-option:has(input[type=radio]:checked) { + background: #25b9d7; + color: #ffffff; + font-weight: 500; +} +.target-conditions-trait .combination-groups-container, +.entity-selector-trait .combination-groups-container { + display: flex; + flex-wrap: wrap; + gap: 1rem; +} +.target-conditions-trait .combination-loading, +.target-conditions-trait .combination-empty, +.target-conditions-trait .combination-error, +.entity-selector-trait .combination-loading, +.entity-selector-trait .combination-empty, +.entity-selector-trait .combination-error { + color: #6c757d; + font-style: italic; + padding: 0.5rem; +} +.target-conditions-trait .combination-error, +.entity-selector-trait .combination-error { + color: #dc3545; +} +.target-conditions-trait .combinations-section, +.entity-selector-trait .combinations-section { + margin-bottom: 1rem; +} +.target-conditions-trait .combinations-header, +.entity-selector-trait .combinations-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 0.5rem; +} +.target-conditions-trait .combinations-label, +.entity-selector-trait .combinations-label { + font-size: 0.75rem; + font-weight: 500; + color: #6c757d; +} +.target-conditions-trait .combinations-help, +.entity-selector-trait .combinations-help { + font-size: 11px; + color: #94a3b8; +} +.target-conditions-trait .btn-toggle-combinations, +.entity-selector-trait .btn-toggle-combinations { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .btn-toggle-combinations:focus, +.entity-selector-trait .btn-toggle-combinations:focus { + outline: none; +} +.target-conditions-trait .btn-toggle-combinations, +.entity-selector-trait .btn-toggle-combinations { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + font-size: 0.75rem; + color: #25b9d7; + background: transparent; + border: 1px solid #25b9d7; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .btn-toggle-combinations:hover, +.entity-selector-trait .btn-toggle-combinations:hover { + background: rgba(37, 185, 215, 0.1); +} +.target-conditions-trait .btn-remove-combinations, +.entity-selector-trait .btn-remove-combinations { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .btn-remove-combinations:focus, +.entity-selector-trait .btn-remove-combinations:focus { + outline: none; +} +.target-conditions-trait .btn-remove-combinations, +.entity-selector-trait .btn-remove-combinations { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + font-size: 0.75rem; + color: #dc3545; + background: transparent; +} +.target-conditions-trait .btn-remove-combinations:hover, +.entity-selector-trait .btn-remove-combinations:hover { + text-decoration: underline; +} +.target-conditions-trait .comb-attr-group, +.entity-selector-trait .comb-attr-group { + flex: none; + min-width: 120px; + max-width: 200px; + background: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.2rem; + overflow: hidden; +} +.target-conditions-trait .comb-attr-group.has-selections, +.entity-selector-trait .comb-attr-group.has-selections { + border-color: #25b9d7; +} +.target-conditions-trait .comb-attr-group-header, +.entity-selector-trait .comb-attr-group-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.375rem 0.625rem; + background: #f1f5f9; + border-bottom: 1px solid #dee2e6; + font-weight: 600; + font-size: 0.75rem; + color: #1e293b; +} +.comb-attr-group.has-selections .target-conditions-trait .comb-attr-group-header, +.comb-attr-group.has-selections .entity-selector-trait .comb-attr-group-header { + background: #ecfeff; + border-bottom-color: #a5f3fc; +} +.target-conditions-trait .comb-attr-group-name, +.entity-selector-trait .comb-attr-group-name { + flex: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.target-conditions-trait .comb-attr-group-count, +.entity-selector-trait .comb-attr-group-count { + flex-shrink: 0; + min-width: 18px; + height: 18px; + padding: 0 0.25rem; + background: #dee2e6; + border-radius: 50rem; + font-size: 11px; + font-weight: 600; + line-height: 18px; + text-align: center; + color: #6c757d; +} +.comb-attr-group.has-selections .target-conditions-trait .comb-attr-group-count, +.comb-attr-group.has-selections .entity-selector-trait .comb-attr-group-count { + background: #25b9d7; + color: #ffffff; +} +.target-conditions-trait .comb-attr-toolbar, +.entity-selector-trait .comb-attr-toolbar { + display: flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.375rem; + background: #f8fafc; + border-bottom: 1px solid #f1f5f9; +} +.target-conditions-trait .comb-toolbar-btn, +.entity-selector-trait .comb-toolbar-btn { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .comb-toolbar-btn:focus, +.entity-selector-trait .comb-toolbar-btn:focus { + outline: none; +} +.target-conditions-trait .comb-toolbar-btn, +.entity-selector-trait .comb-toolbar-btn { + display: flex; + align-items: center; + justify-content: center; + width: 22px; + height: 22px; + padding: 0; + background: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.2rem; + color: #6c757d; + cursor: pointer; + font-size: 0.75rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .comb-toolbar-btn:hover, +.entity-selector-trait .comb-toolbar-btn:hover { + background: #f1f5f9; + border-color: #94a3b8; + color: #1e293b; +} +.target-conditions-trait .comb-attr-search, +.entity-selector-trait .comb-attr-search { + flex: 1; + min-width: 60px; + padding: 0.125rem 0.375rem; + border: 1px solid #dee2e6; + border-radius: 0.2rem; + font-size: 11px; + outline: none; +} +.target-conditions-trait .comb-attr-search:focus, +.entity-selector-trait .comb-attr-search:focus { + border-color: #25b9d7; +} +.target-conditions-trait .comb-attr-search::placeholder, +.entity-selector-trait .comb-attr-search::placeholder { + color: #94a3b8; +} +.target-conditions-trait .comb-attr-values, +.entity-selector-trait .comb-attr-values { + display: flex; + flex-wrap: wrap; + gap: 0.25rem; + padding: 0.375rem; + max-height: 150px; + overflow-y: auto; +} +.target-conditions-trait .comb-attr-values::-webkit-scrollbar, +.entity-selector-trait .comb-attr-values::-webkit-scrollbar { + width: 6px; + height: 6px; +} +.target-conditions-trait .comb-attr-values::-webkit-scrollbar-track, +.entity-selector-trait .comb-attr-values::-webkit-scrollbar-track { + background: #f8f9fa; + border-radius: 3px; +} +.target-conditions-trait .comb-attr-values::-webkit-scrollbar-thumb, +.entity-selector-trait .comb-attr-values::-webkit-scrollbar-thumb { + background: #dee2e6; + border-radius: 3px; +} +.target-conditions-trait .comb-attr-values::-webkit-scrollbar-thumb:hover, +.entity-selector-trait .comb-attr-values::-webkit-scrollbar-thumb:hover { + background: #ced4da; +} +.target-conditions-trait .comb-attr-loading, +.target-conditions-trait .comb-attr-empty, +.target-conditions-trait .comb-attr-error, +.entity-selector-trait .comb-attr-loading, +.entity-selector-trait .comb-attr-empty, +.entity-selector-trait .comb-attr-error { + width: 100%; + text-align: center; + color: #94a3b8; + font-size: 11px; + padding: 0.25rem; +} +.target-conditions-trait .comb-attr-error, +.entity-selector-trait .comb-attr-error { + color: #dc3545; +} +.target-conditions-trait .comb-attr-value, +.entity-selector-trait .comb-attr-value { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.125rem 0.5rem; + background: #ffffff; + border: 1px solid #94a3b8; + border-radius: 0.75rem; + font-size: 11px; + color: #475569; + cursor: pointer; + transition: all 0.15s ease-in-out; + white-space: nowrap; +} +.target-conditions-trait .comb-attr-value:hover, +.entity-selector-trait .comb-attr-value:hover { + background: #f1f5f9; + border-color: #6c757d; +} +.target-conditions-trait .comb-attr-value.selected, +.entity-selector-trait .comb-attr-value.selected { + background: #25b9d7; + border-color: #1a9ab7; + color: #ffffff; +} +.target-conditions-trait .comb-attr-value.selected:hover, +.entity-selector-trait .comb-attr-value.selected:hover { + background: #1a9ab7; + border-color: rgb(22.8277511962, 135.2105263158, 160.6722488038); +} +.target-conditions-trait .comb-attr-value-count, +.entity-selector-trait .comb-attr-value-count { + font-size: 9px; + color: #94a3b8; + background: #f1f5f9; + padding: 1px 0.25rem; + border-radius: 0.5rem; + min-width: 14px; + text-align: center; +} +.comb-attr-value.selected .target-conditions-trait .comb-attr-value-count, +.comb-attr-value.selected .entity-selector-trait .comb-attr-value-count { + color: #ffffff; + background: rgba(255, 255, 255, 0.3); +} +.target-conditions-trait .combination-conditions-container, +.entity-selector-trait .combination-conditions-container { + display: flex; + flex-direction: column; + gap: 0.5rem; +} +.target-conditions-trait .combination-condition-row, +.entity-selector-trait .combination-condition-row { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem; + background: #f8fafc; + border-radius: 0.2rem; +} +.target-conditions-trait .combination-group-select, +.target-conditions-trait .combination-values-select, +.entity-selector-trait .combination-group-select, +.entity-selector-trait .combination-values-select { + flex: 1; + min-width: 120px; +} +.target-conditions-trait .combination-equals, +.entity-selector-trait .combination-equals { + font-size: 0.75rem; + color: #6c757d; + padding: 0 0.25rem; +} +.target-conditions-trait .btn-add-combination-condition, +.entity-selector-trait .btn-add-combination-condition { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .btn-add-combination-condition:focus, +.entity-selector-trait .btn-add-combination-condition:focus { + outline: none; +} +.target-conditions-trait .btn-add-combination-condition, +.entity-selector-trait .btn-add-combination-condition { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.375rem 0.75rem; + font-size: 0.75rem; + font-weight: 500; + color: #25b9d7; + background: transparent; + border: 1px dashed #25b9d7; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .btn-add-combination-condition:hover, +.entity-selector-trait .btn-add-combination-condition:hover { + background: rgba(37, 185, 215, 0.1); +} +.target-conditions-trait .btn-add-combination-condition i, +.entity-selector-trait .btn-add-combination-condition i { + font-size: 10px; +} +.target-conditions-trait .btn-remove-combination-row, +.entity-selector-trait .btn-remove-combination-row { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.target-conditions-trait .btn-remove-combination-row:focus, +.entity-selector-trait .btn-remove-combination-row:focus { + outline: none; +} +.target-conditions-trait .btn-remove-combination-row, +.entity-selector-trait .btn-remove-combination-row { + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + color: #6c757d; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +.target-conditions-trait .btn-remove-combination-row:hover, +.entity-selector-trait .btn-remove-combination-row:hover { + background: rgba(220, 53, 69, 0.1); + color: #dc3545; +} +.target-conditions-trait .btn-remove-combination-row i, +.entity-selector-trait .btn-remove-combination-row i { + font-size: 12px; +} + +/** + * Entity Selector Styles + * @package prestashop-entity-selector + * @version 2.0.0 + * + * Compiles to: assets/css/admin/entity-selector.css + */ +/** + * Method Dropdown Component + * Custom select dropdown with icons for method selection + */ +.target-conditions-trait .method-dropdown-trigger, +.entity-selector-trait .method-dropdown-trigger { + display: inline-flex; + align-items: center; + gap: 0.5rem; + height: 36px; + padding: 0 1rem; + border-radius: 0.25rem; + background: #ffffff; + color: #1e293b; + font-size: 0.875rem; + cursor: pointer; + transition: all 0.15s ease-in-out; + min-width: 180px; + max-width: 320px; + border: 1px solid #dee2e6; +} +.target-conditions-trait .method-dropdown-trigger:hover, +.entity-selector-trait .method-dropdown-trigger:hover { + background: #f8fafc; + border-color: #dee2e6; +} +.target-conditions-trait .method-dropdown-trigger:focus, .target-conditions-trait .method-dropdown-trigger:active, +.entity-selector-trait .method-dropdown-trigger:focus, +.entity-selector-trait .method-dropdown-trigger:active { + outline: none; + border-color: #25b9d7; + box-shadow: 0 0 0 3px rgba(37, 185, 215, 0.1); +} +.target-conditions-trait .method-trigger-icon, +.entity-selector-trait .method-trigger-icon { + font-size: 0.875rem; + color: #6c757d; + flex-shrink: 0; + width: 18px; + text-align: center; +} +.target-conditions-trait .method-trigger-label, +.entity-selector-trait .method-trigger-label { + flex: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + font-weight: 500; +} +.target-conditions-trait .method-trigger-caret, +.entity-selector-trait .method-trigger-caret { + font-size: 0.75rem; + color: #94a3b8; + flex-shrink: 0; + margin-left: auto; +} +.target-conditions-trait .selector-locked .method-dropdown-trigger, +.entity-selector-trait .selector-locked .method-dropdown-trigger { + background: #f1f5f9; + color: #94a3b8; + cursor: not-allowed; + border-color: #dee2e6; +} +.target-conditions-trait .selector-locked .method-dropdown-trigger:hover, +.entity-selector-trait .selector-locked .method-dropdown-trigger:hover { + background: #f1f5f9; + border-color: #dee2e6; +} +.target-conditions-trait .method-selector-wrapper, +.entity-selector-trait .method-selector-wrapper { + position: relative; +} +.target-conditions-trait .method-select-hidden, +.entity-selector-trait .method-select-hidden { + position: absolute !important; + opacity: 0 !important; + pointer-events: none !important; + width: 0 !important; + height: 0 !important; + overflow: hidden !important; +} + +.method-select-hidden { + position: absolute !important; + opacity: 0 !important; + pointer-events: none !important; + width: 0 !important; + height: 0 !important; + overflow: hidden !important; +} + +.method-dropdown-menu { + position: absolute; + z-index: 1001; + min-width: 200px; + max-width: 360px; + max-height: 400px; + overflow-y: auto; + background: #ffffff; + border-radius: 0.3rem; + padding: 0.375rem 0; + border: 1px solid #dee2e6; + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15); + animation: methodDropdownFadeIn 0.15s ease; +} +.method-dropdown-menu::-webkit-scrollbar { + width: 6px; + height: 6px; +} +.method-dropdown-menu::-webkit-scrollbar-track { + background: #f8f9fa; + border-radius: 3px; +} +.method-dropdown-menu::-webkit-scrollbar-thumb { + background: #dee2e6; + border-radius: 3px; +} +.method-dropdown-menu::-webkit-scrollbar-thumb:hover { + background: #ced4da; +} + +@keyframes methodDropdownFadeIn { + from { + opacity: 0; + transform: translateY(-4px); + } + to { + opacity: 1; + transform: translateY(0); + } +} +.method-dropdown-item { + display: flex; + align-items: center; + gap: 0.625rem; + padding: 0.5rem 1rem; + cursor: pointer; + transition: background-color 0.1s; + position: relative; +} +.method-dropdown-item:hover { + background: #f1f5f9; +} +.method-dropdown-item.selected { + background: rgba(37, 185, 215, 0.08); +} +.method-dropdown-item .method-item-icon { + font-size: 0.875rem; + color: #6c757d; + width: 18px; + text-align: center; + flex-shrink: 0; +} +.method-dropdown-item.selected .method-item-icon { + color: #25b9d7; +} +.method-dropdown-item .method-item-label { + flex: 1; + font-size: 0.875rem; + color: #334155; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.method-dropdown-item.selected .method-item-label { + color: #0e7490; + font-weight: 500; +} +.method-dropdown-item .method-item-check { + font-size: 0.75rem; + flex-shrink: 0; + margin-left: auto; + color: #25b9d7; +} + +.method-dropdown-optgroup { + margin-top: 0.25rem; +} +.method-dropdown-optgroup:first-child { + margin-top: 0; +} + +.method-optgroup-label { + padding: 0.5rem 1rem; + font-size: 11px; + font-weight: 600; + color: #6c757d; + text-transform: uppercase; + letter-spacing: 0.05em; + background: #f8fafc; + border-top: 1px solid #f1f5f9; + border-bottom: 1px solid #f1f5f9; +} +.method-dropdown-optgroup:first-child .method-optgroup-label { + border-top: 0; +} + +.method-optgroup-items { + padding: 0.25rem 0; +} +.method-optgroup-items .method-dropdown-item { + padding-left: 1.5rem; +} + +.method-info-placeholder { + font-size: 0.75rem; + color: #6c757d; + font-style: italic; +} + +/** + * Entity Selector Styles + * @package prestashop-entity-selector + * @version 2.0.0 + * + * Compiles to: assets/css/admin/entity-selector.css + */ +/** + * Tooltip Component + * Info tooltips for method help + */ +.mpr-info-wrapper { + display: inline-flex; + align-items: center; + position: relative; + cursor: help; + vertical-align: middle; + margin-left: 0.25rem; +} +.mpr-info-wrapper .material-icons { + font-size: 16px !important; + color: #6c757d; + transition: color 0.15s ease; +} +.mpr-info-wrapper:hover .material-icons { + color: #25b9d7; +} + +.mpr-tooltip-fixed { + position: fixed; + background: #ffffff; + color: #1e293b; + padding: 1rem 1.5rem; + border-radius: 0.25rem; + font-size: 13px; + line-height: 1.5; + white-space: normal; + z-index: 10500; + max-width: 320px; + min-width: 180px; + text-align: left; + box-shadow: rgba(0, 0, 0, 0.12) 0px 1px 1px 0px, rgba(64, 68, 82, 0.16) 0px 0px 0px 1px, rgba(64, 68, 82, 0.08) 0px 2px 5px 0px; + pointer-events: none; +} +.mpr-tooltip-fixed.pinned { + pointer-events: auto; + padding-right: 3rem; +} +.mpr-tooltip-fixed strong { + display: block; + margin-bottom: 0.375rem; + font-weight: 600; + color: #25b9d7; +} +.mpr-tooltip-fixed p { + margin: 0; + color: #495057; +} +.mpr-tooltip-fixed ul { + margin: 0.5rem 0 0; + padding-left: 1.25rem; +} +.mpr-tooltip-fixed ul li { + margin: 0.25rem 0; + color: #495057; +} + +.mpr-tooltip-close { + position: absolute; + top: 0.375rem; + right: 0.375rem; + padding: 0.125rem; + border: none; + background: transparent; + cursor: pointer; + border-radius: 0.2rem; + line-height: 1; + transition: background-color 0.15s ease; +} +.mpr-tooltip-close .material-icons { + font-size: 16px !important; + color: #6c757d; +} +.mpr-tooltip-close:hover { + background: #f1f5f9; +} +.mpr-tooltip-close:hover .material-icons { + color: #334155; +} + +/** + * Entity Selector Styles + * @package prestashop-entity-selector + * @version 2.0.0 + * + * Compiles to: assets/css/admin/entity-selector.css + */ +/** + * Category Tree Component + * Hierarchical tree view for category selection inside dropdown + */ +.category-tree { + display: flex; + flex-direction: column; +} + +.category-tree .tree-toolbar { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.25rem 0.5rem; + background: #f8fafc; + border-bottom: 1px solid #e9ecef; + flex-shrink: 0; +} +.category-tree .tree-toolbar .btn-expand-all, +.category-tree .tree-toolbar .btn-collapse-all { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.category-tree .tree-toolbar .btn-expand-all:focus, +.category-tree .tree-toolbar .btn-collapse-all:focus { + outline: none; +} +.category-tree .tree-toolbar .btn-expand-all, +.category-tree .tree-toolbar .btn-collapse-all { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + font-size: 0.75rem; + font-weight: 500; + color: #495057; + background: #ffffff; + border: 1px solid #dee2e6; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; +} +.category-tree .tree-toolbar .btn-expand-all:hover, +.category-tree .tree-toolbar .btn-collapse-all:hover { + background: #f1f5f9; + border-color: #cbd5e1; +} +.category-tree .tree-toolbar .btn-expand-all i, +.category-tree .tree-toolbar .btn-collapse-all i { + font-size: 12px; +} + +.category-tree .tree-items { + padding: 0; +} + +.tree-item { + display: flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + cursor: pointer; + transition: background 0.15s ease-in-out; + border-radius: 0; +} +.tree-item:hover { + background: #f1f5f9; +} +.tree-item.selected { + background: rgba(37, 185, 215, 0.1); +} +.tree-item.selected .tree-name { + font-weight: 600; + color: #25b9d7; +} +.tree-item.selected .tree-checkbox { + color: #25b9d7; +} +.tree-item.selected .tree-checkbox i { + opacity: 1; +} +.tree-item.inactive { + opacity: 0.6; +} +.tree-item.inactive .tree-name { + font-style: italic; +} +.tree-item.filtered-out { + display: none; +} +.tree-item.filter-match { + background: #fff3cd; +} +.tree-item.filter-match.selected { + background: rgba(37, 185, 215, 0.1); +} + +.category-tree .tree-indent { + flex-shrink: 0; +} +.category-tree .tree-toggle { + display: flex; + align-items: center; + justify-content: center; + width: 12px; + height: 12px; + box-sizing: border-box; + color: #495057; + flex-shrink: 0; + border-radius: 0.2rem; + transition: all 0.15s ease-in-out; + cursor: pointer; +} +.category-tree .tree-toggle:hover { + background: #e2e8f0; + color: #212529; +} +.category-tree .tree-toggle.tree-leaf { + cursor: default; + visibility: hidden; +} +.category-tree .tree-toggle.tree-leaf:hover { + background: transparent; +} +.category-tree .tree-toggle i { + font-size: 10px; + transition: transform 0.15s ease-in-out; +} +.category-tree .tree-item.collapsed > .tree-toggle i { + transform: rotate(-90deg); +} +.category-tree .tree-checkbox { + display: flex; + align-items: center; + justify-content: center; + width: 12px; + height: 12px; + box-sizing: border-box; + flex-shrink: 0; + border: 1px solid #dee2e6; + border-radius: 2px; + background: #ffffff; +} +.category-tree .tree-checkbox i { + font-size: 8px; + opacity: 0; + color: #ffffff; + transition: opacity 0.15s ease-in-out; +} +.category-tree .tree-item.selected .tree-checkbox { + background: #25b9d7; + border-color: #25b9d7; +} +.category-tree .tree-item.selected .tree-checkbox i { + opacity: 1; +} +.category-tree .tree-icon { + display: flex; + align-items: center; + justify-content: center; + width: 12px; + height: 12px; + box-sizing: border-box; + color: #6c757d; + flex-shrink: 0; +} +.category-tree .tree-icon i { + font-size: 12px; +} +.category-tree .tree-item.selected .tree-icon { + color: #25b9d7; +} +.category-tree .tree-name { + flex: 1; + font-size: 0.875rem; + color: #212529; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.category-tree .tree-count { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.25rem; + min-width: 20px; + height: 20px; + padding: 0 0.5rem; + background: #25b9d7; + color: #ffffff; + font-size: 0.75rem; + font-weight: 600; + border-radius: 50rem; + cursor: pointer; + transition: all 0.15s ease-in-out; + flex-shrink: 0; +} +.category-tree .tree-count:hover { + transform: scale(1.05); + box-shadow: 0 2px 8px rgba(37, 185, 215, 0.4); +} +.category-tree .tree-count:focus { + outline: none; + box-shadow: 0 0 0 2px rgba(37, 185, 215, 0.3), 0 2px 8px rgba(37, 185, 215, 0.4); +} +.category-tree .tree-count.loading { + cursor: wait; +} +.category-tree .tree-count.loading i { + font-size: 10px; + animation: spin 0.6s linear infinite; +} +.category-tree .tree-count.loading:hover { + transform: none; + box-shadow: none; +} +.category-tree .tree-count.inactive, .category-tree .tree-count.no-matches { + background: #94a3b8; + cursor: default; +} +.category-tree .tree-count.inactive:hover, .category-tree .tree-count.no-matches:hover { + transform: none; + box-shadow: none; +} +.category-tree .tree-count.popover-open { + background: rgb(29.5119047619, 147.5595238095, 171.4880952381); + box-shadow: 0 2px 8px rgba(37, 185, 215, 0.4); +} +.category-tree .tree-count i { + font-size: 10px; + line-height: 1; + opacity: 0.8; +} +.category-tree .tree-count:hover i { + opacity: 1; +} +.category-tree .tree-count .preview-count { + font-weight: 700; +} +.category-tree .tree-count { + height: 18px; + min-width: 18px; + padding: 0 0.5rem; +} +.category-tree .tree-count i { + font-size: 10px; +} +.category-tree .tree-count.clickable.loading { + pointer-events: none; +} +.category-tree .tree-count.clickable.loading i { + animation: spin 1s linear infinite; +} +.category-tree .tree-count.clickable.popover-open { + background: rgb(29.5119047619, 147.5595238095, 171.4880952381); +} +.category-tree .btn-select-children { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.category-tree .btn-select-children:focus { + outline: none; +} +.category-tree .btn-select-children { + display: inline-flex; + align-items: center; + justify-content: center; + width: 12px; + height: 12px; + box-sizing: border-box; + color: #6c757d; + border-radius: 0.2rem; + opacity: 0.3; + transition: all 0.15s ease-in-out; + flex-shrink: 0; +} +.category-tree .btn-select-children i { + font-size: 14px; +} +.category-tree .btn-select-children:hover { + color: #25b9d7; + opacity: 1; +} +.category-tree .tree-item:hover .btn-select-children { + opacity: 0.6; +} +.category-tree .tree-badge { + display: inline-flex; + align-items: center; + padding: 0.125rem 0.25rem; + font-size: 9px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.025em; + border-radius: 0.2rem; + flex-shrink: 0; +} +.category-tree .tree-badge.inactive { + color: #fab000; + background: #fff3cd; +} +.category-tree .tree-children { + display: block; +} +.category-tree .tree-children.filter-expanded { + display: block !important; +} +.category-tree .tree-item.collapsed + .tree-children { + display: none; +} +.category-tree .tree-item.filtered-out { + display: none !important; +} + +.category-tree .tree-loading, +.category-tree .dropdown-empty, +.category-tree .dropdown-error { + display: flex; + align-items: center; + justify-content: center; + padding: 2rem; + color: #6c757d; + font-size: 0.875rem; +} +.category-tree .tree-loading i, +.category-tree .dropdown-empty i, +.category-tree .dropdown-error i { + margin-right: 0.5rem; +} + +.category-tree .dropdown-error { + color: #dc3545; +} + +.target-search-dropdown.view-tree .dropdown-results { + padding: 0; +} +.target-search-dropdown.view-tree .category-tree { + max-height: 100%; + overflow-y: auto; +} +.target-search-dropdown.view-tree .category-tree::-webkit-scrollbar { + width: 6px; + height: 6px; +} +.target-search-dropdown.view-tree .category-tree::-webkit-scrollbar-track { + background: #f8f9fa; + border-radius: 3px; +} +.target-search-dropdown.view-tree .category-tree::-webkit-scrollbar-thumb { + background: #dee2e6; + border-radius: 3px; +} +.target-search-dropdown.view-tree .category-tree::-webkit-scrollbar-thumb:hover { + background: #ced4da; +} +.target-search-dropdown.view-tree .tree-items { + max-height: calc(100% - 40px); + overflow-y: auto; +} +.target-search-dropdown.view-tree .tree-items::-webkit-scrollbar { + width: 6px; + height: 6px; +} +.target-search-dropdown.view-tree .tree-items::-webkit-scrollbar-track { + background: #f8f9fa; + border-radius: 3px; +} +.target-search-dropdown.view-tree .tree-items::-webkit-scrollbar-thumb { + background: #dee2e6; + border-radius: 3px; +} +.target-search-dropdown.view-tree .tree-items::-webkit-scrollbar-thumb:hover { + background: #ced4da; +} + +/** + * Entity Selector Styles + * @package prestashop-entity-selector + * @version 2.0.0 + * + * Compiles to: assets/css/admin/entity-selector.css + */ +/** + * Validation Toast Component + * Error notifications for selection conflicts + */ +.es-validation-toast { + display: flex; + align-items: flex-start; + gap: 0.5rem; + padding: 1rem; + background: #ffffff; + border: 1px solid #dc3545; + border-left: 4px solid #dc3545; + border-radius: 0.25rem; + box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.175); + max-width: 400px; + animation: es-toast-slide-in 0.2s ease-out; +} +.es-validation-toast .es-toast-icon { + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + color: #dc3545; + flex-shrink: 0; +} +.es-validation-toast .es-toast-icon i { + font-size: 18px; +} +.es-validation-toast .es-toast-content { + flex: 1; + min-width: 0; +} +.es-validation-toast .es-toast-title { + font-size: 0.875rem; + font-weight: 600; + color: #dc3545; + margin-bottom: 2px; +} +.es-validation-toast .es-toast-message { + font-size: 0.75rem; + color: #495057; + line-height: 1.4; +} +.es-validation-toast .es-toast-close { + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + font: inherit; + color: inherit; +} +.es-validation-toast .es-toast-close:focus { + outline: none; +} +.es-validation-toast .es-toast-close { + display: flex; + align-items: center; + justify-content: center; + width: 20px; + height: 20px; + color: #6c757d; + border-radius: 0.2rem; + flex-shrink: 0; + transition: all 0.15s ease-in-out; +} +.es-validation-toast .es-toast-close:hover { + background: #f1f5f9; + color: #212529; +} +.es-validation-toast .es-toast-close i { + font-size: 12px; +} + +@keyframes es-toast-slide-in { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} +/*# sourceMappingURL=entity-selector.css.map */ diff --git a/assets/assets/css/admin/entity-selector.css.map b/assets/assets/css/admin/entity-selector.css.map new file mode 100644 index 0000000..dbb209c --- /dev/null +++ b/assets/assets/css/admin/entity-selector.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["main.scss","_variables.scss","../../../prestashop-admin/assets/scss/_variables.scss","_mixins.scss","layouts/_form-integration.scss","layouts/_responsive.scss","components/_entity-selector.scss","components/_entity-item.scss","components/_dropdown.scss","components/_chips.scss","components/_groups.scss","components/_value-picker.scss","components/_modal.scss","components/_list-preview.scss","components/_schedule.scss","components/_tips.scss","components/_condition-trait.scss","components/_combinations.scss","components/_method-dropdown.scss","components/_tooltip.scss","components/_tree.scss","components/_validation.scss"],"names":[],"mappings":"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I,qBJvHH;;AI2HL;AAAA;EACI;EACA;EACA,KL5DQ;EK6DR;EACA,YLhIU;EKiIV;EACA,WLhBU;EKiBV,aLZgB;EKahB;;AAEA;AAAA;EACI,OJvIH;;AI4IL;AAAA;EACI;EACA,OJ9IC;;AIkJL;AAAA;EACI;EACA,YLlKG;EKmKH;;AAIJ;AAAA;EACI;EACA;EACA;EACA;EACA,YLrIO;EKsIP;;AAGJ;AAAA;EACI;EACA;EACA;EACA,KLpGQ;EKqGR;EACA;EACA;EACA;EACA;EACA;EACA;EACA,OJhLI;EIiLJ,WL7DU;EK8DV,aLzDgB;EK0DhB;EACA;;AAEA;AAAA;EACI,YL3JG;EK4JH,OLvJG;;AK0JP;AAAA;EACI,YLxMD;EKyMC,qBLpJE;EKqJF,OJhMF;;AImMF;AAAA;EACI;;AAGJ;AAAA;EACI;;AAGJ;AAAA;EHlDJ;EACA;EACA;EACA;EACA;EACA;EACA;EACA,YDhKM;ECiKN,OF3KO;EE4KP,WF7Cc;EE8Cd,aFvCsB;EEwCtB,eFjFa;EEkFb;EACA;EACA;;AAEA;AAAA;EACI;EACA;;AAIJ;AAAA;EACI;EACA;;AAIJ;AAAA;EACI;;AAEA;AAAA;EACI;EACA;;AAGJ;AAAA;EACI;EACA;;AAKR;AAAA;AAAA;EAEI,YFtKO;EEuKP;;AAEA;AAAA;AAAA;EACI;EACA;;AAKR;AAAA;EACI;EACA;;AAIJ;AAAA;EACI;EACA;EACA;;AAGJ;AAAA;EACI;;AAGJ;AAAA;EACI,aFpGc;;AKkFd;AAAA;EHtDJ;EACA;EACA;EACA;EACA;EACA;EACA;EACA,YFhIW;EEiIX,OF3KO;EE4KP,WF7Cc;EE8Cd,aFvCsB;EEwCtB,eFjFa;EEkFb;EACA;EACA;;AAEA;AAAA;EACI;EACA;;AAIJ;AAAA;EACI;EACA;;AAIJ;AAAA;EACI;;AAEA;AAAA;EACI;EACA;;AAGJ;AAAA;EACI;EACA;;AAKR;AAAA;AAAA;EAEI,YFtKO;EEuKP;;AAEA;AAAA;AAAA;EACI;EACA;;AAKR;AAAA;EACI;EACA;;AAIJ;AAAA;EACI;EACA;EACA;;AAGJ;AAAA;EACI;;AAGJ;AAAA;EACI,aFpGc;;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ACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,eLvMe;EKwMf;EACA;EACA,ONpOU;EMqOV;EACA;;AAEA;EACI,OLhQI;EKiQJ;;AAGJ;EACI;EACA,cLxQE;EKyQF;;;AAKR;EACI;EACA;EACA;EACA;EACA,eLhOe;EKiOf;EACA;EACA;EACA;EACA,ONjQU;EMkQV;EACA;EACA;;AAEA;EACI,cL9RE;;AKiSN;EACI;EACA,cLnSE;EKoSF;;;AAKR;EACI;EACA;EACA;EACA;EACA;EACA,YNjRW;EMkRX,ONzRU;EM0RV;EACA,aNtLsB;EMuLtB,eLhQe;EKiQf;EACA;;AAEA;EACI,YN/QM;EMgRN,ON5QM;;;AMiRd;EJzSI;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AIgSR;EAEI;EACA;EACA;EACA;EACA;EACA,OLjUK;EKkUL;EACA,aN5MoB;EM6MpB;EACA,eLtRe;EKuRf;EACA;EACA;;AAEA;EACI,YL3UC;EK4UD,ON1VG;;AM6VP;EACI;EACA;;;AAKR;EACI;EACA;EACA,KNxRY;EMyRZ;EACA;EACA;EACA;;AJhPA;EACI;EACA;;AAGJ;EACI,YDhHA;ECiHA;;AAGJ;EACI,YD3EO;EC4EP;;AAEA;EACI,YF5GE;;AMgVV;EACI;;AAIJ;EACI;EACA;EACA;EACA,SNvSQ;;;AM4ShB;EACI;EACA;EACA;EACA,KNhTY;EMiTZ;EACA;EACA;;AAEA;EACI,WNvQU;EMwQV,OL3XI;;AK8XR;EACI;EACA;EACA;EACA,eLjVW;EKkVX;EACA;EACA,WNlRU;EMmRV,aN7QgB;EM8QhB,OLzYE;EK0YF;EACA;EACA;EACA;EACA;;AAEA;EACI,cLjZF;EKkZE,kBNtZO;;AMyZX;EACI;EACA,cLvZF;EKwZE;;AAIR;EACI,WNxSU;EMySV,OL5ZI;;AK8ZJ;EACI,aNrSc;EMsSd,ON3YE;;AM+YV;EACI;EACA;EACA;EACA,SNrWQ;EMsWR;EACA;EACA,OL7aE;EK8aF,YNlbW;EMmbX,eL5XW;EK6XX;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAGJ;EACI;;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ACA;EACA;EACA;EACA;EACA;EACA;EACA,eNlQW;EMmQX;;AAEA;AAAA;AAAA;AAAA;EACI;EACA;EACA,OPrUD;;AOwUH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAEI,YNhUF;EMiUE,cNjUF;;AMmUE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACI;;AAMZ;AAAA;EACI;EACA;EACA,KPvQQ;;AO2QZ;AAAA;EACI;EACA;EACA;EACA,KP/QQ;EOgRR,SP7QQ;EO8QR,ONrVI;EMsVJ,WPlOU;;AOoOV;AAAA;EACI;EACA;;AAKR;AAAA;EACI;EACA;EACA;EACA;EACA,KPhSQ;EOiSR,SP9RQ;EO+RR;EACA,ONvWI;;AMyWJ;AAAA;EACI;EACA;;AAGJ;AAAA;EACI;EACA,WP5PM;;AOiQd;AAAA;EACI;EACA;EACA;EACA,SPlTQ;EOmTR,ON1XI;;AM4XJ;AAAA;EACI;EACA;;AAKR;AAAA;EACI;EACA;EACA;EACA,KNrZC;EMsZD;EACA,YP/WM;EOgXN;EACA;;AAIJ;AAAA;EACI;EACA;EACA,KP/UQ;EOgVR,WPhSU;EOiSV,ONpZI;;AMsZJ;AAAA;EACI,ONvZA;;AM0ZJ;AAAA;AAAA;AAAA;EAEI;EACA;EACA;EACA,eN9WO;EM+WP;EACA;EACA,WP/SM;EOgTN,OP9YE;EO+YF;EACA;;AAEA;AAAA;AAAA;AAAA;EACI,cN1aN;;AM6aE;AAAA;AAAA;AAAA;EACI;EACA,cN/aN;;AMmbF;AAAA;EACI,ONlbA;;AMobA;AAAA;EACI,OPhaF;EOiaE,aP5TU;;AOgUlB;AAAA;ELvaJ;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;EACI;;AK8ZA;AAAA;EAEI;EACA,WP1UM;EO2UN,ONhcF;EMicE;EACA,eN/YO;EMgZP;;AAEA;AAAA;EACI,YP1cG;;AOgdf;AAAA;EACI;EACA;EACA,KPzYQ;;AO4YZ;AAAA;EL7bA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;EACI;;AKobJ;AAAA;EAEI;EACA;EACA;EACA;EACA,WPnWU;EOoWV,aP9VgB;EO+VhB,eNvaW;EMwaX;;AA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8BF;;AMo8BN;AAAA;EL52BA;EACA;EACA,WF4Bc;EE3Bd,aFqCoB;EEpCpB,OFnEU;EEoEV,kBFvGO;EEwGP;EACA,eD7CY;EC8CZ;;AAEA;AAAA;EACI,cDnGE;ECoCN;EACA;;AAkEA;AAAA;EACI,OFnFM;;AO+6BV;AAAA;EAEI;EACA,WPl1BU;EOm1BV;EACA;;AAGJ;AAAA;AAAA;AAAA;EAEI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,ONr9BI;EMs9BJ,YPl+BG;EOm+BH;EACA,eNv6BW;EMw6BX;EACA;;AAEA;AAAA;AAAA;AAAA;EACI;;AAGJ;AAAA;AAAA;AAAA;EACI,YPj9BE;EOk9BF,OP38BE;;AO88BN;AAAA;AAAA;AAAA;EACI,YP5+BO;EO6+BP,cNz+BF;EM0+BE,ON1+BF;;AM8+BN;AAAA;EACI;EACA;;AAIA;AAAA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,ON5/BA;EM6/BA,YPzgCD;EO0gCC;EACA;EACA;EACA;EACA;;AAEA;AAAA;EACI,YPr/BF;EOs/BE,OP/+BF;;AOk/BF;AAAA;EACI,YPxgCE;EOygCF,ONzgCP;EM0gCO,cN1gCP;;AM8gCD;AAAA;EL17BJ;EACA;EACA,WF4Bc;EE3Bd,aFqCoB;EEpCpB,OFnEU;EEoEV,kBFvGO;EEwGP;EACA,eD7CY;EC8CZ;;AAEA;AAAA;EACI,cDnGE;ECoCN;EACA;;AAkEA;AAAA;EACI,OFnFM;;AO6/BN;AAAA;EAEI;EACA;EACA,WPj6BM;EOk6BN;;AAGJ;AAAA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,ONjiCA;EMkiCA,YP9iCD;EO+iCC;EACA;EACA;EACA;;AAEA;AAAA;EACI,YPzhCF;EO0hCE,OPnhCF;;AOyhCV;AAAA;EACI;EACA,SNhkCC;EMikCD,YPzhCM;EO0hCN;;AAEA;AAAA;EACI;;AAIR;AAAA;EACI;EACA;EACA,KP1/BQ;EO2/BR;EACA,eP5/BQ;;AO8/BR;AAAA;EACI;;AAIR;AAAA;EACI;EACA;EACA;EACA,WPx9BU;EOy9BV,OPvjC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A;EAEI;EACA;EACA;EACA;EACA,WPprCU;EOqrCV,OPnxCM;EOoxCN,YP9wCO;EO+wCP;EACA,eN1vCW;EM2vCX;EACA;;AAEA;AAAA;AAAA;AAAA;EACI,YPpxCG;;AOuxCP;AAAA;AAAA;AAAA;EACI,YNtzCF;EMuzCE,OPj0CD;;AO40CP;AAAA;EACI;EACA;EACA,KP/vCQ;EOgwCR,SPhwCQ;EOiwCR,YPj1CG;EOk1CH;EACA,eNtxCW;;AMwxCX;AAAA;EACI;EACA;EACA;EACA;EACA;;AAGJ;AAAA;EACI,WP/tCM;EOguCN,aPztCc;EO0tCd,OP/zCE;EOg0CF;;AAGJ;AAAA;ELr0CJ;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;EACI;;AK4zCA;AAAA;EAEI;EACA;EACA;EACA;EACA;EACA;EACA,ONh2CA;EMi2CA,eNhzCO;;AMkzCP;AAAA;EACI,YPx0CD;EOy0CC,OP90CF;;AOo1CV;AAAA;EACI,aPnvCgB;;AOsvCpB;AAAA;EACI;EACA,ONj3CI;EMk3CJ;;AAGJ;AAAA;AAAA;AAAA;EACI;;AAIJ;AAAA;EACI;EACA;;AL7wCJ;AAAA;EACI;EACA;;AAGJ;AAAA;EACI,YDhHA;ECiHA;;AAGJ;AAAA;EACI,YD3EO;EC4EP;;AAEA;AAAA;EACI,YF5GE;;AO82CV;AAAA;EACI;EACA;EACA,KPh0CQ;EOi0CR,SPh0CQ;;AOm0CZ;AAAA;EACI;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;EACI,YNl5CF;EMm5CE,cNn5CF;;AMu5CN;AAAA;EACI;EACA;EACA;EACA;EACA,eNz2CW;EM02CX,YPh4CO;;AOm4CX;AAAA;EACI;EACA;;AAGJ;AAAA;EACI,WPhzCU;EOizCV,aP5yCgB;EO6yChB,OP/4CM;EEfV;EACA;EACA;;AKg6CA;AAAA;EACI,WPxzCU;EOyzCV,ON56CI;ECQR;EACA;EACA;;AKu6CA;AAAA;EACI;EACA;EACA;EACA,KNn8CC;EMo8CD;EACA,YP75CM;EO85CN;EACA;;AAGJ;AAAA;EACI;EACA;EACA,KP53CQ;EO63CR,WP70CU;EO80CV,ONj8CI;;AMm8CJ;AAAA;EACI,ONp8CA;;AMu8CJ;AAAA;AAAA;AAAA;EAEI;EACA;EACA;EACA,eN35CO;EM45CP;EACA;EACA,WP51CM;EO61CN,OP37CE;EO47CF;EACA;;AAEA;AAAA;AAAA;AAAA;EACI,cNv9CN;;AM09CE;AAAA;AAAA;AAAA;EACI;EACA,cN59CN;;AMg+CF;AAAA;EACI,ON/9CA;;AMi+CA;AAAA;EACI,OP78CF;EO88CE,aPz2CU;;AO82CtB;AAAA;EACI;EACA;EACA,KPv6CQ;;AO06CZ;AAAA;EL39CA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;EACI;;AKk9CJ;AAAA;EAEI;EACA;EACA;EACA;EACA,WPj4CU;EOk4CV,aP53CgB;EO63ChB,eNr8CW;EMs8CX;EACA;;AAEA;AAAA;EACI;EACA;EACA;EACA;EACA,aPv4CY;;AO04ChB;AAAA;EACI,OP9+CE;EO++CF,YPhhDD;EOihDC;;AAEA;AAAA;EACI,YP7+CD;EO8+CC,cPv/CF;;AO2/CN;AAAA;AAAA;EAEI,OP3hDD;EO4hDC,YNlhDF;EMmhDE;;AAEA;AAAA;AAAA;EACI,YP3hDG;EO4hDH,cP5hDG;;AO+hDP;AAAA;AAAA;EACI;;AAKZ;AAAA;EACI,WP56CU;EO66CV,ONhiDI;;AMoiDR;AAAA;ELjhDA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;EACI;;AKwgDJ;AAAA;EAEI;EACA;EACA;EACA;EACA,WPt7CU;EOu7CV,OPvjDG;EOwjDH,YN9iDE;EM+iDF;EACA,eN7/CW;EM8/CX;;AAEA;AAAA;EACI,YPzjDO;EO0jDP,cP1jDO;;AO6jDX;AAAA;EACI;;AAGJ;AAAA;EACI;EACA;EACA;EACA;EACA;;AAKR;AAAA;EACI;EACA;EACA,KPpgDQ;EOqgDR;EACA;;AAGJ;AAAA;AAAA;AAAA;AAAA;ELp1CA;EACA;EACA,KFvLY;EEwLZ;EACA,WFzIc;EE0Id,aFpIoB;EEqIpB,YF9OU;EE+OV,OF1OU;EE2OV,eF/Ka;;AEiLb;AAAA;AAAA;AAAA;EA/OA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;EACI;;AAsOJ;AAAA;AAAA;AAAA;EAhRA;EACA;EACA;EAiRI;EACA;EACA;EACA,ODxQI;ECyQJ;;AAEA;AAAA;AAAA;AAAA;EACI;EACA,OD3QH;;AM+kDL;AAAA;AAAA;AAAA;EAEI;EACA;EACA;EACA;EACA,SPhhDQ;EOihDR;EACA,ONzlDI;EM0lDJ,WPt+CU;;AOw+CV;AAAA;AAAA;AAAA;EACI;EACA;EACA,eP3hDI;;AOgiDZ;AAAA;EACI;EACA,SPliDQ;EOmiDR,YPnnDG;EOonDH;;AAEA;AAAA;EACI;;AAIR;AAAA;EACI;EACA;EACA,KP9iDQ;EO+iDR;EACA,eNnkDW;EMokDX;EACA;;AAEA;AAAA;EACI,YPzmDE;;AO4mDN;AAAA;EACI,ON7nDA;EM8nDA,WP1gDM;;AO6gDV;AAAA;EACI;EACA,WP/gDM;EOghDN,OP7mDE;;AOgnDN;AAAA;AAAA;AAAA;ELpnDJ;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;EACI;;AK2mDA;AAAA;AAAA;AAAA;EAGI;EACA;EACA;EACA;EACA;EACA,ON/oDA;EMgpDA,eN/lDO;EMgmDP;;AAEA;AAAA;AAAA;AAAA;EACI,YPxnDD;EOynDC,ONnpDP;;AMypDL;AAAA;EACI;EACA;EACA,KP3lDQ;;AO+lDZ;AAAA;EACI;EACA;EACA,KPjmDQ;EOkmDR;EACA,YP5oDO;EO6oDP;EACA,WPtjDU;EOujDV,aPhjDkB;EOijDlB,OPtpDM;;AOwpDN;AAAA;EACI;EACA;;AAGJ;AAAA;EACI;EACA;EACA;;AAGJ;AAAA;EACI;EACA;;AAKR;AAAA;EACI;EACA,YP7sDG;EO8sDH;;AAIJ;AAAA;EACI;EACA;EACA;EACA,KPtoDQ;EOuoDR;EACA,YPxtDG;EOytDH;EACA;EACA;EACA;EACA;;AAEA;AAAA;EACI;;AAGJ;AAAA;EACI,YPxsDE;;AO2sDN;AAAA;EACI,YPluDO;;AOouDP;AAAA;EACI,YNjuDN;EMkuDM,cNluDN;EMmuDM,OP7uDL;;AO+uDK;AAAA;EACI;;AAKZ;AAAA;EACI;EACA;;AAKR;AAAA;EACI;EACA;EACA;EACA;EACA;EACA;EACA,YPnwDG;EOowDH;EACA;EACA;;AAEA;AAAA;EACI;EACA;;AAKR;AAAA;EAAkC;EAAe;EAAuC;EAAQ;EAAY;EAAwC;;AACpJ;AAAA;EAAkC;EAAe;EAAuC;EAAQ;EAAY;EAAwC;;AACpJ;AAAA;EAAkC;EAAe;EAAuC;EAAQ;EAAY;EAAwC;;AACpJ;AAAA;EAAkC;EAAe;EAAuC;EAAQ;EAAY;EAAwC;;AACpJ;AAAA;EAAkC;EAAe;EAAuC;EAAQ;EAAY;EAAwC;;AACpJ;AAAA;EAAkC;EAAe;EAAuC;EAAQ;EAAY;EAAwC;;AACpJ;AAAA;EAAkC;EAAe;EAAuC;EAAQ;EAAY;EAAwC;;AAUhJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACI;EACA;EACA;EACA,SPntDI;EOotDJ;EACA;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACI;EACA,KP5tDA;EO6tDA,MP7tDA;;AOguDJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAEI;EACA;EACA,ePpuDA;;AOuuDJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACI;;AAGJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACI,WP5rDE;EO6rDF;EACA;EACA;EACA;EACA;;AAGJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACI;;AAIJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACI;;AAGJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACI;EACA;EACA;EACA;EACA,YPlwDA;EOmwDA;;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACI,OPlzDN;EOmzDM,aPhtDM;;AOmtDV;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACI,ON90DR;;AMg1DQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAAc,ON90DzB;;AM+0DW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAAc,ON90DxB;;AMi1DM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACI,ONp1DV;EMq1DU,aP7tDI;;AOmuDhB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACI;;AAKR;AAAA;EAA+D;;AAC/D;AAAA;EAA+D;;AAC/D;AAAA;EAA+D;;AAC/D;AAAA;EAA+D;;AAC/D;AAAA;EAA+D;;AAC/D;AAAA;EAA+D;;AAC/D;AAAA;EAA+D;;AAQvD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAEI;EACA;;AAGJ;AAAA;AAAA;AAAA;AAAA;EACI;;AAMZ;AAAA;EACI;EACA;EACA,KP5zDQ;EO6zDR;EACA;;AAGJ;AAAA;AAAA;AAAA;EAEI;EACA;EACA;EACA;EACA,eN11DW;EM21DX,YPj3DO;;AOm3DP;AAAA;AAAA;AAAA;EACI;EACA;EACA;;AAIR;AAAA;EACI;EACA;EACA;EACA;EACA;EACA;EACA,YPj4DO;EOk4DP,eN52DW;EM62DX,ON95DI;;AMg6DJ;AAAA;EACI;;AAIR;AAAA;AAAA;AAAA;EAEI;EACA;;AAGJ;AAAA;AAAA;AAAA;EAEI,WPzzDU;EO0zDV,aPrzDgB;EOszDhB,OPx5DM;EEfV;EACA;EACA;;AKy6DA;AAAA;AAAA;AAAA;EAEI,WPl0DU;EOm0DV,ONt7DI;;AMy7DR;AAAA;ELj7DA;EACA;EACA;;AKm7DA;AAAA;EACI,OPz6DM;;AO46DV;AAAA;EACI,ONl8DI;EMm8DJ;;AAIJ;AAAA;EACI;EACA;EACA;EACA,WPx1DU;;AO21Dd;AAAA;EACI,OP17DM;;AO67DV;AAAA;EACI,ONj9DC;EMk9DD,aP11DkB;;AO+1Dd;AAAA;EACI,ONz9DN;;AM49DE;AAAA;EACI,ON39DN;;AM89DE;AAAA;EACI,ONh+DP;;AMq+DL;AAAA;EACI,ONx+DI;;AM2+DR;AAAA;EACI;;AAIJ;AAAA;AAAA;AAAA;EAEI;EACA;EACA;EACA;EACA;EACA;EACA;EACA,eNx8DW;EMy8DX;;AAEA;AAAA;AAAA;AAAA;EACI;EACA;EACA,OP3gED;;AO8gEH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAEI,YNtgEF;EMugEE,cNvgEF;;AMygEE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACI;;AAMZ;AAAA;EACI;EACA;EACA;EACA,KP98DQ;EO+8DR,SP58DQ;EO68DR,ONphEI;EMqhEJ,WPj6DU;;AOm6DV;AAAA;EACI;EACA;;AAKR;AAAA;EACI;EACA;EACA;EACA,KP99DQ;EO+9DR;EACA,WPj7DU;EOk7DV,ONriEI;;AMuiEJ;AAAA;AAAA;AAAA;EAEI;;AAGJ;AAAA;EACI,aPn7Dc;EOo7Dd,OPzhEE;;AO4hEN;AAAA;EL39DJ;EACA;EACA,WF4Bc;EE3Bd,aFqCoB;EEpCpB,OFnEU;EEoEV,kBFvGO;EEwGP;EACA,eD7CY;EC8CZ;;AAEA;AAAA;EACI,cDnGE;ECoCN;EACA;;AAkEA;AAAA;EACI,OFnFM;;AO8hEN;AAAA;EAEI;EACA,WPj8DM;EOk8DN;;AAGJ;AAAA;EACI;EACA;EACA;EACA,SPz/DI;EO0/DJ;EACA;EACA,ONjkEF;EMkkEE;EACA,eNhhEO;EMihEP;EACA;EACA;;AAEA;AAAA;EACI;;AAGJ;AAAA;EACI;;AAMZ;AAAA;EACI;EACA;EACA,SNlmEC;EMmmED;;AAEA;AAAA;ELpkEJ;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;EACI;;AK2jEA;AAAA;EAEI;EACA;EACA,KPxhEI;EOyhEJ;EACA,WPz+DM;EO0+DN,aPr+DY;EOs+DZ,ONjmEF;EMkmEE,YPtmEO;EOumEP,eNjjEI;EMkjEJ;;AAEA;AAAA;EACI;;AAGJ;AAAA;EACI;EACA;;AAMZ;AAAA;EACI;EACA;;ALngEJ;AAAA;EACI;EACA;;AAGJ;AAAA;EACI,YDhHA;ECiHA;;AAGJ;AAAA;EACI,YD3EO;EC4EP;;AAEA;AAAA;EACI,YF5GE;;AOqmEV;AAAA;EACI,SPpjEQ;;AOujEZ;AAAA;EACI;EACA;EACA;EACA,KP3jEQ;EO4jER,SPzjEQ;EO0jER,ONjoEI;EMkoEJ,WP9gEU;;AOghEV;AAAA;EAC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AAA;EAEI;EACA;EACA;EACA;EACA;EACA,OP5rBE;EO6rBF,eP1oBW;EO2oBX;;AAEA;AAAA;EACI,YRrsBO;;AQwsBX;AAAA;EACI;;AAKR;AAAA;EACI;EACA;EACA;EACA;EACA,OP7sBI;EO8sBJ,WR3lBU;EQ4lBV;;AAEA;AAAA;EACI,OP/sBF;;AOktBF;AAAA;EACI,OPrtBF;;AOwtBF;AAAA;EACI,aRhmBc;;AQqmBtB;AAAA;EACI;EACA;EACA,KR/pBQ;;;AQuqBhB;EACI;EACA;EACA;EACA;EACA,YR3vBO;EQ4vBP,eP9rBe;EO+rBf,YRvpBW;EQwpBX;;AAEA;EACI;EACA;EACA;EACA,KRprBQ;EQqrBR;EACA,YPrvBA;EOsvBA;;AAGJ;EACI;EACA;EACA,KR7rBQ;EQ8rBR,WR9oBU;EQ+oBV,aRzoBkB;EQ0oBlB,OR7uBM;;AQgvBV;EACI;EACA;;AAGJ;ENzvBA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AMgvBJ;EAEI;EACA;EACA;EACA;EACA;EACA,OPnxBI;EOoxBJ,ePpuBQ;EOquBR;;AAEA;EACI,YR5vBG;EQ6vBH,ORpwBE;;AQuwBN;EACI;;AAIR;EACI;EACA;EACA,SRhuBQ;;AE2CZ;EACI;EACA;;AAGJ;EACI,YDhHA;ECiHA;;AAGJ;EACI,YD3EO;EC4EP;;AAEA;EACI,YF5GE;;AQuxBV;EACI;EACA;EACA;EACA,KRzuBQ;EQ0uBR;EACA,OP/yBI;EOgzBJ,WR5rBU;;AQ8rBV;EACI;;AAGJ;EACI;;AAKR;EACI;EACA;EACA,OP/zBI;;AOi0BJ;EACI;EACA;EACA,eRhwBI;EQiwBJ;;AAGJ;EACI;EACA,WRttBM;;AQ2tBd;EACI;EACA;EACA,KR/wBQ;;AQkxBZ;EACI;EACA;EACA,KPt2BC;EOu2BD;EACA,YRh0BM;EQi0BN,eP3yBQ;EO4yBR;;AAEA;EAEI,mBP51BL;;AO+1BC;EACI,mBPj2BF;;AOo2BF;EAEI;;AAIR;EACI;EACA;;AAEA;EACI;EACA,WR/vBM;EQgwBN,aR1vBc;EQ2vBd,OR91BE;;AQi2BN;EACI;EACA,WRvwBM;EQwwBN,OP33BA;;AO+3BR;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA,WRzxBU;EQ0xBV,ORv3BM;EQw3BN;;AAGJ;EACI;EACA,aRh1BQ;EQi1BR;EACA;EACA,aR9xBgB;EQ+xBhB;EACA,YR73BO;EQ83BP,ORr4BM;EQs4BN,eP12BW;EO22BX;;AAGJ;EACI,YP96BC;EO+6BD,WR9yBU;EQ+yBV,OPl6BI;EOm6BJ;;AAIJ;EACI;EACA;EACA,KRv2BQ;EQw2BR;EACA;EACA,YRn5BM;;AQq5BN;EACI;EACA,OPj7BA;;AOo7BJ;EACI;EACA;EACA;EACA,WRp0BM;EQq0BN,ORl6BE;EQm6BF;EACA;;AAEA;EACI,OP97BJ;;;AOq8BZ;EACI;IACI;;EAEJ;IACI;;;AAcI;AAAA;AAAA;AAAA;AAAA;AAAA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,ePl7BG;EOm7BH;EACA;EACA,OR/8BF;EQg9BE;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;EACI,OP3+BR;EO4+BQ;;AAGJ;AAAA;AAAA;AAAA;AAAA;AAAA;EACI;EACA,cPn/BV;EOo/BU;;AAKR;AAAA;AAAA;AAAA;AAAA;AAAA;EACI;EACA;EACA;EACA;EACA,eP38BG;EO48BH;EACA;EACA;EACA;EACA,OR5+BF;EQ6+BE;EACA;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;EACI,cP1gCV;;AO6gCM;AAAA;AAAA;AAAA;AAAA;AAAA;EACI;EACA,cP/gCV;EOghCU;;;ATziCpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AUAA;AAAA;AAAA;AAAA;AAYI;AAAA;EACI,YTEG;ESDH;EACA,eR8DW;EQ7DX;;AAIJ;AAAA;EACI;EACA;EACA;EACA,KRXC;EQYD;EACA,YRMA;EQLA;;AAGJ;AAAA;EACI;EACA;EACA,KT8DQ;ES7DR,WT6GU;ES5GV,aTkHkB;ESjHlB,OTcM;;ASZN;AAAA;EACI;EACA;EACA;EACA;EACA;EACA;EACA,YRpBF;EQqBE,OT/BD;ESgCC,WT+FM;ES9FN,aTsGU;ESrGV,eT2DK;;ASvDb;AAAA;EACI;EACA;EACA,KTsCQ;;ASnCZ;AAAA;EPbA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;EACI;;AOIJ;AAAA;EAEI;EACA;EACA;EACA;EACA;EACA,ORvCI;EQwCJ,eRSW;EQRX;;AAEA;AAAA;EACI,YThBG;ESiBH,OTxBE;;AS2BN;AAAA;EACI,YT/CM;ESgDN,ORhDH;;AQqDL;AAAA;AAAA;AAAA;EAEI,SRvEC;;AQ2EL;AAAA;EACI,eR5EC;;AQ+EL;AAAA;EACI;EACA;EACA,KTDQ;ESER,eTDQ;ESER,WT6CU;ES5CV,aTmDkB;ESlDlB;EACA;;AAEA;AAAA;EACI,OT7EM;;AS+EN;AAAA;EACI,OR9EN;;AQkFF;AAAA;EACI,ORlFH;;AQoFG;AAAA;EACI,ORrFP;;AQ2FL;AAAA;EACI;EACA;EACA,KT5BQ;ES6BR,eT7BQ;;ASgCZ;AAAA;EACI;EACA;;AAGJ;AAAA;EPnBA;EACA;EACA,WF4Bc;EE3Bd,aFqCoB;EEpCpB,OFnEU;EEoEV,kBFvGO;EEwGP;EACA,eD7CY;EC8CZ;;AAEA;AAAA;EACI,cDnGE;ECoCN;EACA;;AAkEA;AAAA;EACI,OFnFM;;ASsFV;AAAA;EAEI;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;AAAA;EPjGA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;EACI;;AOwFJ;AAAA;EAEI;EACA;EACA;EACA;EACA;EACA,OR3HI;EQ4HJ,eT3CS;ES4CT;;AAEA;AAAA;EACI,YTrGG;ESsGH,ORnIF;;AQwIN;AAAA;EACI;;AAGJ;AAAA;EPvHA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;EACI;;AO8GJ;AAAA;EAEI;EACA;EACA,KT1EQ;ES2ER;EACA;EACA,YT7JG;ES8JH;EACA,eRnGQ;EQoGR,ORpJI;EQqJJ,WTjCU;ESkCV;EACA;;AAEA;AAAA;EACI,cT7HG;;ASgIP;AAAA;EACI,cRhKF;ECoCN;EACA;;AO+HI;AAAA;EACI,OThJE;;ASqJV;AAAA;EACI;;AAGJ;AAAA;EPtFA;EACA;EACA,WF4Bc;EE3Bd,aFqCoB;EEpCpB,OFnEU;EEoEV,kBFvGO;EEwGP;EACA,eD7CY;EC8CZ;;AAEA;AAAA;EACI,cDnGE;ECoCN;EACA;;AAkEA;AAAA;EACI,OFnFM;;ASyJV;AAAA;EAEI;;AAGJ;AAAA;EP9JA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;EACI;;AOqJJ;AAAA;EAEI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,OR9LE;EQ+LF,eR5IW;EQ6IX;;AAEA;AAAA;EACI,YTvMO;;AS4Mf;AAAA;EACI;EACA;EACA,KTrIQ;;ASwIZ;AAAA;EACI;EACA;EACA,KT3IQ;;AS8IZ;AAAA;EP5HA;EACA;EACA,WF4Bc;EE3Bd,aFqCoB;EEpCpB,OFnEU;EEoEV,kBFvGO;EEwGP;EACA,eD7CY;EC8CZ;;AAEA;AAAA;EACI,cDnGE;ECoCN;EACA;;AAkEA;AAAA;EACI,OFnFM;;AS+LV;AAAA;EAEI;EACA;;AAGJ;AAAA;EACI,ORzNI;EQ0NJ,WTtGU;;ASyGd;AAAA;EP1MA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;EACI;;AOiMJ;AAAA;EAEI;EACA;EACA;EACA;EACA;EACA,ORpOI;EQqOJ,eRpLW;EQqLX;;AAEA;AAAA;EACI,YTvOM;ESwON,ORxOH;;AQ4OL;AAAA;EP3NA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;EACI;;AOkNJ;AAAA;EAEI;EACA;EACA;EACA;EACA,ORtPE;EQuPF,WTlIU;ESmIV,aT7HgB;ES8HhB,eRtMW;EQuMX;;AAEA;AAAA;EACI,YTjQO;;ASsQf;AAAA;EACI;EACA;EACA,KThMQ;;ASmMZ;AAAA;EPnPA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;EACI;;AO0OJ;AAAA;EAEI;EACA;EACA;EACA;EACA,YTjPO;ESkPP,OTxPM;ESyPN,WT3JU;ES4JV,aTtJgB;ESuJhB;EACA,eThMS;ESiMT;;AAEA;AAAA;EACI,YTzPG;;AS4PP;AAAA;EACI,YT/RO;ESgSP,OR5RF;EQ6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CA;EACA;EACA;EACA;EACA;;AAEA;EACI;;ASkCR;EAEI;EACA;EACA;EACA;EACA;EACA,OVrEQ;EUsER,eVtBY;EUuBZ;;AAEA;EACI,YX9CO;EW+CP,OXtDM;;AWyDV;EACI,WXuCU;;;AWlClB;EACI;EACA;EACA,SXjBY;;AEyCZ;EACI;EACA;;AAGJ;EACI,YDhHA;ECiHA;;AAGJ;EACI,YD3EO;EC4EP;;AAEA;EACI,YF5GE;;;AW0Ed;EACI;EACA;EACA;EACA,KX5BY;EW6BZ;EACA,YV7FI;EU8FJ;EACA;;;AAGJ;ETpFI;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AS2ER;EAEI;EACA;EACA;EACA,KXzCY;EW0CZ;EACA,WXMc;EWLd,aXUoB;EWTpB,eVhEY;EUiEZ;;AAEA;EACI,OX/FM;EWgGN,YX1FO;;AW4FP;EACI,YX5FG;;AWgGX;EACI,OXzIG;EW0IH,YVhIE;;AUkIF;EACI,YXxIO;;AW4If;EACI,OXlJG;EWmJH,YVrIC;;AUuID;EACI;;AAIR;EACI;EACA;;;AAMR;EACI;EACA;EACA;EACA,KXtFY;EWuFZ;EACA,YVvJI;EUwJJ;EACA;;;AAGJ;EACI,WX9Cc;EW+Cd,aXzCsB;EW0CtB,OX7IU;;;AWgJd;ETpJI;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AS2IR;EAEI;EACA;EACA;EACA;EACA;EACA,OV9KQ;EU+KR,eV9He;EU+Hf;;AAEA;EACI,YXvJO;EWwJP,OX/JM;;;AWmKd;EACI;EACA;EACA,SXvHY;;AE2CZ;EACI;EACA;;AAGJ;EACI,YDhHA;ECiHA;;AAGJ;EACI,YD3EO;EC4EP;;AAEA;EACI,YF5GE;;;AW6Kd;EACI;EACA;EACA;EACA,KX/HY;EWgIZ;EACA,YVhMI;EUiMJ;EACA;;;AAGJ;EACI,WXxFc;EWyFd,OV5MQ;;;AU+MZ;ET5LI;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;ASmLR;EAEI;EACA;EACA;EACA;EACA,WXlGc;EWmGd,aX7FoB;EW8FpB,OVzNM;EU0NN,eVvKe;EUwKf;;AAEA;EACI,YXlOW;;;AWuOnB;EACI;EACA;EACA;EACA,YXjPO;EWkPP;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;;;AAQR;EACI;EACA;EACA;EACA;EACA;EACA;EACA,SX5JS;;AW8JT;EACI;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA,YXxSG;EWySH,eV3OW;EU4OX,YXpMO;EWqMP;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA,KVtTC;EUuTD;EACA,YVrSA;EUsSA;EACA;;AAGJ;EACI;EACA;EACA,KX9OQ;EW+OR,WX9LY;EW+LZ,aX1LkB;EW2LlB,OX9RM;EW+RN;;AAEA;EACI;EACA,OV5TF;;AUgUN;ET3SA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;ASkSJ;EAEI;EACA;EACA;EACA;EACA;EACA,OVrUI;EUsUJ,eVtRQ;EUuRR;;AAEA;EACI,YX9SG;EW+SH,OXtTE;;AWyTN;EACI;;AAIR;EACI;EACA;EACA,SXhRQ;;AEyCZ;EACI;EACA;;AAGJ;EACI,YDhHA;ECiHA;;AAGJ;EACI,YD3EO;EC4EP;;AAEA;EACI,YF5GE;;AWyUV;EACI;EACA;EACA;EACA,KX3RQ;EW4RR;EACA,OVjWI;EUkWJ,WX9OU;;AWgPV;EACI,WX/OM;;AWoPd;EACI;EACA;EACA,OV7WI;;AU+WJ;EACI;EACA;EACA,eVhYH;;AUmYD;EACI;;AAGJ;EACI,WXvQM;EWwQN,OV3XA;;AUgYR;EACI;EACA;EACA,KX/TQ;;AWkUZ;EACI;EACA;EACA,KVvZC;EUwZD;EACA,YXjXM;EWkXN,eV5VQ;EU6VR;;AAEA;EACI,mBV5YL;;AU+YC;EACI,mBVjZF;;AUoZF;EACI;;AAIR;EACI;EACA;;AAEA;EACI;EACA,WX9SM;EW+SN,aXzSc;EW0Sd,OX7YE;;AWgZN;EACI;EACA,WXtTM;EWuTN,OV1aA;;AU8aR;EACI;EACA;;AAGJ;EACI;EACA,WXjUU;EWkUV,OX/ZM;EWgaN;;AAGJ;EACI;EA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;EajFtB,OblBU;;AaoBV;EACI,OZ5CI;;;AYgDZ;EACI,eZ/DK;EYgEL,WbiEc;EahEd,OZnDQ;;;AYuDZ;EACI;EACA;EACA,KZxEK;;;AY2ET;EACI;EACA;;;AAGJ;EACI;EACA;EACA,Wb8Cc;Ea7Cd,abmDoB;EalDpB,OblDU;;;AaqDd;EXYI;EACA;EACA,WF4Bc;EE3Bd,aFqCoB;EEpCpB,OFnEU;EEoEV,kBFvGO;EEwGP;EACA,eD7CY;EC8CZ;;AAEA;EACI,cDnGE;ECoCN;EACA;;AAkEA;EACI,OFnFM;;;Aa4Dd;EACI;EACA;EACA,KbdY;;;AaiBhB;EACI;EACA;EACA,KZtGK;EYuGL,SbrBY;EasBZ,YbhEU;EaiEV,eZ3CY;;AY6CZ;EACI;;;AAIR;EACI;EACA;EACA,KbjCY;EakCZ;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI,WbIc;EaHd,abQoB;EaPpB,Ob3FU;;;Aa+Fd;EACI;EACA;EACA;EACA,Yb9FW;Ea+FX,eb1Ca;Ea2Cb;;;AAGJ;EACI;EACA;EACA;EACA,YZrIM;EYsIN,ebnDa;EaoDb;;;AAGJ;EACI;EACA;EACA;EACA;EACA,YbzJO;Ea0JP;EACA;EACA;EACA;EACA,Yb3DW;Ea4DX;;AAEA;EACI,Yb9DO;;AaiEX;EACI;;AAGJ;EACI;;AAGJ;EACI;;;AAKR;EACI;EACA;EACA,KbvGY;EawGZ;EACA,WbzDc;Ea0Dd;EACA,ObzJU;;;Aa4Jd;EACI,OZlLQ;;;AYsLZ;EACI,SZrMK;EYsML,Yb9JU;Ea+JV,eZzIY;;;AY4IhB;EACI;EACA;EACA,Kb3HY;Ea4HZ,eZ9MK;;;AYiNT;EACI;EACA;EACA;;;AAGJ;EACI,WbtFc;EauFd,ablFoB;EamFpB,ObrLU;;;AawLd;EACI;EACA;EACA,Kb/IY;;;AakJhB;EXmCI;EACA;EACA,KFvLY;EEwLZ;EACA,WFzIc;EE0Id,aFpIoB;EEqIpB,YF9OU;EE+OV,OF1OU;EE2OV,eF/Ka;;AEiLb;EA/OA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAsOJ;EAhRA;EACA;EACA;EAiRI;EACA;EACA;EA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ACI;;AAGJ;AAAA;EACI;;AAGJ;AAAA;EACI,OfxBF;EeyBE;;AAGJ;AAAA;EACI,Yf7BF;Ee8BE,OhBxCD;EgByCC,ahB4FY;;AgBvFpB;AAAA;EACI;EACA;EACA,KfnDC;;AeuDL;AAAA;AAAA;AAAA;AAAA;AAAA;EAGI,Of5CI;Ee6CJ;EACA;;AAGJ;AAAA;EACI,OfhDC;;AeoDL;AAAA;EACI,efrEC;;AewEL;AAAA;EACI;EACA;EACA;EACA,ehBMQ;;AgBHZ;AAAA;EACI,WhBiDU;EgBhDV,ahBsDgB;EgBrDhB,OfpEI;;AeuER;AAAA;EACI;EACA,OhB3CO;;AgB+CX;AAAA;Ed1DA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;EACI;;AciDJ;AAAA;EAEI;EACA;EACA;EACA;EACA,WhBgCU;EgB/BV,OftFE;EeuFF;EACA;EACA,eftCW;EeuCX;;AAEA;AAAA;EACI,YhBjGO;;AgBqGf;AAAA;Ed5EA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;EACI;;AcmEJ;AAAA;EAEI;EACA;EACA;EACA;EACA,WhBcU;EgBbV,OfpGC;EeqGD;;AAEA;AAAA;EACI;;AAQR;AAAA;EACI;EACA;EACA;EACA,YhBlIG;EgBmIH;EACA,efvEW;EewEX;;AAEA;AAAA;EACI,cf9HF;;AekIN;AAAA;EACI;EACA;EACA;EACA;EACA,YhB1GO;EgB2GP;EACA,ahBbkB;EgBclB,WhBrBU;EgBsBV,OhBvGO;;AgByGP;AAAA;EACI,YhBtGC;EgBuGD,qBhBrGE;;AgByGV;AAAA;EACI;EACA;EACA;EACA;;AAGJ;AAAA;EACI;EACA;EACA;EACA;EACA,Yf9GO;Ee+GP,ehB7ES;EgB8ET;EACA,ahBtCkB;EgBuClB;EACA;EACA,OfnKI;;AeqKJ;AAAA;EACI,YfxKF;EeyKE,OhBnLD;;AgBwLP;AAAA;EACI;EACA;EACA;EACA;EACA,YhBvJM;EgBwJN;;AAGJ;AAAA;EdlKA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;EACI;;AcyJJ;AAAA;EAEI;EACA;EACA;EACA;EACA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","file":"entity-selector.css","sourcesContent":["/**\n * Entity Selector Styles\n * @package prestashop-entity-selector\n * @version 2.0.0\n *\n * Compiles to: assets/css/admin/entity-selector.css\n */\n\n// Foundation\n@use 'variables' as *;\n@use 'mixins' as *;\n\n// Layouts\n@use 'layouts/form-integration';\n@use 'layouts/responsive';\n\n// Components\n@use 'components/entity-selector';\n@use 'components/entity-item'; // Shared base for chips and list items\n@use 'components/dropdown';\n@use 'components/chips';\n@use 'components/groups';\n@use 'components/value-picker';\n@use 'components/modal';\n@use 'components/list-preview';\n@use 'components/schedule';\n@use 'components/tips';\n@use 'components/condition-trait';\n@use 'components/combinations';\n@use 'components/method-dropdown';\n@use 'components/tooltip';\n@use 'components/tree';\n@use 'components/validation';\n","/**\n * Entity Selector Variables\n * Bootstrap 4 compatible values for PrestaShop admin theme\n *\n * Imports shared variables from prestashop-admin package\n * and maps them to $es-* prefixed aliases for this package\n */\n\n// Import shared variables from prestashop-admin\n@use '../../../prestashop-admin/assets/scss/variables' as admin;\n\n// =============================================================================\n// Base Colors\n// =============================================================================\n\n$es-white: #ffffff !default;\n$es-black: #000000 !default;\n\n// Primary (from prestashop-admin)\n$es-primary: admin.$primary !default;\n$es-primary-hover: #1a9ab7 !default;\n$es-primary-light: rgba(37, 185, 215, 0.1) !default;\n\n// Semantic colors (from prestashop-admin)\n$es-success: admin.$success !default;\n$es-success-light: #d4edda !default;\n$es-success-dark: #1e7e34 !default;\n\n$es-danger: admin.$danger !default;\n$es-danger-light: #f8d7da !default;\n$es-danger-dark: #bd2130 !default;\n\n$es-warning: admin.$warning !default;\n$es-warning-light: #fff3cd !default;\n\n$es-info: admin.$info !default;\n$es-info-light: #d1ecf1 !default;\n\n// =============================================================================\n// Gray Scale (Bootstrap 4)\n// =============================================================================\n\n$es-gray-100: admin.$light !default;\n$es-gray-200: #e9ecef !default;\n$es-gray-300: admin.$border-color !default;\n$es-gray-400: #ced4da !default;\n$es-gray-500: #adb5bd !default;\n$es-gray-600: admin.$secondary !default;\n$es-gray-700: #495057 !default;\n$es-gray-800: admin.$dark !default;\n$es-gray-900: #212529 !default;\n\n// Slate (subtle variations)\n$es-slate-50: #f8fafc !default;\n$es-slate-100: #f1f5f9 !default;\n$es-slate-200: #e2e8f0 !default;\n$es-slate-300: #cbd5e1 !default;\n$es-slate-400: #94a3b8 !default;\n$es-slate-500: #64748b !default;\n$es-slate-600: #475569 !default;\n$es-slate-700: #334155 !default;\n$es-slate-800: #1e293b !default;\n$es-slate-900: #0f172a !default;\n\n// Cyan\n$es-cyan-50: #ecfeff !default;\n$es-cyan-100: #cffafe !default;\n$es-cyan-200: #a5f3fc !default;\n$es-cyan-500: #06b6d4 !default;\n$es-cyan-600: #0891b2 !default;\n$es-cyan-700: #0e7490 !default;\n\n// =============================================================================\n// Semantic Aliases\n// =============================================================================\n\n$es-bg-header: $es-gray-100 !default;\n$es-bg-hover: $es-gray-200 !default;\n$es-bg-active: $es-gray-200 !default;\n$es-bg-body: $es-white !default;\n\n$es-border-color: admin.$border-color !default;\n$es-border-light: $es-gray-200 !default;\n$es-border-dark: $es-gray-400 !default;\n\n$es-text-primary: $es-gray-900 !default;\n$es-text-secondary: $es-gray-700 !default;\n$es-text-muted: $es-gray-600 !default;\n$es-text-light: $es-gray-500 !default;\n\n// =============================================================================\n// Spacing (Bootstrap 4 compatible, derived from admin.$spacer)\n// =============================================================================\n\n$es-spacing-xs: admin.$spacer * 0.25 !default; // 4px\n$es-spacing-sm: admin.$spacer * 0.5 !default; // 8px\n$es-spacing-md: admin.$spacer !default; // 16px\n$es-spacing-lg: admin.$spacer * 1.5 !default; // 24px\n$es-spacing-xl: admin.$spacer * 2 !default; // 32px\n\n// =============================================================================\n// Border Radius (from prestashop-admin)\n// =============================================================================\n\n$es-radius-sm: admin.$border-radius-sm !default;\n$es-radius-md: admin.$border-radius !default;\n$es-radius-lg: admin.$border-radius-lg !default;\n$es-radius-xl: 0.5rem !default;\n$es-radius-full: 50rem !default;\n\n// =============================================================================\n// Box Shadows (Bootstrap 4 compatible)\n// =============================================================================\n\n$es-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) !default;\n$es-shadow-md: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !default;\n$es-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175) !default;\n$es-shadow-xl: 0 1.5rem 4rem rgba(0, 0, 0, 0.2) !default;\n\n// =============================================================================\n// Transitions\n// =============================================================================\n\n$es-transition-fast: 0.15s ease-in-out !default;\n$es-transition-normal: 0.2s ease-in-out !default;\n$es-transition-slow: 0.3s ease-in-out !default;\n\n// =============================================================================\n// Z-Index (below Bootstrap modal)\n// =============================================================================\n\n$es-z-dropdown: 1000 !default;\n$es-z-modal: 1050 !default;\n$es-z-popover: 1060 !default;\n$es-z-tooltip: 1070 !default;\n\n// =============================================================================\n// Typography\n// =============================================================================\n\n$es-font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif !default;\n\n$es-font-size-xs: 0.75rem !default; // 12px\n$es-font-size-sm: 0.875rem !default; // 14px\n$es-font-size-base: 1rem !default; // 16px\n$es-font-size-lg: 1.125rem !default; // 18px\n\n$es-font-weight-normal: 400 !default;\n$es-font-weight-medium: 500 !default;\n$es-font-weight-semibold: 600 !default;\n$es-font-weight-bold: 700 !default;\n\n$es-line-height-tight: 1.25 !default;\n$es-line-height-normal: 1.5 !default;\n","/**\n * MPR Admin Variables\n * @package prestashop-admin\n *\n * Color token system:\n * - PS theme vars (--primary, --danger, etc.) → set by PrestaShop admin theme\n * - MPR tokens (--mpr-*) → set here as defaults, overridable per module/theme\n *\n * Usage in SCSS: var(--token, $fallback)\n * The $fallback SCSS vars below ensure compilation succeeds even without :root.\n */\n\n// Spacing scale (Bootstrap 4 compatible)\n$spacer: 1rem;\n$spacers: (\n 0: 0,\n 1: $spacer * 0.25,\n 2: $spacer * 0.5,\n 3: $spacer,\n 4: $spacer * 1.5,\n 5: $spacer * 3\n);\n\n// ─── PS Admin Theme Colors (compile-time fallbacks) ─────────────────\n// PS 1.7/8: --primary: #25b9d7, PS 9.x: --primary: #1d1d1b\n$primary: #25b9d7;\n$primary-dark: #1fa0b8;\n$secondary: #6c757d;\n$success: #70b580;\n$danger: #dc3545;\n$warning: #fab000;\n$info: #17a2b8;\n$light: #f8f9fa;\n$dark: #363a41;\n$white: #fff;\n\n$colors: (\n primary: $primary,\n secondary: $secondary,\n success: $success,\n danger: $danger,\n warning: $warning,\n info: $info,\n light: $light,\n dark: $dark\n);\n\n// ─── Text Colors ────────────────────────────────────────────────────\n$mpr-text-primary: #1e293b;\n$mpr-text-body: #363a41;\n$mpr-text-secondary: #6b7280;\n$mpr-text-muted: #94a3b8;\n$mpr-text-placeholder: #9ca3af;\n\n// ─── Border Colors ──────────────────────────────────────────────────\n$mpr-border-color: #e2e8f0;\n$mpr-border-light: #e5e7eb;\n$mpr-border-dark: #d1d5db;\n$mpr-border-input: #dee2e6;\n\n// ─── Background Colors ──────────────────────────────────────────────\n$mpr-bg-primary: #fff;\n$mpr-bg-surface: #f8fafc;\n$mpr-bg-secondary: #f3f4f6;\n$mpr-bg-muted: #e9ecef;\n$mpr-bg-hover: #f0f0f0;\n$mpr-bg-selected: #e2e8f0;\n\n// ─── Accent / Focus ─────────────────────────────────────────────────\n$mpr-accent: #3b82f6;\n$mpr-accent-dark: #2563eb;\n$mpr-focus-ring: #66afe9;\n\n// ─── Border ─────────────────────────────────────────────────────────\n$border-color: #dee2e6;\n$border-radius: 0.25rem;\n$border-radius-sm: 0.2rem;\n$border-radius-lg: 0.3rem;\n\n// ─── Breakpoints ────────────────────────────────────────────────────\n$breakpoint-sm: 576px;\n$breakpoint-md: 768px;\n$breakpoint-lg: 991px;\n$breakpoint-xl: 1200px;\n","/**\n * Entity Selector Mixins\n * Reusable patterns - prefer Bootstrap utilities in HTML where possible\n */\n\n@use \"sass:color\";\n@use 'variables' as *;\n\n// =============================================================================\n// Layout\n// =============================================================================\n\n@mixin flex-center {\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n@mixin flex-between {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n@mixin grid-columns($cols) {\n display: grid;\n grid-template-columns: repeat($cols, 1fr);\n gap: $es-spacing-sm;\n}\n\n// =============================================================================\n// Text\n// =============================================================================\n\n@mixin text-truncate {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n// =============================================================================\n// Interactive Elements\n// =============================================================================\n\n// Reset button styles\n@mixin button-reset {\n padding: 0;\n margin: 0;\n background: none;\n border: none;\n cursor: pointer;\n font: inherit;\n color: inherit;\n\n &:focus {\n outline: none;\n }\n}\n\n// Focus ring (Bootstrap 4 style)\n@mixin focus-ring($color: $es-primary) {\n outline: 0;\n box-shadow: 0 0 0 0.2rem rgba($color, 0.25);\n}\n\n// Interactive hover state\n@mixin interactive-item {\n cursor: pointer;\n transition: background-color $es-transition-fast, color $es-transition-fast;\n\n &:hover {\n background-color: $es-bg-hover;\n }\n}\n\n// =============================================================================\n// Cards & Containers\n// =============================================================================\n\n@mixin card {\n background: $es-white;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-lg;\n}\n\n@mixin dropdown-container {\n position: absolute;\n z-index: $es-z-dropdown;\n background: $es-white;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-lg;\n box-shadow: $es-shadow-lg;\n}\n\n// =============================================================================\n// Form Elements\n// =============================================================================\n\n// Reset input styles (for inputs in custom wrappers)\n@mixin input-reset {\n padding: 0;\n margin: 0;\n background: none;\n border: none;\n font: inherit;\n color: inherit;\n\n &:focus {\n outline: none;\n }\n}\n\n@mixin input-base {\n width: 100%;\n padding: $es-spacing-sm $es-spacing-md;\n font-size: $es-font-size-sm;\n line-height: $es-line-height-normal;\n color: $es-text-primary;\n background-color: $es-white;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-md;\n transition: border-color $es-transition-fast, box-shadow $es-transition-fast;\n\n &:focus {\n border-color: $es-primary;\n @include focus-ring($es-primary);\n }\n\n &::placeholder {\n color: $es-text-light;\n }\n}\n\n// =============================================================================\n// Scrollbar\n// =============================================================================\n\n@mixin custom-scrollbar {\n &::-webkit-scrollbar {\n width: 6px;\n height: 6px;\n }\n\n &::-webkit-scrollbar-track {\n background: $es-gray-100;\n border-radius: 3px;\n }\n\n &::-webkit-scrollbar-thumb {\n background: $es-gray-300;\n border-radius: 3px;\n\n &:hover {\n background: $es-gray-400;\n }\n }\n}\n\n// =============================================================================\n// Badges & Chips\n// =============================================================================\n\n@mixin badge($bg: $es-gray-200, $color: $es-gray-700) {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 0.125rem 0.5rem;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n line-height: 1;\n background-color: $bg;\n color: $color;\n border-radius: $es-radius-full;\n}\n\n// Count badge with preview icon (used for tab badges, match counts, totals)\n// Note: Eye icon is provided in HTML via visibility\n@mixin count-badge($bg: $es-primary) {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.25rem;\n min-width: 20px;\n height: 20px;\n padding: 0 0.5rem;\n background: $bg;\n color: $es-white;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-semibold;\n border-radius: $es-radius-full;\n cursor: pointer;\n transition: all $es-transition-fast;\n flex-shrink: 0;\n\n &:hover {\n transform: scale(1.05);\n box-shadow: 0 2px 8px rgba($bg, 0.4);\n }\n\n // Focus state - maintain styled appearance\n &:focus {\n outline: none;\n box-shadow: 0 0 0 2px rgba($bg, 0.3), 0 2px 8px rgba($bg, 0.4);\n }\n\n // Loading state - spinner icon replaces eye\n &.loading {\n cursor: wait;\n\n i {\n font-size: 10px;\n animation: spin 0.6s linear infinite;\n }\n\n &:hover {\n transform: none;\n box-shadow: none;\n }\n }\n\n // Inactive/empty state\n &.inactive,\n &.no-matches {\n background: $es-slate-400;\n cursor: default;\n\n &:hover {\n transform: none;\n box-shadow: none;\n }\n }\n\n // Popover open state\n &.popover-open {\n background: color.adjust($bg, $lightness: -10%);\n box-shadow: 0 2px 8px rgba($bg, 0.4);\n }\n\n // Icon inside badge (eye, spinner, etc.)\n i {\n font-size: 10px;\n line-height: 1;\n opacity: 0.8;\n }\n\n &:hover i {\n opacity: 1;\n }\n\n .preview-count {\n font-weight: $es-font-weight-bold;\n }\n}\n\n@keyframes spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n}\n\n@keyframes spin-pulse {\n 0% { transform: rotate(0deg); opacity: 1; }\n 50% { opacity: 0.4; }\n 100% { transform: rotate(360deg); opacity: 1; }\n}\n\n// Global spin utility classes (Material Icons replacement for icon-spin / icon-spin-pulse)\n.es-spin {\n animation: spin 1s linear infinite;\n}\n\n.es-spin-pulse {\n animation: spin-pulse 1s ease-in-out infinite;\n}\n\n@mixin chip {\n display: inline-flex;\n align-items: center;\n gap: $es-spacing-xs;\n padding: $es-spacing-xs $es-spacing-sm;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n background: $es-gray-200;\n color: $es-gray-700;\n border-radius: $es-radius-full;\n\n .chip-remove {\n @include button-reset;\n @include flex-center;\n width: 14px;\n height: 14px;\n font-size: 10px;\n color: $es-text-muted;\n border-radius: 50%;\n\n &:hover {\n background: rgba(0, 0, 0, 0.1);\n color: $es-danger;\n }\n }\n}\n\n// =============================================================================\n// Toggle Switch\n// =============================================================================\n\n@mixin toggle-switch($width: 36px, $height: 20px) {\n position: relative;\n width: $width;\n height: $height;\n border-radius: $height;\n background: $es-gray-400;\n transition: background-color $es-transition-normal;\n cursor: pointer;\n\n &::after {\n content: '';\n position: absolute;\n top: 2px;\n left: 2px;\n width: $height - 4px;\n height: $height - 4px;\n background: $es-white;\n border-radius: 50%;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n transition: transform $es-transition-normal;\n }\n\n &.active {\n background: $es-success;\n\n &::after {\n transform: translateX($width - $height);\n }\n }\n}\n\n// =============================================================================\n// Screen Reader Only\n// =============================================================================\n\n@mixin sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n","/**\n * Form Integration Styles\n * Handles PrestaShop admin form layout overrides\n */\n\n@use '../variables' as *;\n\n// Base border reset for all entity-selector elements\n.target-conditions-trait,\n.target-conditions-trait *,\n.entity-selector-trait,\n.entity-selector-trait *,\n.method-dropdown-menu,\n.method-dropdown-menu *,\n.target-preview-popover,\n.target-preview-popover * {\n border-style: solid;\n border-width: 0;\n border-color: $es-border-color;\n}\n\n// Full-width form group override using :has()\n// Excludes .layout-form-group which uses standard PrestaShop form layout\n.form-group:has(.entity-selector-trait:not(.layout-form-group)),\n.form-group:has(.target-conditions-trait:not(.layout-form-group)),\n.form-group:has(.condition-trait:not(.layout-form-group)) {\n display: block;\n\n > .control-label {\n display: none;\n }\n\n > .col-lg-8 {\n width: 100%;\n max-width: 100%;\n padding-left: $es-spacing-md;\n padding-right: $es-spacing-md;\n flex: 0 0 100% !important;\n }\n}\n\n// Fallback class for browsers without :has() support\n.form-group.condition-trait-fullwidth {\n display: block;\n\n > .control-label {\n display: none;\n }\n\n > .col-lg-8 {\n width: 100%;\n max-width: 100%;\n padding-left: $es-spacing-md;\n padding-right: $es-spacing-md;\n flex: 0 0 100% !important;\n }\n}\n\n// SAFEGUARD: Force label visibility for form-group layout widgets\n// This overrides any conflicting rules (including fallback class rules)\n// when the widget has layout-form-group class indicating standard form integration\n.form-group:has(.layout-form-group) > .control-label {\n display: flex !important;\n}\n\n// Dropdown overflow fix\n// When dropdown is open, parent containers must allow overflow\n.panel:has(.target-search-dropdown.show),\n.card:has(.target-search-dropdown.show),\n.form-wrapper:has(.target-search-dropdown.show),\n.panel-body:has(.target-search-dropdown.show),\n.card-body:has(.target-search-dropdown.show),\n.form-group:has(.target-search-dropdown.show),\n.col-lg-8:has(.target-search-dropdown.show),\n.col-lg-12:has(.target-search-dropdown.show) {\n overflow: visible !important;\n}\n\n// Target conditions wrapper hierarchy overflow fix\n.target-conditions-trait:has(.target-search-dropdown.show),\n.entity-selector-trait:has(.target-search-dropdown.show),\n.condition-trait-body:has(.target-search-dropdown.show),\n.target-block-content:has(.target-search-dropdown.show),\n.target-block-groups:has(.target-search-dropdown.show),\n.target-group:has(.target-search-dropdown.show),\n.target-group-body:has(.target-search-dropdown.show),\n.target-search-wrapper:has(.target-search-dropdown.show) {\n overflow: visible !important;\n}\n\n// =============================================================================\n// Embedded Layout\n// =============================================================================\n// Use .layout-embedded for entity selectors nested inside other components\n// Removes outer wrapper styling to avoid redundant borders/backgrounds\n\n.target-conditions-trait.layout-embedded,\n.entity-selector-trait.layout-embedded {\n background: transparent;\n border: none;\n border-radius: 0;\n\n // Remove padding from groups container when embedded\n .groups-container {\n padding: 0;\n }\n\n // Remove block body padding\n .block-body {\n padding: 0;\n }\n\n // Remove block footer border when embedded\n .block-footer {\n border-top: none;\n padding: $es-spacing-sm 0 0;\n }\n\n // Simplify selection group when embedded - single thin border only\n .selection-group {\n background: $es-white;\n border: 1px solid $es-slate-200;\n border-radius: $es-radius-md;\n\n // Lighter group header in embedded mode\n .group-header {\n background: $es-slate-50;\n border-bottom-color: $es-slate-200;\n padding: $es-spacing-xs $es-spacing-sm;\n border-radius: $es-radius-md $es-radius-md 0 0;\n }\n\n // Reduce group body padding (slightly more than $es-spacing-sm for readability)\n .group-body {\n padding: 0.75rem;\n }\n\n // Reduce group-include section padding\n .group-include {\n padding: $es-spacing-xs;\n margin-bottom: $es-spacing-sm;\n }\n\n // Smaller modifiers section\n .group-modifiers {\n padding: $es-spacing-xs $es-spacing-sm;\n margin: $es-spacing-sm (-$es-spacing-sm) (-$es-spacing-sm);\n }\n }\n\n // Empty state - smaller padding\n .groups-empty-state {\n padding: $es-spacing-md;\n }\n\n // Smaller add group button\n .btn-add-group {\n padding: 0.375rem 0.625rem;\n font-size: $es-font-size-xs;\n }\n}\n","/**\n * Responsive Styles\n * Media query adjustments for different screen sizes\n */\n\n@use '../variables' as *;\n\n// Tablet and below\n@media (max-width: 991px) {\n .target-conditions-trait,\n .entity-selector-trait {\n .condition-trait-header {\n flex-direction: column;\n align-items: flex-start;\n gap: $es-spacing-sm;\n }\n\n .trait-header-right {\n width: 100%;\n justify-content: flex-end;\n }\n\n .target-block-tabs {\n flex-wrap: wrap;\n }\n }\n}\n\n// Mobile\n@media (max-width: 767px) {\n .target-conditions-trait,\n .entity-selector-trait {\n .target-block-tab {\n padding: $es-spacing-sm;\n font-size: $es-font-size-xs;\n }\n\n .target-group-header {\n flex-direction: column;\n align-items: flex-start;\n }\n\n .target-search-dropdown {\n width: 100% !important;\n left: 0 !important;\n right: 0 !important;\n }\n\n .dropdown-results-grid {\n grid-template-columns: 1fr !important;\n }\n }\n}\n\n// High-resolution displays\n@media (min-width: 1600px) {\n .target-conditions-trait,\n .entity-selector-trait {\n .dropdown-results-grid.view-grid-3 {\n grid-template-columns: repeat(4, 1fr);\n }\n }\n}\n","/**\n * Entity Selector - Main Component Styles\n * Wrapper, header, body, tabs, blocks\n */\n\n@use '../variables' as *;\n@use '../mixins' as *;\n\n// Main wrapper (supports both .target-conditions-trait and .entity-selector-trait)\n.target-conditions-trait,\n.entity-selector-trait {\n position: relative;\n overflow: visible;\n background: $es-white;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-lg;\n\n // Base Material Icons sizing — 18px throughout entity-selector\n // !important needed to override .bootstrap .material-icons:not(.js-mobile-menu) { font-size: inherit }\n .material-icons {\n font-size: 18px !important;\n }\n\n // Trait Header (collapsible)\n .condition-trait-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-wrap: wrap;\n gap: $es-spacing-md;\n padding: 0.875rem $es-spacing-md;\n background: $es-bg-header;\n border-bottom: 1px solid $es-border-color;\n border-radius: $es-radius-lg $es-radius-lg 0 0;\n cursor: pointer;\n user-select: none;\n transition: background-color $es-transition-fast;\n\n &:hover {\n background: $es-bg-hover;\n }\n }\n\n .trait-header-left {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n min-width: 0;\n flex: 1;\n }\n\n .trait-icon {\n font-size: $es-font-size-lg;\n color: $es-text-muted;\n flex-shrink: 0;\n }\n\n .trait-title-group {\n display: flex;\n flex-direction: column;\n gap: 0.125rem;\n min-width: 0;\n }\n\n .trait-title {\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-semibold;\n color: $es-text-primary;\n white-space: nowrap;\n }\n\n .trait-subtitle {\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n // Total count badge in header\n .trait-total-count {\n @include count-badge($es-primary);\n margin-left: $es-spacing-sm;\n }\n\n // Show all toggle switch\n .trait-show-all-toggle {\n display: inline-flex;\n align-items: center;\n gap: $es-spacing-sm;\n margin-right: 0.75rem;\n padding: 0.25rem $es-spacing-sm;\n border-radius: $es-radius-sm;\n cursor: pointer;\n user-select: none;\n transition: background-color $es-transition-fast;\n\n &:hover {\n background: rgba(0, 0, 0, 0.05);\n }\n\n .toggle-label {\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n color: $es-text-muted;\n }\n\n .show-all-checkbox {\n display: none;\n }\n\n .toggle-slider {\n position: relative;\n width: 36px;\n height: 20px;\n background: $es-slate-300;\n border-radius: $es-radius-full;\n transition: background-color $es-transition-normal;\n\n &::after {\n content: '';\n position: absolute;\n top: 2px;\n left: 2px;\n width: 16px;\n height: 16px;\n background: $es-white;\n border-radius: 50%;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n transition: transform $es-transition-normal;\n }\n }\n\n .show-all-checkbox:checked + .toggle-slider {\n background: $es-success;\n\n &::after {\n transform: translateX(16px);\n }\n }\n }\n\n // Validation error states\n &.has-validation-error {\n border-color: $es-danger;\n box-shadow: 0 0 0 3px rgba($es-danger, 0.1);\n\n .condition-trait-header {\n border-bottom-color: $es-danger;\n }\n }\n\n .trait-validation-error {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n padding: 0.625rem $es-spacing-md;\n background: $es-danger-light;\n color: #b91c1c;\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-medium;\n border-bottom: 1px solid #fecaca;\n\n i {\n color: $es-danger;\n }\n }\n\n // Required indicator\n &.trait-required .trait-title::after {\n content: ' *';\n color: $es-danger;\n }\n\n // Body\n .condition-trait-body {\n padding: 0;\n background: $es-white;\n border-radius: 0 0 $es-radius-lg $es-radius-lg;\n }\n\n // Block type tabs\n .target-block-tabs {\n display: flex;\n flex-wrap: wrap;\n gap: 0;\n padding: 0;\n background: $es-slate-100;\n border-bottom: 1px solid $es-border-color;\n }\n\n .target-block-tab {\n position: relative;\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n flex: none;\n min-width: 0;\n padding: 0.625rem $es-spacing-md;\n margin-bottom: -1px;\n background: transparent;\n border: 0;\n border-bottom: 2px solid transparent;\n color: $es-text-muted;\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-medium;\n cursor: pointer;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-slate-200;\n color: $es-slate-700;\n }\n\n &.active {\n background: $es-white;\n border-bottom-color: $es-cyan-500;\n color: $es-primary;\n }\n\n i.material-icons {\n font-size: 18px !important;\n }\n\n .tab-label {\n white-space: nowrap;\n }\n\n .tab-badge {\n @include count-badge($es-primary);\n }\n\n &.has-data:not(.active) .tab-badge {\n @include count-badge($es-slate-400);\n }\n }\n\n // Tabs row with actions (form-content layout)\n .entity-selector-tabs-row {\n display: flex;\n align-items: stretch;\n background: $es-slate-100;\n border-bottom: 1px solid $es-border-color;\n border-radius: $es-radius-lg $es-radius-lg 0 0;\n\n .target-block-tabs {\n flex: 1;\n border-bottom: 0;\n border-radius: $es-radius-lg 0 0 0;\n }\n }\n\n // Expand/collapse groups button (standalone, in tabs row)\n .entity-selector-actions:not(.btn-toggle-blocks) {\n display: flex;\n align-items: center;\n padding: $es-spacing-xs $es-spacing-md;\n border-left: 1px solid $es-border-color;\n\n .btn-toggle-groups {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 34px;\n height: 34px;\n padding: 0;\n background: $es-white;\n border: 1px solid $es-slate-400;\n border-radius: $es-radius-md;\n color: $es-slate-700;\n cursor: pointer;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-primary-light;\n color: $es-primary;\n border-color: $es-primary;\n }\n\n .material-icons {\n font-size: 18px !important;\n }\n }\n }\n\n // Expand/collapse toggle area (entire section is clickable)\n .entity-selector-actions.btn-toggle-blocks {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0 $es-spacing-md;\n background: $es-slate-100;\n border-left: 1px solid $es-border-color;\n color: $es-slate-400;\n cursor: pointer;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-slate-200;\n color: $es-primary;\n }\n\n .material-icons {\n font-size: 20px !important;\n }\n }\n\n // When expanded - highlight the toggle area\n .entity-selector-trait:not(.blocks-collapsed) .entity-selector-actions.btn-toggle-blocks {\n background: $es-primary-light;\n border-left-color: $es-primary;\n color: $es-primary;\n }\n\n // Blocks content wrapper (for form-content layout collapse)\n .entity-selector-blocks-content {\n // Inherits styles from condition-trait-body context\n }\n\n // Block container\n .target-block-container {\n display: none;\n\n &.active {\n display: block;\n }\n }\n\n .target-block-content {\n padding: $es-spacing-md;\n }\n\n .target-block-groups {\n display: flex;\n flex-direction: column;\n gap: $es-spacing-md;\n }\n\n // Block header (for standalone blocks)\n .target-block-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: $es-spacing-sm $es-spacing-md;\n background: $es-bg-header;\n border-bottom: 1px solid $es-border-color;\n }\n\n // Empty state\n .target-block-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-xl;\n text-align: center;\n color: $es-text-muted;\n\n i {\n font-size: 2rem !important;\n opacity: 0.5;\n }\n\n p {\n margin: 0;\n font-size: $es-font-size-sm;\n }\n }\n\n // Collapse toggle\n .trait-collapse-toggle,\n .collapse-toggle {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n color: $es-text-muted;\n cursor: pointer;\n transition: transform $es-transition-normal;\n\n &.collapsed {\n transform: rotate(-90deg);\n }\n }\n\n // Header actions\n .trait-header-right {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n }\n\n // Collapsed state\n &.collapsed {\n .condition-trait-body {\n display: none;\n }\n\n .condition-trait-header {\n border-radius: $es-radius-lg;\n }\n }\n}\n\n// Single mode specific styles\n.target-conditions-trait.single-mode,\n.entity-selector-trait.single-mode {\n .target-block-tabs {\n display: none;\n }\n\n .target-block-container {\n display: block;\n }\n}\n\n// Header action buttons\n.target-conditions-trait,\n.entity-selector-trait {\n .header-actions {\n display: flex;\n align-items: center;\n gap: $es-spacing-xs;\n }\n\n .header-action-btn {\n @include button-reset;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem $es-spacing-sm;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n color: $es-text-muted;\n background: transparent;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-slate-200;\n color: $es-text-secondary;\n }\n\n i {\n font-size: 14px !important;\n }\n }\n}\n","/**\n * Entity Item - Shared Base Component\n * Unified styling for entity items in chips, lists, and previews\n *\n * Variants:\n * - .entity-item (base) - default list-row style\n * - .entity-item.chip-style - pill/chip style (compact)\n * - .entity-item.card-style - card/grid style\n */\n\n@use '../variables' as *;\n@use '../mixins' as *;\n\n// =============================================================================\n// Entity Item Sizing\n// =============================================================================\n\n$entity-item-image-sm: 20px;\n$entity-item-image-md: 32px;\n$entity-item-image-lg: 48px;\n\n// =============================================================================\n// Base Entity Item (list-row layout)\n// =============================================================================\n\n.entity-item {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-sm;\n background: $es-white;\n border-radius: $es-radius-sm;\n transition: background $es-transition-fast;\n\n &:hover {\n background: $es-bg-hover;\n }\n\n // Clickable variant\n &.clickable {\n cursor: pointer;\n }\n\n // Selected state\n &.selected {\n background: $es-primary-light;\n }\n}\n\n// -----------------------------------------------------------------------------\n// Entity Item Image\n// -----------------------------------------------------------------------------\n\n.entity-item-image {\n flex-shrink: 0;\n width: $entity-item-image-md;\n height: $entity-item-image-md;\n object-fit: cover;\n border-radius: $es-radius-sm;\n background: $es-slate-100;\n}\n\n// Size variants\n.entity-item-image--sm {\n width: $entity-item-image-sm;\n height: $entity-item-image-sm;\n border-radius: 50%;\n}\n\n.entity-item-image--lg {\n width: $entity-item-image-lg;\n height: $entity-item-image-lg;\n}\n\n// No-image placeholder\n.entity-item-no-image {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: $entity-item-image-md;\n height: $entity-item-image-md;\n background: $es-slate-100;\n color: $es-text-muted;\n border-radius: $es-radius-sm;\n font-size: $es-font-size-sm;\n\n &--sm {\n width: $entity-item-image-sm;\n height: $entity-item-image-sm;\n font-size: 10px;\n border-radius: 50%;\n }\n}\n\n// -----------------------------------------------------------------------------\n// Entity Item Info (name + meta)\n// -----------------------------------------------------------------------------\n\n.entity-item-info {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 0.125rem;\n}\n\n.entity-item-name {\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-medium;\n color: $es-text-primary;\n @include text-truncate;\n}\n\n.entity-item-meta {\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n @include text-truncate;\n}\n\n// -----------------------------------------------------------------------------\n// Entity Item Badge/Price (right side)\n// -----------------------------------------------------------------------------\n\n.entity-item-badge {\n flex-shrink: 0;\n padding: 0.125rem 0.5rem;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n background: $es-slate-100;\n color: $es-text-muted;\n border-radius: $es-radius-sm;\n}\n\n.entity-item-price {\n flex-shrink: 0;\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-semibold;\n color: $es-primary;\n}\n\n// -----------------------------------------------------------------------------\n// Entity Item Actions (remove button, etc.)\n// -----------------------------------------------------------------------------\n\n.entity-item-action {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 20px;\n height: 20px;\n color: $es-text-muted;\n border-radius: 50%;\n transition: all $es-transition-fast;\n\n &:hover {\n background: rgba(0, 0, 0, 0.1);\n color: $es-danger;\n }\n\n i {\n font-size: 10px;\n }\n}\n\n// =============================================================================\n// Chip Style Variant (compact pill)\n// =============================================================================\n\n.entity-item.chip-style {\n display: inline-flex;\n gap: 0.375rem;\n padding: 0.25rem 0.5rem;\n background: $es-slate-100;\n border-radius: $es-radius-full;\n\n &:hover {\n background: $es-slate-200;\n }\n\n .entity-item-image {\n width: $entity-item-image-sm;\n height: $entity-item-image-sm;\n border-radius: 50%;\n }\n\n .entity-item-no-image {\n width: $entity-item-image-sm;\n height: $entity-item-image-sm;\n font-size: 10px;\n border-radius: 50%;\n }\n\n .entity-item-info {\n flex-direction: row;\n align-items: center;\n gap: 0.25rem;\n }\n\n .entity-item-name {\n font-size: $es-font-size-xs;\n }\n\n .entity-item-meta {\n display: none;\n }\n\n .entity-item-action {\n width: 16px;\n height: 16px;\n margin-left: 0.125rem;\n }\n}\n\n// =============================================================================\n// List Style Variant (bordered rows)\n// =============================================================================\n\n.entity-item.list-style {\n padding: $es-spacing-sm 0;\n background: transparent;\n border-bottom: 1px solid $es-border-color;\n border-radius: 0;\n\n &:last-child {\n border-bottom: none;\n }\n\n &:hover {\n background: $es-bg-hover;\n }\n}\n\n// =============================================================================\n// Entity Item Container (wrapper for multiple items)\n// =============================================================================\n\n.entity-items-container {\n display: flex;\n flex-direction: column;\n background: $es-slate-50;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-md;\n overflow: hidden;\n}\n\n// Toolbar (filter, sort, count, clear)\n.entity-items-toolbar {\n display: none;\n align-items: center;\n flex-wrap: nowrap;\n gap: $es-spacing-sm;\n padding: $es-spacing-sm $es-spacing-md;\n padding-bottom: 0;\n background: transparent;\n\n &.has-items {\n display: flex;\n }\n}\n\n// Filter input\n.entity-items-filter {\n all: unset;\n display: block;\n flex: 1 1 auto;\n min-width: 80px;\n width: auto;\n height: auto;\n padding: 0.2rem 0.5rem 0.2rem 1.5rem;\n background: $es-white url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.35-4.35'/%3E%3C/svg%3E\") no-repeat 0.375rem center;\n background-size: 10px;\n border: 1px solid $es-slate-300;\n border-radius: $es-radius-sm;\n font-size: 11px;\n line-height: 1.4;\n color: $es-text-primary;\n box-sizing: border-box;\n transition: all $es-transition-fast;\n\n &::placeholder {\n color: $es-text-muted;\n font-size: 11px;\n }\n\n &:focus {\n outline: none;\n border-color: $es-primary;\n box-shadow: 0 0 0 2px rgba($es-primary, 0.1);\n }\n}\n\n// Sort dropdown\n.entity-items-sort {\n all: unset;\n flex: 0 0 auto;\n padding: 0.2rem 1.25rem 0.2rem 0.5rem;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-sm;\n 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.375rem center;\n background-size: 8px;\n font-size: 10px;\n line-height: 1.4;\n color: $es-text-secondary;\n cursor: pointer;\n box-sizing: border-box;\n white-space: nowrap;\n\n &:hover {\n border-color: $es-primary;\n }\n\n &:focus {\n outline: none;\n border-color: $es-primary;\n box-shadow: 0 0 0 2px rgba($es-primary, 0.1);\n }\n}\n\n// Count badge\n.entity-items-count {\n display: inline-flex;\n align-items: center;\n flex-shrink: 0;\n gap: 0.125rem;\n padding: 0.2rem 0.5rem;\n background: $es-slate-200;\n color: $es-text-secondary;\n font-size: 10px;\n font-weight: $es-font-weight-semibold;\n border-radius: $es-radius-sm;\n white-space: nowrap;\n line-height: 1.4;\n\n &.has-filter {\n background: $es-cyan-100;\n color: $es-cyan-700;\n }\n}\n\n// Clear button\n.entity-items-clear {\n @include button-reset;\n display: inline-flex;\n align-items: center;\n flex-shrink: 0;\n gap: 0.25rem;\n padding: 0.2rem 0.5rem;\n color: $es-danger;\n font-size: 10px;\n font-weight: $es-font-weight-medium;\n background: rgba($es-danger, 0.1);\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n white-space: nowrap;\n line-height: 1.4;\n\n &:hover {\n background: $es-danger;\n color: $es-white;\n }\n\n i {\n font-size: 9px;\n flex-shrink: 0;\n }\n}\n\n// Items list area\n.entity-items-list {\n display: flex;\n flex-wrap: wrap;\n gap: $es-spacing-xs;\n padding: $es-spacing-sm $es-spacing-md $es-spacing-md;\n min-height: 40px;\n max-height: 300px;\n overflow-y: auto;\n @include custom-scrollbar;\n\n &:empty {\n display: none;\n }\n\n // List layout (vertical)\n &.list-layout {\n flex-direction: column;\n flex-wrap: nowrap;\n gap: 0;\n padding: $es-spacing-sm;\n }\n}\n\n// Load more section\n.entity-items-load-more {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-sm $es-spacing-md;\n background: transparent;\n border-top: 1px dashed $es-border-color;\n\n .load-more-label {\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n }\n\n .load-more-select {\n appearance: none;\n padding: 0.25rem 1.75rem 0.25rem 0.5rem;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-sm;\n 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;\n background-size: 8px;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n color: $es-primary;\n cursor: pointer;\n transition: all $es-transition-fast;\n height: auto;\n min-height: 0;\n line-height: 1.3;\n\n &:hover {\n border-color: $es-primary;\n background-color: $es-primary-light;\n }\n\n &:focus {\n outline: none;\n border-color: $es-primary;\n box-shadow: 0 0 0 2px rgba($es-primary, 0.1);\n }\n }\n\n .load-more-remaining {\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n\n .remaining-count {\n font-weight: $es-font-weight-semibold;\n color: $es-text-secondary;\n }\n }\n\n .btn-load-more {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: $es-spacing-xs;\n margin: 0;\n border: none;\n color: $es-primary;\n background: $es-primary-light;\n border-radius: $es-radius-sm;\n cursor: pointer;\n transition: all $es-transition-fast;\n font: inherit;\n\n i {\n font-size: 14px;\n }\n\n &:hover {\n background: rgba($es-primary, 0.2);\n }\n\n &.loading {\n cursor: wait;\n\n i {\n animation: spin 0.6s linear infinite;\n }\n }\n }\n}\n\n// =============================================================================\n// Empty & Loading States\n// =============================================================================\n\n.entity-items-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-xl;\n text-align: center;\n color: $es-text-muted;\n\n i {\n font-size: 2rem;\n opacity: 0.5;\n }\n\n p {\n margin: 0;\n font-size: $es-font-size-sm;\n }\n}\n\n.entity-items-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: $es-spacing-xl;\n color: $es-text-muted;\n\n i {\n font-size: 20px;\n animation: spin 0.6s linear infinite;\n }\n}\n","/**\n * Search Dropdown Component\n * Includes search input, filter panel, results grid\n */\n\n@use '../variables' as *;\n@use '../mixins' as *;\n\n.target-conditions-trait,\n.entity-selector-trait {\n\n // Search wrapper\n .target-search-wrapper {\n position: relative;\n }\n\n // Search dropdown\n .target-search-dropdown {\n @include dropdown-container;\n display: none;\n width: 600px;\n max-width: calc(100vw - 40px);\n\n &.show {\n display: block;\n }\n }\n\n // Dropdown header\n .dropdown-header {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-md;\n background: $es-bg-header;\n border-bottom: 1px solid $es-border-color;\n border-radius: $es-radius-lg $es-radius-lg 0 0;\n }\n\n .dropdown-search-input {\n @include input-base;\n flex: 1;\n padding: $es-spacing-sm $es-spacing-md;\n }\n\n .dropdown-close-btn {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n color: $es-text-muted;\n border-radius: $es-radius-md;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-slate-200;\n color: $es-text-secondary;\n }\n }\n\n // Dropdown controls bar\n .dropdown-controls {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: $es-spacing-sm;\n padding: $es-spacing-sm $es-spacing-md;\n background: $es-white;\n border-bottom: 1px solid $es-border-color;\n }\n\n .dropdown-controls-left,\n .dropdown-controls-right {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n }\n\n // View mode buttons\n .view-mode-btn {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n color: $es-text-muted;\n background: transparent;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-slate-100;\n color: $es-text-secondary;\n }\n\n &.active {\n background: $es-primary;\n color: $es-white;\n }\n }\n\n // Results count\n .dropdown-results-count {\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n }\n\n // Dropdown body\n .dropdown-body {\n max-height: 400px;\n overflow-y: auto;\n @include custom-scrollbar;\n }\n\n // Results container\n .dropdown-results {\n padding: 0 $es-spacing-sm;\n }\n\n // Results count text\n .results-count {\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n padding: $es-spacing-xs $es-spacing-sm;\n }\n\n // Results header (for list view columns)\n .results-header {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-xs $es-spacing-md;\n background: $es-slate-100;\n border-bottom: 1px solid $es-border-color;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-semibold;\n color: $es-text-secondary;\n }\n\n // Grid view\n .dropdown-results-grid {\n display: grid;\n gap: $es-spacing-sm;\n\n &.view-list {\n grid-template-columns: 1fr;\n }\n\n &.view-grid-2 {\n grid-template-columns: repeat(2, 1fr);\n }\n\n &.view-grid-3 {\n grid-template-columns: repeat(3, 1fr);\n }\n }\n\n // Result item (both class names for compatibility)\n // Note: Main dropdown-item styling is in the global .target-search-dropdown section below\n .dropdown-result-item {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-sm 0;\n background: $es-white;\n border: none;\n border-bottom: 1px solid $es-border-color;\n border-radius: 0;\n cursor: pointer;\n transition: background $es-transition-fast;\n\n &:last-child {\n border-bottom: none;\n }\n\n &:hover {\n background: $es-bg-hover;\n }\n\n &.selected {\n background: $es-primary-light;\n }\n\n &.disabled {\n opacity: 0.5;\n cursor: not-allowed;\n\n &:hover {\n background: $es-white;\n }\n }\n }\n\n .result-item-image,\n .result-image {\n flex-shrink: 0;\n width: 40px;\n height: 40px;\n overflow: hidden;\n border-radius: $es-radius-sm;\n background: $es-slate-100;\n\n img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n\n &.result-flag {\n width: 32px;\n height: 24px;\n border-radius: 2px;\n box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);\n background: transparent;\n\n img {\n object-fit: contain;\n }\n\n .flag-fallback {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n background: linear-gradient(135deg, #e8eaed 0%, #dadce0 100%);\n font-size: 14px;\n color: #5f6368;\n }\n }\n }\n\n .result-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 40px;\n height: 40px;\n background: $es-slate-100;\n border-radius: $es-radius-sm;\n color: $es-text-muted;\n\n i {\n font-size: 16px;\n }\n }\n\n .result-item-info,\n .result-info {\n flex: 1;\n min-width: 0;\n }\n\n .result-item-name,\n .result-name {\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-medium;\n color: $es-text-primary;\n @include text-truncate;\n }\n\n .result-item-meta,\n .result-subtitle {\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n }\n\n .subtitle-line {\n @include text-truncate;\n }\n\n .subtitle-line-primary {\n color: $es-text-secondary;\n }\n\n .subtitle-line-secondary {\n color: $es-text-muted;\n font-size: 11px;\n }\n\n // Result columns (for product list view)\n .result-col {\n flex-shrink: 0;\n width: 70px;\n text-align: right;\n font-size: $es-font-size-xs;\n }\n\n .result-col-price {\n color: $es-text-secondary;\n }\n\n .result-col-sale {\n color: $es-danger;\n font-weight: $es-font-weight-semibold;\n }\n\n .result-col-stock {\n .col-value {\n &.stock-ok {\n color: $es-success;\n }\n\n &.stock-low {\n color: $es-warning;\n }\n\n &.stock-out {\n color: $es-danger;\n }\n }\n }\n\n .result-col-sales {\n color: $es-text-muted;\n }\n\n .col-value {\n display: block;\n }\n\n .result-item-checkbox,\n .result-checkbox {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 18px;\n height: 18px;\n border: 2px solid $es-border-dark;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n i {\n display: none;\n font-size: 10px;\n color: $es-white;\n }\n\n .dropdown-result-item.selected &,\n .dropdown-item.selected & {\n background: $es-primary;\n border-color: $es-primary;\n\n i {\n display: block;\n }\n }\n }\n\n // Product-specific result item\n .result-item-product {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n }\n\n // No results state\n .no-results {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-xl;\n color: $es-text-muted;\n font-size: $es-font-size-sm;\n\n i {\n font-size: 1.25rem;\n opacity: 0.5;\n }\n }\n\n // Empty state\n .dropdown-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-xl;\n text-align: center;\n color: $es-text-muted;\n\n i {\n font-size: 2rem;\n opacity: 0.5;\n }\n\n p {\n margin: 0;\n font-size: $es-font-size-sm;\n }\n }\n\n // Loading state\n .dropdown-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: $es-spacing-xl;\n color: $es-text-muted;\n\n i {\n font-size: 1.5rem;\n animation: spin 1s linear infinite;\n }\n }\n\n // Unified dropdown footer - combines load more and actions\n .dropdown-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: $es-spacing-md;\n padding: $es-spacing-sm $es-spacing-md;\n background: $es-slate-50;\n border-top: 1px solid $es-border-color;\n border-radius: 0 0 $es-radius-lg $es-radius-lg;\n }\n\n // Left side: load more controls\n .dropdown-footer-left {\n display: flex;\n align-items: center;\n gap: $es-spacing-xs;\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n\n .load-label {\n color: $es-text-muted;\n }\n\n .load-more-select,\n select.load-more-select {\n appearance: none;\n padding: 0.25rem 1.5rem 0.25rem 0.5rem;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-sm;\n 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.4rem center;\n background-size: 8px;\n font-size: $es-font-size-xs;\n color: $es-text-secondary;\n cursor: pointer;\n min-width: 55px;\n\n &:hover {\n border-color: $es-primary;\n }\n\n &:focus {\n outline: none;\n border-color: $es-primary;\n }\n }\n\n .remaining-text {\n color: $es-text-muted;\n\n strong {\n color: $es-text-secondary;\n font-weight: $es-font-weight-semibold;\n }\n }\n\n .btn-load-all {\n @include button-reset;\n padding: 0.25rem 0.5rem;\n font-size: $es-font-size-xs;\n color: $es-primary;\n background: transparent;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-primary-light;\n }\n }\n }\n\n // Right side: action buttons\n .dropdown-footer-right {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n }\n\n .dropdown-action-btn {\n @include button-reset;\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.75rem;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n .btn-shortcut {\n font-size: 10px;\n padding: 0.125rem 0.25rem;\n background: rgba(0, 0, 0, 0.08);\n border-radius: 3px;\n font-weight: $es-font-weight-normal;\n }\n\n &.btn-cancel {\n color: $es-text-secondary;\n background: $es-white;\n border: 1px solid $es-border-color;\n\n &:hover {\n background: $es-slate-100;\n border-color: $es-border-dark;\n }\n }\n\n &.btn-apply,\n &.btn-save {\n color: $es-white;\n background: $es-primary;\n border: 1px solid $es-primary;\n\n &:hover {\n background: $es-primary-hover;\n border-color: $es-primary-hover;\n }\n\n .btn-shortcut {\n background: rgba(255, 255, 255, 0.2);\n }\n }\n }\n\n // Legacy support - hide old load more section when new footer exists\n .dropdown-load-more {\n display: none;\n }\n\n .load-more-controls {\n display: none;\n }\n\n // Filter panel\n .dropdown-filter-panel {\n padding: $es-spacing-md;\n background: $es-slate-50;\n border-bottom: 1px solid $es-border-color;\n }\n\n .filter-panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: $es-spacing-sm;\n }\n\n .filter-panel-title {\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-semibold;\n color: $es-text-primary;\n }\n\n .filter-panel-toggle {\n @include button-reset;\n font-size: $es-font-size-xs;\n color: $es-primary;\n\n &:hover {\n text-decoration: underline;\n }\n }\n\n .filter-panel-content {\n display: grid;\n gap: $es-spacing-sm;\n grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));\n }\n\n .filter-group {\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n }\n\n .filter-label {\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n color: $es-text-secondary;\n }\n\n .filter-select,\n .filter-input {\n @include input-base;\n padding: 0.375rem $es-spacing-sm;\n font-size: $es-font-size-xs;\n }\n}\n\n// Category tree view\n.target-conditions-trait,\n.entity-selector-trait {\n .category-tree {\n padding: $es-spacing-sm;\n }\n\n .tree-container {\n // Contains tree items\n }\n\n .tree-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-xl;\n color: $es-text-muted;\n font-size: $es-font-size-sm;\n\n i {\n animation: spin 0.6s linear infinite;\n }\n }\n\n // Tree item (used by JavaScript)\n .tree-item {\n display: flex;\n align-items: center;\n gap: $es-spacing-xs;\n padding: 0.375rem $es-spacing-sm;\n border-radius: $es-radius-sm;\n cursor: pointer;\n transition: background-color $es-transition-fast;\n\n &:hover {\n background: $es-bg-hover;\n }\n\n &.selected {\n background: $es-primary-light;\n\n .tree-checkbox {\n background: $es-primary;\n border-color: $es-primary;\n\n i {\n display: block;\n }\n }\n }\n\n &.has-children {\n // Parent node styling\n }\n }\n\n // tree-toggle, btn-select-children, tree-checkbox, tree-icon styles in _tree.scss\n\n .tree-info {\n display: flex;\n align-items: center;\n gap: $es-spacing-xs;\n flex: 1;\n min-width: 0;\n }\n\n .tree-name {\n font-size: $es-font-size-sm;\n color: $es-text-primary;\n @include text-truncate;\n }\n\n .tree-subtitle {\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n }\n\n // Legacy category tree classes (for compatibility)\n .category-tree-item {\n padding: 0.25rem 0;\n }\n\n .category-tree-node {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-xs $es-spacing-sm;\n border-radius: $es-radius-sm;\n cursor: pointer;\n transition: background-color $es-transition-fast;\n\n &:hover {\n background: $es-bg-hover;\n }\n\n &.selected {\n background: $es-primary-light;\n }\n }\n\n .category-tree-toggle {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n color: $es-text-muted;\n transition: transform $es-transition-fast;\n\n &.expanded {\n transform: rotate(90deg);\n }\n\n &.empty {\n visibility: hidden;\n }\n }\n\n .category-tree-checkbox {\n flex-shrink: 0;\n width: 16px;\n height: 16px;\n border: 2px solid $es-border-dark;\n border-radius: 3px;\n transition: all $es-transition-fast;\n\n &.checked {\n background: $es-primary;\n border-color: $es-primary;\n\n &::after {\n content: '\\2713';\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n color: $es-white;\n font-size: 10px;\n }\n }\n\n &.indeterminate {\n background: $es-primary;\n border-color: $es-primary;\n\n &::after {\n content: '\\2212';\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n color: $es-white;\n font-size: 10px;\n }\n }\n }\n\n .category-tree-name {\n flex: 1;\n font-size: $es-font-size-sm;\n color: $es-text-primary;\n @include text-truncate;\n }\n\n .category-tree-count {\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n }\n\n .category-tree-children {\n margin-left: 24px;\n }\n\n // Search history\n .search-history-list {\n padding: $es-spacing-sm;\n }\n\n .history-item {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-sm;\n border-radius: $es-radius-sm;\n cursor: pointer;\n transition: background-color $es-transition-fast;\n\n &:hover {\n background: $es-bg-hover;\n }\n\n > i {\n color: $es-text-muted;\n font-size: 14px;\n }\n }\n\n .history-query {\n flex: 1;\n font-size: $es-font-size-sm;\n color: $es-text-primary;\n }\n\n .btn-delete-history {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n color: $es-text-muted;\n border-radius: $es-radius-sm;\n opacity: 0;\n transition: all $es-transition-fast;\n\n .history-item:hover & {\n opacity: 1;\n }\n\n &:hover {\n background: $es-danger-light;\n color: $es-danger;\n }\n\n i {\n font-size: 12px;\n }\n }\n\n // Filter panel\n .filter-panel {\n display: none;\n padding: $es-spacing-md;\n background: $es-slate-50;\n border-bottom: 1px solid $es-border-color;\n\n &.show {\n display: block;\n }\n }\n\n .filter-row {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: $es-spacing-sm;\n margin-bottom: $es-spacing-sm;\n\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n // View mode select\n .view-mode-select {\n @include input-base;\n padding: 0.25rem 0.5rem;\n font-size: $es-font-size-xs;\n min-width: 80px;\n }\n}\n\n// =============================================================================\n// Global dropdown styles (when appended to body instead of inside wrapper)\n// Duplicates key styles for when dropdown is outside .entity-selector-trait\n// =============================================================================\nbody > .target-search-dropdown,\n.target-search-dropdown {\n @include dropdown-container;\n display: none;\n width: 600px;\n max-width: calc(100vw - 40px);\n\n &.show {\n display: block;\n }\n\n // Dropdown header\n .dropdown-header {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-md;\n background: $es-bg-header;\n border-bottom: 1px solid $es-border-color;\n border-radius: $es-radius-lg $es-radius-lg 0 0;\n flex-wrap: wrap;\n }\n\n .results-count {\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-semibold;\n color: $es-text-primary;\n white-space: nowrap;\n }\n\n .dropdown-actions {\n display: flex;\n align-items: center;\n gap: $es-spacing-xs;\n flex-wrap: wrap;\n flex: 1;\n justify-content: flex-end;\n }\n\n .btn-select-all,\n .btn-clear-selection {\n @include button-reset;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n font-size: $es-font-size-xs;\n color: $es-text-secondary;\n background: $es-white;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-sm;\n cursor: pointer;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-bg-hover;\n border-color: $es-slate-300;\n }\n\n kbd {\n font-size: 0.65rem;\n padding: 0.125rem 0.25rem;\n background: $es-slate-100;\n border-radius: 2px;\n color: $es-text-muted;\n }\n }\n\n .sort-controls {\n display: flex;\n align-items: center;\n // No gap - elements are connected\n }\n\n .sort-field-select {\n @include input-base;\n padding: 0.25rem 0.5rem;\n font-size: $es-font-size-xs;\n min-width: 80px;\n height: 28px; // Match btn-sort-dir height\n border-radius: $es-radius-sm 0 0 $es-radius-sm;\n border-right: none;\n }\n\n .btn-sort-dir {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 38px;\n min-width: 38px;\n flex-shrink: 0;\n height: 28px;\n padding: 0;\n margin: 0;\n color: $es-text-muted;\n background: $es-white;\n border: 1px solid $es-border-color;\n border-radius: 0 $es-radius-sm $es-radius-sm 0;\n cursor: pointer;\n transition: all $es-transition-fast;\n\n i {\n font-size: 14px;\n }\n\n &:hover {\n background: $es-bg-hover;\n color: $es-text-primary;\n }\n\n &.active {\n background: $es-primary-light;\n border-color: $es-primary;\n color: $es-primary;\n }\n }\n\n .view-mode-select {\n @include input-base;\n padding: 0.25rem 0.5rem;\n font-size: $es-font-size-xs;\n min-width: 80px;\n margin-left: 0.25rem;\n }\n\n .btn-toggle-filters,\n .btn-show-history {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n min-width: 32px;\n flex-shrink: 0;\n height: 28px;\n padding: 0;\n margin: 0;\n color: $es-text-muted;\n background: $es-white;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-sm;\n cursor: pointer;\n transition: all $es-transition-fast;\n\n i {\n font-size: 14px;\n }\n\n &:hover {\n background: $es-bg-hover;\n color: $es-text-primary;\n }\n\n &.active {\n background: $es-primary-light;\n border-color: $es-primary;\n color: $es-primary;\n }\n }\n\n .refine-compact {\n display: flex;\n align-items: center;\n // No gap - elements are connected\n\n // Connected to refine-input\n .btn-refine-negate {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n min-width: 32px;\n flex-shrink: 0;\n height: 28px;\n padding: 0;\n margin: 0;\n color: $es-text-muted;\n background: $es-white;\n border: 1px solid $es-border-color;\n border-right: none;\n border-radius: $es-radius-sm 0 0 $es-radius-sm;\n cursor: pointer;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-bg-hover;\n color: $es-text-primary;\n }\n\n &.active {\n background: $es-danger-light;\n color: $es-danger;\n border-color: $es-danger;\n }\n }\n\n .refine-input {\n @include input-base;\n width: 100px;\n padding: 0.25rem 0.5rem;\n font-size: $es-font-size-xs;\n border-radius: 0 $es-radius-sm $es-radius-sm 0;\n }\n\n .btn-clear-refine {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n margin: 0;\n margin-left: -1px; // Overlap input border when visible\n color: $es-text-muted;\n background: $es-white;\n border: 1px solid $es-border-color;\n border-radius: 0 $es-radius-sm $es-radius-sm 0;\n cursor: pointer;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-bg-hover;\n color: $es-text-primary;\n }\n }\n }\n\n // Filter panel\n .filter-panel {\n display: none;\n padding: $es-spacing-md;\n background: $es-slate-50;\n border-bottom: 1px solid $es-border-color;\n\n &.show {\n display: block;\n }\n }\n\n .filter-row {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n flex-wrap: wrap;\n margin-bottom: $es-spacing-sm;\n\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n .filter-label {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n font-size: $es-font-size-xs;\n color: $es-text-secondary;\n cursor: pointer;\n\n input[type=\"checkbox\"] {\n margin: 0;\n }\n }\n\n .filter-price-range {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n\n .filter-price-label {\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n }\n\n .filter-price-min,\n .filter-price-max {\n @include input-base;\n width: 70px;\n padding: 0.25rem 0.5rem;\n font-size: $es-font-size-xs;\n }\n\n .filter-price-sep {\n color: $es-text-muted;\n }\n }\n\n .btn-clear-filters {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n color: $es-text-muted;\n border-radius: $es-radius-sm;\n cursor: pointer;\n margin-left: auto;\n\n &:hover {\n background: $es-slate-200;\n color: $es-text-primary;\n }\n }\n\n // Multi-row filters\n .filter-row-multi {\n flex-direction: column;\n align-items: stretch;\n gap: $es-spacing-sm;\n }\n\n .filter-subrow {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n flex-wrap: wrap;\n }\n\n .filter-range-group,\n .filter-date-group,\n .filter-select-group {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n }\n\n .filter-range-label,\n .filter-date-label,\n .filter-select-label,\n .filter-row-label {\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n white-space: nowrap;\n\n i {\n margin-right: 0.25rem;\n }\n }\n\n .filter-range-sep {\n color: $es-text-muted;\n }\n\n .filter-product-count-min,\n .filter-product-count-max,\n .filter-sales-min,\n .filter-sales-max,\n .filter-turnover-min,\n .filter-turnover-max,\n .filter-date-add-from,\n .filter-date-add-to,\n .filter-last-product-from,\n .filter-last-product-to {\n @include input-base;\n width: 70px;\n padding: 0.25rem 0.5rem;\n font-size: $es-font-size-xs;\n }\n\n .filter-depth-select,\n .filter-attribute-group-select,\n .filter-feature-group-select {\n @include input-base;\n padding: 0.25rem 0.5rem;\n font-size: $es-font-size-xs;\n min-width: 100px;\n }\n\n .filter-attributes-container,\n .filter-features-container,\n .filter-values-container {\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n }\n\n // Filter group toggle buttons (attribute/feature groups)\n .filter-group-toggle {\n @include button-reset;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n font-size: $es-font-size-xs;\n color: $es-text-secondary;\n background: $es-white;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-sm;\n cursor: pointer;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-bg-hover;\n border-color: $es-slate-300;\n }\n\n &.active {\n background: $es-primary-light;\n border-color: $es-primary;\n color: $es-primary;\n\n .toggle-count {\n color: $es-primary;\n }\n }\n\n &.has-selection {\n border-color: $es-success;\n background: rgba($es-success, 0.05);\n\n .toggle-count {\n color: $es-success;\n font-weight: $es-font-weight-semibold;\n }\n }\n\n .toggle-name {\n font-weight: $es-font-weight-medium;\n }\n\n // Count with eye icon (like group-count-badge)\n .toggle-count {\n display: inline-flex;\n align-items: center;\n gap: 0.125rem;\n color: $es-text-muted;\n font-size: 0.65rem;\n\n i {\n font-size: 10px;\n color: $es-primary;\n }\n\n // Clickable preview badge\n &.clickable {\n cursor: pointer;\n padding: 0.125rem 0.25rem;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n &:hover {\n background: rgba($es-primary, 0.1);\n color: $es-primary;\n\n i {\n color: $es-primary;\n }\n }\n\n &.popover-open {\n background: $es-primary;\n color: $es-white;\n\n i {\n color: $es-white;\n }\n }\n\n &.loading {\n i {\n animation: spin 0.6s linear infinite;\n }\n }\n }\n }\n }\n\n // Filter value chips\n .filter-chip {\n @include button-reset;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n font-size: $es-font-size-xs;\n color: $es-text-secondary;\n background: $es-slate-100;\n border: 1px solid transparent;\n border-radius: $es-radius-sm;\n cursor: pointer;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-slate-200;\n }\n\n &.active {\n background: $es-primary;\n color: $es-white;\n }\n }\n\n // Filter attribute chip (specific)\n .filter-attr-chip,\n .filter-feat-chip {\n @extend .filter-chip;\n }\n\n // Filter row for values (expandable)\n .filter-row-values {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-sm;\n background: $es-white;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-sm;\n\n .filter-values-container {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.25rem;\n flex: 1;\n }\n\n .filter-values-label {\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-semibold;\n color: $es-text-secondary;\n white-space: nowrap;\n }\n\n .btn-close-values {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 20px;\n height: 20px;\n color: $es-text-muted;\n border-radius: $es-radius-sm;\n\n &:hover {\n background: $es-slate-200;\n color: $es-text-primary;\n }\n }\n }\n\n // Filter chip name and count\n .chip-name {\n font-weight: $es-font-weight-medium;\n }\n\n .chip-count {\n font-size: 0.6rem;\n color: $es-text-muted;\n margin-left: 0.125rem;\n }\n\n .filter-chip.active .chip-count {\n color: rgba(255, 255, 255, 0.8);\n }\n\n // Dropdown content\n .dropdown-content {\n max-height: 400px;\n overflow-y: auto;\n @include custom-scrollbar;\n }\n\n .dropdown-items {\n display: flex;\n flex-direction: column;\n gap: $es-spacing-xs;\n padding: $es-spacing-sm;\n }\n\n .item-checkbox {\n flex-shrink: 0;\n width: 16px;\n height: 16px;\n border: 2px solid $es-border-dark;\n border-radius: 3px;\n transition: all $es-transition-fast;\n\n .dropdown-item.selected & {\n background: $es-primary;\n border-color: $es-primary;\n }\n }\n\n .item-image {\n flex-shrink: 0;\n width: 40px;\n height: 40px;\n object-fit: cover;\n border-radius: $es-radius-sm;\n background: $es-slate-100;\n }\n\n .item-info {\n flex: 1;\n min-width: 0;\n }\n\n .item-name {\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-medium;\n color: $es-text-primary;\n @include text-truncate;\n }\n\n .item-meta {\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n @include text-truncate;\n }\n\n // Dropdown footer - unified structure\n .dropdown-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: $es-spacing-md;\n padding: $es-spacing-sm $es-spacing-md;\n background: $es-slate-50;\n border-top: 1px solid $es-border-color;\n border-radius: 0 0 $es-radius-lg $es-radius-lg;\n }\n\n .dropdown-footer-left {\n display: flex;\n align-items: center;\n gap: $es-spacing-xs;\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n\n .load-label {\n color: $es-text-muted;\n }\n\n .load-more-select,\n select.load-more-select {\n appearance: none;\n padding: 0.25rem 1.5rem 0.25rem 0.5rem;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-sm;\n 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.4rem center;\n background-size: 8px;\n font-size: $es-font-size-xs;\n color: $es-text-secondary;\n cursor: pointer;\n min-width: 55px;\n\n &:hover {\n border-color: $es-primary;\n }\n\n &:focus {\n outline: none;\n border-color: $es-primary;\n }\n }\n\n .remaining-text {\n color: $es-text-muted;\n\n strong {\n color: $es-text-secondary;\n font-weight: $es-font-weight-semibold;\n }\n }\n }\n\n .dropdown-footer-right {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n }\n\n .dropdown-action-btn {\n @include button-reset;\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.75rem;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n white-space: nowrap;\n\n .btn-shortcut {\n font-size: 10px;\n padding: 0.125rem 0.25rem;\n background: rgba(0, 0, 0, 0.08);\n border-radius: 3px;\n font-weight: $es-font-weight-normal;\n }\n\n &.btn-cancel {\n color: $es-text-secondary;\n background: $es-white;\n border: 1px solid $es-border-color;\n\n &:hover {\n background: $es-slate-100;\n border-color: $es-border-dark;\n }\n }\n\n &.btn-apply,\n &.btn-save {\n color: $es-white;\n background: $es-primary;\n border: 1px solid $es-primary;\n\n &:hover {\n background: $es-primary-hover;\n border-color: $es-primary-hover;\n }\n\n .btn-shortcut {\n background: rgba(255, 255, 255, 0.2);\n }\n }\n }\n\n .dropdown-footer-info {\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n }\n\n // Legacy button support\n .btn-cancel-dropdown {\n @include button-reset;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.375rem 0.75rem;\n font-size: $es-font-size-sm;\n color: $es-white;\n background: $es-primary;\n border: 1px solid $es-primary;\n border-radius: $es-radius-sm;\n cursor: pointer;\n\n &:hover {\n background: $es-primary-hover;\n border-color: $es-primary-hover;\n }\n\n i {\n font-size: 10px;\n }\n\n kbd {\n font-size: 0.65rem;\n padding: 0.125rem 0.25rem;\n background: rgba(255, 255, 255, 0.2);\n border-radius: 2px;\n color: rgba(255, 255, 255, 0.8);\n }\n }\n\n // Filter chips in dropdown\n .filter-chips-row {\n display: flex;\n flex-wrap: wrap;\n gap: $es-spacing-xs;\n padding: $es-spacing-xs $es-spacing-md;\n border-bottom: 1px solid $es-border-color;\n }\n\n .filter-chip {\n @include chip;\n }\n\n // Empty and loading states\n .dropdown-empty,\n .dropdown-loading {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: $es-spacing-xl;\n text-align: center;\n color: $es-text-muted;\n font-size: $es-font-size-sm;\n\n i {\n font-size: 2rem;\n opacity: 0.5;\n margin-bottom: $es-spacing-sm;\n }\n }\n\n // Search history panel\n .search-history-panel {\n display: none;\n padding: $es-spacing-sm;\n background: $es-white;\n border-bottom: 1px solid $es-border-color;\n\n &.show {\n display: block;\n }\n }\n\n .history-item {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-xs $es-spacing-sm;\n border-radius: $es-radius-sm;\n cursor: pointer;\n transition: background $es-transition-fast;\n\n &:hover {\n background: $es-bg-hover;\n }\n\n i {\n color: $es-text-muted;\n font-size: $es-font-size-sm;\n }\n\n span {\n flex: 1;\n font-size: $es-font-size-sm;\n color: $es-text-primary;\n }\n\n .btn-remove-history,\n .btn-delete-history {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 20px;\n height: 20px;\n color: $es-text-muted;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-slate-200;\n color: $es-danger;\n }\n }\n }\n\n // Search history list container\n .search-history-list {\n display: flex;\n flex-direction: column;\n gap: $es-spacing-xs;\n }\n\n // Results header (for list view columns)\n .results-header {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-xs $es-spacing-md;\n background: $es-slate-100;\n border-bottom: 1px solid $es-border-color;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-semibold;\n color: $es-text-secondary;\n\n .header-spacer {\n width: 58px; // checkbox + image width\n flex-shrink: 0;\n }\n\n .header-col {\n flex-shrink: 0;\n width: 70px;\n text-align: right;\n }\n\n .header-col-name {\n flex: 1;\n text-align: left;\n }\n }\n\n // Results container\n .dropdown-results {\n padding: 0 $es-spacing-sm;\n background: $es-white;\n min-height: 200px;\n }\n\n // Dropdown item (search result)\n .dropdown-item {\n position: relative;\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-sm 0;\n background: $es-white;\n border: none;\n border-bottom: 1px solid $es-border-color;\n border-radius: 0;\n cursor: pointer;\n transition: background $es-transition-fast;\n\n &:last-child {\n border-bottom: none;\n }\n\n &:hover {\n background: $es-bg-hover;\n }\n\n &.selected {\n background: $es-primary-light;\n\n .result-checkbox {\n background: $es-primary;\n border-color: $es-primary;\n color: $es-white;\n\n i {\n display: block;\n }\n }\n }\n\n &.disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n }\n\n // Checkbox indicator\n .result-checkbox {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 18px;\n height: 18px;\n background: $es-white;\n border: 2px solid $es-border-dark;\n border-radius: 3px;\n transition: all $es-transition-fast;\n\n i {\n display: none;\n font-size: 10px;\n }\n }\n\n // View mode classes (applied to dropdown container) - no gap/padding for shared borders\n &.view-cols-2 .dropdown-results { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0; padding: 0; border-top: 1px solid $es-border-color; border-left: 1px solid $es-border-color; }\n &.view-cols-3 .dropdown-results { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0; padding: 0; border-top: 1px solid $es-border-color; border-left: 1px solid $es-border-color; }\n &.view-cols-4 .dropdown-results { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0; padding: 0; border-top: 1px solid $es-border-color; border-left: 1px solid $es-border-color; }\n &.view-cols-5 .dropdown-results { display: grid; grid-template-columns: repeat(5, 1fr); gap: 0; padding: 0; border-top: 1px solid $es-border-color; border-left: 1px solid $es-border-color; }\n &.view-cols-6 .dropdown-results { display: grid; grid-template-columns: repeat(6, 1fr); gap: 0; padding: 0; border-top: 1px solid $es-border-color; border-left: 1px solid $es-border-color; }\n &.view-cols-7 .dropdown-results { display: grid; grid-template-columns: repeat(7, 1fr); gap: 0; padding: 0; border-top: 1px solid $es-border-color; border-left: 1px solid $es-border-color; }\n &.view-cols-8 .dropdown-results { display: grid; grid-template-columns: repeat(8, 1fr); gap: 0; padding: 0; border-top: 1px solid $es-border-color; border-left: 1px solid $es-border-color; }\n\n // Grid view item styling (compact cards with shared borders)\n &.view-cols-2,\n &.view-cols-3,\n &.view-cols-4,\n &.view-cols-5,\n &.view-cols-6,\n &.view-cols-7,\n &.view-cols-8 {\n .dropdown-item {\n flex-direction: column;\n align-items: center;\n text-align: center;\n padding: $es-spacing-sm;\n border: none;\n border-right: 1px solid $es-border-color;\n border-bottom: 1px solid $es-border-color;\n border-radius: 0;\n\n .result-checkbox {\n position: absolute;\n top: $es-spacing-xs;\n left: $es-spacing-xs;\n }\n\n .result-image,\n .result-icon {\n width: 48px;\n height: 48px;\n margin-bottom: $es-spacing-xs;\n }\n\n .result-info {\n width: 100%;\n }\n\n .result-name {\n font-size: $es-font-size-xs;\n line-height: 1.3;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n }\n\n .result-subtitle {\n display: none;\n }\n\n // Show compact product info in grid\n .result-col {\n display: none;\n }\n\n .result-grid-info {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n gap: 0.25rem;\n margin-top: $es-spacing-xs;\n font-size: 0.65rem;\n\n .grid-price {\n color: $es-text-primary;\n font-weight: $es-font-weight-semibold;\n }\n\n .grid-stock {\n color: $es-text-muted;\n\n &.stock-out { color: $es-danger; }\n &.stock-low { color: $es-warning; }\n }\n\n .grid-discount {\n color: $es-success;\n font-weight: $es-font-weight-medium;\n }\n }\n }\n\n // Hide results header in grid views\n .results-header {\n display: none;\n }\n }\n\n // Remove right border from last item in each row (per column count)\n &.view-cols-2 .dropdown-results .dropdown-item:nth-child(2n) { border-right: none; }\n &.view-cols-3 .dropdown-results .dropdown-item:nth-child(3n) { border-right: none; }\n &.view-cols-4 .dropdown-results .dropdown-item:nth-child(4n) { border-right: none; }\n &.view-cols-5 .dropdown-results .dropdown-item:nth-child(5n) { border-right: none; }\n &.view-cols-6 .dropdown-results .dropdown-item:nth-child(6n) { border-right: none; }\n &.view-cols-7 .dropdown-results .dropdown-item:nth-child(7n) { border-right: none; }\n &.view-cols-8 .dropdown-results .dropdown-item:nth-child(8n) { border-right: none; }\n\n // Smaller items for higher column counts\n &.view-cols-5,\n &.view-cols-6,\n &.view-cols-7,\n &.view-cols-8 {\n .dropdown-item {\n .result-image,\n .result-icon {\n width: 40px;\n height: 40px;\n }\n\n .result-name {\n font-size: 0.65rem;\n }\n }\n }\n\n // Product-specific result item\n .result-item-product {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n flex: 1;\n min-width: 0;\n }\n\n .result-item-image,\n .result-image {\n flex-shrink: 0;\n width: 40px;\n height: 40px;\n overflow: hidden;\n border-radius: $es-radius-sm;\n background: $es-slate-100;\n\n img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n }\n\n .result-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 40px;\n height: 40px;\n background: $es-slate-100;\n border-radius: $es-radius-sm;\n color: $es-text-muted;\n\n i {\n font-size: 16px;\n }\n }\n\n .result-item-info,\n .result-info {\n flex: 1;\n min-width: 0;\n }\n\n .result-item-name,\n .result-name {\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-medium;\n color: $es-text-primary;\n @include text-truncate;\n }\n\n .result-item-meta,\n .result-subtitle {\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n }\n\n .subtitle-line {\n @include text-truncate;\n }\n\n .subtitle-line-primary {\n color: $es-text-secondary;\n }\n\n .subtitle-line-secondary {\n color: $es-text-muted;\n font-size: 11px;\n }\n\n // Result columns (for product list view)\n .result-col {\n flex-shrink: 0;\n width: 70px;\n text-align: right;\n font-size: $es-font-size-xs;\n }\n\n .result-col-price {\n color: $es-text-secondary;\n }\n\n .result-col-sale {\n color: $es-danger;\n font-weight: $es-font-weight-semibold;\n }\n\n .result-col-stock {\n .col-value {\n &.stock-ok {\n color: $es-success;\n }\n\n &.stock-low {\n color: $es-warning;\n }\n\n &.stock-out {\n color: $es-danger;\n }\n }\n }\n\n .result-col-sales {\n color: $es-text-muted;\n }\n\n .col-value {\n display: block;\n }\n\n // Result checkbox\n .result-item-checkbox,\n .result-checkbox {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 18px;\n height: 18px;\n border: 2px solid $es-border-dark;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n i {\n display: none;\n font-size: 10px;\n color: $es-white;\n }\n\n .dropdown-result-item.selected &,\n .dropdown-item.selected & {\n background: $es-primary;\n border-color: $es-primary;\n\n i {\n display: block;\n }\n }\n }\n\n // No results state\n .no-results {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-xl;\n color: $es-text-muted;\n font-size: $es-font-size-sm;\n\n i {\n font-size: 1.25rem;\n opacity: 0.5;\n }\n }\n\n // Load more controls\n .load-more-controls {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-sm $es-spacing-md;\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n\n .load-more-label,\n .load-more-of {\n white-space: nowrap;\n }\n\n .remaining-count {\n font-weight: $es-font-weight-semibold;\n color: $es-text-secondary;\n }\n\n .load-more-select {\n @include input-base;\n padding: 0.25rem 0.5rem;\n font-size: $es-font-size-xs;\n min-width: 60px;\n }\n\n .btn-load-more {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: $es-spacing-xs;\n margin: 0;\n border: none;\n color: $es-primary;\n background: $es-primary-light !important;\n border-radius: $es-radius-sm;\n cursor: pointer;\n transition: all $es-transition-fast;\n font: inherit;\n\n i {\n font-size: 14px;\n }\n\n &:hover {\n background: rgba($es-primary, 0.2) !important;\n }\n }\n }\n\n // Load more button\n .dropdown-load-more {\n display: flex;\n justify-content: center;\n padding: $es-spacing-md;\n border-top: 1px solid $es-border-color;\n\n .load-more-btn {\n @include button-reset;\n display: inline-flex;\n align-items: center;\n gap: $es-spacing-xs;\n padding: $es-spacing-sm $es-spacing-md;\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-medium;\n color: $es-primary;\n background: $es-primary-light;\n border-radius: $es-radius-md;\n transition: all $es-transition-fast;\n\n &:hover {\n background: rgba($es-primary, 0.2);\n }\n\n &.loading {\n opacity: 0.7;\n cursor: wait;\n }\n }\n }\n\n // Dropdown body\n .dropdown-body {\n max-height: 400px;\n overflow-y: auto;\n @include custom-scrollbar;\n }\n\n // Tree view styles (for categories)\n .tree-container {\n padding: $es-spacing-sm;\n }\n\n .tree-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-xl;\n color: $es-text-muted;\n font-size: $es-font-size-sm;\n\n i {\n animation: spin 0.6s linear infinite;\n }\n }\n\n .tree-item {\n display: flex;\n align-items: center;\n gap: $es-spacing-xs;\n padding: 0.375rem $es-spacing-sm;\n border-radius: $es-radius-sm;\n cursor: pointer;\n transition: background-color $es-transition-fast;\n\n &:hover {\n background: $es-bg-hover;\n }\n\n &.selected {\n background: $es-primary-light;\n\n .tree-checkbox {\n background: $es-primary;\n border-color: $es-primary;\n\n i {\n display: block;\n }\n }\n }\n }\n\n // tree-toggle, btn-select-children, tree-checkbox, tree-icon styles in _tree.scss\n\n .tree-info {\n display: flex;\n align-items: center;\n gap: $es-spacing-xs;\n flex: 1;\n min-width: 0;\n }\n\n .tree-name {\n font-size: $es-font-size-sm;\n color: $es-text-primary;\n @include text-truncate;\n }\n\n .tree-subtitle {\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n }\n}\n\n// ============================================================================\n// Standalone dropdown styles (for when dropdown is appended to body)\n// These selectors work because .target-search-dropdown is on the dropdown itself\n// ============================================================================\n\n.target-search-dropdown {\n // Results container - scrollable\n .dropdown-results {\n max-height: 400px;\n overflow-y: auto;\n padding: 0 $es-spacing-sm;\n @include custom-scrollbar;\n }\n\n // Results header (for list view columns)\n .results-header {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-xs $es-spacing-md;\n background: $es-slate-100;\n border-bottom: 1px solid $es-border-color;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-semibold;\n color: $es-text-secondary;\n\n .header-spacer {\n width: 58px; // checkbox + image width\n flex-shrink: 0;\n }\n\n .header-col {\n flex-shrink: 0;\n width: 70px;\n text-align: right;\n }\n\n .header-col-name {\n flex: 1;\n text-align: left;\n }\n }\n\n // Hide results-header by default, show only for products in list view\n &:not(.view-list) .results-header,\n &.view-tree .results-header {\n display: none;\n }\n\n // Result item for products\n .result-item-product {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n flex: 1;\n min-width: 0;\n }\n\n // Result columns for product data\n .result-col {\n flex-shrink: 0;\n width: 70px;\n text-align: right;\n font-size: $es-font-size-xs;\n }\n\n .result-col-price {\n color: $es-text-secondary;\n }\n\n .result-col-sale {\n color: $es-danger;\n font-weight: $es-font-weight-semibold;\n }\n\n .result-col-stock {\n .col-value {\n &.stock-ok { color: $es-success; }\n &.stock-low { color: $es-warning; }\n &.stock-out { color: $es-danger; }\n }\n }\n\n .result-col-sales {\n color: $es-text-muted;\n }\n\n // Dropdown item styling\n .dropdown-item {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n padding: 0;\n border: none;\n border-bottom: 1px solid $es-border-color;\n border-radius: 0;\n cursor: pointer;\n transition: background-color $es-transition-fast;\n\n &:last-child {\n border-bottom: none;\n }\n\n &:hover {\n background: $es-bg-hover;\n }\n\n &.selected {\n background: $es-primary-light;\n }\n }\n\n // Result checkbox styling\n .result-checkbox {\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n border: 2px solid $es-border-dark;\n border-radius: 3px;\n transition: all $es-transition-fast;\n\n i {\n font-size: 10px;\n color: transparent;\n }\n\n .dropdown-item.selected & {\n background: $es-primary;\n border-color: $es-primary;\n\n i {\n color: $es-white;\n }\n }\n }\n\n // Result image\n .result-image {\n flex-shrink: 0;\n width: 40px;\n height: 40px;\n overflow: hidden;\n border-radius: $es-radius-sm;\n background: $es-slate-100;\n\n img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n }\n\n // Result icon (for non-image entities)\n .result-icon {\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n background: $es-slate-100;\n border-radius: $es-radius-sm;\n\n i {\n font-size: 16px;\n color: $es-text-muted;\n }\n }\n\n // Result info container\n .result-info {\n flex: 1;\n min-width: 0;\n }\n\n .result-name {\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-medium;\n color: $es-text-primary;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .result-subtitle {\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n }\n\n .subtitle-line {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .subtitle-line-primary {\n color: $es-text-secondary;\n }\n\n .subtitle-line-secondary {\n color: $es-text-muted;\n font-size: 11px;\n }\n\n // Hide columns in grid/tree views\n &[class*=\"view-cols-\"] .result-col,\n &.view-tree .result-col {\n display: none;\n }\n\n // Entity search box - full width\n .entity-search-box {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n width: 100%;\n padding: $es-spacing-sm $es-spacing-md;\n background: $es-white;\n border: none;\n border-bottom: 1px solid $es-border-color;\n border-radius: 0;\n\n .entity-search-icon {\n color: $es-text-muted;\n flex-shrink: 0;\n margin-left: $es-spacing-xs;\n }\n\n // Override Bootstrap/parent form input styles\n input.entity-search-input,\n input.entity-search-input[type=\"text\"] {\n flex: 1;\n min-width: 0;\n width: auto !important;\n max-width: none !important;\n height: auto;\n padding: 0;\n margin: 0;\n border: none !important;\n outline: none;\n background: transparent !important;\n font-size: $es-font-size-sm;\n color: $es-text-primary;\n box-shadow: none !important;\n\n &::placeholder {\n color: $es-text-muted;\n }\n\n &:focus {\n border: none !important;\n box-shadow: none !important;\n outline: none;\n }\n }\n\n .search-loading {\n color: $es-text-muted;\n }\n }\n}\n\n// Body-level dropdown (when appended to body for z-index)\nbody > .target-search-dropdown {\n // Override dropdown-item border when inside body-appended dropdown\n .dropdown-item {\n border: none;\n border-radius: 0;\n\n &:not(:last-child) {\n border-bottom: 1px solid $es-border-color;\n }\n }\n}\n\n@keyframes spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n","/**\n * Chips Component\n * Entity chips, selection pills, tags\n */\n\n@use \"sass:color\";\n@use '../variables' as *;\n@use '../mixins' as *;\n\n.target-conditions-trait,\n.entity-selector-trait {\n\n // Chips container wrapper with toolbar\n .chips-wrapper {\n display: flex;\n flex-direction: column;\n margin-top: $es-spacing-sm;\n background: $es-slate-50;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-md;\n overflow: hidden;\n }\n\n // Chips toolbar - integrated filter bar inside chips area\n .chips-toolbar {\n display: none;\n align-items: center;\n flex-wrap: nowrap;\n gap: $es-spacing-sm;\n padding: $es-spacing-sm $es-spacing-md;\n padding-bottom: 0;\n background: transparent;\n\n &.has-chips {\n display: flex;\n }\n\n // Filter input - takes available space, icon embedded as background\n // Using [type=\"text\"] for specificity over .bootstrap input[type=\"text\"]\n input[type=\"text\"].chips-search-input {\n all: unset;\n display: block;\n flex: 1 1 auto;\n min-width: 80px;\n width: auto;\n height: auto;\n padding: 0.2rem 0.5rem 0.2rem 1.5rem;\n background: $es-white url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.35-4.35'/%3E%3C/svg%3E\") no-repeat 0.375rem center;\n background-size: 10px;\n border: 1px solid $es-slate-300;\n border-radius: $es-radius-sm;\n font-size: 11px;\n line-height: 1.4;\n color: $es-text-primary;\n box-sizing: border-box;\n transition: all $es-transition-fast;\n\n &::placeholder {\n color: $es-text-muted;\n font-size: 11px;\n }\n\n &:focus {\n outline: none;\n border-color: $es-primary;\n box-shadow: 0 0 0 2px rgba($es-primary, 0.1);\n }\n }\n\n // Sort dropdown - compact, auto width\n select.chips-sort-select {\n all: unset;\n flex: 0 0 auto;\n padding: 0.2rem 1.25rem 0.2rem 0.5rem;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-sm;\n 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.375rem center;\n background-size: 8px;\n font-size: 10px;\n line-height: 1.4;\n color: $es-text-secondary;\n cursor: pointer;\n box-sizing: border-box;\n white-space: nowrap;\n\n &:hover {\n border-color: $es-primary;\n }\n\n &:focus {\n outline: none;\n border-color: $es-primary;\n box-shadow: 0 0 0 2px rgba($es-primary, 0.1);\n }\n }\n }\n\n // Count badge - smaller, pill style\n .chips-count {\n display: inline-flex;\n align-items: center;\n flex-shrink: 0; // Don't shrink\n gap: 0.125rem;\n padding: 0.2rem 0.5rem;\n background: $es-slate-200;\n color: $es-text-secondary;\n font-size: 10px;\n font-weight: $es-font-weight-semibold;\n border-radius: $es-radius-sm;\n white-space: nowrap;\n line-height: 1.4;\n\n &.has-filter {\n background: $es-cyan-100;\n color: $es-cyan-700;\n }\n\n .count-filtered {\n font-weight: $es-font-weight-bold;\n }\n\n .count-separator {\n opacity: 0.6;\n margin: 0 0.125rem;\n }\n }\n\n .chips-actions {\n display: flex;\n align-items: center;\n gap: $es-spacing-xs;\n margin-left: auto;\n }\n\n // Clear button - subtle, chip-like\n .btn-chips-clear {\n @include button-reset;\n display: inline-flex;\n align-items: center;\n flex-shrink: 0; // Don't shrink\n gap: 0.25rem;\n padding: 0.2rem 0.5rem;\n color: $es-danger;\n font-size: 10px;\n font-weight: $es-font-weight-medium;\n background: rgba($es-danger, 0.1);\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n white-space: nowrap; // Prevent text wrapping\n line-height: 1.4;\n\n &:hover {\n background: $es-danger;\n color: $es-white;\n }\n\n i {\n font-size: 9px;\n flex-shrink: 0;\n }\n\n .clear-text {\n // Hide text on small screens, keep icon\n @media (max-width: 480px) {\n display: none;\n }\n }\n }\n\n // Chips container - flows naturally from toolbar\n .entity-chips {\n display: flex;\n flex-wrap: wrap;\n gap: $es-spacing-xs;\n padding: $es-spacing-sm $es-spacing-md $es-spacing-md;\n min-height: 40px;\n max-height: 300px;\n overflow-y: auto;\n\n &:empty {\n display: none;\n }\n }\n\n // Load more section with select dropdown\n .chips-load-more {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-sm $es-spacing-md;\n background: transparent;\n border-top: 1px dashed $es-border-color;\n\n .load-more-label {\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n }\n\n .load-more-select,\n select.load-more-select {\n appearance: none;\n padding: 0.25rem 1.75rem 0.25rem 0.5rem !important;\n border: 1px solid $es-border-color !important;\n border-radius: $es-radius-sm !important;\n 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;\n background-size: 8px !important;\n font-size: $es-font-size-xs !important;\n font-weight: $es-font-weight-medium;\n color: $es-primary;\n cursor: pointer;\n transition: all $es-transition-fast;\n height: auto !important;\n min-height: 0 !important;\n line-height: 1.3 !important;\n\n &:hover {\n border-color: $es-primary !important;\n background-color: $es-primary-light !important;\n }\n\n &:focus {\n outline: none !important;\n border-color: $es-primary !important;\n box-shadow: 0 0 0 2px rgba($es-primary, 0.1) !important;\n }\n }\n\n .load-more-remaining {\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n }\n }\n\n // Individual chip\n .entity-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.25rem 0.5rem;\n background: $es-slate-100;\n color: $es-text-secondary;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n border-radius: $es-radius-full;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-slate-200;\n }\n\n // Chip with image\n &.has-image {\n padding-left: 0.25rem;\n }\n\n // Hidden by search filter or pagination\n &.chip-filtered-out,\n &.chip-paginated-out {\n display: none;\n }\n }\n\n .chip-image {\n width: 20px;\n height: 20px;\n object-fit: cover;\n border-radius: 50%;\n flex-shrink: 0;\n }\n\n .chip-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n color: $es-text-muted;\n flex-shrink: 0;\n\n // Product/entity images inside chip\n img {\n width: 20px;\n height: 20px;\n object-fit: cover;\n border-radius: $es-radius-sm;\n }\n }\n\n // Country flag in chip\n .chip-flag {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n\n img {\n width: 18px;\n height: 12px;\n object-fit: cover;\n border-radius: 2px;\n box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);\n }\n\n .flag-fallback {\n width: 18px;\n height: 12px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: linear-gradient(135deg, #e8eaed 0%, #dadce0 100%);\n border-radius: 2px;\n font-size: 10px;\n color: #5f6368;\n }\n }\n\n // Holiday preview button in country chip\n .chip-preview-holidays {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n color: $es-primary;\n border-radius: 50%;\n flex-shrink: 0;\n transition: all $es-transition-fast;\n\n &:hover {\n background: rgba($es-primary, 0.15);\n color: darken($es-primary, 10%);\n }\n\n i.material-icons {\n font-size: 14px !important;\n }\n }\n\n .chip-text,\n .chip-name {\n // Show full name, no truncation\n word-break: break-word;\n }\n\n .chip-remove {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n margin-left: 0.125rem;\n color: $es-text-muted;\n border-radius: 50%;\n flex-shrink: 0;\n transition: all $es-transition-fast;\n\n &:hover {\n background: rgba(0, 0, 0, 0.1);\n color: $es-danger;\n }\n\n i {\n font-size: 10px;\n }\n }\n\n // Chip variants\n .entity-chip.chip-primary {\n background: $es-primary-light;\n color: $es-primary;\n\n &:hover {\n background: rgba($es-primary, 0.2);\n }\n }\n\n .entity-chip.chip-success {\n background: $es-success-light;\n color: $es-success-dark;\n\n &:hover {\n background: rgba($es-success, 0.2);\n }\n }\n\n .entity-chip.chip-danger {\n background: $es-danger-light;\n color: $es-danger;\n\n &:hover {\n background: rgba($es-danger, 0.2);\n }\n }\n\n .entity-chip.chip-warning {\n background: $es-warning-light;\n color: color.adjust($es-warning, $lightness: -20%);\n\n &:hover {\n background: rgba($es-warning, 0.3);\n }\n }\n\n // Chip loading state\n .entity-chip.loading,\n .entity-chip-loading {\n opacity: 0.7;\n\n .chip-remove {\n display: none;\n }\n\n .chip-icon i {\n animation: spin 0.6s linear infinite;\n }\n }\n\n // Hidden chip (collapsed view)\n .entity-chip.chip-hidden {\n display: none;\n }\n\n // Chips expanded/collapsed states\n .entity-chips.chips-collapsed,\n .entity-chips.chips-expanded {\n position: relative;\n }\n\n // Show more/less toggle\n .chips-show-more-toggle {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n color: $es-primary;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n cursor: pointer;\n transition: color $es-transition-fast;\n\n &:hover {\n color: $es-primary-hover;\n }\n\n i {\n font-size: 10px;\n }\n }\n\n .chips-collapse-toggle,\n .chips-expand-toggle {\n // Specific variants inherit from .chips-show-more-toggle\n }\n\n // More chips indicator\n .chips-more {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 0.25rem 0.5rem;\n background: $es-slate-200;\n color: $es-text-secondary;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-semibold;\n border-radius: $es-radius-full;\n cursor: pointer;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-slate-300;\n }\n }\n\n // Add chip button\n .chip-add-btn {\n @include button-reset;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n background: transparent;\n color: $es-primary;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n border: 1px dashed $es-primary;\n border-radius: $es-radius-full;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-primary-light;\n }\n\n i {\n font-size: 10px;\n }\n }\n\n // Inline chips (compact mode)\n .entity-chips.inline {\n display: inline-flex;\n padding: 0;\n min-height: auto;\n\n .entity-chip {\n padding: 0.125rem 0.375rem;\n font-size: 11px;\n }\n }\n\n // Selected chips section in include/exclude\n .selected-chips-container {\n display: flex;\n flex-direction: column;\n gap: $es-spacing-xs;\n }\n\n .selected-chips-label {\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n color: $es-text-muted;\n }\n\n // Pattern chips (for name/reference patterns)\n .entity-chip.chip-pattern {\n background: #fef3c7;\n color: #92400e;\n font-family: monospace;\n\n &:hover {\n background: #fde68a;\n }\n\n .chip-icon {\n color: #d97706;\n }\n }\n\n // Range chips (price, quantity, etc.)\n .entity-chip.chip-range,\n .range-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.25rem 0.5rem;\n background: $es-cyan-50;\n color: $es-cyan-600;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n border-radius: $es-radius-full;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-cyan-100;\n }\n }\n\n .range-chip-text {\n font-family: monospace;\n }\n\n .btn-remove-range {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n color: $es-cyan-600;\n border-radius: 50%;\n transition: all $es-transition-fast;\n\n &:hover {\n background: rgba(0, 0, 0, 0.1);\n color: $es-danger;\n }\n\n i {\n font-size: 10px;\n }\n }\n\n // Multi-range chips container\n .multi-range-chips {\n display: flex;\n flex-wrap: wrap;\n gap: $es-spacing-xs;\n margin-bottom: $es-spacing-xs;\n\n &:empty {\n display: none;\n }\n }\n\n // Pattern chips container\n .pattern-chips {\n display: flex;\n flex-wrap: wrap;\n gap: $es-spacing-xs;\n padding: $es-spacing-sm 0;\n min-height: 32px;\n\n &:empty::before {\n content: attr(data-placeholder);\n color: $es-text-muted;\n font-size: $es-font-size-xs;\n font-style: italic;\n }\n }\n\n // Pattern tag\n .pattern-tag {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n background: #fef3c7;\n color: #92400e;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n &:hover {\n background: #fde68a;\n }\n\n &.case-sensitive {\n .case-icon {\n color: $es-success;\n font-weight: $es-font-weight-bold;\n }\n }\n\n &.draft-tag {\n background: $es-white;\n border: 1px solid $es-border-color;\n padding: 0;\n flex: 1;\n min-width: 150px;\n\n &:hover {\n background: $es-white;\n }\n\n .pattern-input {\n flex: 1;\n min-width: 100px;\n padding: 0.375rem;\n border: 0;\n background: transparent;\n font-size: $es-font-size-sm;\n font-family: inherit;\n\n &:focus {\n outline: none;\n }\n\n &::placeholder {\n color: $es-text-muted;\n font-style: italic;\n }\n }\n }\n }\n\n .pattern-tag-text {\n font-family: monospace;\n max-width: 200px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .btn-toggle-case {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n color: $es-text-muted;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n &:hover {\n background: rgba(0, 0, 0, 0.1);\n }\n }\n\n .case-icon {\n font-size: 11px;\n font-weight: $es-font-weight-semibold;\n font-family: monospace;\n }\n\n .btn-remove-pattern {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n color: #d97706;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n &:hover {\n background: rgba(0, 0, 0, 0.1);\n color: $es-danger;\n }\n\n i {\n font-size: 10px;\n }\n }\n\n .btn-add-pattern {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n color: $es-primary;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-primary-light;\n }\n\n i {\n font-size: 12px;\n }\n }\n\n // Pattern match count (in draft tag)\n .pattern-match-count {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0 0.375rem;\n color: $es-text-muted;\n font-size: $es-font-size-xs;\n cursor: pointer;\n\n &.count-zero {\n color: $es-warning;\n }\n\n &.count-found {\n color: $es-success;\n }\n\n .count-value {\n font-weight: $es-font-weight-semibold;\n }\n }\n\n // Pattern input row\n .pattern-input-row {\n display: flex;\n align-items: stretch;\n gap: $es-spacing-xs;\n }\n}\n\n// ==========================================================================\n// Holiday Preview Popover (Country chip eye button)\n// ==========================================================================\n\n.holiday-preview-popover {\n position: absolute;\n z-index: 10001;\n width: 320px;\n max-width: 90vw;\n background: $es-white;\n border-radius: $es-radius-lg;\n box-shadow: $es-shadow-xl;\n overflow: hidden;\n\n .popover-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: $es-spacing-sm;\n padding: $es-spacing-sm $es-spacing-md;\n background: $es-bg-header;\n border-bottom: 1px solid $es-border-color;\n }\n\n .popover-title {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-semibold;\n color: $es-text-primary;\n }\n\n .popover-flag {\n border-radius: 2px;\n box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);\n }\n\n .popover-close {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n color: $es-text-muted;\n border-radius: $es-radius-md;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-slate-200;\n color: $es-text-secondary;\n }\n\n i.material-icons {\n font-size: 18px !important;\n }\n }\n\n .popover-body {\n max-height: 350px;\n overflow-y: auto;\n padding: $es-spacing-sm;\n @include custom-scrollbar;\n }\n\n // Loading state\n .holiday-preview-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-xl 0;\n color: $es-text-muted;\n font-size: $es-font-size-sm;\n\n i.material-icons {\n font-size: 20px !important;\n }\n\n .es-spin {\n animation: spin 1s linear infinite;\n }\n }\n\n // Empty state\n .holiday-preview-empty {\n text-align: center;\n padding: $es-spacing-xl 0;\n color: $es-text-muted;\n\n i.material-icons {\n font-size: 48px !important;\n opacity: 0.4;\n margin-bottom: $es-spacing-sm;\n display: block;\n }\n\n p {\n margin: 0;\n font-size: $es-font-size-sm;\n }\n }\n\n // Holiday list\n .holiday-list {\n display: flex;\n flex-direction: column;\n gap: $es-spacing-xs;\n }\n\n .holiday-item {\n display: flex;\n align-items: flex-start;\n gap: $es-spacing-md;\n padding: $es-spacing-sm $es-spacing-md;\n background: $es-slate-50;\n border-radius: $es-radius-md;\n border-left: 3px solid $es-success;\n\n &.holiday-type-bank,\n &.holiday-type-bank-holiday {\n border-left-color: $es-info;\n }\n\n &.holiday-type-observance {\n border-left-color: $es-warning;\n }\n\n &.holiday-type-regional,\n &.holiday-type-local-holiday {\n border-left-color: #8b5cf6;\n }\n }\n\n .holiday-date {\n flex-shrink: 0;\n min-width: 80px;\n\n .holiday-day {\n display: block;\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-semibold;\n color: $es-text-primary;\n }\n\n .holiday-weekday {\n display: block;\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n }\n }\n\n .holiday-info {\n flex: 1;\n min-width: 0;\n }\n\n .holiday-country-flag {\n vertical-align: middle;\n margin-right: 0.25rem;\n border-radius: 2px;\n box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);\n }\n\n .holiday-name {\n display: inline;\n font-size: $es-font-size-sm;\n color: $es-text-primary;\n word-wrap: break-word;\n }\n\n .holiday-type-badge {\n display: inline-block;\n margin-left: $es-spacing-sm;\n padding: 0.125rem 0.375rem;\n font-size: 10px;\n font-weight: $es-font-weight-medium;\n text-transform: capitalize;\n background: $es-slate-200;\n color: $es-text-secondary;\n border-radius: $es-radius-sm;\n vertical-align: middle;\n }\n\n .holiday-preview-note {\n margin-top: $es-spacing-md;\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n text-align: center;\n }\n\n // Filter input\n .popover-filter {\n display: flex;\n align-items: center;\n gap: $es-spacing-xs;\n padding: $es-spacing-xs $es-spacing-md;\n border-bottom: 1px solid $es-border-color;\n background: $es-slate-50;\n\n i.material-icons {\n font-size: 18px !important;\n color: $es-text-muted;\n }\n\n .holiday-filter-input {\n flex: 1;\n border: none;\n background: transparent;\n font-size: $es-font-size-sm;\n color: $es-text-primary;\n outline: none;\n padding: $es-spacing-xs 0;\n\n &::placeholder {\n color: $es-text-muted;\n }\n }\n }\n}\n\n// Spin animation for loading icons\n@keyframes spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n// Bootstrap specificity overrides for chips toolbar form elements\n// PrestaShop admin uses #content .mpr-config-form... with high specificity\n// We need to match or exceed that specificity\n#content.bootstrap,\n#content .bootstrap,\n.bootstrap #content {\n .target-conditions-trait,\n .entity-selector-trait {\n .chips-wrapper .chips-toolbar {\n // Double class for extra specificity\n input[type=\"text\"].chips-search-input.chips-search-input {\n all: unset;\n display: block;\n flex: 1 1 auto;\n min-width: 80px;\n width: auto;\n height: auto;\n padding: 0.2rem 0.5rem 0.2rem 1.5rem;\n background: $es-white url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.35-4.35'/%3E%3C/svg%3E\") no-repeat 0.375rem center;\n background-size: 10px;\n border: 1px solid $es-slate-300;\n border-radius: $es-radius-sm;\n font-size: 11px;\n line-height: 1.4;\n color: $es-text-primary;\n box-sizing: border-box;\n transition: all $es-transition-fast;\n\n &::placeholder {\n color: $es-text-muted;\n font-size: 11px;\n }\n\n &:focus {\n outline: none;\n border-color: $es-primary;\n box-shadow: 0 0 0 2px rgba($es-primary, 0.1);\n }\n }\n\n // Double class for extra specificity\n select.chips-sort-select.chips-sort-select {\n all: unset;\n flex: 0 0 auto;\n padding: 0.2rem 1.25rem 0.2rem 0.5rem;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-sm;\n 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.375rem center;\n background-size: 8px;\n font-size: 10px;\n line-height: 1.4;\n color: $es-text-secondary;\n cursor: pointer;\n box-sizing: border-box;\n white-space: nowrap;\n height: auto;\n\n &:hover {\n border-color: $es-primary;\n }\n\n &:focus {\n outline: none;\n border-color: $es-primary;\n box-shadow: 0 0 0 2px rgba($es-primary, 0.1);\n }\n }\n }\n }\n}\n","/**\n * Groups Component\n * Selection groups, include/exclude sections, method selectors\n */\n\n@use '../variables' as *;\n@use '../mixins' as *;\n\n.target-conditions-trait,\n.entity-selector-trait {\n\n // Group container\n .target-group {\n background: $es-white;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-lg;\n overflow: hidden;\n }\n\n // Group header\n .target-group-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: $es-spacing-md;\n padding: $es-spacing-sm $es-spacing-md;\n background: $es-bg-header;\n border-bottom: 1px solid $es-border-color;\n }\n\n .target-group-title {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-semibold;\n color: $es-text-primary;\n\n .group-number {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 20px;\n height: 20px;\n padding: 0 0.25rem;\n background: $es-primary;\n color: $es-white;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-bold;\n border-radius: $es-radius-full;\n }\n }\n\n .target-group-actions {\n display: flex;\n align-items: center;\n gap: $es-spacing-xs;\n }\n\n .group-action-btn {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n color: $es-text-muted;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-slate-200;\n color: $es-text-secondary;\n }\n\n &.danger:hover {\n background: $es-danger-light;\n color: $es-danger;\n }\n }\n\n // Group body\n .target-group-body,\n .group-body {\n padding: $es-spacing-md;\n }\n\n // Include section\n .include-section {\n margin-bottom: $es-spacing-md;\n }\n\n .section-label {\n display: flex;\n align-items: center;\n gap: $es-spacing-xs;\n margin-bottom: $es-spacing-sm;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-semibold;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n\n &.label-include {\n color: $es-success-dark;\n\n i {\n color: $es-success;\n }\n }\n\n &.label-exclude {\n color: $es-danger;\n\n i {\n color: $es-danger;\n }\n }\n }\n\n // Method selector\n .method-selector {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n margin-bottom: $es-spacing-sm;\n }\n\n .method-selector-wrapper {\n flex: 1;\n position: relative;\n }\n\n .method-select {\n @include input-base;\n padding-right: 2rem;\n cursor: pointer;\n appearance: none;\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E\");\n background-position: right 0.5rem center;\n background-repeat: no-repeat;\n background-size: 1.5em 1.5em;\n }\n\n .method-help-btn {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n color: $es-text-muted;\n border-radius: $es-radius-full;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-slate-100;\n color: $es-primary;\n }\n }\n\n // Value picker (search trigger)\n .value-picker {\n position: relative;\n }\n\n .value-picker-trigger {\n @include button-reset;\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n width: 100%;\n padding: $es-spacing-sm $es-spacing-md;\n background: $es-white;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-md;\n color: $es-text-muted;\n font-size: $es-font-size-sm;\n text-align: left;\n transition: all $es-transition-fast;\n\n &:hover {\n border-color: $es-slate-300;\n }\n\n &:focus {\n border-color: $es-primary;\n @include focus-ring($es-primary);\n }\n\n i {\n color: $es-text-light;\n }\n }\n\n // Pattern input (text input for patterns)\n .pattern-input-wrapper {\n position: relative;\n }\n\n .pattern-input {\n @include input-base;\n font-family: monospace;\n }\n\n .pattern-add-btn {\n @include button-reset;\n position: absolute;\n right: 0.25rem;\n top: 50%;\n transform: translateY(-50%);\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n color: $es-primary;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-primary-light;\n }\n }\n\n // Multi-range input (price ranges)\n .multi-range-container {\n display: flex;\n flex-direction: column;\n gap: $es-spacing-sm;\n }\n\n .range-row {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n }\n\n .range-input {\n @include input-base;\n width: 100px;\n text-align: center;\n }\n\n .range-separator {\n color: $es-text-muted;\n font-size: $es-font-size-sm;\n }\n\n .range-remove-btn {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n color: $es-text-muted;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-danger-light;\n color: $es-danger;\n }\n }\n\n .range-add-btn {\n @include button-reset;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n color: $es-primary;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-primary-light;\n }\n }\n\n // Multi-select tiles (stock status, etc.)\n .multi-select-tiles {\n display: flex;\n flex-wrap: wrap;\n gap: $es-spacing-xs;\n }\n\n .multi-select-tile {\n @include button-reset;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.375rem 0.75rem;\n background: $es-slate-100;\n color: $es-text-secondary;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n border: 1px solid transparent;\n border-radius: $es-radius-full;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-slate-200;\n }\n\n &.selected {\n background: $es-primary-light;\n color: $es-primary;\n border-color: $es-primary;\n }\n }\n\n // Exclude section\n .exclude-section {\n margin-top: $es-spacing-md;\n padding-top: $es-spacing-md;\n border-top: 1px dashed $es-border-color;\n }\n\n // Legacy exclude-rows (if used elsewhere)\n .exclude-rows {\n display: flex;\n flex-direction: column;\n gap: $es-spacing-sm;\n }\n\n .exclude-row-content {\n flex: 1;\n }\n\n .exclude-remove-btn {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n color: $es-text-muted;\n border-radius: $es-radius-sm;\n flex-shrink: 0;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-danger-light;\n color: $es-danger;\n }\n }\n\n .add-exclude-btn {\n @include button-reset;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n margin-top: $es-spacing-sm;\n padding: 0.25rem 0.5rem;\n color: $es-danger;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n border: 1px dashed $es-danger;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-danger-light;\n }\n }\n\n // Add group button (used in block-footer)\n .btn-add-group {\n @include button-reset;\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.5rem 0.875rem;\n color: $es-primary;\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-medium;\n background: rgba($es-primary, 0.05);\n border: 1px dashed $es-primary;\n border-radius: 0.375rem;\n cursor: pointer;\n transition: all $es-transition-fast;\n\n &:hover {\n background: rgba($es-primary, 0.1);\n }\n\n i {\n font-size: 12px;\n }\n }\n\n // Block footer\n .block-footer {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-md;\n border-top: 1px solid $es-border-color;\n }\n\n // Block body\n .block-body {\n padding: 0;\n }\n\n // Groups container\n .groups-container {\n padding: $es-spacing-md;\n }\n\n // Groups empty state\n .groups-empty-state {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: $es-spacing-xl;\n color: $es-text-muted;\n font-size: $es-font-size-sm;\n }\n\n // Selection group\n .selection-group {\n background: $es-white;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-lg;\n margin-bottom: $es-spacing-md;\n\n &:last-child {\n margin-bottom: 0;\n }\n\n &.collapsed {\n .group-body {\n display: none;\n }\n\n .group-collapse-toggle i {\n transform: rotate(-90deg);\n }\n }\n }\n\n // Group header\n .group-header {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-sm $es-spacing-md;\n background: $es-bg-header;\n border-bottom: 1px solid $es-border-color;\n border-radius: $es-radius-lg $es-radius-lg 0 0;\n cursor: pointer;\n\n &.group-header-single {\n padding: $es-spacing-xs $es-spacing-md;\n background: transparent;\n border-bottom: none;\n }\n }\n\n .group-collapse-toggle {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n color: $es-text-muted;\n\n i {\n font-size: 20px !important;\n transition: transform $es-transition-fast;\n }\n }\n\n .group-name-wrapper {\n flex: 1;\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n }\n\n .group-name-input {\n flex: 1;\n padding: 0.25rem 0.5rem;\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-semibold;\n color: $es-text-primary;\n background: transparent;\n border: 1px solid transparent;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n &:hover,\n &:focus {\n background: $es-white;\n border-color: $es-border-color;\n outline: none;\n }\n\n &::placeholder {\n color: $es-text-muted;\n font-weight: $es-font-weight-medium;\n }\n }\n\n .group-count-badge {\n @include count-badge($es-primary);\n }\n\n .btn-remove-group {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n color: $es-text-muted;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-danger-light;\n color: $es-danger;\n }\n }\n\n // Group include section - green accent to distinguish from exclude\n .group-include {\n margin-bottom: $es-spacing-md;\n padding: $es-spacing-sm;\n background: rgba($es-success, 0.03);\n border: 1px solid rgba($es-success, 0.2);\n border-radius: $es-radius-md;\n }\n\n .section-row {\n display: flex;\n flex-direction: column;\n gap: $es-spacing-sm;\n }\n\n // Method selector wrapper (from PHP)\n .method-selector-wrapper {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n }\n\n .method-info-placeholder {\n display: flex;\n align-items: center;\n min-width: 20px;\n }\n\n .include-method-select,\n .exclude-method-select {\n flex: 1;\n @include input-base;\n cursor: pointer;\n }\n\n // Lock indicator for method selector (when excludes are present)\n .selector-locked {\n .include-method-select {\n opacity: 0.7;\n cursor: not-allowed;\n }\n }\n\n .lock-indicator {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n color: $es-warning;\n cursor: help;\n\n i {\n font-size: 16px !important;\n }\n\n .mpr-tooltip {\n display: none;\n position: absolute;\n bottom: calc(100% + 8px);\n left: 50%;\n transform: translateX(-50%);\n padding: $es-spacing-xs $es-spacing-sm;\n background: $es-slate-800;\n color: $es-white;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-normal;\n white-space: nowrap;\n border-radius: $es-radius-sm;\n z-index: 100;\n }\n\n &:hover .mpr-tooltip {\n display: block;\n }\n }\n\n // Group excludes section\n .group-excludes {\n margin-top: $es-spacing-md;\n }\n\n .except-separator {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n margin: 0 0 $es-spacing-sm 0;\n\n // Lines on both sides\n &::before,\n &::after {\n content: '';\n flex: 1;\n height: 1px;\n background: rgba($es-danger, 0.3);\n }\n }\n\n .except-label {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.75rem;\n background: $es-danger-light;\n color: $es-danger;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-semibold;\n border-radius: $es-radius-full;\n white-space: nowrap;\n flex-shrink: 0;\n\n i {\n font-size: 12px !important;\n }\n }\n\n .exclude-rows-container {\n display: flex;\n flex-direction: column;\n gap: $es-spacing-sm;\n }\n\n .exclude-row {\n display: flex;\n flex-direction: column;\n padding: $es-spacing-sm;\n background: rgba($es-danger, 0.03);\n border: 1px solid rgba($es-danger, 0.15);\n border-radius: $es-radius-md;\n\n // Value picker inside exclude row - full width\n .value-picker {\n width: 100%;\n margin-top: $es-spacing-sm;\n }\n }\n\n .exclude-header-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: $es-spacing-sm;\n width: 100%;\n\n .method-selector-wrapper {\n flex: 1;\n }\n\n // Delete button at the far right\n .btn-remove-exclude-row {\n flex-shrink: 0;\n margin-left: auto;\n }\n }\n\n .btn-remove-exclude-row {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n color: $es-text-muted;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-danger-light;\n color: $es-danger;\n }\n }\n\n .btn-add-exclude,\n .btn-add-another-exclude {\n @include button-reset;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n margin-top: $es-spacing-sm;\n padding: 0.375rem 0.625rem;\n color: $es-danger;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n background: transparent;\n border: 1px dashed rgba($es-danger, 0.5);\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-danger-light;\n border-color: $es-danger;\n }\n\n i {\n font-size: 12px !important;\n }\n }\n\n // Group modifiers (inline version from PHP)\n // Uses negative margins to break out of .group-body padding\n // Elements use .mpr-input-compact class to opt out of admin.css global sizing\n .group-modifiers {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: $es-spacing-md;\n padding: $es-spacing-sm $es-spacing-md;\n margin: $es-spacing-md (-$es-spacing-md) (-$es-spacing-md);\n background: $es-slate-50;\n border-top: 1px solid $es-border-color;\n border-radius: 0 0 $es-radius-lg $es-radius-lg;\n }\n\n .modifier-inline {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n flex-shrink: 0;\n }\n\n // Common height for all modifier controls\n $modifier-height: 26px;\n\n .group-modifier-limit {\n width: 50px;\n max-width: 50px;\n min-width: 50px;\n height: $modifier-height;\n padding: 0 0.375rem;\n font-size: $es-font-size-xs;\n text-align: center;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-sm;\n box-sizing: border-box;\n\n &:focus {\n border-color: $es-primary;\n outline: none;\n }\n }\n\n // Sort modifier - input group style (select + button glued together)\n .modifier-sort {\n gap: 0; // Remove gap to glue select + button together\n\n .modifier-label {\n margin-right: 0.375rem; // Keep space between label and input group\n }\n\n .group-modifier-sort {\n width: auto;\n height: $modifier-height;\n padding: 0 1.25rem 0 0.5rem;\n font-size: $es-font-size-xs;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-sm 0 0 $es-radius-sm;\n border-right: none;\n cursor: pointer;\n box-sizing: border-box;\n\n &:focus {\n border-color: $es-primary;\n outline: none;\n position: relative;\n z-index: 1;\n }\n }\n\n .btn-sort-dir {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: $modifier-height;\n height: $modifier-height;\n color: $es-text-muted;\n background: $es-slate-100;\n border: 1px solid $es-border-color;\n border-radius: 0 $es-radius-sm $es-radius-sm 0;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-slate-200;\n color: $es-text-secondary;\n }\n\n i {\n font-size: 14px !important;\n }\n }\n }\n\n // Fallback for elements outside .modifier-sort context\n .group-modifier-sort {\n height: $modifier-height;\n padding: 0 0.5rem;\n font-size: $es-font-size-xs;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-sm;\n cursor: pointer;\n\n &:focus {\n border-color: $es-primary;\n outline: none;\n }\n }\n\n .btn-sort-dir {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: $modifier-height;\n height: $modifier-height;\n color: $es-text-muted;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-slate-100;\n color: $es-text-secondary;\n }\n }\n\n .group-preview-badge {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n background: $es-slate-100;\n color: $es-text-muted;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n border-radius: $es-radius-full;\n transition: all $es-transition-fast;\n\n &.clickable {\n cursor: pointer;\n\n &:hover {\n background: $es-primary-light;\n color: $es-primary;\n }\n }\n }\n\n // OR separator between groups\n .group-separator {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: $es-spacing-sm 0;\n color: $es-text-muted;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-semibold;\n text-transform: uppercase;\n letter-spacing: 0.1em;\n\n &::before,\n &::after {\n content: '';\n flex: 1;\n height: 1px;\n background: $es-border-color;\n margin: 0 $es-spacing-md;\n }\n }\n\n // Group modifiers (limit, sort)\n .group-modifiers {\n display: flex;\n flex-wrap: wrap;\n gap: $es-spacing-md;\n padding-top: $es-spacing-md;\n margin-top: $es-spacing-md;\n border-top: 1px solid $es-border-color;\n }\n\n .modifier-group {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n }\n\n .modifier-label {\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n color: $es-text-muted;\n white-space: nowrap;\n }\n\n .modifier-input {\n @include input-base;\n width: 80px;\n padding: 0.25rem 0.5rem;\n font-size: $es-font-size-xs;\n }\n\n .modifier-select {\n @include input-base;\n width: auto;\n padding: 0.25rem 1.5rem 0.25rem 0.5rem;\n font-size: $es-font-size-xs;\n cursor: pointer;\n appearance: none;\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E\");\n background-position: right 0.25rem center;\n background-repeat: no-repeat;\n background-size: 1.25em 1.25em;\n }\n\n // Condition match count badge\n .condition-match-count {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.125rem 0.375rem;\n background: $es-slate-100;\n color: $es-text-muted;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n border-radius: $es-radius-full;\n cursor: pointer;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-slate-200;\n }\n\n &.has-results {\n background: $es-primary-light;\n color: $es-primary;\n }\n\n // Country holidays variant - use calendar icon style\n &.country-holidays {\n background: rgba(139, 92, 246, 0.1);\n color: #8b5cf6;\n\n &:hover {\n background: rgba(139, 92, 246, 0.2);\n }\n\n &.clickable {\n background: rgba(139, 92, 246, 0.15);\n }\n }\n\n i {\n font-size: 12px !important;\n }\n }\n}\n","/**\n * Value Picker Component\n * Search boxes, input types, range inputs\n */\n\n@use '../variables' as *;\n@use '../mixins' as *;\n\n.target-conditions-trait,\n.entity-selector-trait {\n\n // Value picker container\n .value-picker {\n padding: $es-spacing-sm 0;\n\n &[style*=\"display: none\"],\n &[style*=\"display:none\"] {\n padding: 0;\n }\n }\n\n .include-picker,\n .exclude-picker {\n // Section-specific picker styles\n }\n\n // Entity search box\n .entity-search-box {\n position: relative;\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-xs;\n background: $es-white;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-md;\n transition: all $es-transition-fast;\n\n &:focus-within {\n border-color: $es-primary;\n box-shadow: 0 0 0 2px rgba($es-primary, 0.1);\n }\n }\n\n // Separation between chips and search box\n .chips-wrapper + .entity-search-box {\n margin-top: $es-spacing-md;\n }\n\n .entity-search-icon {\n color: $es-text-muted;\n font-size: 14px;\n flex-shrink: 0;\n margin-left: $es-spacing-xs;\n }\n\n // Override parent form's max-width on search input\n input.entity-search-input,\n input.entity-search-input[type=\"text\"] {\n @include input-reset;\n flex: 1;\n min-width: 0;\n width: auto !important;\n max-width: none !important;\n padding: 0.375rem;\n font-size: $es-font-size-sm;\n color: $es-text-primary;\n border: none !important;\n background: transparent !important;\n box-shadow: none !important;\n\n &::placeholder {\n color: $es-text-muted;\n }\n\n &:focus {\n border: none !important;\n box-shadow: none !important;\n outline: none;\n }\n }\n\n .search-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n color: $es-primary;\n\n i {\n animation: spin 0.6s linear infinite;\n }\n }\n\n // Browse tree button (for categories)\n .btn-browse-tree {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n margin-left: auto;\n color: $es-primary;\n background: $es-primary-light;\n border-radius: $es-radius-sm;\n flex-shrink: 0;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-primary;\n color: $es-white;\n }\n\n i {\n font-size: 14px;\n }\n }\n\n // Numeric range box\n .numeric-range-box,\n .multi-range-input-row {\n display: flex;\n align-items: center;\n gap: $es-spacing-xs;\n }\n\n .range-min-input,\n .range-max-input {\n @include input-base;\n width: 100px;\n padding: $es-spacing-sm;\n text-align: center;\n font-size: $es-font-size-sm;\n\n &::-webkit-inner-spin-button,\n &::-webkit-outer-spin-button {\n -webkit-appearance: none;\n margin: 0;\n }\n -moz-appearance: textfield;\n }\n\n .range-separator {\n color: $es-text-muted;\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-medium;\n }\n\n .btn-add-range {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n color: $es-white;\n background: $es-primary;\n border-radius: $es-radius-md;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-primary-hover;\n }\n\n i {\n font-size: 12px;\n }\n }\n\n // Multi-range container\n .multi-range-container {\n display: flex;\n flex-direction: column;\n gap: $es-spacing-sm;\n }\n\n // Date range box\n .date-range-box {\n display: flex;\n align-items: center;\n gap: $es-spacing-xs;\n }\n\n .date-from-input,\n .date-to-input {\n @include input-base;\n width: 140px;\n padding: $es-spacing-sm;\n font-size: $es-font-size-sm;\n }\n\n // Multi-select tiles\n .multi-select-tiles {\n display: flex;\n flex-wrap: wrap;\n gap: $es-spacing-xs;\n }\n\n .tile-option {\n @include button-reset;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.375rem 0.75rem;\n color: $es-text-muted;\n background: transparent;\n border: 1px dashed $es-border-color;\n border-radius: 100px; // Pill shape\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-normal;\n cursor: pointer;\n transition: all $es-transition-fast;\n\n &:hover {\n color: $es-text-secondary;\n border-color: $es-slate-400;\n border-style: solid;\n }\n\n &.selected {\n color: $es-primary;\n background: $es-primary-light;\n border: 1px solid $es-primary;\n font-weight: $es-font-weight-medium;\n }\n\n i {\n font-size: 11px;\n opacity: 0.6;\n }\n\n &.selected i {\n opacity: 1;\n }\n }\n\n .tile-label {\n white-space: nowrap;\n }\n\n // Select input box\n .select-input-box {\n display: inline-block;\n }\n\n .select-value-input {\n @include input-base;\n padding: $es-spacing-sm $es-spacing-md;\n font-size: $es-font-size-sm;\n min-width: 150px;\n }\n\n // Boolean input box\n .boolean-input-box {\n display: inline-flex;\n align-items: center;\n padding: $es-spacing-sm $es-spacing-md;\n background: $es-success-light;\n color: $es-success-dark;\n border-radius: $es-radius-md;\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-medium;\n }\n\n .boolean-label {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n\n &::before {\n content: '\\2713';\n font-weight: bold;\n }\n }\n\n // Condition match count badge\n .condition-match-count {\n @include count-badge($es-primary);\n margin-left: $es-spacing-sm;\n }\n}\n","/**\n * Modal Component\n * Preview modals, confirmation dialogs\n */\n\n@use \"sass:color\";\n@use '../variables' as *;\n@use '../mixins' as *;\n\n// Modal backdrop\n.mpr-modal-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n z-index: $es-z-modal;\n opacity: 0;\n transition: opacity $es-transition-normal;\n\n &.show {\n opacity: 1;\n }\n}\n\n// Modal container\n.mpr-modal {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%) scale(0.95);\n z-index: $es-z-modal + 1;\n width: 90%;\n max-width: 600px;\n max-height: 90vh;\n background: $es-white;\n border-radius: $es-radius-xl;\n box-shadow: $es-shadow-xl;\n opacity: 0;\n transition: all $es-transition-normal;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n\n &.show {\n opacity: 1;\n transform: translate(-50%, -50%) scale(1);\n }\n\n &.modal-sm {\n max-width: 400px;\n }\n\n &.modal-lg {\n max-width: 800px;\n }\n\n &.modal-xl {\n max-width: 1000px;\n }\n\n &.modal-fullscreen {\n width: 95%;\n max-width: none;\n height: 90vh;\n max-height: none;\n }\n}\n\n// Modal header\n.mpr-modal-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: $es-spacing-md;\n padding: $es-spacing-md $es-spacing-lg;\n background: $es-bg-header;\n border-bottom: 1px solid $es-border-color;\n flex-shrink: 0;\n}\n\n.mpr-modal-title {\n font-size: $es-font-size-base;\n font-weight: $es-font-weight-semibold;\n color: $es-text-primary;\n margin: 0;\n}\n\n.mpr-modal-close {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n color: $es-text-muted;\n border-radius: $es-radius-md;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-slate-200;\n color: $es-text-secondary;\n }\n\n i {\n font-size: $es-font-size-lg;\n }\n}\n\n// Modal body\n.mpr-modal-body {\n flex: 1;\n overflow-y: auto;\n padding: $es-spacing-lg;\n @include custom-scrollbar;\n}\n\n// Modal footer\n.mpr-modal-footer {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: $es-spacing-sm;\n padding: $es-spacing-md $es-spacing-lg;\n background: $es-bg-header;\n border-top: 1px solid $es-border-color;\n flex-shrink: 0;\n}\n\n.mpr-modal-btn {\n @include button-reset;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: $es-spacing-xs;\n padding: $es-spacing-sm $es-spacing-md;\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-medium;\n border-radius: $es-radius-md;\n transition: all $es-transition-fast;\n\n &.btn-secondary {\n color: $es-text-secondary;\n background: $es-slate-100;\n\n &:hover {\n background: $es-slate-200;\n }\n }\n\n &.btn-primary {\n color: $es-white;\n background: $es-primary;\n\n &:hover {\n background: $es-primary-hover;\n }\n }\n\n &.btn-danger {\n color: $es-white;\n background: $es-danger;\n\n &:hover {\n background: color.adjust($es-danger, $lightness: -10%);\n }\n }\n\n &:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n}\n\n// Preview popover styles moved to _list-preview.scss\n\n.popover-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: $es-spacing-sm;\n padding: $es-spacing-sm $es-spacing-md;\n background: $es-bg-header;\n border-bottom: 1px solid $es-border-color;\n border-radius: $es-radius-lg $es-radius-lg 0 0;\n}\n\n.popover-title {\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-semibold;\n color: $es-text-primary;\n}\n\n.popover-close {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n color: $es-text-muted;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-slate-200;\n color: $es-text-secondary;\n }\n}\n\n.popover-body {\n max-height: 300px;\n overflow-y: auto;\n padding: $es-spacing-sm;\n @include custom-scrollbar;\n}\n\n.popover-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: $es-spacing-sm;\n padding: $es-spacing-sm $es-spacing-md;\n background: $es-bg-header;\n border-top: 1px solid $es-border-color;\n border-radius: 0 0 $es-radius-lg $es-radius-lg;\n}\n\n.popover-info {\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n}\n\n.popover-load-more {\n @include button-reset;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n color: $es-primary;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-primary-light;\n }\n}\n\n// Popover arrow\n.popover-arrow {\n position: absolute;\n width: 12px;\n height: 12px;\n background: $es-white;\n border: 1px solid $es-border-color;\n transform: rotate(45deg);\n\n &.arrow-top {\n top: -7px;\n left: 50%;\n margin-left: -6px;\n border-right: none;\n border-bottom: none;\n }\n\n &.arrow-bottom {\n bottom: -7px;\n left: 50%;\n margin-left: -6px;\n border-left: none;\n border-top: none;\n }\n}\n\n// ==========================================================================\n// Holiday Preview Modal\n// ==========================================================================\n\n#mpr-holiday-preview-modal {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: $es-z-modal;\n\n &.show {\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .mpr-modal-backdrop {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n cursor: pointer;\n }\n\n .mpr-modal-dialog {\n position: relative;\n width: 90%;\n max-width: 480px;\n max-height: 80vh;\n background: $es-white;\n border-radius: $es-radius-lg;\n box-shadow: $es-shadow-xl;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .mpr-modal-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: $es-spacing-md;\n padding: $es-spacing-md $es-spacing-lg;\n background: $es-bg-header;\n border-bottom: 1px solid $es-border-color;\n flex-shrink: 0;\n }\n\n .mpr-modal-title {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n font-size: $es-font-size-base;\n font-weight: $es-font-weight-semibold;\n color: $es-text-primary;\n margin: 0;\n\n i.material-icons {\n font-size: 20px !important;\n color: $es-primary;\n }\n }\n\n .mpr-modal-close {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n color: $es-text-muted;\n border-radius: $es-radius-md;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-slate-200;\n color: $es-text-secondary;\n }\n\n i {\n font-size: 18px;\n }\n }\n\n .mpr-modal-body {\n flex: 1;\n overflow-y: auto;\n padding: $es-spacing-lg;\n @include custom-scrollbar;\n }\n\n // Loading state\n .holiday-preview-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-xl 0;\n color: $es-text-muted;\n font-size: $es-font-size-sm;\n\n i {\n font-size: $es-font-size-lg;\n }\n }\n\n // Empty state\n .holiday-preview-empty {\n text-align: center;\n padding: $es-spacing-xl 0;\n color: $es-text-muted;\n\n i.material-icons {\n font-size: 48px !important;\n opacity: 0.5;\n margin-bottom: $es-spacing-md;\n }\n\n p {\n margin: 0 0 $es-spacing-xs;\n }\n\n .hint {\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n }\n }\n\n // Holiday list\n .holiday-list {\n display: flex;\n flex-direction: column;\n gap: $es-spacing-sm;\n }\n\n .holiday-item {\n display: flex;\n align-items: flex-start;\n gap: $es-spacing-md;\n padding: $es-spacing-sm $es-spacing-md;\n background: $es-slate-50;\n border-radius: $es-radius-md;\n border-left: 3px solid $es-success;\n\n &.holiday-type-bank {\n border-left-color: $es-info;\n }\n\n &.holiday-type-observance {\n border-left-color: $es-warning;\n }\n\n &.holiday-type-regional {\n border-left-color: #8b5cf6;\n }\n }\n\n .holiday-date {\n flex-shrink: 0;\n min-width: 100px;\n\n .holiday-day {\n display: block;\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-semibold;\n color: $es-text-primary;\n }\n\n .holiday-weekday {\n display: block;\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n }\n }\n\n .holiday-info {\n flex: 1;\n min-width: 0;\n }\n\n .holiday-name {\n display: block;\n font-size: $es-font-size-sm;\n color: $es-text-primary;\n word-wrap: break-word;\n }\n\n .holiday-type-badge {\n display: inline-block;\n margin-top: $es-spacing-xs;\n padding: 0.125rem 0.375rem;\n font-size: 10px;\n font-weight: $es-font-weight-medium;\n text-transform: capitalize;\n background: $es-slate-200;\n color: $es-text-secondary;\n border-radius: $es-radius-sm;\n }\n\n .holiday-preview-note {\n margin-top: $es-spacing-md;\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n text-align: center;\n }\n}\n","/**\n * List Preview Component\n * Popover and modal views for entity preview\n *\n * Uses shared entity-item base for item styling.\n * This file only contains popover/modal container styles.\n */\n\n@use '../variables' as *;\n@use '../mixins' as *;\n\n// =============================================================================\n// Preview Popover Container\n// =============================================================================\n\n.target-preview-popover,\n.target-list-preview-popover {\n position: absolute;\n z-index: 10000;\n min-width: 320px;\n max-width: 480px;\n background: $es-white;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-lg;\n box-shadow: $es-shadow-lg;\n overflow: hidden;\n\n // Arrow pointing to badge\n &::before {\n content: '';\n position: absolute;\n top: -8px;\n left: 50%;\n transform: translateX(-50%);\n border-left: 8px solid transparent;\n border-right: 8px solid transparent;\n border-bottom: 8px solid $es-border-color;\n }\n\n &::after {\n content: '';\n position: absolute;\n top: -6px;\n left: 50%;\n transform: translateX(-50%);\n border-left: 6px solid transparent;\n border-right: 6px solid transparent;\n border-bottom: 6px solid $es-white;\n }\n\n // Positioned to the right - arrow on left\n &.position-right {\n &::before,\n &::after {\n left: 20px;\n transform: none;\n }\n }\n\n // Positioned to the left - arrow on right\n &.position-left {\n &::before,\n &::after {\n left: auto;\n right: 20px;\n transform: none;\n }\n }\n}\n\n// =============================================================================\n// Preview Header\n// =============================================================================\n\n.preview-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: $es-spacing-sm $es-spacing-md;\n background: $es-bg-header;\n border-bottom: 1px solid $es-border-color;\n\n .preview-title {\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-semibold;\n color: $es-text-primary;\n }\n\n .preview-close {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n color: $es-text-muted;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-slate-200;\n color: $es-text-primary;\n }\n }\n}\n\n// =============================================================================\n// Preview Tabs (entity type switcher)\n// =============================================================================\n\n.preview-tabs {\n display: flex;\n flex-wrap: wrap;\n gap: 0;\n padding: 0;\n background: $es-slate-50;\n border-bottom: 1px solid $es-border-color;\n}\n\n.preview-tab {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.5rem 0.75rem;\n background: transparent;\n border: 0;\n border-bottom: 2px solid transparent;\n margin-bottom: -1px;\n color: $es-text-muted;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n cursor: pointer;\n transition: all $es-transition-fast;\n white-space: nowrap;\n\n &:hover {\n background: $es-slate-100;\n color: $es-text-secondary;\n }\n\n &.active {\n background: $es-white;\n border-bottom-color: $es-primary;\n color: $es-primary;\n }\n\n i {\n font-size: 12px;\n }\n}\n\n// =============================================================================\n// Preview Filter\n// =============================================================================\n\n.preview-filter {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-sm $es-spacing-md;\n background: $es-white;\n border-bottom: 1px solid $es-border-color;\n\n i {\n color: $es-text-muted;\n font-size: 12px;\n }\n\n .preview-filter-input {\n all: unset;\n flex: 1;\n padding: 0.25rem 0;\n font-size: $es-font-size-xs;\n color: $es-text-primary;\n box-sizing: border-box;\n\n &::placeholder {\n color: $es-text-muted;\n }\n }\n}\n\n// =============================================================================\n// Preview Contents (tabbed content areas)\n// =============================================================================\n\n.preview-contents {\n max-height: 350px;\n overflow: hidden;\n}\n\n.preview-content {\n display: none;\n max-height: 350px;\n overflow-y: auto;\n @include custom-scrollbar;\n\n &.active {\n display: block;\n }\n}\n\n// =============================================================================\n// Preview Items Container\n// =============================================================================\n\n.preview-items {\n display: flex;\n flex-direction: column;\n padding: $es-spacing-xs $es-spacing-sm;\n}\n\n// =============================================================================\n// Preview Item - Uses entity-item patterns\n// Maps legacy classes to shared styling\n// =============================================================================\n\n.preview-item {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-sm;\n background: $es-white;\n border-radius: $es-radius-sm;\n transition: background $es-transition-fast;\n\n &:hover {\n background: $es-bg-hover;\n }\n\n // Clickable items\n &[data-id] {\n cursor: pointer;\n }\n}\n\n// Image - matches chip image sizing for consistency\n.preview-item-image {\n flex-shrink: 0;\n width: 32px;\n height: 32px;\n object-fit: cover;\n border-radius: $es-radius-sm;\n background: $es-slate-100;\n}\n\n// No-image placeholder\n.preview-item-no-image {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 32px;\n height: 32px;\n background: $es-slate-100;\n color: $es-text-muted;\n border-radius: $es-radius-sm;\n font-size: $es-font-size-sm;\n}\n\n// Info container\n.preview-item-info {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 0.125rem;\n}\n\n// Name\n.preview-item-name {\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-medium;\n color: $es-text-primary;\n @include text-truncate;\n}\n\n// Meta/ref (category, email, etc.)\n.preview-item-ref,\n.preview-item-meta {\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n @include text-truncate;\n}\n\n// Price badge\n.preview-item-price {\n flex-shrink: 0;\n padding: 0.25rem 0.5rem;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-semibold;\n color: $es-primary;\n background: $es-primary-light;\n border-radius: $es-radius-sm;\n}\n\n// =============================================================================\n// Preview Footer (load more)\n// =============================================================================\n\n.preview-footer {\n padding: $es-spacing-sm $es-spacing-md;\n background: $es-slate-50;\n border-top: 1px solid $es-border-color;\n}\n\n.load-more-controls {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: $es-spacing-sm;\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n\n .load-more-label {\n white-space: nowrap;\n }\n\n .load-more-select {\n appearance: none;\n padding: 0.25rem 1.75rem 0.25rem 0.5rem;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-sm;\n 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;\n background-size: 8px;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n color: $es-primary;\n cursor: pointer;\n transition: all $es-transition-fast;\n height: auto;\n min-height: 0;\n line-height: 1.3;\n\n &:hover {\n border-color: $es-primary;\n background-color: $es-primary-light;\n }\n\n &:focus {\n outline: none;\n border-color: $es-primary;\n box-shadow: 0 0 0 2px rgba($es-primary, 0.1);\n }\n }\n\n .load-more-of {\n white-space: nowrap;\n }\n\n .remaining-count {\n font-weight: $es-font-weight-semibold;\n color: $es-text-secondary;\n }\n\n .btn-load-more {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: $es-spacing-xs;\n margin: 0;\n border: none;\n color: $es-primary;\n background: $es-primary-light;\n border-radius: $es-radius-sm;\n cursor: pointer;\n transition: all $es-transition-fast;\n font: inherit;\n\n i {\n font-size: 14px;\n }\n\n &:hover {\n background: rgba($es-primary, 0.2);\n }\n\n &.loading {\n cursor: wait;\n\n i {\n animation: spin 0.6s linear infinite;\n }\n }\n }\n}\n\n// =============================================================================\n// Preview States\n// =============================================================================\n\n.preview-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-xl;\n text-align: center;\n color: $es-text-muted;\n\n i {\n font-size: 2rem;\n opacity: 0.5;\n }\n\n p {\n margin: 0;\n font-size: $es-font-size-sm;\n }\n}\n\n.preview-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: $es-spacing-xl;\n color: $es-text-muted;\n\n i {\n font-size: 20px;\n color: $es-primary;\n animation: spin 0.6s linear infinite;\n }\n}\n\n// =============================================================================\n// Total Summary Popover (header total badge click)\n// =============================================================================\n\n.total-preview-popover {\n min-width: 240px;\n max-width: 320px;\n\n .preview-popover-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: $es-spacing-md;\n padding: $es-spacing-sm $es-spacing-md;\n background: $es-bg-header;\n border-bottom: 1px solid $es-border-color;\n\n .preview-popover-title {\n font-weight: $es-font-weight-semibold;\n color: $es-text-primary;\n font-size: $es-font-size-sm;\n }\n\n .preview-popover-count {\n flex-shrink: 0;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n color: $es-text-muted;\n background: $es-slate-200;\n padding: 0.125rem 0.5rem;\n border-radius: $es-radius-sm;\n }\n }\n\n .preview-popover-body {\n padding: $es-spacing-xs 0;\n }\n\n .total-summary-list {\n list-style: none;\n margin: 0;\n padding: 0;\n }\n\n .total-summary-item {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-sm $es-spacing-md;\n cursor: pointer;\n transition: background-color 0.15s ease;\n\n &:hover {\n background: $es-slate-50;\n }\n\n i {\n width: 18px;\n text-align: center;\n color: $es-text-muted;\n font-size: 14px;\n }\n\n .summary-item-label {\n flex: 1;\n font-size: $es-font-size-sm;\n color: $es-text-primary;\n }\n\n .summary-item-count {\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-semibold;\n color: $es-primary;\n background: rgba($es-primary, 0.1);\n padding: 2px 8px;\n border-radius: $es-radius-sm;\n }\n }\n}\n\n// Make trait-total-count clickable\n.trait-total-count {\n cursor: pointer;\n transition: all 0.15s ease;\n\n &:hover {\n opacity: 0.8;\n }\n\n &.popover-open {\n opacity: 0.9;\n }\n}\n\n// =============================================================================\n// Schedule Dropdown Preview\n// Inline dropdown for schedule details in admin list\n// =============================================================================\n\n.mpr-dropdown-preview {\n display: none;\n position: absolute;\n top: 100%;\n left: 50%;\n transform: translateX(-50%);\n margin-top: 6px;\n z-index: 1000;\n padding: 0.625rem 0.75rem;\n background: $es-white;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-lg;\n box-shadow: $es-shadow-lg;\n font-size: 12px;\n text-align: left;\n text-transform: none;\n font-weight: normal;\n white-space: nowrap; // Allow dropdown to grow as needed\n\n &.is-open {\n display: block;\n }\n}\n\n.mpr-dropdown-preview__item {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.375rem 0;\n color: #666;\n line-height: 1.4;\n\n &:not(:last-child) {\n margin-bottom: 0.25rem;\n padding-bottom: 0.5rem;\n border-bottom: 1px solid rgba($es-border-color, 0.5);\n }\n\n // Icon styles\n > .material-icons,\n > i:first-child {\n flex-shrink: 0;\n width: 16px;\n font-size: 14px !important;\n color: #999;\n text-align: center;\n }\n}\n\n.mpr-dropdown-preview__muted {\n color: #999;\n}\n\n// Schedule inline layout\n.mpr-dropdown-preview__schedule {\n display: inline;\n}\n\n.mpr-dropdown-preview__schedule-row {\n display: inline;\n\n &:not(:last-child)::after {\n content: ',';\n margin-right: 0.5rem;\n }\n}\n\n.mpr-dropdown-preview__day {\n color: #666;\n}\n\n.mpr-dropdown-preview__hours {\n color: $es-primary;\n font-weight: 500;\n margin-left: 0.25rem;\n}\n\n// Badge trigger for preview dropdown/popover\n.mpr-badge--preview {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.25rem;\n position: relative;\n min-width: 20px;\n height: 20px;\n padding: 0 0.5rem;\n font-size: 0.75rem;\n font-weight: 600;\n border-radius: 50rem;\n cursor: pointer;\n text-transform: none;\n\n .material-icons {\n font-size: 12px !important;\n line-height: 1;\n opacity: 0.8;\n }\n}\n\n.mpr-badge--preview-primary {\n background: $es-primary;\n color: $es-white;\n}\n\n.mpr-badge--preview-success {\n background: #d4edda;\n color: #155724;\n}\n\n.mpr-badge--preview-warning {\n background: #fff3cd;\n color: #856404;\n}\n\n.mpr-badge--preview-muted {\n background: $es-slate-200;\n color: $es-text-muted;\n}\n","/**\n * Schedule Conditions Component\n * DateTime picker, weekly timeline, holidays\n */\n\n@use '../variables' as *;\n@use '../mixins' as *;\n\n// Schedule conditions wrapper\n.schedule-conditions-trait {\n background: $es-white;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-lg;\n}\n\n// Schedule header\n.schedule-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: $es-spacing-md;\n padding: 0.875rem $es-spacing-md;\n background: $es-bg-header;\n border-bottom: 1px solid $es-border-color;\n border-radius: $es-radius-lg $es-radius-lg 0 0;\n cursor: pointer;\n user-select: none;\n transition: background-color $es-transition-fast;\n\n &:hover {\n background: $es-bg-hover;\n }\n}\n\n.schedule-title {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-semibold;\n color: $es-text-primary;\n\n i {\n color: $es-text-muted;\n }\n}\n\n// Schedule body\n.schedule-body {\n padding: $es-spacing-md;\n}\n\n// Schedule section\n.schedule-section {\n margin-bottom: $es-spacing-lg;\n\n &:last-child {\n margin-bottom: 0;\n }\n}\n\n.schedule-section-title {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n margin-bottom: $es-spacing-sm;\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-semibold;\n color: $es-text-primary;\n\n i {\n color: $es-text-muted;\n }\n}\n\n.schedule-section-description {\n margin-bottom: $es-spacing-md;\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n}\n\n// DateTime range picker\n.datetime-range {\n display: flex;\n flex-wrap: wrap;\n gap: $es-spacing-md;\n}\n\n.datetime-field {\n flex: 1;\n min-width: 200px;\n}\n\n.datetime-label {\n display: block;\n margin-bottom: 0.25rem;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n color: $es-text-secondary;\n}\n\n.datetime-input {\n @include input-base;\n}\n\n// Weekly schedule\n.weekly-schedule {\n display: flex;\n flex-direction: column;\n gap: $es-spacing-sm;\n}\n\n.day-row {\n display: flex;\n align-items: center;\n gap: $es-spacing-md;\n padding: $es-spacing-sm;\n background: $es-slate-50;\n border-radius: $es-radius-md;\n\n &.disabled {\n opacity: 0.5;\n }\n}\n\n.day-toggle {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n min-width: 100px;\n}\n\n.day-checkbox {\n width: 18px;\n height: 18px;\n cursor: pointer;\n}\n\n.day-name {\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-medium;\n color: $es-text-primary;\n}\n\n// Timeline slider\n.timeline-slider {\n flex: 1;\n position: relative;\n height: 24px;\n background: $es-slate-200;\n border-radius: $es-radius-full;\n cursor: pointer;\n}\n\n.timeline-fill {\n position: absolute;\n top: 0;\n height: 100%;\n background: $es-primary;\n border-radius: $es-radius-full;\n transition: all $es-transition-fast;\n}\n\n.timeline-handle {\n position: absolute;\n top: 50%;\n width: 16px;\n height: 16px;\n background: $es-white;\n border: 2px solid $es-primary;\n border-radius: 50%;\n transform: translate(-50%, -50%);\n cursor: grab;\n box-shadow: $es-shadow-sm;\n transition: box-shadow $es-transition-fast;\n\n &:hover {\n box-shadow: $es-shadow-md;\n }\n\n &:active {\n cursor: grabbing;\n }\n\n &.handle-start {\n z-index: 2;\n }\n\n &.handle-end {\n z-index: 1;\n }\n}\n\n// Time display\n.day-times {\n display: flex;\n align-items: center;\n gap: $es-spacing-xs;\n min-width: 120px;\n font-size: $es-font-size-xs;\n font-family: monospace;\n color: $es-text-secondary;\n}\n\n.time-separator {\n color: $es-text-muted;\n}\n\n// Holiday exclusions\n.holiday-section {\n padding: $es-spacing-md;\n background: $es-slate-50;\n border-radius: $es-radius-md;\n}\n\n.holiday-toggle {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n margin-bottom: $es-spacing-md;\n}\n\n.holiday-checkbox {\n width: 18px;\n height: 18px;\n cursor: pointer;\n}\n\n.holiday-label {\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-medium;\n color: $es-text-primary;\n}\n\n.holiday-countries {\n display: flex;\n flex-wrap: wrap;\n gap: $es-spacing-xs;\n}\n\n.holiday-country-chip {\n @include chip;\n cursor: pointer;\n\n &.selected {\n background: $es-primary-light;\n color: $es-primary;\n }\n}\n\n// Server time display\n.server-time {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-sm $es-spacing-md;\n background: $es-info-light;\n border-radius: $es-radius-md;\n font-size: $es-font-size-xs;\n color: $es-info;\n\n i {\n font-size: $es-font-size-sm;\n }\n\n .time-value {\n font-family: monospace;\n font-weight: $es-font-weight-semibold;\n }\n}\n\n// Schedule summary\n.schedule-summary {\n display: flex;\n flex-direction: column;\n gap: $es-spacing-xs;\n padding: $es-spacing-md;\n background: $es-slate-50;\n border-radius: $es-radius-md;\n font-size: $es-font-size-sm;\n color: $es-text-secondary;\n\n .summary-item {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n\n i {\n color: $es-success;\n font-size: $es-font-size-sm;\n }\n\n &.inactive i {\n color: $es-text-muted;\n }\n }\n}\n\n// Collapsed state\n.schedule-conditions-trait.collapsed {\n .schedule-body {\n display: none;\n }\n\n .schedule-header {\n border-radius: $es-radius-lg;\n }\n}\n\n// Schedule toggle row (form-content layout)\n.schedule-toggle-row {\n display: flex;\n align-items: center;\n background: $es-slate-100;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-lg;\n\n .schedule-toggle-switch {\n padding: $es-spacing-sm $es-spacing-md;\n }\n\n .schedule-toggle-actions {\n padding: $es-spacing-sm $es-spacing-md;\n border-left: 1px solid $es-border-color;\n cursor: pointer;\n transition: background-color $es-transition-fast;\n\n &:hover {\n background: $es-slate-200;\n }\n\n .material-icons {\n color: $es-slate-400;\n font-size: 20px !important;\n }\n }\n}\n\n// Schedule summary badges (read-only indicators in header)\n.schedule-summary-badges {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n margin-left: auto;\n padding: 0 $es-spacing-sm;\n}\n\n.schedule-badge {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n background: $es-slate-200;\n color: $es-slate-600;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n border-radius: $es-radius-full;\n white-space: nowrap;\n\n .material-icons {\n font-size: 14px !important;\n opacity: 0.7;\n }\n}\n\n// Section hint after embedded entity selector - add margin\n.schedule-holidays .section-hint {\n margin-top: $es-spacing-md;\n}\n","/**\n * Tips Box Component\n * Pro tips and help information display\n */\n\n@use '../variables' as *;\n@use '../mixins' as *;\n\n.target-conditions-trait,\n.entity-selector-trait {\n\n // Tips box container\n .target-tips-box {\n margin: $es-spacing-lg $es-spacing-md $es-spacing-md;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-lg;\n overflow: hidden;\n background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);\n }\n\n // Tips header (clickable to expand/collapse)\n .tips-header {\n display: flex;\n align-items: center;\n gap: 0.625rem;\n padding: $es-spacing-md $es-spacing-lg;\n cursor: pointer;\n user-select: none;\n transition: background-color $es-transition-fast;\n\n &:hover {\n background: rgba(0, 0, 0, 0.02);\n }\n\n // Lightbulb icon\n > i:first-child {\n font-size: 1rem;\n color: $es-warning;\n }\n\n // Title text\n > span {\n flex: 1;\n font-size: 13px;\n font-weight: $es-font-weight-semibold;\n color: $es-slate-600;\n }\n }\n\n // Toggle chevron icon\n .tips-toggle {\n font-size: $es-font-size-xs;\n color: $es-slate-400;\n transition: transform 0.2s;\n }\n\n // Expanded state\n .target-tips-box.expanded {\n .tips-toggle {\n transform: rotate(180deg);\n }\n\n .tips-content {\n display: block;\n }\n }\n\n // Tips content (hidden by default)\n .tips-content {\n display: none;\n padding: 0 $es-spacing-lg $es-spacing-lg;\n }\n\n // Tips grid layout\n .tips-grid {\n display: grid;\n gap: $es-spacing-md;\n grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));\n }\n\n // Individual tip item\n .tip-item {\n display: flex;\n gap: $es-spacing-md;\n padding: $es-spacing-md;\n background: $es-white;\n border-radius: $es-radius-md;\n border: 1px solid $es-border-color;\n }\n\n // Tip icon\n .tip-icon {\n flex-shrink: 0;\n width: 2rem;\n height: 2rem;\n display: flex;\n align-items: center;\n justify-content: center;\n background: $es-primary-light;\n border-radius: $es-radius-md;\n color: $es-primary;\n font-size: $es-font-size-sm;\n }\n\n // Tip text content\n .tip-text {\n flex: 1;\n min-width: 0;\n\n strong {\n display: block;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-semibold;\n color: $es-slate-700;\n margin-bottom: 0.25rem;\n }\n\n p {\n font-size: 11px;\n color: $es-text-muted;\n line-height: 1.625;\n margin: 0;\n }\n }\n\n // Tips footer\n .tips-footer {\n margin-top: $es-spacing-md;\n padding: 0.625rem $es-spacing-md;\n background: $es-white;\n border-radius: $es-radius-md;\n border: 1px dashed $es-gray-300;\n font-size: 11px;\n color: $es-text-muted;\n line-height: 1.625;\n\n i {\n color: $es-primary;\n margin-right: 0.25rem;\n }\n }\n}\n","/**\n * Condition Trait Base Styles\n * Shared styling for all condition trait components\n */\n\n@use '../variables' as *;\n@use '../mixins' as *;\n\n// Base condition trait container\n.condition-trait {\n background: $es-white;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-lg;\n margin-bottom: $es-spacing-lg;\n\n &:last-child {\n margin-bottom: 0;\n }\n}\n\n// Collapsed state\n.condition-trait.collapsed {\n .condition-trait-header {\n border-bottom-color: transparent;\n border-radius: $es-radius-lg;\n }\n\n .collapse-icon {\n transform: rotate(180deg);\n }\n}\n\n// =============================================================================\n// Trait Header\n// =============================================================================\n\n.condition-trait-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: $es-spacing-lg;\n flex-wrap: wrap;\n padding: 0.875rem $es-spacing-lg;\n background: $es-slate-50;\n border-bottom: 1px solid $es-border-color;\n border-radius: $es-radius-lg $es-radius-lg 0 0;\n cursor: pointer;\n transition: background-color $es-transition-fast;\n\n &:hover {\n background: $es-slate-100;\n }\n}\n\n.trait-header-left {\n display: flex;\n align-items: center;\n gap: $es-spacing-md;\n min-width: 0;\n flex: 1;\n}\n\n.trait-icon {\n font-size: 1.125rem;\n color: $es-text-muted;\n flex-shrink: 0;\n}\n\n.trait-title-group {\n display: flex;\n flex-direction: column;\n gap: 0.125rem;\n min-width: 0;\n}\n\n.trait-title {\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-semibold;\n color: $es-slate-800;\n white-space: nowrap;\n}\n\n.trait-subtitle {\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n// Schedule summary (shows current config at a glance)\n.trait-summary {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.25rem 0.625rem;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n color: $es-primary;\n background: rgba($es-primary, 0.08);\n border-radius: $es-radius-full;\n white-space: nowrap;\n margin-left: $es-spacing-md;\n flex-shrink: 0;\n max-width: 320px;\n overflow: hidden;\n text-overflow: ellipsis;\n\n &:empty {\n display: none;\n }\n}\n\n.trait-header-right {\n display: flex;\n align-items: center;\n gap: $es-spacing-md;\n flex-shrink: 0;\n margin-left: auto;\n}\n\n.trait-header-actions {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n}\n\n// Collapse icon\n.collapse-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n font-size: $es-font-size-sm;\n color: $es-text-muted;\n cursor: pointer;\n transition: all 0.2s;\n border-radius: $es-radius-sm;\n background: transparent;\n\n &:hover {\n color: $es-primary;\n background: rgba($es-primary, 0.08);\n }\n}\n\n// Show all toggle\n.trait-show-all-toggle {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n font-size: $es-font-size-xs;\n color: $es-primary;\n cursor: pointer;\n\n &:hover {\n text-decoration: underline;\n }\n}\n\n// Trait total count badge (global fallback)\n.trait-total-count {\n @include count-badge($es-primary);\n}\n\n// Required indicator\n.trait-required {\n color: $es-danger;\n font-size: $es-font-size-xs;\n}\n\n// Validation error\n.trait-validation-error {\n color: $es-danger;\n font-size: $es-font-size-xs;\n margin-top: 0.25rem;\n}\n\n// Trait toggle button\n.trait-toggle {\n @include button-reset;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.375rem 0.75rem;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n color: $es-text-secondary;\n background: $es-white;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-md;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-slate-50;\n border-color: $es-gray-300;\n }\n\n &.active {\n color: $es-primary;\n border-color: $es-primary;\n background: $es-primary-light;\n }\n}\n\n// =============================================================================\n// Trait Body\n// =============================================================================\n\n.condition-trait-body {\n padding: $es-spacing-lg;\n border-radius: 0 0 $es-radius-lg $es-radius-lg;\n background: $es-white;\n animation: slideDown 0.2s ease-out;\n}\n\n// Condition trait collapsed - hide body\n.condition-trait.collapsed .condition-trait-body {\n display: none;\n}\n\n// =============================================================================\n// Section Styles\n// =============================================================================\n\n.schedule-section,\n.context-section {\n margin-bottom: 1.25rem;\n padding-bottom: 1.25rem;\n border-bottom: 1px solid $es-slate-100;\n\n &:last-child {\n margin-bottom: 0;\n padding-bottom: 0;\n border-bottom: 0;\n }\n}\n\n.section-label {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-size: 13px;\n font-weight: $es-font-weight-semibold;\n color: $es-slate-600;\n margin-bottom: $es-spacing-md;\n\n i {\n font-size: $es-font-size-sm;\n color: $es-slate-400;\n margin-right: 0.25rem;\n }\n}\n\n.section-content {\n // Container for section content\n}\n\n.section-hint {\n margin-top: 0.5rem;\n font-size: 11px;\n color: $es-slate-400;\n}\n\n// =============================================================================\n// Full-width Form Group Override\n// =============================================================================\n\n.form-group.condition-trait-fullwidth {\n display: block !important;\n\n > .control-label {\n display: none !important;\n }\n\n > .col-lg-8,\n > .col-lg-8.col-lg-offset-3 {\n width: 100% !important;\n max-width: 100% !important;\n flex: 0 0 100% !important;\n padding-left: $es-spacing-lg !important;\n padding-right: $es-spacing-lg !important;\n margin: 0 !important;\n margin-left: 0 !important;\n }\n}\n\n// Condition traits group label\n.condition-traits-group-label {\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-semibold;\n color: $es-slate-700;\n margin-bottom: $es-spacing-md;\n}\n\n.condition-traits-wrapper {\n display: flex;\n flex-direction: column;\n gap: $es-spacing-md;\n}\n\n// =============================================================================\n// Collapse Header (form-content layout)\n// =============================================================================\n\n.entity-selector-collapse-header {\n padding: 0;\n margin-bottom: $es-spacing-sm;\n\n .btn-collapse-toggle {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0;\n background: none;\n border: none;\n color: $es-primary;\n font-size: $es-font-size-sm;\n cursor: pointer;\n transition: color $es-transition-fast;\n\n &:hover {\n color: $es-primary-hover;\n }\n\n .collapse-icon {\n font-size: 1.25rem;\n transition: transform 0.2s;\n }\n\n .collapse-label {\n font-weight: $es-font-weight-medium;\n }\n }\n}\n\n// When collapsed, rotate icon\n.condition-trait.collapsed .entity-selector-collapse-header {\n .collapse-icon {\n // Icon already shows expand_more when collapsed\n }\n}\n\n// =============================================================================\n// Animations\n// =============================================================================\n\n@keyframes slideDown {\n from {\n opacity: 0;\n transform: translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n","/**\n * Combination Attributes Picker Component\n * Product attribute combination selection styles\n */\n\n@use \"sass:color\";\n@use '../variables' as *;\n@use '../mixins' as *;\n\n.target-conditions-trait,\n.entity-selector-trait {\n\n // Main container\n .combination-attributes-picker {\n display: flex;\n flex-direction: column;\n gap: 0.625rem;\n }\n\n // Mode toggle (Any/All)\n .combination-mode-toggle {\n display: inline-flex;\n gap: 0.25rem;\n padding: 0.125rem;\n background: $es-slate-100;\n border-radius: $es-radius-md;\n margin-bottom: 0.5rem;\n }\n\n .combination-mode-option {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n cursor: pointer;\n font-size: 11px;\n color: $es-text-muted;\n padding: 0.25rem 0.625rem;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n input[type=\"radio\"] {\n display: none;\n }\n\n .mode-label {\n user-select: none;\n }\n\n &:hover {\n color: $es-primary;\n background: rgba($es-primary, 0.1);\n }\n\n &:has(input[type=\"radio\"]:checked) {\n background: $es-primary;\n color: $es-white;\n font-weight: $es-font-weight-medium;\n }\n }\n\n // Groups container\n .combination-groups-container {\n display: flex;\n flex-wrap: wrap;\n gap: $es-spacing-md;\n }\n\n // Loading/Empty/Error states\n .combination-loading,\n .combination-empty,\n .combination-error {\n color: $es-text-muted;\n font-style: italic;\n padding: 0.5rem;\n }\n\n .combination-error {\n color: $es-danger;\n }\n\n // Section header\n .combinations-section {\n margin-bottom: $es-spacing-md;\n }\n\n .combinations-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: $es-spacing-sm;\n }\n\n .combinations-label {\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n color: $es-text-muted;\n }\n\n .combinations-help {\n font-size: 11px;\n color: $es-slate-400;\n }\n\n // Toggle combinations button\n .btn-toggle-combinations {\n @include button-reset;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n font-size: $es-font-size-xs;\n color: $es-primary;\n background: transparent;\n border: 1px solid $es-primary;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-primary-light;\n }\n }\n\n .btn-remove-combinations {\n @include button-reset;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n font-size: $es-font-size-xs;\n color: $es-danger;\n background: transparent;\n\n &:hover {\n text-decoration: underline;\n }\n }\n\n // =============================================================================\n // Attribute Group\n // =============================================================================\n\n .comb-attr-group {\n flex: none;\n min-width: 120px;\n max-width: 200px;\n background: $es-white;\n border: 1px solid $es-gray-300;\n border-radius: $es-radius-sm;\n overflow: hidden;\n\n &.has-selections {\n border-color: $es-primary;\n }\n }\n\n .comb-attr-group-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 0.375rem 0.625rem;\n background: $es-slate-100;\n border-bottom: 1px solid $es-gray-300;\n font-weight: $es-font-weight-semibold;\n font-size: $es-font-size-xs;\n color: $es-slate-800;\n\n .comb-attr-group.has-selections & {\n background: $es-cyan-50;\n border-bottom-color: $es-cyan-200;\n }\n }\n\n .comb-attr-group-name {\n flex: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .comb-attr-group-count {\n flex-shrink: 0;\n min-width: 18px;\n height: 18px;\n padding: 0 0.25rem;\n background: $es-gray-300;\n border-radius: $es-radius-full;\n font-size: 11px;\n font-weight: $es-font-weight-semibold;\n line-height: 18px;\n text-align: center;\n color: $es-text-muted;\n\n .comb-attr-group.has-selections & {\n background: $es-primary;\n color: $es-white;\n }\n }\n\n // Toolbar\n .comb-attr-toolbar {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.375rem;\n background: $es-slate-50;\n border-bottom: 1px solid $es-slate-100;\n }\n\n .comb-toolbar-btn {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 22px;\n height: 22px;\n padding: 0;\n background: $es-white;\n border: 1px solid $es-gray-300;\n border-radius: $es-radius-sm;\n color: $es-text-muted;\n cursor: pointer;\n font-size: $es-font-size-xs;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-slate-100;\n border-color: $es-slate-400;\n color: $es-slate-800;\n }\n }\n\n .comb-attr-search {\n flex: 1;\n min-width: 60px;\n padding: 0.125rem 0.375rem;\n border: 1px solid $es-gray-300;\n border-radius: $es-radius-sm;\n font-size: 11px;\n outline: none;\n\n &:focus {\n border-color: $es-primary;\n }\n\n &::placeholder {\n color: $es-slate-400;\n }\n }\n\n // Values container\n .comb-attr-values {\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n padding: 0.375rem;\n max-height: 150px;\n overflow-y: auto;\n @include custom-scrollbar;\n }\n\n .comb-attr-loading,\n .comb-attr-empty,\n .comb-attr-error {\n width: 100%;\n text-align: center;\n color: $es-slate-400;\n font-size: 11px;\n padding: 0.25rem;\n }\n\n .comb-attr-error {\n color: $es-danger;\n }\n\n // Individual value\n .comb-attr-value {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.125rem 0.5rem;\n background: $es-white;\n border: 1px solid $es-slate-400;\n border-radius: 0.75rem;\n font-size: 11px;\n color: $es-slate-600;\n cursor: pointer;\n transition: all $es-transition-fast;\n white-space: nowrap;\n\n &:hover {\n background: $es-slate-100;\n border-color: $es-text-muted;\n }\n\n &.selected {\n background: $es-primary;\n border-color: $es-primary-hover;\n color: $es-white;\n\n &:hover {\n background: $es-primary-hover;\n border-color: color.adjust($es-primary-hover, $lightness: -5%);\n }\n }\n }\n\n .comb-attr-value-count {\n font-size: 9px;\n color: $es-slate-400;\n background: $es-slate-100;\n padding: 1px 0.25rem;\n border-radius: 0.5rem;\n min-width: 14px;\n text-align: center;\n\n .comb-attr-value.selected & {\n color: $es-white;\n background: rgba(255, 255, 255, 0.3);\n }\n }\n\n // =============================================================================\n // Combination Conditions (Row-based)\n // =============================================================================\n\n .combination-conditions-container {\n display: flex;\n flex-direction: column;\n gap: $es-spacing-sm;\n }\n\n .combination-condition-row {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-sm;\n background: $es-slate-50;\n border-radius: $es-radius-sm;\n }\n\n .combination-group-select,\n .combination-values-select {\n flex: 1;\n min-width: 120px;\n }\n\n .combination-equals {\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n padding: 0 0.25rem;\n }\n\n .btn-add-combination-condition {\n @include button-reset;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.375rem 0.75rem;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n color: $es-primary;\n background: transparent;\n border: 1px dashed $es-primary;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-primary-light;\n }\n\n i {\n font-size: 10px;\n }\n }\n\n .btn-remove-combination-row {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n color: $es-text-muted;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n &:hover {\n background: rgba($es-danger, 0.1);\n color: $es-danger;\n }\n\n i {\n font-size: 12px;\n }\n }\n}\n","/**\n * Method Dropdown Component\n * Custom select dropdown with icons for method selection\n */\n\n@use '../variables' as *;\n@use '../mixins' as *;\n\n.target-conditions-trait,\n.entity-selector-trait {\n\n // Method dropdown trigger button\n .method-dropdown-trigger {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n height: 36px;\n padding: 0 $es-spacing-md;\n border-radius: $es-radius-md;\n background: $es-white;\n color: $es-slate-800;\n font-size: $es-font-size-sm;\n cursor: pointer;\n transition: all $es-transition-fast;\n min-width: 180px;\n max-width: 320px;\n border: 1px solid $es-border-color;\n\n &:hover {\n background: $es-slate-50;\n border-color: $es-gray-300;\n }\n\n &:focus,\n &:active {\n outline: none;\n border-color: $es-primary;\n box-shadow: 0 0 0 3px rgba($es-primary, 0.1);\n }\n }\n\n .method-trigger-icon {\n font-size: $es-font-size-sm;\n color: $es-text-muted;\n flex-shrink: 0;\n width: 18px;\n text-align: center;\n }\n\n .method-trigger-label {\n flex: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n font-weight: $es-font-weight-medium;\n }\n\n .method-trigger-caret {\n font-size: $es-font-size-xs;\n color: $es-slate-400;\n flex-shrink: 0;\n margin-left: auto;\n }\n\n // Locked state\n .selector-locked .method-dropdown-trigger {\n background: $es-slate-100;\n color: $es-slate-400;\n cursor: not-allowed;\n border-color: $es-border-color;\n\n &:hover {\n background: $es-slate-100;\n border-color: $es-border-color;\n }\n }\n\n // Method selector wrapper\n .method-selector-wrapper {\n position: relative;\n }\n\n // Hidden select (for form submission)\n .method-select-hidden {\n position: absolute !important;\n opacity: 0 !important;\n pointer-events: none !important;\n width: 0 !important;\n height: 0 !important;\n overflow: hidden !important;\n }\n}\n\n// Global fallback for hidden method selects\n.method-select-hidden {\n position: absolute !important;\n opacity: 0 !important;\n pointer-events: none !important;\n width: 0 !important;\n height: 0 !important;\n overflow: hidden !important;\n}\n\n// =============================================================================\n// Method Dropdown Menu (appended to body, outside trait wrappers)\n// =============================================================================\n\n.method-dropdown-menu {\n position: absolute;\n z-index: $es-z-dropdown + 1;\n min-width: 200px;\n max-width: 360px;\n max-height: 400px;\n overflow-y: auto;\n background: $es-white;\n border-radius: $es-radius-lg;\n padding: 0.375rem 0;\n border: 1px solid $es-border-color;\n box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15);\n animation: methodDropdownFadeIn 0.15s ease;\n @include custom-scrollbar;\n}\n\n@keyframes methodDropdownFadeIn {\n from {\n opacity: 0;\n transform: translateY(-4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n// Method dropdown item\n.method-dropdown-item {\n display: flex;\n align-items: center;\n gap: 0.625rem;\n padding: 0.5rem $es-spacing-md;\n cursor: pointer;\n transition: background-color 0.1s;\n position: relative;\n\n &:hover {\n background: $es-slate-100;\n }\n\n &.selected {\n background: rgba($es-primary, 0.08);\n }\n\n .method-item-icon {\n font-size: $es-font-size-sm;\n color: $es-text-muted;\n width: 18px;\n text-align: center;\n flex-shrink: 0;\n }\n\n &.selected .method-item-icon {\n color: $es-primary;\n }\n\n .method-item-label {\n flex: 1;\n font-size: $es-font-size-sm;\n color: $es-slate-700;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n &.selected .method-item-label {\n color: $es-cyan-700;\n font-weight: $es-font-weight-medium;\n }\n\n .method-item-check {\n font-size: $es-font-size-xs;\n flex-shrink: 0;\n margin-left: auto;\n color: $es-primary;\n }\n}\n\n// Method dropdown optgroup\n.method-dropdown-optgroup {\n margin-top: 0.25rem;\n\n &:first-child {\n margin-top: 0;\n }\n}\n\n.method-optgroup-label {\n padding: 0.5rem $es-spacing-md;\n font-size: 11px;\n font-weight: $es-font-weight-semibold;\n color: $es-text-muted;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n background: $es-slate-50;\n border-top: 1px solid $es-slate-100;\n border-bottom: 1px solid $es-slate-100;\n\n .method-dropdown-optgroup:first-child & {\n border-top: 0;\n }\n}\n\n.method-optgroup-items {\n padding: 0.25rem 0;\n\n .method-dropdown-item {\n padding-left: $es-spacing-lg;\n }\n}\n\n// Method info placeholder\n.method-info-placeholder {\n font-size: $es-font-size-xs;\n color: $es-text-muted;\n font-style: italic;\n}\n","/**\n * Tooltip Component\n * Info tooltips for method help\n */\n\n@use '../variables' as *;\n\n// =============================================================================\n// Info Wrapper (tooltip trigger)\n// =============================================================================\n\n.mpr-info-wrapper {\n display: inline-flex;\n align-items: center;\n position: relative;\n cursor: help;\n vertical-align: middle;\n margin-left: 0.25rem;\n\n .material-icons {\n font-size: 16px !important;\n color: $es-text-muted;\n transition: color 0.15s ease;\n }\n\n &:hover .material-icons {\n color: $es-primary;\n }\n}\n\n// =============================================================================\n// Fixed Tooltip (appended to body on hover)\n// =============================================================================\n\n.mpr-tooltip-fixed {\n position: fixed;\n background: $es-white;\n color: $es-slate-800;\n padding: $es-spacing-md $es-spacing-lg;\n border-radius: $es-radius-md;\n font-size: 13px;\n line-height: 1.5;\n white-space: normal;\n z-index: 10500;\n max-width: 320px;\n min-width: 180px;\n text-align: left;\n box-shadow: rgba(0, 0, 0, 0.12) 0px 1px 1px 0px,\n rgba(64, 68, 82, 0.16) 0px 0px 0px 1px,\n rgba(64, 68, 82, 0.08) 0px 2px 5px 0px;\n pointer-events: none;\n\n // Pinned tooltip allows interaction\n &.pinned {\n pointer-events: auto;\n padding-right: $es-spacing-xl + 1rem;\n }\n\n strong {\n display: block;\n margin-bottom: 0.375rem;\n font-weight: $es-font-weight-semibold;\n color: $es-primary;\n }\n\n p {\n margin: 0;\n color: $es-text-secondary;\n }\n\n ul {\n margin: 0.5rem 0 0;\n padding-left: 1.25rem;\n\n li {\n margin: 0.25rem 0;\n color: $es-text-secondary;\n }\n }\n}\n\n// Close button for pinned tooltips\n.mpr-tooltip-close {\n position: absolute;\n top: 0.375rem;\n right: 0.375rem;\n padding: 0.125rem;\n border: none;\n background: transparent;\n cursor: pointer;\n border-radius: $es-radius-sm;\n line-height: 1;\n transition: background-color 0.15s ease;\n\n .material-icons {\n font-size: 16px !important;\n color: $es-text-muted;\n }\n\n &:hover {\n background: $es-slate-100;\n\n .material-icons {\n color: $es-slate-700;\n }\n }\n}\n","/**\n * Category Tree Component\n * Hierarchical tree view for category selection inside dropdown\n */\n\n@use \"sass:color\";\n@use '../variables' as *;\n@use '../mixins' as *;\n\n// Category tree container (inside dropdown)\n.category-tree {\n display: flex;\n flex-direction: column;\n}\n\n// Tree toolbar inside dropdown\n.category-tree .tree-toolbar {\n display: flex;\n align-items: center;\n gap: $es-spacing-sm;\n padding: $es-spacing-xs $es-spacing-sm;\n background: $es-slate-50;\n border-bottom: 1px solid $es-border-light;\n flex-shrink: 0;\n\n .btn-expand-all,\n .btn-collapse-all {\n @include button-reset;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: $es-spacing-xs $es-spacing-sm;\n font-size: $es-font-size-xs;\n font-weight: $es-font-weight-medium;\n color: $es-text-secondary;\n background: $es-white;\n border: 1px solid $es-border-color;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-slate-100;\n border-color: $es-slate-300;\n }\n\n i {\n font-size: 12px;\n }\n }\n}\n\n// Tree items container\n.category-tree .tree-items {\n padding: 0;\n}\n\n// Tree item\n.tree-item {\n display: flex;\n align-items: center;\n gap: $es-spacing-xs;\n padding: $es-spacing-xs $es-spacing-sm;\n cursor: pointer;\n transition: background $es-transition-fast;\n border-radius: 0;\n\n &:hover {\n background: $es-slate-100;\n }\n\n &.selected {\n background: $es-primary-light;\n\n .tree-name {\n font-weight: $es-font-weight-semibold;\n color: $es-primary;\n }\n\n .tree-checkbox {\n color: $es-primary;\n\n i {\n opacity: 1;\n }\n }\n }\n\n &.inactive {\n opacity: 0.6;\n\n .tree-name {\n font-style: italic;\n }\n }\n\n &.filtered-out {\n display: none;\n }\n\n &.filter-match {\n background: $es-warning-light;\n\n &.selected {\n background: $es-primary-light;\n }\n }\n}\n\n// All tree element styles nested under .category-tree for specificity\n.category-tree {\n // Tree indentation\n .tree-indent {\n flex-shrink: 0;\n }\n\n // Tree toggle (expand/collapse)\n .tree-toggle {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 12px;\n height: 12px;\n box-sizing: border-box;\n color: $es-text-secondary;\n flex-shrink: 0;\n border-radius: $es-radius-sm;\n transition: all $es-transition-fast;\n cursor: pointer;\n\n &:hover {\n background: $es-slate-200;\n color: $es-text-primary;\n }\n\n &.tree-leaf {\n cursor: default;\n visibility: hidden;\n\n &:hover {\n background: transparent;\n }\n }\n\n i {\n font-size: 10px;\n transition: transform $es-transition-fast;\n }\n }\n\n .tree-item.collapsed > .tree-toggle i {\n transform: rotate(-90deg);\n }\n\n // Tree checkbox indicator - 12x12 to match PrestaShop admin standards\n .tree-checkbox {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 12px;\n height: 12px;\n box-sizing: border-box;\n flex-shrink: 0;\n border: 1px solid $es-border-color;\n border-radius: 2px;\n background: $es-white;\n\n i {\n font-size: 8px;\n opacity: 0;\n color: $es-white;\n transition: opacity $es-transition-fast;\n }\n }\n\n .tree-item.selected .tree-checkbox {\n background: $es-primary;\n border-color: $es-primary;\n\n i {\n opacity: 1;\n }\n }\n\n // Tree icon\n .tree-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 12px;\n height: 12px;\n box-sizing: border-box;\n color: $es-text-muted;\n flex-shrink: 0;\n\n i {\n font-size: 12px; // match visual weight of other icons\n }\n }\n\n .tree-item.selected .tree-icon {\n color: $es-primary;\n }\n\n // Tree name\n .tree-name {\n flex: 1;\n font-size: $es-font-size-sm;\n color: $es-text-primary;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n // Tree product/page count with preview\n .tree-count {\n @include count-badge($es-primary);\n height: 18px;\n min-width: 18px;\n padding: 0 $es-spacing-sm;\n\n i {\n font-size: 10px;\n }\n\n &.clickable {\n &.loading {\n pointer-events: none;\n\n i {\n animation: spin 1s linear infinite;\n }\n }\n\n &.popover-open {\n background: color.adjust($es-primary, $lightness: -10%);\n }\n }\n }\n\n // Select children button - positioned on the left next to toggle\n .btn-select-children {\n @include button-reset;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 12px;\n height: 12px;\n box-sizing: border-box;\n color: $es-text-muted;\n border-radius: $es-radius-sm;\n opacity: 0.3;\n transition: all $es-transition-fast;\n flex-shrink: 0;\n\n i {\n font-size: 14px; // larger to visually match other icons\n }\n\n &:hover {\n color: $es-primary;\n opacity: 1;\n }\n }\n\n .tree-item:hover .btn-select-children {\n opacity: 0.6;\n }\n\n // Tree badge (inactive, etc.)\n .tree-badge {\n display: inline-flex;\n align-items: center;\n padding: 0.125rem $es-spacing-xs;\n font-size: 9px;\n font-weight: $es-font-weight-semibold;\n text-transform: uppercase;\n letter-spacing: 0.025em;\n border-radius: $es-radius-sm;\n flex-shrink: 0;\n\n &.inactive {\n color: $es-warning;\n background: $es-warning-light;\n }\n }\n\n // Tree children container\n .tree-children {\n display: block;\n\n &.filter-expanded {\n display: block !important;\n }\n }\n\n .tree-item.collapsed + .tree-children {\n display: none;\n }\n\n // Filtering - must be inside .category-tree for specificity\n .tree-item.filtered-out {\n display: none !important;\n }\n} // end .category-tree\n\n// Loading/empty/error states\n.category-tree .tree-loading,\n.category-tree .dropdown-empty,\n.category-tree .dropdown-error {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: $es-spacing-xl;\n color: $es-text-muted;\n font-size: $es-font-size-sm;\n\n i {\n margin-right: $es-spacing-sm;\n }\n}\n\n.category-tree .dropdown-error {\n color: $es-danger;\n}\n\n// Tree view mode in dropdown\n.target-search-dropdown.view-tree {\n .dropdown-results {\n padding: 0;\n }\n\n .category-tree {\n max-height: 100%;\n overflow-y: auto;\n @include custom-scrollbar;\n }\n\n .tree-items {\n max-height: calc(100% - 40px);\n overflow-y: auto;\n @include custom-scrollbar;\n }\n}\n","/**\n * Validation Toast Component\n * Error notifications for selection conflicts\n */\n\n@use '../variables' as *;\n@use '../mixins' as *;\n\n// Validation error toast\n.es-validation-toast {\n display: flex;\n align-items: flex-start;\n gap: $es-spacing-sm;\n padding: $es-spacing-md;\n background: $es-white;\n border: 1px solid $es-danger;\n border-left: 4px solid $es-danger;\n border-radius: $es-radius-md;\n box-shadow: $es-shadow-lg;\n max-width: 400px;\n animation: es-toast-slide-in 0.2s ease-out;\n\n .es-toast-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n color: $es-danger;\n flex-shrink: 0;\n\n i {\n font-size: 18px;\n }\n }\n\n .es-toast-content {\n flex: 1;\n min-width: 0;\n }\n\n .es-toast-title {\n font-size: $es-font-size-sm;\n font-weight: $es-font-weight-semibold;\n color: $es-danger;\n margin-bottom: 2px;\n }\n\n .es-toast-message {\n font-size: $es-font-size-xs;\n color: $es-text-secondary;\n line-height: 1.4;\n }\n\n .es-toast-close {\n @include button-reset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 20px;\n height: 20px;\n color: $es-text-muted;\n border-radius: $es-radius-sm;\n flex-shrink: 0;\n transition: all $es-transition-fast;\n\n &:hover {\n background: $es-slate-100;\n color: $es-text-primary;\n }\n\n i {\n font-size: 12px;\n }\n }\n}\n\n@keyframes es-toast-slide-in {\n from {\n opacity: 0;\n transform: translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n"]} \ No newline at end of file diff --git a/assets/assets/css/admin/mpr-modal.css b/assets/assets/css/admin/mpr-modal.css new file mode 100755 index 0000000..acdb4d7 --- /dev/null +++ b/assets/assets/css/admin/mpr-modal.css @@ -0,0 +1,184 @@ +/** + * MPR Search Revolution - Universal Modal Styles + * All admin modals use .mpr-sr-admin-modal class + * Works on both Symfony pages (.show) and Legacy pages (.in) + */ + +.mpr-sr-admin-modal.show, +.mpr-sr-admin-modal.in { + display: flex !important; + align-items: center; + justify-content: center; +} + +.mpr-sr-admin-modal.show .modal-dialog, +.mpr-sr-admin-modal.in .modal-dialog { + transform: none !important; + top: auto !important; + margin: 0 auto !important; +} + +.mpr-sr-admin-modal .modal-dialog { + max-width: 480px; +} + +.mpr-sr-admin-modal .modal-content { + padding: 1.25rem; + border-radius: 8px; + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); +} + +.mpr-sr-admin-modal .modal-header, +.mpr-sr-admin-modal .modal-body, +.mpr-sr-admin-modal .modal-footer { + padding: 0; +} + +.mpr-sr-admin-modal .modal-header { + margin-bottom: 1rem; + display: flex; + align-items: center; + justify-content: space-between; + border: none; +} + +.mpr-sr-admin-modal .modal-header .modal-title { + font-size: 1.125rem; + font-weight: 600; + display: flex; + align-items: center; + gap: 0.5rem; + margin: 0; +} + +.mpr-sr-admin-modal .modal-header .modal-title i { + margin-right: 8px; +} + +.mpr-sr-admin-modal .modal-header .close, +.mpr-sr-admin-modal .modal-header .mpr-close-modal { + display: flex; + align-items: center; + justify-content: center; + margin: 0; + margin-left: auto; + padding: 5px; + background: transparent; + border: none; + cursor: pointer; + transition: opacity 0.2s; + line-height: 1; + opacity: 0.7; +} + +.mpr-sr-admin-modal .modal-header .close:hover, +.mpr-sr-admin-modal .modal-header .mpr-close-modal:hover { + opacity: 1; +} + +.mpr-sr-admin-modal .modal-body { + text-align: center; +} + +.mpr-sr-admin-modal .modal-body .body-title { + font-size: 0.875rem; + color: #6b7280; + margin-bottom: 0.25rem; +} + +.mpr-sr-admin-modal .modal-body .modal-amount { + font-size: 2.5rem; + font-weight: 600; + margin-bottom: 1.25rem; + color: #dc2626; +} + +.mpr-sr-admin-modal .modal-body .tables-table { + margin-bottom: 1rem; + font-size: 0.875rem; + text-align: left; +} + +.mpr-sr-admin-modal .modal-body .tables-table thead th { + background: #f8fafc; + font-weight: 600; + font-size: 0.75rem; + text-transform: uppercase; + letter-spacing: 0.025em; + color: #64748b; + padding: 0.5rem 0.75rem; +} + +.mpr-sr-admin-modal .modal-body .tables-table tbody td { + padding: 0.5rem 0.75rem; + vertical-align: middle; + border-color: #f1f5f9; +} + +.mpr-sr-admin-modal .modal-footer { + display: flex; + padding-top: 1rem; + gap: 0.75rem; + border: none; +} + +.mpr-sr-admin-modal .modal-footer .btn { + flex: 1; + display: flex; + justify-content: center; + align-items: center; + gap: 0.5rem; + padding: 0.625rem 1rem; + font-weight: 500; + border-radius: 6px; + position: relative; + z-index: 1; + cursor: pointer; +} + +.mpr-sr-admin-modal .modal-footer .btn i { + margin-right: 5px; +} + +.mpr-sr-admin-modal .modal-footer .cancel-btn, +.mpr-sr-admin-modal .modal-footer .btn-secondary { + background: #f1f5f9; + border: 1px solid #e2e8f0; + color: #64748b; +} + +.mpr-sr-admin-modal .modal-footer .cancel-btn:hover, +.mpr-sr-admin-modal .modal-footer .btn-secondary:hover { + background: #e2e8f0; + color: #475569; +} + +.mpr-sr-admin-modal .modal-footer .confirm-btn, +.mpr-sr-admin-modal .modal-footer .btn-primary { + border: none; + color: #fff; + background: linear-gradient(135deg, #337ab7 0%, #286090 100%); +} + +.mpr-sr-admin-modal .modal-footer .confirm-btn:hover:not(:disabled), +.mpr-sr-admin-modal .modal-footer .btn-primary:hover:not(:disabled) { + transform: translateY(-1px); + background: linear-gradient(135deg, #286090 0%, #204d74 100%); +} + +.mpr-sr-admin-modal .modal-footer .confirm-btn:disabled, +.mpr-sr-admin-modal .modal-footer .btn-primary:disabled { + opacity: 0.6; + cursor: not-allowed; +} + +.mpr-sr-admin-modal .modal-footer .btn-danger { + background: linear-gradient(135deg, #dc2626 0%, #b91c1c 100%); + border: none; + color: #fff; +} + +.mpr-sr-admin-modal .modal-footer .btn-danger:hover:not(:disabled) { + background: linear-gradient(135deg, #b91c1c 0%, #991b1b 100%); + transform: translateY(-1px); +} diff --git a/assets/assets/js/admin/entity-list-preview.js b/assets/assets/js/admin/entity-list-preview.js new file mode 100755 index 0000000..b6dd149 --- /dev/null +++ b/assets/assets/js/admin/entity-list-preview.js @@ -0,0 +1,1149 @@ +/** + * Target Conditions List Preview + * + * Handles showing item previews in admin list views when clicking on target count badges. + * Uses the TargetConditions trait's AJAX endpoint to load preview data. + * + * Note: Uses native event capturing to intercept clicks before PrestaShop's + * inline onclick handlers on parent td elements can navigate away. + */ + +(function($) { + 'use strict'; + + var TargetListPreview = { + $popover: null, + $backdrop: null, + currentTrigger: null, + currentConditions: null, + ajaxUrl: '', + trans: {}, + currentEntityType: null, + filterQuery: '', + filterTimeout: null, + loadedData: {}, + itemsPerPage: 20, + + init: function(config) { + this.ajaxUrl = config.ajaxUrl || ''; + this.trans = config.trans || {}; + this.createPopover(); + this.bindEvents(); + this.loadBadgeCounts(); + }, + + loadBadgeCounts: function() { + var self = this; + var $triggers = $('.target-preview-trigger'); + + if ($triggers.length === 0) { + return; + } + + $triggers.each(function() { + var $trigger = $(this); + var conditions = $trigger.data('conditions'); + + if (!conditions) { + return; + } + + if (typeof conditions === 'string') { + try { + conditions = JSON.parse(conditions); + } catch (e) { + return; + } + } + + // Check for summary badge (more than 3 entity types) + var $summaryBadge = $trigger.find('.badge[data-entity-type="summary"]'); + if ($summaryBadge.length > 0) { + self.fetchSummaryCount($trigger, conditions, $summaryBadge); + return; + } + + // Find entity types with groups + for (var entityType in conditions) { + if (conditions[entityType] && conditions[entityType].groups && conditions[entityType].groups.length > 0) { + self.fetchEntityCount($trigger, entityType, conditions[entityType]); + } + } + }); + }, + + fetchSummaryCount: function($trigger, conditions, $badge) { + var self = this; + var entityTypes = ($badge.data('entity-types') || '').split(',').filter(function(t) { return t; }); + var pendingCount = entityTypes.length; + var totalSum = 0; + var hasAll = $badge.data('has-all') === 1 || $badge.data('has-all') === '1'; + + if (pendingCount === 0) { + return; + } + + entityTypes.forEach(function(entityType) { + var conditionsData = conditions[entityType]; + if (!conditionsData || !conditionsData.groups || conditionsData.groups.length === 0) { + pendingCount--; + if (pendingCount === 0) { + self.updateSummaryBadge($badge, totalSum, hasAll); + } + return; + } + + $.ajax({ + url: self.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'previewTargetConditions', + trait: 'TargetConditions', + block_type: entityType, + conditions: JSON.stringify(conditionsData), + limit: 0 + } + }).done(function(response) { + if (response.success && typeof response.total !== 'undefined') { + totalSum += response.total; + } + }).always(function() { + pendingCount--; + if (pendingCount === 0) { + self.updateSummaryBadge($badge, totalSum, hasAll); + } + }); + }); + }, + + updateSummaryBadge: function($badge, total, hasAll) { + var displayText; + if (hasAll) { + displayText = (this.trans.multiple || 'Multiple') + ' (' + total + ')'; + } else { + displayText = total + ' ' + (this.trans.items || 'items'); + } + + $badge.empty() + .append($('', { class: 'icon-th-list' })) + .append(' ' + displayText); + + $badge.attr('title', displayText); + + if (total === 0) { + $badge.removeClass('badge-info badge-success badge-warning').addClass('badge-danger'); + } + }, + + fetchEntityCount: function($trigger, entityType, conditionsData) { + var self = this; + + // Skip AJAX if no badge exists for this entity type + var $badge = $trigger.find('.badge[data-entity-type="' + entityType + '"]'); + if ($badge.length === 0) { + return; + } + + $.ajax({ + url: this.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'previewTargetConditions', + trait: 'TargetConditions', + block_type: entityType, + conditions: JSON.stringify(conditionsData), + limit: 0 + } + }).done(function(response) { + if (response.success && typeof response.total !== 'undefined') { + self.updateBadgeCount($trigger, entityType, response.total); + } + }); + }, + + updateBadgeCount: function($trigger, entityType, total) { + // Find badge for this specific entity type only - no fallback + var $badge = $trigger.find('.badge[data-entity-type="' + entityType + '"]'); + if ($badge.length === 0) { + return; + } + + var hasAll = $badge.data('has-all') === 1 || $badge.data('has-all') === '1'; + var excludes = parseInt($badge.data('excludes') || 0, 10); + + // Entity icon mapping + var iconMap = { + 'products': 'icon-cube', + 'categories': 'icon-folder-open', + 'manufacturers': 'icon-building', + 'suppliers': 'icon-truck', + 'cms': 'icon-file-text', + 'cms_categories': 'icon-folder' + }; + + // Get entity icon (first that's not the spinner) + var $existingIcon = $badge.find('i').not('.icon-spinner').first(); + var iconClass = $existingIcon.length ? $existingIcon.attr('class') : (iconMap[entityType] || 'icon-list'); + var $icon = $('', { class: iconClass }); + + // Build display text + var displayText; + var entityLabels = this.trans || {}; + var singular = entityLabels[entityType + '_singular'] || entityType.replace(/_/g, ' ').replace(/s$/, ''); + var plural = entityLabels[entityType + '_plural'] || entityType.replace(/_/g, ' '); + + if (hasAll) { + // "All products (49)" or "All products" + var allLabel = entityLabels[entityType + '_all'] || ('All ' + plural); + displayText = allLabel + ' (' + total + ')'; + } else { + // "5 products" + displayText = total + ' ' + (total === 1 ? singular : plural); + } + + // Update badge content + $badge.empty().append($icon).append(' ' + displayText); + + // Update tooltip + var tooltip = displayText; + if (excludes > 0) { + tooltip += ' (with ' + excludes + ' exclusion' + (excludes === 1 ? '' : 's') + ')'; + } + $badge.attr('title', tooltip); + + // Update color based on count + if (total === 0) { + $badge.removeClass('badge-info badge-success badge-warning').addClass('badge-danger'); + } + }, + + createPopover: function() { + this.$popover = $('
', { + class: 'target-list-preview-popover', + css: { display: 'none' } + }).appendTo('body'); + + this.$backdrop = $('
', { + class: 'target-list-preview-backdrop', + css: { display: 'none' } + }).appendTo('body'); + + this.initDragAndResize(); + }, + + setPopoverContent: function(html) { + this.$popover.html(html + '
'); + }, + + initDragAndResize: function() { + var self = this; + var isDragging = false; + var isResizing = false; + var startX, startY, startLeft, startTop, startWidth, startHeight; + + // Drag by header + this.$popover.on('mousedown', '.preview-header', function(e) { + if ($(e.target).closest('.preview-close').length) return; + + isDragging = true; + startX = e.clientX; + startY = e.clientY; + startLeft = parseInt(self.$popover.css('left'), 10) || 0; + startTop = parseInt(self.$popover.css('top'), 10) || 0; + + self.$popover.addClass('dragging'); + e.preventDefault(); + }); + + // Resize by handle + this.$popover.on('mousedown', '.popover-resize-handle', function(e) { + isResizing = true; + startX = e.clientX; + startY = e.clientY; + startWidth = self.$popover.outerWidth(); + startHeight = self.$popover.outerHeight(); + + self.$popover.addClass('resizing'); + e.preventDefault(); + e.stopPropagation(); + }); + + $(document).on('mousemove', function(e) { + if (isDragging) { + var dx = e.clientX - startX; + var dy = e.clientY - startY; + var newLeft = startLeft + dx; + var newTop = startTop + dy; + + // Keep within viewport + var maxLeft = $(window).width() - self.$popover.outerWidth() - 10; + var maxTop = $(window).height() - 50; + newLeft = Math.max(10, Math.min(newLeft, maxLeft)); + newTop = Math.max(10, Math.min(newTop, maxTop)); + + self.$popover.css({ left: newLeft, top: newTop }); + } + + if (isResizing) { + var dx = e.clientX - startX; + var dy = e.clientY - startY; + var newWidth = Math.max(300, Math.min(startWidth + dx, $(window).width() - 40)); + var newHeight = Math.max(200, Math.min(startHeight + dy, $(window).height() - 40)); + + self.$popover.css({ + width: newWidth, + height: newHeight + }); + } + }); + + $(document).on('mouseup', function() { + if (isDragging) { + isDragging = false; + self.$popover.removeClass('dragging'); + } + if (isResizing) { + isResizing = false; + self.$popover.removeClass('resizing'); + } + }); + }, + + bindEvents: function() { + var self = this; + + // Use native event listener with capture phase to intercept BEFORE + // the inline onclick on parent td elements can fire + document.addEventListener('click', function(e) { + var trigger = e.target.closest('.target-preview-trigger'); + if (trigger) { + e.preventDefault(); + e.stopPropagation(); + e.stopImmediatePropagation(); + + // Also remove inline onclick from parent td to prevent navigation + var td = trigger.closest('td'); + if (td && td.onclick) { + td._originalOnclick = td.onclick; + td.onclick = null; + // Restore after a tick + setTimeout(function() { + if (td._originalOnclick) { + td.onclick = td._originalOnclick; + delete td._originalOnclick; + } + }, 0); + } + + self.showPreview($(trigger)); + return false; + } + }, true); // true = capture phase + + // Click backdrop to close + this.$backdrop.on('click', function() { + self.hidePreview(); + }); + + // ESC to close + $(document).on('keydown', function(e) { + if (e.key === 'Escape' && self.$popover.is(':visible')) { + self.hidePreview(); + } + }); + + // Close button + this.$popover.on('click', '.preview-close', function() { + self.hidePreview(); + }); + + // Tab switching + this.$popover.on('click', '.preview-tab', function() { + var $tab = $(this); + var entityType = $tab.data('entity'); + + self.$popover.find('.preview-tab').removeClass('active'); + $tab.addClass('active'); + + self.$popover.find('.preview-content').removeClass('active'); + self.$popover.find('.preview-content[data-entity="' + entityType + '"]').addClass('active'); + + self.currentEntityType = entityType; + self.filterQuery = ''; + self.$popover.find('.preview-filter-input').val(''); + }); + + // Filter input with debounce + this.$popover.on('input', '.preview-filter-input', function() { + var query = $(this).val().trim().toLowerCase(); + clearTimeout(self.filterTimeout); + self.filterTimeout = setTimeout(function() { + self.filterQuery = query; + self.applyFilter(); + }, 150); + }); + + // Load more button click + this.$popover.on('click', '.btn-load-more', function() { + var $content = $(this).closest('.preview-content'); + var entityType = $content.data('entity'); + var limit = parseInt($content.find('.load-more-select').val(), 10); + self.loadMoreItems(entityType, limit); + }); + + // Rule badge click - show entity names + this.$popover.on('click', '.preview-rule', function(e) { + e.stopPropagation(); + var $rule = $(this); + + // If clicking on same rule with open popup, close it + if (self.$currentRuleElement && self.$currentRuleElement.is($rule)) { + $('.rule-detail-popup').remove(); + self.$currentRuleElement = null; + self.$currentRulePopup = null; + return; + } + + self.showRuleDetails($rule); + }); + + // Close rule popup when clicking elsewhere + $(document).on('click', function(e) { + if (!$(e.target).closest('.preview-rule').length && !$(e.target).closest('.rule-detail-popup').length) { + $('.rule-detail-popup').remove(); + self.$currentRuleElement = null; + self.$currentRulePopup = null; + } + }); + }, + + showRuleDetails: function($rule) { + var self = this; + var entityType = $rule.data('entity-type'); + var method = $rule.data('method'); + var values = $rule.data('values'); + + // Methods that don't have entity IDs to resolve + var nonEntityMethods = ['all', 'by_price_range', 'by_quantity_range', 'by_condition', + 'by_visibility', 'by_active_status', 'by_stock_status', 'by_on_sale', 'by_is_virtual', + 'by_is_pack', 'by_has_combinations', 'by_name_pattern', 'by_reference_pattern', + 'by_date_added', 'by_date_updated', 'by_weight_range', 'by_depth', 'by_active', + 'by_newsletter', 'by_optin']; + + if (nonEntityMethods.indexOf(method) !== -1 || !entityType || !values || values.length === 0) { + // Show simple info popup with properly formatted values + var valuesDisplay = this.formatValuesForDisplay(values); + this.showRulePopup($rule, '
' + + '' + this.humanizeMethod(method) + '' + + (valuesDisplay ? '
' + valuesDisplay + '' : '') + + '
'); + return; + } + + // Show loading state + this.showRulePopup($rule, '
Loading...
'); + + // Fetch entity names + $.ajax({ + url: this.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'getTargetEntitiesByIds', + trait: 'TargetConditions', + entity_type: entityType, + ids: JSON.stringify(values) + } + }).done(function(response) { + if (response.success && response.entities) { + var icon = self.getEntityIcon(entityType); + var html = '
'; + response.entities.forEach(function(entity) { + html += '
'; + if (entity.image) { + html += ''; + } else { + html += ''; + } + html += '' + self.escapeHtml(entity.name || entity.title || 'ID: ' + entity.id) + ''; + html += '
'; + }); + html += '
'; + self.updateRulePopup(html); + } else { + self.updateRulePopup('
Failed to load names
'); + } + }).fail(function() { + self.updateRulePopup('
Failed to load names
'); + }); + }, + + formatValuesForDisplay: function(values) { + if (!values || values.length === 0) { + return ''; + } + + var formatted = []; + for (var i = 0; i < values.length && i < 10; i++) { + var val = values[i]; + if (typeof val === 'object' && val !== null) { + // Handle object values (like {min: x, max: y} for ranges) + if (val.min !== undefined || val.max !== undefined) { + formatted.push((val.min || '0') + ' - ' + (val.max || '∞')); + } else if (val.pattern !== undefined) { + formatted.push('"' + val.pattern + '"'); + } else if (val.from !== undefined || val.to !== undefined) { + formatted.push((val.from || 'start') + ' → ' + (val.to || 'now')); + } else { + // Generic object - show key: value pairs + var parts = []; + for (var key in val) { + if (val.hasOwnProperty(key)) { + parts.push(key + ': ' + val[key]); + } + } + formatted.push(parts.join(', ')); + } + } else { + formatted.push(String(val)); + } + } + + var result = formatted.join(', '); + if (values.length > 10) { + result += ' (+' + (values.length - 10) + ' more)'; + } + return result; + }, + + showRulePopup: function($rule, content) { + // Remove any existing popup + $('.rule-detail-popup').remove(); + + // Create popup and append to body for proper positioning + var $popup = $('
', { class: 'rule-detail-popup' }).html(content); + $('body').append($popup); + + // Position below the rule badge + var offset = $rule.offset(); + var ruleHeight = $rule.outerHeight(); + var popupWidth = $popup.outerWidth(); + var windowWidth = $(window).width(); + + var left = offset.left; + var top = offset.top + ruleHeight + 4; + + // Keep popup within viewport + if (left + popupWidth > windowWidth - 10) { + left = windowWidth - popupWidth - 10; + } + if (left < 10) { + left = 10; + } + + $popup.css({ + position: 'fixed', + top: top - $(window).scrollTop(), + left: left + }); + + this.$currentRulePopup = $popup; + this.$currentRuleElement = $rule; + }, + + updateRulePopup: function(content) { + if (this.$currentRulePopup) { + this.$currentRulePopup.html(content); + } + }, + + showPreview: function($trigger) { + var self = this; + var conditions = $trigger.data('conditions'); + + if (!conditions) { + return; + } + + if (typeof conditions === 'string') { + try { + conditions = JSON.parse(conditions); + } catch (e) { + console.error('[TargetListPreview] Failed to parse conditions:', e); + return; + } + } + + this.currentTrigger = $trigger; + this.currentConditions = conditions; + this.loadedData = {}; + this.filterQuery = ''; + + // Show loading state + this.setPopoverContent(this.renderLoading()); + this.$popover.show(); + this.$backdrop.show(); + + // Position popover + this.positionPopover(); + + // Load preview data + this.loadPreview(conditions); + }, + + hidePreview: function() { + this.$popover.hide(); + this.$backdrop.hide(); + this.currentTrigger = null; + this.currentConditions = null; + this.currentEntityType = null; + // Clean up any open rule popups + $('.rule-detail-popup').remove(); + this.$currentRuleElement = null; + this.$currentRulePopup = null; + }, + + positionPopover: function() { + if (!this.currentTrigger) return; + + var $trigger = this.currentTrigger; + var offset = $trigger.offset(); + var triggerWidth = $trigger.outerWidth(); + var triggerHeight = $trigger.outerHeight(); + var windowWidth = $(window).width(); + var windowHeight = $(window).height(); + var scrollTop = $(window).scrollTop(); + var scrollLeft = $(window).scrollLeft(); + + var popoverWidth = this.$popover.outerWidth() || 380; + var popoverHeight = this.$popover.outerHeight() || 500; + + // Convert document offset to viewport position (for position: fixed) + var triggerViewportLeft = offset.left - scrollLeft; + var triggerViewportTop = offset.top - scrollTop; + + // Center popover below trigger + var left = triggerViewportLeft + (triggerWidth / 2) - (popoverWidth / 2); + var top = triggerViewportTop + triggerHeight + 8; + + // Keep within viewport bounds + if (left < 10) left = 10; + if (left + popoverWidth > windowWidth - 10) { + left = windowWidth - popoverWidth - 10; + } + + // Calculate space available above and below + var spaceBelow = windowHeight - (triggerViewportTop + triggerHeight + 8); + var spaceAbove = triggerViewportTop - 8; + + // Only flip to above if: + // 1. Not enough space below for popover AND + // 2. More space above than below + if (spaceBelow < popoverHeight && spaceAbove > spaceBelow) { + top = triggerViewportTop - popoverHeight - 8; + // Ensure not above viewport + if (top < 10) top = 10; + } else { + // Show below, constrain to viewport if needed + if (top + popoverHeight > windowHeight - 10) { + top = windowHeight - popoverHeight - 10; + } + } + + this.$popover.css({ left: left, top: top }); + }, + + loadPreview: function(conditions) { + var self = this; + + var entityTypes = []; + for (var type in conditions) { + if (conditions[type] && conditions[type].groups && conditions[type].groups.length > 0) { + entityTypes.push(type); + } + } + + if (entityTypes.length === 0) { + this.setPopoverContent(this.renderEmpty()); + return; + } + + var promises = []; + var results = {}; + + entityTypes.forEach(function(entityType) { + var promise = $.ajax({ + url: self.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'previewTargetConditions', + trait: 'TargetConditions', + block_type: entityType, + conditions: JSON.stringify(conditions[entityType]), + limit: self.itemsPerPage + } + }).then(function(response) { + results[entityType] = response; + self.loadedData[entityType] = { + items: response.items || [], + total: response.total || 0, + offset: response.items ? response.items.length : 0 + }; + }); + + promises.push(promise); + }); + + $.when.apply($, promises).then(function() { + self.currentEntityType = entityTypes[0]; + self.setPopoverContent(self.renderPreview(entityTypes, results)); + self.positionPopover(); + }).fail(function() { + self.setPopoverContent(self.renderError()); + }); + }, + + loadMoreItems: function(entityType, limit) { + var self = this; + var data = this.loadedData[entityType]; + + if (!data || data.offset >= data.total) return; + + var requestLimit = limit || this.itemsPerPage; + var $content = this.$popover.find('.preview-content[data-entity="' + entityType + '"]'); + var $loadMore = $content.find('.preview-footer'); + + $loadMore.html(' ' + (this.trans.loading || 'Loading...') + ''); + + $.ajax({ + url: this.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'previewTargetConditions', + trait: 'TargetConditions', + block_type: entityType, + conditions: JSON.stringify(this.currentConditions[entityType]), + limit: requestLimit, + offset: data.offset + } + }).done(function(response) { + if (response.success && response.items) { + data.items = data.items.concat(response.items); + data.offset += response.items.length; + + var $list = $content.find('.preview-items'); + response.items.forEach(function(item) { + $list.append(self.renderItem(item)); + }); + + self.updateFooter(entityType); + self.applyFilter(); + } + }).fail(function() { + $loadMore.html(' ' + (self.trans.error || 'Failed to load') + ''); + }); + }, + + applyFilter: function() { + var query = this.filterQuery; + var $content = this.$popover.find('.preview-content.active'); + var $items = $content.find('.preview-item'); + + if (!query) { + $items.show(); + return; + } + + $items.each(function() { + var $item = $(this); + var name = ($item.find('.preview-item-name').text() || '').toLowerCase(); + var ref = ($item.find('.preview-item-ref').text() || '').toLowerCase(); + + if (name.indexOf(query) !== -1 || ref.indexOf(query) !== -1) { + $item.show(); + } else { + $item.hide(); + } + }); + }, + + updateFooter: function(entityType) { + var data = this.loadedData[entityType]; + var $content = this.$popover.find('.preview-content[data-entity="' + entityType + '"]'); + var $footer = $content.find('.preview-footer'); + + if (data.offset >= data.total) { + $footer.remove(); + } else { + var remaining = data.total - data.offset; + var html = '
'; + html += 'Load'; + html += ''; + html += 'of ' + remaining + ' remaining'; + html += ''; + html += '
'; + $footer.html(html); + } + }, + + renderLoading: function() { + return '
' + + ' ' + + (this.trans.loading || 'Loading...') + + '
'; + }, + + renderEmpty: function() { + return '
' + + '' + (this.trans.items_preview || 'Items Preview') + '' + + '' + + '
' + + '
' + + ' ' + + (this.trans.no_items || 'No items selected') + + '
'; + }, + + renderError: function() { + return '
' + + '' + (this.trans.items_preview || 'Items Preview') + '' + + '' + + '
' + + '
' + + ' ' + + (this.trans.error || 'Failed to load preview') + + '
'; + }, + + renderPreview: function(entityTypes, results) { + var self = this; + var html = '
'; + html += '' + (this.trans.items_preview || 'Items Preview') + ''; + html += ''; + html += '
'; + + // Tabs if multiple entity types + if (entityTypes.length > 1) { + html += '
'; + entityTypes.forEach(function(type, index) { + var result = results[type]; + var count = result && result.total ? result.total : 0; + var icon = self.getEntityIcon(type); + var label = self.getEntityLabel(type); + var activeClass = index === 0 ? ' active' : ''; + html += ''; + }); + html += '
'; + } + + // Filter input + html += '
'; + html += ''; + html += ''; + html += '
'; + + // Content for each entity type + html += '
'; + entityTypes.forEach(function(type, index) { + var activeClass = index === 0 ? ' active' : ''; + html += '
'; + html += self.renderEntityPreview(type, results[type]); + html += '
'; + }); + html += '
'; + + return html; + }, + + renderEntityPreview: function(entityType, result) { + if (!result || !result.success) { + return '
' + (this.trans.error || 'Failed to load') + '
'; + } + + var items = result.items || []; + var total = result.total || 0; + var self = this; + var html = ''; + + // Render rules summary if conditions are available + var conditions = this.currentConditions && this.currentConditions[entityType]; + if (conditions && conditions.groups && conditions.groups.length > 0) { + html += this.renderRulesSummary(entityType, conditions.groups); + } + + if (items.length === 0) { + return html + '
' + (this.trans.no_items || 'No items') + '
'; + } + + html += '
'; + + items.forEach(function(item) { + html += self.renderItem(item); + }); + + html += '
'; + + if (total > items.length) { + var remaining = total - items.length; + html += ''; + } + + return html; + }, + + renderRulesSummary: function(entityType, groups) { + var self = this; + var html = '
'; + + groups.forEach(function(group, index) { + var include = group.include || {}; + var excludes = group.excludes || []; + var method = include.method || 'unknown'; + var values = include.values || []; + + html += '
'; + + // Group label + if (groups.length > 1) { + html += 'Group ' + (index + 1) + ''; + } + + // Include rule - clickable to show details + var entityTypeForMethod = self.getEntityTypeForMethod(entityType, method); + html += '
'; + html += ''; + html += '' + self.formatRuleMethod(method, values.length) + ''; + html += '
'; + + // Exclusion rules + if (excludes.length > 0) { + excludes.forEach(function(exclude) { + var exMethod = exclude.method || 'unknown'; + var exValues = exclude.values || []; + var exEntityType = self.getEntityTypeForMethod(entityType, exMethod); + html += '
'; + html += ''; + html += '' + self.formatRuleMethod(exMethod, exValues.length) + ''; + html += '
'; + }); + } + + html += '
'; + }); + + html += '
'; + return html; + }, + + getEntityTypeForMethod: function(baseEntityType, method) { + // Map method to entity type for resolving names + var methodToEntity = { + 'specific': baseEntityType, + 'by_category': 'categories', + 'by_manufacturer': 'manufacturers', + 'by_supplier': 'suppliers', + 'by_attribute': 'attributes', + 'by_feature': 'features', + 'by_parent': 'categories', + 'by_cms_category': 'cms_categories', + 'by_group': 'customer_groups', + 'by_profile': 'profiles', + 'by_zone': 'zones', + 'by_country': 'countries' + }; + return methodToEntity[method] || null; + }, + + buildRuleTooltip: function(type, method, values) { + var tooltip = type + ': ' + this.humanizeMethod(method); + if (values && values.length > 0) { + tooltip += ' (' + values.length + ' selected)'; + } + return tooltip; + }, + + escapeAttr: function(str) { + return String(str) + .replace(/&/g, '&') + .replace(/"/g, '"') + .replace(/'/g, ''') + .replace(//g, '>'); + }, + + formatRuleMethod: function(method, valueCount) { + var countStr = valueCount !== undefined ? ' (' + valueCount + ')' : ''; + var methodLabels = { + // Basic methods + 'all': 'All', + 'specific': 'Specific' + countStr, + // Product selection methods + 'by_category': 'Category' + countStr, + 'by_manufacturer': 'Manufacturer' + countStr, + 'by_supplier': 'Supplier' + countStr, + 'by_attribute': 'Attribute' + countStr, + 'by_feature': 'Feature' + countStr, + 'by_price_range': 'Price range', + 'by_quantity_range': 'Quantity range', + 'by_condition': 'Condition' + countStr, + 'by_visibility': 'Visibility' + countStr, + 'by_active_status': 'Active status', + 'by_stock_status': 'Stock status', + 'by_on_sale': 'On sale', + 'by_is_virtual': 'Virtual products', + 'by_is_pack': 'Pack products', + 'by_has_combinations': 'Has combinations', + 'by_name_pattern': 'Name pattern', + 'by_reference_pattern': 'Reference pattern', + 'by_date_added': 'Date added', + 'by_date_updated': 'Date updated', + 'by_weight_range': 'Weight range', + // Category methods + 'by_parent': 'Parent category' + countStr, + 'by_depth': 'Depth level', + 'by_active': 'Active status', + // CMS methods + 'by_cms_category': 'CMS category' + countStr, + // Customer methods + 'by_group': 'Customer group' + countStr, + 'by_newsletter': 'Newsletter', + 'by_optin': 'Opt-in', + // Employee methods + 'by_profile': 'Profile' + countStr, + // Generic + 'by_zone': 'Zone' + countStr, + 'by_country': 'Country' + countStr + }; + return methodLabels[method] || this.humanizeMethod(method) + countStr; + }, + + humanizeMethod: function(method) { + return method + .replace(/^by_/, '') + .replace(/_/g, ' ') + .replace(/\b\w/g, function(l) { return l.toUpperCase(); }); + }, + + renderItem: function(item) { + var html = '
'; + if (item.image) { + html += ''; + } else { + html += ''; + } + html += '
'; + html += '' + this.escapeHtml(item.name || item.title || 'Item #' + item.id) + ''; + if (item.reference) { + html += '' + this.escapeHtml(item.reference) + ''; + } + if (item.price_formatted) { + html += '' + item.price_formatted + ''; + } + html += '
'; + html += '
'; + return html; + }, + + escapeHtml: function(text) { + var div = document.createElement('div'); + div.textContent = text; + return div.innerHTML; + }, + + getEntityIcon: function(entityType) { + var icons = { + 'products': 'icon-cube', + 'categories': 'icon-folder-open', + 'manufacturers': 'icon-building', + 'suppliers': 'icon-truck', + 'cms': 'icon-file-text', + 'cms_categories': 'icon-folder', + 'carriers': 'icon-truck', + 'zones': 'icon-globe', + 'countries': 'icon-flag', + 'currencies': 'icon-money', + 'languages': 'icon-language', + 'customer_groups': 'icon-users', + 'shops': 'icon-shopping-cart', + 'shop_groups': 'icon-th', + 'customers': 'icon-user', + 'employees': 'icon-user-secret', + 'profiles': 'icon-id-card', + 'order_states': 'icon-check-circle', + 'taxes': 'icon-percent' + }; + return icons[entityType] || 'icon-list'; + }, + + getEntityLabel: function(entityType) { + var labels = { + 'products': this.trans.products || 'Products', + 'categories': this.trans.categories || 'Categories', + 'manufacturers': this.trans.manufacturers || 'Manufacturers', + 'suppliers': this.trans.suppliers || 'Suppliers', + 'cms': this.trans.cms_pages || 'CMS Pages', + 'cms_categories': this.trans.cms_categories || 'CMS Categories', + 'carriers': this.trans.carriers || 'Carriers', + 'zones': this.trans.zones || 'Zones', + 'countries': this.trans.countries || 'Countries', + 'currencies': this.trans.currencies || 'Currencies', + 'languages': this.trans.languages || 'Languages', + 'customer_groups': this.trans.customer_groups || 'Customer Groups', + 'shops': this.trans.shops || 'Shops', + 'shop_groups': this.trans.shop_groups || 'Shop Groups', + 'customers': this.trans.customers || 'Customers', + 'employees': this.trans.employees || 'Employees', + 'profiles': this.trans.profiles || 'Profiles', + 'order_states': this.trans.order_states || 'Order States', + 'taxes': this.trans.taxes || 'Taxes' + }; + return labels[entityType] || entityType; + } + }; + + // Initialize when config is available + $(document).ready(function() { + if (typeof targetListPreviewConfig !== 'undefined') { + TargetListPreview.init(targetListPreviewConfig); + } + }); + + window.TargetListPreview = TargetListPreview; + +})(jQuery); diff --git a/assets/assets/js/admin/entity-selector.js b/assets/assets/js/admin/entity-selector.js new file mode 100644 index 0000000..c9b535e --- /dev/null +++ b/assets/assets/js/admin/entity-selector.js @@ -0,0 +1,11132 @@ +/** + * Entity Selector - Utilities Module + * Helper functions: escape, validation, icons, search history + * @partial _utils.js (must be loaded first) + * + * EXTRACTION SOURCE: assets/js/admin/entity-selector.js + * Lines: 7552-7570 (escapeHtml, escapeAttr) + * 7577-7590 (getEntityTypeLabel) + * 6289-6350 (validate, showValidationError, clearValidationError) + * 7115-7137 (showRangeInputError) + * 7728-7745 (getBlockMode, isBlockSingleMode) + * 7707-7723 (getCurrentSingleSelection) + * 5411-5467 (search history methods) + */ + +(function($) { + 'use strict'; + + // Create mixin namespace + window._EntitySelectorMixins = window._EntitySelectorMixins || {}; + + // --------------------------------------------------------------- + // Icon framework detection & FA4 mapping (module-level singleton) + // --------------------------------------------------------------- + var _iconMode = null; + + /** + * Material Icons → FontAwesome 4 class mapping. + * FA4 uses class-based icons (icon-name), Material uses text content. + */ + var FA4_MAP = { + 'account_tree': 'icon-sitemap', + 'add': 'icon-plus', + 'add_box': 'icon-plus-square', + 'arrow_downward': 'icon-sort-desc', + 'arrow_drop_down': 'icon-caret-down', + 'arrow_right': 'icon-chevron-right', + 'arrow_upward': 'icon-sort-asc', + 'block': 'icon-ban', + 'brush': 'icon-paint-brush', + 'business': 'icon-building', + 'check': 'icon-check', + 'check_box': 'icon-check-square', + 'check_box_outline_blank': 'icon-square-o', + 'check_circle': 'icon-check-circle', + 'close': 'icon-times', + 'delete': 'icon-trash', + 'description': 'icon-file-text', + 'error': 'icon-exclamation-circle', + 'event': 'icon-calendar', + 'event_busy': 'icon-calendar-times-o', + 'expand_less': 'icon-chevron-up', + 'expand_more': 'icon-chevron-down', + 'filter_list': 'icon-filter', + 'flag': 'icon-flag', + 'folder': 'icon-folder', + 'folder_open': 'icon-folder-open', + 'indeterminate_check_box': 'icon-minus-square', + 'info': 'icon-info-circle', + 'inventory_2': 'icon-archive', + 'label': 'icon-tag', + 'language': 'icon-globe', + 'lightbulb': 'icon-lightbulb-o', + 'list': 'icon-list', + 'list_alt': 'icon-list-alt', + 'local_shipping': 'icon-truck', + 'lock': 'icon-lock', + 'my_location': 'icon-crosshairs', + 'open_in_full': 'icon-expand', + 'payments': 'icon-credit-card', + 'progress_activity': 'icon-circle-o-notch', + 'schedule': 'icon-clock-o', + 'search': 'icon-search', + 'shopping_cart': 'icon-shopping-cart', + 'shuffle': 'icon-random', + 'sort': 'icon-sort', + 'sort_by_alpha': 'icon-sort-alpha-asc', + 'star': 'icon-star', + 'sync': 'icon-refresh', + 'tune': 'icon-sliders', + 'visibility': 'icon-eye', + 'warning': 'icon-warning', + 'widgets': 'icon-th-large' + }; + + /** + * Reverse map: FontAwesome 4 class → Material Icons name. + * Built once lazily from FA4_MAP + extra mappings for FA4 names + * that don't appear as values in FA4_MAP. + */ + var _REVERSE_FA4_MAP = null; + + var EXTRA_REVERSE_MAPPINGS = { + 'icon-cube': 'inventory', + 'icon-folder-o': 'folder', + 'icon-file-text-o': 'description', + 'icon-briefcase': 'work', + 'icon-user': 'person', + 'icon-users': 'group', + 'icon-money': 'payments', + 'icon-tasks': 'checklist', + 'icon-calculator': 'calculate', + 'icon-asterisk': 'star', + 'icon-bar-chart': 'bar_chart', + 'icon-cogs': 'settings', + 'icon-cog': 'settings', + 'icon-tags': 'label', + 'icon-list-ul': 'list', + 'icon-th': 'grid_view', + 'icon-certificate': 'verified', + 'icon-power-off': 'power_settings_new', + 'icon-circle-o': 'radio_button_unchecked' + }; + + function getReverseFa4Map() { + if (_REVERSE_FA4_MAP !== null) return _REVERSE_FA4_MAP; + _REVERSE_FA4_MAP = {}; + // Invert FA4_MAP: value → key + for (var material in FA4_MAP) { + if (FA4_MAP.hasOwnProperty(material)) { + var fa4Class = FA4_MAP[material]; + if (!_REVERSE_FA4_MAP[fa4Class]) { + _REVERSE_FA4_MAP[fa4Class] = material; + } + } + } + // Merge extras + for (var fa4 in EXTRA_REVERSE_MAPPINGS) { + if (EXTRA_REVERSE_MAPPINGS.hasOwnProperty(fa4) && !_REVERSE_FA4_MAP[fa4]) { + _REVERSE_FA4_MAP[fa4] = EXTRA_REVERSE_MAPPINGS[fa4]; + } + } + return _REVERSE_FA4_MAP; + } + + /** + * Normalize an icon name — handles both Material and FA4 class names. + * @param {string} name - Icon name (Material or FA4 format) + * @param {string} mode - 'material' or 'fa4' + * @returns {object} { name: string, extra: string, rawFa4: boolean } + */ + function normalizeIconName(name, mode) { + var extra = ''; + var rawFa4 = false; + + if (name.indexOf('icon-') === 0) { + // FA4 class name input — may have extra classes (e.g. "icon-power-off text-success") + var spaceIdx = name.indexOf(' '); + var fa4Class = (spaceIdx !== -1) ? name.substring(0, spaceIdx) : name; + if (spaceIdx !== -1) extra = name.substring(spaceIdx + 1); + + if (mode === 'material') { + var reverseMap = getReverseFa4Map(); + var materialName = reverseMap[fa4Class]; + if (materialName) { + return { name: materialName, extra: extra, rawFa4: false }; + } + // Fallback: strip 'icon-' and convert hyphens to underscores + var fallback = fa4Class.substring(5).replace(/-/g, '_'); + return { name: fallback, extra: extra, rawFa4: false }; + } + + // FA4 mode + FA4 input — use as-is + return { name: fa4Class, extra: extra, rawFa4: true }; + } + + // Material Icons name — pass through + return { name: name, extra: extra, rawFa4: false }; + } + + /** + * Detect icon framework: 'material' (PS 8+/9+) or 'fa4' (PS 1.6/1.7). + * Checks PHP-set data attribute first, falls back to font detection. + */ + function detectIconMode() { + if (_iconMode !== null) return _iconMode; + + // 1. PHP sets data-icon-mode on the wrapper + var $w = $('.entity-selector-trait[data-icon-mode], .target-conditions-trait[data-icon-mode]').first(); + if ($w.length && $w.data('icon-mode')) { + _iconMode = $w.data('icon-mode'); + return _iconMode; + } + + // 2. Fallback: probe whether Material Icons font is loaded + var test = document.createElement('i'); + test.className = 'material-icons'; + test.style.cssText = 'position:absolute;left:-9999px;top:-9999px;font-size:16px;pointer-events:none'; + test.textContent = 'check'; + (document.body || document.documentElement).appendChild(test); + var family = (window.getComputedStyle(test).fontFamily || '').toLowerCase(); + test.parentNode.removeChild(test); + + _iconMode = (family.indexOf('material') !== -1) ? 'material' : 'fa4'; + return _iconMode; + } + + // Utility functions mixin + window._EntitySelectorMixins.utils = { + + /** + * Debounce function - delays execution until after wait milliseconds + * @param {Function} func - Function to debounce + * @param {number} wait - Milliseconds to wait + * @returns {Function} Debounced function + */ + debounce: function(func, wait) { + var timeout; + return function() { + var context = this; + var args = arguments; + clearTimeout(timeout); + timeout = setTimeout(function() { + func.apply(context, args); + }, wait); + }; + }, + + escapeHtml: function(str) { + if (str === null || str === undefined) return ''; + return String(str) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); + }, + + escapeAttr: function(str) { + if (str === null || str === undefined) return ''; + return String(str) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); + }, + + /** + * Icon helper — returns HTML for an icon that works on PS 1.6 through 9.x. + * Accepts both Material Icons names and FA4 class names as input. + * Automatically uses Material Icons (PS 8+/9+) or FontAwesome 4 (PS 1.6/1.7). + * + * @param {string} name - Icon name (Material or FA4 format, e.g. 'search', 'icon-cube') + * @param {string} [extraClass] - Additional CSS class(es) (e.g. 'es-spin', 'method-trigger-icon') + * @returns {string} HTML string for an element + */ + esIcon: function(name, extraClass) { + var mode = detectIconMode(); + var normalized = normalizeIconName(name, mode); + var iconName = normalized.name; + // Merge extra classes from normalization + if (normalized.extra) { + extraClass = extraClass ? extraClass + ' ' + normalized.extra : normalized.extra; + } + + if (mode === 'material') { + var cls = 'material-icons es-icon'; + if (extraClass) cls += ' ' + extraClass; + return '' + iconName + ''; + } + // FA4 mode + if (normalized.rawFa4) { + // Input was already an FA4 class — use directly + var cls = iconName + ' es-icon'; + } else { + // Input was Material — map to FA4 + var cls = (FA4_MAP[iconName] || 'icon-circle') + ' es-icon'; + } + if (extraClass) cls += ' ' + extraClass; + return ''; + }, + + /** + * Update an existing icon element to show a different icon. + * Handles both Material Icons and FA4 modes. + * Accepts both Material Icons names and FA4 class names as input. + * + * @param {jQuery} $el - The element to update + * @param {string} name - Icon name (Material or FA4 format) + * @param {string} [extraClass] - Additional CSS class(es) to preserve + */ + esIconUpdate: function($el, name, extraClass) { + var mode = detectIconMode(); + var normalized = normalizeIconName(name, mode); + var iconName = normalized.name; + if (normalized.extra) { + extraClass = extraClass ? extraClass + ' ' + normalized.extra : normalized.extra; + } + + if (mode === 'material') { + var cls = 'material-icons es-icon'; + if (extraClass) cls += ' ' + extraClass; + $el.attr('class', cls).text(iconName); + } else { + if (normalized.rawFa4) { + var cls = iconName + ' es-icon'; + } else { + var cls = (FA4_MAP[iconName] || 'icon-circle') + ' es-icon'; + } + if (extraClass) cls += ' ' + extraClass; + $el.attr('class', cls).text(''); + } + }, + + getEntityTypeIcon: function(entityType) { + var icons = { + 'products': 'shopping_cart', + 'categories': 'folder_open', + 'manufacturers': 'business', + 'suppliers': 'local_shipping', + 'attributes': 'list_alt', + 'features': 'label', + 'cms': 'description', + 'cms_categories': 'folder' + }; + return icons[entityType] || 'widgets'; + }, + + getEntityTypeLabel: function(entityType) { + var trans = this.config.trans || {}; + var labels = { + 'products': trans.product || 'Product', + 'categories': trans.category || 'Category', + 'manufacturers': trans.manufacturer || 'Manufacturer', + 'suppliers': trans.supplier || 'Supplier', + 'attributes': trans.attribute || 'Attribute', + 'features': trans.feature || 'Feature', + 'cms': trans.cms_page || 'CMS Page', + 'cms_categories': trans.cms_category || 'CMS Category' + }; + return labels[entityType] || entityType; + }, + + validate: function() { + var isRequired = this.$wrapper.data('required') === 1 || this.$wrapper.data('required') === '1'; + if (!isRequired) return true; + + var hasData = false; + this.$wrapper.find('.target-block').each(function() { + if ($(this).find('.selection-group').length > 0) { + hasData = true; + return false; + } + }); + + if (!hasData) { + this.showValidationError(); + return false; + } + + this.clearValidationError(); + return true; + }, + + showValidationError: function() { + this.$wrapper.addClass('has-validation-error'); + var message = this.$wrapper.data('required-message') || 'Please select at least one item'; + this.$wrapper.find('.trait-validation-error').remove(); + var $error = $('
', { + class: 'trait-validation-error', + html: this.esIcon('warning') + ' ' + message + }); + this.$wrapper.find('.condition-trait-header').after($error); + $('html, body').animate({ scrollTop: this.$wrapper.offset().top - 100 }, 300); + if (!this.$wrapper.find('.condition-trait-body').is(':visible')) { + this.$wrapper.find('.condition-trait-body').slideDown(200); + this.$wrapper.removeClass('collapsed'); + } + }, + + clearValidationError: function() { + this.$wrapper.removeClass('has-validation-error'); + this.$wrapper.find('.trait-validation-error').remove(); + }, + + getBlockMode: function(blockType) { + var blockDef = this.config.blocks[blockType]; + return (blockDef && blockDef.mode) ? blockDef.mode : 'multi'; + }, + + isBlockSingleMode: function(blockType) { + return this.getBlockMode(blockType) === 'single'; + }, + + getCurrentSingleSelection: function() { + if ((this.config.mode || 'multi') !== 'single') return null; + var $chip = this.$wrapper.find('.entity-chips .entity-chip').first(); + if ($chip.length) { + var $block = $chip.closest('.target-block'); + return { + name: $chip.find('.chip-name').text() || $chip.data('id'), + entityType: $block.data('block-type') || 'item' + }; + } + return null; + }, + + /** + * Check if entity type supports tree browsing + */ + supportsTreeBrowsing: function(entityType) { + return entityType === 'categories' || entityType === 'cms_categories'; + } + }; + +})(jQuery); + +/** + * Entity Selector - Events Module + * All event binding and handlers + * @partial _events.js + * + * Contains event handlers for: + * - Tab switching + * - Block/group collapse toggle + * - Dropdown open/close + * - Search input handling + * - Item selection/deselection + * - Group add/remove + * - Exclude row add/remove + * - Method select changes + * - Filter panel toggles + * - Keyboard shortcuts (Ctrl+A, Ctrl+D, Esc, Enter) + * - Load more pagination + * - Sort controls + * - View mode switching + * - Tree view events + * - Preview badge clicks + * - Pattern tag interactions + * - Combination picker events + * - Group modifier events + */ + +(function($) { + 'use strict'; + + window._EntitySelectorMixins = window._EntitySelectorMixins || {}; + + window._EntitySelectorMixins.events = { + + bindEvents: function() { + var self = this; + + // Tab switching + this.$wrapper.on('click', '.target-block-tab', function(e) { + e.preventDefault(); + var blockType = $(this).data('blockType'); + self.switchToBlock(blockType); + }); + + // Tab badge click for preview popover (toggle) + this.$wrapper.on('click', '.target-block-tab .tab-badge', function(e) { + e.stopPropagation(); + e.preventDefault(); + + var $tab = $(this).closest('.target-block-tab'); + var $badge = $(this); + + if ($badge.hasClass('popover-open')) { + self.hidePreviewPopover(); + } else { + self.showPreviewPopover($tab); + } + }); + + // Condition count badge click for preview popover + this.$wrapper.on('click', '.condition-match-count.clickable', function(e) { + e.stopPropagation(); + e.preventDefault(); + + var $badge = $(this); + + if ($badge.hasClass('popover-open')) { + self.hidePreviewPopover(); + } else { + self.showConditionPreviewPopover($badge); + } + }); + + // Group count badge click for preview popover + this.$wrapper.on('click', '.group-count-badge.clickable', function(e) { + e.stopPropagation(); + e.preventDefault(); + + var $badge = $(this); + + if ($badge.hasClass('popover-open')) { + self.hidePreviewPopover(); + } else { + self.showGroupPreviewPopover($badge); + } + }); + + // Total count badge click for summary popover + this.$wrapper.on('click', '.trait-total-count', function(e) { + e.stopPropagation(); + e.preventDefault(); + + var $badge = $(this); + + if ($badge.hasClass('popover-open')) { + self.hidePreviewPopover(); + } else { + self.showTotalPreviewPopover($badge); + } + }); + + // Close popover when clicking outside + $(document).on('click', function(e) { + if (!$(e.target).closest('.target-preview-popover').length && + !$(e.target).closest('.holiday-preview-popover').length && + !$(e.target).closest('.tab-badge').length && + !$(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('.toggle-count.clickable').length && + !$(e.target).closest('.trait-total-count').length && + !$(e.target).closest('.chip-preview-holidays').length) { + self.hidePreviewPopover(); + // Also close holiday popover + $('.holiday-preview-popover').remove(); + } + }); + + // Block-level collapse toggle (click on header) + this.$wrapper.on('click', '.condition-trait-header', function(e) { + if ($(e.target).closest('.target-block-tabs').length || + $(e.target).closest('.trait-header-actions').length || + $(e.target).closest('.prestashop-switch').length || + $(e.target).closest('.trait-total-count').length) { + return; + } + var $body = self.$wrapper.find('.condition-trait-body'); + $body.stop(true, true); + if ($body.is(':visible')) { + $body.slideUp(200); + self.$wrapper.addClass('collapsed'); + } else { + $body.slideDown(200); + self.$wrapper.removeClass('collapsed'); + } + }); + + // Toggle blocks content (form-content layout) + this.$wrapper.on('click', '.btn-toggle-blocks', function(e) { + e.preventDefault(); + var $blocksContent = self.$wrapper.find('.entity-selector-blocks-content'); + var $icon = $(this).find('.es-icon'); + $blocksContent.stop(true, true); + if ($blocksContent.is(':visible')) { + $blocksContent.slideUp(200); + self.$wrapper.addClass('blocks-collapsed'); + $icon.text('expand_more'); + } else { + $blocksContent.slideDown(200); + self.$wrapper.removeClass('blocks-collapsed'); + $icon.text('expand_less'); + } + }); + + // Custom block input changes — update tab badge when value changes + this.$wrapper.on('input change', '.custom-block-content input, .custom-block-content textarea, .custom-block-content select', function() { + self.updateTabBadges(); + }); + + // 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) { + return; + } + if (self.$wrapper.data('mode') === 'single') { + return; + } + var $group = $(this).closest('.selection-group'); + $group.toggleClass('collapsed'); + }); + + // Toggle all groups (single button that switches between expand/collapse) + console.log('[ES-DEBUG] Binding .btn-toggle-groups click on wrapper:', self.$wrapper.attr('id'), 'found buttons:', self.$wrapper.find('.btn-toggle-groups').length); + this.$wrapper.on('click', '.btn-toggle-groups', function(e) { + e.preventDefault(); + e.stopPropagation(); + var $btn = $(this); + var currentState = $btn.attr('data-state') || 'collapsed'; + var trans = self.config.trans || {}; + console.log('[ES-DEBUG] .btn-toggle-groups CLICKED! currentState:', currentState, 'btn parent:', $btn.parent().attr('class'), 'groups found:', self.$wrapper.find('.selection-group').length); + + if (currentState === 'collapsed') { + self.$wrapper.find('.selection-group').removeClass('collapsed'); + $btn.attr('data-state', 'expanded'); + $btn.attr('title', trans.collapse_all || 'Collapse all groups'); + $btn.find('i').text('close_fullscreen'); + console.log('[ES-DEBUG] Expanded all groups'); + } else { + self.$wrapper.find('.selection-group').addClass('collapsed'); + $btn.attr('data-state', 'collapsed'); + $btn.attr('title', trans.expand_all || 'Expand all groups'); + $btn.find('i').text('open_in_full'); + console.log('[ES-DEBUG] Collapsed all groups'); + } + }); + + // Show all toggle change (legacy checkbox) + this.$wrapper.on('change', '.trait-show-all-toggle .show-all-checkbox', function(e) { + e.stopPropagation(); + var isChecked = $(this).prop('checked'); + if (isChecked) { + self.clearAllConditions(); + } + }); + + // Target switch change (PrestaShop native switch) + this.$wrapper.on('change', '.target-switch-toggle', function(e) { + e.stopPropagation(); + var value = $(this).val(); + if (value === '1') { + self.clearAllConditions(); + self.$wrapper.find('.condition-trait-body').slideUp(200); + self.$wrapper.addClass('collapsed'); + } else { + self.$wrapper.find('.condition-trait-body').slideDown(200); + self.$wrapper.removeClass('collapsed'); + } + }); + + // Add group + this.$wrapper.on('click', '.btn-add-group', function(e) { + e.preventDefault(); + var $block = $(this).closest('.target-block'); + var blockType = $block.data('blockType'); + self.addGroup($block, blockType); + }); + + // Remove group + this.$wrapper.on('click', '.btn-remove-group', function(e) { + e.preventDefault(); + var $group = $(this).closest('.selection-group'); + var $block = $(this).closest('.target-block'); + self.removeGroup($group, $block); + }); + + // Group name input - stop propagation to prevent collapse + this.$wrapper.on('click focus', '.group-name-input', function(e) { + e.stopPropagation(); + }); + + // Group name change + this.$wrapper.on('change blur', '.group-name-input', function() { + var $input = $(this); + var $group = $input.closest('.selection-group'); + var name = $.trim($input.val()); + $group.attr('data-group-name', name); + self.serializeAllBlocks(); + }); + + // Add exceptions (first exclude row) + this.$wrapper.on('click', '.btn-add-exclude', function(e) { + e.preventDefault(); + var $group = $(this).closest('.selection-group'); + var $block = $(this).closest('.target-block'); + self.addFirstExcludeRow($group, $block); + }); + + // Add another exclude row + this.$wrapper.on('click', '.btn-add-another-exclude', function(e) { + e.preventDefault(); + var $group = $(this).closest('.selection-group'); + var $block = $(this).closest('.target-block'); + self.addExcludeRow($group, $block); + }); + + // Remove individual exclude row + this.$wrapper.on('click', '.btn-remove-exclude-row', function(e) { + e.preventDefault(); + var $excludeRow = $(this).closest('.exclude-row'); + var $group = $(this).closest('.selection-group'); + var $block = $(this).closest('.target-block'); + self.removeExcludeRow($excludeRow, $group, $block); + }); + + // Include method change + this.$wrapper.on('change', '.include-method-select', function() { + self.hideDropdown(); + + var $group = $(this).closest('.selection-group'); + var $block = $(this).closest('.target-block'); + var $row = $group.find('.group-include'); + var blockType = $block.data('blockType'); + var blockDef = self.config.blocks[blockType] || {}; + var methods = blockDef.selection_methods || {}; + + var $option = $(this).find('option:selected'); + var valueType = $option.data('valueType') || 'none'; + var searchEntity = $option.data('searchEntity') || ''; + var methodOptions = $option.data('options') || null; + + var $oldPicker = $group.find('.include-picker'); + var newPickerHtml = self.buildValuePickerHtml('include', valueType, searchEntity, methods); + $oldPicker.replaceWith(newPickerHtml); + + if (valueType === 'select' && methodOptions) { + var $newPicker = $group.find('.include-picker'); + var $select = $newPicker.find('.select-value-input'); + $select.empty(); + $.each(methodOptions, function(key, label) { + $select.append(''); + }); + } + + if (valueType === 'multi_select_tiles' && methodOptions) { + var $newPicker = $group.find('.include-picker'); + var isExclusive = $option.data('exclusive') === true; + self.populateTiles($newPicker, methodOptions, isExclusive); + } + + if (valueType === 'multi_numeric_range') { + var $newPicker = $group.find('.include-picker'); + var step = $option.data('step'); + var min = $option.data('min'); + self.applyRangeInputConstraints($newPicker, step, min); + } + + if (valueType === 'combination_attributes') { + var $newPicker = $group.find('.include-picker'); + self.loadCombinationAttributeGroups($newPicker); + } + + var selectedMethod = $(this).val(); + self.updateMethodInfoPlaceholder($group.find('.method-selector-wrapper'), selectedMethod, blockType); + + self.updateBlockStatus($block); + self.serializeAllBlocks($row); + }); + + // Exclude method change (within an exclude row) + this.$wrapper.on('change', '.exclude-method-select', function() { + self.hideDropdown(); + + var $excludeRow = $(this).closest('.exclude-row'); + var $group = $(this).closest('.selection-group'); + var $block = $(this).closest('.target-block'); + var blockType = $block.data('blockType'); + var blockDef = self.config.blocks[blockType] || {}; + var methods = blockDef.selection_methods || {}; + + var $option = $(this).find('option:selected'); + var valueType = $option.data('valueType') || 'entity_search'; + var searchEntity = $option.data('searchEntity') || blockType; + var methodOptions = $option.data('options') || null; + + var $oldPicker = $excludeRow.find('.exclude-picker'); + var newPickerHtml = self.buildValuePickerHtml('exclude', valueType, searchEntity, methods); + $oldPicker.replaceWith(newPickerHtml); + + if (valueType === 'select' && methodOptions) { + var $newPicker = $excludeRow.find('.exclude-picker'); + var $select = $newPicker.find('.select-value-input'); + $select.empty(); + $.each(methodOptions, function(key, label) { + $select.append(''); + }); + } + + if (valueType === 'multi_select_tiles' && methodOptions) { + var $newPicker = $excludeRow.find('.exclude-picker'); + var isExclusive = $option.data('exclusive') === true; + self.populateTiles($newPicker, methodOptions, isExclusive); + } + + if (valueType === 'multi_numeric_range') { + var $newPicker = $excludeRow.find('.exclude-picker'); + var step = $option.data('step'); + var min = $option.data('min'); + self.applyRangeInputConstraints($newPicker, step, min); + } + + if (valueType === 'combination_attributes') { + var $newPicker = $excludeRow.find('.exclude-picker'); + self.loadCombinationAttributeGroups($newPicker); + } + + var selectedMethod = $(this).val(); + self.updateMethodInfoPlaceholder($excludeRow.find('.exclude-header-row'), selectedMethod, blockType); + + self.serializeAllBlocks($excludeRow); + }); + + // Handle pattern input Enter key - adds pattern as tag + this.$wrapper.on('keydown', '.pattern-input', function(e) { + if (e.keyCode === 13) { + e.preventDefault(); + var $btn = $(this).closest('.draft-tag').find('.btn-add-pattern'); + $btn.click(); + } + }); + + // Handle add pattern button click (in draft tag) + this.$wrapper.on('click', '.draft-tag .btn-add-pattern', function(e) { + e.preventDefault(); + e.stopPropagation(); + var $draftTag = $(this).closest('.draft-tag'); + var $picker = $draftTag.closest('.value-picker'); + var $row = $draftTag.closest('.group-include, .exclude-row'); + var $input = $draftTag.find('.pattern-input'); + var pattern = $.trim($input.val()); + + if (pattern) { + var caseSensitive = $draftTag.attr('data-case-sensitive') === '1'; + self.addPatternTag($picker, pattern, caseSensitive); + + $input.val('').focus(); + $draftTag.find('.pattern-match-count').removeClass('count-found count-zero').hide(); + $draftTag.find('.pattern-match-count .count-value').text(''); + + self.serializeAllBlocks($row); + } + }); + + // Handle pattern input live typing - update match count in draft tag + this.$wrapper.on('input', '.pattern-input', function() { + var $input = $(this); + var $draftTag = $input.closest('.draft-tag'); + if (!$draftTag.length) return; + + var pattern = $.trim($input.val()); + + if ($input.data('countTimeout')) { + clearTimeout($input.data('countTimeout')); + } + + var $matchCount = $draftTag.find('.pattern-match-count'); + + if (!pattern) { + $matchCount.removeClass('count-found count-zero').hide(); + $matchCount.find('.count-value').text(''); + var $group = $draftTag.closest('.selection-group'); + if ($group.length) { + self.updateGroupTotalCount($group); + } + return; + } + + var timeout = setTimeout(function() { + var caseSensitive = $draftTag.attr('data-case-sensitive') === '1'; + self.updateDraftTagCount($draftTag, pattern, caseSensitive); + }, 300); + $input.data('countTimeout', timeout); + }); + + // Handle pattern tag remove + this.$wrapper.on('click', '.pattern-tag .btn-remove-pattern', function(e) { + e.preventDefault(); + e.stopPropagation(); + var $row = $(this).closest('.group-include, .exclude-row'); + $(this).closest('.pattern-tag').remove(); + self.serializeAllBlocks($row); + }); + + // Handle pattern tag case-sensitivity toggle + this.$wrapper.on('click', '.pattern-tag .btn-toggle-case', function(e) { + e.preventDefault(); + e.stopPropagation(); + var $tag = $(this).closest('.pattern-tag'); + var $btn = $(this); + var trans = self.config.trans || {}; + var isDraftTag = $tag.hasClass('draft-tag'); + + var isCaseSensitive = $tag.data('caseSensitive') === 1 || $tag.data('caseSensitive') === '1' || $tag.attr('data-case-sensitive') === '1'; + var newCaseSensitive = !isCaseSensitive; + + $tag.data('caseSensitive', newCaseSensitive ? 1 : 0); + $tag.attr('data-case-sensitive', newCaseSensitive ? '1' : '0'); + $tag.toggleClass('case-sensitive', newCaseSensitive); + + $btn.find('.case-icon').text(newCaseSensitive ? 'Aa' : 'aa'); + var caseTitle = newCaseSensitive + ? (trans.case_sensitive || 'Case sensitive - click to toggle') + : (trans.case_insensitive || 'Case insensitive - click to toggle'); + $btn.attr('title', caseTitle); + + if (isDraftTag) { + var pattern = $.trim($tag.find('.pattern-input').val()); + if (pattern) { + self.updateDraftTagCount($tag, pattern, newCaseSensitive); + } + } else { + var $row = $tag.closest('.group-include, .exclude-row'); + self.serializeAllBlocks($row); + } + }); + + // Handle pattern match count click - show preview modal + this.$wrapper.on('click', '.pattern-match-count', function(e) { + e.preventDefault(); + e.stopPropagation(); + + var $matchCount = $(this); + var count = $matchCount.data('count'); + var pattern = $matchCount.data('pattern'); + var entityType = $matchCount.data('entityType'); + var caseSensitive = $matchCount.data('caseSensitive'); + + if (!count || count <= 0 || !pattern) { + return; + } + + self.showPatternPreviewModal(pattern, entityType, caseSensitive, count); + }); + + // Handle pattern tag edit (click on tag text) + this.$wrapper.on('click', '.pattern-tag .pattern-tag-text', function(e) { + e.preventDefault(); + var $tag = $(this).closest('.pattern-tag'); + if ($tag.hasClass('editing')) return; + + var currentPattern = $tag.data('pattern'); + + var $editInput = $('').val(currentPattern); + var $saveBtn = $(''); + var $cancelBtn = $(''); + var $editActions = $('').append($saveBtn, $cancelBtn); + + $tag.addClass('editing').find('.pattern-tag-text').hide(); + $tag.find('.btn-remove-pattern').hide(); + $tag.prepend($editActions).prepend($editInput); + $editInput.focus().select(); + + $editInput.on('keydown', function(ev) { + if (ev.keyCode === 13) { + ev.preventDefault(); + $saveBtn.click(); + } else if (ev.keyCode === 27) { + ev.preventDefault(); + $cancelBtn.click(); + } + }); + }); + + // Pattern edit - Save button + this.$wrapper.on('click', '.pattern-tag .btn-pattern-save', function(e) { + e.preventDefault(); + e.stopPropagation(); + var $tag = $(this).closest('.pattern-tag'); + var $editInput = $tag.find('.pattern-tag-edit'); + var currentPattern = $tag.data('pattern'); + var newPattern = $.trim($editInput.val()); + + if (newPattern && newPattern !== currentPattern) { + $tag.data('pattern', newPattern); + $tag.find('.pattern-tag-text').text(newPattern); + } + $editInput.remove(); + $tag.find('.pattern-edit-actions').remove(); + $tag.removeClass('editing').find('.pattern-tag-text, .btn-remove-pattern').show(); + var $row = $tag.closest('.group-include, .exclude-row'); + self.serializeAllBlocks($row); + }); + + // Pattern edit - Cancel button + this.$wrapper.on('click', '.pattern-tag .btn-pattern-cancel', function(e) { + e.preventDefault(); + e.stopPropagation(); + var $tag = $(this).closest('.pattern-tag'); + $tag.find('.pattern-tag-edit').remove(); + $tag.find('.pattern-edit-actions').remove(); + $tag.removeClass('editing').find('.pattern-tag-text, .btn-remove-pattern').show(); + }); + + // Handle numeric range input changes + this.$wrapper.on('change', '.range-min-input, .range-max-input', function() { + var $row = $(this).closest('.group-include, .exclude-row'); + self.serializeAllBlocks($row); + }); + + // Handle date range input changes + this.$wrapper.on('change', '.date-from-input, .date-to-input', function() { + var $row = $(this).closest('.group-include, .exclude-row'); + self.serializeAllBlocks($row); + }); + + // Handle select value changes + this.$wrapper.on('change', '.select-value-input', function() { + var $row = $(this).closest('.group-include, .exclude-row'); + self.serializeAllBlocks($row); + }); + + // Handle multi-range add button click + this.$wrapper.on('click', '.btn-add-range', function(e) { + e.preventDefault(); + var $picker = $(this).closest('.value-picker'); + var $row = $(this).closest('.group-include, .exclude-row'); + var $container = $picker.find('.multi-range-container'); + var $chipsContainer = $container.find('.multi-range-chips'); + var $minInput = $container.find('.range-min-input'); + var $maxInput = $container.find('.range-max-input'); + + var minVal = $minInput.val().trim(); + var maxVal = $maxInput.val().trim(); + + if (minVal === '' && maxVal === '') { + return; + } + + var step = parseFloat($minInput.attr('step')) || 0.01; + var minAllowed = $minInput.attr('min'); + var hasMinConstraint = typeof minAllowed !== 'undefined' && minAllowed !== ''; + minAllowed = hasMinConstraint ? parseFloat(minAllowed) : null; + + var minNum = minVal !== '' ? parseFloat(minVal) : null; + var maxNum = maxVal !== '' ? parseFloat(maxVal) : null; + + if (hasMinConstraint) { + if (minNum !== null && minNum < minAllowed) { + self.showRangeInputError($minInput, self.config.trans.min_value_error || 'Minimum value is ' + minAllowed); + return; + } + if (maxNum !== null && maxNum < minAllowed) { + self.showRangeInputError($maxInput, self.config.trans.min_value_error || 'Minimum value is ' + minAllowed); + return; + } + } + + if (minNum !== null && maxNum !== null && minNum > maxNum) { + self.showRangeInputError($minInput, self.config.trans.min_greater_than_max || 'Min cannot be greater than max'); + return; + } + + var decimals = step < 1 ? String(step).split('.')[1].length : 0; + if (minNum !== null) { + if (step >= 1) { + minNum = Math.round(minNum); + } else { + minNum = parseFloat(minNum.toFixed(decimals)); + } + minVal = String(minNum); + } + if (maxNum !== null) { + if (step >= 1) { + maxNum = Math.round(maxNum); + } else { + maxNum = parseFloat(maxNum.toFixed(decimals)); + } + maxVal = String(maxNum); + } + + var chipText = ''; + if (minVal !== '' && maxVal !== '') { + chipText = minVal + ' - ' + maxVal; + } else if (minVal !== '') { + chipText = '≥ ' + minVal; + } else { + chipText = '≤ ' + maxVal; + } + + var $chip = $('', { + class: 'range-chip', + 'data-min': minVal, + 'data-max': maxVal + }); + $chip.append($('', { class: 'range-chip-text', text: chipText })); + $chip.append($(''; + html += ''; + + // Sort controls - options with data-entities attribute for entity-specific filtering + html += '
'; + html += ''; + html += ''; + + // View mode selector - Tree option always present, shown for categories + html += ''; + html += '
'; // End sort-controls + + // Refine search + html += '
'; + html += ''; + html += ''; + html += ''; + html += '
'; + + // Filter toggle button + html += ''; + + // History button + html += ''; + + html += '
'; // End dropdown-actions + html += '
'; // End dropdown-header + + // Filter panel + html += '
'; + + // Quick filters row (for products) + html += '
'; + html += ''; + html += ''; + + // Price range + html += '
'; + html += '' + (trans.price || 'Price') + ':'; + html += ''; + html += '-'; + html += ''; + html += '
'; + + html += ''; + html += '
'; + + // Attribute/Feature filter toggles for products + html += ''; + html += ''; + + html += ''; + html += ''; + + // Entity-specific filters: Categories + html += ''; + + // Entity-specific filters: Manufacturers + html += ''; + + // Entity-specific filters: Suppliers + html += ''; + + // Entity-specific filters: Attributes + html += ''; + + // Entity-specific filters: Features + html += ''; + + // Entity-specific filters: CMS Pages + html += ''; + + // Entity-specific filters: CMS Categories + html += ''; + + // Entity-specific filters: Countries + html += ''; + + html += '
'; // End filter-panel + + // Results header for list view (product columns) + html += '
'; + html += ''; + html += '' + (trans.product || 'Product') + ''; + html += '' + (trans.price || 'Price') + ''; + html += '' + (trans.sale || 'Sale') + ''; + html += '' + (trans.stock || 'Stock') + ''; + html += '' + (trans.sold || 'Sold') + ''; + html += '
'; + + // Results + html += ''; + + // Footer - unified load more + actions + html += ''; + + html += '
'; + + this.$dropdown = $(html); + $('body').append(this.$dropdown); + }, + + hideDropdown: function() { + if (this.$dropdown) { + this.$dropdown.removeClass('show'); + } + this.activeGroup = null; + }, + + positionDropdown: function($input) { + if (!this.$dropdown) return; + + var $picker = $input.closest('.value-picker'); + var $searchBox = $input.closest('.entity-search-box'); + + // Get absolute positions (dropdown is appended to body) + var searchBoxOffset = $searchBox.offset(); + var searchBoxHeight = $searchBox.outerHeight(); + var pickerOffset = $picker.offset(); + var pickerWidth = $picker.outerWidth(); + + // Calculate position relative to document + var dropdownTop = searchBoxOffset.top + searchBoxHeight + 4; + var dropdownLeft = pickerOffset.left; + var dropdownWidth = Math.max(pickerWidth, 400); + + // Ensure dropdown doesn't overflow the viewport horizontally + var viewportWidth = $(window).width(); + if (dropdownLeft + dropdownWidth > viewportWidth - 10) { + dropdownWidth = viewportWidth - dropdownLeft - 10; + } + + // Ensure dropdown doesn't overflow viewport vertically + var viewportHeight = $(window).height(); + var scrollTop = $(window).scrollTop(); + var maxHeight = viewportHeight - (dropdownTop - scrollTop) - 20; + maxHeight = Math.max(maxHeight, 400); + + this.$dropdown.css({ + position: 'absolute', + top: dropdownTop, + left: dropdownLeft, + width: dropdownWidth, + maxHeight: maxHeight, + zIndex: 10000 + }); + + // Show the dropdown + this.$dropdown.addClass('show'); + } + }; + +})(jQuery); + +/** + * Entity Selector - Search Module + * AJAX search, results rendering, category tree, filters, search history + * @partial _search.js + */ + +(function($) { + 'use strict'; + + window._EntitySelectorMixins = window._EntitySelectorMixins || {}; + + window._EntitySelectorMixins.search = { + + // Category tree cache + categoryTreeCache: null, + + /** + * Perform AJAX search for entities + */ + performSearch: function(appendMode) { + var self = this; + + if (!this.activeGroup) return; + + this.isLoading = true; + + var searchEntity = this.activeGroup.searchEntity; + + // Build request data with sort and filter params + var limit = appendMode && this.loadMoreCount ? this.loadMoreCount : 20; + var requestData = { + ajax: 1, + action: 'searchTargetEntities', + trait: 'EntitySelector', + entity_type: searchEntity, + q: this.searchQuery, + limit: limit, + offset: appendMode ? this.searchOffset : 0, + sort_by: this.currentSort ? this.currentSort.field : 'name', + sort_dir: this.currentSort ? this.currentSort.dir : 'ASC' + }; + + // Add refine query if present + if (this.refineQuery) { + requestData.refine = this.refineQuery; + if (this.refineNegate) { + requestData.refine_negate = 1; + } + } + + // Add product-specific filters + if (searchEntity === 'products' && this.filters) { + if (this.filters.inStock) { + requestData.filter_in_stock = 1; + } + if (this.filters.discounted) { + requestData.filter_discounted = 1; + } + if (this.filters.priceMin !== null && this.filters.priceMin !== '') { + requestData.filter_price_min = this.filters.priceMin; + } + if (this.filters.priceMax !== null && this.filters.priceMax !== '') { + requestData.filter_price_max = this.filters.priceMax; + } + if (this.filters.attributes && this.filters.attributes.length > 0) { + requestData.filter_attributes = JSON.stringify(this.filters.attributes); + } + if (this.filters.features && this.filters.features.length > 0) { + requestData.filter_features = JSON.stringify(this.filters.features); + } + } + + // Add entity-specific filters for non-product entities + if (searchEntity !== 'products' && this.filters) { + // Product count range (categories, manufacturers, suppliers, attributes, features) + if (this.filters.productCountMin !== null && this.filters.productCountMin !== '') { + requestData.filter_product_count_min = this.filters.productCountMin; + } + if (this.filters.productCountMax !== null && this.filters.productCountMax !== '') { + requestData.filter_product_count_max = this.filters.productCountMax; + } + + // Category-specific + if (searchEntity === 'categories') { + if (this.filters.depth) { + requestData.filter_depth = this.filters.depth; + } + if (this.filters.hasProducts) { + requestData.filter_has_products = 1; + } + if (this.filters.hasDescription) { + requestData.filter_has_description = 1; + } + if (this.filters.hasImage) { + requestData.filter_has_image = 1; + } + if (this.filters.salesMin !== null && this.filters.salesMin !== '') { + requestData.filter_sales_min = this.filters.salesMin; + } + if (this.filters.salesMax !== null && this.filters.salesMax !== '') { + requestData.filter_sales_max = this.filters.salesMax; + } + if (this.filters.turnoverMin !== null && this.filters.turnoverMin !== '') { + requestData.filter_turnover_min = this.filters.turnoverMin; + } + if (this.filters.turnoverMax !== null && this.filters.turnoverMax !== '') { + requestData.filter_turnover_max = this.filters.turnoverMax; + } + if (this.filters.activeOnly) { + requestData.filter_active = 1; + } + } + + // Manufacturer-specific + if (searchEntity === 'manufacturers') { + if (this.filters.salesMin !== null && this.filters.salesMin !== '') { + requestData.filter_sales_min = this.filters.salesMin; + } + if (this.filters.salesMax !== null && this.filters.salesMax !== '') { + requestData.filter_sales_max = this.filters.salesMax; + } + if (this.filters.turnoverMin !== null && this.filters.turnoverMin !== '') { + requestData.filter_turnover_min = this.filters.turnoverMin; + } + if (this.filters.turnoverMax !== null && this.filters.turnoverMax !== '') { + requestData.filter_turnover_max = this.filters.turnoverMax; + } + if (this.filters.dateAddFrom) { + requestData.filter_date_add_from = this.filters.dateAddFrom; + } + if (this.filters.dateAddTo) { + requestData.filter_date_add_to = this.filters.dateAddTo; + } + if (this.filters.lastProductFrom) { + requestData.filter_last_product_from = this.filters.lastProductFrom; + } + if (this.filters.lastProductTo) { + requestData.filter_last_product_to = this.filters.lastProductTo; + } + if (this.filters.activeOnly) { + requestData.filter_active = 1; + } + } + + // Supplier-specific + if (searchEntity === 'suppliers') { + if (this.filters.salesMin !== null && this.filters.salesMin !== '') { + requestData.filter_sales_min = this.filters.salesMin; + } + if (this.filters.salesMax !== null && this.filters.salesMax !== '') { + requestData.filter_sales_max = this.filters.salesMax; + } + if (this.filters.turnoverMin !== null && this.filters.turnoverMin !== '') { + requestData.filter_turnover_min = this.filters.turnoverMin; + } + if (this.filters.turnoverMax !== null && this.filters.turnoverMax !== '') { + requestData.filter_turnover_max = this.filters.turnoverMax; + } + if (this.filters.dateAddFrom) { + requestData.filter_date_add_from = this.filters.dateAddFrom; + } + if (this.filters.dateAddTo) { + requestData.filter_date_add_to = this.filters.dateAddTo; + } + if (this.filters.lastProductFrom) { + requestData.filter_last_product_from = this.filters.lastProductFrom; + } + if (this.filters.lastProductTo) { + requestData.filter_last_product_to = this.filters.lastProductTo; + } + if (this.filters.activeOnly) { + requestData.filter_active = 1; + } + } + + // Attribute-specific + if (searchEntity === 'attributes') { + if (this.filters.salesMin !== null && this.filters.salesMin !== '') { + requestData.filter_sales_min = this.filters.salesMin; + } + if (this.filters.salesMax !== null && this.filters.salesMax !== '') { + requestData.filter_sales_max = this.filters.salesMax; + } + if (this.filters.turnoverMin !== null && this.filters.turnoverMin !== '') { + requestData.filter_turnover_min = this.filters.turnoverMin; + } + if (this.filters.turnoverMax !== null && this.filters.turnoverMax !== '') { + requestData.filter_turnover_max = this.filters.turnoverMax; + } + if (this.filters.attributeGroup) { + requestData.filter_attribute_group = this.filters.attributeGroup; + } + if (this.filters.isColor) { + requestData.filter_is_color = 1; + } + } + + // Feature-specific + if (searchEntity === 'features') { + if (this.filters.salesMin !== null && this.filters.salesMin !== '') { + requestData.filter_sales_min = this.filters.salesMin; + } + if (this.filters.salesMax !== null && this.filters.salesMax !== '') { + requestData.filter_sales_max = this.filters.salesMax; + } + if (this.filters.turnoverMin !== null && this.filters.turnoverMin !== '') { + requestData.filter_turnover_min = this.filters.turnoverMin; + } + if (this.filters.turnoverMax !== null && this.filters.turnoverMax !== '') { + requestData.filter_turnover_max = this.filters.turnoverMax; + } + if (this.filters.featureGroup) { + requestData.filter_feature_group = this.filters.featureGroup; + } + if (this.filters.isCustom) { + requestData.filter_is_custom = 1; + } + } + + // CMS-specific + if (searchEntity === 'cms') { + if (this.filters.activeOnly) { + requestData.filter_active = 1; + } + if (this.filters.indexable) { + requestData.filter_indexable = 1; + } + } + + // CMS Categories-specific + if (searchEntity === 'cms_categories') { + if (this.filters.activeOnly) { + requestData.filter_active = 1; + } + } + + // Countries-specific + if (searchEntity === 'countries') { + if (this.filters.activeOnly) { + requestData.filter_active = 1; + } + if (this.filters.hasHolidays) { + requestData.filter_has_holidays = 1; + } + if (this.filters.containsStates) { + requestData.filter_contains_states = 1; + } + if (this.filters.zone) { + requestData.filter_zone = this.filters.zone; + } + } + } + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: requestData, + success: function(response) { + self.isLoading = false; + + if (!response.success) return; + + // Save to search history if query is not empty and has results + if (self.searchQuery && self.searchQuery.length >= 2 && response.total > 0) { + self.addToSearchHistory(searchEntity, self.searchQuery); + } + + if (appendMode) { + self.searchResults = self.searchResults.concat(response.results || []); + } else { + self.searchResults = response.results || []; + } + self.searchTotal = response.total || 0; + self.searchOffset = appendMode ? self.searchOffset + (response.results || []).length : (response.results || []).length; + + self.renderSearchResults(appendMode); + self.$dropdown.addClass('show'); + }, + error: function() { + self.isLoading = false; + } + }); + }, + + /** + * Render search results in the dropdown + */ + renderSearchResults: function(appendMode) { + var self = this; + var trans = this.config.trans || {}; + var $container = this.$dropdown.find('.dropdown-results'); + + // Get selected IDs from current picker (to mark as selected) + // and hidden IDs from sibling exclude pickers with same entity type (to hide completely) + var selectedIds = []; + var hiddenIds = []; + if (this.activeGroup) { + var $block = this.$wrapper.find('.target-block[data-block-type="' + this.activeGroup.blockType + '"]'); + var $group = $block.find('.selection-group[data-group-index="' + this.activeGroup.groupIndex + '"]'); + var currentSearchEntity = this.activeGroup.searchEntity; + var currentExcludeIndex = this.activeGroup.excludeIndex; + + if (this.activeGroup.section === 'include') { + // For include section, just get current picker's selections + var $picker = $group.find('.include-picker'); + $picker.find('.entity-chip').each(function() { + selectedIds.push(String($(this).data('id'))); + }); + } else { + // For exclude section, get current picker's selections AND + // collect IDs from sibling exclude rows with same entity type to hide + var $currentExcludeRow = $group.find('.exclude-row[data-exclude-index="' + currentExcludeIndex + '"]'); + var $currentPicker = $currentExcludeRow.find('.exclude-picker'); + + // Get selected IDs from current exclude row + $currentPicker.find('.entity-chip').each(function() { + selectedIds.push(String($(this).data('id'))); + }); + + // Get hidden IDs from OTHER exclude rows with the same entity type + $group.find('.exclude-row').each(function() { + var $row = $(this); + var rowIndex = parseInt($row.data('excludeIndex'), 10); + + // Skip current exclude row + if (rowIndex === currentExcludeIndex) return; + + var $picker = $row.find('.exclude-picker'); + var rowEntityType = $picker.attr('data-search-entity') || self.activeGroup.blockType; + + // Only collect if same entity type + if (rowEntityType === currentSearchEntity) { + $picker.find('.entity-chip').each(function() { + hiddenIds.push(String($(this).data('id'))); + }); + } + }); + } + } + + // Check if this is a product search + var isProductSearch = this.activeGroup && this.activeGroup.searchEntity === 'products'; + var isListView = this.viewMode === 'list'; + + // Show/hide results header for products in list view + this.$dropdown.find('.results-header').toggle(isProductSearch && isListView); + + // Build HTML - filter out items that are hidden (selected in sibling exclude rows) + var visibleResults = this.searchResults.filter(function(item) { + return hiddenIds.indexOf(String(item.id)) === -1; + }); + + // Update count (show visible count and total, noting hidden items if any) + var hiddenCount = this.searchResults.length - visibleResults.length; + var countText = visibleResults.length + ' / ' + this.searchTotal + ' results'; + if (hiddenCount > 0) { + countText += ' (' + hiddenCount + ' hidden)'; + } + this.$dropdown.find('.results-count').text(countText); + + var html = ''; + if (visibleResults.length === 0 && !appendMode) { + html = '
' + this.esIcon('search') + ' ' + (trans.no_results || 'No results found') + '
'; + } else { + visibleResults.forEach(function(item) { + var isSelected = selectedIds.indexOf(String(item.id)) !== -1; + var itemClass = 'dropdown-item' + (isSelected ? ' selected' : ''); + if (item.type === 'product') itemClass += ' result-item-product'; + + html += '
'; + + var searchEntity = self.activeGroup ? self.activeGroup.searchEntity : null; + + // Countries show flags + if (searchEntity === 'countries' && item.iso_code) { + var flagUrl = 'https://flagcdn.com/w40/' + item.iso_code.toLowerCase() + '.png'; + html += '
' + self.escapeAttr(item.iso_code) + '
'; + } else if (item.image) { + html += '
'; + } else { + // Entity-specific icons + var iconName = 'widgets'; // default + if (searchEntity === 'categories') iconName = 'folder'; + else if (searchEntity === 'manufacturers') iconName = 'business'; + else if (searchEntity === 'suppliers') iconName = 'local_shipping'; + else if (searchEntity === 'attributes') iconName = 'brush'; + else if (searchEntity === 'features') iconName = 'list'; + else if (searchEntity === 'cms') iconName = 'description'; + else if (searchEntity === 'cms_categories') iconName = 'folder'; + html += '
' + self.esIcon(iconName) + '
'; + } + + html += '
'; + html += '
' + self.escapeHtml(item.name) + '
'; + if (item.subtitle) { + // Split multi-line subtitles into separate divs for styling + var subtitleLines = item.subtitle.split('\n'); + html += '
'; + subtitleLines.forEach(function(line, idx) { + var lineClass = idx === 0 ? 'subtitle-line subtitle-line-primary' : 'subtitle-line subtitle-line-secondary'; + html += '
' + self.escapeHtml(line) + '
'; + }); + html += '
'; + } + html += '
'; + + // Add product-specific columns (price, sale price, stock, sold) + if (item.type === 'product') { + if (isListView) { + // List view: full columns + // Regular price + html += '
'; + html += '' + (item.regular_price_formatted || item.price_formatted || '') + ''; + html += '
'; + + // Sale price (only if discounted) + if (item.has_discount) { + html += '
'; + html += '' + (item.price_formatted || '') + ''; + html += '
'; + } else { + html += '
'; + } + + // Stock column + var stockClass = item.stock_status === 'out_of_stock' ? 'stock-out' : + (item.stock_status === 'low_stock' ? 'stock-low' : 'stock-ok'); + html += '
'; + html += '' + (item.stock_qty !== undefined ? item.stock_qty : '') + ''; + html += '
'; + + // Sales column + html += '
'; + html += '' + (item.sales_qty !== undefined ? item.sales_qty : '0') + ''; + html += '
'; + } else { + // Grid view: compact info line + var gridStockClass = item.stock_status === 'out_of_stock' ? 'stock-out' : + (item.stock_status === 'low_stock' ? 'stock-low' : ''); + html += '
'; + html += '' + (item.price_formatted || '') + ''; + if (item.stock_qty !== undefined) { + html += '' + item.stock_qty + ' qty'; + } + if (item.has_discount) { + html += '-' + (item.discount_percent || '') + '%'; + } + html += '
'; + } + } + + html += '
'; + }); + } + + if (appendMode) { + $container.append(html); + } else { + $container.html(html); + } + + // Show/hide load more controls and update remaining count + var hasMore = this.searchResults.length < this.searchTotal; + var $loadMoreControls = this.$dropdown.find('.load-more-controls'); + $loadMoreControls.toggle(hasMore); + + if (hasMore) { + var remaining = this.searchTotal - this.searchResults.length; + $loadMoreControls.find('.remaining-count').text(remaining); + + // Update "All" option in dropdown + var $select = $loadMoreControls.find('.load-more-select'); + var $allOption = $select.find('option[data-all="true"]'); + if ($allOption.length) { + $allOption.val(remaining).text((trans.all || 'All') + ' (' + remaining + ')'); + } else { + $select.find('option:last').after(''); + } + } + + // Ensure dropdown-actions are visible and history button is deactivated + this.$dropdown.find('.dropdown-actions').show(); + this.$dropdown.find('.btn-show-history').removeClass('active'); + + // Disable history button if no search history for current entity type + var entityType = this.activeGroup ? this.activeGroup.searchEntity : null; + var hasHistory = entityType && this.getSearchHistory(entityType).length > 0; + this.$dropdown.find('.btn-show-history').prop('disabled', !hasHistory); + }, + + // NOTE: Tree methods (loadCategoryTree, renderCategoryTree, filterCategoryTree, + // findTreeDescendants, findTreeAncestors, updateSelectChildrenButtons) are + // defined in _tree.js which is merged later and takes precedence. + + // ========================================================================= + // Search History + // ========================================================================= + + loadSearchHistory: function() { + try { + var stored = localStorage.getItem(this.searchHistoryKey); + this.searchHistory = stored ? JSON.parse(stored) : {}; + } catch (e) { + this.searchHistory = {}; + } + }, + + saveSearchHistory: function() { + try { + localStorage.setItem(this.searchHistoryKey, JSON.stringify(this.searchHistory)); + } catch (e) { + // localStorage might be full or unavailable + } + }, + + addToSearchHistory: function(entityType, query) { + if (!query || query.length < 2) return; + + if (!this.searchHistory[entityType]) { + this.searchHistory[entityType] = []; + } + + var history = this.searchHistory[entityType]; + + // Remove if already exists (will re-add at top) + var existingIndex = history.indexOf(query); + if (existingIndex !== -1) { + history.splice(existingIndex, 1); + } + + // Add at beginning + history.unshift(query); + + // Trim to max + if (history.length > this.searchHistoryMax) { + history = history.slice(0, this.searchHistoryMax); + } + + this.searchHistory[entityType] = history; + this.saveSearchHistory(); + }, + + removeFromSearchHistory: function(entityType, query) { + if (!this.searchHistory[entityType]) return; + + var index = this.searchHistory[entityType].indexOf(query); + if (index !== -1) { + this.searchHistory[entityType].splice(index, 1); + this.saveSearchHistory(); + } + }, + + getSearchHistory: function(entityType) { + return this.searchHistory[entityType] || []; + }, + + showSearchHistory: function(entityType) { + var history = this.getSearchHistory(entityType); + var trans = this.config.trans || {}; + var $container = this.$dropdown.find('.dropdown-results'); + + // Update header + this.$dropdown.find('.results-count').text(trans.recent_searches || 'Recent searches'); + + // Hide filters, actions, and results header for history view + this.$dropdown.find('.dropdown-actions').hide(); + this.$dropdown.find('.filter-panel').removeClass('show'); + this.$dropdown.find('.btn-toggle-filters').removeClass('active'); + this.$dropdown.find('.results-header').hide(); + + if (!history.length) { + // No history - just do a regular search + this.performSearch(); + return; + } + + // Build history items + var html = '
'; + for (var i = 0; i < history.length; i++) { + var query = history[i]; + html += '
'; + html += this.esIcon('schedule'); + html += '' + this.escapeHtml(query) + ''; + html += ''; + html += '
'; + } + html += '
'; + + $container.html(html); + this.$dropdown.addClass('show'); + }, + + // ========================================================================= + // Filter Methods + // ========================================================================= + + refreshSearch: function() { + // In tree view mode, re-filter the tree instead of doing a flat AJAX search + if (this.viewMode === 'tree') { + this.filterCategoryTree(this.searchQuery || ''); + return; + } + + this.searchOffset = 0; + this.loadMoreCount = 20; + // Reset load more select to default + if (this.$dropdown) { + this.$dropdown.find('.load-more-select').val('20'); + // Remove the dynamic "All" option + this.$dropdown.find('.load-more-select option[data-all="true"]').remove(); + } + this.performSearch(false); + }, + + clearFilters: function() { + this.refineQuery = ''; + this.refineNegate = false; + this.filters = { + inStock: false, + discounted: false, + priceMin: null, + priceMax: null, + attributes: [], + features: [], + // Entity-specific filters + productCountMin: null, + productCountMax: null, + salesMin: null, + salesMax: null, + turnoverMin: null, + turnoverMax: null, + depth: null, + hasProducts: false, + hasDescription: false, + hasImage: false, + activeOnly: true, + attributeGroup: null, + featureGroup: null, + dateAddFrom: null, + dateAddTo: null, + lastProductFrom: null, + lastProductTo: null, + // Country-specific filters + hasHolidays: false, + containsStates: false, + zone: null + }; + + if (this.$dropdown) { + var trans = this.config.trans || {}; + this.$dropdown.find('.refine-input').val('').attr('placeholder', trans.refine_short || 'Refine...'); + this.$dropdown.find('.btn-clear-refine').hide(); + this.$dropdown.find('.btn-refine-negate').removeClass('active'); + this.$dropdown.find('.filter-in-stock').prop('checked', false); + this.$dropdown.find('.filter-discounted').prop('checked', false); + this.$dropdown.find('.filter-price-min').val(''); + this.$dropdown.find('.filter-price-max').val(''); + this.$dropdown.find('.filter-attr-chip').removeClass('active'); + this.$dropdown.find('.filter-feat-chip').removeClass('active'); + this.$dropdown.find('.filter-group-toggle').removeClass('active has-selection'); + this.$dropdown.find('.filter-row-values').hide(); + + // Clear entity-specific filter inputs + this.$dropdown.find('.filter-product-count-min, .filter-product-count-max').val(''); + this.$dropdown.find('.filter-sales-min, .filter-sales-max').val(''); + this.$dropdown.find('.filter-turnover-min, .filter-turnover-max').val(''); + this.$dropdown.find('.filter-date-add-from, .filter-date-add-to').val(''); + this.$dropdown.find('.filter-last-product-from, .filter-last-product-to').val(''); + this.$dropdown.find('.filter-depth-select').val(''); + this.$dropdown.find('.filter-has-products').prop('checked', false); + this.$dropdown.find('.filter-has-description').prop('checked', false); + this.$dropdown.find('.filter-has-image').prop('checked', false); + this.$dropdown.find('.filter-active-only').prop('checked', true); + this.$dropdown.find('.filter-attribute-group-select, .filter-feature-group-select').val(''); + // Country filters + this.$dropdown.find('.filter-has-holidays').prop('checked', false); + this.$dropdown.find('.filter-contains-states').prop('checked', false); + this.$dropdown.find('.filter-zone-select').val(''); + } + + this.refreshSearch(); + }, + + // Reset filters without triggering a search (used when switching entity types) + resetFiltersWithoutSearch: function() { + this.refineQuery = ''; + this.refineNegate = false; + this.filters = { + inStock: false, + discounted: false, + priceMin: null, + priceMax: null, + attributes: [], + features: [], + productCountMin: null, + productCountMax: null, + salesMin: null, + salesMax: null, + turnoverMin: null, + turnoverMax: null, + depth: null, + hasProducts: false, + hasDescription: false, + hasImage: false, + activeOnly: true, + attributeGroup: null, + featureGroup: null, + dateAddFrom: null, + dateAddTo: null, + lastProductFrom: null, + lastProductTo: null, + // Country-specific filters + hasHolidays: false, + containsStates: false, + zone: null + }; + + if (this.$dropdown) { + var trans = this.config.trans || {}; + this.$dropdown.find('.refine-input').val('').attr('placeholder', trans.refine_short || 'Refine...'); + this.$dropdown.find('.btn-clear-refine').hide(); + this.$dropdown.find('.btn-refine-negate').removeClass('active'); + this.$dropdown.find('.filter-in-stock').prop('checked', false); + this.$dropdown.find('.filter-discounted').prop('checked', false); + this.$dropdown.find('.filter-price-min').val(''); + this.$dropdown.find('.filter-price-max').val(''); + this.$dropdown.find('.filter-attr-chip').removeClass('active'); + this.$dropdown.find('.filter-feat-chip').removeClass('active'); + this.$dropdown.find('.filter-group-toggle').removeClass('active has-selection'); + this.$dropdown.find('.filter-row-values').hide(); + this.$dropdown.find('.filter-product-count-min, .filter-product-count-max').val(''); + this.$dropdown.find('.filter-sales-min, .filter-sales-max').val(''); + this.$dropdown.find('.filter-turnover-min, .filter-turnover-max').val(''); + this.$dropdown.find('.filter-date-add-from, .filter-date-add-to').val(''); + this.$dropdown.find('.filter-last-product-from, .filter-last-product-to').val(''); + this.$dropdown.find('.filter-depth-select').val(''); + this.$dropdown.find('.filter-has-products').prop('checked', false); + this.$dropdown.find('.filter-has-description').prop('checked', false); + this.$dropdown.find('.filter-has-image').prop('checked', false); + this.$dropdown.find('.filter-active-only').prop('checked', true); + this.$dropdown.find('.filter-attribute-group-select, .filter-feature-group-select').val(''); + // Country filters + this.$dropdown.find('.filter-has-holidays').prop('checked', false); + this.$dropdown.find('.filter-contains-states').prop('checked', false); + this.$dropdown.find('.filter-zone-select').val(''); + } + // Note: Does NOT call refreshSearch() - caller handles search/load + }, + + updateFilterPanelForEntity: function(entityType) { + if (!this.$dropdown) { + return; + } + + var $panel = this.$dropdown.find('.filter-panel'); + + // Hide all filter rows first + $panel.find('.filter-row').hide(); + + // Show/hide tree view option based on entity type + var $treeOption = this.$dropdown.find('.view-mode-select option.tree-view-option'); + if (entityType === 'categories' || entityType === 'cms_categories') { + $treeOption.prop('disabled', false).prop('hidden', false); + // Auto-switch to tree view for categories + if (this.viewMode !== 'tree') { + this.viewMode = 'tree'; + this.$dropdown.find('.view-mode-select').val('tree'); + this.$dropdown.removeClass('view-list view-cols-2 view-cols-3 view-cols-4 view-cols-5 view-cols-6 view-cols-7 view-cols-8').addClass('view-tree'); + this.loadCategoryTree(); + } else { + this.loadCategoryTree(); + } + } else { + $treeOption.prop('disabled', true).prop('hidden', true); + // If currently in tree mode, switch back to list + if (this.viewMode === 'tree') { + this.viewMode = 'list'; + this.$dropdown.find('.view-mode-select').val('list'); + this.$dropdown.removeClass('view-tree').addClass('view-list'); + } + } + + // Show entity-specific filter row (prepare visibility, but don't auto-expand panel) + if (entityType === 'products') { + // Prepare the correct rows to be visible when panel is shown + $panel.find('.filter-row-quick').show(); + // Show attribute/feature rows if we have cached data + if (this.filterableData) { + if (this.filterableData.attributes && this.filterableData.attributes.length > 0) { + this.$dropdown.find('.filter-row-attributes').show(); + } + if (this.filterableData.features && this.filterableData.features.length > 0) { + this.$dropdown.find('.filter-row-features').show(); + } + } + } else if (entityType === 'categories') { + $panel.find('.filter-row-entity-categories').show(); + } else if (entityType === 'manufacturers') { + $panel.find('.filter-row-entity-manufacturers').show(); + } else if (entityType === 'suppliers') { + $panel.find('.filter-row-entity-suppliers').show(); + } else if (entityType === 'attributes') { + $panel.find('.filter-row-entity-attributes').show(); + this.loadAttributeGroups(); + } else if (entityType === 'features') { + $panel.find('.filter-row-entity-features').show(); + } else if (entityType === 'cms') { + $panel.find('.filter-row-entity-cms').show(); + } else if (entityType === 'cms_categories') { + $panel.find('.filter-row-entity-cms-categories').show(); + } else if (entityType === 'countries') { + $panel.find('.filter-row-entity-countries').show(); + this.loadZonesForCountryFilter(); + } + }, + + loadAttributeGroups: function() { + var self = this; + var $select = this.$dropdown.find('.filter-attribute-group-select'); + + // Already loaded? + if ($select.find('option').length > 1) return; + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'getAttributeGroups', + trait: 'EntitySelector' + }, + success: function(response) { + if (response.success && response.groups) { + $.each(response.groups, function(i, group) { + $select.append(''); + }); + } + } + }); + }, + + loadFeatureGroups: function() { + var self = this; + var $select = this.$dropdown.find('.filter-feature-group-select'); + + // Already loaded? + if ($select.find('option').length > 1) return; + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'getFeatureGroups', + trait: 'EntitySelector' + }, + success: function(response) { + if (response.success && response.groups) { + $.each(response.groups, function(i, group) { + $select.append(''); + }); + } + } + }); + } + }; + +})(jQuery); + +/** + * Entity Selector - Filters Module + * Filter panel, filter state management + * @partial _filters.js + * + * EXTRACTION SOURCE: assets/js/admin/entity-selector.js + * Lines: 6605-6758 (filter methods) + * + * Contains: + * - clearFilters() - Reset all filters + * - resetFiltersWithoutSearch() - Reset without triggering search + * - updateFilterPanelForEntity() - Show/hide filters based on entity type + * - loadFilterableData() - Load attributes/features for filter panel + * - renderFilterDropdowns() - Render attribute/feature group toggles + * - showFilterGroupValues() - Show values for a filter group + * - hideFilterGroupValues() - Hide filter values row + * - updateFilterToggleStates() - Update toggle states based on selections + */ + +(function($) { + 'use strict'; + + window._EntitySelectorMixins = window._EntitySelectorMixins || {}; + + window._EntitySelectorMixins.filters = { + + clearFilters: function() { + this.refineQuery = ''; + this.refineNegate = false; + this.filters = { + inStock: false, + discounted: false, + priceMin: null, + priceMax: null, + attributes: [], + features: [], + productCountMin: null, + productCountMax: null, + salesMin: null, + salesMax: null, + turnoverMin: null, + turnoverMax: null, + depth: null, + hasProducts: false, + hasDescription: false, + hasImage: false, + activeOnly: true, + attributeGroup: null, + featureGroup: null, + dateAddFrom: null, + dateAddTo: null, + lastProductFrom: null, + lastProductTo: null, + // Country-specific filters + hasHolidays: false, + containsStates: false, + zone: null + }; + + if (this.$dropdown) { + var trans = this.config.trans || {}; + this.$dropdown.find('.refine-input').val(''); + this.$dropdown.find('.btn-refine-negate').removeClass('active'); + this.$dropdown.find('.filter-in-stock').prop('checked', false); + this.$dropdown.find('.filter-discounted').prop('checked', false); + this.$dropdown.find('.filter-price-min, .filter-price-max').val(''); + this.$dropdown.find('.filter-attr-chip, .filter-feat-chip').removeClass('active'); + this.$dropdown.find('.filter-product-count-min, .filter-product-count-max').val(''); + this.$dropdown.find('.filter-sales-min, .filter-sales-max').val(''); + this.$dropdown.find('.filter-depth-select').val(''); + this.$dropdown.find('.filter-has-products').prop('checked', false); + this.$dropdown.find('.filter-active-only').prop('checked', true); + // Country filters + this.$dropdown.find('.filter-has-holidays').prop('checked', false); + this.$dropdown.find('.filter-contains-states').prop('checked', false); + this.$dropdown.find('.filter-zone-select').val(''); + } + + this.refreshSearch(); + }, + + resetFiltersWithoutSearch: function() { + // Same as clearFilters but doesn't trigger search + // Used when switching entity types + this.refineQuery = ''; + this.refineNegate = false; + this.filters = { + inStock: false, + discounted: false, + priceMin: null, + priceMax: null, + attributes: [], + features: [], + productCountMin: null, + productCountMax: null, + salesMin: null, + salesMax: null, + turnoverMin: null, + turnoverMax: null, + depth: null, + hasProducts: false, + hasDescription: false, + hasImage: false, + activeOnly: true, + attributeGroup: null, + featureGroup: null, + dateAddFrom: null, + dateAddTo: null, + lastProductFrom: null, + lastProductTo: null, + // Country-specific filters + hasHolidays: false, + containsStates: false, + zone: null + }; + }, + + updateFilterPanelForEntity: function(entityType) { + if (!this.$dropdown) { + return; + } + + var $panel = this.$dropdown.find('.filter-panel'); + + // Hide all entity-specific filter rows + $panel.find('.filter-row').hide(); + + // Show filters for current entity type + $panel.find('.filter-row[data-entity="' + entityType + '"]').show(); + $panel.find('.filter-row-entity-' + entityType.replace('_', '-')).show(); + + // Show/hide tree view option based on entity type + var isCategory = (entityType === 'categories' || entityType === 'cms_categories'); + this.$dropdown.find('.tree-view-option').toggle(isCategory); + + // Default to tree view for categories (only if currently on list mode) + if (isCategory && this.viewMode === 'list') { + this.viewMode = 'tree'; + this.$dropdown.find('.view-mode-select').val('tree'); + this.$dropdown.removeClass('view-list view-cols-2 view-cols-3 view-cols-4 view-cols-5 view-cols-6 view-cols-7 view-cols-8').addClass('view-tree'); + } else if (!isCategory && this.viewMode === 'tree') { + // If switching away from categories while in tree mode, switch to list + this.viewMode = 'list'; + this.$dropdown.find('.view-mode-select').val('list'); + this.$dropdown.removeClass('view-tree view-cols-2 view-cols-3 view-cols-4 view-cols-5 view-cols-6 view-cols-7 view-cols-8').addClass('view-list'); + } + + // Load zones for countries filter + if (entityType === 'countries') { + this.loadZonesForCountryFilter(); + } + + // Update sort options for entity type + this.updateSortOptionsForEntity(entityType); + }, + + /** + * Show/hide sort options based on entity type + * Options with data-entities attribute are only shown for matching entities + */ + updateSortOptionsForEntity: function(entityType) { + if (!this.$dropdown) { + return; + } + + var $select = this.$dropdown.find('.sort-field-select'); + var currentValue = $select.val(); + var hasCurrentOption = false; + + $select.find('option').each(function() { + var $option = $(this); + var entities = $option.data('entities'); + + // Options without data-entities are universal (always shown) + if (!entities) { + $option.show(); + if ($option.val() === currentValue) { + hasCurrentOption = true; + } + return; + } + + // Check if this entity type is in the allowed list + var allowedEntities = entities.split(','); + var isAllowed = allowedEntities.indexOf(entityType) !== -1; + + $option.toggle(isAllowed); + + if (isAllowed && $option.val() === currentValue) { + hasCurrentOption = true; + } + }); + + // If current sort field is not available for this entity, reset to 'name' + if (!hasCurrentOption) { + $select.val('name'); + this.currentSort.field = 'name'; + } + }, + + loadFilterableData: function() { + var self = this; + + if (this.filterableData) { + this.renderFilterDropdowns(); + return; + } + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + data: { + ajax: 1, + action: 'getTargetFilterableAttributes', + trait: 'EntitySelector' + }, + dataType: 'json', + success: function(response) { + if (response.success && response.data) { + self.filterableData = response.data; + self.renderFilterDropdowns(); + } + } + }); + }, + + renderFilterDropdowns: function() { + if (!this.$dropdown || !this.filterableData) return; + + var self = this; + + // Render attribute group toggle buttons + var $attrContainer = this.$dropdown.find('.filter-attributes-container'); + $attrContainer.empty(); + + if (this.filterableData.attributes && this.filterableData.attributes.length > 0) { + this.filterableData.attributes.forEach(function(group) { + var html = ''; + $attrContainer.append(html); + }); + this.$dropdown.find('.filter-row-attributes').show(); + } + + // Render feature group toggle buttons + var $featContainer = this.$dropdown.find('.filter-features-container'); + $featContainer.empty(); + + if (this.filterableData.features && this.filterableData.features.length > 0) { + this.filterableData.features.forEach(function(group) { + var html = ''; + $featContainer.append(html); + }); + this.$dropdown.find('.filter-row-features').show(); + } + }, + + showFilterGroupValues: function(groupId, type) { + if (!this.filterableData) return; + + var self = this; + var groups = type === 'attribute' ? this.filterableData.attributes : this.filterableData.features; + var group = groups.find(function(g) { return g.id == groupId; }); + + if (!group) return; + + // Hide all values rows first, then show the correct one + this.$dropdown.find('.filter-row-values').hide(); + + // Target the correct values row based on type + var valuesRowClass = type === 'attribute' ? '.filter-row-attr-values' : '.filter-row-feat-values'; + var $filterRowValues = this.$dropdown.find(valuesRowClass); + var $valuesContainer = $filterRowValues.find('.filter-values-container'); + $valuesContainer.empty(); + + // Add group label + var html = '' + group.name + ':'; + + // Add chips + group.values.forEach(function(val) { + var isActive = type === 'attribute' + ? self.filters.attributes.indexOf(val.id) !== -1 + : self.filters.features.indexOf(val.id) !== -1; + var activeClass = isActive ? ' active' : ''; + var chipClass = type === 'attribute' ? 'filter-attr-chip' : 'filter-feat-chip'; + var colorStyle = val.color ? ' style="--chip-color: ' + val.color + '"' : ''; + var colorClass = val.color ? ' has-color' : ''; + + html += ''; + }); + + $valuesContainer.html(html); + + // Add close button as sibling (outside filter-values-container, inside filter-row-values) + $filterRowValues.find('.btn-close-values').remove(); + $filterRowValues.append(''); + $filterRowValues.show(); + + // Scroll into view if needed + var rowValues = $filterRowValues[0]; + if (rowValues) { + rowValues.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); + } + }, + + hideFilterGroupValues: function() { + this.$dropdown.find('.filter-row-values').hide(); + this.$dropdown.find('.filter-group-toggle').removeClass('active'); + }, + + updateFilterToggleStates: function() { + if (!this.$dropdown || !this.filterableData) return; + + var self = this; + + // Update attribute group toggles + if (this.filterableData.attributes) { + this.filterableData.attributes.forEach(function(group) { + var $toggle = self.$dropdown.find('.filter-group-toggle[data-group-id="' + group.id + '"][data-type="attribute"]'); + var hasActiveInGroup = group.values.some(function(val) { + return self.filters.attributes.indexOf(val.id) !== -1; + }); + $toggle.toggleClass('has-selection', hasActiveInGroup); + }); + } + + // Update feature group toggles + if (this.filterableData.features) { + this.filterableData.features.forEach(function(group) { + var $toggle = self.$dropdown.find('.filter-group-toggle[data-group-id="' + group.id + '"][data-type="feature"]'); + var hasActiveInGroup = group.values.some(function(val) { + return self.filters.features.indexOf(val.id) !== -1; + }); + $toggle.toggleClass('has-selection', hasActiveInGroup); + }); + } + }, + + /** + * Load zones for country filter dropdown + */ + loadZonesForCountryFilter: function() { + var self = this; + + if (this.zonesLoaded || !this.$dropdown) { + return; + } + + var $select = this.$dropdown.find('.filter-zone-select'); + if (!$select.length) { + return; + } + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'getZonesForFilter', + trait: 'EntitySelector' + }, + success: function(response) { + if (response.success && response.zones && response.zones.length > 0) { + var trans = self.config.trans || {}; + $select.empty(); + $select.append(''); + + response.zones.forEach(function(zone) { + $select.append(''); + }); + + self.zonesLoaded = true; + } + } + }); + } + }; + +})(jQuery); + +/** + * Entity Selector - Chips Module + * Entity chip rendering, selection management, and pattern tag handling + * @partial _chips.js + * + * EXTRACTION SOURCE: assets/js/admin/entity-selector.js + * + * Contains: + * - addSelection() / addSelectionNoUpdate() - Add entity chip to picker + * - removeSelection() - Remove chip and update state + * - updateChipsVisibility() - Show/hide based on count + * - loadExistingSelections() - Load saved values on init + * - collectPickerEntities() / loadPickerValues() - Entity loading helpers + * - Pattern tag methods: addPatternTag, getPatternTags, updateDraftTagCount + * - Single mode: getCurrentSingleSelection, showReplaceConfirmation + * - Count updates: updateConditionCount, updateGroupCounts, updateGroupTotalCount + */ + +(function($) { + 'use strict'; + + window._EntitySelectorMixins = window._EntitySelectorMixins || {}; + + window._EntitySelectorMixins.chips = { + + // ========================================================================= + // Selection Methods (Entity Chips) + // ========================================================================= + + addSelection: function($picker, id, name, data) { + this.addSelectionNoUpdate($picker, id, name, data); + var $chips = $picker.find('.entity-chips'); + this.updateChipsVisibility($chips); + }, + + addSelectionNoUpdate: function($picker, id, name, data) { + var $chips = $picker.find('.entity-chips'); + var $block = $picker.closest('.target-block'); + + // Check for global single mode (only ONE item across ALL entity types) + var globalMode = this.config.mode || 'multi'; + + if (globalMode === 'single') { + // Clear ALL selections in ALL blocks (across all entity types) + this.$wrapper.find('.entity-chips .entity-chip').remove(); + // Clear all selected states in dropdown + if (this.$dropdown) { + this.$dropdown.find('.dropdown-item.selected, .tree-item.selected').removeClass('selected'); + } + // Clear tab badges (since we're clearing other blocks) + this.$wrapper.find('.target-block-tab .tab-badge').remove(); + this.$wrapper.find('.target-block-tab').removeClass('has-data'); + } else { + // Check if this block is in per-block single mode + var blockMode = $block.data('mode') || 'multi'; + + // In per-block single mode, clear chips in THIS block only + if (blockMode === 'single') { + $chips.find('.entity-chip').remove(); + // Also deselect all items in dropdown + if (this.$dropdown) { + this.$dropdown.find('.dropdown-item.selected, .tree-item.selected').removeClass('selected'); + } + } + } + + if ($chips.find('.entity-chip[data-id="' + id + '"]').length) { + return; + } + + // Check if this is a country entity (for flag and holiday preview) + var blockType = $block.data('blockType') || ''; + var searchEntity = $picker.attr('data-search-entity') || blockType; + var isCountry = (searchEntity === 'countries'); + + var html = '' + this.esIcon('flag', 'flag-fallback').replace('>', ' style="display:none">') + ''; + } else if (data && data.image) { + html += ''; + } + + html += '' + this.escapeHtml(name) + ''; + + // Country: add holiday preview button + if (isCountry) { + html += ''; + } + + html += ''; + html += ''; + + $chips.append(html); + }, + + removeSelection: function($picker, id) { + var $chips = $picker.find('.entity-chips'); + $picker.find('.entity-chip[data-id="' + id + '"]').remove(); + this.updateChipsVisibility($chips); + }, + + updateChipsVisibility: function($chips) { + var self = this; + var trans = this.config.trans || {}; + var $picker = $chips.closest('.value-picker'); + var $allChips = $chips.find('.entity-chip'); + var totalCount = $allChips.length; + + // If no chips, remove the wrapper entirely + var $existingWrapper = $chips.closest('.chips-wrapper'); + if (totalCount === 0) { + if ($existingWrapper.length) { + // Move chips out of wrapper before removing + $existingWrapper.before($chips); + $existingWrapper.remove(); + } + return; + } + + // Ensure chips wrapper structure exists + this.ensureChipsWrapper($chips); + + var $wrapper = $chips.closest('.chips-wrapper'); + var $toolbar = $wrapper.find('.chips-toolbar'); + var $loadMore = $wrapper.find('.chips-load-more'); + + // Get current search filter + var searchTerm = $toolbar.find('.chips-search-input').val() || ''; + searchTerm = searchTerm.toLowerCase().trim(); + + // Filter and paginate chips + var visibleCount = 0; + var filteredCount = 0; + var isExpanded = $chips.hasClass('chips-expanded'); + var maxVisible = isExpanded ? 999999 : (this.maxVisibleChips || 12); + + $allChips.each(function() { + var $chip = $(this); + var chipName = ($chip.find('.chip-name').text() || '').toLowerCase(); + var matchesFilter = !searchTerm || chipName.indexOf(searchTerm) !== -1; + + $chip.removeClass('chip-filtered-out chip-paginated-out'); + + if (!matchesFilter) { + $chip.addClass('chip-filtered-out'); + } else { + filteredCount++; + if (filteredCount > maxVisible) { + $chip.addClass('chip-paginated-out'); + } else { + visibleCount++; + } + } + }); + + // Update toolbar (always show when we have chips) + $toolbar.addClass('has-chips'); + this.updateChipsToolbar($toolbar, totalCount, filteredCount, searchTerm); + + // Update load more select dropdown + var hiddenByPagination = filteredCount - visibleCount; + if (hiddenByPagination > 0 && !isExpanded) { + var loadText = trans.load || 'Load'; + var remainingText = (trans.remaining || '{count} remaining').replace('{count}', hiddenByPagination); + var loadMoreHtml = '' + loadText + '' + + '' + + '' + remainingText + ''; + $loadMore.html(loadMoreHtml).show(); + } else if (isExpanded && filteredCount > (this.maxVisibleChips || 12)) { + var collapseText = trans.collapse || 'Collapse'; + $loadMore.html( + '' + ).show(); + } else { + $loadMore.hide(); + } + }, + + ensureChipsWrapper: function($chips) { + // Check if already wrapped + if ($chips.closest('.chips-wrapper').length) { + return; + } + + var trans = this.config.trans || {}; + var $picker = $chips.closest('.value-picker'); + + // Create wrapper structure - integrated filter toolbar with sort + var wrapperHtml = '
' + + '
' + + '' + + '' + + '' + + '' + + '
' + + '' + + '
'; + + var $wrapper = $(wrapperHtml); + + // Insert wrapper before chips and move chips inside + $chips.before($wrapper); + $wrapper.find('.chips-toolbar').after($chips); + $wrapper.append($wrapper.find('.chips-load-more')); + + // Bind toolbar events + this.bindChipsToolbarEvents($wrapper); + }, + + bindChipsToolbarEvents: function($wrapper) { + var self = this; + var $chips = $wrapper.find('.entity-chips'); + var searchTimeout; + + // Search input + $wrapper.on('input', '.chips-search-input', function() { + clearTimeout(searchTimeout); + searchTimeout = setTimeout(function() { + // Collapse when searching to show filtered results from start + $chips.removeClass('chips-expanded'); + self.updateChipsVisibility($chips); + }, 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() || ''; + var $chipsToRemove; + + if (searchTerm.trim()) { + // Remove only filtered (visible) chips + $chipsToRemove = $chips.find('.entity-chip:not(.chip-filtered-out)'); + } else { + // Remove all chips + $chipsToRemove = $chips.find('.entity-chip'); + } + + $chipsToRemove.each(function() { + $(this).find('.chip-remove').trigger('click'); + }); + + // Clear search + $wrapper.find('.chips-search-input').val(''); + self.updateChipsVisibility($chips); + }); + + // 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) { + var trans = this.config.trans || {}; + var $count = $toolbar.find('.chips-count'); + var $clearBtn = $toolbar.find('.btn-chips-clear'); + var $clearText = $clearBtn.find('.clear-text'); + + // Update count display + if (searchTerm) { + $count.addClass('has-filter').html( + '' + filteredCount + '' + + '/' + + '' + totalCount + '' + ); + $clearText.text((trans.clear || 'Clear') + ' ' + filteredCount); + } else { + $count.removeClass('has-filter').html(totalCount); + $clearText.text(trans.clear_all || 'Clear all'); + } + + // Show/hide clear button + if (searchTerm && filteredCount === 0) { + $clearBtn.hide(); + } else if (totalCount > 0) { + $clearBtn.show(); + } else { + $clearBtn.hide(); + } + }, + + // ========================================================================= + // Loading/Initialization + // ========================================================================= + + loadExistingSelections: function() { + var self = this; + console.log('[EntitySelector] loadExistingSelections called for id:', this.config.id); + + // Collect all entity IDs to load, grouped by entity type + var entitiesToLoad = {}; // { entity_type: { ids: [], pickers: [] } } + + console.log('[EntitySelector] Looking for .selection-group in wrapper:', this.$wrapper.length ? 'found' : 'NOT FOUND'); + this.$wrapper.find('.selection-group').each(function() { + console.log('[EntitySelector] Found .selection-group, index:', $(this).data('groupIndex')); + var $group = $(this); + var $block = $group.closest('.target-block'); + var blockType = $block.data('blockType'); + + // Load include values + var $includePicker = $group.find('.include-picker'); + self.collectPickerEntities($includePicker, blockType, entitiesToLoad); + + // Enhance the include method select if not already enhanced + self.enhanceMethodSelect($group.find('.include-method-select')); + + // Load exclude values from each exclude row + $group.find('.exclude-row').each(function() { + var $excludeRow = $(this); + self.collectPickerEntities($excludeRow.find('.exclude-picker'), blockType, entitiesToLoad); + + // Enhance the exclude method select if not already enhanced + self.enhanceMethodSelect($excludeRow.find('.exclude-method-select')); + }); + + // Lock method selector if excludes exist + var hasExcludes = $group.find('.group-excludes.has-excludes').length > 0; + if (hasExcludes) { + self.updateMethodSelectorLock($group, true); + } + }); + + // Build bulk request: { entityType: [uniqueIds], ... } + var bulkRequest = {}; + var hasEntities = false; + + Object.keys(entitiesToLoad).forEach(function(entityType) { + var data = entitiesToLoad[entityType]; + if (data.ids.length === 0) return; + + // Deduplicate IDs + var uniqueIds = data.ids.filter(function(id, index, arr) { + return arr.indexOf(id) === index; + }); + + bulkRequest[entityType] = uniqueIds; + hasEntities = true; + }); + + // Skip AJAX if no entities to load + if (!hasEntities) { + console.log('[EntitySelector] No entities to load, skipping AJAX'); + return; + } + + console.log('[EntitySelector] Making bulk AJAX request for entities:', JSON.stringify(bulkRequest)); + + // Single bulk AJAX call for all entity types + $.ajax({ + url: self.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'getTargetEntitiesByIdsBulk', + trait: 'EntitySelector', + entities: JSON.stringify(bulkRequest) + }, + success: function(response) { + console.log('[EntitySelector] AJAX response:', response); + if (!response.success || !response.entities) { + console.log('[EntitySelector] Response failed or no entities'); + return; + } + try { + + // Process each entity type's results + Object.keys(entitiesToLoad).forEach(function(entityType) { + var data = entitiesToLoad[entityType]; + var entities = response.entities[entityType] || []; + + // Build a map of id -> entity for quick lookup + var entityMap = {}; + entities.forEach(function(entity) { + entityMap[entity.id] = entity; + }); + + // Update each picker that requested this entity type + data.pickers.forEach(function(pickerData) { + var $picker = pickerData.$picker; + var $chips = $picker.find('.entity-chips'); + var $dataInput = $picker.find('.include-values-data, .exclude-values-data'); + var validIds = []; + + // Check if this is a country entity + var isCountry = (entityType === 'countries'); + + // Replace loading chips with real data + pickerData.ids.forEach(function(id) { + var $loadingChip = $chips.find('.entity-chip-loading[data-id="' + id + '"]'); + if (entityMap[id]) { + var entity = entityMap[id]; + validIds.push(entity.id); + + // Create real chip + var html = '' + self.esIcon('flag', 'flag-fallback').replace('>', ' style="display:none">') + ''; + } else if (entity.image) { + html += ''; + } + + html += '' + self.escapeHtml(entity.name) + ''; + + // Country: add holiday preview button + if (isCountry) { + html += ''; + } + + html += ''; + html += ''; + + $loadingChip.replaceWith(html); + } else { + // Entity not found, remove loading chip + $loadingChip.remove(); + } + }); + + // Update chips visibility + self.updateChipsVisibility($chips); + + // If some entities were not found, update the hidden input + if (validIds.length !== pickerData.ids.length) { + $dataInput.val(JSON.stringify(validIds)); + self.serializeAllBlocks(); + } + + self.updateBlockStatus($picker.closest('.target-block')); + }); + }); + + // Update condition counts after chips are loaded (for holiday counts, etc.) + self.updateAllConditionCounts(); + + } catch (e) { + console.error('[EntitySelector] Error processing AJAX response:', e); + } + }, + error: function(xhr, status, error) { + console.error('[EntitySelector] AJAX request failed:', status, error, xhr.responseText); + } + }); + }, + + /** + * Collect entity IDs from a picker for bulk loading + * Also shows loading placeholders for entity_search types + */ + collectPickerEntities: function($picker, blockType, entitiesToLoad) { + console.log('[EntitySelector] collectPickerEntities called, blockType:', blockType, 'picker length:', $picker.length); + if (!$picker.length) { + console.log('[EntitySelector] Picker not found, returning'); + return; + } + + var self = this; + var $dataInput = $picker.find('.include-values-data, .exclude-values-data'); + console.log('[EntitySelector] Looking for values-data input, found:', $dataInput.length); + if (!$dataInput.length) { + console.log('[EntitySelector] No data input found, returning'); + return; + } + + var valueType = $picker.attr('data-value-type'); + var rawValue = $dataInput.val() || '[]'; + console.log('[EntitySelector] valueType:', valueType, 'rawValue:', rawValue); + + var values = []; + try { + values = JSON.parse(rawValue); + console.log('[EntitySelector] Parsed values:', values); + } catch (e) { + console.log('[EntitySelector] JSON parse error:', e); + return; + } + + // Handle non-entity types synchronously + if (valueType === 'multi_numeric_range') { + if (!Array.isArray(values) || values.length === 0) return; + + var $chipsContainer = $picker.find('.multi-range-chips'); + values.forEach(function(range) { + if (!range || (range.min === null && range.max === null)) return; + + var chipText = ''; + if (range.min !== null && range.max !== null) { + chipText = range.min + ' - ' + range.max; + } else if (range.min !== null) { + chipText = '≥ ' + range.min; + } else { + chipText = '≤ ' + range.max; + } + + var $chip = $('', { + class: 'range-chip', + 'data-min': range.min !== null ? range.min : '', + 'data-max': range.max !== null ? range.max : '' + }); + $chip.append($('', { class: 'range-chip-text', text: chipText })); + $chip.append($(''; + html += '' + this.escapeHtml(pattern) + ''; + html += ''; + html += '
'; + $chipsContainer.append(html); + }, + + /** + * Get all pattern tags from a wrapper + * Returns array of objects: { pattern: string, caseSensitive: boolean } + */ + getPatternTags: function($wrapper) { + var patterns = []; + // Exclude draft-tag which is the input field, not a saved pattern + $wrapper.find('.pattern-tag:not(.draft-tag)').each(function() { + var pattern = $(this).data('pattern'); + var caseSensitive = $(this).data('caseSensitive') === 1 || $(this).data('caseSensitive') === '1'; + if (pattern) { + patterns.push({ + pattern: pattern, + caseSensitive: caseSensitive + }); + } + }); + return patterns; + }, + + /** + * Update the match count displayed in the draft tag while typing + * Shows live preview with current case sensitivity setting + */ + updateDraftTagCount: function($draftTag, pattern, caseSensitive) { + var self = this; + var $matchCount = $draftTag.find('.pattern-match-count'); + var $countValue = $matchCount.find('.count-value'); + + // Get entity type from block + var $block = $draftTag.closest('.target-block'); + var entityType = $block.data('blockType') || 'products'; + + // Show loading - keep eye icon, update count value + $countValue.html(this.esIcon('progress_activity', 'es-spin')); + $matchCount.show(); + + // Store pattern for click handler + $matchCount.data('pattern', pattern); + $matchCount.data('caseSensitive', caseSensitive); + $matchCount.data('entityType', entityType); + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'countPatternMatches', + trait: 'EntitySelector', + pattern: pattern, + field: 'name', + entity_type: entityType, + case_sensitive: caseSensitive ? 1 : 0 + }, + success: function(response) { + if (response.success) { + var count = parseInt(response.count, 10) || 0; + $countValue.text(count); + $matchCount.show(); + // Add visual feedback based on count + $matchCount.removeClass('count-zero count-found'); + $matchCount.addClass(count === 0 ? 'count-zero' : 'count-found'); + // Store count for preview + $matchCount.data('count', count); + // Update group total count to reflect draft pattern in calculation + var $group = $draftTag.closest('.selection-group'); + if ($group.length) { + self.updateGroupTotalCount($group); + } + } else { + $countValue.text('?'); + $matchCount.show(); + } + }, + error: function() { + $countValue.text('?'); + $matchCount.show(); + } + }); + }, + + /** + * Update condition count with a pending pattern (typed but not yet added as tag) + * This shows a live preview of what the count would be if the user pressed Enter + */ + updateConditionCountWithPendingPattern: function($row, pendingPattern) { + var self = this; + var trans = this.config.trans || {}; + + // Find the count element - in method-selector-wrapper for include, in exclude-header-row for exclude + var $countEl = $row.find('.method-selector-wrapper > .condition-match-count, > .exclude-header-row > .condition-match-count').first(); + if (!$countEl.length) return; + + var isExclude = $row.hasClass('exclude-row'); + var $methodSelect = isExclude + ? $row.find('.exclude-method-select') + : $row.find('.include-method-select'); + + var method = $methodSelect.val(); + if (!method) { + $countEl.hide(); + return; + } + + var $picker = isExclude + ? $row.find('.exclude-picker') + : $row.find('.include-picker'); + + var valueType = $picker.data('valueType') || 'none'; + + // Only process for pattern value types + if (valueType !== 'pattern') { + return; + } + + // Get existing pattern tags + var values = this.getPatternTags($picker); + + // Add the pending pattern as a temporary tag (case-insensitive by default) + if (pendingPattern) { + values.push({ pattern: pendingPattern, caseSensitive: false }); + } + + if (values.length === 0) { + $countEl.hide(); + return; + } + + var $block = $row.closest('.target-block'); + var blockType = $block.data('blockType') || 'products'; + + // Show loading + $countEl.find('.preview-count').html(this.esIcon('progress_activity', 'es-spin')); + $countEl.removeClass('clickable no-matches').show(); + + // Store condition data on badge for popover + $countEl.data('conditionData', { + method: method, + values: values, + blockType: blockType, + isExclude: isExclude + }); + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'countConditionMatches', + trait: 'EntitySelector', + method: method, + values: JSON.stringify(values), + block_type: blockType + }, + success: function(response) { + if (response && response.success) { + var count = response.count || 0; + $countEl.removeClass('no-matches clickable'); + if (count === 0) { + $countEl.find('.preview-count').text(count); + $countEl.addClass('no-matches').show(); + } else { + $countEl.find('.preview-count').text(count); + $countEl.addClass('clickable').show(); + } + } else { + $countEl.hide().removeClass('clickable'); + } + }, + error: function() { + $countEl.hide().removeClass('clickable'); + } + }); + }, + + /** + * Fetch pattern match count via AJAX + */ + fetchPatternMatchCount: function($picker, pattern, $countEl) { + // Determine field type from method select + // Check if we're in an exclude row first, then fall back to include + var $excludeRow = $picker.closest('.exclude-row'); + var $methodSelect; + if ($excludeRow.length) { + $methodSelect = $excludeRow.find('.exclude-method-select'); + } else { + var $group = $picker.closest('.selection-group'); + $methodSelect = $group.find('.include-method-select'); + } + var method = $methodSelect.val() || ''; + var field = method.indexOf('reference') !== -1 ? 'reference' : 'name'; + + // Get entity type from block + var $block = $picker.closest('.target-block'); + var entityType = $block.data('blockType') || 'products'; + + // Show loading state + $countEl.find('.preview-count').html(this.esIcon('progress_activity', 'es-spin')); + $countEl.removeClass('clickable no-matches').show(); + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'countPatternMatches', + trait: 'EntitySelector', + pattern: pattern, + field: field, + entity_type: entityType, + case_sensitive: 0 + }, + success: function(response) { + if (response && response.success) { + var count = response.count || 0; + $countEl.find('.preview-count').text(count); + $countEl.removeClass('no-matches clickable').show(); + if (count === 0) { + $countEl.addClass('no-matches'); + } else { + $countEl.addClass('clickable'); + } + } else { + $countEl.hide(); + } + }, + error: function() { + $countEl.hide(); + } + }); + }, + + // ========================================================================= + // Picker Value Extraction + // ========================================================================= + + /** + * Get values from a picker based on its type + */ + getPickerValues: function($picker, valueType) { + switch (valueType) { + case 'entity_search': + var ids = []; + $picker.find('.entity-chip').each(function() { + var id = $(this).data('id'); + if (id) ids.push(id); + }); + return ids; + + case 'pattern': + var patternValues = this.getPatternTags($picker); + // Also include draft pattern if it has content (not yet added as tag) + var $draftPatternInput = $picker.find('.draft-tag .pattern-input'); + var draftPatternVal = $.trim($draftPatternInput.val()); + if (draftPatternVal) { + var draftCaseSens = $draftPatternInput.closest('.draft-tag').attr('data-case-sensitive') === '1'; + patternValues.push({ + pattern: draftPatternVal, + caseSensitive: draftCaseSens + }); + } + return patternValues; + + case 'numeric_range': + var min = $picker.find('.range-min-input').val(); + var max = $picker.find('.range-max-input').val(); + return { min: min || null, max: max || null }; + + case 'date_range': + var from = $picker.find('.date-from-input').val(); + var to = $picker.find('.date-to-input').val(); + return { from: from || null, to: to || null }; + + case 'select': + return [$picker.find('.select-value-input').val()]; + + case 'boolean': + return [true]; + + default: + return []; + } + }, + + // ========================================================================= + // Count/Status Updates + // ========================================================================= + + /** + * Fetch and update condition match count for a row (include or exclude) + */ + updateConditionCount: function($row) { + var self = this; + var trans = this.config.trans || {}; + + // Find the count element - in method-selector-wrapper for include, in exclude-header-row for exclude + var $countEl = $row.find('.method-selector-wrapper > .condition-match-count, > .exclude-header-row > .condition-match-count').first(); + if (!$countEl.length) return; + + // Determine if this is an include or exclude row + var isExclude = $row.hasClass('exclude-row'); + var $methodSelect = isExclude + ? $row.find('.exclude-method-select') + : $row.find('.include-method-select'); + + var method = $methodSelect.val(); + if (!method) { + $countEl.hide(); + return; + } + + // Get the picker and extract values + var $picker = isExclude + ? $row.find('.exclude-picker') + : $row.find('.include-picker'); + + var valueType = $picker.data('valueType') || 'none'; + var values = this.getPickerValues($picker, valueType); + + // Don't count if no values (except for boolean/all methods) + var hasNoValues = !values || + (Array.isArray(values) && values.length === 0) || + (typeof values === 'object' && !Array.isArray(values) && ( + // For combination_attributes, check if attributes object is empty + (valueType === 'combination_attributes' && values.attributes !== undefined && Object.keys(values.attributes).length === 0) || + // For other objects, check if completely empty + (valueType !== 'combination_attributes' && Object.keys(values).length === 0) + )); + if (valueType !== 'none' && valueType !== 'boolean' && hasNoValues) { + $countEl.hide(); + return; + } + + // Get block type + var $block = $row.closest('.target-block'); + var blockType = $block.data('blockType') || 'products'; + + // Show loading + $countEl.find('.preview-count').html(this.esIcon('progress_activity', 'es-spin')); + $countEl.removeClass('clickable no-matches').show(); + + // Store condition data on badge for popover + $countEl.data('conditionData', { + method: method, + values: values, + blockType: blockType, + isExclude: isExclude + }); + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'countConditionMatches', + trait: 'EntitySelector', + method: method, + values: JSON.stringify(values), + block_type: blockType + }, + success: function(response) { + if (response && response.success) { + var count = response.count || 0; + $countEl.removeClass('no-matches clickable'); + if (count === 0) { + $countEl.find('.preview-count').text(count); + $countEl.addClass('no-matches').show(); + } else { + // Show count, make clickable for preview popover + $countEl.find('.preview-count').text(count); + $countEl.addClass('clickable').show(); + } + } else { + $countEl.hide().removeClass('clickable'); + } + }, + error: function() { + $countEl.hide().removeClass('clickable'); + } + }); + }, + + /** + * Update all condition counts in a group + */ + updateGroupCounts: function($group) { + var self = this; + + // Update include count + var $include = $group.find('.group-include'); + if ($include.length) { + this.updateConditionCount($include); + } + + // Update each exclude row count + $group.find('.exclude-row').each(function() { + self.updateConditionCount($(this)); + }); + + // Update group total count (include - excludes) + this.updateGroupTotalCount($group); + }, + + /** + * Update the group total count badge (include - excludes) + * Also updates the limit input placeholder + */ + updateGroupTotalCount: function($group) { + var self = this; + var $block = $group.closest('.target-block'); + var blockType = $block.data('blockType') || 'products'; + var $badge = $group.find('.group-header .group-count-badge'); + var $limitInput = $group.find('.group-modifier-limit'); + + // Build group data for AJAX + var groupData = this.serializeGroup($group, blockType); + + // Check if include has valid data + if (!groupData.include || !groupData.include.method) { + $badge.hide(); + $limitInput.attr('placeholder', '–'); + return; + } + + // Show loading + $badge.html(this.esIcon('progress_activity', 'es-spin')).show(); + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'countGroupItems', + trait: 'EntitySelector', + group_data: JSON.stringify(groupData), + block_type: blockType + }, + success: function(response) { + if (response && response.success) { + var finalCount = response.final_count || 0; + var excludeCount = response.exclude_count || 0; + + // Update badge with eye icon and count + var badgeHtml = self.esIcon('visibility') + ' ' + finalCount; + if (excludeCount > 0) { + badgeHtml += ' (-' + excludeCount + ')'; + } + $badge.html(badgeHtml); + $badge.addClass('clickable').show(); + + // Store group data on badge for preview popover + $badge.data('groupData', groupData); + $badge.data('blockType', blockType); + $badge.data('finalCount', finalCount); + + // Update limit placeholder with the count + $limitInput.attr('placeholder', finalCount); + + // Also update the group-preview-badge count (apply limit if set) + var $previewBadge = $group.find('.group-preview-badge .preview-count'); + if ($previewBadge.length) { + var limit = parseInt($limitInput.val(), 10); + var displayCount = (limit > 0 && limit < finalCount) ? limit : finalCount; + $previewBadge.text(displayCount); + } + } else { + $badge.hide().removeClass('clickable'); + $limitInput.attr('placeholder', '–'); + } + }, + error: function() { + $badge.hide(); + $limitInput.attr('placeholder', '–'); + } + }); + }, + + /** + * Update all condition counts for all visible groups + */ + updateAllConditionCounts: function() { + var self = this; + this.$wrapper.find('.target-block.active .selection-group').each(function() { + self.updateGroupCounts($(this)); + }); + }, + + /** + * Fetch category names by IDs and add chips to the picker + * Used when adding selections from the tree modal + * @param {jQuery} $picker - Picker element + * @param {Array} ids - Category IDs to add + * @param {string} entityType - 'categories' or 'cms_categories' + * @param {Function} callback - Called when done + */ + fetchCategoryNamesAndAddChips: function($picker, ids, entityType, callback) { + var self = this; + + if (!ids || ids.length === 0) { + if (typeof callback === 'function') { + callback(); + } + return; + } + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'getTargetEntitiesByIds', + trait: 'EntitySelector', + entity_type: entityType, + ids: JSON.stringify(ids) + }, + success: function(response) { + if (response.success && response.entities) { + response.entities.forEach(function(entity) { + self.addSelectionNoUpdate($picker, entity.id, entity.name, entity); + }); + } + if (typeof callback === 'function') { + callback(); + } + }, + error: function() { + if (typeof callback === 'function') { + callback(); + } + } + }); + } + }; + +})(jQuery); + +/** + * Entity Selector - Groups Module + * Selection group management, serialization, block/tab management + * @partial _groups.js + * + * Contains: + * - Group management: addGroup, removeGroup, clearAllConditions + * - Block/Tab: switchToBlock, updateTabBadges, updateBlockStatus + * - Serialization: serializeGroup, serializeAllBlocks, getBlockGroups + * - Counts: fetchProductCount, updateHeaderTotalCount, updateAllConditionCounts + * - Excludes: addFirstExcludeRow, addExcludeRow, removeExcludeRow + * - Validation: validate, showValidationError, clearValidationError + */ + +(function($) { + 'use strict'; + + window._EntitySelectorMixins = window._EntitySelectorMixins || {}; + + window._EntitySelectorMixins.groups = { + + addGroup: function($block, blockType) { + var $container = $block.find('.groups-container'); + var trans = this.config.trans || {}; + var blockDef = this.config.blocks[blockType] || {}; + var methods = blockDef.selection_methods || {}; + + // Remove empty state + $container.find('.groups-empty-state').remove(); + + // Get next group index + var maxIndex = -1; + $container.find('.selection-group').each(function() { + var idx = parseInt($(this).data('groupIndex'), 10); + if (idx > maxIndex) maxIndex = idx; + }); + var groupIndex = maxIndex + 1; + + // Build method options with optgroups + var methodOptions = this.buildMethodOptions(methods, false); + + // Build exclude method options (no "all") with optgroups + var excludeMethodOptions = this.buildMethodOptions(methods, true); + + var defaultGroupName = (trans.group || 'Group') + ' ' + (groupIndex + 1); + var html = '
'; + + // Group header + html += '
'; + html += '' + this.esIcon('expand_less') + ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += '
'; + + // Group body (collapsible content) + html += '
'; + + // Include section + html += '
'; + html += '
'; + html += '
'; + html += ''; + html += '' + this.esIcon('visibility') + ' 0'; + html += ''; + html += '
'; + var noItemsText = trans.no_items_selected || 'No items selected - use search below'; + html += ''; + html += '
'; + html += '
'; + + // Excludes section (collapsed by default) + html += '
'; + html += ''; + html += '
'; + + // Group-level modifiers (limit & sort) + html += '
'; + html += ''; + html += '' + (trans.limit || 'Limit') + ''; + html += ''; + html += ''; + html += ''; + html += '' + (trans.sort || 'Sort') + ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += this.esIcon('visibility') + ' '; + html += ''; + html += '
'; + + html += '
'; // Close group-body + + html += '
'; // Close selection-group + + $container.append(html); + + // Find the new group and set method to "all" by default + var $newGroup = $container.find('.selection-group[data-group-index="' + groupIndex + '"]'); + + // Enhance the method select with styled dropdown + this.enhanceMethodSelect($newGroup.find('.include-method-select')); + + $newGroup.find('.include-method-select').val('all').trigger('change'); + + this.updateBlockStatus($block); + this.serializeAllBlocks(); + }, + + removeGroup: function($group, $block) { + $group.remove(); + + var $container = $block.find('.groups-container'); + var remainingGroups = $container.find('.selection-group').length; + + if (remainingGroups === 0) { + var emptyText = this.getEmptyStateText($block); + var emptyHtml = '
'; + emptyHtml += '' + emptyText + ''; + emptyHtml += '
'; + $container.html(emptyHtml); + } + + this.updateBlockStatus($block); + this.serializeAllBlocks(); + + // Update tab badges and header total count + this.updateTabBadges(); + }, + + clearAllConditions: function() { + var self = this; + + // Remove all groups from all blocks + this.$wrapper.find('.target-block').each(function() { + var $block = $(this); + var $container = $block.find('.groups-container'); + + // Remove all groups + $container.find('.selection-group').remove(); + + // Show empty state + var emptyText = self.getEmptyStateText($block); + var emptyHtml = '
'; + emptyHtml += '' + emptyText + ''; + emptyHtml += '
'; + $container.html(emptyHtml); + + self.updateBlockStatus($block); + }); + + // Update serialized data + this.serializeAllBlocks(); + + // Update tab badges and header count + this.updateTabBadges(); + + // Also update header total count immediately (since all cleared) + this.updateHeaderTotalCount(); + }, + + switchToBlock: function(blockType) { + // Update tabs + this.$wrapper.find('.target-block-tab').removeClass('active'); + this.$wrapper.find('.target-block-tab[data-block-type="' + blockType + '"]').addClass('active'); + + // Update blocks + this.$wrapper.find('.target-block').removeClass('active').hide(); + this.$wrapper.find('.target-block[data-block-type="' + blockType + '"]').addClass('active').show(); + + // Close dropdown if open + this.hideDropdown(); + }, + + updateTabBadges: function() { + var self = this; + + // Collect all block types with data and set loading state + var blockTypesWithData = []; + this.$wrapper.find('.target-block-tab').each(function() { + var $tab = $(this); + var blockType = $tab.data('blockType'); + var $block = self.$wrapper.find('.target-block[data-block-type="' + blockType + '"]'); + var groupCount = $block.find('.selection-group').length; + + // Update or add badge + var $badge = $tab.find('.tab-badge'); + if (groupCount > 0) { + // Show loading state first + if ($badge.length) { + $badge.addClass('loading').html(self.esIcon('progress_activity', 'es-spin')); + } else { + $tab.append('' + self.esIcon('progress_activity', 'es-spin') + ''); + } + $tab.addClass('has-data'); + blockTypesWithData.push(blockType); + } else if ($block.hasClass('custom-block')) { + // Custom blocks: check if any input/textarea/select has a non-empty value + var hasCustomValue = false; + $block.find('.custom-block-content').find('input, textarea, select').each(function() { + if ($(this).val() && $(this).val().trim() !== '') { + hasCustomValue = true; + return false; + } + }); + if (hasCustomValue) { + if ($badge.length) { + $badge.removeClass('loading').html(self.esIcon('check')); + } else { + $tab.append('' + self.esIcon('check') + ''); + } + $tab.addClass('has-data'); + } else { + $badge.remove(); + $tab.removeClass('has-data'); + } + } else { + $badge.remove(); + $tab.removeClass('has-data'); + } + }); + + // Update target switch state based on whether any data exists + this.updateTargetSwitchState(); + + // Fetch all counts in a single bulk request + if (blockTypesWithData.length > 0) { + this.fetchAllCounts(blockTypesWithData); + } + }, + + updateTargetSwitchState: function() { + var $switch = this.$wrapper.find('.prestashop-switch'); + if (!$switch.length) { + return; + } + + // Check if any block has data + var hasData = false; + this.$wrapper.find('.target-block').each(function() { + if ($(this).find('.selection-group').length > 0) { + hasData = true; + return false; // break + } + }); + + // Update switch: value="1" is "Everyone/All/None", value="0" is "Specific/Selected" + if (hasData) { + $switch.find('input[value="0"]').prop('checked', true); + } else { + $switch.find('input[value="1"]').prop('checked', true); + } + }, + + /** + * Fetch counts for all block types in a single bulk AJAX request + * @param {Array} blockTypes - Array of block type strings to fetch counts for + */ + fetchAllCounts: function(blockTypes) { + var self = this; + + // Read saved data from hidden input + var $hiddenInput = this.$wrapper.find('input[name="' + this.config.name + '"]'); + var savedData = {}; + try { + savedData = JSON.parse($hiddenInput.val() || '{}'); + } catch (e) { + savedData = {}; + } + + // Build conditions object for all requested block types + var conditions = {}; + blockTypes.forEach(function(blockType) { + var groups = (savedData[blockType] && savedData[blockType].groups) ? savedData[blockType].groups : []; + if (groups.length > 0) { + conditions[blockType] = { groups: groups }; + } + }); + + // If no valid conditions, remove loading spinners + if (Object.keys(conditions).length === 0) { + blockTypes.forEach(function(blockType) { + var $tab = self.$wrapper.find('.target-block-tab[data-block-type="' + blockType + '"]'); + $tab.find('.tab-badge').remove(); + $tab.removeClass('has-data'); + }); + return; + } + + // Single bulk AJAX request for all counts + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'previewEntitySelectorBulk', + trait: 'EntitySelector', + conditions: JSON.stringify(conditions) + }, + success: function(response) { + if (response.success && response.counts) { + // Update each tab with its count + Object.keys(response.counts).forEach(function(blockType) { + var count = response.counts[blockType]; + var $tab = self.$wrapper.find('.target-block-tab[data-block-type="' + blockType + '"]'); + var $badge = $tab.find('.tab-badge'); + + if ($badge.length) { + $badge.removeClass('loading').html(self.esIcon('visibility') + ' ' + count); + // Store preview data for later popover use + $tab.data('previewData', { count: count, success: true }); + } + }); + + // Handle any block types not in response (set count to 0 or remove badge) + blockTypes.forEach(function(blockType) { + if (!(blockType in response.counts)) { + var $tab = self.$wrapper.find('.target-block-tab[data-block-type="' + blockType + '"]'); + $tab.find('.tab-badge').remove(); + $tab.removeClass('has-data'); + } + }); + + self.updateHeaderTotalCount(); + } else { + console.error('[EntitySelector] Bulk preview failed:', response.error || 'Unknown error'); + // Remove loading spinners on error + blockTypes.forEach(function(blockType) { + var $tab = self.$wrapper.find('.target-block-tab[data-block-type="' + blockType + '"]'); + $tab.find('.tab-badge').remove(); + }); + } + }, + error: function(xhr, status, error) { + console.error('[EntitySelector] Bulk AJAX error:', status, error); + // Remove loading spinners on error + blockTypes.forEach(function(blockType) { + var $tab = self.$wrapper.find('.target-block-tab[data-block-type="' + blockType + '"]'); + $tab.find('.tab-badge').remove(); + }); + } + }); + }, + + /** + * Fetch count for a single block type (legacy, used for single updates) + */ + fetchProductCount: function(blockType, $tab) { + var self = this; + var data = {}; + + // Read from hidden input (contains full saved data or freshly serialized data) + var $hiddenInput = this.$wrapper.find('input[name="' + this.config.name + '"]'); + var savedData = {}; + try { + savedData = JSON.parse($hiddenInput.val() || '{}'); + } catch (e) { + savedData = {}; + } + + // Get groups for the requested block type + var groups = (savedData[blockType] && savedData[blockType].groups) ? savedData[blockType].groups : []; + + if (groups.length === 0) { + $tab.find('.tab-badge').remove(); + $tab.removeClass('has-data'); + $tab.removeData('previewData'); + return; + } + + // Show loading state + var $badge = $tab.find('.tab-badge'); + if (!$badge.length) { + $badge = $('' + this.esIcon('progress_activity', 'es-spin') + ''); + $tab.append($badge); + } else { + $badge.addClass('loading').html(this.esIcon('progress_activity', 'es-spin')); + } + $tab.addClass('has-data'); + + data[blockType] = { groups: groups }; + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'previewEntitySelector', + trait: 'EntitySelector', + conditions: JSON.stringify(data), + block_type: blockType, + limit: 10 + }, + success: function(response) { + if (response.success) { + var $badge = $tab.find('.tab-badge'); + $badge.removeClass('loading').html(self.esIcon('visibility') + ' ' + response.count); + + // Store preview data for popover + $tab.data('previewData', response); + + // Update header total count + self.updateHeaderTotalCount(); + } else { + console.error('[EntitySelector] Preview failed for', blockType, ':', response.error || 'Unknown error'); + $tab.find('.tab-badge').remove(); + } + }, + error: function(xhr, status, error) { + console.error('[EntitySelector] AJAX error for', blockType, ':', status, error); + $tab.find('.tab-badge').remove(); + self.updateHeaderTotalCount(); + } + }); + }, + + updateHeaderTotalCount: function() { + var self = this; + var total = 0; + + // Sum up all tab badge counts + this.$wrapper.find('.target-block-tab .tab-badge').each(function() { + var $badge = $(this); + if (!$badge.hasClass('loading')) { + var count = parseInt($badge.text(), 10); + if (!isNaN(count)) { + total += count; + } + } + }); + + var $totalBadge = this.$wrapper.find('.trait-total-count'); + if (total > 0) { + $totalBadge.find('.count-value').text(total); + $totalBadge.show(); + } else { + $totalBadge.hide(); + } + + // Update show-all toggle state + this.updateShowAllToggle(); + }, + + updateShowAllToggle: function() { + var $toggle = this.$wrapper.find('.trait-show-all-toggle'); + if (!$toggle.length) return; + + var $checkbox = $toggle.find('.show-all-checkbox'); + var hasData = this.$wrapper.find('.target-block-tab.has-data').length > 0; + + // If there's data, uncheck (not showing to all), otherwise check + $checkbox.prop('checked', !hasData); + }, + + updateBlockStatus: function($block) { + var $status = $block.find('.block-status'); + var blockType = $block.data('blockType'); + var blockDef = this.config.blocks[blockType] || {}; + var trans = this.config.trans || {}; + + var groups = this.getBlockGroups($block); + + if (groups.length === 0) { + var emptyMeansAll = this.config.emptyMeansAll !== false; + if (emptyMeansAll) { + $status.text((trans.all || 'All') + ' ' + (blockDef.entity_label_plural || 'items')); + } else { + $status.text(trans.nothing_selected || 'Nothing selected'); + } + } else { + $status.text(groups.length + ' ' + (groups.length === 1 ? (trans.group || 'group') : (trans.groups || 'groups'))); + } + }, + + getEmptyStateText: function($block) { + var blockType = $block.data('blockType'); + var blockMode = $block.data('mode') || 'multi'; + var blockDef = this.config.blocks[blockType] || {}; + var trans = this.config.trans || {}; + var emptyMeansAll = this.config.emptyMeansAll !== false; + + if (blockMode === 'single') { + return trans.no_item_selected || 'No item selected'; + } + + if (emptyMeansAll) { + return (trans.all || 'All') + ' ' + (blockDef.entity_label_plural || 'items') + ' ' + (trans.included || 'included'); + } + + return trans.nothing_selected || 'Nothing selected'; + }, + + serializeGroup: function($group, blockType) { + var self = this; + + // Include + var includeMethod = $group.find('.include-method-select').val() || 'all'; + var $includePicker = $group.find('.include-picker'); + var includeValues = this.getPickerValues($includePicker); + + // Excludes (multiple rows) + var excludes = []; + var $excludesSection = $group.find('.group-excludes.has-excludes'); + if ($excludesSection.length) { + $group.find('.exclude-row').each(function() { + var $row = $(this); + var excludeMethod = $row.find('.exclude-method-select').val() || null; + var $excludePicker = $row.find('.exclude-picker'); + var excludeValues = self.getPickerValues($excludePicker); + + if (excludeMethod && excludeValues && (Array.isArray(excludeValues) ? excludeValues.length > 0 : true)) { + excludes.push({ + method: excludeMethod, + values: excludeValues + }); + } + }); + } + + var groupData = { + include: { + method: includeMethod, + values: includeValues + } + }; + + if (excludes.length > 0) { + groupData.excludes = excludes; + } + + // Add modifiers if present + var modifiers = this.getGroupModifiers($group); + if (modifiers.limit || modifiers.sort_by) { + groupData.modifiers = modifiers; + } + + return groupData; + }, + + serializeAllBlocks: function($changedRow) { + var self = this; + var data = {}; + + console.log('[EntitySelector] serializeAllBlocks called'); + + this.$wrapper.find('.target-block').each(function() { + var $block = $(this); + var blockType = $block.data('blockType'); + var groups = self.getBlockGroups($block); + + console.log('[EntitySelector] Block:', blockType, 'Groups:', groups.length); + + // Groups now contain their own modifiers, no block-level modifiers + if (groups.length > 0) { + data[blockType] = { groups: groups }; + } + + self.updateBlockStatus($block); + }); + + // Update hidden input first + var $input = this.$wrapper.find('input[name="' + this.config.name + '"]'); + var jsonData = JSON.stringify(data); + + console.log('[EntitySelector] Hidden input name:', this.config.name); + console.log('[EntitySelector] Hidden input found:', $input.length); + console.log('[EntitySelector] Serialized data:', jsonData.substring(0, 500)); + + $input.val(jsonData); + + // Then update tab badges (reads from hidden input) + this.updateTabBadges(); + + // Debounced update of condition count - only for changed row if specified + if (this.countUpdateTimeout) { + clearTimeout(this.countUpdateTimeout); + } + this.countUpdateTimeout = setTimeout(function() { + if ($changedRow && $changedRow.length) { + // Update the specific row that changed + self.updateConditionCount($changedRow); + // Also update the group total count (include - excludes) + var $group = $changedRow.closest('.selection-group'); + if ($group.length) { + self.updateGroupTotalCount($group); + } + } else { + // Fallback: update all counts (initial load, structure changes) + self.updateAllConditionCounts(); + } + }, 500); + }, + + getBlockGroups: function($block) { + var self = this; + var groups = []; + + $block.find('.selection-group').each(function() { + var $group = $(this); + + // Include + var includeMethod = $group.find('.include-method-select').val() || 'all'; + var $includePicker = $group.find('.include-picker'); + var includeValues = self.getPickerValues($includePicker); + + // Skip groups with invalid include conditions (e.g., "specific products" with none selected) + if (!self.isConditionValid(includeMethod, includeValues, $includePicker)) { + return true; // continue to next group + } + + // Excludes (multiple rows) - only include valid ones + var excludes = []; + var $excludesSection = $group.find('.group-excludes.has-excludes'); + if ($excludesSection.length) { + $group.find('.exclude-row').each(function() { + var $row = $(this); + var excludeMethod = $row.find('.exclude-method-select').val() || null; + var $excludePicker = $row.find('.exclude-picker'); + var excludeValues = self.getPickerValues($excludePicker); + + // Only include valid exclude conditions + if (excludeMethod && self.isConditionValid(excludeMethod, excludeValues, $excludePicker)) { + excludes.push({ + method: excludeMethod, + values: excludeValues + }); + } + }); + } + + var groupData = { + include: { + method: includeMethod, + values: includeValues + } + }; + + // Group name (optional, for organizational purposes) + var groupName = $.trim($group.attr('data-group-name') || ''); + if (groupName) { + groupData.name = groupName; + } + + if (excludes.length > 0) { + groupData.excludes = excludes; + } + + // Group-level modifiers + var modifiers = self.getGroupModifiers($group); + if (modifiers.limit || modifiers.sort_by) { + groupData.modifiers = modifiers; + } + + groups.push(groupData); + }); + + return groups; + }, + + getGroupModifiers: function($group) { + var limit = $group.find('.group-modifier-limit').val(); + var sortBy = $group.find('.group-modifier-sort').val() || 'sales'; + var $sortDirBtn = $group.find('.group-modifiers .btn-sort-dir'); + var sortDir = $sortDirBtn.data('dir') || 'DESC'; + + return { + limit: limit ? parseInt(limit, 10) : null, + sort_by: sortBy || null, + sort_dir: sortDir || 'DESC' + }; + }, + + getPickerValues: function($picker) { + var valueType = $picker.attr('data-value-type') || 'entity_search'; + var values = []; + + switch (valueType) { + case 'entity_search': + $picker.find('.entity-chip').each(function() { + var id = $(this).data('id'); + values.push(isNaN(id) ? id : Number(id)); + }); + break; + + case 'pattern': + values = this.getPatternTags($picker); + // Also include draft pattern if it has content (not yet added as tag) + var $draftInput = $picker.find('.draft-tag .pattern-input'); + var draftPattern = $.trim($draftInput.val()); + if (draftPattern) { + var draftCaseSensitive = $draftInput.closest('.draft-tag').attr('data-case-sensitive') === '1'; + values.push({ + pattern: draftPattern, + caseSensitive: draftCaseSensitive + }); + } + break; + + case 'numeric_range': + var min = $picker.find('.range-min-input').val(); + var max = $picker.find('.range-max-input').val(); + if (min !== '' || max !== '') { + values = { + min: min !== '' ? parseFloat(min) : null, + max: max !== '' ? parseFloat(max) : null + }; + } + break; + + case 'date_range': + var from = $picker.find('.date-from-input').val(); + var to = $picker.find('.date-to-input').val(); + if (from || to) { + values = { + from: from || null, + to: to || null + }; + } + break; + + case 'select': + var selectVal = $picker.find('.select-value-input').val(); + if (selectVal) { + values = [selectVal]; + } + break; + + case 'boolean': + values = [true]; + break; + + case 'multi_numeric_range': + var ranges = []; + $picker.find('.range-chip').each(function() { + var $chip = $(this); + var minVal = $chip.data('min'); + var maxVal = $chip.data('max'); + ranges.push({ + min: minVal !== '' && minVal !== undefined ? parseFloat(minVal) : null, + max: maxVal !== '' && maxVal !== undefined ? parseFloat(maxVal) : null + }); + }); + if (ranges.length > 0) { + values = ranges; + } + break; + + case 'multi_select_tiles': + $picker.find('.tile-option.selected').each(function() { + values.push($(this).data('value')); + }); + break; + + case 'combination_attributes': + // Returns object: { mode: 'products'|'combinations', attributes: { groupId: [valueId1, valueId2], ... } } + var combAttrs = {}; + $picker.find('.comb-attr-value.selected').each(function() { + var groupId = $(this).data('groupId').toString(); + var valueId = $(this).data('valueId'); + if (!combAttrs[groupId]) { + combAttrs[groupId] = []; + } + combAttrs[groupId].push(valueId); + }); + if (Object.keys(combAttrs).length > 0) { + // Get mode: from radio if toggle exists, otherwise from config + var $combPicker = $picker.find('.combination-attributes-picker'); + var configMode = $combPicker.data('combinationMode') || this.config.combinationMode || 'products'; + var combMode; + if (configMode === 'toggle') { + combMode = $picker.find('.comb-mode-radio:checked').val() || 'products'; + } else { + combMode = configMode; + } + values = { + mode: combMode, + attributes: combAttrs + }; + } + break; + } + + return values; + }, + + isConditionValid: function(method, values, $picker) { + // 'all' method never needs values + if (method === 'all') { + return true; + } + + // Boolean methods are always valid (the value is implicit true) + var valueType = $picker.attr('data-value-type') || 'entity_search'; + if (valueType === 'boolean') { + return true; + } + + // For other methods, check if values are meaningful + if (Array.isArray(values)) { + return values.length > 0; + } + + // For object values (ranges, combination_attributes), check if meaningful + if (typeof values === 'object' && values !== null) { + // Special handling for combination_attributes: { mode, attributes } + if (valueType === 'combination_attributes' && values.attributes !== undefined) { + return Object.keys(values.attributes).length > 0; + } + // For ranges and other objects, check if at least one bound is set + return Object.keys(values).some(function(key) { + return values[key] !== null && values[key] !== ''; + }); + } + + return false; + }, + + /** + * Update all condition counts using a single bulk AJAX request + */ + updateAllConditionCounts: function() { + var self = this; + var conditions = {}; + var conditionElements = {}; + var conditionIndex = 0; + + // Collect all conditions from all active groups + this.$wrapper.find('.target-block.active .selection-group').each(function() { + var $group = $(this); + var $block = $group.closest('.target-block'); + var blockType = $block.data('blockType') || 'products'; + + // Process include row + var $include = $group.find('.group-include'); + if ($include.length) { + var includeData = self.getConditionData($include, blockType); + if (includeData) { + var id = 'c' + conditionIndex++; + conditions[id] = includeData.condition; + conditionElements[id] = includeData.$countEl; + } + } + + // Process exclude rows + $group.find('.exclude-row').each(function() { + var excludeData = self.getConditionData($(this), blockType); + if (excludeData) { + var id = 'c' + conditionIndex++; + conditions[id] = excludeData.condition; + conditionElements[id] = excludeData.$countEl; + } + }); + }); + + // If no conditions, nothing to do + if (Object.keys(conditions).length === 0) { + return; + } + + // Make single bulk AJAX request + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'countConditionMatchesBulk', + trait: 'EntitySelector', + conditions: JSON.stringify(conditions) + }, + success: function(response) { + if (response && response.success && response.counts) { + // Update each count element with its result + Object.keys(response.counts).forEach(function(id) { + var count = response.counts[id] || 0; + var $countEl = conditionElements[id]; + if ($countEl && $countEl.length) { + $countEl.removeClass('no-matches clickable'); + if (count === 0) { + $countEl.find('.preview-count').text(count); + $countEl.addClass('no-matches').show(); + } else { + $countEl.find('.preview-count').text(count); + $countEl.addClass('clickable').show(); + } + } + }); + } + // Note: Group totals are updated on-demand when user interacts, not on initial load + }, + error: function() { + // Hide all count elements on error + Object.keys(conditionElements).forEach(function(id) { + var $countEl = conditionElements[id]; + if ($countEl && $countEl.length) { + $countEl.hide().removeClass('clickable'); + } + }); + } + }); + }, + + /** + * Extract condition data from a row for bulk counting + */ + getConditionData: function($row, blockType) { + console.log('[getConditionData] Called with blockType:', blockType); + var $countEl = $row.find('.method-selector-wrapper > .condition-match-count, > .exclude-header-row .condition-match-count').first(); + console.log('[getConditionData] $countEl found:', $countEl.length); + if (!$countEl.length) return null; + + var isExclude = $row.hasClass('exclude-row'); + var $methodSelect = isExclude + ? $row.find('.exclude-method-select') + : $row.find('.include-method-select'); + + var method = $methodSelect.val(); + console.log('[getConditionData] method:', method); + if (!method) { + $countEl.hide(); + return null; + } + + var $picker = isExclude + ? $row.find('.exclude-picker') + : $row.find('.include-picker'); + console.log('[getConditionData] $picker found:', $picker.length, 'data-value-type attr:', $picker.attr('data-value-type')); + + var valueType = $picker.data('valueType') || $picker.attr('data-value-type') || 'none'; + console.log('[getConditionData] valueType:', valueType); + + // Special case: "All countries" method - needs separate handling for holidays + if (valueType === 'none' && blockType === 'countries' && method === 'all') { + console.log('[getConditionData] All countries detected - triggering updateConditionCount'); + // Trigger separate update for this special case (uses nested AJAX) + var self = this; + setTimeout(function() { + self.updateConditionCount($row, blockType); + }, 0); + return null; // Skip bulk processing, handled separately + } + + // Special case: Specific countries with entity_search - needs holiday counting, not entity counting + var searchEntity = $picker.attr('data-search-entity') || ''; + if (blockType === 'countries' && valueType === 'entity_search' && searchEntity === 'countries') { + console.log('[getConditionData] Specific countries detected - triggering updateConditionCount for holiday counting'); + var self = this; + setTimeout(function() { + self.updateConditionCount($row, blockType); + }, 0); + return null; // Skip bulk processing, handled separately + } + + // Hide badge for other "all" type methods (valueType === 'none') since they don't filter + if (valueType === 'none') { + $countEl.hide(); + return null; + } + + var values = this.getPickerValues($picker, valueType); + + // Don't count if no values (except for boolean methods) + var hasNoValues = !values || + (Array.isArray(values) && values.length === 0) || + (typeof values === 'object' && !Array.isArray(values) && ( + (valueType === 'combination_attributes' && values.attributes !== undefined && Object.keys(values.attributes).length === 0) || + (valueType !== 'combination_attributes' && Object.keys(values).length === 0) + )); + if (valueType !== 'boolean' && hasNoValues) { + $countEl.hide(); + return null; + } + + // Show loading spinner + $countEl.find('.preview-count').html(this.esIcon('progress_activity', 'es-spin')); + $countEl.removeClass('clickable no-matches').show(); + + // Store condition data on badge for popover + $countEl.data('conditionData', { + method: method, + values: values, + blockType: blockType, + isExclude: isExclude + }); + + return { + condition: { + method: method, + values: values, + block_type: blockType + }, + $countEl: $countEl + }; + }, + + updateGroupCounts: function($group) { + var self = this; + var $block = $group.closest('.target-block'); + var blockType = $block.data('blockType') || 'products'; + + // Update include count + var $include = $group.find('.group-include'); + if ($include.length) { + this.updateConditionCount($include, blockType); + } + + // Update each exclude row count + $group.find('.exclude-row').each(function() { + self.updateConditionCount($(this), blockType); + }); + + // Update group total count (include - excludes) + this.updateGroupTotalCount($group); + }, + + /** + * Update a single condition count (used for individual updates after user changes) + */ + updateConditionCount: function($row, blockType) { + var self = this; + + var $countEl = $row.find('.method-selector-wrapper > .condition-match-count, > .exclude-header-row .condition-match-count').first(); + if (!$countEl.length) { + console.log('[updateConditionCount] No $countEl found'); + return; + } + + var isExclude = $row.hasClass('exclude-row'); + var $methodSelect = isExclude + ? $row.find('.exclude-method-select') + : $row.find('.include-method-select'); + + var method = $methodSelect.val(); + console.log('[updateConditionCount] method:', method, 'isExclude:', isExclude); + if (!method) { + console.log('[updateConditionCount] No method, hiding badge'); + $countEl.hide(); + return; + } + + var $picker = isExclude + ? $row.find('.exclude-picker') + : $row.find('.include-picker'); + + var valueType = $picker.data('valueType') || 'none'; + var searchEntity = $picker.attr('data-search-entity') || ''; + + // Get the block type to check if this is a countries block + if (!blockType) { + var $block = $row.closest('.target-block'); + blockType = $block.data('blockType') || 'products'; + } + + console.log('[updateConditionCount] valueType:', valueType, 'searchEntity:', searchEntity, 'blockType:', blockType, 'method:', method); + + // Special case: "All countries" method - fetch holidays for all countries + if (valueType === 'none' && blockType === 'countries' && method === 'all') { + console.log('[updateConditionCount] All countries method - fetching all country holidays'); + $countEl.find('.preview-count').html(this.esIcon('progress_activity', 'es-spin')); + $countEl.removeClass('clickable no-matches country-holidays').show(); + + // First fetch all active country IDs, then get holidays + $.ajax({ + url: self.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'searchTargetEntities', + trait: 'EntitySelector', + entity_type: 'countries', + query: '', + limit: 500 + }, + success: function(response) { + var items = response.results || response.items || []; + if (response && response.success && items.length > 0) { + var allCountryIds = items.map(function(item) { return item.id; }); + console.log('[updateConditionCount] Found', allCountryIds.length, 'countries, fetching holidays'); + + // Store condition data for click handler + $countEl.data('conditionData', { + method: method, + values: allCountryIds, + blockType: blockType, + isExclude: isExclude, + isCountryHolidays: true, + countryIds: allCountryIds, + isAllCountries: true + }); + + // Now fetch holiday count + $.ajax({ + url: self.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'getHolidaysForCountries', + trait: 'EntitySelector', + country_ids: allCountryIds.join(','), + count_only: 1 + }, + success: function(holidayResponse) { + console.log('[updateConditionCount] All countries holiday response:', holidayResponse); + if (holidayResponse && holidayResponse.success) { + var count = holidayResponse.total_count || 0; + $countEl.removeClass('no-matches clickable'); + $countEl.addClass('country-holidays'); + if (count === 0) { + $countEl.find('.preview-count').text(count); + $countEl.addClass('no-matches').show(); + } else { + $countEl.find('.preview-count').text(count); + $countEl.addClass('clickable').show(); + } + $countEl.data('countriesInfo', holidayResponse.countries || []); + } else { + $countEl.hide().removeClass('clickable'); + } + }, + error: function() { + $countEl.hide().removeClass('clickable'); + } + }); + } else { + $countEl.hide().removeClass('clickable'); + } + }, + error: function() { + $countEl.hide().removeClass('clickable'); + } + }); + return; + } + + // Hide badge for other "all" type methods (valueType === 'none') since they don't filter + if (valueType === 'none') { + console.log('[updateConditionCount] valueType is none, hiding badge'); + $countEl.hide(); + return; + } + + var values = this.getPickerValues($picker, valueType); + + var hasNoValues = !values || + (Array.isArray(values) && values.length === 0) || + (typeof values === 'object' && !Array.isArray(values) && ( + (valueType === 'combination_attributes' && values.attributes !== undefined && Object.keys(values.attributes).length === 0) || + (valueType !== 'combination_attributes' && Object.keys(values).length === 0) + )); + if (valueType !== 'boolean' && hasNoValues) { + $countEl.hide(); + return; + } + + if (!blockType) { + var $block = $row.closest('.target-block'); + blockType = $block.data('blockType') || 'products'; + } + + // Check if this is a country selection - show holiday count instead + var isCountrySelection = (searchEntity === 'countries' && valueType === 'entity_search'); + console.log('[updateConditionCount] isCountrySelection:', isCountrySelection, 'values:', values); + + $countEl.find('.preview-count').html(this.esIcon('progress_activity', 'es-spin')); + $countEl.removeClass('clickable no-matches country-holidays').show(); + + // For countries, fetch holiday count + if (isCountrySelection && Array.isArray(values) && values.length > 0) { + console.log('[updateConditionCount] Fetching holiday count for countries:', values); + $countEl.data('conditionData', { + method: method, + values: values, + blockType: blockType, + isExclude: isExclude, + isCountryHolidays: true, + countryIds: values + }); + + $.ajax({ + url: self.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'getHolidaysForCountries', + trait: 'EntitySelector', + country_ids: values.join(','), + count_only: 1 + }, + success: function(response) { + console.log('[updateConditionCount] Holiday response:', response); + if (response && response.success) { + var count = response.total_count || 0; + console.log('[updateConditionCount] Holiday count:', count); + $countEl.removeClass('no-matches clickable'); + $countEl.addClass('country-holidays'); + if (count === 0) { + $countEl.find('.preview-count').text(count); + $countEl.addClass('no-matches').show(); + } else { + $countEl.find('.preview-count').text(count); + $countEl.addClass('clickable').show(); + } + // Store countries info for popover + $countEl.data('countriesInfo', response.countries || []); + } else { + console.log('[updateConditionCount] Holiday response failed:', response); + $countEl.hide().removeClass('clickable'); + } + }, + error: function() { + $countEl.hide().removeClass('clickable'); + } + }); + return; + } + + // Default: count entities + $countEl.data('conditionData', { + method: method, + values: values, + blockType: blockType, + isExclude: isExclude + }); + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'countConditionMatches', + trait: 'EntitySelector', + method: method, + values: JSON.stringify(values), + block_type: blockType + }, + success: function(response) { + if (response && response.success) { + var count = response.count || 0; + $countEl.removeClass('no-matches clickable'); + if (count === 0) { + $countEl.find('.preview-count').text(count); + $countEl.addClass('no-matches').show(); + } else { + $countEl.find('.preview-count').text(count); + $countEl.addClass('clickable').show(); + } + } else { + $countEl.hide().removeClass('clickable'); + } + }, + error: function() { + $countEl.hide().removeClass('clickable'); + } + }); + }, + + updateGroupTotalCount: function($group) { + var self = this; + var $block = $group.closest('.target-block'); + var blockType = $block.data('blockType') || 'products'; + var $badge = $group.find('.group-header .group-count-badge'); + var $limitInput = $group.find('.group-modifier-limit'); + + // Build group data for AJAX + var groupData = this.serializeGroup($group, blockType); + + // Check if include has valid data + if (!groupData.include || !groupData.include.method) { + $badge.hide(); + $limitInput.attr('placeholder', '–'); + return; + } + + // Show loading + $badge.html(this.esIcon('progress_activity', 'es-spin')).show(); + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'countGroupItems', + trait: 'EntitySelector', + group_data: JSON.stringify(groupData), + block_type: blockType + }, + success: function(response) { + if (response && response.success) { + var finalCount = response.final_count || 0; + var excludeCount = response.exclude_count || 0; + + // Update badge with eye icon and count + var badgeHtml = self.esIcon('visibility') + ' ' + finalCount; + if (excludeCount > 0) { + badgeHtml += ' (-' + excludeCount + ')'; + } + $badge.html(badgeHtml); + $badge.addClass('clickable').show(); + + // Store group data on badge for preview popover + $badge.data('groupData', groupData); + $badge.data('blockType', blockType); + $badge.data('finalCount', finalCount); + + // Update limit placeholder with the count + $limitInput.attr('placeholder', finalCount); + + // Also update the group-preview-badge count (apply limit if set) + var $previewBadge = $group.find('.group-preview-badge .preview-count'); + if ($previewBadge.length) { + var limit = parseInt($limitInput.val(), 10); + var displayCount = (limit > 0 && limit < finalCount) ? limit : finalCount; + $previewBadge.text(displayCount); + } + } else { + $badge.hide().removeClass('clickable'); + $limitInput.attr('placeholder', '–'); + } + }, + error: function() { + $badge.hide(); + $limitInput.attr('placeholder', '–'); + } + }); + }, + + // Exclude row management + addFirstExcludeRow: function($group, $block) { + var $excludesDiv = $group.find('.group-excludes'); + var trans = this.config.trans || {}; + + // Build the full excludes structure with first row + var html = '
'; + html += '' + this.esIcon('block') + ' ' + (trans.except || 'EXCEPT') + ''; + html += '
'; + + html += '
'; + html += this.buildExcludeRowHtml($block, 0); + html += '
'; + + html += ''; + + $excludesDiv.addClass('has-excludes').html(html); + + // Enhance the first exclude method select with styled dropdown + var $firstRow = $excludesDiv.find('.exclude-row[data-exclude-index="0"]'); + var $firstSelect = $firstRow.find('.exclude-method-select'); + this.enhanceMethodSelect($firstSelect); + + // Update method info placeholder for initial selection + var blockType = $block.data('blockType'); + var initialMethod = $firstSelect.val(); + this.updateMethodInfoPlaceholder($firstRow.find('.method-selector-wrapper'), initialMethod, blockType); + + this.updateMethodSelectorLock($group, true); + this.serializeAllBlocks(); + }, + + addExcludeRow: function($group, $block) { + var $container = $group.find('.exclude-rows-container'); + + // Get next exclude index + var maxIndex = -1; + $container.find('.exclude-row').each(function() { + var idx = parseInt($(this).data('excludeIndex'), 10); + if (idx > maxIndex) maxIndex = idx; + }); + var excludeIndex = maxIndex + 1; + + var html = this.buildExcludeRowHtml($block, excludeIndex); + $container.append(html); + + // Enhance the exclude method select with styled dropdown + var $newRow = $container.find('.exclude-row[data-exclude-index="' + excludeIndex + '"]'); + var $newSelect = $newRow.find('.exclude-method-select'); + this.enhanceMethodSelect($newSelect); + + // Update method info placeholder for initial selection + var blockType = $block.data('blockType'); + var initialMethod = $newSelect.val(); + this.updateMethodInfoPlaceholder($newRow.find('.method-selector-wrapper'), initialMethod, blockType); + + this.serializeAllBlocks(); + }, + + buildExcludeRowHtml: function($block, excludeIndex) { + var blockType = $block.data('blockType'); + var blockDef = this.config.blocks[blockType] || {}; + var methods = blockDef.selection_methods || {}; + var trans = this.config.trans || {}; + + // Build exclude method options with optgroups (no "all") + var excludeMethodOptions = this.buildMethodOptions(methods, true); + + // Find first non-all method for default search entity + var firstSearchEntity = blockType; + var firstValueType = 'entity_search'; + $.each(methods, function(methodKey, methodDef) { + if (methodKey === 'all') return true; + firstSearchEntity = methodDef.search_entity || blockType; + firstValueType = methodDef.value_type || 'entity_search'; + return false; // break + }); + + var html = '
'; + + // Header row with method select wrapped in method-selector-wrapper (same as include) + html += '
'; + html += '
'; + html += ''; + html += '' + this.esIcon('visibility') + ' 0'; + html += ''; + html += '
'; + html += ''; + html += '
'; + + // Value picker based on first method's value type + html += this.buildValuePickerHtml('exclude', firstValueType, firstSearchEntity, methods); + + html += '
'; + + return html; + }, + + removeExcludeRow: function($excludeRow, $group, $block) { + var $container = $group.find('.exclude-rows-container'); + var trans = this.config.trans || {}; + + $excludeRow.remove(); + + // Check if there are remaining exclude rows + var remainingRows = $container.find('.exclude-row').length; + + if (remainingRows === 0) { + // Remove entire excludes section and show "Add exceptions" button + var $excludesDiv = $group.find('.group-excludes'); + $excludesDiv.removeClass('has-excludes').html( + '' + ); + // Unlock the method selector since no excludes exist + this.updateMethodSelectorLock($group, false); + } + + this.serializeAllBlocks(); + }, + + // Method options building + buildMethodOptions: function(methods, excludeAll) { + var self = this; + var trans = this.config.trans || {}; + var html = ''; + + // Group labels + var groupLabels = { + 'select_by': trans.select_by || 'Select by...', + 'filter_by': trans.filter_by || 'Filter by...' + }; + + // Separate methods by group + var grouped = {}; + var ungrouped = {}; + + $.each(methods, function(methodKey, methodDef) { + if (excludeAll && methodKey === 'all') return true; // skip + + var group = methodDef.group || ''; + if (group) { + if (!grouped[group]) { + grouped[group] = {}; + } + grouped[group][methodKey] = methodDef; + } else { + ungrouped[methodKey] = methodDef; + } + }); + + // Render ungrouped options first + $.each(ungrouped, function(methodKey, methodDef) { + html += self.buildMethodOption(methodKey, methodDef); + }); + + // Render grouped options with optgroups + $.each(grouped, function(groupKey, groupMethods) { + var groupLabel = groupLabels[groupKey] || groupKey.replace(/_/g, ' '); + html += ''; + $.each(groupMethods, function(methodKey, methodDef) { + html += self.buildMethodOption(methodKey, methodDef); + }); + html += ''; + }); + + return html; + }, + + buildMethodOption: function(methodKey, methodDef) { + var html = '")}this.$dropdown.find(".dropdown-actions").show(),this.$dropdown.find(".btn-show-history").removeClass("active");var x=this.activeGroup?this.activeGroup.searchEntity:null,_=x&&this.getSearchHistory(x).length>0;this.$dropdown.find(".btn-show-history").prop("disabled",!_)},loadSearchHistory:function(){try{var e=localStorage.getItem(this.searchHistoryKey);this.searchHistory=e?JSON.parse(e):{}}catch(e){this.searchHistory={}}},saveSearchHistory:function(){try{localStorage.setItem(this.searchHistoryKey,JSON.stringify(this.searchHistory))}catch(e){}},addToSearchHistory:function(e,t){if(t&&!(t.length<2)){this.searchHistory[e]||(this.searchHistory[e]=[]);var i=this.searchHistory[e],a=i.indexOf(t);-1!==a&&i.splice(a,1),i.unshift(t),i.length>this.searchHistoryMax&&(i=i.slice(0,this.searchHistoryMax)),this.searchHistory[e]=i,this.saveSearchHistory()}},removeFromSearchHistory:function(e,t){if(this.searchHistory[e]){var i=this.searchHistory[e].indexOf(t);-1!==i&&(this.searchHistory[e].splice(i,1),this.saveSearchHistory())}},getSearchHistory:function(e){return this.searchHistory[e]||[]},showSearchHistory:function(e){var t=this.getSearchHistory(e),i=this.config.trans||{},a=this.$dropdown.find(".dropdown-results");if(this.$dropdown.find(".results-count").text(i.recent_searches||"Recent searches"),this.$dropdown.find(".dropdown-actions").hide(),this.$dropdown.find(".filter-panel").removeClass("show"),this.$dropdown.find(".btn-toggle-filters").removeClass("active"),this.$dropdown.find(".results-header").hide(),t.length){for(var s='
',o=0;o',s+='',s+=''+this.escapeHtml(n)+"",s+='",s+="
"}s+="",a.html(s),this.$dropdown.addClass("show")}else this.performSearch()},refreshSearch:function(){"tree"!==this.viewMode?(this.searchOffset=0,this.loadMoreCount=20,this.$dropdown&&(this.$dropdown.find(".load-more-select").val("20"),this.$dropdown.find('.load-more-select option[data-all="true"]').remove()),this.performSearch(!1)):this.filterCategoryTree(this.searchQuery||"")},clearFilters:function(){if(this.refineQuery="",this.refineNegate=!1,this.filters={inStock:!1,discounted:!1,priceMin:null,priceMax:null,attributes:[],features:[],productCountMin:null,productCountMax:null,salesMin:null,salesMax:null,turnoverMin:null,turnoverMax:null,depth:null,hasProducts:!1,hasDescription:!1,hasImage:!1,activeOnly:!0,attributeGroup:null,featureGroup:null,dateAddFrom:null,dateAddTo:null,lastProductFrom:null,lastProductTo:null,hasHolidays:!1,containsStates:!1,zone:null},this.$dropdown){var e=this.config.trans||{};this.$dropdown.find(".refine-input").val("").attr("placeholder",e.refine_short||"Refine..."),this.$dropdown.find(".btn-clear-refine").hide(),this.$dropdown.find(".btn-refine-negate").removeClass("active"),this.$dropdown.find(".filter-in-stock").prop("checked",!1),this.$dropdown.find(".filter-discounted").prop("checked",!1),this.$dropdown.find(".filter-price-min").val(""),this.$dropdown.find(".filter-price-max").val(""),this.$dropdown.find(".filter-attr-chip").removeClass("active"),this.$dropdown.find(".filter-feat-chip").removeClass("active"),this.$dropdown.find(".filter-group-toggle").removeClass("active has-selection"),this.$dropdown.find(".filter-row-values").hide(),this.$dropdown.find(".filter-product-count-min, .filter-product-count-max").val(""),this.$dropdown.find(".filter-sales-min, .filter-sales-max").val(""),this.$dropdown.find(".filter-turnover-min, .filter-turnover-max").val(""),this.$dropdown.find(".filter-date-add-from, .filter-date-add-to").val(""),this.$dropdown.find(".filter-last-product-from, .filter-last-product-to").val(""),this.$dropdown.find(".filter-depth-select").val(""),this.$dropdown.find(".filter-has-products").prop("checked",!1),this.$dropdown.find(".filter-has-description").prop("checked",!1),this.$dropdown.find(".filter-has-image").prop("checked",!1),this.$dropdown.find(".filter-active-only").prop("checked",!0),this.$dropdown.find(".filter-attribute-group-select, .filter-feature-group-select").val(""),this.$dropdown.find(".filter-has-holidays").prop("checked",!1),this.$dropdown.find(".filter-contains-states").prop("checked",!1),this.$dropdown.find(".filter-zone-select").val("")}this.refreshSearch()},resetFiltersWithoutSearch:function(){if(this.refineQuery="",this.refineNegate=!1,this.filters={inStock:!1,discounted:!1,priceMin:null,priceMax:null,attributes:[],features:[],productCountMin:null,productCountMax:null,salesMin:null,salesMax:null,turnoverMin:null,turnoverMax:null,depth:null,hasProducts:!1,hasDescription:!1,hasImage:!1,activeOnly:!0,attributeGroup:null,featureGroup:null,dateAddFrom:null,dateAddTo:null,lastProductFrom:null,lastProductTo:null,hasHolidays:!1,containsStates:!1,zone:null},this.$dropdown){var e=this.config.trans||{};this.$dropdown.find(".refine-input").val("").attr("placeholder",e.refine_short||"Refine..."),this.$dropdown.find(".btn-clear-refine").hide(),this.$dropdown.find(".btn-refine-negate").removeClass("active"),this.$dropdown.find(".filter-in-stock").prop("checked",!1),this.$dropdown.find(".filter-discounted").prop("checked",!1),this.$dropdown.find(".filter-price-min").val(""),this.$dropdown.find(".filter-price-max").val(""),this.$dropdown.find(".filter-attr-chip").removeClass("active"),this.$dropdown.find(".filter-feat-chip").removeClass("active"),this.$dropdown.find(".filter-group-toggle").removeClass("active has-selection"),this.$dropdown.find(".filter-row-values").hide(),this.$dropdown.find(".filter-product-count-min, .filter-product-count-max").val(""),this.$dropdown.find(".filter-sales-min, .filter-sales-max").val(""),this.$dropdown.find(".filter-turnover-min, .filter-turnover-max").val(""),this.$dropdown.find(".filter-date-add-from, .filter-date-add-to").val(""),this.$dropdown.find(".filter-last-product-from, .filter-last-product-to").val(""),this.$dropdown.find(".filter-depth-select").val(""),this.$dropdown.find(".filter-has-products").prop("checked",!1),this.$dropdown.find(".filter-has-description").prop("checked",!1),this.$dropdown.find(".filter-has-image").prop("checked",!1),this.$dropdown.find(".filter-active-only").prop("checked",!0),this.$dropdown.find(".filter-attribute-group-select, .filter-feature-group-select").val(""),this.$dropdown.find(".filter-has-holidays").prop("checked",!1),this.$dropdown.find(".filter-contains-states").prop("checked",!1),this.$dropdown.find(".filter-zone-select").val("")}},updateFilterPanelForEntity:function(e){if(this.$dropdown){var t=this.$dropdown.find(".filter-panel");t.find(".filter-row").hide();var i=this.$dropdown.find(".view-mode-select option.tree-view-option");"categories"===e||"cms_categories"===e?(i.prop("disabled",!1).prop("hidden",!1),"tree"!==this.viewMode?(this.viewMode="tree",this.$dropdown.find(".view-mode-select").val("tree"),this.$dropdown.removeClass("view-list view-cols-2 view-cols-3 view-cols-4 view-cols-5 view-cols-6 view-cols-7 view-cols-8").addClass("view-tree"),this.loadCategoryTree()):this.loadCategoryTree()):(i.prop("disabled",!0).prop("hidden",!0),"tree"===this.viewMode&&(this.viewMode="list",this.$dropdown.find(".view-mode-select").val("list"),this.$dropdown.removeClass("view-tree").addClass("view-list"))),"products"===e?(t.find(".filter-row-quick").show(),this.filterableData&&(this.filterableData.attributes&&this.filterableData.attributes.length>0&&this.$dropdown.find(".filter-row-attributes").show(),this.filterableData.features&&this.filterableData.features.length>0&&this.$dropdown.find(".filter-row-features").show())):"categories"===e?t.find(".filter-row-entity-categories").show():"manufacturers"===e?t.find(".filter-row-entity-manufacturers").show():"suppliers"===e?t.find(".filter-row-entity-suppliers").show():"attributes"===e?(t.find(".filter-row-entity-attributes").show(),this.loadAttributeGroups()):"features"===e?t.find(".filter-row-entity-features").show():"cms"===e?t.find(".filter-row-entity-cms").show():"cms_categories"===e?t.find(".filter-row-entity-cms-categories").show():"countries"===e&&(t.find(".filter-row-entity-countries").show(),this.loadZonesForCountryFilter())}},loadAttributeGroups:function(){var t=this,i=this.$dropdown.find(".filter-attribute-group-select");i.find("option").length>1||e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"getAttributeGroups",trait:"EntitySelector"},success:function(a){a.success&&a.groups&&e.each(a.groups,function(e,a){i.append('")})}})},loadFeatureGroups:function(){var t=this,i=this.$dropdown.find(".filter-feature-group-select");i.find("option").length>1||e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"getFeatureGroups",trait:"EntitySelector"},success:function(a){a.success&&a.groups&&e.each(a.groups,function(e,a){i.append('")})}})}}}(jQuery),function(e){"use strict";window._EntitySelectorMixins=window._EntitySelectorMixins||{},window._EntitySelectorMixins.filters={clearFilters:function(){this.refineQuery="",this.refineNegate=!1,this.filters={inStock:!1,discounted:!1,priceMin:null,priceMax:null,attributes:[],features:[],productCountMin:null,productCountMax:null,salesMin:null,salesMax:null,turnoverMin:null,turnoverMax:null,depth:null,hasProducts:!1,hasDescription:!1,hasImage:!1,activeOnly:!0,attributeGroup:null,featureGroup:null,dateAddFrom:null,dateAddTo:null,lastProductFrom:null,lastProductTo:null,hasHolidays:!1,containsStates:!1,zone:null},this.$dropdown&&(this.config.trans,this.$dropdown.find(".refine-input").val(""),this.$dropdown.find(".btn-refine-negate").removeClass("active"),this.$dropdown.find(".filter-in-stock").prop("checked",!1),this.$dropdown.find(".filter-discounted").prop("checked",!1),this.$dropdown.find(".filter-price-min, .filter-price-max").val(""),this.$dropdown.find(".filter-attr-chip, .filter-feat-chip").removeClass("active"),this.$dropdown.find(".filter-product-count-min, .filter-product-count-max").val(""),this.$dropdown.find(".filter-sales-min, .filter-sales-max").val(""),this.$dropdown.find(".filter-depth-select").val(""),this.$dropdown.find(".filter-has-products").prop("checked",!1),this.$dropdown.find(".filter-active-only").prop("checked",!0),this.$dropdown.find(".filter-has-holidays").prop("checked",!1),this.$dropdown.find(".filter-contains-states").prop("checked",!1),this.$dropdown.find(".filter-zone-select").val("")),this.refreshSearch()},resetFiltersWithoutSearch:function(){this.refineQuery="",this.refineNegate=!1,this.filters={inStock:!1,discounted:!1,priceMin:null,priceMax:null,attributes:[],features:[],productCountMin:null,productCountMax:null,salesMin:null,salesMax:null,turnoverMin:null,turnoverMax:null,depth:null,hasProducts:!1,hasDescription:!1,hasImage:!1,activeOnly:!0,attributeGroup:null,featureGroup:null,dateAddFrom:null,dateAddTo:null,lastProductFrom:null,lastProductTo:null,hasHolidays:!1,containsStates:!1,zone:null}},updateFilterPanelForEntity:function(e){if(this.$dropdown){var t=this.$dropdown.find(".filter-panel");t.find(".filter-row").hide(),t.find('.filter-row[data-entity="'+e+'"]').show(),t.find(".filter-row-entity-"+e.replace("_","-")).show();var i="categories"===e||"cms_categories"===e;this.$dropdown.find(".tree-view-option").toggle(i),i&&"list"===this.viewMode?(this.viewMode="tree",this.$dropdown.find(".view-mode-select").val("tree"),this.$dropdown.removeClass("view-list view-cols-2 view-cols-3 view-cols-4 view-cols-5 view-cols-6 view-cols-7 view-cols-8").addClass("view-tree")):i||"tree"!==this.viewMode||(this.viewMode="list",this.$dropdown.find(".view-mode-select").val("list"),this.$dropdown.removeClass("view-tree view-cols-2 view-cols-3 view-cols-4 view-cols-5 view-cols-6 view-cols-7 view-cols-8").addClass("view-list")),"countries"===e&&this.loadZonesForCountryFilter(),this.updateSortOptionsForEntity(e)}},updateSortOptionsForEntity:function(t){if(this.$dropdown){var i=this.$dropdown.find(".sort-field-select"),a=i.val(),s=!1;i.find("option").each(function(){var i=e(this),o=i.data("entities");if(!o)return i.show(),void(i.val()===a&&(s=!0));var n=-1!==o.split(",").indexOf(t);i.toggle(n),n&&i.val()===a&&(s=!0)}),s||(i.val("name"),this.currentSort.field="name")}},loadFilterableData:function(){var t=this;this.filterableData?this.renderFilterDropdowns():e.ajax({url:this.config.ajaxUrl,type:"POST",data:{ajax:1,action:"getTargetFilterableAttributes",trait:"EntitySelector"},dataType:"json",success:function(e){e.success&&e.data&&(t.filterableData=e.data,t.renderFilterDropdowns())}})},renderFilterDropdowns:function(){if(this.$dropdown&&this.filterableData){var e=this,t=e.config.trans&&e.config.trans.preview||"Preview",i=this.$dropdown.find(".filter-attributes-container");i.empty(),this.filterableData.attributes&&this.filterableData.attributes.length>0&&(this.filterableData.attributes.forEach(function(a){var s='';s+='",s+='",s+="",i.append(s)}),this.$dropdown.find(".filter-row-attributes").show());var a=this.$dropdown.find(".filter-features-container");a.empty(),this.filterableData.features&&this.filterableData.features.length>0&&(this.filterableData.features.forEach(function(i){var s='';s+='",s+='",s+="",a.append(s)}),this.$dropdown.find(".filter-row-features").show())}},showFilterGroupValues:function(e,t){if(this.filterableData){var i=this,a=("attribute"===t?this.filterableData.attributes:this.filterableData.features).find(function(t){return t.id==e});if(a){this.$dropdown.find(".filter-row-values").hide();var s="attribute"===t?".filter-row-attr-values":".filter-row-feat-values",o=this.$dropdown.find(s),n=o.find(".filter-values-container");n.empty();var r=''+a.name+":";a.values.forEach(function(a){var s=("attribute"===t?-1!==i.filters.attributes.indexOf(a.id):-1!==i.filters.features.indexOf(a.id))?" active":"",o="attribute"===t?"filter-attr-chip":"filter-feat-chip",n=a.color?' style="--chip-color: '+a.color+'"':"",l=a.color?" has-color":"";r+='',r+='",r+='",r+=""}),n.html(r),o.find(".btn-close-values").remove(),o.append(''),o.show();var l=o[0];l&&l.scrollIntoView({behavior:"smooth",block:"nearest"})}}},hideFilterGroupValues:function(){this.$dropdown.find(".filter-row-values").hide(),this.$dropdown.find(".filter-group-toggle").removeClass("active")},updateFilterToggleStates:function(){if(this.$dropdown&&this.filterableData){var e=this;this.filterableData.attributes&&this.filterableData.attributes.forEach(function(t){var i=e.$dropdown.find('.filter-group-toggle[data-group-id="'+t.id+'"][data-type="attribute"]'),a=t.values.some(function(t){return-1!==e.filters.attributes.indexOf(t.id)});i.toggleClass("has-selection",a)}),this.filterableData.features&&this.filterableData.features.forEach(function(t){var i=e.$dropdown.find('.filter-group-toggle[data-group-id="'+t.id+'"][data-type="feature"]'),a=t.values.some(function(t){return-1!==e.filters.features.indexOf(t.id)});i.toggleClass("has-selection",a)})}},loadZonesForCountryFilter:function(){var t=this;if(!this.zonesLoaded&&this.$dropdown){var i=this.$dropdown.find(".filter-zone-select");i.length&&e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"getZonesForFilter",trait:"EntitySelector"},success:function(e){if(e.success&&e.zones&&e.zones.length>0){var a=t.config.trans||{};i.empty(),i.append('"),e.zones.forEach(function(e){i.append('")}),t.zonesLoaded=!0}}})}}}}(jQuery),function(e){"use strict";window._EntitySelectorMixins=window._EntitySelectorMixins||{},window._EntitySelectorMixins.chips={addSelection:function(e,t,i,a){this.addSelectionNoUpdate(e,t,i,a);var s=e.find(".entity-chips");this.updateChipsVisibility(s)},addSelectionNoUpdate:function(e,t,i,a){var s=e.find(".entity-chips"),o=e.closest(".target-block");if("single"===(this.config.mode||"multi")?(this.$wrapper.find(".entity-chips .entity-chip").remove(),this.$dropdown&&this.$dropdown.find(".dropdown-item.selected, .tree-item.selected").removeClass("selected"),this.$wrapper.find(".target-block-tab .tab-badge").remove(),this.$wrapper.find(".target-block-tab").removeClass("has-data")):"single"===(o.data("mode")||"multi")&&(s.find(".entity-chip").remove(),this.$dropdown&&this.$dropdown.find(".dropdown-item.selected, .tree-item.selected").removeClass("selected")),!s.find('.entity-chip[data-id="'+t+'"]').length){var n=o.data("blockType")||"",r="countries"===(e.attr("data-search-entity")||n),l='':a&&a.image&&(l+=''),l+=''+this.escapeHtml(i)+"",r&&(l+=''),l+='',l+="",s.append(l)}},removeSelection:function(e,t){var i=e.find(".entity-chips");e.find('.entity-chip[data-id="'+t+'"]').remove(),this.updateChipsVisibility(i)},updateChipsVisibility:function(t){var i=this.config.trans||{},a=(t.closest(".value-picker"),t.find(".entity-chip")),s=a.length,o=t.closest(".chips-wrapper");if(0!==s){this.ensureChipsWrapper(t);var n=t.closest(".chips-wrapper"),r=n.find(".chips-toolbar"),l=n.find(".chips-load-more"),c=r.find(".chips-search-input").val()||"";c=c.toLowerCase().trim();var d=0,p=0,u=t.hasClass("chips-expanded"),h=u?999999:this.maxVisibleChips||12;a.each(function(){var t=e(this),i=(t.find(".chip-name").text()||"").toLowerCase(),a=!c||-1!==i.indexOf(c);t.removeClass("chip-filtered-out chip-paginated-out"),a?++p>h?t.addClass("chip-paginated-out"):d++:t.addClass("chip-filtered-out")}),r.addClass("has-chips"),this.updateChipsToolbar(r,s,p,c);var f=p-d;if(f>0&&!u){var v=i.load||"Load",m=(i.remaining||"{count} remaining").replace("{count}",f),g=''+v+''+m+"";l.html(g).show()}else if(u&&p>(this.maxVisibleChips||12)){var b=i.collapse||"Collapse";l.html('").show()}else l.hide()}else o.length&&(o.before(t),o.remove())},ensureChipsWrapper:function(t){if(!t.closest(".chips-wrapper").length){var i=this.config.trans||{},a=(t.closest(".value-picker"),'
'),s=e(a);t.before(s),s.find(".chips-toolbar").after(t),s.append(s.find(".chips-load-more")),this.bindChipsToolbarEvents(s)}},bindChipsToolbarEvents:function(t){var i,a=this,s=t.find(".entity-chips");t.on("input",".chips-search-input",function(){clearTimeout(i),i=setTimeout(function(){s.removeClass("chips-expanded"),a.updateChipsVisibility(s)},150)}),t.on("change",".chips-sort-select",function(){var t=e(this).val();a.sortChips(s,t)}),t.on("click",".btn-chips-clear",function(){((t.find(".chips-search-input").val()||"").trim()?s.find(".entity-chip:not(.chip-filtered-out)"):s.find(".entity-chip")).each(function(){e(this).find(".chip-remove").trigger("click")}),t.find(".chips-search-input").val(""),a.updateChipsVisibility(s)}),t.on("change",".load-more-select",function(){var t=e(this).val();"all"===t?(s.addClass("chips-expanded"),a.maxVisibleChips=999999):a.maxVisibleChips=(a.maxVisibleChips||12)+parseInt(t,10),a.updateChipsVisibility(s)}),t.on("click",".btn-collapse-chips",function(){s.removeClass("chips-expanded"),a.maxVisibleChips=12,a.updateChipsVisibility(s)})},sortChips:function(t,i){var a=t.find(".entity-chip");if(!(a.length<2)){var s=a.toArray().sort(function(t,a){var s=e(t),o=e(a);switch(i){case"name_asc":var n=(s.find(".chip-name").text()||"").toLowerCase(),r=(o.find(".chip-name").text()||"").toLowerCase();return n.localeCompare(r);case"name_desc":var l=(s.find(".chip-name").text()||"").toLowerCase();return(o.find(".chip-name").text()||"").toLowerCase().localeCompare(l);default:return 0}});e.each(s,function(e,i){t.append(i)}),this.updateChipsVisibility(t)}},updateChipsToolbar:function(e,t,i,a){var s=this.config.trans||{},o=e.find(".chips-count"),n=e.find(".btn-chips-clear"),r=n.find(".clear-text");a?(o.addClass("has-filter").html(''+i+'/'+t+""),r.text((s.clear||"Clear")+" "+i)):(o.removeClass("has-filter").html(t),r.text(s.clear_all||"Clear all")),a&&0===i?n.hide():t>0?n.show():n.hide()},loadExistingSelections:function(){var t=this,i={};this.$wrapper.find(".selection-group").each(function(){var a=e(this),s=a.closest(".target-block").data("blockType"),o=a.find(".include-picker");t.collectPickerEntities(o,s,i),t.enhanceMethodSelect(a.find(".include-method-select")),a.find(".exclude-row").each(function(){var a=e(this);t.collectPickerEntities(a.find(".exclude-picker"),s,i),t.enhanceMethodSelect(a.find(".exclude-method-select"))}),a.find(".group-excludes.has-excludes").length>0&&t.updateMethodSelectorLock(a,!0)});var a={},s=!1;if(Object.keys(i).forEach(function(e){var t=i[e];if(0!==t.ids.length){var o=t.ids.filter(function(e,t,i){return i.indexOf(e)===t});a[e]=o,s=!0}}),s){var o={ajax:1,action:"getTargetEntitiesByIdsBulk",trait:"EntitySelector",entities:JSON.stringify(a)};t.config.productSelectionLevel&&"product"!==t.config.productSelectionLevel&&(o.product_selection_level=t.config.productSelectionLevel),e.ajax({url:t.config.ajaxUrl,type:"POST",dataType:"json",data:o,success:function(e){if(e.success&&e.entities)try{Object.keys(i).forEach(function(a){var s=i[a],o=e.entities[a]||[],n={};o.forEach(function(e){n[e.id]=e}),s.pickers.forEach(function(e){var i=e.$picker,s=i.find(".entity-chips"),o=i.find(".include-values-data, .exclude-values-data"),r=[],l="countries"===a;e.ids.forEach(function(e){var i=s.find('.entity-chip-loading[data-id="'+e+'"]');if(n[e]){var a=n[e];r.push(a.id);var o='':a.image&&(o+=''),o+=''+t.escapeHtml(a.name)+"",l&&(o+=''),o+='',o+="",i.replaceWith(o)}else i.remove()}),t.updateChipsVisibility(s),r.length!==e.ids.length&&(o.val(JSON.stringify(r)),t.serializeAllBlocks()),t.updateBlockStatus(i.closest(".target-block"))})}),t.updateAllConditionCounts()}catch(e){}},error:function(e,t,i){}})}},collectPickerEntities:function(t,i,a){if(t.length){var s=this,o=t.find(".include-values-data, .exclude-values-data");if(o.length){var n=t.attr("data-value-type"),r=o.val()||"[]",l=[];try{l=JSON.parse(r)}catch(e){return}if("multi_numeric_range"!==n)if("multi_select_tiles"!==n){if("combination_attributes"===n)return"object"!=typeof l||null===l||0===Object.keys(l).length||o.val(JSON.stringify(l)),void s.loadCombinationAttributeGroups(t);if(l.length)if("pattern"!==n){var c=t.attr("data-search-entity")||i,d=t.find(".entity-chips"),p=this.getEntityTypeIcon(c);l.forEach(function(e){var t='';t+='',t+='Loading...',t+="",d.append(t)}),a[c]||(a[c]={ids:[],pickers:[]}),a[c].ids=a[c].ids.concat(l),a[c].pickers.push({$picker:t,ids:l})}else l.forEach(function(e){"string"==typeof e&&e?s.addPatternTag(t,e,!1):e&&e.pattern&&s.addPatternTag(t,e.pattern,!0===e.caseSensitive)})}else{if(!Array.isArray(l)||0===l.length)return;l.forEach(function(e){t.find('.tile-option[data-value="'+e+'"]').addClass("selected")})}else{if(!Array.isArray(l)||0===l.length)return;var u=t.find(".multi-range-chips");l.forEach(function(t){if(t&&(null!==t.min||null!==t.max)){var i;i=null!==t.min&&null!==t.max?t.min+" - "+t.max:null!==t.min?"≥ "+t.min:"≤ "+t.max;var a=e("",{class:"range-chip","data-min":null!==t.min?t.min:"","data-max":null!==t.max?t.max:""});a.append(e("",{class:"range-chip-text",text:i})),a.append(e("",r+=''+this.escapeHtml(t)+"",r+='',r+="",s.append(r)},getPatternTags:function(t){var i=[];return t.find(".pattern-tag:not(.draft-tag)").each(function(){var t=e(this).data("pattern"),a=1===e(this).data("caseSensitive")||"1"===e(this).data("caseSensitive");t&&i.push({pattern:t,caseSensitive:a})}),i},updateDraftTagCount:function(t,i,a){var s=this,o=t.find(".pattern-match-count"),n=o.find(".count-value"),r=t.closest(".target-block").data("blockType")||"products";n.html(''),o.show(),o.data("pattern",i),o.data("caseSensitive",a),o.data("entityType",r),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"countPatternMatches",trait:"EntitySelector",pattern:i,field:"name",entity_type:r,case_sensitive:a?1:0},success:function(e){if(e.success){var i=parseInt(e.count,10)||0;n.text(i),o.show(),o.removeClass("count-zero count-found"),o.addClass(0===i?"count-zero":"count-found"),o.data("count",i);var a=t.closest(".selection-group");a.length&&s.updateGroupTotalCount(a)}else n.text("?"),o.show()},error:function(){n.text("?"),o.show()}})},updateConditionCountWithPendingPattern:function(t,i){this.config.trans;var a=t.find(".method-selector-wrapper > .condition-match-count, > .exclude-header-row > .condition-match-count").first();if(a.length){var s=t.hasClass("exclude-row"),o=(s?t.find(".exclude-method-select"):t.find(".include-method-select")).val();if(o){var n=s?t.find(".exclude-picker"):t.find(".include-picker");if("pattern"===(n.data("valueType")||"none")){var r=this.getPatternTags(n);if(i&&r.push({pattern:i,caseSensitive:!1}),0!==r.length){var l=t.closest(".target-block").data("blockType")||"products";a.find(".preview-count").html(''),a.removeClass("clickable no-matches").show(),a.data("conditionData",{method:o,values:r,blockType:l,isExclude:s}),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"countConditionMatches",trait:"EntitySelector",method:o,values:JSON.stringify(r),block_type:l},success:function(e){if(e&&e.success){var t=e.count||0;a.removeClass("no-matches clickable"),0===t?(a.find(".preview-count").text(t),a.addClass("no-matches").show()):(a.find(".preview-count").text(t),a.addClass("clickable").show())}else a.hide().removeClass("clickable")},error:function(){a.hide().removeClass("clickable")}})}else a.hide()}}else a.hide()}},fetchPatternMatchCount:function(t,i,a){var s=t.closest(".exclude-row"),o=-1!==((s.length?s.find(".exclude-method-select"):t.closest(".selection-group").find(".include-method-select")).val()||"").indexOf("reference")?"reference":"name",n=t.closest(".target-block").data("blockType")||"products";a.find(".preview-count").html(''),a.removeClass("clickable no-matches").show(),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"countPatternMatches",trait:"EntitySelector",pattern:i,field:o,entity_type:n,case_sensitive:0},success:function(e){if(e&&e.success){var t=e.count||0;a.find(".preview-count").text(t),a.removeClass("no-matches clickable").show(),0===t?a.addClass("no-matches"):a.addClass("clickable")}else a.hide()},error:function(){a.hide()}})},getPickerValues:function(t,i){switch(i){case"entity_search":var a=[];return t.find(".entity-chip").each(function(){var t=e(this).data("id");t&&a.push(t)}),a;case"pattern":var s=this.getPatternTags(t),o=t.find(".draft-tag .pattern-input"),n=e.trim(o.val());if(n){var r="1"===o.closest(".draft-tag").attr("data-case-sensitive");s.push({pattern:n,caseSensitive:r})}return s;case"numeric_range":return{min:t.find(".range-min-input").val()||null,max:t.find(".range-max-input").val()||null};case"date_range":return{from:t.find(".date-from-input").val()||null,to:t.find(".date-to-input").val()||null};case"select":return[t.find(".select-value-input").val()];case"boolean":return[!0];default:return[]}},updateConditionCount:function(t){this.config.trans;var i=t.find(".method-selector-wrapper > .condition-match-count, > .exclude-header-row > .condition-match-count").first();if(i.length){var a=t.hasClass("exclude-row"),s=(a?t.find(".exclude-method-select"):t.find(".include-method-select")).val();if(s){var o=a?t.find(".exclude-picker"):t.find(".include-picker"),n=o.data("valueType")||"none",r=this.getPickerValues(o,n),l=!r||Array.isArray(r)&&0===r.length||"object"==typeof r&&!Array.isArray(r)&&("combination_attributes"===n&&void 0!==r.attributes&&0===Object.keys(r.attributes).length||"combination_attributes"!==n&&0===Object.keys(r).length);if("none"!==n&&"boolean"!==n&&l)i.hide();else{var c=t.closest(".target-block").data("blockType")||"products";i.find(".preview-count").html(''),i.removeClass("clickable no-matches").show(),i.data("conditionData",{method:s,values:r,blockType:c,isExclude:a}),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"countConditionMatches",trait:"EntitySelector",method:s,values:JSON.stringify(r),block_type:c},success:function(e){if(e&&e.success){var t=e.count||0;i.removeClass("no-matches clickable"),0===t?(i.find(".preview-count").text(t),i.addClass("no-matches").show()):(i.find(".preview-count").text(t),i.addClass("clickable").show())}else i.hide().removeClass("clickable")},error:function(){i.hide().removeClass("clickable")}})}}else i.hide()}},updateGroupCounts:function(t){var i=this,a=t.find(".group-include");a.length&&this.updateConditionCount(a),t.find(".exclude-row").each(function(){i.updateConditionCount(e(this))}),this.updateGroupTotalCount(t)},updateGroupTotalCount:function(t){var i=t.closest(".target-block").data("blockType")||"products",a=t.find(".group-header .group-count-badge"),s=t.find(".group-modifier-limit"),o=this.serializeGroup(t,i);if(!o.include||!o.include.method)return a.hide(),void s.attr("placeholder","–");a.html('').show(),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"countGroupItems",trait:"EntitySelector",group_data:JSON.stringify(o),block_type:i},success:function(e){if(e&&e.success){var n=e.final_count||0,r=e.exclude_count||0,l=' '+n;r>0&&(l+=' (-'+r+")"),a.html(l),a.addClass("clickable").show(),a.data("groupData",o),a.data("blockType",i),a.data("finalCount",n),s.attr("placeholder",n);var c=t.find(".group-preview-badge .preview-count");if(c.length){var d=parseInt(s.val(),10),p=d>0&&dn&&(n=t)});var r=n+1,l=this.buildMethodOptions(o,!1),c=(this.buildMethodOptions(o,!0),'
');c+='
',c+='',c+='',c+='',c+='',c+="",c+='",c+="
",c+='
',c+='
',c+='
',c+='
',c+='",c+=' 0',c+='',c+="
",c+='",c+="
",c+="
",c+='
',c+='",c+="
",c+='
',c+='',c+=''+(s.limit||"Limit")+"",c+='',c+="",c+='',c+=''+(s.sort||"Sort")+"",c+='",c+='",c+="",c+='',c+=' ',c+="",c+="
",c+="
",c+="
",a.append(c);var d=a.find('.selection-group[data-group-index="'+r+'"]');this.enhanceMethodSelect(d.find(".include-method-select")),d.find(".include-method-select").val("all").trigger("change"),this.updateBlockStatus(t),this.serializeAllBlocks()},removeGroup:function(e,t){e.remove();var i=t.find(".groups-container");if(0===i.find(".selection-group").length){var a='
';a+=''+this.getEmptyStateText(t)+"",a+="
",i.html(a)}this.updateBlockStatus(t),this.serializeAllBlocks(),this.updateTabBadges()},clearAllConditions:function(){var t=this;this.$wrapper.find(".target-block").each(function(){var i=e(this),a=i.find(".groups-container");a.find(".selection-group").remove();var s='
';s+=''+t.getEmptyStateText(i)+"",s+="
",a.html(s),t.updateBlockStatus(i)}),this.serializeAllBlocks(),this.updateTabBadges(),this.updateHeaderTotalCount()},switchToBlock:function(e){this.$wrapper.find(".target-block-tab").removeClass("active"),this.$wrapper.find('.target-block-tab[data-block-type="'+e+'"]').addClass("active"),this.$wrapper.find(".target-block").removeClass("active").hide(),this.$wrapper.find('.target-block[data-block-type="'+e+'"]').addClass("active").show(),this.hideDropdown()},updateTabBadges:function(){var t=this,i=[];this.$wrapper.find(".target-block-tab").each(function(){var a=e(this),s=a.data("blockType"),o=t.$wrapper.find('.target-block[data-block-type="'+s+'"]').find(".selection-group").length,n=a.find(".tab-badge");o>0?(n.length?n.addClass("loading").html(''):a.append(''),a.addClass("has-data"),i.push(s)):(n.remove(),a.removeClass("has-data"))}),this.updateTargetSwitchState(),i.length>0&&this.fetchAllCounts(i)},updateTargetSwitchState:function(){var t=this.$wrapper.find(".prestashop-switch");if(t.length){var i=!1;this.$wrapper.find(".target-block").each(function(){if(e(this).find(".selection-group").length>0)return i=!0,!1}),i?t.find('input[value="0"]').prop("checked",!0):t.find('input[value="1"]').prop("checked",!0)}},fetchAllCounts:function(t){var i=this,a=this.$wrapper.find('input[name="'+this.config.name+'"]'),s={};try{s=JSON.parse(a.val()||"{}")}catch(e){s={}}var o={};t.forEach(function(e){var t=s[e]&&s[e].groups?s[e].groups:[];t.length>0&&(o[e]={groups:t})}),0!==Object.keys(o).length?e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"previewEntitySelectorBulk",trait:"EntitySelector",conditions:JSON.stringify(o)},success:function(e){e.success&&e.counts?(Object.keys(e.counts).forEach(function(t){var a=e.counts[t],s=i.$wrapper.find('.target-block-tab[data-block-type="'+t+'"]'),o=s.find(".tab-badge");o.length&&(o.removeClass("loading").html(' '+a),s.data("previewData",{count:a,success:!0}))}),t.forEach(function(t){if(!(t in e.counts)){var a=i.$wrapper.find('.target-block-tab[data-block-type="'+t+'"]');a.find(".tab-badge").remove(),a.removeClass("has-data")}}),i.updateHeaderTotalCount()):t.forEach(function(e){i.$wrapper.find('.target-block-tab[data-block-type="'+e+'"]').find(".tab-badge").remove()})},error:function(e,a,s){t.forEach(function(e){i.$wrapper.find('.target-block-tab[data-block-type="'+e+'"]').find(".tab-badge").remove()})}}):t.forEach(function(e){var t=i.$wrapper.find('.target-block-tab[data-block-type="'+e+'"]');t.find(".tab-badge").remove(),t.removeClass("has-data")})},fetchProductCount:function(t,i){var a=this,s={},o=this.$wrapper.find('input[name="'+this.config.name+'"]'),n={};try{n=JSON.parse(o.val()||"{}")}catch(e){n={}}var r=n[t]&&n[t].groups?n[t].groups:[];if(0===r.length)return i.find(".tab-badge").remove(),i.removeClass("has-data"),void i.removeData("previewData");var l=i.find(".tab-badge");l.length?l.addClass("loading").html(''):(l=e(''),i.append(l)),i.addClass("has-data"),s[t]={groups:r},e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"previewEntitySelector",trait:"EntitySelector",conditions:JSON.stringify(s),block_type:t,limit:10},success:function(e){e.success?(i.find(".tab-badge").removeClass("loading").html(' '+e.count),i.data("previewData",e),a.updateHeaderTotalCount()):i.find(".tab-badge").remove()},error:function(e,t,s){i.find(".tab-badge").remove(),a.updateHeaderTotalCount()}})},updateHeaderTotalCount:function(){var t=0;this.$wrapper.find(".target-block-tab .tab-badge").each(function(){var i=e(this);if(!i.hasClass("loading")){var a=parseInt(i.text(),10);isNaN(a)||(t+=a)}});var i=this.$wrapper.find(".trait-total-count");t>0?(i.find(".count-value").text(t),i.show()):i.hide(),this.updateShowAllToggle()},updateShowAllToggle:function(){var e=this.$wrapper.find(".trait-show-all-toggle");if(e.length){var t=e.find(".show-all-checkbox"),i=this.$wrapper.find(".target-block-tab.has-data").length>0;t.prop("checked",!i)}},updateBlockStatus:function(e){var t=e.find(".block-status"),i=e.data("blockType"),a=this.config.blocks[i]||{},s=this.config.trans||{},o=this.getBlockGroups(e);0===o.length?!1!==this.config.emptyMeansAll?t.text((s.all||"All")+" "+(a.entity_label_plural||"items")):t.text(s.nothing_selected||"Nothing selected"):t.text(o.length+" "+(1===o.length?s.group||"group":s.groups||"groups"))},getEmptyStateText:function(e){var t=e.data("blockType"),i=e.data("mode")||"multi",a=this.config.blocks[t]||{},s=this.config.trans||{},o=!1!==this.config.emptyMeansAll;return"single"===i?s.no_item_selected||"No item selected":o?(s.all||"All")+" "+(a.entity_label_plural||"items")+" "+(s.included||"included"):s.nothing_selected||"Nothing selected"},serializeGroup:function(t,i){var a=this,s=t.find(".include-method-select").val()||"all",o=t.find(".include-picker"),n=this.getPickerValues(o),r=[];t.find(".group-excludes.has-excludes").length&&t.find(".exclude-row").each(function(){var t=e(this),i=t.find(".exclude-method-select").val()||null,s=t.find(".exclude-picker"),o=a.getPickerValues(s);i&&o&&(!Array.isArray(o)||o.length>0)&&r.push({method:i,values:o})});var l={include:{method:s,values:n}};r.length>0&&(l.excludes=r);var c=this.getGroupModifiers(t);return(c.limit||c.sort_by)&&(l.modifiers=c),l},serializeAllBlocks:function(t){var i=this,a={};this.$wrapper.find(".target-block").each(function(){var t=e(this),s=t.data("blockType"),o=i.getBlockGroups(t);o.length>0&&(a[s]={groups:o}),i.updateBlockStatus(t)});var s=this.$wrapper.find('input[name="'+this.config.name+'"]'),o=JSON.stringify(a);s.val(o),this.updateTabBadges(),this.countUpdateTimeout&&clearTimeout(this.countUpdateTimeout),this.countUpdateTimeout=setTimeout(function(){if(t&&t.length){i.updateConditionCount(t);var e=t.closest(".selection-group");e.length&&i.updateGroupTotalCount(e)}else i.updateAllConditionCounts()},500)},getBlockGroups:function(t){var i=this,a=[];return t.find(".selection-group").each(function(){var t=e(this),s=t.find(".include-method-select").val()||"all",o=t.find(".include-picker"),n=i.getPickerValues(o);if(!i.isConditionValid(s,n,o))return!0;var r=[];t.find(".group-excludes.has-excludes").length&&t.find(".exclude-row").each(function(){var t=e(this),a=t.find(".exclude-method-select").val()||null,s=t.find(".exclude-picker"),o=i.getPickerValues(s);a&&i.isConditionValid(a,o,s)&&r.push({method:a,values:o})});var l={include:{method:s,values:n}},c=e.trim(t.attr("data-group-name")||"");c&&(l.name=c),r.length>0&&(l.excludes=r);var d=i.getGroupModifiers(t);(d.limit||d.sort_by)&&(l.modifiers=d),a.push(l)}),a},getGroupModifiers:function(e){var t=e.find(".group-modifier-limit").val(),i=e.find(".group-modifier-sort").val()||"sales",a=e.find(".group-modifiers .btn-sort-dir").data("dir")||"DESC";return{limit:t?parseInt(t,10):null,sort_by:i||null,sort_dir:a||"DESC"}},getPickerValues:function(t){var i=t.attr("data-value-type")||"entity_search",a=[];switch(i){case"entity_search":t.find(".entity-chip").each(function(){var t=e(this).data("id");a.push(isNaN(t)?t:Number(t))});break;case"pattern":a=this.getPatternTags(t);var s=t.find(".draft-tag .pattern-input"),o=e.trim(s.val());if(o){var n="1"===s.closest(".draft-tag").attr("data-case-sensitive");a.push({pattern:o,caseSensitive:n})}break;case"numeric_range":var r=t.find(".range-min-input").val(),l=t.find(".range-max-input").val();""===r&&""===l||(a={min:""!==r?parseFloat(r):null,max:""!==l?parseFloat(l):null});break;case"date_range":var c=t.find(".date-from-input").val(),d=t.find(".date-to-input").val();(c||d)&&(a={from:c||null,to:d||null});break;case"select":var p=t.find(".select-value-input").val();p&&(a=[p]);break;case"boolean":a=[!0];break;case"multi_numeric_range":var u=[];t.find(".range-chip").each(function(){var t=e(this),i=t.data("min"),a=t.data("max");u.push({min:""!==i&&void 0!==i?parseFloat(i):null,max:""!==a&&void 0!==a?parseFloat(a):null})}),u.length>0&&(a=u);break;case"multi_select_tiles":t.find(".tile-option.selected").each(function(){a.push(e(this).data("value"))});break;case"combination_attributes":var h={};if(t.find(".comb-attr-value.selected").each(function(){var t=e(this).data("groupId").toString(),i=e(this).data("valueId");h[t]||(h[t]=[]),h[t].push(i)}),Object.keys(h).length>0){var f,v=t.find(".combination-attributes-picker").data("combinationMode")||this.config.combinationMode||"products";f="toggle"===v?t.find(".comb-mode-radio:checked").val()||"products":v,a={mode:f,attributes:h}}}return a},isConditionValid:function(e,t,i){if("all"===e)return!0;var a=i.attr("data-value-type")||"entity_search";return"boolean"===a||(Array.isArray(t)?t.length>0:"object"==typeof t&&null!==t&&("combination_attributes"===a&&void 0!==t.attributes?Object.keys(t.attributes).length>0:Object.keys(t).some(function(e){return null!==t[e]&&""!==t[e]})))},updateAllConditionCounts:function(){var t=this,i={},a={},s=0;this.$wrapper.find(".target-block.active .selection-group").each(function(){var o=e(this),n=o.closest(".target-block").data("blockType")||"products",r=o.find(".group-include");if(r.length){var l=t.getConditionData(r,n);if(l){var c="c"+s++;i[c]=l.condition,a[c]=l.$countEl}}o.find(".exclude-row").each(function(){var o=t.getConditionData(e(this),n);if(o){var r="c"+s++;i[r]=o.condition,a[r]=o.$countEl}})}),0!==Object.keys(i).length&&e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"countConditionMatchesBulk",trait:"EntitySelector",conditions:JSON.stringify(i)},success:function(e){e&&e.success&&e.counts&&Object.keys(e.counts).forEach(function(t){var i=e.counts[t]||0,s=a[t];s&&s.length&&(s.removeClass("no-matches clickable"),0===i?(s.find(".preview-count").text(i),s.addClass("no-matches").show()):(s.find(".preview-count").text(i),s.addClass("clickable").show()))})},error:function(){Object.keys(a).forEach(function(e){var t=a[e];t&&t.length&&t.hide().removeClass("clickable")})}})},getConditionData:function(e,t){var i=e.find(".method-selector-wrapper > .condition-match-count, > .exclude-header-row .condition-match-count").first();if(!i.length)return null;var a=e.hasClass("exclude-row"),s=(a?e.find(".exclude-method-select"):e.find(".include-method-select")).val();if(!s)return i.hide(),null;var o=a?e.find(".exclude-picker"):e.find(".include-picker"),n=o.data("valueType")||o.attr("data-value-type")||"none";if("none"===n&&"countries"===t&&"all"===s){var r=this;return setTimeout(function(){r.updateConditionCount(e,t)},0),null}var l=o.attr("data-search-entity")||"";if("countries"===t&&"entity_search"===n&&"countries"===l)return r=this,setTimeout(function(){r.updateConditionCount(e,t)},0),null;if("none"===n)return i.hide(),null;var c=this.getPickerValues(o,n),d=!c||Array.isArray(c)&&0===c.length||"object"==typeof c&&!Array.isArray(c)&&("combination_attributes"===n&&void 0!==c.attributes&&0===Object.keys(c.attributes).length||"combination_attributes"!==n&&0===Object.keys(c).length);return"boolean"!==n&&d?(i.hide(),null):(i.find(".preview-count").html(''),i.removeClass("clickable no-matches").show(),i.data("conditionData",{method:s,values:c,blockType:t,isExclude:a}),{condition:{method:s,values:c,block_type:t},$countEl:i})},updateGroupCounts:function(t){var i=this,a=t.closest(".target-block").data("blockType")||"products",s=t.find(".group-include");s.length&&this.updateConditionCount(s,a),t.find(".exclude-row").each(function(){i.updateConditionCount(e(this),a)}),this.updateGroupTotalCount(t)},updateConditionCount:function(t,i){var a=this,s=t.find(".method-selector-wrapper > .condition-match-count, > .exclude-header-row .condition-match-count").first();if(s.length){var o=t.hasClass("exclude-row"),n=(o?t.find(".exclude-method-select"):t.find(".include-method-select")).val();if(n){var r=o?t.find(".exclude-picker"):t.find(".include-picker"),l=r.data("valueType")||"none",c=r.attr("data-search-entity")||"";if(!i){var d=t.closest(".target-block");i=d.data("blockType")||"products"}if("none"===l&&"countries"===i&&"all"===n)return s.find(".preview-count").html(''),s.removeClass("clickable no-matches country-holidays").show(),void e.ajax({url:a.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"searchTargetEntities",trait:"EntitySelector",entity_type:"countries",query:"",limit:500},success:function(t){var r=t.results||t.items||[];if(t&&t.success&&r.length>0){var l=r.map(function(e){return e.id});s.data("conditionData",{method:n,values:l,blockType:i,isExclude:o,isCountryHolidays:!0,countryIds:l,isAllCountries:!0}),e.ajax({url:a.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"getHolidaysForCountries",trait:"EntitySelector",country_ids:l.join(","),count_only:1},success:function(e){if(e&&e.success){var t=e.total_count||0;s.removeClass("no-matches clickable"),s.addClass("country-holidays"),0===t?(s.find(".preview-count").text(t),s.addClass("no-matches").show()):(s.find(".preview-count").text(t),s.addClass("clickable").show()),s.data("countriesInfo",e.countries||[])}else s.hide().removeClass("clickable")},error:function(){s.hide().removeClass("clickable")}})}else s.hide().removeClass("clickable")},error:function(){s.hide().removeClass("clickable")}});if("none"!==l){var p=this.getPickerValues(r,l),u=!p||Array.isArray(p)&&0===p.length||"object"==typeof p&&!Array.isArray(p)&&("combination_attributes"===l&&void 0!==p.attributes&&0===Object.keys(p.attributes).length||"combination_attributes"!==l&&0===Object.keys(p).length);if("boolean"!==l&&u)s.hide();else{i||(d=t.closest(".target-block"),i=d.data("blockType")||"products");var h="countries"===c&&"entity_search"===l;if(s.find(".preview-count").html(''),s.removeClass("clickable no-matches country-holidays").show(),h&&Array.isArray(p)&&p.length>0)return s.data("conditionData",{method:n,values:p,blockType:i,isExclude:o,isCountryHolidays:!0,countryIds:p}),void e.ajax({url:a.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"getHolidaysForCountries",trait:"EntitySelector",country_ids:p.join(","),count_only:1},success:function(e){if(e&&e.success){var t=e.total_count||0;s.removeClass("no-matches clickable"),s.addClass("country-holidays"),0===t?(s.find(".preview-count").text(t),s.addClass("no-matches").show()):(s.find(".preview-count").text(t),s.addClass("clickable").show()),s.data("countriesInfo",e.countries||[])}else s.hide().removeClass("clickable")},error:function(){s.hide().removeClass("clickable")}});s.data("conditionData",{method:n,values:p,blockType:i,isExclude:o}),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"countConditionMatches",trait:"EntitySelector",method:n,values:JSON.stringify(p),block_type:i},success:function(e){if(e&&e.success){var t=e.count||0;s.removeClass("no-matches clickable"),0===t?(s.find(".preview-count").text(t),s.addClass("no-matches").show()):(s.find(".preview-count").text(t),s.addClass("clickable").show())}else s.hide().removeClass("clickable")},error:function(){s.hide().removeClass("clickable")}})}}else s.hide()}else s.hide()}},updateGroupTotalCount:function(t){var i=t.closest(".target-block").data("blockType")||"products",a=t.find(".group-header .group-count-badge"),s=t.find(".group-modifier-limit"),o=this.serializeGroup(t,i);if(!o.include||!o.include.method)return a.hide(),void s.attr("placeholder","–");a.html('').show(),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"countGroupItems",trait:"EntitySelector",group_data:JSON.stringify(o),block_type:i},success:function(e){if(e&&e.success){var n=e.final_count||0,r=e.exclude_count||0,l=' '+n;r>0&&(l+=' (-'+r+")"),a.html(l),a.addClass("clickable").show(),a.data("groupData",o),a.data("blockType",i),a.data("finalCount",n),s.attr("placeholder",n);var c=t.find(".group-preview-badge .preview-count");if(c.length){var d=parseInt(s.val(),10),p=d>0&&d';s+=' '+(a.except||"EXCEPT")+"",s+="",s+='
',s+=this.buildExcludeRowHtml(t,0),s+="
",s+='",i.addClass("has-excludes").html(s);var o=i.find('.exclude-row[data-exclude-index="0"]'),n=o.find(".exclude-method-select");this.enhanceMethodSelect(n);var r=t.data("blockType"),l=n.val();this.updateMethodInfoPlaceholder(o.find(".method-selector-wrapper"),l,r),this.updateMethodSelectorLock(e,!0),this.serializeAllBlocks()},addExcludeRow:function(t,i){var a=t.find(".exclude-rows-container"),s=-1;a.find(".exclude-row").each(function(){var t=parseInt(e(this).data("excludeIndex"),10);t>s&&(s=t)});var o=s+1,n=this.buildExcludeRowHtml(i,o);a.append(n);var r=a.find('.exclude-row[data-exclude-index="'+o+'"]'),l=r.find(".exclude-method-select");this.enhanceMethodSelect(l);var c=i.data("blockType"),d=l.val();this.updateMethodInfoPlaceholder(r.find(".method-selector-wrapper"),d,c),this.serializeAllBlocks()},buildExcludeRowHtml:function(t,i){var a=t.data("blockType"),s=(this.config.blocks[a]||{}).selection_methods||{},o=this.config.trans||{},n=this.buildMethodOptions(s,!0),r=a,l="entity_search";e.each(s,function(e,t){return"all"===e||(r=t.search_entity||a,l=t.value_type||"entity_search",!1)});var c='
';return c+='
',c+='
',c+='",c+=' 0',c+='',c+="
",c+='",c+="
",(c+=this.buildValuePickerHtml("exclude",l,r,s))+"
"},removeExcludeRow:function(e,t,i){var a=t.find(".exclude-rows-container"),s=this.config.trans||{};e.remove(),0===a.find(".exclude-row").length&&(t.find(".group-excludes").removeClass("has-excludes").html('"),this.updateMethodSelectorLock(t,!1)),this.serializeAllBlocks()},buildMethodOptions:function(t,i){var a=this,s=this.config.trans||{},o="",n={select_by:s.select_by||"Select by...",filter_by:s.filter_by||"Filter by..."},r={},l={};return e.each(t,function(e,t){if(i&&"all"===e)return!0;var a=t.group||"";a?(r[a]||(r[a]={}),r[a][e]=t):l[e]=t}),e.each(l,function(e,t){o+=a.buildMethodOption(e,t)}),e.each(r,function(t,i){var s=n[t]||t.replace(/_/g," ");o+='',e.each(i,function(e,t){o+=a.buildMethodOption(e,t)}),o+=""}),o},buildMethodOption:function(e,t){var i='"},buildValuePickerHtml:function(e,t,i,a){var s=this.config.trans||{},o=e+"-picker",n=e+"-chips",r=e+"-values-data",l="";if("none"===t)return l='";switch(l='
',t){case"entity_search":var c=s.no_items_selected||"No items selected - use search below";l+='
',l+='",l+='';break;case"pattern":var d=""+this.escapeHtml(s.pattern_help_title||"Pattern Syntax")+"";d+='
',d+='
* '+this.escapeHtml(s.pattern_help_wildcard||"any text (wildcard)")+"
",d+='
{number} '+this.escapeHtml(s.pattern_help_number||"any number (e.g. 100, 250)")+"
",d+='
{letter} '+this.escapeHtml(s.pattern_help_letter||"single letter (A-Z)")+"
",d+="
",d+='
',d+=""+this.escapeHtml(s.pattern_help_examples||"Examples:")+"",d+='
*cotton* '+this.escapeHtml(s.pattern_example_1||'contains "cotton"')+"
",d+='
iPhone {number} Pro* '+this.escapeHtml(s.pattern_example_2||'matches "iPhone 15 Pro Max"')+"
",d+='
Size {letter} '+this.escapeHtml(s.pattern_example_3||'matches "Size M", "Size L"')+"
",d+="
";var p=s.no_patterns||"No patterns - press Enter to add";l+='
',l+='
',l+='
',l+='',l+='',l+=' ',l+='',l+="
",l+='',l+='',l+="",l+="
",l+='';break;case"numeric_range":l+='
',l+='',l+='-',l+='',l+="
",l+='';break;case"multi_numeric_range":l+='
',l+='
',l+='
',l+='',l+='-',l+='',l+='',l+="
",l+="
",l+='';break;case"multi_select_tiles":l+='
',l+="
",l+='';break;case"date_range":l+='
',l+='',l+='-',l+='',l+="
",l+='';break;case"select":l+='
',l+='',l+="
",l+='';break;case"boolean":l+='
',l+=''+this.escapeHtml(s.yes||"Yes")+"",l+="
",l+='';break;case"combination_attributes":this.escapeHtml(s.combination_help_title||"Combination Targeting"),this.escapeHtml(s.combination_help_desc||"Select attributes to target specific product combinations."),this.escapeHtml(s.combination_help_logic||"Logic:"),this.escapeHtml(s.combination_help_within||"Within group: OR (Red OR Blue)"),this.escapeHtml(s.combination_help_between||"Between groups: AND (Color AND Size)");var u=this.config.combinationMode||"products",h="toggle"===u,f=h?"products":u;l+='
',h&&(l+='
',l+='",l+='",l+="
"),l+='
',l+=' '+this.escapeHtml(s.loading||"Loading...")+"",l+="
",l+="
",l+='';break;default:l+=''}return l+"
"},getSortOptionsArray:function(e){var t=this.config.trans||{};switch(e){case"products":return[{value:"sales",label:t.sort_bestsellers||"Best sellers"},{value:"date_add",label:t.sort_newest||"Newest"},{value:"price",label:t.sort_price||"Price"},{value:"name",label:t.sort_name||"Name"},{value:"position",label:t.sort_position||"Position"},{value:"quantity",label:t.sort_stock||"Stock quantity"},{value:"random",label:t.sort_random||"Random"}];case"categories":return[{value:"name",label:t.sort_name||"Name"},{value:"position",label:t.sort_position||"Position"},{value:"product_count",label:t.sort_products||"Products count"},{value:"date_add",label:t.sort_newest||"Newest"}];default:return[{value:"name",label:t.sort_name||"Name"},{value:"date_add",label:t.sort_newest||"Newest"}]}},getSortIconClass:function(e,t){var i="ASC"===t;switch(e){case"name":return i?"icon-sort-alpha-asc":"icon-sort-alpha-desc";case"price":case"quantity":case"product_count":case"date_add":case"newest_products":case"position":return i?"icon-sort-numeric-asc":"icon-sort-numeric-desc";case"sales":case"total_sales":default:return i?"icon-sort-amount-asc":"icon-sort-amount-desc";case"random":return"icon-random"}},cycleSortOption:function(e,t){for(var i,a,s,o=this.getSortOptionsArray(t),n=e.data("sort")||"sales",r=e.data("dir")||"DESC",l=-1,c=0;c0)return t=!0,!1}),t?(this.clearValidationError(),!0):(this.showValidationError(),!1)},showValidationError:function(){this.$wrapper.addClass("has-validation-error");var t=this.$wrapper.data("required-message")||"Please select at least one item";this.$wrapper.find(".trait-validation-error").remove();var i=e("
",{class:"trait-validation-error",html:' '+t});this.$wrapper.find(".condition-trait-header").after(i),e("html, body").animate({scrollTop:this.$wrapper.offset().top-100},300),this.$wrapper.find(".condition-trait-body").is(":visible")||(this.$wrapper.find(".condition-trait-body").slideDown(200),this.$wrapper.removeClass("collapsed"))},clearValidationError:function(){this.$wrapper.removeClass("has-validation-error"),this.$wrapper.find(".trait-validation-error").remove()}}}(jQuery),function(e){"use strict";window._EntitySelectorMixins=window._EntitySelectorMixins||{},window._EntitySelectorMixins.methods={initMethodDropdowns:function(){var t=this;this.$wrapper.find(".include-method-select").each(function(){t.enhanceMethodSelect(e(this))}),this.$wrapper.find(".exclude-method-select").each(function(){t.enhanceMethodSelect(e(this))}),this.initMethodInfoPlaceholders()},initMethodInfoPlaceholders:function(){var t=this;this.$wrapper.find(".selection-group").each(function(){var i=e(this),a=i.closest(".target-block").data("blockType")||"products",s=i.find(".include-method-select").val()||"all";t.updateMethodInfoPlaceholder(i.find(".method-selector-wrapper"),s,a),i.find(".exclude-row").each(function(){var i=e(this),s=i.find(".exclude-method-select").val();s&&t.updateMethodInfoPlaceholder(i.find(".method-selector-wrapper"),s,a)})})},enhanceMethodSelect:function(t){var i=this;if(t.length&&!t.data("methodDropdownInit")){t.data("methodDropdownInit",!0),t.addClass("method-select-hidden");var a=t.find("option:selected"),s=a.data("icon")||"icon-caret-down",o=a.text(),n='
';n+='',n+=''+this.escapeHtml(o)+"",n+='';var r=e(n+="
");t.after(r),r.on("click",function(e){e.preventDefault(),e.stopPropagation(),t.closest(".method-selector-wrapper").hasClass("selector-locked")||i.showMethodDropdownMenu(t,r)}),t.on("change.methodDropdown",function(){i.updateMethodTrigger(t,r)})}},updateMethodTrigger:function(e,t){var i=e.find("option:selected"),a=i.data("icon")||"icon-caret-down",s=i.text();t.find(".method-trigger-icon").attr("class",a+" method-trigger-icon"),t.find(".method-trigger-label").text(s)},showMethodDropdownMenu:function(t,i){var a=this;this.closeMethodDropdownMenu();var s=this.buildMethodDropdownMenuHtml(t),o=e(s),n=i.offset(),r=i.outerWidth(),l=i.outerHeight();o.css({position:"absolute",top:n.top+l+2,left:n.left,minWidth:r,zIndex:10001}),e("body").append(o),this.$methodDropdownMenu=o,this.$methodDropdownSelect=t,this.$methodDropdownTrigger=i,o.on("click",".method-dropdown-item",function(i){i.preventDefault(),i.stopPropagation();var s=e(this).data("value");t.val(s).trigger("change"),a.closeMethodDropdownMenu()}),e(document).on("click.methodDropdown",function(t){e(t.target).closest(".method-dropdown-menu, .method-dropdown-trigger").length||a.closeMethodDropdownMenu()}),e(document).on("keydown.methodDropdown",function(e){27===e.keyCode&&a.closeMethodDropdownMenu()})},buildMethodDropdownMenuHtml:function(t){var i=this,a='
';return t.children("option").each(function(){var t=e(this),s=t.data("icon")||"icon-asterisk",o=t.text(),n=t.val(),r=t.is(":selected");a+='
',a+='',a+=''+i.escapeHtml(o)+"",r&&(a+=''),a+="
"}),t.children("optgroup").each(function(){var t=e(this),s=t.attr("label")||"";a+='
',a+='
'+i.escapeHtml(s)+"
",a+='
',t.children("option").each(function(){var t=e(this),s=t.data("icon")||"icon-cog",o=t.text(),n=t.val(),r=t.is(":selected");a+='
',a+='',a+=''+i.escapeHtml(o)+"",r&&(a+=''),a+="
"}),a+="
",a+="
"}),a+="
"},closeMethodDropdownMenu:function(){this.$methodDropdownMenu&&(this.$methodDropdownMenu.remove(),this.$methodDropdownMenu=null),this.$methodDropdownSelect=null,this.$methodDropdownTrigger=null,e(document).off("click.methodDropdown keydown.methodDropdown")},populateTiles:function(t,i,a){var s=t.find(".multi-select-tiles");s.empty(),a?s.attr("data-exclusive","true"):s.removeAttr("data-exclusive"),e.each(i,function(t,i){var a="object"==typeof i?i.label:i,o="object"==typeof i&&i.icon?i.icon:null,n="object"==typeof i&&i.color?i.color:null,r="tile-option";n&&(r+=" tile-color-"+n);var l=e("',c+="
",c+='
',c+='',c+="
",o.length>0){if(c+='
',c+=this.renderPreviewItems(o),c+="
",r){var d=n-o.length;c+='"}}else c+='
'+(a.no_preview||"No items to preview")+"
";var p=e(c+="");e("body").append(p),this.$previewPopover=p,this.$previewList=p.find(".preview-list"),this.previewLoadedCount=o.length,this.previewTotalCount=n,this.previewContext=t.context||{},this.previewOnLoadMore=t.onLoadMore||null,this.previewOnFilter=t.onFilter||null,this.previewCurrentFilter="",this.previewEntityLabel=l,p.find(".preview-close").on("click",function(){i.hidePreviewPopover()});var u=p.find(".preview-filter-input");if(t.onFilter){var h=this.debounce(function(e){i.previewCurrentFilter=e,i.showFilterLoading(!0),t.onFilter.call(i,e)},300);u.on("input",function(){var t=e(this).val().trim();t!==i.previewCurrentFilter&&h(t)})}else u.on("input",function(){var t=e(this).val().toLowerCase().trim();i.filterPreviewItems(t)});return t.onLoadMore&&p.find(".btn-load-more").on("click",function(){var a=e(this),s=a.closest(".load-more-controls").find(".load-more-select");if(!a.hasClass("loading")){a.addClass("loading"),a.find("i").removeClass("icon-plus").addClass("icon-spinner icon-spin"),s.prop("disabled",!0);var o=parseInt(s.val(),10)||20;i.previewLoadCount=o,t.onLoadMore.call(i,a)}}),this.positionPopover(p,s),p.addClass("show"),p},positionPopover:function(t,i,a){var s,o=i[0].getBoundingClientRect(),n=e(window).scrollTop(),r=e(window).scrollLeft(),l=t.outerWidth(),c=t.outerHeight(),d=e(window).width(),p=e(window).height(),u=o.left+r+o.width/2-l/2;u=Math.max(10,Math.min(u,d-l-10));var h=!1;o.bottom+c+8>p-10?(s=o.top+n-c-8,h=!0):s=o.bottom+n+8,t.css({position:"absolute",top:s,left:u,zIndex:a||1e4}),t.toggleClass("position-above",h);var f=o.left+o.width/2,v=u;t.removeClass("position-left position-right"),f-v<.3*l?t.addClass("position-right"):f-v>.7*l&&t.addClass("position-left")},updatePreviewPopover:function(e,t){var i=this.config.trans||{};this.$previewList.html(this.renderPreviewItems(e)),this.previewLoadedCount=e.length;var a=this.$previewPopover.find(".preview-footer");if(t){var s=this.previewTotalCount-e.length,o=a.find(".load-more-controls"),n=o.find(".btn-load-more"),r=o.find(".load-more-select");n.removeClass("loading"),n.find("i").removeClass("icon-spinner icon-spin").addClass("icon-plus"),r.prop("disabled",!1),o.find(".remaining-count").text(s),r.empty(),s>=10&&r.append(''),s>=20&&r.append(''),s>=50&&r.append(''),s>=100&&r.append(''),r.append('")}else a.remove();var l=this.$previewPopover.find(".preview-filter-input").val();l&&this.filterPreviewItems(l.toLowerCase().trim())},renderPreviewItems:function(e){for(var t="",i=0;i",a.image?t+='':t+='
inventory_2
',t+='
',t+='
'+this.escapeHtml(a.name||"Unnamed")+"
";var n=[];a.reference&&n.push("Ref: "+a.reference),a.manufacturer&&n.push(a.manufacturer),a.category&&n.push(a.category),a.attributes&&n.push(a.attributes),n.length>0&&(t+='
'+this.escapeHtml(n.join(" • "))+"
"),t+="
",void 0!==a.price&&null!==a.price?t+='
'+this.formatPrice(a.price)+"
":a.price_formatted&&(t+='
'+this.escapeHtml(a.price_formatted)+"
"),void 0===a.active||a.active||(t+='Inactive'),t+=""}return t},filterPreviewItems:function(t){if(this.$previewList){var i=this.$previewList.find(".preview-item");t?i.each(function(){var i=e(this),a=i.data("name")||"",s=i.data("ref")||"",o=i.data("attrs")||"",n=-1!==a.indexOf(t)||-1!==s.indexOf(t)||-1!==o.indexOf(t);i.toggle(n)}):i.show()}},showFilterLoading:function(e){if(this.$previewPopover){var t=this.$previewList;t&&(e?(this.previewLockedWidth||(this.previewLockedWidth=this.$previewPopover.outerWidth(),this.$previewPopover.css("width",this.previewLockedWidth+"px")),t.addClass("filtering"),t.find(".filter-loading-overlay").length||t.append('
')):(t.removeClass("filtering"),t.find(".filter-loading-overlay").remove()))}},updatePreviewPopoverFiltered:function(t){var i=this.config.trans||{};if(this.showFilterLoading(!1),t.success){var a=t.items||[],s=t.count||0,o=t.hasMore||!1,n=this.$previewPopover.find(".preview-header"),r=this.previewEntityLabel||"items";if(n.find(".preview-count").text(s+" "+r),a.length>0)this.$previewList.html(this.renderPreviewItems(a)),this.previewLoadedCount=a.length,this.previewTotalCount=s;else{var l=i.no_filter_results||"No matching items found";this.$previewList.html('
'+l+"
"),this.previewLoadedCount=0,this.previewTotalCount=0}var c=this.$previewPopover.find(".preview-footer");if(o&&a.length>0){var d=s-a.length;if(c.length){var p=c.find(".load-more-controls"),u=p.find(".btn-load-more"),h=p.find(".load-more-select");u.removeClass("loading"),u.find("i").removeClass("icon-spinner icon-spin").addClass("icon-plus"),h.prop("disabled",!1),p.find(".remaining-count").text(d),h.empty(),d>=10&&h.append(''),d>=20&&h.append(''),d>=50&&h.append(''),d>=100&&h.append(''),h.append('")}else{var f='");this.$previewList.after(v);var m=this;this.previewOnLoadMore&&v.find(".btn-load-more").on("click",function(){var t=e(this),i=t.closest(".load-more-controls").find(".load-more-select");if(!t.hasClass("loading")){t.addClass("loading"),t.find("i").removeClass("icon-plus").addClass("icon-spinner icon-spin"),i.prop("disabled",!0);var a=parseInt(i.val(),10)||20;m.previewLoadCount=a,m.previewOnLoadMore.call(m,t)}})}}else c.remove()}},formatPrice:function(e){"number"!=typeof e&&(e=parseFloat(e)||0);var t=this.config&&this.config.currency_sign||"€",i=this.config&&this.config.currency_format||"right",a=e.toFixed(2);return"left"===i?t+" "+a:a+" "+t},hidePreviewPopover:function(){this.$activeBadge&&(this.$activeBadge.removeClass("popover-open loading"),this.$activeBadge=null),this.$previewPopover&&(this.$previewPopover.remove(),this.$previewPopover=null),this.$previewList=null,this.previewContext=null,this.previewOnLoadMore=null,this.previewOnFilter=null,this.previewCurrentFilter="",this.previewEntityLabel=null,this.previewLockedWidth=null},showPreviewPopover:function(e){var t=this,i=e.data("previewData");if(i){this.hidePreviewPopover();var a=e.find(".tab-badge");a.addClass("popover-open"),this.$activeBadge=a;var s=i.items||i.products||[],o=e.data("blockType"),n=(this.config.blocks&&this.config.blocks[o]?this.config.blocks[o]:{}).entity_label_plural||"items";if(this.previewBlockType=o,0===s.length&&i.count>0)return a.addClass("loading"),void this.fetchTabPreviewItems(e,function(s,r){a.removeClass("loading"),t.createPreviewPopover({$badge:a,items:s,totalCount:i.count,hasMore:r,entityLabel:n,previewType:"tab",context:{$tab:e,blockType:o},onLoadMore:function(i){t.loadMoreTabPreviewItems(e,i)},onFilter:function(i){t.filterTabPreviewItems(e,i)}})});this.createPreviewPopover({$badge:a,items:s,totalCount:i.count,hasMore:i.hasMore,entityLabel:n,previewType:"tab",context:{$tab:e,blockType:o},onLoadMore:function(i){t.loadMoreTabPreviewItems(e,i)},onFilter:function(i){t.filterTabPreviewItems(e,i)}})}},fetchTabPreviewItems:function(t,i){var a=t.data("blockType"),s=this.$wrapper.find('input[name="'+this.config.name+'"]'),o={};try{o=JSON.parse(s.val()||"{}")}catch(e){return void i([],!1)}var n=o[a]&&o[a].groups?o[a].groups:[];if(0!==n.length){var r={};r[a]={groups:n},e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"previewEntitySelector",trait:"EntitySelector",conditions:JSON.stringify(r),block_type:a,limit:20,offset:0},success:function(e){var a=e.items||e.products||[],s=e.hasMore||e.count>a.length;t.data("previewData",e),i(a,s)},error:function(){i([],!1)}})}else i([],!1)},filterTabPreviewItems:function(t,i){var a=this,s=this.previewBlockType,o=this.$wrapper.find('input[name="'+this.config.name+'"]'),n={};try{n=JSON.parse(o.val()||"{}")}catch(e){return void a.showFilterLoading(!1)}var r=n[s]&&n[s].groups?n[s].groups:[];if(0!==r.length){var l={};l[s]={groups:r},e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"previewTargetConditions",trait:"TargetConditions",conditions:JSON.stringify(l),block_type:s,filter:i,limit:20,offset:0},success:function(e){a.updatePreviewPopoverFiltered(e)},error:function(){a.showFilterLoading(!1)}})}else a.showFilterLoading(!1)},loadMoreTabPreviewItems:function(t,i){var a=this,s=this.previewBlockType,o=this.$wrapper.find('input[name="'+this.config.name+'"]'),n={};try{n=JSON.parse(o.val()||"{}")}catch(e){return}var r=n[s]&&n[s].groups?n[s].groups:[];if(0!==r.length){var l={};l[s]={groups:r};var c=this.previewLoadCount||20,d={ajax:1,action:"previewTargetConditions",trait:"TargetConditions",conditions:JSON.stringify(l),block_type:s,limit:a.previewLoadedCount+c,offset:0};a.previewCurrentFilter&&(d.filter=a.previewCurrentFilter),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:d,success:function(e){var i=e.items||e.products||[];e.success&&i.length>0&&(t.data("previewData",e),a.previewTotalCount=e.count,a.updatePreviewPopover(i,e.hasMore))},error:function(){var e=i.closest(".load-more-controls").find(".load-more-select");i.removeClass("loading"),i.find("i").removeClass("icon-spinner icon-spin").addClass("icon-plus"),e.prop("disabled",!1)}})}},showConditionPreviewPopover:function(t){var i=this,a=t.data("conditionData");if(a)if(a.isCountryHolidays&&a.countryIds)this.showCountriesHolidayPreview(t,a.countryIds);else{this.hidePreviewPopover(),t.addClass("popover-open loading"),this.$activeBadge=t;var s=a.blockType||"products",o=(this.config.blocks&&this.config.blocks[s]?this.config.blocks[s]:{}).entity_label_plural||"products";e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"previewConditionItems",trait:"EntitySelector",method:a.method,values:JSON.stringify(a.values),block_type:s,limit:10},success:function(e){t.removeClass("loading"),e.success?i.createPreviewPopover({$badge:t,items:e.items||[],totalCount:e.count,hasMore:e.hasMore,entityLabel:o,previewType:"condition",context:{conditionData:a,blockType:s},onLoadMore:function(e){i.loadMoreConditionItems(e)},onFilter:function(e){i.filterConditionItems(e)}}):(t.removeClass("popover-open"),i.$activeBadge=null)},error:function(){t.removeClass("loading popover-open"),i.$activeBadge=null}})}},filterConditionItems:function(t){var i=this,a=this.previewContext;a&&a.conditionData?e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"previewConditionItems",trait:"EntitySelector",method:a.conditionData.method,values:JSON.stringify(a.conditionData.values),block_type:a.blockType,filter:t,limit:20},success:function(e){i.updatePreviewPopoverFiltered(e)},error:function(){i.showFilterLoading(!1)}}):i.showFilterLoading(!1)},loadMoreConditionItems:function(t){var i=this,a=this.previewContext;if(a&&a.conditionData){var s=this.previewLoadCount||20,o={ajax:1,action:"previewConditionItems",trait:"EntitySelector",method:a.conditionData.method,values:JSON.stringify(a.conditionData.values),block_type:a.blockType,limit:i.previewLoadedCount+s};i.previewCurrentFilter&&(o.filter=i.previewCurrentFilter),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:o,success:function(e){e.success&&(i.previewTotalCount=e.count,i.updatePreviewPopover(e.items||[],e.hasMore))},error:function(){var e=t.closest(".load-more-controls").find(".load-more-select");t.removeClass("loading"),t.find("i").removeClass("icon-spinner icon-spin").addClass("icon-plus"),e.prop("disabled",!1)}})}},showGroupPreviewPopover:function(t,i,a){var s=this;if(i||(i=t.closest(".selection-group")),!a){var o=t.closest(".target-block");a=o.data("blockType")||"products"}var n=t.data("groupData");if(n||(n=this.serializeGroup(i,a)),n&&n.include){this.hidePreviewPopover(),t.addClass("popover-open loading"),this.$activeBadge=t;var r=(this.config.blocks&&this.config.blocks[a]?this.config.blocks[a]:{}).entity_label_plural||"products";e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"previewGroupItems",trait:"EntitySelector",group_data:JSON.stringify(n),block_type:a,limit:10},success:function(e){t.removeClass("loading"),e.success?s.createPreviewPopover({$badge:t,items:e.items||[],totalCount:e.count,hasMore:e.hasMore,entityLabel:r,previewType:"group",context:{groupData:n,blockType:a,$group:i},onLoadMore:function(e){s.loadMoreGroupItems(e)},onFilter:function(e){s.filterGroupItems(e)}}):(t.removeClass("popover-open"),s.$activeBadge=null)},error:function(){t.removeClass("loading popover-open"),s.$activeBadge=null}})}},filterGroupItems:function(t){var i=this,a=this.previewContext;a&&a.groupData?e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"previewGroupItems",trait:"EntitySelector",group_data:JSON.stringify(a.groupData),block_type:a.blockType,filter:t,limit:20},success:function(e){i.updatePreviewPopoverFiltered(e)},error:function(){i.showFilterLoading(!1)}}):i.showFilterLoading(!1)},loadMoreGroupItems:function(t){var i=this,a=this.previewContext;if(a&&a.groupData){var s=this.previewLoadCount||20,o={ajax:1,action:"previewGroupItems",trait:"EntitySelector",group_data:JSON.stringify(a.groupData),block_type:a.blockType,limit:i.previewLoadedCount+s};i.previewCurrentFilter&&(o.filter=i.previewCurrentFilter),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:o,success:function(e){e.success&&(i.previewTotalCount=e.count,i.updatePreviewPopover(e.items||[],e.hasMore))},error:function(){t.removeClass("loading"),t.find(".load-more-text").show(),t.find(".load-more-loading").hide()}})}},showFilterGroupPreviewPopover:function(t,i,a,s){var o=this;this.hidePreviewPopover(),t.addClass("popover-open loading"),this.$activeBadge=t,e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"previewFilterGroupProducts",trait:"EntitySelector",group_id:i,group_type:a,limit:10},success:function(e){t.removeClass("loading"),e.success?o.createPreviewPopover({$badge:t,items:e.items||[],totalCount:e.count||0,hasMore:e.hasMore||!1,entityLabel:"products",previewType:"filter-group",context:{groupId:i,groupType:a,groupName:s},onLoadMore:function(e){o.loadMoreFilterGroupItems(e)},onFilter:function(e){o.filterFilterGroupItems(e)}}):(t.removeClass("popover-open"),o.$activeBadge=null)},error:function(){t.removeClass("loading popover-open"),o.$activeBadge=null}})},filterFilterGroupItems:function(t){var i=this,a=this.previewContext;a&&a.groupId?e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"previewFilterGroupProducts",trait:"EntitySelector",group_id:a.groupId,group_type:a.groupType,filter:t,limit:20},success:function(e){i.updatePreviewPopoverFiltered(e)},error:function(){i.showFilterLoading(!1)}}):i.showFilterLoading(!1)},loadMoreFilterGroupItems:function(t){var i=this,a=this.previewContext;if(a&&a.groupId){var s=this.previewLoadCount||20,o={ajax:1,action:"previewFilterGroupProducts",trait:"EntitySelector",group_id:a.groupId,group_type:a.groupType,limit:i.previewLoadedCount+s};i.previewCurrentFilter&&(o.filter=i.previewCurrentFilter),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:o,success:function(e){e.success&&(i.previewTotalCount=e.count,i.updatePreviewPopover(e.items||[],e.hasMore))},error:function(){t.removeClass("loading"),t.find(".load-more-text").show(),t.find(".load-more-loading").hide()}})}},showFilterValuePreviewPopover:function(t,i,a,s,o){var n=this;this.hidePreviewPopover(),t.addClass("popover-open loading"),this.$activeBadge=t,e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"previewFilterValueProducts",trait:"EntitySelector",value_id:i,value_type:a,group_id:o,limit:10},success:function(e){t.removeClass("loading"),e.success?n.createPreviewPopover({$badge:t,items:e.items||[],totalCount:e.count||0,hasMore:e.hasMore||!1,entityLabel:"products",previewType:"filter-value",context:{valueId:i,valueType:a,groupId:o,valueName:s},onLoadMore:function(e){n.loadMoreFilterValueItems(e)},onFilter:function(e){n.filterFilterValueItems(e)}}):(t.removeClass("popover-open"),n.$activeBadge=null)},error:function(){t.removeClass("loading popover-open"),n.$activeBadge=null}})},filterFilterValueItems:function(t){var i=this,a=this.previewContext;a&&a.valueId?e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"previewFilterValueProducts",trait:"EntitySelector",value_id:a.valueId,value_type:a.valueType,group_id:a.groupId,filter:t,limit:20},success:function(e){i.updatePreviewPopoverFiltered(e)},error:function(){i.showFilterLoading(!1)}}):i.showFilterLoading(!1)},loadMoreFilterValueItems:function(t){var i=this,a=this.previewContext;if(a&&a.valueId){var s=this.previewLoadCount||20,o={ajax:1,action:"previewFilterValueProducts",trait:"EntitySelector",value_id:a.valueId,value_type:a.valueType,group_id:a.groupId,limit:i.previewLoadedCount+s};i.previewCurrentFilter&&(o.filter=i.previewCurrentFilter),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:o,success:function(e){e.success&&(i.previewTotalCount=e.count,i.updatePreviewPopover(e.items||[],e.hasMore))},error:function(){t.removeClass("loading"),t.find("i").removeClass("icon-spinner icon-spin").addClass("icon-plus")}})}},showCategoryItemsPreview:function(t,i,a,s){var o=this;this.hidePreviewPopover(),t.addClass("popover-open loading"),this.$activeBadge=t;var n="categories"===s,r=n?"products":"pages",l=n?"previewCategoryProducts":"previewCategoryPages";e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:l,trait:"EntitySelector",category_id:i,limit:10},success:function(e){t.removeClass("loading"),e.success?o.createPreviewPopover({$badge:t,items:e.items||[],totalCount:e.count||0,hasMore:e.hasMore||!1,entityLabel:r,previewType:"category-items",context:{categoryId:i,categoryName:a,entityType:s},onLoadMore:function(e){o.loadMoreCategoryItems(e)},onFilter:function(e){o.filterCategoryItems(e)}}):(t.removeClass("popover-open"),o.$activeBadge=null)},error:function(){t.removeClass("loading popover-open"),o.$activeBadge=null}})},loadMoreCategoryItems:function(t){var i=this,a=this.previewContext;if(a&&a.categoryId){var s="categories"===a.entityType?"previewCategoryProducts":"previewCategoryPages";t.prop("disabled",!0).find("i").addClass("icon-spin"),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:s,trait:"EntitySelector",category_id:a.categoryId,offset:this.previewOffset,limit:10,query:this.previewFilterQuery||""},success:function(e){t.prop("disabled",!1).find("i").removeClass("icon-spin"),e.success&&e.items&&(i.appendPreviewItems(e.items),i.previewOffset+=e.items.length,e.hasMore||t.hide())},error:function(){t.prop("disabled",!1).find("i").removeClass("icon-spin")}})}},filterCategoryItems:function(t){var i=this,a=this.previewContext;if(a&&a.categoryId){var s="categories"===a.entityType?"previewCategoryProducts":"previewCategoryPages";e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:s,trait:"EntitySelector",category_id:a.categoryId,query:t,limit:10},success:function(e){i.showFilterLoading(!1),e.success&&(i.replacePreviewItems(e.items||[],e.count||0,e.hasMore||!1),i.previewOffset=e.items?e.items.length:0,i.previewFilterQuery=t)},error:function(){i.showFilterLoading(!1)}})}else i.showFilterLoading(!1)},showPatternPreviewModal:function(t,i,a,s){var o=this,n=this.config.trans||{},r=this.config.blocks&&this.config.blocks[i]?this.config.blocks[i]:{},l=r.entity_label_plural||"items",c=r.entity_label||"item",d='
';d+='
',d+='
',d+='',d+=' '+(n.preview||"Preview")+": "+this.escapeHtml(t)+"",d+="",d+=''+s+" "+(1===s?c:l)+"",d+='',d+="
",d+='
',d+='
'+(n.loading||"Loading...")+"
",d+="
",d+="
";var p=e(d+="
");e("body").append(p),p.find(".pattern-preview-close").on("click",function(){p.remove()}),p.on("click",function(t){e(t.target).hasClass("pattern-preview-modal-overlay")&&p.remove()}),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"previewPatternMatches",trait:"TargetConditions",pattern:t,entity_type:i,case_sensitive:a?1:0,limit:50},success:function(e){if(e.success&&e.items){var t=e.items,i='
';if(0===t.length)i+='
'+(n.no_matches||"No matches found")+"
";else{for(var a=0;a',r.image&&(i+=''),i+=''+o.escapeHtml(r.name)+"",r.id&&(i+='#'+r.id+""),i+="
"}s>t.length&&(i+='
... '+(n.and||"and")+" "+(s-t.length)+" "+(n.more||"more")+"
")}i+="",p.find(".pattern-preview-content").html(i)}else p.find(".pattern-preview-content").html('
'+(n.error_loading||"Error loading preview")+"
")},error:function(){p.find(".pattern-preview-content").html('
'+(n.error_loading||"Error loading preview")+"
")}})},refreshGroupPreviewIfOpen:function(e){this.$activeBadge&&this.$previewPopover},escapeHtml:function(e){return e?String(e).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'"):""},escapeAttr:function(e){return e?String(e).replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'"):""},showTotalPreviewPopover:function(t){var i=this,a=this.config.trans||{};this.hidePreviewPopover(),t.addClass("popover-open"),this.$activeBadge=t;var s=[];this.$wrapper.find(".target-block-tab.has-data").each(function(){var t=e(this),a=t.data("blockType"),o=t.find(".tab-badge").text().replace(/[^0-9]/g,""),n=parseInt(o,10)||0;if(n>0){i.config.blocks&&i.config.blocks[a]&&i.config.blocks[a];var r=t.find(".tab-label").prev("i").attr("class")||"icon-cube",l=t.find(".tab-label").text()||a;s.push({blockType:a,label:l,icon:r,count:n})}});var o=parseInt(t.find(".count-value").text(),10)||0,n='
';n+='
',n+=''+(a.total_summary||"Selection Summary")+"",n+=''+o+" "+(a.total_items||"total items")+"",n+="
",n+='
',n+='
    ';for(var r=0;r',n+='',n+=''+i.escapeHtml(l.label)+"",n+=''+l.count+"",n+=""}n+="
",n+="
";var c=e(n+="
");this.$previewPopover=c,c.on("click",".total-summary-item",function(){var t=e(this).data("blockType");i.hidePreviewPopover(),i.switchToBlock(t)}),e("body").append(c),this.positionPopover(c,t),c.hide().fadeIn(150)},showHolidayPreview:function(t,i,a,s){var o=this,n=this.config.trans||{};e(".holiday-preview-popover").remove();var r='
';r+='
',r+='',a&&(r+=' '),r+=this.escapeHtml(i)+" - "+(n.holidays||"Holidays"),r+="",r+='',r+="
",r+='
',r+='
sync '+(n.loading||"Loading...")+"
",r+="
";var l=e(r+="
");e("body").append(l);var c=s[0].getBoundingClientRect(),d=e(window).scrollTop(),p=e(window).scrollLeft(),u=l.outerWidth(),h=l.outerHeight(),f=e(window).width(),v=e(window).height(),m=c.bottom+d+8,g=c.left+p;g+u>f-10&&(g=f-u-10),g<10&&(g=10),c.bottom+h>v-10&&(m=c.top+d-h-8),l.css({position:"absolute",top:m,left:g,zIndex:10001}),l.find(".popover-close").on("click",function(){l.remove()}),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"getHolidaysPreview",trait:"EntitySelector",id_country:t},success:function(e){if(e.success&&e.holidays&&e.holidays.length>0){for(var t='
',i=0;i',t+='
',t+=''+o.escapeHtml(a.date_formatted||a.date)+"",a.day_of_week&&(t+=''+o.escapeHtml(a.day_of_week)+""),t+="
",t+='
',t+=''+o.escapeHtml(a.name)+"",a.type&&(t+=''+o.escapeHtml(a.type)+""),t+="
",t+="
"}t+="",e.total_count&&(t+='
'+e.total_count+" "+(n.upcoming_holidays||"upcoming holidays")+"
"),l.find(".popover-body").html(t)}else{var s='
';s+='event_busy',s+="

"+(n.no_holidays||"No holidays found")+"

",s+="
",l.find(".popover-body").html(s)}var r=l.outerHeight();if(c.bottom+r>v-10){var p=c.top+d-r-8;p>10&&l.css("top",p)}},error:function(){var e='
';e+='error_outline',e+="

"+(n.error_loading||"Error loading holidays")+"

",e+="
",l.find(".popover-body").html(e)}})},showCountriesHolidayPreview:function(t,i){var a=this,s=this.config.trans||{};this.hidePreviewPopover(),e(".holiday-preview-popover").remove();var o='
';o+='
',o+='sync '+(s.loading||"Loading...")+"",o+='',o+="
",o+='
',o+='search',o+='',o+="
",o+='
',o+='
sync '+(s.loading||"Loading...")+"
",o+="
";var n=e(o+="
");e("body").append(n);var r=t[0].getBoundingClientRect(),l=e(window).scrollTop(),c=e(window).scrollLeft(),d=n.outerWidth(),p=n.outerHeight(),u=e(window).width(),h=e(window).height(),f=r.bottom+l+8,v=r.left+c;v+d>u-10&&(v=u-d-10),v<10&&(v=10),r.bottom+p>h-10&&(f=r.top+l-p-8),n.css({position:"absolute",top:f,left:v,zIndex:10001}),t.addClass("popover-open"),this.$activeBadge=t,n.find(".popover-close").on("click",function(){n.remove(),t.removeClass("popover-open"),a.$activeBadge=null}),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"getHolidaysForCountries",trait:"EntitySelector",country_ids:i.join(","),count_only:0},success:function(t){if(t.success&&t.holidays&&t.holidays.length>0){var o={},c={};if(t.countries)for(var d=0;d ')}else{for(var y=0;y<2;y++){var x=v[y];x&&x.iso_code&&(m+=' ')}m+="+"+(g-2)+" "}m+=t.total_count+" "+(s.holidays||"Holidays"),n.find(".popover-title").html(m);for(var _='
',k=0;k',_+='
',_+=''+a.escapeHtml(C.date_formatted||C.date)+"",C.day_of_week&&(_+=''+a.escapeHtml(C.day_of_week)+""),_+="
",_+='
',C.country_iso&&i.length>1&&(_+=' '),_+=''+a.escapeHtml(C.name)+"",C.type&&(_+=''+a.escapeHtml(C.type)+""),_+="
",_+="
"}_+="",t.total_count&&i.length>1&&(_+='
'+(s.across_countries||"across")+" "+i.length+" "+(s.countries||"countries")+"
"),n.find(".popover-body").html(_),n.find(".holiday-filter-input").on("input",function(){var t=e(this).val().toLowerCase().trim(),a=n.find(".holiday-item"),o=0;a.each(function(){var i=e(this).attr("data-search")||"";t&&-1===i.indexOf(t)?e(this).hide():(e(this).show(),o++)});var r=n.find(".holiday-preview-note");if(t&&r.length)r.text(o+" "+(s.matches||"matches"));else if(r.length&&i.length>1){var l=(s.across_countries||"across")+" "+i.length+" "+(s.countries||"countries");r.text(l)}})}else{n.find(".popover-title").html("0 "+(s.holidays||"Holidays"));var M='
';M+='event_busy',M+="

"+(s.no_holidays||"No holidays found")+"

",M+="
",n.find(".popover-body").html(M)}var P=n.outerHeight();if(r.bottom+P>h-10){var T=r.top+l-P-8;T>10&&n.css("top",T)}},error:function(){n.find(".popover-title").html('error_outline '+(s.error||"Error"));var e='
';e+='error_outline',e+="

"+(s.error_loading||"Error loading holidays")+"

",e+="
",n.find(".popover-body").html(e)}})}}}(jQuery),function(e){"use strict";window._EntitySelectorMixins=window._EntitySelectorMixins||{},window._EntitySelectorMixins.tree={treeData:null,treeFlatData:null,loadCategoryTree:function(){var t=this,i=this.$dropdown.find(".dropdown-results"),a=this.config.trans||{},s=this.activeGroup?this.activeGroup.searchEntity:"categories";i.html('
'+this.escapeHtml(a.loading||"Loading...")+"
"),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"getCategoryTree",trait:"EntitySelector",entity_type:s},success:function(e){e.success&&e.categories&&e.categories.length>0?(t.treeFlatData=e.categories,t.treeData=t.buildTreeStructure(e.categories),t.renderCategoryTree(i,s)):i.html('")},error:function(){i.html('")}})},buildTreeStructure:function(t){var i={},a=[];return t.forEach(function(t){i[t.id]=e.extend({},t,{children:[]})}),t.forEach(function(e){var t=i[e.id],s=parseInt(e.parent_id,10);s&&i[s]?i[s].children.push(t):a.push(t)}),a},renderCategoryTree:function(e,t){var i=this.config.trans||{},a=this.getSelectedIdsFromChips(),s='
';s+='
',s+='",s+='",s+="
",s+='
',s+=this.renderTreeItems(this.treeData,0,a),s+="
",s+="
",e.html(s);var o=this.treeFlatData?this.treeFlatData.length:0,n=a.length,r=o+" "+("cms_categories"===t?"CMS categories":"categories");n>0&&(r+=" ("+n+" selected)"),this.$dropdown.find(".results-count").text(r),this.updateSelectChildrenButtons(this.$dropdown.find(".tree-item"))},renderTreeItems:function(e,t,i){var a=this,s="",o=this.config.trans||{};return e.forEach(function(e){var n=e.children&&e.children.length>0,r=-1!==i.indexOf(parseInt(e.id,10)),l=20*t,c="tree-item";n&&(c+=" has-children"),r&&(c+=" selected"),e.active||(c+=" inactive"),s+='
',s+='',n?(s+='',s+='"):s+='',s+='',s+='',s+=''+a.escapeHtml(e.name)+"";var d=e.product_count||e.page_count||0;if(d>0){var p=e.page_count?o.pages||"pages":o.products||"products";s+='',s+=' '+d,s+=""}e.active||(s+=''+a.escapeHtml(o.inactive||"Inactive")+""),s+="
",n&&(s+='
',s+=a.renderTreeItems(e.children,t+1,i),s+="
")}),s},getSelectedIdsFromChips:function(){var t=[];if(!this.activeGroup)return t;var i=this.$wrapper.find('.target-block[data-block-type="'+this.activeGroup.blockType+'"]').find('.selection-group[data-group-index="'+this.activeGroup.groupIndex+'"]');return("include"===this.activeGroup.section?i.find(".include-picker"):i.find('.exclude-row[data-exclude-index="'+this.activeGroup.excludeIndex+'"]').find(".exclude-picker")).find(".entity-chip").each(function(){t.push(parseInt(e(this).data("id"),10))}),t},filterCategoryTree:function(t){var i=this.$dropdown.find(".category-tree");if(i.length){var a=i.find(".tree-item"),s=i.find(".tree-children");if(t=(t||"").toLowerCase().trim(),a.css("display",""),!t)return a.removeClass("filtered-out filter-match"),void s.removeClass("filter-expanded");a.addClass("filtered-out").removeClass("filter-match"),a.each(function(){var i=e(this);-1!==(i.data("name")||"").toLowerCase().indexOf(t)&&(i.removeClass("filtered-out"),i.parents(".tree-children").addClass("filter-expanded"),i.parents(".tree-item").removeClass("filtered-out"),i.next(".tree-children").find(".tree-item").removeClass("filtered-out"),i.next(".tree-children").addClass("filter-expanded"))})}},findTreeDescendants:function(e,t){var i=[],a=(parseInt(e.data("id"),10),parseInt(e.data("level"),10),e.next(".tree-children"));return a.length&&a.find(".tree-item").each(function(){i.push(this)}),i},updateSelectChildrenButtons:function(t){var i=this.config.trans||{};t.filter(".has-children").each(function(){var t=e(this),a=t.find(".btn-select-children");if(a.length){var s=t.next(".tree-children");if(s.length){var o=s.find(".tree-item"),n=t.hasClass("selected"),r=!0;o.each(function(){if(!e(this).hasClass("selected"))return r=!1,!1}),n&&r?(a.find("i").removeClass("icon-plus-square").addClass("icon-minus-square"),a.attr("title",i.deselect_with_children||"Deselect with all children")):(a.find("i").removeClass("icon-minus-square").addClass("icon-plus-square"),a.attr("title",i.select_with_children||"Select with all children"))}}})}}}(jQuery),function(e){"use strict";window._EntitySelectorMixins=window._EntitySelectorMixins||{},window._EntitySelectorMixins.validation={validateSelection:function(t,i,a,s){if(!this.activeGroup)return{valid:!0};var o=this.config.trans||{};t=parseInt(t,10);var n=this.$wrapper.find('.target-block[data-block-type="'+this.activeGroup.blockType+'"]').find('.selection-group[data-group-index="'+this.activeGroup.groupIndex+'"]'),r=this.getChipIds(n.find(".include-picker")),l=[];n.find(".exclude-row").each(function(){var t=e(this).find(".exclude-picker"),i=[];t.find(".entity-chip").each(function(){i.push(parseInt(e(this).data("id"),10))}),l=l.concat(i)});var c=this.checkIncludeExcludeConflict(t,i,a,r,l,o);if(!c.valid)return c;var d=this.checkRedundantSelection(t,i,a,r,l,o);if(!d.valid)return d;var p=this.activeGroup.searchEntity;if("categories"===p||"cms_categories"===p){var u=this.checkTreeConflicts(t,i,a,s,r,l,o);if(!u.valid)return u}return{valid:!0}},checkIncludeExcludeConflict:function(e,t,i,a,s,o){return"include"===i&&-1!==s.indexOf(e)?{valid:!1,type:"include_exclude_conflict",error:(o.error_in_exclude||'"{name}" is already in the exclude list. Remove it from exclude first.').replace("{name}",t)}:"exclude"===i&&-1!==a.indexOf(e)?{valid:!1,type:"include_exclude_conflict",error:(o.error_in_include||'"{name}" is already in the include list. Remove it from include first.').replace("{name}",t)}:{valid:!0}},checkRedundantSelection:function(e,t,i,a,s,o){return"include"===i&&-1!==a.indexOf(e)?{valid:!1,type:"redundant",error:(o.error_already_selected||'"{name}" is already selected.').replace("{name}",t)}:"exclude"===i&&-1!==s.indexOf(e)?{valid:!1,type:"redundant",error:(o.error_already_excluded||'"{name}" is already in an exclude list.').replace("{name}",t)}:{valid:!0}},checkTreeConflicts:function(e,t,i,a,s,o,n){if(!this.treeFlatData)return{valid:!0};a&&a.parentId&&parseInt(a.parentId,10);var r={};this.treeFlatData.forEach(function(e){r[parseInt(e.id,10)]=e});var l=this.getAncestorIds(e,r),c=this.getDescendantIds(e,r);if("include"===i){for(var d=0;d0)return{valid:!1,type:"children_included",error:(n.error_children_included||'Cannot exclude "{name}" because its children ({children}) are included. Remove them from include first.').replace("{name}",t).replace("{children}",m.slice(0,3).join(", ")+(m.length>3?"...":""))}}return{valid:!0}},getAncestorIds:function(e,t){for(var i=[],a=t[e];a&&a.parent_id;){var s=parseInt(a.parent_id,10);if(!s||!t[s])break;i.push(s),a=t[s]}return i},getDescendantIds:function(e,t){var i=[],a=this;return Object.keys(t).forEach(function(s){var o=t[s];if(parseInt(o.parent_id,10)===e){var n=parseInt(o.id,10);i.push(n);var r=a.getDescendantIds(n,t);i=i.concat(r)}}),i},getChipIds:function(t){var i=[];return t.find(".entity-chip").each(function(){i.push(parseInt(e(this).data("id"),10))}),i},validatePendingSelections:function(e,t){var i=this,a=[];return e&&e.length?(e.forEach(function(e){var s=i.validateSelection(e.id,e.name,t,e.data||{});s.valid||a.push({id:e.id,name:e.name,error:s.error,type:s.type})}),a):a},showValidationError:function(t){var i=(this.config.trans||{}).validation_error||"Selection Conflict";e(".es-validation-toast").remove();var a='
';a+='
',a+='
',a+='
'+this.escapeHtml(i)+"
",a+='
'+this.escapeHtml(t)+"
",a+="
",a+='';var s=e(a+="
");if(e("body").append(s),this.$dropdown&&this.$dropdown.hasClass("show")){var o=this.$dropdown.offset();s.css({position:"fixed",top:o.top-s.outerHeight()-10,left:o.left,zIndex:10001})}else s.css({position:"fixed",top:20,right:20,zIndex:10001});s.hide().fadeIn(200),setTimeout(function(){s.fadeOut(200,function(){e(this).remove()})},5e3),s.on("click",".es-toast-close",function(){s.fadeOut(200,function(){e(this).remove()})})},validateAndAddSelection:function(e,t,i,a,s){var o=this.validateSelection(t,i,s,a||{});return o.valid?(this.addSelection(e,t,i,a),!0):(this.showValidationError(o.error),!1)}}}(jQuery),function(e){"use strict";var t={instances:[],create:function(t){var i=function(){var t={config:{},$wrapper:null,$dropdown:null,activeGroup:null,searchTimeout:null,searchResults:[],searchTotal:0,searchOffset:0,searchQuery:"",isLoading:!1,loadMoreCount:20,viewMode:"list",currentSort:{field:"name",dir:"ASC"},refineQuery:"",refineNegate:!1,filters:{inStock:!1,discounted:!1,priceMin:null,priceMax:null,attributes:[],features:[],productCountMin:null,productCountMax:null,salesMin:null,salesMax:null,turnoverMin:null,turnoverMax:null,depth:null,hasProducts:!1,hasDescription:!1,hasImage:!1,activeOnly:!0,attributeGroup:null,featureGroup:null,dateAddFrom:null,dateAddTo:null,lastProductFrom:null,lastProductTo:null,hasHolidays:!1,containsStates:!1,zone:null},filterableData:null,searchHistory:{},searchHistoryMax:10,searchHistoryKey:"targetConditionsSearchHistory",maxVisibleChips:20,$methodDropdownMenu:null,$methodDropdownSelect:null,$methodDropdownTrigger:null,$previewPopover:null,$activeBadge:null,$previewList:null,previewLoadedCount:0,previewBlockType:null,allPreviewData:null,countUpdateTimeout:null,init:function(t){if(this.config=e.extend({id:"target-conditions",name:"target_conditions",namePrefix:"target_",mode:"multi",blocks:{},ajaxUrl:"",trans:{}},t),this.$wrapper=e('[data-entity-selector-id="'+this.config.id+'"]'),this.$wrapper.length){"single"===this.config.mode&&(this.$wrapper.find(".btn-add-group").hide(),this.$wrapper.find(".group-excludes").hide(),this.$wrapper.find(".group-modifiers").hide());var i=this.$wrapper.hasClass("layout-form-group"),a=this.$wrapper.closest(".entity-selector-form-group");if(!i&&!a.length){var s=this.$wrapper.closest(".form-group");s.addClass("condition-trait-fullwidth"),s.find(".col-lg-offset-3").removeClass("col-lg-offset-3")}this.createDropdown(),this.bindEvents(),this.loadExistingSelections(),this.loadSearchHistory(),this.initMethodDropdowns(),this.observeNewSelects();var o=this;setTimeout(function(){o.updateTabBadges(),o.updateAllConditionCounts()},100)}},observeNewSelects:function(){var t=this;"undefined"!=typeof MutationObserver&&new MutationObserver(function(i){i.forEach(function(i){i.addedNodes.length&&e(i.addedNodes).find(".include-method-select, .exclude-method-select").each(function(){t.enhanceMethodSelect(e(this))})})}).observe(this.$wrapper[0],{childList:!0,subtree:!0})},loadExistingSelections:function(){}},i=window._EntitySelectorMixins||{};return i.utils&&e.extend(t,i.utils),i.events&&e.extend(t,i.events),i.dropdown&&e.extend(t,i.dropdown),i.search&&e.extend(t,i.search),i.filters&&e.extend(t,i.filters),i.chips&&e.extend(t,i.chips),i.groups&&e.extend(t,i.groups),i.methods&&e.extend(t,i.methods),i.preview&&e.extend(t,i.preview),i.tree&&e.extend(t,i.tree),i.validation&&e.extend(t,i.validation),t}();return i.init(t),this.instances.push(i),i},init:function(e){return this.create(e)},validateAll:function(){for(var e=!0,t=0;t0&&!t.validateAll())return i.preventDefault(),!1})})}(jQuery); +!function(e){"use strict";window._EntitySelectorMixins=window._EntitySelectorMixins||{};var t=null,i={account_tree:"icon-sitemap",add:"icon-plus",add_box:"icon-plus-square",arrow_downward:"icon-sort-desc",arrow_drop_down:"icon-caret-down",arrow_right:"icon-chevron-right",arrow_upward:"icon-sort-asc",block:"icon-ban",brush:"icon-paint-brush",business:"icon-building",check:"icon-check",check_box:"icon-check-square",check_box_outline_blank:"icon-square-o",check_circle:"icon-check-circle",close:"icon-times",delete:"icon-trash",description:"icon-file-text",error:"icon-exclamation-circle",event:"icon-calendar",event_busy:"icon-calendar-times-o",expand_less:"icon-chevron-up",expand_more:"icon-chevron-down",filter_list:"icon-filter",flag:"icon-flag",folder:"icon-folder",folder_open:"icon-folder-open",indeterminate_check_box:"icon-minus-square",info:"icon-info-circle",inventory_2:"icon-archive",label:"icon-tag",language:"icon-globe",lightbulb:"icon-lightbulb-o",list:"icon-list",list_alt:"icon-list-alt",local_shipping:"icon-truck",lock:"icon-lock",my_location:"icon-crosshairs",open_in_full:"icon-expand",payments:"icon-credit-card",progress_activity:"icon-circle-o-notch",schedule:"icon-clock-o",search:"icon-search",shopping_cart:"icon-shopping-cart",shuffle:"icon-random",sort:"icon-sort",sort_by_alpha:"icon-sort-alpha-asc",star:"icon-star",sync:"icon-refresh",tune:"icon-sliders",visibility:"icon-eye",warning:"icon-warning",widgets:"icon-th-large"},a=null,s={"icon-cube":"inventory","icon-folder-o":"folder","icon-file-text-o":"description","icon-briefcase":"work","icon-user":"person","icon-users":"group","icon-money":"payments","icon-tasks":"checklist","icon-calculator":"calculate","icon-asterisk":"star","icon-bar-chart":"bar_chart","icon-cogs":"settings","icon-cog":"settings","icon-tags":"label","icon-list-ul":"list","icon-th":"grid_view","icon-certificate":"verified","icon-power-off":"power_settings_new","icon-circle-o":"radio_button_unchecked"};function o(e,t){var o="";if(0===e.indexOf("icon-")){var n=e.indexOf(" "),r=-1!==n?e.substring(0,n):e;if(-1!==n&&(o=e.substring(n+1)),"material"===t){var l=function(){if(null!==a)return a;for(var e in a={},i)if(i.hasOwnProperty(e)){var t=i[e];a[t]||(a[t]=e)}for(var o in s)s.hasOwnProperty(o)&&!a[o]&&(a[o]=s[o]);return a}(),c=l[r];return c?{name:c,extra:o,rawFa4:!1}:{name:r.substring(5).replace(/-/g,"_"),extra:o,rawFa4:!1}}return{name:r,extra:o,rawFa4:!0}}return{name:e,extra:o,rawFa4:!1}}function n(){if(null!==t)return t;var i=e(".entity-selector-trait[data-icon-mode], .target-conditions-trait[data-icon-mode]").first();if(i.length&&i.data("icon-mode"))return t=i.data("icon-mode");var a=document.createElement("i");a.className="material-icons",a.style.cssText="position:absolute;left:-9999px;top:-9999px;font-size:16px;pointer-events:none",a.textContent="check",(document.body||document.documentElement).appendChild(a);var s=(window.getComputedStyle(a).fontFamily||"").toLowerCase();return a.parentNode.removeChild(a),t=-1!==s.indexOf("material")?"material":"fa4"}window._EntitySelectorMixins.utils={debounce:function(e,t){var i;return function(){var a=this,s=arguments;clearTimeout(i),i=setTimeout(function(){e.apply(a,s)},t)}},escapeHtml:function(e){return null==e?"":String(e).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")},escapeAttr:function(e){return null==e?"":String(e).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")},esIcon:function(e,t){var a=n(),s=o(e,a),r=s.name;if(s.extra&&(t=t?t+" "+s.extra:s.extra),"material"===a){var l="material-icons es-icon";return t&&(l+=" "+t),''+r+""}return l=s.rawFa4?r+" es-icon":(i[r]||"icon-circle")+" es-icon",t&&(l+=" "+t),''},esIconUpdate:function(e,t,a){var s=n(),r=o(t,s),l=r.name;if(r.extra&&(a=a?a+" "+r.extra:r.extra),"material"===s){var c="material-icons es-icon";a&&(c+=" "+a),e.attr("class",c).text(l)}else c=r.rawFa4?l+" es-icon":(i[l]||"icon-circle")+" es-icon",a&&(c+=" "+a),e.attr("class",c).text("")},getEntityTypeIcon:function(e){return{products:"shopping_cart",categories:"folder_open",manufacturers:"business",suppliers:"local_shipping",attributes:"list_alt",features:"label",cms:"description",cms_categories:"folder"}[e]||"widgets"},getEntityTypeLabel:function(e){var t=this.config.trans||{};return{products:t.product||"Product",categories:t.category||"Category",manufacturers:t.manufacturer||"Manufacturer",suppliers:t.supplier||"Supplier",attributes:t.attribute||"Attribute",features:t.feature||"Feature",cms:t.cms_page||"CMS Page",cms_categories:t.cms_category||"CMS Category"}[e]||e},validate:function(){if(1!==this.$wrapper.data("required")&&"1"!==this.$wrapper.data("required"))return!0;var t=!1;return this.$wrapper.find(".target-block").each(function(){if(e(this).find(".selection-group").length>0)return t=!0,!1}),t?(this.clearValidationError(),!0):(this.showValidationError(),!1)},showValidationError:function(){this.$wrapper.addClass("has-validation-error");var t=this.$wrapper.data("required-message")||"Please select at least one item";this.$wrapper.find(".trait-validation-error").remove();var i=e("
",{class:"trait-validation-error",html:this.esIcon("warning")+" "+t});this.$wrapper.find(".condition-trait-header").after(i),e("html, body").animate({scrollTop:this.$wrapper.offset().top-100},300),this.$wrapper.find(".condition-trait-body").is(":visible")||(this.$wrapper.find(".condition-trait-body").slideDown(200),this.$wrapper.removeClass("collapsed"))},clearValidationError:function(){this.$wrapper.removeClass("has-validation-error"),this.$wrapper.find(".trait-validation-error").remove()},getBlockMode:function(e){var t=this.config.blocks[e];return t&&t.mode?t.mode:"multi"},isBlockSingleMode:function(e){return"single"===this.getBlockMode(e)},getCurrentSingleSelection:function(){if("single"!==(this.config.mode||"multi"))return null;var e=this.$wrapper.find(".entity-chips .entity-chip").first();if(e.length){var t=e.closest(".target-block");return{name:e.find(".chip-name").text()||e.data("id"),entityType:t.data("block-type")||"item"}}return null},supportsTreeBrowsing:function(e){return"categories"===e||"cms_categories"===e}}}(jQuery),function(e){"use strict";window._EntitySelectorMixins=window._EntitySelectorMixins||{},window._EntitySelectorMixins.events={bindEvents:function(){var t=this;this.$wrapper.on("click",".target-block-tab",function(i){i.preventDefault();var a=e(this).data("blockType");t.switchToBlock(a)}),this.$wrapper.on("click",".target-block-tab .tab-badge",function(i){i.stopPropagation(),i.preventDefault();var a=e(this).closest(".target-block-tab");e(this).hasClass("popover-open")?t.hidePreviewPopover():t.showPreviewPopover(a)}),this.$wrapper.on("click",".condition-match-count.clickable",function(i){i.stopPropagation(),i.preventDefault();var a=e(this);a.hasClass("popover-open")?t.hidePreviewPopover():t.showConditionPreviewPopover(a)}),this.$wrapper.on("click",".group-count-badge.clickable",function(i){i.stopPropagation(),i.preventDefault();var a=e(this);a.hasClass("popover-open")?t.hidePreviewPopover():t.showGroupPreviewPopover(a)}),this.$wrapper.on("click",".trait-total-count",function(i){i.stopPropagation(),i.preventDefault();var a=e(this);a.hasClass("popover-open")?t.hidePreviewPopover():t.showTotalPreviewPopover(a)}),e(document).on("click",function(i){e(i.target).closest(".target-preview-popover").length||e(i.target).closest(".holiday-preview-popover").length||e(i.target).closest(".tab-badge").length||e(i.target).closest(".condition-match-count").length||e(i.target).closest(".group-count-badge").length||e(i.target).closest(".group-modifiers").length||e(i.target).closest(".group-preview-badge").length||e(i.target).closest(".toggle-count.clickable").length||e(i.target).closest(".trait-total-count").length||e(i.target).closest(".chip-preview-holidays").length||(t.hidePreviewPopover(),e(".holiday-preview-popover").remove())}),this.$wrapper.on("click",".condition-trait-header",function(i){if(!(e(i.target).closest(".target-block-tabs").length||e(i.target).closest(".trait-header-actions").length||e(i.target).closest(".prestashop-switch").length||e(i.target).closest(".trait-total-count").length)){var a=t.$wrapper.find(".condition-trait-body");a.stop(!0,!0),a.is(":visible")?(a.slideUp(200),t.$wrapper.addClass("collapsed")):(a.slideDown(200),t.$wrapper.removeClass("collapsed"))}}),this.$wrapper.on("click",".btn-toggle-blocks",function(i){i.preventDefault();var a=t.$wrapper.find(".entity-selector-blocks-content"),s=e(this).find(".es-icon");a.stop(!0,!0),a.is(":visible")?(a.slideUp(200),t.$wrapper.addClass("blocks-collapsed"),s.text("expand_more")):(a.slideDown(200),t.$wrapper.removeClass("blocks-collapsed"),s.text("expand_less"))}),this.$wrapper.on("input change",".custom-block-content input, .custom-block-content textarea, .custom-block-content select",function(){t.updateTabBadges()}),this.$wrapper.on("click",".group-header",function(i){e(i.target).closest(".btn-remove-group, .group-name-input").length||"single"!==t.$wrapper.data("mode")&&e(this).closest(".selection-group").toggleClass("collapsed")}),this.$wrapper.on("click",".btn-toggle-groups",function(i){i.preventDefault(),i.stopPropagation();var a=e(this),s=a.attr("data-state")||"collapsed",o=t.config.trans||{};"collapsed"===s?(t.$wrapper.find(".selection-group").removeClass("collapsed"),a.attr("data-state","expanded"),a.attr("title",o.collapse_all||"Collapse all groups"),a.find("i").text("close_fullscreen")):(t.$wrapper.find(".selection-group").addClass("collapsed"),a.attr("data-state","collapsed"),a.attr("title",o.expand_all||"Expand all groups"),a.find("i").text("open_in_full"))}),this.$wrapper.on("change",".trait-show-all-toggle .show-all-checkbox",function(i){i.stopPropagation(),e(this).prop("checked")&&t.clearAllConditions()}),this.$wrapper.on("change",".target-switch-toggle",function(i){i.stopPropagation(),"1"===e(this).val()?(t.clearAllConditions(),t.$wrapper.find(".condition-trait-body").slideUp(200),t.$wrapper.addClass("collapsed")):(t.$wrapper.find(".condition-trait-body").slideDown(200),t.$wrapper.removeClass("collapsed"))}),this.$wrapper.on("click",".btn-add-group",function(i){i.preventDefault();var a=e(this).closest(".target-block"),s=a.data("blockType");t.addGroup(a,s)}),this.$wrapper.on("click",".btn-remove-group",function(i){i.preventDefault();var a=e(this).closest(".selection-group"),s=e(this).closest(".target-block");t.removeGroup(a,s)}),this.$wrapper.on("click focus",".group-name-input",function(e){e.stopPropagation()}),this.$wrapper.on("change blur",".group-name-input",function(){var i=e(this),a=i.closest(".selection-group"),s=e.trim(i.val());a.attr("data-group-name",s),t.serializeAllBlocks()}),this.$wrapper.on("click",".btn-add-exclude",function(i){i.preventDefault();var a=e(this).closest(".selection-group"),s=e(this).closest(".target-block");t.addFirstExcludeRow(a,s)}),this.$wrapper.on("click",".btn-add-another-exclude",function(i){i.preventDefault();var a=e(this).closest(".selection-group"),s=e(this).closest(".target-block");t.addExcludeRow(a,s)}),this.$wrapper.on("click",".btn-remove-exclude-row",function(i){i.preventDefault();var a=e(this).closest(".exclude-row"),s=e(this).closest(".selection-group"),o=e(this).closest(".target-block");t.removeExcludeRow(a,s,o)}),this.$wrapper.on("change",".include-method-select",function(){t.hideDropdown();var i=e(this).closest(".selection-group"),a=e(this).closest(".target-block"),s=i.find(".group-include"),o=a.data("blockType"),n=(t.config.blocks[o]||{}).selection_methods||{},r=e(this).find("option:selected"),l=r.data("valueType")||"none",c=r.data("searchEntity")||"",d=r.data("options")||null,p=i.find(".include-picker"),u=t.buildValuePickerHtml("include",l,c,n);if(p.replaceWith(u),"select"===l&&d){var h=(f=i.find(".include-picker")).find(".select-value-input");h.empty(),e.each(d,function(e,i){h.append('")})}if("multi_select_tiles"===l&&d){var f=i.find(".include-picker"),v=!0===r.data("exclusive");t.populateTiles(f,d,v)}if("multi_numeric_range"===l){f=i.find(".include-picker");var g=r.data("step"),m=r.data("min");t.applyRangeInputConstraints(f,g,m)}"combination_attributes"===l&&(f=i.find(".include-picker"),t.loadCombinationAttributeGroups(f));var b=e(this).val();t.updateMethodInfoPlaceholder(i.find(".method-selector-wrapper"),b,o),t.updateBlockStatus(a),t.serializeAllBlocks(s)}),this.$wrapper.on("change",".exclude-method-select",function(){t.hideDropdown();var i=e(this).closest(".exclude-row"),a=(e(this).closest(".selection-group"),e(this).closest(".target-block").data("blockType")),s=(t.config.blocks[a]||{}).selection_methods||{},o=e(this).find("option:selected"),n=o.data("valueType")||"entity_search",r=o.data("searchEntity")||a,l=o.data("options")||null,c=i.find(".exclude-picker"),d=t.buildValuePickerHtml("exclude",n,r,s);if(c.replaceWith(d),"select"===n&&l){var p=(u=i.find(".exclude-picker")).find(".select-value-input");p.empty(),e.each(l,function(e,i){p.append('")})}if("multi_select_tiles"===n&&l){var u=i.find(".exclude-picker"),h=!0===o.data("exclusive");t.populateTiles(u,l,h)}if("multi_numeric_range"===n){u=i.find(".exclude-picker");var f=o.data("step"),v=o.data("min");t.applyRangeInputConstraints(u,f,v)}"combination_attributes"===n&&(u=i.find(".exclude-picker"),t.loadCombinationAttributeGroups(u));var g=e(this).val();t.updateMethodInfoPlaceholder(i.find(".exclude-header-row"),g,a),t.serializeAllBlocks(i)}),this.$wrapper.on("keydown",".pattern-input",function(t){13===t.keyCode&&(t.preventDefault(),e(this).closest(".draft-tag").find(".btn-add-pattern").click())}),this.$wrapper.on("click",".draft-tag .btn-add-pattern",function(i){i.preventDefault(),i.stopPropagation();var a=e(this).closest(".draft-tag"),s=a.closest(".value-picker"),o=a.closest(".group-include, .exclude-row"),n=a.find(".pattern-input"),r=e.trim(n.val());if(r){var l="1"===a.attr("data-case-sensitive");t.addPatternTag(s,r,l),n.val("").focus(),a.find(".pattern-match-count").removeClass("count-found count-zero").hide(),a.find(".pattern-match-count .count-value").text(""),t.serializeAllBlocks(o)}}),this.$wrapper.on("input",".pattern-input",function(){var i=e(this),a=i.closest(".draft-tag");if(a.length){var s=e.trim(i.val());i.data("countTimeout")&&clearTimeout(i.data("countTimeout"));var o=a.find(".pattern-match-count");if(s){var n=setTimeout(function(){var e="1"===a.attr("data-case-sensitive");t.updateDraftTagCount(a,s,e)},300);i.data("countTimeout",n)}else{o.removeClass("count-found count-zero").hide(),o.find(".count-value").text("");var r=a.closest(".selection-group");r.length&&t.updateGroupTotalCount(r)}}}),this.$wrapper.on("click",".pattern-tag .btn-remove-pattern",function(i){i.preventDefault(),i.stopPropagation();var a=e(this).closest(".group-include, .exclude-row");e(this).closest(".pattern-tag").remove(),t.serializeAllBlocks(a)}),this.$wrapper.on("click",".pattern-tag .btn-toggle-case",function(i){i.preventDefault(),i.stopPropagation();var a=e(this).closest(".pattern-tag"),s=e(this),o=t.config.trans||{},n=a.hasClass("draft-tag"),r=!(1===a.data("caseSensitive")||"1"===a.data("caseSensitive")||"1"===a.attr("data-case-sensitive"));a.data("caseSensitive",r?1:0),a.attr("data-case-sensitive",r?"1":"0"),a.toggleClass("case-sensitive",r),s.find(".case-icon").text(r?"Aa":"aa");var l=r?o.case_sensitive||"Case sensitive - click to toggle":o.case_insensitive||"Case insensitive - click to toggle";if(s.attr("title",l),n){var c=e.trim(a.find(".pattern-input").val());c&&t.updateDraftTagCount(a,c,r)}else{var d=a.closest(".group-include, .exclude-row");t.serializeAllBlocks(d)}}),this.$wrapper.on("click",".pattern-match-count",function(i){i.preventDefault(),i.stopPropagation();var a=e(this),s=a.data("count"),o=a.data("pattern"),n=a.data("entityType"),r=a.data("caseSensitive");!s||s<=0||!o||t.showPatternPreviewModal(o,n,r,s)}),this.$wrapper.on("click",".pattern-tag .pattern-tag-text",function(t){t.preventDefault();var i=e(this).closest(".pattern-tag");if(!i.hasClass("editing")){var a=i.data("pattern"),s=e('').val(a),o=e('"),n=e('"),r=e('').append(o,n);i.addClass("editing").find(".pattern-tag-text").hide(),i.find(".btn-remove-pattern").hide(),i.prepend(r).prepend(s),s.focus().select(),s.on("keydown",function(e){13===e.keyCode?(e.preventDefault(),o.click()):27===e.keyCode&&(e.preventDefault(),n.click())})}}),this.$wrapper.on("click",".pattern-tag .btn-pattern-save",function(i){i.preventDefault(),i.stopPropagation();var a=e(this).closest(".pattern-tag"),s=a.find(".pattern-tag-edit"),o=a.data("pattern"),n=e.trim(s.val());n&&n!==o&&(a.data("pattern",n),a.find(".pattern-tag-text").text(n)),s.remove(),a.find(".pattern-edit-actions").remove(),a.removeClass("editing").find(".pattern-tag-text, .btn-remove-pattern").show();var r=a.closest(".group-include, .exclude-row");t.serializeAllBlocks(r)}),this.$wrapper.on("click",".pattern-tag .btn-pattern-cancel",function(t){t.preventDefault(),t.stopPropagation();var i=e(this).closest(".pattern-tag");i.find(".pattern-tag-edit").remove(),i.find(".pattern-edit-actions").remove(),i.removeClass("editing").find(".pattern-tag-text, .btn-remove-pattern").show()}),this.$wrapper.on("change",".range-min-input, .range-max-input",function(){var i=e(this).closest(".group-include, .exclude-row");t.serializeAllBlocks(i)}),this.$wrapper.on("change",".date-from-input, .date-to-input",function(){var i=e(this).closest(".group-include, .exclude-row");t.serializeAllBlocks(i)}),this.$wrapper.on("change",".select-value-input",function(){var i=e(this).closest(".group-include, .exclude-row");t.serializeAllBlocks(i)}),this.$wrapper.on("click",".btn-add-range",function(i){i.preventDefault();var a=e(this).closest(".value-picker"),s=e(this).closest(".group-include, .exclude-row"),o=a.find(".multi-range-container"),n=o.find(".multi-range-chips"),r=o.find(".range-min-input"),l=o.find(".range-max-input"),c=r.val().trim(),d=l.val().trim();if(""!==c||""!==d){var p=parseFloat(r.attr("step"))||.01,u=r.attr("min"),h=void 0!==u&&""!==u;u=h?parseFloat(u):null;var f=""!==c?parseFloat(c):null,v=""!==d?parseFloat(d):null;if(h){if(null!==f&&fv)t.showRangeInputError(r,t.config.trans.min_greater_than_max||"Min cannot be greater than max");else{var g,m=p<1?String(p).split(".")[1].length:0;null!==f&&(f=p>=1?Math.round(f):parseFloat(f.toFixed(m)),c=String(f)),null!==v&&(v=p>=1?Math.round(v):parseFloat(v.toFixed(m)),d=String(v)),g=""!==c&&""!==d?c+" - "+d:""!==c?"≥ "+c:"≤ "+d;var b=e("",{class:"range-chip","data-min":c,"data-max":d});b.append(e("",{class:"range-chip-text",text:g})),b.append(e("",i+='",i+='
',i+='",i+='",i+='",i+="
",i+='
',i+='",i+='',i+='",i+="
",i+='",i+='",i+="
",i+="",i+='
',i+='
',i+='",i+='",i+='
',i+=''+(t.price||"Price")+":",i+='',i+='-',i+='',i+="
",i+='",i+="
",i+='",i+='",i+='",i+='",i+='",i+='",i+='",i+='",i+='",i+='",i+='",i+='",i+="
",i+='
',i+='',i+=''+(t.product||"Product")+"",i+=''+(t.price||"Price")+"",i+=''+(t.sale||"Sale")+"",i+=''+(t.stock||"Stock")+"",i+=''+(t.sold||"Sold")+"",i+="
",i+='',i+='",i+="",this.$dropdown=e(i),e("body").append(this.$dropdown)},hideDropdown:function(){this.$dropdown&&this.$dropdown.removeClass("show"),this.activeGroup=null},positionDropdown:function(t){if(this.$dropdown){var i=t.closest(".value-picker"),a=t.closest(".entity-search-box"),s=a.offset(),o=a.outerHeight(),n=i.offset(),r=i.outerWidth(),l=s.top+o+4,c=n.left,d=Math.max(r,400),p=e(window).width();c+d>p-10&&(d=p-c-10);var u=e(window).height()-(l-e(window).scrollTop())-20;u=Math.max(u,400),this.$dropdown.css({position:"absolute",top:l,left:c,width:d,maxHeight:u,zIndex:1e4}),this.$dropdown.addClass("show")}}}}(jQuery),function(e){"use strict";window._EntitySelectorMixins=window._EntitySelectorMixins||{},window._EntitySelectorMixins.search={categoryTreeCache:null,performSearch:function(t){var i=this;if(this.activeGroup){this.isLoading=!0;var a=this.activeGroup.searchEntity,s=t&&this.loadMoreCount?this.loadMoreCount:20,o={ajax:1,action:"searchTargetEntities",trait:"EntitySelector",entity_type:a,q:this.searchQuery,limit:s,offset:t?this.searchOffset:0,sort_by:this.currentSort?this.currentSort.field:"name",sort_dir:this.currentSort?this.currentSort.dir:"ASC"};this.refineQuery&&(o.refine=this.refineQuery,this.refineNegate&&(o.refine_negate=1)),"products"===a&&this.filters&&(this.filters.inStock&&(o.filter_in_stock=1),this.filters.discounted&&(o.filter_discounted=1),null!==this.filters.priceMin&&""!==this.filters.priceMin&&(o.filter_price_min=this.filters.priceMin),null!==this.filters.priceMax&&""!==this.filters.priceMax&&(o.filter_price_max=this.filters.priceMax),this.filters.attributes&&this.filters.attributes.length>0&&(o.filter_attributes=JSON.stringify(this.filters.attributes)),this.filters.features&&this.filters.features.length>0&&(o.filter_features=JSON.stringify(this.filters.features))),"products"!==a&&this.filters&&(null!==this.filters.productCountMin&&""!==this.filters.productCountMin&&(o.filter_product_count_min=this.filters.productCountMin),null!==this.filters.productCountMax&&""!==this.filters.productCountMax&&(o.filter_product_count_max=this.filters.productCountMax),"categories"===a&&(this.filters.depth&&(o.filter_depth=this.filters.depth),this.filters.hasProducts&&(o.filter_has_products=1),this.filters.hasDescription&&(o.filter_has_description=1),this.filters.hasImage&&(o.filter_has_image=1),null!==this.filters.salesMin&&""!==this.filters.salesMin&&(o.filter_sales_min=this.filters.salesMin),null!==this.filters.salesMax&&""!==this.filters.salesMax&&(o.filter_sales_max=this.filters.salesMax),null!==this.filters.turnoverMin&&""!==this.filters.turnoverMin&&(o.filter_turnover_min=this.filters.turnoverMin),null!==this.filters.turnoverMax&&""!==this.filters.turnoverMax&&(o.filter_turnover_max=this.filters.turnoverMax),this.filters.activeOnly&&(o.filter_active=1)),"manufacturers"===a&&(null!==this.filters.salesMin&&""!==this.filters.salesMin&&(o.filter_sales_min=this.filters.salesMin),null!==this.filters.salesMax&&""!==this.filters.salesMax&&(o.filter_sales_max=this.filters.salesMax),null!==this.filters.turnoverMin&&""!==this.filters.turnoverMin&&(o.filter_turnover_min=this.filters.turnoverMin),null!==this.filters.turnoverMax&&""!==this.filters.turnoverMax&&(o.filter_turnover_max=this.filters.turnoverMax),this.filters.dateAddFrom&&(o.filter_date_add_from=this.filters.dateAddFrom),this.filters.dateAddTo&&(o.filter_date_add_to=this.filters.dateAddTo),this.filters.lastProductFrom&&(o.filter_last_product_from=this.filters.lastProductFrom),this.filters.lastProductTo&&(o.filter_last_product_to=this.filters.lastProductTo),this.filters.activeOnly&&(o.filter_active=1)),"suppliers"===a&&(null!==this.filters.salesMin&&""!==this.filters.salesMin&&(o.filter_sales_min=this.filters.salesMin),null!==this.filters.salesMax&&""!==this.filters.salesMax&&(o.filter_sales_max=this.filters.salesMax),null!==this.filters.turnoverMin&&""!==this.filters.turnoverMin&&(o.filter_turnover_min=this.filters.turnoverMin),null!==this.filters.turnoverMax&&""!==this.filters.turnoverMax&&(o.filter_turnover_max=this.filters.turnoverMax),this.filters.dateAddFrom&&(o.filter_date_add_from=this.filters.dateAddFrom),this.filters.dateAddTo&&(o.filter_date_add_to=this.filters.dateAddTo),this.filters.lastProductFrom&&(o.filter_last_product_from=this.filters.lastProductFrom),this.filters.lastProductTo&&(o.filter_last_product_to=this.filters.lastProductTo),this.filters.activeOnly&&(o.filter_active=1)),"attributes"===a&&(null!==this.filters.salesMin&&""!==this.filters.salesMin&&(o.filter_sales_min=this.filters.salesMin),null!==this.filters.salesMax&&""!==this.filters.salesMax&&(o.filter_sales_max=this.filters.salesMax),null!==this.filters.turnoverMin&&""!==this.filters.turnoverMin&&(o.filter_turnover_min=this.filters.turnoverMin),null!==this.filters.turnoverMax&&""!==this.filters.turnoverMax&&(o.filter_turnover_max=this.filters.turnoverMax),this.filters.attributeGroup&&(o.filter_attribute_group=this.filters.attributeGroup),this.filters.isColor&&(o.filter_is_color=1)),"features"===a&&(null!==this.filters.salesMin&&""!==this.filters.salesMin&&(o.filter_sales_min=this.filters.salesMin),null!==this.filters.salesMax&&""!==this.filters.salesMax&&(o.filter_sales_max=this.filters.salesMax),null!==this.filters.turnoverMin&&""!==this.filters.turnoverMin&&(o.filter_turnover_min=this.filters.turnoverMin),null!==this.filters.turnoverMax&&""!==this.filters.turnoverMax&&(o.filter_turnover_max=this.filters.turnoverMax),this.filters.featureGroup&&(o.filter_feature_group=this.filters.featureGroup),this.filters.isCustom&&(o.filter_is_custom=1)),"cms"===a&&(this.filters.activeOnly&&(o.filter_active=1),this.filters.indexable&&(o.filter_indexable=1)),"cms_categories"===a&&this.filters.activeOnly&&(o.filter_active=1),"countries"===a&&(this.filters.activeOnly&&(o.filter_active=1),this.filters.hasHolidays&&(o.filter_has_holidays=1),this.filters.containsStates&&(o.filter_contains_states=1),this.filters.zone&&(o.filter_zone=this.filters.zone))),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:o,success:function(e){i.isLoading=!1,e.success&&(i.searchQuery&&i.searchQuery.length>=2&&e.total>0&&i.addToSearchHistory(a,i.searchQuery),i.searchResults=t?i.searchResults.concat(e.results||[]):e.results||[],i.searchTotal=e.total||0,i.searchOffset=t?i.searchOffset+(e.results||[]).length:(e.results||[]).length,i.renderSearchResults(t),i.$dropdown.addClass("show"))},error:function(){i.isLoading=!1}})}},renderSearchResults:function(t){var i=this,a=this.config.trans||{},s=this.$dropdown.find(".dropdown-results"),o=[],n=[];if(this.activeGroup){var r=this.$wrapper.find('.target-block[data-block-type="'+this.activeGroup.blockType+'"]').find('.selection-group[data-group-index="'+this.activeGroup.groupIndex+'"]'),l=this.activeGroup.searchEntity,c=this.activeGroup.excludeIndex;"include"===this.activeGroup.section?r.find(".include-picker").find(".entity-chip").each(function(){o.push(String(e(this).data("id")))}):(r.find('.exclude-row[data-exclude-index="'+c+'"]').find(".exclude-picker").find(".entity-chip").each(function(){o.push(String(e(this).data("id")))}),r.find(".exclude-row").each(function(){var t=e(this);if(parseInt(t.data("excludeIndex"),10)!==c){var a=t.find(".exclude-picker");(a.attr("data-search-entity")||i.activeGroup.blockType)===l&&a.find(".entity-chip").each(function(){n.push(String(e(this).data("id")))})}}))}var d=this.activeGroup&&"products"===this.activeGroup.searchEntity,p="list"===this.viewMode;this.$dropdown.find(".results-header").toggle(d&&p);var u=this.searchResults.filter(function(e){return-1===n.indexOf(String(e.id))}),h=this.searchResults.length-u.length,f=u.length+" / "+this.searchTotal+" results";h>0&&(f+=" ("+h+" hidden)"),this.$dropdown.find(".results-count").text(f);var v="";0!==u.length||t?u.forEach(function(e){var t="dropdown-item"+(-1!==o.indexOf(String(e.id))?" selected":"");"product"===e.type&&(t+=" result-item-product"),v+='
";var a=i.activeGroup?i.activeGroup.searchEntity:null;if("countries"===a&&e.iso_code){var s="https://flagcdn.com/w40/"+e.iso_code.toLowerCase()+".png";v+='
'+i.escapeAttr(e.iso_code)+'
"}else if(e.image)v+='
';else{var n="widgets";"categories"===a?n="folder":"manufacturers"===a?n="business":"suppliers"===a?n="local_shipping":"attributes"===a?n="brush":"features"===a?n="list":"cms"===a?n="description":"cms_categories"===a&&(n="folder"),v+='
'+i.esIcon(n)+"
"}if(v+='
',v+='
'+i.escapeHtml(e.name)+"
",e.subtitle){var r=e.subtitle.split("\n");v+='
',r.forEach(function(e,t){v+='
'+i.escapeHtml(e)+"
"}),v+="
"}if(v+="
","product"===e.type)if(p){v+='
',v+=''+(e.regular_price_formatted||e.price_formatted||"")+"",v+="
",e.has_discount?(v+='
',v+=''+(e.price_formatted||"")+"",v+="
"):v+='
';var l="out_of_stock"===e.stock_status?"stock-out":"low_stock"===e.stock_status?"stock-low":"stock-ok";v+='
',v+=''+(void 0!==e.stock_qty?e.stock_qty:"")+"",v+="
",v+='
',v+=''+(void 0!==e.sales_qty?e.sales_qty:"0")+"",v+="
"}else{var c="out_of_stock"===e.stock_status?"stock-out":"low_stock"===e.stock_status?"stock-low":"";v+='
',v+=''+(e.price_formatted||"")+"",void 0!==e.stock_qty&&(v+=''+e.stock_qty+" qty"),e.has_discount&&(v+='-'+(e.discount_percent||"")+"%"),v+="
"}v+="
"}):v='
'+this.esIcon("search")+" "+(a.no_results||"No results found")+"
",t?s.append(v):s.html(v);var g=this.searchResults.length'+(a.all||"All")+" ("+b+")")}this.$dropdown.find(".dropdown-actions").show(),this.$dropdown.find(".btn-show-history").removeClass("active");var _=this.activeGroup?this.activeGroup.searchEntity:null,x=_&&this.getSearchHistory(_).length>0;this.$dropdown.find(".btn-show-history").prop("disabled",!x)},loadSearchHistory:function(){try{var e=localStorage.getItem(this.searchHistoryKey);this.searchHistory=e?JSON.parse(e):{}}catch(e){this.searchHistory={}}},saveSearchHistory:function(){try{localStorage.setItem(this.searchHistoryKey,JSON.stringify(this.searchHistory))}catch(e){}},addToSearchHistory:function(e,t){if(t&&!(t.length<2)){this.searchHistory[e]||(this.searchHistory[e]=[]);var i=this.searchHistory[e],a=i.indexOf(t);-1!==a&&i.splice(a,1),i.unshift(t),i.length>this.searchHistoryMax&&(i=i.slice(0,this.searchHistoryMax)),this.searchHistory[e]=i,this.saveSearchHistory()}},removeFromSearchHistory:function(e,t){if(this.searchHistory[e]){var i=this.searchHistory[e].indexOf(t);-1!==i&&(this.searchHistory[e].splice(i,1),this.saveSearchHistory())}},getSearchHistory:function(e){return this.searchHistory[e]||[]},showSearchHistory:function(e){var t=this.getSearchHistory(e),i=this.config.trans||{},a=this.$dropdown.find(".dropdown-results");if(this.$dropdown.find(".results-count").text(i.recent_searches||"Recent searches"),this.$dropdown.find(".dropdown-actions").hide(),this.$dropdown.find(".filter-panel").removeClass("show"),this.$dropdown.find(".btn-toggle-filters").removeClass("active"),this.$dropdown.find(".results-header").hide(),t.length){for(var s='
',o=0;o',s+=this.esIcon("schedule"),s+=''+this.escapeHtml(n)+"",s+='",s+="
"}s+="",a.html(s),this.$dropdown.addClass("show")}else this.performSearch()},refreshSearch:function(){"tree"!==this.viewMode?(this.searchOffset=0,this.loadMoreCount=20,this.$dropdown&&(this.$dropdown.find(".load-more-select").val("20"),this.$dropdown.find('.load-more-select option[data-all="true"]').remove()),this.performSearch(!1)):this.filterCategoryTree(this.searchQuery||"")},clearFilters:function(){if(this.refineQuery="",this.refineNegate=!1,this.filters={inStock:!1,discounted:!1,priceMin:null,priceMax:null,attributes:[],features:[],productCountMin:null,productCountMax:null,salesMin:null,salesMax:null,turnoverMin:null,turnoverMax:null,depth:null,hasProducts:!1,hasDescription:!1,hasImage:!1,activeOnly:!0,attributeGroup:null,featureGroup:null,dateAddFrom:null,dateAddTo:null,lastProductFrom:null,lastProductTo:null,hasHolidays:!1,containsStates:!1,zone:null},this.$dropdown){var e=this.config.trans||{};this.$dropdown.find(".refine-input").val("").attr("placeholder",e.refine_short||"Refine..."),this.$dropdown.find(".btn-clear-refine").hide(),this.$dropdown.find(".btn-refine-negate").removeClass("active"),this.$dropdown.find(".filter-in-stock").prop("checked",!1),this.$dropdown.find(".filter-discounted").prop("checked",!1),this.$dropdown.find(".filter-price-min").val(""),this.$dropdown.find(".filter-price-max").val(""),this.$dropdown.find(".filter-attr-chip").removeClass("active"),this.$dropdown.find(".filter-feat-chip").removeClass("active"),this.$dropdown.find(".filter-group-toggle").removeClass("active has-selection"),this.$dropdown.find(".filter-row-values").hide(),this.$dropdown.find(".filter-product-count-min, .filter-product-count-max").val(""),this.$dropdown.find(".filter-sales-min, .filter-sales-max").val(""),this.$dropdown.find(".filter-turnover-min, .filter-turnover-max").val(""),this.$dropdown.find(".filter-date-add-from, .filter-date-add-to").val(""),this.$dropdown.find(".filter-last-product-from, .filter-last-product-to").val(""),this.$dropdown.find(".filter-depth-select").val(""),this.$dropdown.find(".filter-has-products").prop("checked",!1),this.$dropdown.find(".filter-has-description").prop("checked",!1),this.$dropdown.find(".filter-has-image").prop("checked",!1),this.$dropdown.find(".filter-active-only").prop("checked",!0),this.$dropdown.find(".filter-attribute-group-select, .filter-feature-group-select").val(""),this.$dropdown.find(".filter-has-holidays").prop("checked",!1),this.$dropdown.find(".filter-contains-states").prop("checked",!1),this.$dropdown.find(".filter-zone-select").val("")}this.refreshSearch()},resetFiltersWithoutSearch:function(){if(this.refineQuery="",this.refineNegate=!1,this.filters={inStock:!1,discounted:!1,priceMin:null,priceMax:null,attributes:[],features:[],productCountMin:null,productCountMax:null,salesMin:null,salesMax:null,turnoverMin:null,turnoverMax:null,depth:null,hasProducts:!1,hasDescription:!1,hasImage:!1,activeOnly:!0,attributeGroup:null,featureGroup:null,dateAddFrom:null,dateAddTo:null,lastProductFrom:null,lastProductTo:null,hasHolidays:!1,containsStates:!1,zone:null},this.$dropdown){var e=this.config.trans||{};this.$dropdown.find(".refine-input").val("").attr("placeholder",e.refine_short||"Refine..."),this.$dropdown.find(".btn-clear-refine").hide(),this.$dropdown.find(".btn-refine-negate").removeClass("active"),this.$dropdown.find(".filter-in-stock").prop("checked",!1),this.$dropdown.find(".filter-discounted").prop("checked",!1),this.$dropdown.find(".filter-price-min").val(""),this.$dropdown.find(".filter-price-max").val(""),this.$dropdown.find(".filter-attr-chip").removeClass("active"),this.$dropdown.find(".filter-feat-chip").removeClass("active"),this.$dropdown.find(".filter-group-toggle").removeClass("active has-selection"),this.$dropdown.find(".filter-row-values").hide(),this.$dropdown.find(".filter-product-count-min, .filter-product-count-max").val(""),this.$dropdown.find(".filter-sales-min, .filter-sales-max").val(""),this.$dropdown.find(".filter-turnover-min, .filter-turnover-max").val(""),this.$dropdown.find(".filter-date-add-from, .filter-date-add-to").val(""),this.$dropdown.find(".filter-last-product-from, .filter-last-product-to").val(""),this.$dropdown.find(".filter-depth-select").val(""),this.$dropdown.find(".filter-has-products").prop("checked",!1),this.$dropdown.find(".filter-has-description").prop("checked",!1),this.$dropdown.find(".filter-has-image").prop("checked",!1),this.$dropdown.find(".filter-active-only").prop("checked",!0),this.$dropdown.find(".filter-attribute-group-select, .filter-feature-group-select").val(""),this.$dropdown.find(".filter-has-holidays").prop("checked",!1),this.$dropdown.find(".filter-contains-states").prop("checked",!1),this.$dropdown.find(".filter-zone-select").val("")}},updateFilterPanelForEntity:function(e){if(this.$dropdown){var t=this.$dropdown.find(".filter-panel");t.find(".filter-row").hide();var i=this.$dropdown.find(".view-mode-select option.tree-view-option");"categories"===e||"cms_categories"===e?(i.prop("disabled",!1).prop("hidden",!1),"tree"!==this.viewMode?(this.viewMode="tree",this.$dropdown.find(".view-mode-select").val("tree"),this.$dropdown.removeClass("view-list view-cols-2 view-cols-3 view-cols-4 view-cols-5 view-cols-6 view-cols-7 view-cols-8").addClass("view-tree"),this.loadCategoryTree()):this.loadCategoryTree()):(i.prop("disabled",!0).prop("hidden",!0),"tree"===this.viewMode&&(this.viewMode="list",this.$dropdown.find(".view-mode-select").val("list"),this.$dropdown.removeClass("view-tree").addClass("view-list"))),"products"===e?(t.find(".filter-row-quick").show(),this.filterableData&&(this.filterableData.attributes&&this.filterableData.attributes.length>0&&this.$dropdown.find(".filter-row-attributes").show(),this.filterableData.features&&this.filterableData.features.length>0&&this.$dropdown.find(".filter-row-features").show())):"categories"===e?t.find(".filter-row-entity-categories").show():"manufacturers"===e?t.find(".filter-row-entity-manufacturers").show():"suppliers"===e?t.find(".filter-row-entity-suppliers").show():"attributes"===e?(t.find(".filter-row-entity-attributes").show(),this.loadAttributeGroups()):"features"===e?t.find(".filter-row-entity-features").show():"cms"===e?t.find(".filter-row-entity-cms").show():"cms_categories"===e?t.find(".filter-row-entity-cms-categories").show():"countries"===e&&(t.find(".filter-row-entity-countries").show(),this.loadZonesForCountryFilter())}},loadAttributeGroups:function(){var t=this,i=this.$dropdown.find(".filter-attribute-group-select");i.find("option").length>1||e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"getAttributeGroups",trait:"EntitySelector"},success:function(a){a.success&&a.groups&&e.each(a.groups,function(e,a){i.append('")})}})},loadFeatureGroups:function(){var t=this,i=this.$dropdown.find(".filter-feature-group-select");i.find("option").length>1||e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"getFeatureGroups",trait:"EntitySelector"},success:function(a){a.success&&a.groups&&e.each(a.groups,function(e,a){i.append('")})}})}}}(jQuery),function(e){"use strict";window._EntitySelectorMixins=window._EntitySelectorMixins||{},window._EntitySelectorMixins.filters={clearFilters:function(){this.refineQuery="",this.refineNegate=!1,this.filters={inStock:!1,discounted:!1,priceMin:null,priceMax:null,attributes:[],features:[],productCountMin:null,productCountMax:null,salesMin:null,salesMax:null,turnoverMin:null,turnoverMax:null,depth:null,hasProducts:!1,hasDescription:!1,hasImage:!1,activeOnly:!0,attributeGroup:null,featureGroup:null,dateAddFrom:null,dateAddTo:null,lastProductFrom:null,lastProductTo:null,hasHolidays:!1,containsStates:!1,zone:null},this.$dropdown&&(this.config.trans,this.$dropdown.find(".refine-input").val(""),this.$dropdown.find(".btn-refine-negate").removeClass("active"),this.$dropdown.find(".filter-in-stock").prop("checked",!1),this.$dropdown.find(".filter-discounted").prop("checked",!1),this.$dropdown.find(".filter-price-min, .filter-price-max").val(""),this.$dropdown.find(".filter-attr-chip, .filter-feat-chip").removeClass("active"),this.$dropdown.find(".filter-product-count-min, .filter-product-count-max").val(""),this.$dropdown.find(".filter-sales-min, .filter-sales-max").val(""),this.$dropdown.find(".filter-depth-select").val(""),this.$dropdown.find(".filter-has-products").prop("checked",!1),this.$dropdown.find(".filter-active-only").prop("checked",!0),this.$dropdown.find(".filter-has-holidays").prop("checked",!1),this.$dropdown.find(".filter-contains-states").prop("checked",!1),this.$dropdown.find(".filter-zone-select").val("")),this.refreshSearch()},resetFiltersWithoutSearch:function(){this.refineQuery="",this.refineNegate=!1,this.filters={inStock:!1,discounted:!1,priceMin:null,priceMax:null,attributes:[],features:[],productCountMin:null,productCountMax:null,salesMin:null,salesMax:null,turnoverMin:null,turnoverMax:null,depth:null,hasProducts:!1,hasDescription:!1,hasImage:!1,activeOnly:!0,attributeGroup:null,featureGroup:null,dateAddFrom:null,dateAddTo:null,lastProductFrom:null,lastProductTo:null,hasHolidays:!1,containsStates:!1,zone:null}},updateFilterPanelForEntity:function(e){if(this.$dropdown){var t=this.$dropdown.find(".filter-panel");t.find(".filter-row").hide(),t.find('.filter-row[data-entity="'+e+'"]').show(),t.find(".filter-row-entity-"+e.replace("_","-")).show();var i="categories"===e||"cms_categories"===e;this.$dropdown.find(".tree-view-option").toggle(i),i&&"list"===this.viewMode?(this.viewMode="tree",this.$dropdown.find(".view-mode-select").val("tree"),this.$dropdown.removeClass("view-list view-cols-2 view-cols-3 view-cols-4 view-cols-5 view-cols-6 view-cols-7 view-cols-8").addClass("view-tree")):i||"tree"!==this.viewMode||(this.viewMode="list",this.$dropdown.find(".view-mode-select").val("list"),this.$dropdown.removeClass("view-tree view-cols-2 view-cols-3 view-cols-4 view-cols-5 view-cols-6 view-cols-7 view-cols-8").addClass("view-list")),"countries"===e&&this.loadZonesForCountryFilter(),this.updateSortOptionsForEntity(e)}},updateSortOptionsForEntity:function(t){if(this.$dropdown){var i=this.$dropdown.find(".sort-field-select"),a=i.val(),s=!1;i.find("option").each(function(){var i=e(this),o=i.data("entities");if(!o)return i.show(),void(i.val()===a&&(s=!0));var n=-1!==o.split(",").indexOf(t);i.toggle(n),n&&i.val()===a&&(s=!0)}),s||(i.val("name"),this.currentSort.field="name")}},loadFilterableData:function(){var t=this;this.filterableData?this.renderFilterDropdowns():e.ajax({url:this.config.ajaxUrl,type:"POST",data:{ajax:1,action:"getTargetFilterableAttributes",trait:"EntitySelector"},dataType:"json",success:function(e){e.success&&e.data&&(t.filterableData=e.data,t.renderFilterDropdowns())}})},renderFilterDropdowns:function(){if(this.$dropdown&&this.filterableData){var e=this,t=this.$dropdown.find(".filter-attributes-container");t.empty(),this.filterableData.attributes&&this.filterableData.attributes.length>0&&(this.filterableData.attributes.forEach(function(i){var a='",t.append(a)}),this.$dropdown.find(".filter-row-attributes").show());var i=this.$dropdown.find(".filter-features-container");i.empty(),this.filterableData.features&&this.filterableData.features.length>0&&(this.filterableData.features.forEach(function(t){var a='",i.append(a)}),this.$dropdown.find(".filter-row-features").show())}},showFilterGroupValues:function(e,t){if(this.filterableData){var i=this,a=("attribute"===t?this.filterableData.attributes:this.filterableData.features).find(function(t){return t.id==e});if(a){this.$dropdown.find(".filter-row-values").hide();var s="attribute"===t?".filter-row-attr-values":".filter-row-feat-values",o=this.$dropdown.find(s),n=o.find(".filter-values-container");n.empty();var r=''+a.name+":";a.values.forEach(function(a){var s=("attribute"===t?-1!==i.filters.attributes.indexOf(a.id):-1!==i.filters.features.indexOf(a.id))?" active":"",o="attribute"===t?"filter-attr-chip":"filter-feat-chip",n=a.color?' style="--chip-color: '+a.color+'"':"",l=a.color?" has-color":"";r+='"}),n.html(r),o.find(".btn-close-values").remove(),o.append('"),o.show();var l=o[0];l&&l.scrollIntoView({behavior:"smooth",block:"nearest"})}}},hideFilterGroupValues:function(){this.$dropdown.find(".filter-row-values").hide(),this.$dropdown.find(".filter-group-toggle").removeClass("active")},updateFilterToggleStates:function(){if(this.$dropdown&&this.filterableData){var e=this;this.filterableData.attributes&&this.filterableData.attributes.forEach(function(t){var i=e.$dropdown.find('.filter-group-toggle[data-group-id="'+t.id+'"][data-type="attribute"]'),a=t.values.some(function(t){return-1!==e.filters.attributes.indexOf(t.id)});i.toggleClass("has-selection",a)}),this.filterableData.features&&this.filterableData.features.forEach(function(t){var i=e.$dropdown.find('.filter-group-toggle[data-group-id="'+t.id+'"][data-type="feature"]'),a=t.values.some(function(t){return-1!==e.filters.features.indexOf(t.id)});i.toggleClass("has-selection",a)})}},loadZonesForCountryFilter:function(){var t=this;if(!this.zonesLoaded&&this.$dropdown){var i=this.$dropdown.find(".filter-zone-select");i.length&&e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"getZonesForFilter",trait:"EntitySelector"},success:function(e){if(e.success&&e.zones&&e.zones.length>0){var a=t.config.trans||{};i.empty(),i.append('"),e.zones.forEach(function(e){i.append('")}),t.zonesLoaded=!0}}})}}}}(jQuery),function(e){"use strict";window._EntitySelectorMixins=window._EntitySelectorMixins||{},window._EntitySelectorMixins.chips={addSelection:function(e,t,i,a){this.addSelectionNoUpdate(e,t,i,a);var s=e.find(".entity-chips");this.updateChipsVisibility(s)},addSelectionNoUpdate:function(e,t,i,a){var s=e.find(".entity-chips"),o=e.closest(".target-block");if("single"===(this.config.mode||"multi")?(this.$wrapper.find(".entity-chips .entity-chip").remove(),this.$dropdown&&this.$dropdown.find(".dropdown-item.selected, .tree-item.selected").removeClass("selected"),this.$wrapper.find(".target-block-tab .tab-badge").remove(),this.$wrapper.find(".target-block-tab").removeClass("has-data")):"single"===(o.data("mode")||"multi")&&(s.find(".entity-chip").remove(),this.$dropdown&&this.$dropdown.find(".dropdown-item.selected, .tree-item.selected").removeClass("selected")),!s.find('.entity-chip[data-id="'+t+'"]').length){var n=o.data("blockType")||"",r="countries"===(e.attr("data-search-entity")||n),l='"+this.esIcon("flag","flag-fallback").replace(">",' style="display:none">')+"":a&&a.image&&(l+=''),l+=''+this.escapeHtml(i)+"",r&&(l+='"),l+='",l+="
",s.append(l)}},removeSelection:function(e,t){var i=e.find(".entity-chips");e.find('.entity-chip[data-id="'+t+'"]').remove(),this.updateChipsVisibility(i)},updateChipsVisibility:function(t){var i=this.config.trans||{},a=(t.closest(".value-picker"),t.find(".entity-chip")),s=a.length,o=t.closest(".chips-wrapper");if(0!==s){this.ensureChipsWrapper(t);var n=t.closest(".chips-wrapper"),r=n.find(".chips-toolbar"),l=n.find(".chips-load-more"),c=r.find(".chips-search-input").val()||"";c=c.toLowerCase().trim();var d=0,p=0,u=t.hasClass("chips-expanded"),h=u?999999:this.maxVisibleChips||12;a.each(function(){var t=e(this),i=(t.find(".chip-name").text()||"").toLowerCase(),a=!c||-1!==i.indexOf(c);t.removeClass("chip-filtered-out chip-paginated-out"),a?++p>h?t.addClass("chip-paginated-out"):d++:t.addClass("chip-filtered-out")}),r.addClass("has-chips"),this.updateChipsToolbar(r,s,p,c);var f=p-d;if(f>0&&!u){var v=i.load||"Load",g=(i.remaining||"{count} remaining").replace("{count}",f),m=''+v+''+g+"";l.html(m).show()}else if(u&&p>(this.maxVisibleChips||12)){var b=i.collapse||"Collapse";l.html('").show()}else l.hide()}else o.length&&(o.before(t),o.remove())},ensureChipsWrapper:function(t){if(!t.closest(".chips-wrapper").length){var i=this.config.trans||{},a=(t.closest(".value-picker"),'
'),s=e(a);t.before(s),s.find(".chips-toolbar").after(t),s.append(s.find(".chips-load-more")),this.bindChipsToolbarEvents(s)}},bindChipsToolbarEvents:function(t){var i,a=this,s=t.find(".entity-chips");t.on("input",".chips-search-input",function(){clearTimeout(i),i=setTimeout(function(){s.removeClass("chips-expanded"),a.updateChipsVisibility(s)},150)}),t.on("change",".chips-sort-select",function(){var t=e(this).val();a.sortChips(s,t)}),t.on("click",".btn-chips-clear",function(){((t.find(".chips-search-input").val()||"").trim()?s.find(".entity-chip:not(.chip-filtered-out)"):s.find(".entity-chip")).each(function(){e(this).find(".chip-remove").trigger("click")}),t.find(".chips-search-input").val(""),a.updateChipsVisibility(s)}),t.on("change",".load-more-select",function(){var t=e(this).val();"all"===t?(s.addClass("chips-expanded"),a.maxVisibleChips=999999):a.maxVisibleChips=(a.maxVisibleChips||12)+parseInt(t,10),a.updateChipsVisibility(s)}),t.on("click",".btn-collapse-chips",function(){s.removeClass("chips-expanded"),a.maxVisibleChips=12,a.updateChipsVisibility(s)})},sortChips:function(t,i){var a=t.find(".entity-chip");if(!(a.length<2)){var s=a.toArray().sort(function(t,a){var s=e(t),o=e(a);switch(i){case"name_asc":var n=(s.find(".chip-name").text()||"").toLowerCase(),r=(o.find(".chip-name").text()||"").toLowerCase();return n.localeCompare(r);case"name_desc":var l=(s.find(".chip-name").text()||"").toLowerCase();return(o.find(".chip-name").text()||"").toLowerCase().localeCompare(l);default:return 0}});e.each(s,function(e,i){t.append(i)}),this.updateChipsVisibility(t)}},updateChipsToolbar:function(e,t,i,a){var s=this.config.trans||{},o=e.find(".chips-count"),n=e.find(".btn-chips-clear"),r=n.find(".clear-text");a?(o.addClass("has-filter").html(''+i+'/'+t+""),r.text((s.clear||"Clear")+" "+i)):(o.removeClass("has-filter").html(t),r.text(s.clear_all||"Clear all")),a&&0===i?n.hide():t>0?n.show():n.hide()},loadExistingSelections:function(){var t=this,i={};this.$wrapper.find(".selection-group").each(function(){var a=e(this),s=a.closest(".target-block").data("blockType"),o=a.find(".include-picker");t.collectPickerEntities(o,s,i),t.enhanceMethodSelect(a.find(".include-method-select")),a.find(".exclude-row").each(function(){var a=e(this);t.collectPickerEntities(a.find(".exclude-picker"),s,i),t.enhanceMethodSelect(a.find(".exclude-method-select"))}),a.find(".group-excludes.has-excludes").length>0&&t.updateMethodSelectorLock(a,!0)});var a={},s=!1;Object.keys(i).forEach(function(e){var t=i[e];if(0!==t.ids.length){var o=t.ids.filter(function(e,t,i){return i.indexOf(e)===t});a[e]=o,s=!0}}),s&&e.ajax({url:t.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"getTargetEntitiesByIdsBulk",trait:"EntitySelector",entities:JSON.stringify(a)},success:function(e){if(e.success&&e.entities)try{Object.keys(i).forEach(function(a){var s=i[a],o=e.entities[a]||[],n={};o.forEach(function(e){n[e.id]=e}),s.pickers.forEach(function(e){var i=e.$picker,s=i.find(".entity-chips"),o=i.find(".include-values-data, .exclude-values-data"),r=[],l="countries"===a;e.ids.forEach(function(e){var i=s.find('.entity-chip-loading[data-id="'+e+'"]');if(n[e]){var a=n[e];r.push(a.id);var o='"+t.esIcon("flag","flag-fallback").replace(">",' style="display:none">')+"":a.image&&(o+=''),o+=''+t.escapeHtml(a.name)+"",l&&(o+='"),o+='",o+="
",i.replaceWith(o)}else i.remove()}),t.updateChipsVisibility(s),r.length!==e.ids.length&&(o.val(JSON.stringify(r)),t.serializeAllBlocks()),t.updateBlockStatus(i.closest(".target-block"))})}),t.updateAllConditionCounts()}catch(e){}},error:function(e,t,i){}})},collectPickerEntities:function(t,i,a){if(t.length){var s=this,o=t.find(".include-values-data, .exclude-values-data");if(o.length){var n=t.attr("data-value-type"),r=o.val()||"[]",l=[];try{l=JSON.parse(r)}catch(e){return}if("multi_numeric_range"!==n)if("multi_select_tiles"!==n){if("combination_attributes"===n)return"object"!=typeof l||null===l||0===Object.keys(l).length||o.val(JSON.stringify(l)),void s.loadCombinationAttributeGroups(t);if(l.length)if("pattern"!==n){var c=t.attr("data-search-entity")||i,d=t.find(".entity-chips"),p=this.getEntityTypeIcon(c);l.forEach(function(e){var t='';t+=''+s.esIcon(p,"es-spin-pulse")+"",t+='Loading...',t+="",d.append(t)}),a[c]||(a[c]={ids:[],pickers:[]}),a[c].ids=a[c].ids.concat(l),a[c].pickers.push({$picker:t,ids:l})}else l.forEach(function(e){"string"==typeof e&&e?s.addPatternTag(t,e,!1):e&&e.pattern&&s.addPatternTag(t,e.pattern,!0===e.caseSensitive)})}else{if(!Array.isArray(l)||0===l.length)return;l.forEach(function(e){t.find('.tile-option[data-value="'+e+'"]').addClass("selected")})}else{if(!Array.isArray(l)||0===l.length)return;var u=t.find(".multi-range-chips");l.forEach(function(t){if(t&&(null!==t.min||null!==t.max)){var i;i=null!==t.min&&null!==t.max?t.min+" - "+t.max:null!==t.min?"≥ "+t.min:"≤ "+t.max;var a=e("",{class:"range-chip","data-min":null!==t.min?t.min:"","data-max":null!==t.max?t.max:""});a.append(e("",{class:"range-chip-text",text:i})),a.append(e("",r+=''+this.escapeHtml(t)+"",r+='",r+="",s.append(r)},getPatternTags:function(t){var i=[];return t.find(".pattern-tag:not(.draft-tag)").each(function(){var t=e(this).data("pattern"),a=1===e(this).data("caseSensitive")||"1"===e(this).data("caseSensitive");t&&i.push({pattern:t,caseSensitive:a})}),i},updateDraftTagCount:function(t,i,a){var s=this,o=t.find(".pattern-match-count"),n=o.find(".count-value"),r=t.closest(".target-block").data("blockType")||"products";n.html(this.esIcon("progress_activity","es-spin")),o.show(),o.data("pattern",i),o.data("caseSensitive",a),o.data("entityType",r),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"countPatternMatches",trait:"EntitySelector",pattern:i,field:"name",entity_type:r,case_sensitive:a?1:0},success:function(e){if(e.success){var i=parseInt(e.count,10)||0;n.text(i),o.show(),o.removeClass("count-zero count-found"),o.addClass(0===i?"count-zero":"count-found"),o.data("count",i);var a=t.closest(".selection-group");a.length&&s.updateGroupTotalCount(a)}else n.text("?"),o.show()},error:function(){n.text("?"),o.show()}})},updateConditionCountWithPendingPattern:function(t,i){this.config.trans;var a=t.find(".method-selector-wrapper > .condition-match-count, > .exclude-header-row > .condition-match-count").first();if(a.length){var s=t.hasClass("exclude-row"),o=(s?t.find(".exclude-method-select"):t.find(".include-method-select")).val();if(o){var n=s?t.find(".exclude-picker"):t.find(".include-picker");if("pattern"===(n.data("valueType")||"none")){var r=this.getPatternTags(n);if(i&&r.push({pattern:i,caseSensitive:!1}),0!==r.length){var l=t.closest(".target-block").data("blockType")||"products";a.find(".preview-count").html(this.esIcon("progress_activity","es-spin")),a.removeClass("clickable no-matches").show(),a.data("conditionData",{method:o,values:r,blockType:l,isExclude:s}),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"countConditionMatches",trait:"EntitySelector",method:o,values:JSON.stringify(r),block_type:l},success:function(e){if(e&&e.success){var t=e.count||0;a.removeClass("no-matches clickable"),0===t?(a.find(".preview-count").text(t),a.addClass("no-matches").show()):(a.find(".preview-count").text(t),a.addClass("clickable").show())}else a.hide().removeClass("clickable")},error:function(){a.hide().removeClass("clickable")}})}else a.hide()}}else a.hide()}},fetchPatternMatchCount:function(t,i,a){var s=t.closest(".exclude-row"),o=-1!==((s.length?s.find(".exclude-method-select"):t.closest(".selection-group").find(".include-method-select")).val()||"").indexOf("reference")?"reference":"name",n=t.closest(".target-block").data("blockType")||"products";a.find(".preview-count").html(this.esIcon("progress_activity","es-spin")),a.removeClass("clickable no-matches").show(),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"countPatternMatches",trait:"EntitySelector",pattern:i,field:o,entity_type:n,case_sensitive:0},success:function(e){if(e&&e.success){var t=e.count||0;a.find(".preview-count").text(t),a.removeClass("no-matches clickable").show(),0===t?a.addClass("no-matches"):a.addClass("clickable")}else a.hide()},error:function(){a.hide()}})},getPickerValues:function(t,i){switch(i){case"entity_search":var a=[];return t.find(".entity-chip").each(function(){var t=e(this).data("id");t&&a.push(t)}),a;case"pattern":var s=this.getPatternTags(t),o=t.find(".draft-tag .pattern-input"),n=e.trim(o.val());if(n){var r="1"===o.closest(".draft-tag").attr("data-case-sensitive");s.push({pattern:n,caseSensitive:r})}return s;case"numeric_range":return{min:t.find(".range-min-input").val()||null,max:t.find(".range-max-input").val()||null};case"date_range":return{from:t.find(".date-from-input").val()||null,to:t.find(".date-to-input").val()||null};case"select":return[t.find(".select-value-input").val()];case"boolean":return[!0];default:return[]}},updateConditionCount:function(t){this.config.trans;var i=t.find(".method-selector-wrapper > .condition-match-count, > .exclude-header-row > .condition-match-count").first();if(i.length){var a=t.hasClass("exclude-row"),s=(a?t.find(".exclude-method-select"):t.find(".include-method-select")).val();if(s){var o=a?t.find(".exclude-picker"):t.find(".include-picker"),n=o.data("valueType")||"none",r=this.getPickerValues(o,n),l=!r||Array.isArray(r)&&0===r.length||"object"==typeof r&&!Array.isArray(r)&&("combination_attributes"===n&&void 0!==r.attributes&&0===Object.keys(r.attributes).length||"combination_attributes"!==n&&0===Object.keys(r).length);if("none"!==n&&"boolean"!==n&&l)i.hide();else{var c=t.closest(".target-block").data("blockType")||"products";i.find(".preview-count").html(this.esIcon("progress_activity","es-spin")),i.removeClass("clickable no-matches").show(),i.data("conditionData",{method:s,values:r,blockType:c,isExclude:a}),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"countConditionMatches",trait:"EntitySelector",method:s,values:JSON.stringify(r),block_type:c},success:function(e){if(e&&e.success){var t=e.count||0;i.removeClass("no-matches clickable"),0===t?(i.find(".preview-count").text(t),i.addClass("no-matches").show()):(i.find(".preview-count").text(t),i.addClass("clickable").show())}else i.hide().removeClass("clickable")},error:function(){i.hide().removeClass("clickable")}})}}else i.hide()}},updateGroupCounts:function(t){var i=this,a=t.find(".group-include");a.length&&this.updateConditionCount(a),t.find(".exclude-row").each(function(){i.updateConditionCount(e(this))}),this.updateGroupTotalCount(t)},updateGroupTotalCount:function(t){var i=this,a=t.closest(".target-block").data("blockType")||"products",s=t.find(".group-header .group-count-badge"),o=t.find(".group-modifier-limit"),n=this.serializeGroup(t,a);if(!n.include||!n.include.method)return s.hide(),void o.attr("placeholder","–");s.html(this.esIcon("progress_activity","es-spin")).show(),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"countGroupItems",trait:"EntitySelector",group_data:JSON.stringify(n),block_type:a},success:function(e){if(e&&e.success){var r=e.final_count||0,l=e.exclude_count||0,c=i.esIcon("visibility")+" "+r;l>0&&(c+=' (-'+l+")"),s.html(c),s.addClass("clickable").show(),s.data("groupData",n),s.data("blockType",a),s.data("finalCount",r),o.attr("placeholder",r);var d=t.find(".group-preview-badge .preview-count");if(d.length){var p=parseInt(o.val(),10),u=p>0&&pn&&(n=t)});var r=n+1,l=this.buildMethodOptions(o,!1),c=(this.buildMethodOptions(o,!0),(s.group||"Group")+" "+(r+1)),d='
';d+='
',d+=''+this.esIcon("expand_less")+"",d+='',d+='',d+='",d+="",d+='",d+="
",d+='
',d+='
',d+='
',d+='
',d+='",d+=''+this.esIcon("visibility")+' 0',d+='',d+="
",d+='",d+="
",d+="
",d+='
',d+='",d+="
",d+='
',d+='',d+=''+(s.limit||"Limit")+"",d+='',d+="",d+='',d+=''+(s.sort||"Sort")+"",d+='",d+='",d+="",d+='',d+=this.esIcon("visibility")+' ',d+="",d+="
",d+="
",d+="
",a.append(d);var p=a.find('.selection-group[data-group-index="'+r+'"]');this.enhanceMethodSelect(p.find(".include-method-select")),p.find(".include-method-select").val("all").trigger("change"),this.updateBlockStatus(t),this.serializeAllBlocks()},removeGroup:function(e,t){e.remove();var i=t.find(".groups-container");if(0===i.find(".selection-group").length){var a='
';a+=''+this.getEmptyStateText(t)+"",a+="
",i.html(a)}this.updateBlockStatus(t),this.serializeAllBlocks(),this.updateTabBadges()},clearAllConditions:function(){var t=this;this.$wrapper.find(".target-block").each(function(){var i=e(this),a=i.find(".groups-container");a.find(".selection-group").remove();var s='
';s+=''+t.getEmptyStateText(i)+"",s+="
",a.html(s),t.updateBlockStatus(i)}),this.serializeAllBlocks(),this.updateTabBadges(),this.updateHeaderTotalCount()},switchToBlock:function(e){this.$wrapper.find(".target-block-tab").removeClass("active"),this.$wrapper.find('.target-block-tab[data-block-type="'+e+'"]').addClass("active"),this.$wrapper.find(".target-block").removeClass("active").hide(),this.$wrapper.find('.target-block[data-block-type="'+e+'"]').addClass("active").show(),this.hideDropdown()},updateTabBadges:function(){var t=this,i=[];this.$wrapper.find(".target-block-tab").each(function(){var a=e(this),s=a.data("blockType"),o=t.$wrapper.find('.target-block[data-block-type="'+s+'"]'),n=o.find(".selection-group").length,r=a.find(".tab-badge");if(n>0)r.length?r.addClass("loading").html(t.esIcon("progress_activity","es-spin")):a.append(''+t.esIcon("progress_activity","es-spin")+""),a.addClass("has-data"),i.push(s);else if(o.hasClass("custom-block")){var l=!1;o.find(".custom-block-content").find("input, textarea, select").each(function(){if(e(this).val()&&""!==e(this).val().trim())return l=!0,!1}),l?(r.length?r.removeClass("loading").html(t.esIcon("check")):a.append(''+t.esIcon("check")+""),a.addClass("has-data")):(r.remove(),a.removeClass("has-data"))}else r.remove(),a.removeClass("has-data")}),this.updateTargetSwitchState(),i.length>0&&this.fetchAllCounts(i)},updateTargetSwitchState:function(){var t=this.$wrapper.find(".prestashop-switch");if(t.length){var i=!1;this.$wrapper.find(".target-block").each(function(){if(e(this).find(".selection-group").length>0)return i=!0,!1}),i?t.find('input[value="0"]').prop("checked",!0):t.find('input[value="1"]').prop("checked",!0)}},fetchAllCounts:function(t){var i=this,a=this.$wrapper.find('input[name="'+this.config.name+'"]'),s={};try{s=JSON.parse(a.val()||"{}")}catch(e){s={}}var o={};t.forEach(function(e){var t=s[e]&&s[e].groups?s[e].groups:[];t.length>0&&(o[e]={groups:t})}),0!==Object.keys(o).length?e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"previewEntitySelectorBulk",trait:"EntitySelector",conditions:JSON.stringify(o)},success:function(e){e.success&&e.counts?(Object.keys(e.counts).forEach(function(t){var a=e.counts[t],s=i.$wrapper.find('.target-block-tab[data-block-type="'+t+'"]'),o=s.find(".tab-badge");o.length&&(o.removeClass("loading").html(i.esIcon("visibility")+" "+a),s.data("previewData",{count:a,success:!0}))}),t.forEach(function(t){if(!(t in e.counts)){var a=i.$wrapper.find('.target-block-tab[data-block-type="'+t+'"]');a.find(".tab-badge").remove(),a.removeClass("has-data")}}),i.updateHeaderTotalCount()):t.forEach(function(e){i.$wrapper.find('.target-block-tab[data-block-type="'+e+'"]').find(".tab-badge").remove()})},error:function(e,a,s){t.forEach(function(e){i.$wrapper.find('.target-block-tab[data-block-type="'+e+'"]').find(".tab-badge").remove()})}}):t.forEach(function(e){var t=i.$wrapper.find('.target-block-tab[data-block-type="'+e+'"]');t.find(".tab-badge").remove(),t.removeClass("has-data")})},fetchProductCount:function(t,i){var a=this,s={},o=this.$wrapper.find('input[name="'+this.config.name+'"]'),n={};try{n=JSON.parse(o.val()||"{}")}catch(e){n={}}var r=n[t]&&n[t].groups?n[t].groups:[];if(0===r.length)return i.find(".tab-badge").remove(),i.removeClass("has-data"),void i.removeData("previewData");var l=i.find(".tab-badge");l.length?l.addClass("loading").html(this.esIcon("progress_activity","es-spin")):(l=e(''+this.esIcon("progress_activity","es-spin")+""),i.append(l)),i.addClass("has-data"),s[t]={groups:r},e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"previewEntitySelector",trait:"EntitySelector",conditions:JSON.stringify(s),block_type:t,limit:10},success:function(e){e.success?(i.find(".tab-badge").removeClass("loading").html(a.esIcon("visibility")+" "+e.count),i.data("previewData",e),a.updateHeaderTotalCount()):i.find(".tab-badge").remove()},error:function(e,t,s){i.find(".tab-badge").remove(),a.updateHeaderTotalCount()}})},updateHeaderTotalCount:function(){var t=0;this.$wrapper.find(".target-block-tab .tab-badge").each(function(){var i=e(this);if(!i.hasClass("loading")){var a=parseInt(i.text(),10);isNaN(a)||(t+=a)}});var i=this.$wrapper.find(".trait-total-count");t>0?(i.find(".count-value").text(t),i.show()):i.hide(),this.updateShowAllToggle()},updateShowAllToggle:function(){var e=this.$wrapper.find(".trait-show-all-toggle");if(e.length){var t=e.find(".show-all-checkbox"),i=this.$wrapper.find(".target-block-tab.has-data").length>0;t.prop("checked",!i)}},updateBlockStatus:function(e){var t=e.find(".block-status"),i=e.data("blockType"),a=this.config.blocks[i]||{},s=this.config.trans||{},o=this.getBlockGroups(e);0===o.length?!1!==this.config.emptyMeansAll?t.text((s.all||"All")+" "+(a.entity_label_plural||"items")):t.text(s.nothing_selected||"Nothing selected"):t.text(o.length+" "+(1===o.length?s.group||"group":s.groups||"groups"))},getEmptyStateText:function(e){var t=e.data("blockType"),i=e.data("mode")||"multi",a=this.config.blocks[t]||{},s=this.config.trans||{},o=!1!==this.config.emptyMeansAll;return"single"===i?s.no_item_selected||"No item selected":o?(s.all||"All")+" "+(a.entity_label_plural||"items")+" "+(s.included||"included"):s.nothing_selected||"Nothing selected"},serializeGroup:function(t,i){var a=this,s=t.find(".include-method-select").val()||"all",o=t.find(".include-picker"),n=this.getPickerValues(o),r=[];t.find(".group-excludes.has-excludes").length&&t.find(".exclude-row").each(function(){var t=e(this),i=t.find(".exclude-method-select").val()||null,s=t.find(".exclude-picker"),o=a.getPickerValues(s);i&&o&&(!Array.isArray(o)||o.length>0)&&r.push({method:i,values:o})});var l={include:{method:s,values:n}};r.length>0&&(l.excludes=r);var c=this.getGroupModifiers(t);return(c.limit||c.sort_by)&&(l.modifiers=c),l},serializeAllBlocks:function(t){var i=this,a={};this.$wrapper.find(".target-block").each(function(){var t=e(this),s=t.data("blockType"),o=i.getBlockGroups(t);o.length>0&&(a[s]={groups:o}),i.updateBlockStatus(t)});var s=this.$wrapper.find('input[name="'+this.config.name+'"]'),o=JSON.stringify(a);s.val(o),this.updateTabBadges(),this.countUpdateTimeout&&clearTimeout(this.countUpdateTimeout),this.countUpdateTimeout=setTimeout(function(){if(t&&t.length){i.updateConditionCount(t);var e=t.closest(".selection-group");e.length&&i.updateGroupTotalCount(e)}else i.updateAllConditionCounts()},500)},getBlockGroups:function(t){var i=this,a=[];return t.find(".selection-group").each(function(){var t=e(this),s=t.find(".include-method-select").val()||"all",o=t.find(".include-picker"),n=i.getPickerValues(o);if(!i.isConditionValid(s,n,o))return!0;var r=[];t.find(".group-excludes.has-excludes").length&&t.find(".exclude-row").each(function(){var t=e(this),a=t.find(".exclude-method-select").val()||null,s=t.find(".exclude-picker"),o=i.getPickerValues(s);a&&i.isConditionValid(a,o,s)&&r.push({method:a,values:o})});var l={include:{method:s,values:n}},c=e.trim(t.attr("data-group-name")||"");c&&(l.name=c),r.length>0&&(l.excludes=r);var d=i.getGroupModifiers(t);(d.limit||d.sort_by)&&(l.modifiers=d),a.push(l)}),a},getGroupModifiers:function(e){var t=e.find(".group-modifier-limit").val(),i=e.find(".group-modifier-sort").val()||"sales",a=e.find(".group-modifiers .btn-sort-dir").data("dir")||"DESC";return{limit:t?parseInt(t,10):null,sort_by:i||null,sort_dir:a||"DESC"}},getPickerValues:function(t){var i=t.attr("data-value-type")||"entity_search",a=[];switch(i){case"entity_search":t.find(".entity-chip").each(function(){var t=e(this).data("id");a.push(isNaN(t)?t:Number(t))});break;case"pattern":a=this.getPatternTags(t);var s=t.find(".draft-tag .pattern-input"),o=e.trim(s.val());if(o){var n="1"===s.closest(".draft-tag").attr("data-case-sensitive");a.push({pattern:o,caseSensitive:n})}break;case"numeric_range":var r=t.find(".range-min-input").val(),l=t.find(".range-max-input").val();""===r&&""===l||(a={min:""!==r?parseFloat(r):null,max:""!==l?parseFloat(l):null});break;case"date_range":var c=t.find(".date-from-input").val(),d=t.find(".date-to-input").val();(c||d)&&(a={from:c||null,to:d||null});break;case"select":var p=t.find(".select-value-input").val();p&&(a=[p]);break;case"boolean":a=[!0];break;case"multi_numeric_range":var u=[];t.find(".range-chip").each(function(){var t=e(this),i=t.data("min"),a=t.data("max");u.push({min:""!==i&&void 0!==i?parseFloat(i):null,max:""!==a&&void 0!==a?parseFloat(a):null})}),u.length>0&&(a=u);break;case"multi_select_tiles":t.find(".tile-option.selected").each(function(){a.push(e(this).data("value"))});break;case"combination_attributes":var h={};if(t.find(".comb-attr-value.selected").each(function(){var t=e(this).data("groupId").toString(),i=e(this).data("valueId");h[t]||(h[t]=[]),h[t].push(i)}),Object.keys(h).length>0){var f,v=t.find(".combination-attributes-picker").data("combinationMode")||this.config.combinationMode||"products";f="toggle"===v?t.find(".comb-mode-radio:checked").val()||"products":v,a={mode:f,attributes:h}}}return a},isConditionValid:function(e,t,i){if("all"===e)return!0;var a=i.attr("data-value-type")||"entity_search";return"boolean"===a||(Array.isArray(t)?t.length>0:"object"==typeof t&&null!==t&&("combination_attributes"===a&&void 0!==t.attributes?Object.keys(t.attributes).length>0:Object.keys(t).some(function(e){return null!==t[e]&&""!==t[e]})))},updateAllConditionCounts:function(){var t=this,i={},a={},s=0;this.$wrapper.find(".target-block.active .selection-group").each(function(){var o=e(this),n=o.closest(".target-block").data("blockType")||"products",r=o.find(".group-include");if(r.length){var l=t.getConditionData(r,n);if(l){var c="c"+s++;i[c]=l.condition,a[c]=l.$countEl}}o.find(".exclude-row").each(function(){var o=t.getConditionData(e(this),n);if(o){var r="c"+s++;i[r]=o.condition,a[r]=o.$countEl}})}),0!==Object.keys(i).length&&e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"countConditionMatchesBulk",trait:"EntitySelector",conditions:JSON.stringify(i)},success:function(e){e&&e.success&&e.counts&&Object.keys(e.counts).forEach(function(t){var i=e.counts[t]||0,s=a[t];s&&s.length&&(s.removeClass("no-matches clickable"),0===i?(s.find(".preview-count").text(i),s.addClass("no-matches").show()):(s.find(".preview-count").text(i),s.addClass("clickable").show()))})},error:function(){Object.keys(a).forEach(function(e){var t=a[e];t&&t.length&&t.hide().removeClass("clickable")})}})},getConditionData:function(e,t){var i=e.find(".method-selector-wrapper > .condition-match-count, > .exclude-header-row .condition-match-count").first();if(!i.length)return null;var a=e.hasClass("exclude-row"),s=(a?e.find(".exclude-method-select"):e.find(".include-method-select")).val();if(!s)return i.hide(),null;var o=a?e.find(".exclude-picker"):e.find(".include-picker"),n=o.data("valueType")||o.attr("data-value-type")||"none";if("none"===n&&"countries"===t&&"all"===s){var r=this;return setTimeout(function(){r.updateConditionCount(e,t)},0),null}var l=o.attr("data-search-entity")||"";if("countries"===t&&"entity_search"===n&&"countries"===l)return r=this,setTimeout(function(){r.updateConditionCount(e,t)},0),null;if("none"===n)return i.hide(),null;var c=this.getPickerValues(o,n),d=!c||Array.isArray(c)&&0===c.length||"object"==typeof c&&!Array.isArray(c)&&("combination_attributes"===n&&void 0!==c.attributes&&0===Object.keys(c.attributes).length||"combination_attributes"!==n&&0===Object.keys(c).length);return"boolean"!==n&&d?(i.hide(),null):(i.find(".preview-count").html(this.esIcon("progress_activity","es-spin")),i.removeClass("clickable no-matches").show(),i.data("conditionData",{method:s,values:c,blockType:t,isExclude:a}),{condition:{method:s,values:c,block_type:t},$countEl:i})},updateGroupCounts:function(t){var i=this,a=t.closest(".target-block").data("blockType")||"products",s=t.find(".group-include");s.length&&this.updateConditionCount(s,a),t.find(".exclude-row").each(function(){i.updateConditionCount(e(this),a)}),this.updateGroupTotalCount(t)},updateConditionCount:function(t,i){var a=this,s=t.find(".method-selector-wrapper > .condition-match-count, > .exclude-header-row .condition-match-count").first();if(s.length){var o=t.hasClass("exclude-row"),n=(o?t.find(".exclude-method-select"):t.find(".include-method-select")).val();if(n){var r=o?t.find(".exclude-picker"):t.find(".include-picker"),l=r.data("valueType")||"none",c=r.attr("data-search-entity")||"";if(!i){var d=t.closest(".target-block");i=d.data("blockType")||"products"}if("none"===l&&"countries"===i&&"all"===n)return s.find(".preview-count").html(this.esIcon("progress_activity","es-spin")),s.removeClass("clickable no-matches country-holidays").show(),void e.ajax({url:a.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"searchTargetEntities",trait:"EntitySelector",entity_type:"countries",query:"",limit:500},success:function(t){var r=t.results||t.items||[];if(t&&t.success&&r.length>0){var l=r.map(function(e){return e.id});s.data("conditionData",{method:n,values:l,blockType:i,isExclude:o,isCountryHolidays:!0,countryIds:l,isAllCountries:!0}),e.ajax({url:a.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"getHolidaysForCountries",trait:"EntitySelector",country_ids:l.join(","),count_only:1},success:function(e){if(e&&e.success){var t=e.total_count||0;s.removeClass("no-matches clickable"),s.addClass("country-holidays"),0===t?(s.find(".preview-count").text(t),s.addClass("no-matches").show()):(s.find(".preview-count").text(t),s.addClass("clickable").show()),s.data("countriesInfo",e.countries||[])}else s.hide().removeClass("clickable")},error:function(){s.hide().removeClass("clickable")}})}else s.hide().removeClass("clickable")},error:function(){s.hide().removeClass("clickable")}});if("none"!==l){var p=this.getPickerValues(r,l),u=!p||Array.isArray(p)&&0===p.length||"object"==typeof p&&!Array.isArray(p)&&("combination_attributes"===l&&void 0!==p.attributes&&0===Object.keys(p.attributes).length||"combination_attributes"!==l&&0===Object.keys(p).length);if("boolean"!==l&&u)s.hide();else{i||(d=t.closest(".target-block"),i=d.data("blockType")||"products");var h="countries"===c&&"entity_search"===l;if(s.find(".preview-count").html(this.esIcon("progress_activity","es-spin")),s.removeClass("clickable no-matches country-holidays").show(),h&&Array.isArray(p)&&p.length>0)return s.data("conditionData",{method:n,values:p,blockType:i,isExclude:o,isCountryHolidays:!0,countryIds:p}),void e.ajax({url:a.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"getHolidaysForCountries",trait:"EntitySelector",country_ids:p.join(","),count_only:1},success:function(e){if(e&&e.success){var t=e.total_count||0;s.removeClass("no-matches clickable"),s.addClass("country-holidays"),0===t?(s.find(".preview-count").text(t),s.addClass("no-matches").show()):(s.find(".preview-count").text(t),s.addClass("clickable").show()),s.data("countriesInfo",e.countries||[])}else s.hide().removeClass("clickable")},error:function(){s.hide().removeClass("clickable")}});s.data("conditionData",{method:n,values:p,blockType:i,isExclude:o}),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"countConditionMatches",trait:"EntitySelector",method:n,values:JSON.stringify(p),block_type:i},success:function(e){if(e&&e.success){var t=e.count||0;s.removeClass("no-matches clickable"),0===t?(s.find(".preview-count").text(t),s.addClass("no-matches").show()):(s.find(".preview-count").text(t),s.addClass("clickable").show())}else s.hide().removeClass("clickable")},error:function(){s.hide().removeClass("clickable")}})}}else s.hide()}else s.hide()}},updateGroupTotalCount:function(t){var i=this,a=t.closest(".target-block").data("blockType")||"products",s=t.find(".group-header .group-count-badge"),o=t.find(".group-modifier-limit"),n=this.serializeGroup(t,a);if(!n.include||!n.include.method)return s.hide(),void o.attr("placeholder","–");s.html(this.esIcon("progress_activity","es-spin")).show(),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"countGroupItems",trait:"EntitySelector",group_data:JSON.stringify(n),block_type:a},success:function(e){if(e&&e.success){var r=e.final_count||0,l=e.exclude_count||0,c=i.esIcon("visibility")+" "+r;l>0&&(c+=' (-'+l+")"),s.html(c),s.addClass("clickable").show(),s.data("groupData",n),s.data("blockType",a),s.data("finalCount",r),o.attr("placeholder",r);var d=t.find(".group-preview-badge .preview-count");if(d.length){var p=parseInt(o.val(),10),u=p>0&&p';s+=''+this.esIcon("block")+" "+(a.except||"EXCEPT")+"",s+="",s+='
',s+=this.buildExcludeRowHtml(t,0),s+="
",s+='",i.addClass("has-excludes").html(s);var o=i.find('.exclude-row[data-exclude-index="0"]'),n=o.find(".exclude-method-select");this.enhanceMethodSelect(n);var r=t.data("blockType"),l=n.val();this.updateMethodInfoPlaceholder(o.find(".method-selector-wrapper"),l,r),this.updateMethodSelectorLock(e,!0),this.serializeAllBlocks()},addExcludeRow:function(t,i){var a=t.find(".exclude-rows-container"),s=-1;a.find(".exclude-row").each(function(){var t=parseInt(e(this).data("excludeIndex"),10);t>s&&(s=t)});var o=s+1,n=this.buildExcludeRowHtml(i,o);a.append(n);var r=a.find('.exclude-row[data-exclude-index="'+o+'"]'),l=r.find(".exclude-method-select");this.enhanceMethodSelect(l);var c=i.data("blockType"),d=l.val();this.updateMethodInfoPlaceholder(r.find(".method-selector-wrapper"),d,c),this.serializeAllBlocks()},buildExcludeRowHtml:function(t,i){var a=t.data("blockType"),s=(this.config.blocks[a]||{}).selection_methods||{},o=this.config.trans||{},n=this.buildMethodOptions(s,!0),r=a,l="entity_search";e.each(s,function(e,t){return"all"===e||(r=t.search_entity||a,l=t.value_type||"entity_search",!1)});var c='
';return c+='
',c+='
',c+='",c+=''+this.esIcon("visibility")+' 0',c+='',c+="
",c+='",c+="
",(c+=this.buildValuePickerHtml("exclude",l,r,s))+"
"},removeExcludeRow:function(e,t,i){var a=t.find(".exclude-rows-container"),s=this.config.trans||{};e.remove(),0===a.find(".exclude-row").length&&(t.find(".group-excludes").removeClass("has-excludes").html('"),this.updateMethodSelectorLock(t,!1)),this.serializeAllBlocks()},buildMethodOptions:function(t,i){var a=this,s=this.config.trans||{},o="",n={select_by:s.select_by||"Select by...",filter_by:s.filter_by||"Filter by..."},r={},l={};return e.each(t,function(e,t){if(i&&"all"===e)return!0;var a=t.group||"";a?(r[a]||(r[a]={}),r[a][e]=t):l[e]=t}),e.each(l,function(e,t){o+=a.buildMethodOption(e,t)}),e.each(r,function(t,i){var s=n[t]||t.replace(/_/g," ");o+='',e.each(i,function(e,t){o+=a.buildMethodOption(e,t)}),o+=""}),o},buildMethodOption:function(e,t){var i='"},buildValuePickerHtml:function(e,t,i,a){var s=this.config.trans||{},o=e+"-picker",n=e+"-chips",r=e+"-values-data",l="";if("none"===t)return l='";switch(l='
',t){case"entity_search":var c=s.no_items_selected||"No items selected - use search below";l+='
',l+='",l+='';break;case"pattern":var d=""+this.escapeHtml(s.pattern_help_title||"Pattern Syntax")+"";d+='
',d+='
* '+this.escapeHtml(s.pattern_help_wildcard||"any text (wildcard)")+"
",d+='
{number} '+this.escapeHtml(s.pattern_help_number||"any number (e.g. 100, 250)")+"
",d+='
{letter} '+this.escapeHtml(s.pattern_help_letter||"single letter (A-Z)")+"
",d+="
",d+='
',d+=""+this.escapeHtml(s.pattern_help_examples||"Examples:")+"",d+='
*cotton* '+this.escapeHtml(s.pattern_example_1||'contains "cotton"')+"
",d+='
iPhone {number} Pro* '+this.escapeHtml(s.pattern_example_2||'matches "iPhone 15 Pro Max"')+"
",d+='
Size {letter} '+this.escapeHtml(s.pattern_example_3||'matches "Size M", "Size L"')+"
",d+="
";var p=s.no_patterns||"No patterns - press Enter to add";l+='
',l+='
',l+='
',l+='',l+='',l+=''+this.esIcon("visibility")+' ',l+='",l+="
",l+='',l+=this.esIcon("info"),l+="",l+="
",l+='';break;case"numeric_range":l+='
',l+='',l+='-',l+='',l+="
",l+='';break;case"multi_numeric_range":l+='
',l+='
',l+='
',l+='',l+='-',l+='',l+='",l+="
",l+="
",l+='';break;case"multi_select_tiles":l+='
',l+="
",l+='';break;case"date_range":l+='
',l+='',l+='-',l+='',l+="
",l+='';break;case"select":l+='
',l+='',l+="
",l+='';break;case"boolean":l+='
',l+=''+this.escapeHtml(s.yes||"Yes")+"",l+="
",l+='';break;case"combination_attributes":this.escapeHtml(s.combination_help_title||"Combination Targeting"),this.escapeHtml(s.combination_help_desc||"Select attributes to target specific product combinations."),this.escapeHtml(s.combination_help_logic||"Logic:"),this.escapeHtml(s.combination_help_within||"Within group: OR (Red OR Blue)"),this.escapeHtml(s.combination_help_between||"Between groups: AND (Color AND Size)");var u=this.config.combinationMode||"products",h="toggle"===u,f=h?"products":u;l+='
',h&&(l+='
',l+='",l+='",l+="
"),l+='
',l+=''+this.esIcon("progress_activity","es-spin")+" "+this.escapeHtml(s.loading||"Loading...")+"",l+="
",l+="
",l+='';break;default:l+=''}return l+"
"},getSortOptionsArray:function(e){var t=this.config.trans||{};switch(e){case"products":return[{value:"sales",label:t.sort_bestsellers||"Best sellers"},{value:"date_add",label:t.sort_newest||"Newest"},{value:"price",label:t.sort_price||"Price"},{value:"name",label:t.sort_name||"Name"},{value:"position",label:t.sort_position||"Position"},{value:"quantity",label:t.sort_stock||"Stock quantity"},{value:"random",label:t.sort_random||"Random"}];case"categories":return[{value:"name",label:t.sort_name||"Name"},{value:"position",label:t.sort_position||"Position"},{value:"product_count",label:t.sort_products||"Products count"},{value:"date_add",label:t.sort_newest||"Newest"}];default:return[{value:"name",label:t.sort_name||"Name"},{value:"date_add",label:t.sort_newest||"Newest"}]}},getSortIconName:function(e,t){switch(e){case"name":return"sort_by_alpha";case"random":return"shuffle";default:return"sort"}},cycleSortOption:function(e,t){for(var i,a,s,o=this.getSortOptionsArray(t),n=e.data("sort")||"sales",r=e.data("dir")||"DESC",l=-1,c=0;c0)return t=!0,!1}),t?(this.clearValidationError(),!0):(this.showValidationError(),!1)},showValidationError:function(){this.$wrapper.addClass("has-validation-error");var t=this.$wrapper.data("required-message")||"Please select at least one item";this.$wrapper.find(".trait-validation-error").remove();var i=e("
",{class:"trait-validation-error",html:this.esIcon("warning")+" "+t});this.$wrapper.find(".condition-trait-header").after(i),e("html, body").animate({scrollTop:this.$wrapper.offset().top-100},300),this.$wrapper.find(".condition-trait-body").is(":visible")||(this.$wrapper.find(".condition-trait-body").slideDown(200),this.$wrapper.removeClass("collapsed"))},clearValidationError:function(){this.$wrapper.removeClass("has-validation-error"),this.$wrapper.find(".trait-validation-error").remove()}}}(jQuery),function(e){"use strict";window._EntitySelectorMixins=window._EntitySelectorMixins||{},window._EntitySelectorMixins.methods={initMethodDropdowns:function(){var t=this;this.$wrapper.find(".include-method-select").each(function(){t.enhanceMethodSelect(e(this))}),this.$wrapper.find(".exclude-method-select").each(function(){t.enhanceMethodSelect(e(this))}),this.initMethodInfoPlaceholders()},initMethodInfoPlaceholders:function(){var t=this;this.$wrapper.find(".selection-group").each(function(){var i=e(this),a=i.closest(".target-block").data("blockType")||"products",s=i.find(".include-method-select").val()||"all";t.updateMethodInfoPlaceholder(i.find(".method-selector-wrapper"),s,a),i.find(".exclude-row").each(function(){var i=e(this),s=i.find(".exclude-method-select").val();s&&t.updateMethodInfoPlaceholder(i.find(".method-selector-wrapper"),s,a)})})},enhanceMethodSelect:function(t){var i=this;if(t.length&&!t.data("methodDropdownInit")){t.data("methodDropdownInit",!0),t.addClass("method-select-hidden");var a=t.find("option:selected"),s=a.data("icon")||"arrow_drop_down",o=a.text(),n='
';n+=this.esIcon(s,"method-trigger-icon"),n+=''+this.escapeHtml(o)+"",n+=this.esIcon("arrow_drop_down","method-trigger-caret");var r=e(n+="
");t.after(r),r.on("click",function(e){e.preventDefault(),e.stopPropagation(),t.closest(".method-selector-wrapper").hasClass("selector-locked")||i.showMethodDropdownMenu(t,r)}),t.on("change.methodDropdown",function(){i.updateMethodTrigger(t,r)})}},updateMethodTrigger:function(e,t){var i=e.find("option:selected"),a=i.data("icon")||"arrow_drop_down",s=i.text();t.find(".method-trigger-icon").replaceWith(this.esIcon(a,"method-trigger-icon")),t.find(".method-trigger-label").text(s)},showMethodDropdownMenu:function(t,i){var a=this;this.closeMethodDropdownMenu();var s=this.buildMethodDropdownMenuHtml(t),o=e(s),n=i.offset(),r=i.outerWidth(),l=i.outerHeight();o.css({position:"absolute",top:n.top+l+2,left:n.left,minWidth:r,zIndex:10001}),e("body").append(o),this.$methodDropdownMenu=o,this.$methodDropdownSelect=t,this.$methodDropdownTrigger=i,o.on("click",".method-dropdown-item",function(i){i.preventDefault(),i.stopPropagation();var s=e(this).data("value");t.val(s).trigger("change"),a.closeMethodDropdownMenu()}),e(document).on("click.methodDropdown",function(t){e(t.target).closest(".method-dropdown-menu, .method-dropdown-trigger").length||a.closeMethodDropdownMenu()}),e(document).on("keydown.methodDropdown",function(e){27===e.keyCode&&a.closeMethodDropdownMenu()})},buildMethodDropdownMenuHtml:function(t){var i=this,a='
';return t.children("option").each(function(){var t=e(this),s=t.data("icon")||"star",o=t.text(),n=t.val(),r=t.is(":selected");a+='
',a+=i.esIcon(s,"method-item-icon"),a+=''+i.escapeHtml(o)+"",r&&(a+=i.esIcon("check","method-item-check")),a+="
"}),t.children("optgroup").each(function(){var t=e(this),s=t.attr("label")||"";a+='
',a+='
'+i.escapeHtml(s)+"
",a+='
',t.children("option").each(function(){var t=e(this),s=t.data("icon")||"settings",o=t.text(),n=t.val(),r=t.is(":selected");a+='
',a+=i.esIcon(s,"method-item-icon"),a+=''+i.escapeHtml(o)+"",r&&(a+=i.esIcon("check","method-item-check")),a+="
"}),a+="
",a+="
"}),a+="
"},closeMethodDropdownMenu:function(){this.$methodDropdownMenu&&(this.$methodDropdownMenu.remove(),this.$methodDropdownMenu=null),this.$methodDropdownSelect=null,this.$methodDropdownTrigger=null,e(document).off("click.methodDropdown keydown.methodDropdown")},populateTiles:function(t,i,a){var s=t.find(".multi-select-tiles");s.empty(),a?s.attr("data-exclusive","true"):s.removeAttr("data-exclusive"),e.each(i,function(t,i){var a="object"==typeof i?i.label:i,o="object"==typeof i&&i.icon?i.icon:null,n="object"==typeof i&&i.color?i.color:null,r="tile-option";n&&(r+=" tile-color-"+n);var l=e("",c+="
",c+='
',c+='',c+="
",o.length>0){if(c+='
',c+=this.renderPreviewItems(o),c+="
",r){var d=n-o.length;c+='"}}else c+='
'+(a.no_preview||"No items to preview")+"
";var p=e(c+="");e("body").append(p),this.$previewPopover=p,this.$previewList=p.find(".preview-list"),this.previewLoadedCount=o.length,this.previewTotalCount=n,this.previewContext=t.context||{},this.previewOnLoadMore=t.onLoadMore||null,this.previewOnFilter=t.onFilter||null,this.previewCurrentFilter="",this.previewEntityLabel=l,p.find(".preview-close").on("click",function(){i.hidePreviewPopover()});var u=p.find(".preview-filter-input");if(t.onFilter){var h=this.debounce(function(e){i.previewCurrentFilter=e,i.showFilterLoading(!0),t.onFilter.call(i,e)},300);u.on("input",function(){var t=e(this).val().trim();t!==i.previewCurrentFilter&&h(t)})}else u.on("input",function(){var t=e(this).val().toLowerCase().trim();i.filterPreviewItems(t)});t.onLoadMore&&p.find(".btn-load-more").on("click",function(){var a=e(this),s=a.closest(".load-more-controls").find(".load-more-select");if(!a.hasClass("loading")){a.addClass("loading"),a.find("i").replaceWith(i.esIcon("progress_activity","es-spin")),s.prop("disabled",!0);var o=parseInt(s.val(),10)||20;i.previewLoadCount=o,t.onLoadMore.call(i,a)}});var f=s.offset(),v=s.outerHeight(),g=s.outerWidth(),m=p.outerWidth(),b=f.left+g/2-m/2,y=e(window).width()-m-10;return b=Math.max(10,Math.min(b,y)),p.css({position:"absolute",top:f.top+v+8,left:b,zIndex:1e4}),p.addClass("show"),p},updatePreviewPopover:function(e,t){var i=this.config.trans||{};this.$previewList.html(this.renderPreviewItems(e)),this.previewLoadedCount=e.length;var a=this.$previewPopover.find(".preview-footer");if(t){var s=this.previewTotalCount-e.length,o=a.find(".load-more-controls"),n=o.find(".btn-load-more"),r=o.find(".load-more-select");n.removeClass("loading"),n.find("i").replaceWith(this.esIcon("add")),r.prop("disabled",!1),o.find(".remaining-count").text(s),r.empty(),s>=10&&r.append(''),s>=20&&r.append(''),s>=50&&r.append(''),s>=100&&r.append(''),r.append('")}else a.remove();var l=this.$previewPopover.find(".preview-filter-input").val();l&&this.filterPreviewItems(l.toLowerCase().trim())},renderPreviewItems:function(e){for(var t="",i=0;i",a.image?t+='':t+='
'+this.esIcon("inventory_2")+"
",t+='
',t+='
'+this.escapeHtml(a.name||"Unnamed")+"
";var n=[];a.reference&&n.push("Ref: "+a.reference),a.manufacturer&&n.push(a.manufacturer),a.category&&n.push(a.category),a.attributes&&n.push(a.attributes),n.length>0&&(t+='
'+this.escapeHtml(n.join(" • "))+"
"),t+="
",void 0!==a.price&&null!==a.price?t+='
'+this.formatPrice(a.price)+"
":a.price_formatted&&(t+='
'+this.escapeHtml(a.price_formatted)+"
"),void 0===a.active||a.active||(t+='Inactive'),t+=""}return t},filterPreviewItems:function(t){if(this.$previewList){var i=this.$previewList.find(".preview-item");t?i.each(function(){var i=e(this),a=i.data("name")||"",s=i.data("ref")||"",o=i.data("attrs")||"",n=-1!==a.indexOf(t)||-1!==s.indexOf(t)||-1!==o.indexOf(t);i.toggle(n)}):i.show()}},showFilterLoading:function(e){if(this.$previewPopover){var t=this.$previewList;t&&(e?(this.previewLockedWidth||(this.previewLockedWidth=this.$previewPopover.outerWidth(),this.$previewPopover.css("width",this.previewLockedWidth+"px")),t.addClass("filtering"),t.find(".filter-loading-overlay").length||t.append('
'+this.esIcon("progress_activity","es-spin")+"
")):(t.removeClass("filtering"),t.find(".filter-loading-overlay").remove()))}},updatePreviewPopoverFiltered:function(t){var i=this.config.trans||{};if(this.showFilterLoading(!1),t.success){var a=t.items||[],s=t.count||0,o=t.hasMore||!1,n=this.$previewPopover.find(".preview-header"),r=this.previewEntityLabel||"items";if(n.find(".preview-count").text(s+" "+r),a.length>0)this.$previewList.html(this.renderPreviewItems(a)),this.previewLoadedCount=a.length,this.previewTotalCount=s;else{var l=i.no_filter_results||"No matching items found";this.$previewList.html('
'+l+"
"),this.previewLoadedCount=0,this.previewTotalCount=0}var c=this.$previewPopover.find(".preview-footer");if(o&&a.length>0){var d=s-a.length;if(c.length){var p=c.find(".load-more-controls"),u=p.find(".btn-load-more"),h=p.find(".load-more-select");u.removeClass("loading"),u.find("i").replaceWith(g.esIcon("add")),h.prop("disabled",!1),p.find(".remaining-count").text(d),h.empty(),d>=10&&h.append(''),d>=20&&h.append(''),d>=50&&h.append(''),d>=100&&h.append(''),h.append('")}else{var f='");this.$previewList.after(v);var g=this;this.previewOnLoadMore&&v.find(".btn-load-more").on("click",function(){var t=e(this),i=t.closest(".load-more-controls").find(".load-more-select");if(!t.hasClass("loading")){t.addClass("loading"),t.find("i").replaceWith(g.esIcon("progress_activity","es-spin")),i.prop("disabled",!0);var a=parseInt(i.val(),10)||20;g.previewLoadCount=a,g.previewOnLoadMore.call(g,t)}})}}else c.remove()}},formatPrice:function(e){"number"!=typeof e&&(e=parseFloat(e)||0);var t=this.config&&this.config.currency_sign||"€",i=this.config&&this.config.currency_format||"right",a=e.toFixed(2);return"left"===i?t+" "+a:a+" "+t},hidePreviewPopover:function(){this.$activeBadge&&(this.$activeBadge.removeClass("popover-open loading"),this.$activeBadge=null),this.$previewPopover&&(this.$previewPopover.remove(),this.$previewPopover=null),this.$previewList=null,this.previewContext=null,this.previewOnLoadMore=null,this.previewOnFilter=null,this.previewCurrentFilter="",this.previewEntityLabel=null,this.previewLockedWidth=null},showPreviewPopover:function(e){var t=this,i=e.data("previewData");if(i){this.hidePreviewPopover();var a=e.find(".tab-badge");a.addClass("popover-open"),this.$activeBadge=a;var s=i.items||i.products||[],o=e.data("blockType"),n=(this.config.blocks&&this.config.blocks[o]?this.config.blocks[o]:{}).entity_label_plural||"items";if(this.previewBlockType=o,0===s.length&&i.count>0)return a.addClass("loading"),void this.fetchTabPreviewItems(e,function(s,r){a.removeClass("loading"),t.createPreviewPopover({$badge:a,items:s,totalCount:i.count,hasMore:r,entityLabel:n,previewType:"tab",context:{$tab:e,blockType:o},onLoadMore:function(i){t.loadMoreTabPreviewItems(e,i)},onFilter:function(i){t.filterTabPreviewItems(e,i)}})});this.createPreviewPopover({$badge:a,items:s,totalCount:i.count,hasMore:i.hasMore,entityLabel:n,previewType:"tab",context:{$tab:e,blockType:o},onLoadMore:function(i){t.loadMoreTabPreviewItems(e,i)},onFilter:function(i){t.filterTabPreviewItems(e,i)}})}},fetchTabPreviewItems:function(t,i){var a=t.data("blockType"),s=this.$wrapper.find('input[name="'+this.config.name+'"]'),o={};try{o=JSON.parse(s.val()||"{}")}catch(e){return void i([],!1)}var n=o[a]&&o[a].groups?o[a].groups:[];if(0!==n.length){var r={};r[a]={groups:n},e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"previewEntitySelector",trait:"EntitySelector",conditions:JSON.stringify(r),block_type:a,limit:20,offset:0},success:function(e){var a=e.items||e.products||[],s=e.hasMore||e.count>a.length;t.data("previewData",e),i(a,s)},error:function(){i([],!1)}})}else i([],!1)},filterTabPreviewItems:function(t,i){var a=this,s=this.previewBlockType,o=this.$wrapper.find('input[name="'+this.config.name+'"]'),n={};try{n=JSON.parse(o.val()||"{}")}catch(e){return void a.showFilterLoading(!1)}var r=n[s]&&n[s].groups?n[s].groups:[];if(0!==r.length){var l={};l[s]={groups:r},e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"previewTargetConditions",trait:"TargetConditions",conditions:JSON.stringify(l),block_type:s,filter:i,limit:20,offset:0},success:function(e){a.updatePreviewPopoverFiltered(e)},error:function(){a.showFilterLoading(!1)}})}else a.showFilterLoading(!1)},loadMoreTabPreviewItems:function(t,i){var a=this,s=this.previewBlockType,o=this.$wrapper.find('input[name="'+this.config.name+'"]'),n={};try{n=JSON.parse(o.val()||"{}")}catch(e){return}var r=n[s]&&n[s].groups?n[s].groups:[];if(0!==r.length){var l={};l[s]={groups:r};var c=this.previewLoadCount||20,d={ajax:1,action:"previewTargetConditions",trait:"TargetConditions",conditions:JSON.stringify(l),block_type:s,limit:a.previewLoadedCount+c,offset:0};a.previewCurrentFilter&&(d.filter=a.previewCurrentFilter),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:d,success:function(e){var i=e.items||e.products||[];e.success&&i.length>0&&(t.data("previewData",e),a.previewTotalCount=e.count,a.updatePreviewPopover(i,e.hasMore))},error:function(){var e=i.closest(".load-more-controls").find(".load-more-select");i.removeClass("loading"),i.find("i").replaceWith(a.esIcon("add")),e.prop("disabled",!1)}})}},showConditionPreviewPopover:function(t){var i=this,a=t.data("conditionData");if(a)if(a.isCountryHolidays&&a.countryIds)this.showCountriesHolidayPreview(t,a.countryIds);else{this.hidePreviewPopover(),t.addClass("popover-open loading"),this.$activeBadge=t;var s=a.blockType||"products",o=(this.config.blocks&&this.config.blocks[s]?this.config.blocks[s]:{}).entity_label_plural||"products";e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"previewConditionItems",trait:"EntitySelector",method:a.method,values:JSON.stringify(a.values),block_type:s,limit:10},success:function(e){t.removeClass("loading"),e.success?i.createPreviewPopover({$badge:t,items:e.items||[],totalCount:e.count,hasMore:e.hasMore,entityLabel:o,previewType:"condition",context:{conditionData:a,blockType:s},onLoadMore:function(e){i.loadMoreConditionItems(e)},onFilter:function(e){i.filterConditionItems(e)}}):(t.removeClass("popover-open"),i.$activeBadge=null)},error:function(){t.removeClass("loading popover-open"),i.$activeBadge=null}})}},filterConditionItems:function(t){var i=this,a=this.previewContext;a&&a.conditionData?e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"previewConditionItems",trait:"EntitySelector",method:a.conditionData.method,values:JSON.stringify(a.conditionData.values),block_type:a.blockType,filter:t,limit:20},success:function(e){i.updatePreviewPopoverFiltered(e)},error:function(){i.showFilterLoading(!1)}}):i.showFilterLoading(!1)},loadMoreConditionItems:function(t){var i=this,a=this.previewContext;if(a&&a.conditionData){var s=this.previewLoadCount||20,o={ajax:1,action:"previewConditionItems",trait:"EntitySelector",method:a.conditionData.method,values:JSON.stringify(a.conditionData.values),block_type:a.blockType,limit:i.previewLoadedCount+s};i.previewCurrentFilter&&(o.filter=i.previewCurrentFilter),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:o,success:function(e){e.success&&(i.previewTotalCount=e.count,i.updatePreviewPopover(e.items||[],e.hasMore))},error:function(){var e=t.closest(".load-more-controls").find(".load-more-select");t.removeClass("loading"),t.find("i").replaceWith(i.esIcon("add")),e.prop("disabled",!1)}})}},showGroupPreviewPopover:function(t,i,a){var s=this;if(i||(i=t.closest(".selection-group")),!a){var o=t.closest(".target-block");a=o.data("blockType")||"products"}var n=t.data("groupData");if(n||(n=this.serializeGroup(i,a)),n&&n.include){this.hidePreviewPopover(),t.addClass("popover-open loading"),this.$activeBadge=t;var r=(this.config.blocks&&this.config.blocks[a]?this.config.blocks[a]:{}).entity_label_plural||"products";e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"previewGroupItems",trait:"EntitySelector",group_data:JSON.stringify(n),block_type:a,limit:10},success:function(e){t.removeClass("loading"),e.success?s.createPreviewPopover({$badge:t,items:e.items||[],totalCount:e.count,hasMore:e.hasMore,entityLabel:r,previewType:"group",context:{groupData:n,blockType:a,$group:i},onLoadMore:function(e){s.loadMoreGroupItems(e)},onFilter:function(e){s.filterGroupItems(e)}}):(t.removeClass("popover-open"),s.$activeBadge=null)},error:function(){t.removeClass("loading popover-open"),s.$activeBadge=null}})}},filterGroupItems:function(t){var i=this,a=this.previewContext;a&&a.groupData?e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"previewGroupItems",trait:"EntitySelector",group_data:JSON.stringify(a.groupData),block_type:a.blockType,filter:t,limit:20},success:function(e){i.updatePreviewPopoverFiltered(e)},error:function(){i.showFilterLoading(!1)}}):i.showFilterLoading(!1)},loadMoreGroupItems:function(t){var i=this,a=this.previewContext;if(a&&a.groupData){var s=this.previewLoadCount||20,o={ajax:1,action:"previewGroupItems",trait:"EntitySelector",group_data:JSON.stringify(a.groupData),block_type:a.blockType,limit:i.previewLoadedCount+s};i.previewCurrentFilter&&(o.filter=i.previewCurrentFilter),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:o,success:function(e){e.success&&(i.previewTotalCount=e.count,i.updatePreviewPopover(e.items||[],e.hasMore))},error:function(){t.removeClass("loading"),t.find(".load-more-text").show(),t.find(".load-more-loading").hide()}})}},showFilterGroupPreviewPopover:function(t,i,a,s){var o=this;this.hidePreviewPopover(),t.addClass("popover-open loading"),this.$activeBadge=t,e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"previewFilterGroupProducts",trait:"EntitySelector",group_id:i,group_type:a,limit:10},success:function(e){t.removeClass("loading"),e.success?o.createPreviewPopover({$badge:t,items:e.items||[],totalCount:e.count||0,hasMore:e.hasMore||!1,entityLabel:"products",previewType:"filter-group",context:{groupId:i,groupType:a,groupName:s},onLoadMore:function(e){o.loadMoreFilterGroupItems(e)},onFilter:function(e){o.filterFilterGroupItems(e)}}):(t.removeClass("popover-open"),o.$activeBadge=null)},error:function(){t.removeClass("loading popover-open"),o.$activeBadge=null}})},filterFilterGroupItems:function(t){var i=this,a=this.previewContext;a&&a.groupId?e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"previewFilterGroupProducts",trait:"EntitySelector",group_id:a.groupId,group_type:a.groupType,filter:t,limit:20},success:function(e){i.updatePreviewPopoverFiltered(e)},error:function(){i.showFilterLoading(!1)}}):i.showFilterLoading(!1)},loadMoreFilterGroupItems:function(t){var i=this,a=this.previewContext;if(a&&a.groupId){var s=this.previewLoadCount||20,o={ajax:1,action:"previewFilterGroupProducts",trait:"EntitySelector",group_id:a.groupId,group_type:a.groupType,limit:i.previewLoadedCount+s};i.previewCurrentFilter&&(o.filter=i.previewCurrentFilter),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:o,success:function(e){e.success&&(i.previewTotalCount=e.count,i.updatePreviewPopover(e.items||[],e.hasMore))},error:function(){t.removeClass("loading"),t.find(".load-more-text").show(),t.find(".load-more-loading").hide()}})}},showCategoryItemsPreview:function(t,i,a,s){var o=this;this.hidePreviewPopover(),t.addClass("popover-open loading"),this.$activeBadge=t;var n="categories"===s,r=n?"products":"pages",l=n?"previewCategoryProducts":"previewCategoryPages";e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:l,trait:"EntitySelector",category_id:i,limit:10},success:function(e){t.removeClass("loading"),e.success?o.createPreviewPopover({$badge:t,items:e.items||[],totalCount:e.count||0,hasMore:e.hasMore||!1,entityLabel:r,previewType:"category-items",context:{categoryId:i,categoryName:a,entityType:s},onLoadMore:function(e){o.loadMoreCategoryItems(e)},onFilter:function(e){o.filterCategoryItems(e)}}):(t.removeClass("popover-open"),o.$activeBadge=null)},error:function(){t.removeClass("loading popover-open"),o.$activeBadge=null}})},loadMoreCategoryItems:function(t){var i=this,a=this.previewContext;if(a&&a.categoryId){var s="categories"===a.entityType?"previewCategoryProducts":"previewCategoryPages";t.prop("disabled",!0).find("i").addClass("es-spin"),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:s,trait:"EntitySelector",category_id:a.categoryId,offset:this.previewOffset,limit:10,query:this.previewFilterQuery||""},success:function(e){t.prop("disabled",!1).find("i").removeClass("es-spin"),e.success&&e.items&&(i.appendPreviewItems(e.items),i.previewOffset+=e.items.length,e.hasMore||t.hide())},error:function(){t.prop("disabled",!1).find("i").removeClass("es-spin")}})}},filterCategoryItems:function(t){var i=this,a=this.previewContext;if(a&&a.categoryId){var s="categories"===a.entityType?"previewCategoryProducts":"previewCategoryPages";e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:s,trait:"EntitySelector",category_id:a.categoryId,query:t,limit:10},success:function(e){i.showFilterLoading(!1),e.success&&(i.replacePreviewItems(e.items||[],e.count||0,e.hasMore||!1),i.previewOffset=e.items?e.items.length:0,i.previewFilterQuery=t)},error:function(){i.showFilterLoading(!1)}})}else i.showFilterLoading(!1)},showPatternPreviewModal:function(t,i,a,s){var o=this,n=this.config.trans||{},r=this.config.blocks&&this.config.blocks[i]?this.config.blocks[i]:{},l=r.entity_label_plural||"items",c=r.entity_label||"item",d='
';d+='
',d+='
',d+='',d+=this.esIcon("visibility")+" "+(n.preview||"Preview")+": "+this.escapeHtml(t)+"",d+="",d+=''+s+" "+(1===s?c:l)+"",d+='",d+="
",d+='
',d+='
'+this.esIcon("progress_activity","es-spin")+" "+(n.loading||"Loading...")+"
",d+="
",d+="
";var p=e(d+="
");e("body").append(p),p.find(".pattern-preview-close").on("click",function(){p.remove()}),p.on("click",function(t){e(t.target).hasClass("pattern-preview-modal-overlay")&&p.remove()}),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"previewPatternMatches",trait:"TargetConditions",pattern:t,entity_type:i,case_sensitive:a?1:0,limit:50},success:function(e){if(e.success&&e.items){var t=e.items,i='
';if(0===t.length)i+='
'+(n.no_matches||"No matches found")+"
";else{for(var a=0;a',r.image&&(i+=''),i+=''+o.escapeHtml(r.name)+"",r.id&&(i+='#'+r.id+""),i+="
"}s>t.length&&(i+='
... '+(n.and||"and")+" "+(s-t.length)+" "+(n.more||"more")+"
")}i+="",p.find(".pattern-preview-content").html(i)}else p.find(".pattern-preview-content").html('
'+(n.error_loading||"Error loading preview")+"
")},error:function(){p.find(".pattern-preview-content").html('
'+(n.error_loading||"Error loading preview")+"
")}})},refreshGroupPreviewIfOpen:function(e){this.$activeBadge&&this.$previewPopover},escapeHtml:function(e){return e?String(e).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'"):""},escapeAttr:function(e){return e?String(e).replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'"):""},showTotalPreviewPopover:function(t){var i=this,a=this.config.trans||{};this.hidePreviewPopover(),t.addClass("popover-open"),this.$activeBadge=t;var s=[];this.$wrapper.find(".target-block-tab.has-data").each(function(){var t=e(this),a=t.data("blockType"),o=t.find(".tab-badge").text().replace(/[^0-9]/g,""),n=parseInt(o,10)||0;if(n>0){i.config.blocks&&i.config.blocks[a]&&i.config.blocks[a];var r=t.find(".tab-label").prev("i").text()||"widgets",l=t.find(".tab-label").text()||a;s.push({blockType:a,label:l,icon:r,count:n})}});var o=parseInt(t.find(".count-value").text(),10)||0,n='
';n+='
',n+=''+(a.total_summary||"Selection Summary")+"",n+=''+o+" "+(a.total_items||"total items")+"",n+="
",n+='
',n+='
    ';for(var r=0;r',n+=this.esIcon(l.icon),n+=''+i.escapeHtml(l.label)+"",n+=''+l.count+"",n+=""}n+="
",n+="
";var c=e(n+="
");this.$previewPopover=c,c.on("click",".total-summary-item",function(){var t=e(this).data("blockType");i.hidePreviewPopover(),i.switchToBlock(t)}),e("body").append(c);var d=t.offset(),p=t.outerHeight(),u=c.outerWidth();c.css({position:"absolute",top:d.top+p+5,left:d.left-u/2+t.outerWidth()/2,zIndex:1e4});var h=e(window).width();c.offset().left+u>h-10&&c.css("left",h-u-10),c.offset().left<10&&c.css("left",10),c.hide().fadeIn(150)},showHolidayPreview:function(t,i,a,s){var o=this,n=this.config.trans||{};e(".holiday-preview-popover").remove();var r='
';r+='
',r+='',a&&(r+=' '),r+=this.escapeHtml(i)+" - "+(n.holidays||"Holidays"),r+="",r+='",r+="
",r+='
',r+='
'+this.esIcon("sync","es-spin")+" "+(n.loading||"Loading...")+"
",r+="
";var l=e(r+="
");e("body").append(l);var c=s[0].getBoundingClientRect(),d=e(window).scrollTop(),p=e(window).scrollLeft(),u=l.outerWidth(),h=l.outerHeight(),f=e(window).width(),v=e(window).height(),g=c.bottom+d+8,m=c.left+p;m+u>f-10&&(m=f-u-10),m<10&&(m=10),c.bottom+h>v-10&&(g=c.top+d-h-8),l.css({position:"absolute",top:g,left:m,zIndex:10001}),l.find(".popover-close").on("click",function(){l.remove()}),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"getHolidaysPreview",trait:"EntitySelector",id_country:t},success:function(e){if(e.success&&e.holidays&&e.holidays.length>0){for(var t='
',i=0;i',t+='
',t+=''+o.escapeHtml(a.date_formatted||a.date)+"",a.day_of_week&&(t+=''+o.escapeHtml(a.day_of_week)+""),t+="
",t+='
',t+=''+o.escapeHtml(a.name)+"",a.type&&(t+=''+o.escapeHtml(a.type)+""),t+="
",t+="
"}t+="",e.total_count&&(t+='
'+e.total_count+" "+(n.upcoming_holidays||"upcoming holidays")+"
"),l.find(".popover-body").html(t)}else{var s='
';s+=o.esIcon("event_busy"),s+="

"+(n.no_holidays||"No holidays found")+"

",s+="
",l.find(".popover-body").html(s)}var r=l.outerHeight();if(c.bottom+r>v-10){var p=c.top+d-r-8;p>10&&l.css("top",p)}},error:function(){var e='
';e+=o.esIcon("error"),e+="

"+(n.error_loading||"Error loading holidays")+"

",e+="
",l.find(".popover-body").html(e)}})},showCountriesHolidayPreview:function(t,i){var a=this,s=this.config.trans||{};this.hidePreviewPopover(),e(".holiday-preview-popover").remove();var o='
';o+='
',o+=''+this.esIcon("sync","es-spin")+" "+(s.loading||"Loading...")+"",o+='",o+="
",o+='
',o+=this.esIcon("search"),o+='',o+="
",o+='
',o+='
'+this.esIcon("sync","es-spin")+" "+(s.loading||"Loading...")+"
",o+="
";var n=e(o+="
");e("body").append(n);var r=t[0].getBoundingClientRect(),l=e(window).scrollTop(),c=e(window).scrollLeft(),d=n.outerWidth(),p=n.outerHeight(),u=e(window).width(),h=e(window).height(),f=r.bottom+l+8,v=r.left+c;v+d>u-10&&(v=u-d-10),v<10&&(v=10),r.bottom+p>h-10&&(f=r.top+l-p-8),n.css({position:"absolute",top:f,left:v,zIndex:10001}),t.addClass("popover-open"),this.$activeBadge=t,n.find(".popover-close").on("click",function(){n.remove(),t.removeClass("popover-open"),a.$activeBadge=null}),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"getHolidaysForCountries",trait:"EntitySelector",country_ids:i.join(","),count_only:0},success:function(t){if(t.success&&t.holidays&&t.holidays.length>0){var o={},c={};if(t.countries)for(var d=0;d ')}else{for(var w=0;w<2;w++){var _=v[w];_&&_.iso_code&&(g+=' ')}g+="+"+(m-2)+" "}g+=t.total_count+" "+(s.holidays||"Holidays"),n.find(".popover-title").html(g);for(var x='
',k=0;k',x+='
',x+=''+a.escapeHtml(C.date_formatted||C.date)+"",C.day_of_week&&(x+=''+a.escapeHtml(C.day_of_week)+""),x+="
",x+='
',C.country_iso&&i.length>1&&(x+=' '),x+=''+a.escapeHtml(C.name)+"",C.type&&(x+=''+a.escapeHtml(C.type)+""),x+="
",x+="
"}x+="",t.total_count&&i.length>1&&(x+='
'+(s.across_countries||"across")+" "+i.length+" "+(s.countries||"countries")+"
"),n.find(".popover-body").html(x),n.find(".holiday-filter-input").on("input",function(){var t=e(this).val().toLowerCase().trim(),a=n.find(".holiday-item"),o=0;a.each(function(){var i=e(this).attr("data-search")||"";t&&-1===i.indexOf(t)?e(this).hide():(e(this).show(),o++)});var r=n.find(".holiday-preview-note");if(t&&r.length)r.text(o+" "+(s.matches||"matches"));else if(r.length&&i.length>1){var l=(s.across_countries||"across")+" "+i.length+" "+(s.countries||"countries");r.text(l)}})}else{n.find(".popover-title").html("0 "+(s.holidays||"Holidays"));var I='
';I+=a.esIcon("event_busy"),I+="

"+(s.no_holidays||"No holidays found")+"

",I+="
",n.find(".popover-body").html(I)}var M=n.outerHeight();if(r.bottom+M>h-10){var T=r.top+l-M-8;T>10&&n.css("top",T)}},error:function(){n.find(".popover-title").html(a.esIcon("error")+" "+(s.error||"Error"));var e='
';e+=a.esIcon("error"),e+="

"+(s.error_loading||"Error loading holidays")+"

",e+="
",n.find(".popover-body").html(e)}})}}}(jQuery),function(e){"use strict";window._EntitySelectorMixins=window._EntitySelectorMixins||{},window._EntitySelectorMixins.tree={treeData:null,treeFlatData:null,loadCategoryTree:function(){var t=this,i=this.$dropdown.find(".dropdown-results"),a=this.config.trans||{},s=this.activeGroup?this.activeGroup.searchEntity:"categories";i.html('
'+this.esIcon("progress_activity","es-spin")+" "+this.escapeHtml(a.loading||"Loading...")+"
"),e.ajax({url:this.config.ajaxUrl,type:"POST",dataType:"json",data:{ajax:1,action:"getCategoryTree",trait:"EntitySelector",entity_type:s},success:function(e){e.success&&e.categories&&e.categories.length>0?(t.treeFlatData=e.categories,t.treeData=t.buildTreeStructure(e.categories),t.renderCategoryTree(i,s)):i.html('")},error:function(){i.html('")}})},buildTreeStructure:function(t){var i={},a=[];return t.forEach(function(t){i[t.id]=e.extend({},t,{children:[]})}),t.forEach(function(e){var t=i[e.id],s=parseInt(e.parent_id,10);s&&i[s]?i[s].children.push(t):a.push(t)}),a},renderCategoryTree:function(e,t){var i=this.config.trans||{},a=this.getSelectedIdsFromChips(),s='
';s+='
',s+='",s+='",s+="
",s+='
',s+=this.renderTreeItems(this.treeData,0,a),s+="
",s+="
",e.html(s);var o=this.treeFlatData?this.treeFlatData.length:0,n=a.length,r=o+" "+("cms_categories"===t?"CMS categories":"categories");n>0&&(r+=" ("+n+" selected)"),this.$dropdown.find(".results-count").text(r),this.updateSelectChildrenButtons(this.$dropdown.find(".tree-item"))},renderTreeItems:function(e,t,i){var a=this,s="",o=this.config.trans||{};return e.forEach(function(e){var n=e.children&&e.children.length>0,r=-1!==i.indexOf(parseInt(e.id,10)),l=20*t,c="tree-item";n&&(c+=" has-children"),r&&(c+=" selected"),e.active||(c+=" inactive"),s+='
',s+='',n?(s+=''+a.esIcon("arrow_drop_down")+"",s+='"):s+='',s+=''+a.esIcon("check")+"",s+=''+a.esIcon("folder")+"",s+=''+a.escapeHtml(e.name)+"";var d=e.product_count||e.page_count||0;if(d>0){var p=e.page_count?o.pages||"pages":o.products||"products";s+='',s+=a.esIcon("visibility")+" "+d,s+=""}e.active||(s+=''+a.escapeHtml(o.inactive||"Inactive")+""),s+="
",n&&(s+='
',s+=a.renderTreeItems(e.children,t+1,i),s+="
")}),s},getSelectedIdsFromChips:function(){var t=[];if(!this.activeGroup)return t;var i=this.$wrapper.find('.target-block[data-block-type="'+this.activeGroup.blockType+'"]').find('.selection-group[data-group-index="'+this.activeGroup.groupIndex+'"]');return("include"===this.activeGroup.section?i.find(".include-picker"):i.find('.exclude-row[data-exclude-index="'+this.activeGroup.excludeIndex+'"]').find(".exclude-picker")).find(".entity-chip").each(function(){t.push(parseInt(e(this).data("id"),10))}),t},filterCategoryTree:function(t){var i=this.$dropdown.find(".category-tree");if(i.length){var a=i.find(".tree-item"),s=i.find(".tree-children");if(t=(t||"").toLowerCase().trim(),a.css("display",""),!t)return a.removeClass("filtered-out filter-match"),void s.removeClass("filter-expanded");a.addClass("filtered-out").removeClass("filter-match"),a.each(function(){var i=e(this);-1!==(i.data("name")||"").toLowerCase().indexOf(t)&&(i.removeClass("filtered-out"),i.parents(".tree-children").addClass("filter-expanded"),i.parents(".tree-item").removeClass("filtered-out"),i.next(".tree-children").find(".tree-item").removeClass("filtered-out"),i.next(".tree-children").addClass("filter-expanded"))})}},findTreeDescendants:function(e,t){var i=[],a=(parseInt(e.data("id"),10),parseInt(e.data("level"),10),e.next(".tree-children"));return a.length&&a.find(".tree-item").each(function(){i.push(this)}),i},updateSelectChildrenButtons:function(t){var i=this,a=this.config.trans||{};t.filter(".has-children").each(function(){var t=e(this),s=t.find(".btn-select-children");if(s.length){var o=t.next(".tree-children");if(o.length){var n=o.find(".tree-item"),r=t.hasClass("selected"),l=!0;n.each(function(){if(!e(this).hasClass("selected"))return l=!1,!1}),r&&l?(s.find("i").replaceWith(i.esIcon("indeterminate_check_box")),s.attr("title",a.deselect_with_children||"Deselect with all children")):(s.find("i").replaceWith(i.esIcon("add_box")),s.attr("title",a.select_with_children||"Select with all children"))}}})}}}(jQuery),function(e){"use strict";window._EntitySelectorMixins=window._EntitySelectorMixins||{},window._EntitySelectorMixins.validation={validateSelection:function(t,i,a,s){if(!this.activeGroup)return{valid:!0};var o=this.config.trans||{};t=parseInt(t,10);var n=this.$wrapper.find('.target-block[data-block-type="'+this.activeGroup.blockType+'"]').find('.selection-group[data-group-index="'+this.activeGroup.groupIndex+'"]'),r=this.getChipIds(n.find(".include-picker")),l=[];n.find(".exclude-row").each(function(){var t=e(this).find(".exclude-picker"),i=[];t.find(".entity-chip").each(function(){i.push(parseInt(e(this).data("id"),10))}),l=l.concat(i)});var c=this.checkIncludeExcludeConflict(t,i,a,r,l,o);if(!c.valid)return c;var d=this.checkRedundantSelection(t,i,a,r,l,o);if(!d.valid)return d;var p=this.activeGroup.searchEntity;if("categories"===p||"cms_categories"===p){var u=this.checkTreeConflicts(t,i,a,s,r,l,o);if(!u.valid)return u}return{valid:!0}},checkIncludeExcludeConflict:function(e,t,i,a,s,o){return"include"===i&&-1!==s.indexOf(e)?{valid:!1,type:"include_exclude_conflict",error:(o.error_in_exclude||'"{name}" is already in the exclude list. Remove it from exclude first.').replace("{name}",t)}:"exclude"===i&&-1!==a.indexOf(e)?{valid:!1,type:"include_exclude_conflict",error:(o.error_in_include||'"{name}" is already in the include list. Remove it from include first.').replace("{name}",t)}:{valid:!0}},checkRedundantSelection:function(e,t,i,a,s,o){return"include"===i&&-1!==a.indexOf(e)?{valid:!1,type:"redundant",error:(o.error_already_selected||'"{name}" is already selected.').replace("{name}",t)}:"exclude"===i&&-1!==s.indexOf(e)?{valid:!1,type:"redundant",error:(o.error_already_excluded||'"{name}" is already in an exclude list.').replace("{name}",t)}:{valid:!0}},checkTreeConflicts:function(e,t,i,a,s,o,n){if(!this.treeFlatData)return{valid:!0};a&&a.parentId&&parseInt(a.parentId,10);var r={};this.treeFlatData.forEach(function(e){r[parseInt(e.id,10)]=e});var l=this.getAncestorIds(e,r),c=this.getDescendantIds(e,r);if("include"===i){for(var d=0;d0)return{valid:!1,type:"children_included",error:(n.error_children_included||'Cannot exclude "{name}" because its children ({children}) are included. Remove them from include first.').replace("{name}",t).replace("{children}",g.slice(0,3).join(", ")+(g.length>3?"...":""))}}return{valid:!0}},getAncestorIds:function(e,t){for(var i=[],a=t[e];a&&a.parent_id;){var s=parseInt(a.parent_id,10);if(!s||!t[s])break;i.push(s),a=t[s]}return i},getDescendantIds:function(e,t){var i=[],a=this;return Object.keys(t).forEach(function(s){var o=t[s];if(parseInt(o.parent_id,10)===e){var n=parseInt(o.id,10);i.push(n);var r=a.getDescendantIds(n,t);i=i.concat(r)}}),i},getChipIds:function(t){var i=[];return t.find(".entity-chip").each(function(){i.push(parseInt(e(this).data("id"),10))}),i},validatePendingSelections:function(e,t){var i=this,a=[];return e&&e.length?(e.forEach(function(e){var s=i.validateSelection(e.id,e.name,t,e.data||{});s.valid||a.push({id:e.id,name:e.name,error:s.error,type:s.type})}),a):a},showValidationError:function(t){var i=(this.config.trans||{}).validation_error||"Selection Conflict";e(".es-validation-toast").remove();var a='
';a+='
'+this.esIcon("warning")+"
",a+='
',a+='
'+this.escapeHtml(i)+"
",a+='
'+this.escapeHtml(t)+"
",a+="
",a+='";var s=e(a+="
");if(e("body").append(s),this.$dropdown&&this.$dropdown.hasClass("show")){var o=this.$dropdown.offset();s.css({position:"fixed",top:o.top-s.outerHeight()-10,left:o.left,zIndex:10001})}else s.css({position:"fixed",top:20,right:20,zIndex:10001});s.hide().fadeIn(200),setTimeout(function(){s.fadeOut(200,function(){e(this).remove()})},5e3),s.on("click",".es-toast-close",function(){s.fadeOut(200,function(){e(this).remove()})})},validateAndAddSelection:function(e,t,i,a,s){var o=this.validateSelection(t,i,s,a||{});return o.valid?(this.addSelection(e,t,i,a),!0):(this.showValidationError(o.error),!1)}}}(jQuery),function(e){"use strict";var t={instances:[],create:function(t){var i=function(){var t={config:{},$wrapper:null,$dropdown:null,activeGroup:null,searchTimeout:null,searchResults:[],searchTotal:0,searchOffset:0,searchQuery:"",isLoading:!1,loadMoreCount:20,viewMode:"list",currentSort:{field:"name",dir:"ASC"},refineQuery:"",refineNegate:!1,filters:{inStock:!1,discounted:!1,priceMin:null,priceMax:null,attributes:[],features:[],productCountMin:null,productCountMax:null,salesMin:null,salesMax:null,turnoverMin:null,turnoverMax:null,depth:null,hasProducts:!1,hasDescription:!1,hasImage:!1,activeOnly:!0,attributeGroup:null,featureGroup:null,dateAddFrom:null,dateAddTo:null,lastProductFrom:null,lastProductTo:null,hasHolidays:!1,containsStates:!1,zone:null},filterableData:null,searchHistory:{},searchHistoryMax:10,searchHistoryKey:"targetConditionsSearchHistory",maxVisibleChips:20,$methodDropdownMenu:null,$methodDropdownSelect:null,$methodDropdownTrigger:null,$previewPopover:null,$activeBadge:null,$previewList:null,previewLoadedCount:0,previewBlockType:null,allPreviewData:null,countUpdateTimeout:null,init:function(t){if(this.config=e.extend({id:"target-conditions",name:"target_conditions",namePrefix:"target_",mode:"multi",blocks:{},ajaxUrl:"",trans:{}},t),this.$wrapper=e('[data-entity-selector-id="'+this.config.id+'"]'),this.$wrapper.length){"single"===this.config.mode&&(this.$wrapper.find(".btn-add-group").hide(),this.$wrapper.find(".group-excludes").hide(),this.$wrapper.find(".group-modifiers").hide());var i=this.$wrapper.hasClass("layout-form-group"),a=this.$wrapper.closest(".entity-selector-form-group");if(!i&&!a.length){var s=this.$wrapper.closest(".form-group");s.addClass("condition-trait-fullwidth"),s.find(".col-lg-offset-3").removeClass("col-lg-offset-3")}this.createDropdown(),this.bindEvents(),this.loadExistingSelections(),this.loadSearchHistory(),this.initMethodDropdowns(),this.observeNewSelects();var o=this;setTimeout(function(){o.updateTabBadges(),o.updateAllConditionCounts()},100)}},observeNewSelects:function(){var t=this;"undefined"!=typeof MutationObserver&&new MutationObserver(function(i){i.forEach(function(i){i.addedNodes.length&&e(i.addedNodes).find(".include-method-select, .exclude-method-select").each(function(){t.enhanceMethodSelect(e(this))})})}).observe(this.$wrapper[0],{childList:!0,subtree:!0})},loadExistingSelections:function(){}},i=window._EntitySelectorMixins||{};return i.utils&&e.extend(t,i.utils),i.events&&e.extend(t,i.events),i.dropdown&&e.extend(t,i.dropdown),i.search&&e.extend(t,i.search),i.filters&&e.extend(t,i.filters),i.chips&&e.extend(t,i.chips),i.groups&&e.extend(t,i.groups),i.methods&&e.extend(t,i.methods),i.preview&&e.extend(t,i.preview),i.tree&&e.extend(t,i.tree),i.validation&&e.extend(t,i.validation),t}();return i.init(t),this.instances.push(i),i},init:function(e){return this.create(e)},validateAll:function(){for(var e=!0,t=0;t0&&!t.validateAll())return i.preventDefault(),!1})})}(jQuery); //# sourceMappingURL=entity-selector.min.js.map diff --git a/assets/js/admin/entity-selector.min.js.map b/assets/js/admin/entity-selector.min.js.map index abc241c..3854cf3 100644 --- a/assets/js/admin/entity-selector.min.js.map +++ b/assets/js/admin/entity-selector.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["_utils.js","_events.js","_dropdown.js","_search.js","_filters.js","_chips.js","_groups.js","_methods.js","_preview.js","_tree.js","_validation.js","_core.js"],"names":["$","window","_EntitySelectorMixins","utils","debounce","func","wait","timeout","context","this","args","arguments","clearTimeout","setTimeout","apply","escapeHtml","str","String","replace","escapeAttr","getEntityTypeIcon","entityType","products","categories","manufacturers","suppliers","attributes","features","cms","cms_categories","getEntityTypeLabel","trans","config","product","category","manufacturer","supplier","attribute","feature","cms_page","cms_category","validate","$wrapper","data","hasData","find","each","length","clearValidationError","showValidationError","addClass","message","remove","$error","class","html","after","animate","scrollTop","offset","top","is","slideDown","removeClass","getBlockMode","blockType","blockDef","blocks","mode","isBlockSingleMode","getCurrentSingleSelection","$chip","first","$block","closest","name","text","supportsTreeBrowsing","jQuery","events","bindEvents","self","on","e","preventDefault","switchToBlock","stopPropagation","$tab","hasClass","hidePreviewPopover","showPreviewPopover","$badge","showConditionPreviewPopover","showGroupPreviewPopover","showTotalPreviewPopover","document","target","$body","stop","slideUp","$blocksContent","$icon","$btn","valueId","valueType","valueName","groupId","showFilterValuePreviewPopover","showFilterGroupPreviewPopover","toggleClass","currentState","attr","collapse_all","expand_all","prop","clearAllConditions","val","addGroup","$group","removeGroup","$input","trim","serializeAllBlocks","addFirstExcludeRow","addExcludeRow","$excludeRow","removeExcludeRow","hideDropdown","$row","methods","selection_methods","$option","searchEntity","methodOptions","$oldPicker","newPickerHtml","buildValuePickerHtml","replaceWith","$select","$newPicker","empty","key","label","append","isExclusive","populateTiles","step","min","applyRangeInputConstraints","loadCombinationAttributeGroups","selectedMethod","updateMethodInfoPlaceholder","updateBlockStatus","keyCode","click","$draftTag","$picker","pattern","caseSensitive","addPatternTag","focus","hide","$matchCount","updateDraftTagCount","updateGroupTotalCount","$tag","isDraftTag","newCaseSensitive","caseTitle","case_sensitive","case_insensitive","count","showPatternPreviewModal","currentPattern","$editInput","$saveBtn","$cancelBtn","$editActions","prepend","select","ev","newPattern","show","content","tooltipClass","$tooltip","triggerWidth","outerWidth","tooltipWidth","tooltipHeight","outerHeight","left","width","css","position","$container","$chipsContainer","$minInput","$maxInput","minVal","maxVal","parseFloat","minAllowed","hasMinConstraint","minNum","maxNum","showRangeInputError","min_value_error","min_greater_than_max","chipText","decimals","split","Math","round","toFixed","type","$tile","$value","updateCombinationData","query","toLowerCase","indexOf","$modifiers","$content","slideToggle","$limitInput","limit","parseInt","finalCount","$previewBadge","displayCount","updateModifierButtonState","refreshGroupPreviewIfOpen","newDir","groupIndex","section","excludeIndex","activeGroup","searchResults","searchOffset","searchQuery","viewMode","resetFiltersWithoutSearch","$dropdown","$chips","pendingSelections","push","id","pendingPicker","pendingRow","updateFilterPanelForEntity","loadFilterableData","positionDropdown","performSearch","loadCategoryTree","searchTimeout","filterCategoryTree","$item","removeFromSearchHistory","fadeOut","activeElement","filter","blur","isSelected","s","removeSelection","validation","validateSelection","valid","error","currentSelection","newEntityType","showReplaceConfirmation","addSelection","some","countryId","countryName","countryIso","showHolidayPreview","updateChipsVisibility","skippedCount","addSelectionNoUpdate","msg","items_skipped_conflicts","selectedCount","totalCount","categoryLabel","forEach","sel","isLoading","loadCount","loadMoreCount","currentSort","field","refreshSearch","dir","$allItems","isCollapsed","descendants","findTreeDescendants","i","toggle","updateSelectChildrenButtons","$count","categoryId","categoryName","showCategoryItemsPreview","allSelected","j","$child","select_with_children","skippedChildren","parentValidation","k","$descendant","skipMsg","children_skipped_conflicts","deselect_with_children","minLevel","Infinity","level","hasChildren","refineQuery","refineTimeout","refineNegate","placeholder","refine_exclude","refine_short","$panel","showSearchHistory","filters","inStock","discounted","priceMin","priceMax","productCountMin","productCountMax","salesMin","salesMax","turnoverMin","turnoverMax","dateAddFrom","dateAddTo","lastProductFrom","lastProductTo","depth","hasProducts","hasDescription","hasImage","activeOnly","attributeGroup","featureGroup","isColor","isCustom","indexable","hasHolidays","containsStates","zone","isActive","hideFilterGroupValues","showFilterGroupValues","prevMode","renderSearchResults","filterArray","index","splice","updateFilterToggleStates","clearFilters","isInputFocused","ctrlKey","metaKey","trigger","rect","getBoundingClientRect","innerWidth","bottom","$closeBtn","dropdown","createDropdown","select_all","all","clear_selection","clear","sort_name","sort_id","sort_selected","sort_price","sort_stock","sort_popularity","sort_reference","sort_position","sort_product_count","view_list","view_tree","cols","exclude_matches","toggle_filters","recent_searches","in_stock","price","max","clear_filters","product_count","total_sales","turnover","active_only","all_levels","root","has_products","has_description","has_image","date_added","from","to","last_product","attribute_group","all_groups","color_only","feature_group","custom_only","has_holidays","contains_states","all_zones","sale","stock","sold","load","of","remaining","cancel","save","$searchBox","searchBoxOffset","searchBoxHeight","pickerOffset","pickerWidth","dropdownTop","dropdownLeft","dropdownWidth","viewportWidth","maxHeight","height","zIndex","search","categoryTreeCache","appendMode","requestData","ajax","action","trait","entity_type","q","sort_by","sort_dir","productSelectionLevel","product_selection_level","refine","refine_negate","filter_in_stock","filter_discounted","filter_price_min","filter_price_max","filter_attributes","JSON","stringify","filter_features","filter_product_count_min","filter_product_count_max","filter_depth","filter_has_products","filter_has_description","filter_has_image","filter_sales_min","filter_sales_max","filter_turnover_min","filter_turnover_max","filter_active","filter_date_add_from","filter_date_add_to","filter_last_product_from","filter_last_product_to","filter_attribute_group","filter_is_color","filter_feature_group","filter_is_custom","filter_indexable","filter_has_holidays","filter_contains_states","filter_zone","url","ajaxUrl","dataType","success","response","total","addToSearchHistory","concat","results","searchTotal","selectedIds","hiddenIds","currentSearchEntity","currentExcludeIndex","isProductSearch","isListView","visibleResults","item","hiddenCount","countText","itemClass","is_combination","is_parent","image","subtitle","iso_code","flagUrl","iconClass","subtitleLines","line","idx","regular_price_formatted","price_formatted","has_discount","stockClass","stock_status","undefined","stock_qty","sales_qty","gridStockClass","discount_percent","no_results","hasMore","$loadMoreControls","$allOption","hasHistory","getSearchHistory","loadSearchHistory","stored","localStorage","getItem","searchHistoryKey","searchHistory","parse","saveSearchHistory","setItem","history","existingIndex","unshift","searchHistoryMax","slice","$treeOption","filterableData","loadAttributeGroups","loadZonesForCountryFilter","groups","group","loadFeatureGroups","isCategory","updateSortOptionsForEntity","currentValue","hasCurrentOption","entities","isAllowed","renderFilterDropdowns","previewLabel","preview","$attrContainer","$featContainer","g","valuesRowClass","$filterRowValues","$valuesContainer","values","activeClass","chipClass","colorStyle","color","colorClass","rowValues","scrollIntoView","behavior","block","$toggle","hasActiveInGroup","zonesLoaded","zones","chips","isCountry","$allChips","$existingWrapper","ensureChipsWrapper","$toolbar","$loadMore","searchTerm","visibleCount","filteredCount","isExpanded","maxVisible","maxVisibleChips","chipName","matchesFilter","updateChipsToolbar","hiddenByPagination","loadText","remainingText","loadMoreHtml","collapseText","collapse","before","wrapperHtml","filter_selected","sort","sort_added","sort_name_asc","sort_name_desc","clear_all","bindChipsToolbarEvents","sortBy","sortChips","sorted","toArray","a","b","$a","$b","nameA","nameB","localeCompare","nameA2","chip","$clearBtn","$clearText","loadExistingSelections","entitiesToLoad","$includePicker","collectPickerEntities","enhanceMethodSelect","updateMethodSelectorLock","bulkRequest","hasEntities","Object","keys","ids","uniqueIds","arr","bulkAjaxData","entityMap","entity","pickers","pickerData","$dataInput","validIds","$loadingChip","updateAllConditionCounts","xhr","status","rawValue","entityIcon","Array","isArray","range","loadPickerValues","pickerAjaxData","isCaseSensitive","remove_pattern","getPatternTags","patterns","$countValue","updateConditionCountWithPendingPattern","pendingPattern","$countEl","isExclude","method","block_type","fetchPatternMatchCount","getPickerValues","patternValues","$draftPatternInput","draftPatternVal","draftCaseSens","updateConditionCount","hasNoValues","updateGroupCounts","$include","groupData","serializeGroup","include","group_data","final_count","excludeCount","exclude_count","badgeHtml","fetchCategoryNamesAndAddChips","callback","maxIndex","buildMethodOptions","click_to_name","remove_group","no_items_selected","search_placeholder","add_exceptions","limit_tooltip","sort_bestsellers","sort_newest","sort_random","sort_direction","preview_results","$newGroup","emptyHtml","getEmptyStateText","updateTabBadges","updateHeaderTotalCount","blockTypesWithData","groupCount","updateTargetSwitchState","fetchAllCounts","$switch","blockTypes","$hiddenInput","savedData","conditions","counts","fetchProductCount","removeData","isNaN","$totalBadge","updateShowAllToggle","$checkbox","$status","getBlockGroups","emptyMeansAll","entity_label_plural","nothing_selected","blockMode","no_item_selected","included","includeMethod","includeValues","excludes","excludeMethod","$excludePicker","excludeValues","modifiers","getGroupModifiers","$changedRow","jsonData","countUpdateTimeout","isConditionValid","groupName","sortDir","Number","$draftInput","draftPattern","draftCaseSensitive","selectVal","ranges","combAttrs","toString","combMode","configMode","combinationMode","conditionElements","conditionIndex","includeData","getConditionData","condition","excludeData","items","allCountryIds","map","isCountryHolidays","countryIds","isAllCountries","country_ids","join","count_only","holidayResponse","total_count","countries","isCountrySelection","$excludesDiv","except","buildExcludeRowHtml","add_another_exception","$firstRow","$firstSelect","initialMethod","$newRow","$newSelect","excludeMethodOptions","firstSearchEntity","firstValueType","methodKey","methodDef","search_entity","value_type","remove_this_exception","excludeAll","groupLabels","select_by","filter_by","grouped","ungrouped","buildMethodOption","groupKey","groupMethods","groupLabel","icon","options","exclusive","pickerClass","chipsClass","dataClass","noItemsText","tooltipContent","pattern_help_title","pattern_help_wildcard","pattern_help_number","pattern_help_letter","pattern_help_examples","pattern_example_1","pattern_example_2","pattern_example_3","noPatternText","no_patterns","enter_pattern","click_to_preview","add_pattern","add_range","yes","combination_help_title","combination_help_desc","combination_help_logic","combination_help_within","combination_help_between","showModeToggle","defaultMode","Date","now","comb_mode_products","comb_mode_combinations","loading","getSortOptionsArray","value","sort_products","getSortIconClass","isAsc","cycleSortOption","newSort","newLabel","sortOptions","currentDir","currentIndex","initMethodDropdowns","initMethodInfoPlaceholders","$selectedOption","selectedIcon","selectedLabel","triggerHtml","$trigger","showMethodDropdownMenu","updateMethodTrigger","closeMethodDropdownMenu","menuHtml","buildMethodDropdownMenuHtml","$menu","triggerOffset","triggerHeight","minWidth","$methodDropdownMenu","$methodDropdownSelect","$methodDropdownTrigger","children","$el","$optgroup","off","removeAttr","optData","tileClass","$inputs","$groupDiv","$groupHeader","title","filter_results","loadCombinationAttributeValues","no_attribute_groups","error_loading","id_attribute_group","productCount","$valueBtn","restoreCombinationSelections","no_values","dataStr","valueIds","updateCombinationGroupCounts","$headerRow","$placeholder","methodHelp","helpContent","getBuiltInMethodHelp","$infoWrapper","help_all_title","help_all_desc","help_specific_title","help_specific_desc","help_category_title","help_category_desc","help_manufacturer_title","help_manufacturer_desc","help_supplier_title","help_supplier_desc","help_tag_title","help_tag_desc","help_attribute_title","help_attribute_desc","help_feature_title","help_feature_desc","help_combination_title","help_combination_desc","help_combination_logic","help_combination_within","help_combination_between","help_carrier_title","help_carrier_desc","help_condition_title","help_condition_desc","help_visibility_title","help_visibility_desc","help_active_title","help_active_desc","help_stock_title","help_stock_desc","help_boolean_title","help_boolean_desc","help_pattern_title","help_pattern_desc","help_pattern_wildcard","help_pattern_number","help_pattern_letter","help_range_title","help_range_desc","help_range_tip","help_date_title","help_date_desc","buildSortOptions","summary","sortLabel","$arrow","insertBefore","locked","wrap","parent","lockHtml","remove_excludes_first","siblings","createPreviewPopover","entityLabel","previewType","renderPreviewItems","no_preview","$popover","$previewPopover","$previewList","previewLoadedCount","previewTotalCount","previewContext","previewOnLoadMore","onLoadMore","previewOnFilter","onFilter","previewCurrentFilter","previewEntityLabel","$filterInput","debouncedFilter","showFilterLoading","call","filterPreviewItems","previewLoadCount","positionPopover","triggerRect","scrollLeft","popoverWidth","popoverHeight","windowWidth","windowHeight","positionAbove","triggerCenter","popoverLeft","updatePreviewPopover","$footer","$controls","filterQuery","isCombination","dataAttrs","reference","meta","formatPrice","active","$items","ref","attrs","matches","$list","previewLockedWidth","updatePreviewPopoverFiltered","$header","noResultsText","no_filter_results","footerHtml","$newFooter","currencySign","currency_sign","currencyFormat","currency_format","formatted","$activeBadge","previewData","entityLabelPlural","previewBlockType","fetchTabPreviewItems","fetchedItems","loadMoreTabPreviewItems","filterTabPreviewItems","ajaxData","conditionData","showCountriesHolidayPreview","loadMoreConditionItems","filterConditionItems","ctx","loadMoreGroupItems","filterGroupItems","groupType","group_id","group_type","loadMoreFilterGroupItems","filterFilterGroupItems","value_id","loadMoreFilterValueItems","filterFilterValueItems","isProducts","category_id","loadMoreCategoryItems","filterCategoryItems","previewOffset","previewFilterQuery","appendPreviewItems","replacePreviewItems","blockConfig","entityLabelSingular","entity_label","$modal","listHtml","no_matches","and","more","summaryItems","prev","popoverHtml","total_summary","total_items","fadeIn","holidays","id_country","h","date_formatted","date","day_of_week","upcoming_holidays","noDataHtml","no_holidays","newPopoverHeight","newTop","errorHtml","filter_holidays","badgeRect","countryHolidayCounts","countriesMap","ci","cInfo","hi","hol","country_id","sortedCountries","titleHtml","numCountries","fi","fc","fj","fcc","typeClass","searchText","country_name","country_iso","across_countries","searchData","$note","noteText","tree","treeData","treeFlatData","$results","buildTreeStructure","renderCategoryTree","no_categories","flatData","lookup","extend","node","parentId","parent_id","getSelectedIdsFromChips","renderTreeItems","nodes","indent","itemCount","page_count","countLabel","pages","inactive","$tree","$children","parents","next","$next","$childItems","isParentSelected","allChildrenSelected","includeIds","getChipIds","excludeIds","conflictResult","checkIncludeExcludeConflict","redundantResult","checkRedundantSelection","treeResult","checkTreeConflicts","error_in_exclude","error_in_include","error_already_selected","error_already_excluded","ancestorIds","getAncestorIds","descendantIds","getDescendantIds","ancestorName","error_parent_excluded","descendantName","error_child_excluded","parentName","error_parent_included","includedDescendants","m","childName","error_children_included","ancestors","current","childId","childDescendants","validatePendingSelections","errors","result","validation_error","$toast","dropdownOffset","right","validateAndAddSelection","TargetConditions","instances","create","instance","allPreviewData","init","namePrefix","hasLayoutFormGroup","$entitySelectorFormGroup","$formGroup","observeNewSelects","MutationObserver","mutations","mutation","addedNodes","observe","childList","subtree","mixins","createTargetConditionsInstance","validateAll","allValid","ready","configData"],"mappings":"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","file":"entity-selector.min.js","sourcesContent":["/**\n * Entity Selector - Utilities Module\n * Helper functions: escape, validation, icons, search history\n * @partial _utils.js (must be loaded first)\n *\n * EXTRACTION SOURCE: assets/js/admin/entity-selector.js\n * Lines: 7552-7570 (escapeHtml, escapeAttr)\n * 7577-7590 (getEntityTypeLabel)\n * 6289-6350 (validate, showValidationError, clearValidationError)\n * 7115-7137 (showRangeInputError)\n * 7728-7745 (getBlockMode, isBlockSingleMode)\n * 7707-7723 (getCurrentSingleSelection)\n * 5411-5467 (search history methods)\n */\n\n(function($) {\n 'use strict';\n\n // Create mixin namespace\n window._EntitySelectorMixins = window._EntitySelectorMixins || {};\n\n // Utility functions mixin\n window._EntitySelectorMixins.utils = {\n\n /**\n * Debounce function - delays execution until after wait milliseconds\n * @param {Function} func - Function to debounce\n * @param {number} wait - Milliseconds to wait\n * @returns {Function} Debounced function\n */\n debounce: function(func, wait) {\n var timeout;\n return function() {\n var context = this;\n var args = arguments;\n clearTimeout(timeout);\n timeout = setTimeout(function() {\n func.apply(context, args);\n }, wait);\n };\n },\n\n escapeHtml: function(str) {\n if (str === null || str === undefined) return '';\n return String(str)\n .replace(/&/g, '&')\n .replace(//g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n },\n\n escapeAttr: function(str) {\n if (str === null || str === undefined) return '';\n return String(str)\n .replace(/&/g, '&')\n .replace(//g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n },\n\n getEntityTypeIcon: function(entityType) {\n var icons = {\n 'products': 'icon-shopping-cart',\n 'categories': 'icon-folder-open',\n 'manufacturers': 'icon-building',\n 'suppliers': 'icon-truck',\n 'attributes': 'icon-list-alt',\n 'features': 'icon-tags',\n 'cms': 'icon-file-text',\n 'cms_categories': 'icon-folder'\n };\n return icons[entityType] || 'icon-cube';\n },\n\n getEntityTypeLabel: function(entityType) {\n var trans = this.config.trans || {};\n var labels = {\n 'products': trans.product || 'Product',\n 'categories': trans.category || 'Category',\n 'manufacturers': trans.manufacturer || 'Manufacturer',\n 'suppliers': trans.supplier || 'Supplier',\n 'attributes': trans.attribute || 'Attribute',\n 'features': trans.feature || 'Feature',\n 'cms': trans.cms_page || 'CMS Page',\n 'cms_categories': trans.cms_category || 'CMS Category'\n };\n return labels[entityType] || entityType;\n },\n\n validate: function() {\n var isRequired = this.$wrapper.data('required') === 1 || this.$wrapper.data('required') === '1';\n if (!isRequired) return true;\n\n var hasData = false;\n this.$wrapper.find('.target-block').each(function() {\n if ($(this).find('.selection-group').length > 0) {\n hasData = true;\n return false;\n }\n });\n\n if (!hasData) {\n this.showValidationError();\n return false;\n }\n\n this.clearValidationError();\n return true;\n },\n\n showValidationError: function() {\n this.$wrapper.addClass('has-validation-error');\n var message = this.$wrapper.data('required-message') || 'Please select at least one item';\n this.$wrapper.find('.trait-validation-error').remove();\n var $error = $('
', {\n class: 'trait-validation-error',\n html: ' ' + message\n });\n this.$wrapper.find('.condition-trait-header').after($error);\n $('html, body').animate({ scrollTop: this.$wrapper.offset().top - 100 }, 300);\n if (!this.$wrapper.find('.condition-trait-body').is(':visible')) {\n this.$wrapper.find('.condition-trait-body').slideDown(200);\n this.$wrapper.removeClass('collapsed');\n }\n },\n\n clearValidationError: function() {\n this.$wrapper.removeClass('has-validation-error');\n this.$wrapper.find('.trait-validation-error').remove();\n },\n\n getBlockMode: function(blockType) {\n var blockDef = this.config.blocks[blockType];\n return (blockDef && blockDef.mode) ? blockDef.mode : 'multi';\n },\n\n isBlockSingleMode: function(blockType) {\n return this.getBlockMode(blockType) === 'single';\n },\n\n getCurrentSingleSelection: function() {\n if ((this.config.mode || 'multi') !== 'single') return null;\n var $chip = this.$wrapper.find('.entity-chips .entity-chip').first();\n if ($chip.length) {\n var $block = $chip.closest('.target-block');\n return {\n name: $chip.find('.chip-name').text() || $chip.data('id'),\n entityType: $block.data('block-type') || 'item'\n };\n }\n return null;\n },\n\n /**\n * Check if entity type supports tree browsing\n */\n supportsTreeBrowsing: function(entityType) {\n return entityType === 'categories' || entityType === 'cms_categories';\n }\n };\n\n})(jQuery);\n","/**\n * Entity Selector - Events Module\n * All event binding and handlers\n * @partial _events.js\n *\n * Contains event handlers for:\n * - Tab switching\n * - Block/group collapse toggle\n * - Dropdown open/close\n * - Search input handling\n * - Item selection/deselection\n * - Group add/remove\n * - Exclude row add/remove\n * - Method select changes\n * - Filter panel toggles\n * - Keyboard shortcuts (Ctrl+A, Ctrl+D, Esc, Enter)\n * - Load more pagination\n * - Sort controls\n * - View mode switching\n * - Tree view events\n * - Preview badge clicks\n * - Pattern tag interactions\n * - Combination picker events\n * - Group modifier events\n */\n\n(function($) {\n 'use strict';\n\n window._EntitySelectorMixins = window._EntitySelectorMixins || {};\n\n window._EntitySelectorMixins.events = {\n\n bindEvents: function() {\n var self = this;\n\n // Tab switching\n this.$wrapper.on('click', '.target-block-tab', function(e) {\n e.preventDefault();\n var blockType = $(this).data('blockType');\n self.switchToBlock(blockType);\n });\n\n // Tab badge click for preview popover (toggle)\n this.$wrapper.on('click', '.target-block-tab .tab-badge', function(e) {\n e.stopPropagation();\n e.preventDefault();\n\n var $tab = $(this).closest('.target-block-tab');\n var $badge = $(this);\n\n if ($badge.hasClass('popover-open')) {\n self.hidePreviewPopover();\n } else {\n self.showPreviewPopover($tab);\n }\n });\n\n // Condition count badge click for preview popover\n this.$wrapper.on('click', '.condition-match-count.clickable', function(e) {\n e.stopPropagation();\n e.preventDefault();\n\n var $badge = $(this);\n\n if ($badge.hasClass('popover-open')) {\n self.hidePreviewPopover();\n } else {\n self.showConditionPreviewPopover($badge);\n }\n });\n\n // Group count badge click for preview popover\n this.$wrapper.on('click', '.group-count-badge.clickable', function(e) {\n e.stopPropagation();\n e.preventDefault();\n\n var $badge = $(this);\n\n if ($badge.hasClass('popover-open')) {\n self.hidePreviewPopover();\n } else {\n self.showGroupPreviewPopover($badge);\n }\n });\n\n // Total count badge click for summary popover\n this.$wrapper.on('click', '.trait-total-count', function(e) {\n e.stopPropagation();\n e.preventDefault();\n\n var $badge = $(this);\n\n if ($badge.hasClass('popover-open')) {\n self.hidePreviewPopover();\n } else {\n self.showTotalPreviewPopover($badge);\n }\n });\n\n // Close popover when clicking outside\n $(document).on('click', function(e) {\n if (!$(e.target).closest('.target-preview-popover').length &&\n !$(e.target).closest('.holiday-preview-popover').length &&\n !$(e.target).closest('.tab-badge').length &&\n !$(e.target).closest('.condition-match-count').length &&\n !$(e.target).closest('.group-count-badge').length &&\n !$(e.target).closest('.group-modifiers').length &&\n !$(e.target).closest('.group-preview-badge').length &&\n !$(e.target).closest('.trait-total-count').length &&\n !$(e.target).closest('.chip-preview-holidays').length &&\n !$(e.target).closest('.chip-preview-btn').length) {\n self.hidePreviewPopover();\n // Also close holiday popover\n $('.holiday-preview-popover').remove();\n }\n });\n\n // Block-level collapse toggle (click on header)\n this.$wrapper.on('click', '.condition-trait-header', function(e) {\n if ($(e.target).closest('.target-block-tabs').length ||\n $(e.target).closest('.trait-header-actions').length ||\n $(e.target).closest('.prestashop-switch').length ||\n $(e.target).closest('.trait-total-count').length) {\n return;\n }\n var $body = self.$wrapper.find('.condition-trait-body');\n $body.stop(true, true);\n if ($body.is(':visible')) {\n $body.slideUp(200);\n self.$wrapper.addClass('collapsed');\n } else {\n $body.slideDown(200);\n self.$wrapper.removeClass('collapsed');\n }\n });\n\n // Toggle blocks content (form-content layout)\n this.$wrapper.on('click', '.btn-toggle-blocks', function(e) {\n e.preventDefault();\n var $blocksContent = self.$wrapper.find('.entity-selector-blocks-content');\n var $icon = $(this).find('.material-icons');\n $blocksContent.stop(true, true);\n if ($blocksContent.is(':visible')) {\n $blocksContent.slideUp(200);\n self.$wrapper.addClass('blocks-collapsed');\n $icon.text('expand_more');\n } else {\n $blocksContent.slideDown(200);\n self.$wrapper.removeClass('blocks-collapsed');\n $icon.text('expand_less');\n }\n });\n\n // Filter chip/group preview eye button (unified handler)\n this.$wrapper.on('click', '.chip-preview-btn', function(e) {\n e.preventDefault();\n e.stopPropagation();\n\n var $btn = $(this);\n\n if ($btn.hasClass('popover-open')) {\n self.hidePreviewPopover();\n } else {\n var valueId = $btn.data('id');\n var valueType = $btn.data('type');\n var valueName = $btn.data('name');\n var groupId = $btn.data('groupId');\n\n if (valueId) {\n // Value-level preview (specific attribute/feature value)\n self.showFilterValuePreviewPopover($btn, valueId, valueType, valueName, groupId);\n } else if (groupId) {\n // Group-level preview (entire attribute/feature group)\n self.showFilterGroupPreviewPopover($btn, groupId, valueType, valueName);\n }\n }\n });\n\n // Group-level collapse toggle (click on group header or toggle icon)\n this.$wrapper.on('click', '.group-header', function(e) {\n if ($(e.target).closest('.btn-remove-group, .group-name-input').length) {\n return;\n }\n if (self.$wrapper.data('mode') === 'single') {\n return;\n }\n var $group = $(this).closest('.selection-group');\n $group.toggleClass('collapsed');\n });\n\n // Toggle all groups (single button that switches between expand/collapse)\n this.$wrapper.on('click', '.trait-header-actions .btn-toggle-groups', function(e) {\n e.preventDefault();\n e.stopPropagation();\n var $btn = $(this);\n var currentState = $btn.attr('data-state') || 'collapsed';\n var trans = self.config.trans || {};\n\n if (currentState === 'collapsed') {\n self.$wrapper.find('.selection-group').removeClass('collapsed');\n $btn.attr('data-state', 'expanded');\n $btn.attr('title', trans.collapse_all || 'Collapse all groups');\n $btn.find('i').removeClass('icon-expand').addClass('icon-compress');\n } else {\n self.$wrapper.find('.selection-group').addClass('collapsed');\n $btn.attr('data-state', 'collapsed');\n $btn.attr('title', trans.expand_all || 'Expand all groups');\n $btn.find('i').removeClass('icon-compress').addClass('icon-expand');\n }\n });\n\n // Show all toggle change (legacy checkbox)\n this.$wrapper.on('change', '.trait-show-all-toggle .show-all-checkbox', function(e) {\n e.stopPropagation();\n var isChecked = $(this).prop('checked');\n if (isChecked) {\n self.clearAllConditions();\n }\n });\n\n // Target switch change (PrestaShop native switch)\n this.$wrapper.on('change', '.target-switch-toggle', function(e) {\n e.stopPropagation();\n var value = $(this).val();\n if (value === '1') {\n self.clearAllConditions();\n self.$wrapper.find('.condition-trait-body').slideUp(200);\n self.$wrapper.addClass('collapsed');\n } else {\n self.$wrapper.find('.condition-trait-body').slideDown(200);\n self.$wrapper.removeClass('collapsed');\n }\n });\n\n // Add group\n this.$wrapper.on('click', '.btn-add-group', function(e) {\n e.preventDefault();\n var $block = $(this).closest('.target-block');\n var blockType = $block.data('blockType');\n self.addGroup($block, blockType);\n });\n\n // Remove group\n this.$wrapper.on('click', '.btn-remove-group', function(e) {\n e.preventDefault();\n var $group = $(this).closest('.selection-group');\n var $block = $(this).closest('.target-block');\n self.removeGroup($group, $block);\n });\n\n // Group name input - stop propagation to prevent collapse\n this.$wrapper.on('click focus', '.group-name-input', function(e) {\n e.stopPropagation();\n });\n\n // Group name change\n this.$wrapper.on('change blur', '.group-name-input', function() {\n var $input = $(this);\n var $group = $input.closest('.selection-group');\n var name = $.trim($input.val());\n $group.attr('data-group-name', name);\n self.serializeAllBlocks();\n });\n\n // Add exceptions (first exclude row)\n this.$wrapper.on('click', '.btn-add-exclude', function(e) {\n e.preventDefault();\n var $group = $(this).closest('.selection-group');\n var $block = $(this).closest('.target-block');\n self.addFirstExcludeRow($group, $block);\n });\n\n // Add another exclude row\n this.$wrapper.on('click', '.btn-add-another-exclude', function(e) {\n e.preventDefault();\n var $group = $(this).closest('.selection-group');\n var $block = $(this).closest('.target-block');\n self.addExcludeRow($group, $block);\n });\n\n // Remove individual exclude row\n this.$wrapper.on('click', '.btn-remove-exclude-row', function(e) {\n e.preventDefault();\n var $excludeRow = $(this).closest('.exclude-row');\n var $group = $(this).closest('.selection-group');\n var $block = $(this).closest('.target-block');\n self.removeExcludeRow($excludeRow, $group, $block);\n });\n\n // Include method change\n this.$wrapper.on('change', '.include-method-select', function() {\n self.hideDropdown();\n\n var $group = $(this).closest('.selection-group');\n var $block = $(this).closest('.target-block');\n var $row = $group.find('.group-include');\n var blockType = $block.data('blockType');\n var blockDef = self.config.blocks[blockType] || {};\n var methods = blockDef.selection_methods || {};\n\n var $option = $(this).find('option:selected');\n var valueType = $option.data('valueType') || 'none';\n var searchEntity = $option.data('searchEntity') || '';\n var methodOptions = $option.data('options') || null;\n\n var $oldPicker = $group.find('.include-picker');\n var newPickerHtml = self.buildValuePickerHtml('include', valueType, searchEntity, methods);\n $oldPicker.replaceWith(newPickerHtml);\n\n if (valueType === 'select' && methodOptions) {\n var $newPicker = $group.find('.include-picker');\n var $select = $newPicker.find('.select-value-input');\n $select.empty();\n $.each(methodOptions, function(key, label) {\n $select.append('');\n });\n }\n\n if (valueType === 'multi_select_tiles' && methodOptions) {\n var $newPicker = $group.find('.include-picker');\n var isExclusive = $option.data('exclusive') === true;\n self.populateTiles($newPicker, methodOptions, isExclusive);\n }\n\n if (valueType === 'multi_numeric_range') {\n var $newPicker = $group.find('.include-picker');\n var step = $option.data('step');\n var min = $option.data('min');\n self.applyRangeInputConstraints($newPicker, step, min);\n }\n\n if (valueType === 'combination_attributes') {\n var $newPicker = $group.find('.include-picker');\n self.loadCombinationAttributeGroups($newPicker);\n }\n\n var selectedMethod = $(this).val();\n self.updateMethodInfoPlaceholder($group.find('.method-selector-wrapper'), selectedMethod, blockType);\n\n self.updateBlockStatus($block);\n self.serializeAllBlocks($row);\n });\n\n // Exclude method change (within an exclude row)\n this.$wrapper.on('change', '.exclude-method-select', function() {\n self.hideDropdown();\n\n var $excludeRow = $(this).closest('.exclude-row');\n var $group = $(this).closest('.selection-group');\n var $block = $(this).closest('.target-block');\n var blockType = $block.data('blockType');\n var blockDef = self.config.blocks[blockType] || {};\n var methods = blockDef.selection_methods || {};\n\n var $option = $(this).find('option:selected');\n var valueType = $option.data('valueType') || 'entity_search';\n var searchEntity = $option.data('searchEntity') || blockType;\n var methodOptions = $option.data('options') || null;\n\n var $oldPicker = $excludeRow.find('.exclude-picker');\n var newPickerHtml = self.buildValuePickerHtml('exclude', valueType, searchEntity, methods);\n $oldPicker.replaceWith(newPickerHtml);\n\n if (valueType === 'select' && methodOptions) {\n var $newPicker = $excludeRow.find('.exclude-picker');\n var $select = $newPicker.find('.select-value-input');\n $select.empty();\n $.each(methodOptions, function(key, label) {\n $select.append('');\n });\n }\n\n if (valueType === 'multi_select_tiles' && methodOptions) {\n var $newPicker = $excludeRow.find('.exclude-picker');\n var isExclusive = $option.data('exclusive') === true;\n self.populateTiles($newPicker, methodOptions, isExclusive);\n }\n\n if (valueType === 'multi_numeric_range') {\n var $newPicker = $excludeRow.find('.exclude-picker');\n var step = $option.data('step');\n var min = $option.data('min');\n self.applyRangeInputConstraints($newPicker, step, min);\n }\n\n if (valueType === 'combination_attributes') {\n var $newPicker = $excludeRow.find('.exclude-picker');\n self.loadCombinationAttributeGroups($newPicker);\n }\n\n var selectedMethod = $(this).val();\n self.updateMethodInfoPlaceholder($excludeRow.find('.exclude-header-row'), selectedMethod, blockType);\n\n self.serializeAllBlocks($excludeRow);\n });\n\n // Handle pattern input Enter key - adds pattern as tag\n this.$wrapper.on('keydown', '.pattern-input', function(e) {\n if (e.keyCode === 13) {\n e.preventDefault();\n var $btn = $(this).closest('.draft-tag').find('.btn-add-pattern');\n $btn.click();\n }\n });\n\n // Handle add pattern button click (in draft tag)\n this.$wrapper.on('click', '.draft-tag .btn-add-pattern', function(e) {\n e.preventDefault();\n e.stopPropagation();\n var $draftTag = $(this).closest('.draft-tag');\n var $picker = $draftTag.closest('.value-picker');\n var $row = $draftTag.closest('.group-include, .exclude-row');\n var $input = $draftTag.find('.pattern-input');\n var pattern = $.trim($input.val());\n\n if (pattern) {\n var caseSensitive = $draftTag.attr('data-case-sensitive') === '1';\n self.addPatternTag($picker, pattern, caseSensitive);\n\n $input.val('').focus();\n $draftTag.find('.pattern-match-count').removeClass('count-found count-zero').hide();\n $draftTag.find('.pattern-match-count .count-value').text('');\n\n self.serializeAllBlocks($row);\n }\n });\n\n // Handle pattern input live typing - update match count in draft tag\n this.$wrapper.on('input', '.pattern-input', function() {\n var $input = $(this);\n var $draftTag = $input.closest('.draft-tag');\n if (!$draftTag.length) return;\n\n var pattern = $.trim($input.val());\n\n if ($input.data('countTimeout')) {\n clearTimeout($input.data('countTimeout'));\n }\n\n var $matchCount = $draftTag.find('.pattern-match-count');\n\n if (!pattern) {\n $matchCount.removeClass('count-found count-zero').hide();\n $matchCount.find('.count-value').text('');\n var $group = $draftTag.closest('.selection-group');\n if ($group.length) {\n self.updateGroupTotalCount($group);\n }\n return;\n }\n\n var timeout = setTimeout(function() {\n var caseSensitive = $draftTag.attr('data-case-sensitive') === '1';\n self.updateDraftTagCount($draftTag, pattern, caseSensitive);\n }, 300);\n $input.data('countTimeout', timeout);\n });\n\n // Handle pattern tag remove\n this.$wrapper.on('click', '.pattern-tag .btn-remove-pattern', function(e) {\n e.preventDefault();\n e.stopPropagation();\n var $row = $(this).closest('.group-include, .exclude-row');\n $(this).closest('.pattern-tag').remove();\n self.serializeAllBlocks($row);\n });\n\n // Handle pattern tag case-sensitivity toggle\n this.$wrapper.on('click', '.pattern-tag .btn-toggle-case', function(e) {\n e.preventDefault();\n e.stopPropagation();\n var $tag = $(this).closest('.pattern-tag');\n var $btn = $(this);\n var trans = self.config.trans || {};\n var isDraftTag = $tag.hasClass('draft-tag');\n\n var isCaseSensitive = $tag.data('caseSensitive') === 1 || $tag.data('caseSensitive') === '1' || $tag.attr('data-case-sensitive') === '1';\n var newCaseSensitive = !isCaseSensitive;\n\n $tag.data('caseSensitive', newCaseSensitive ? 1 : 0);\n $tag.attr('data-case-sensitive', newCaseSensitive ? '1' : '0');\n $tag.toggleClass('case-sensitive', newCaseSensitive);\n\n $btn.find('.case-icon').text(newCaseSensitive ? 'Aa' : 'aa');\n var caseTitle = newCaseSensitive\n ? (trans.case_sensitive || 'Case sensitive - click to toggle')\n : (trans.case_insensitive || 'Case insensitive - click to toggle');\n $btn.attr('title', caseTitle);\n\n if (isDraftTag) {\n var pattern = $.trim($tag.find('.pattern-input').val());\n if (pattern) {\n self.updateDraftTagCount($tag, pattern, newCaseSensitive);\n }\n } else {\n var $row = $tag.closest('.group-include, .exclude-row');\n self.serializeAllBlocks($row);\n }\n });\n\n // Handle pattern match count click - show preview modal\n this.$wrapper.on('click', '.pattern-match-count', function(e) {\n e.preventDefault();\n e.stopPropagation();\n\n var $matchCount = $(this);\n var count = $matchCount.data('count');\n var pattern = $matchCount.data('pattern');\n var entityType = $matchCount.data('entityType');\n var caseSensitive = $matchCount.data('caseSensitive');\n\n if (!count || count <= 0 || !pattern) {\n return;\n }\n\n self.showPatternPreviewModal(pattern, entityType, caseSensitive, count);\n });\n\n // Handle pattern tag edit (click on tag text)\n this.$wrapper.on('click', '.pattern-tag .pattern-tag-text', function(e) {\n e.preventDefault();\n var $tag = $(this).closest('.pattern-tag');\n if ($tag.hasClass('editing')) return;\n\n var currentPattern = $tag.data('pattern');\n\n var $editInput = $('').val(currentPattern);\n var $saveBtn = $('');\n var $cancelBtn = $('');\n var $editActions = $('').append($saveBtn, $cancelBtn);\n\n $tag.addClass('editing').find('.pattern-tag-text').hide();\n $tag.find('.btn-remove-pattern').hide();\n $tag.prepend($editActions).prepend($editInput);\n $editInput.focus().select();\n\n $editInput.on('keydown', function(ev) {\n if (ev.keyCode === 13) {\n ev.preventDefault();\n $saveBtn.click();\n } else if (ev.keyCode === 27) {\n ev.preventDefault();\n $cancelBtn.click();\n }\n });\n });\n\n // Pattern edit - Save button\n this.$wrapper.on('click', '.pattern-tag .btn-pattern-save', function(e) {\n e.preventDefault();\n e.stopPropagation();\n var $tag = $(this).closest('.pattern-tag');\n var $editInput = $tag.find('.pattern-tag-edit');\n var currentPattern = $tag.data('pattern');\n var newPattern = $.trim($editInput.val());\n\n if (newPattern && newPattern !== currentPattern) {\n $tag.data('pattern', newPattern);\n $tag.find('.pattern-tag-text').text(newPattern);\n }\n $editInput.remove();\n $tag.find('.pattern-edit-actions').remove();\n $tag.removeClass('editing').find('.pattern-tag-text, .btn-remove-pattern').show();\n var $row = $tag.closest('.group-include, .exclude-row');\n self.serializeAllBlocks($row);\n });\n\n // Pattern edit - Cancel button\n this.$wrapper.on('click', '.pattern-tag .btn-pattern-cancel', function(e) {\n e.preventDefault();\n e.stopPropagation();\n var $tag = $(this).closest('.pattern-tag');\n $tag.find('.pattern-tag-edit').remove();\n $tag.find('.pattern-edit-actions').remove();\n $tag.removeClass('editing').find('.pattern-tag-text, .btn-remove-pattern').show();\n });\n\n // Handle mpr-info-wrapper tooltip with fixed positioning\n this.$wrapper.on('mouseenter', '.mpr-info-wrapper[data-details]', function() {\n var $wrapper = $(this);\n if ($wrapper.data('tooltip-active')) return;\n\n var content = $wrapper.attr('data-details');\n var tooltipClass = $wrapper.attr('data-tooltip-class') || '';\n var $tooltip = $('
', { class: 'mpr-tooltip mpr-tooltip-fixed ' + tooltipClass, html: content });\n\n $('body').append($tooltip);\n $wrapper.data('tooltip-active', true);\n\n var offset = $wrapper.offset();\n var triggerWidth = $wrapper.outerWidth();\n var tooltipWidth = $tooltip.outerWidth();\n var tooltipHeight = $tooltip.outerHeight();\n\n var left = offset.left + (triggerWidth / 2) - (tooltipWidth / 2);\n var top = offset.top - tooltipHeight - 10;\n\n if (left < 10) left = 10;\n if (left + tooltipWidth > $(window).width() - 10) {\n left = $(window).width() - tooltipWidth - 10;\n }\n\n $tooltip.css({\n position: 'fixed',\n left: left + 'px',\n top: (top - $(window).scrollTop()) + 'px'\n });\n\n $wrapper.data('tooltip-el', $tooltip);\n });\n\n this.$wrapper.on('mouseleave', '.mpr-info-wrapper[data-details]', function() {\n var $wrapper = $(this);\n var $tooltip = $wrapper.data('tooltip-el');\n if ($tooltip) {\n $tooltip.remove();\n }\n $wrapper.data('tooltip-active', false);\n $wrapper.data('tooltip-el', null);\n });\n\n // Handle numeric range input changes\n this.$wrapper.on('change', '.range-min-input, .range-max-input', function() {\n var $row = $(this).closest('.group-include, .exclude-row');\n self.serializeAllBlocks($row);\n });\n\n // Handle date range input changes\n this.$wrapper.on('change', '.date-from-input, .date-to-input', function() {\n var $row = $(this).closest('.group-include, .exclude-row');\n self.serializeAllBlocks($row);\n });\n\n // Handle select value changes\n this.$wrapper.on('change', '.select-value-input', function() {\n var $row = $(this).closest('.group-include, .exclude-row');\n self.serializeAllBlocks($row);\n });\n\n // Handle multi-range add button click\n this.$wrapper.on('click', '.btn-add-range', function(e) {\n e.preventDefault();\n var $picker = $(this).closest('.value-picker');\n var $row = $(this).closest('.group-include, .exclude-row');\n var $container = $picker.find('.multi-range-container');\n var $chipsContainer = $container.find('.multi-range-chips');\n var $minInput = $container.find('.range-min-input');\n var $maxInput = $container.find('.range-max-input');\n\n var minVal = $minInput.val().trim();\n var maxVal = $maxInput.val().trim();\n\n if (minVal === '' && maxVal === '') {\n return;\n }\n\n var step = parseFloat($minInput.attr('step')) || 0.01;\n var minAllowed = $minInput.attr('min');\n var hasMinConstraint = typeof minAllowed !== 'undefined' && minAllowed !== '';\n minAllowed = hasMinConstraint ? parseFloat(minAllowed) : null;\n\n var minNum = minVal !== '' ? parseFloat(minVal) : null;\n var maxNum = maxVal !== '' ? parseFloat(maxVal) : null;\n\n if (hasMinConstraint) {\n if (minNum !== null && minNum < minAllowed) {\n self.showRangeInputError($minInput, self.config.trans.min_value_error || 'Minimum value is ' + minAllowed);\n return;\n }\n if (maxNum !== null && maxNum < minAllowed) {\n self.showRangeInputError($maxInput, self.config.trans.min_value_error || 'Minimum value is ' + minAllowed);\n return;\n }\n }\n\n if (minNum !== null && maxNum !== null && minNum > maxNum) {\n self.showRangeInputError($minInput, self.config.trans.min_greater_than_max || 'Min cannot be greater than max');\n return;\n }\n\n var decimals = step < 1 ? String(step).split('.')[1].length : 0;\n if (minNum !== null) {\n if (step >= 1) {\n minNum = Math.round(minNum);\n } else {\n minNum = parseFloat(minNum.toFixed(decimals));\n }\n minVal = String(minNum);\n }\n if (maxNum !== null) {\n if (step >= 1) {\n maxNum = Math.round(maxNum);\n } else {\n maxNum = parseFloat(maxNum.toFixed(decimals));\n }\n maxVal = String(maxNum);\n }\n\n var chipText = '';\n if (minVal !== '' && maxVal !== '') {\n chipText = minVal + ' - ' + maxVal;\n } else if (minVal !== '') {\n chipText = '≥ ' + minVal;\n } else {\n chipText = '≤ ' + maxVal;\n }\n\n var $chip = $('', {\n class: 'range-chip',\n 'data-min': minVal,\n 'data-max': maxVal\n });\n $chip.append($('', { class: 'range-chip-text', text: chipText }));\n $chip.append($('';\n html += '';\n\n // Sort controls - options with data-entities attribute for entity-specific filtering\n html += '
';\n html += '';\n html += '';\n\n // View mode selector - Tree option always present, shown for categories\n html += '';\n html += '
'; // End sort-controls\n\n // Refine search\n html += '
';\n html += '';\n html += '';\n html += '';\n html += '
';\n\n // Filter toggle button\n html += '';\n\n // History button\n html += '';\n\n html += '
'; // End dropdown-actions\n html += '
'; // End dropdown-header\n\n // Filter panel\n html += '
';\n\n // Quick filters row (for products)\n html += '
';\n html += '';\n html += '';\n\n // Price range\n html += '
';\n html += '' + (trans.price || 'Price') + ':';\n html += '';\n html += '-';\n html += '';\n html += '
';\n\n html += '';\n html += '
';\n\n // Attribute/Feature filter toggles for products\n html += '
';\n html += ' ' + (trans.attributes || 'Attributes') + ':';\n html += '
';\n html += '
';\n html += '
';\n html += '
';\n html += '
';\n\n html += '
';\n html += ' ' + (trans.features || 'Features') + ':';\n html += '
';\n html += '
';\n html += '
';\n html += '
';\n html += '
';\n\n // Entity-specific filters: Categories\n html += '
';\n html += '
';\n html += '
';\n html += ' ' + (trans.product_count || 'Products') + ':';\n html += '';\n html += '-';\n html += '';\n html += '
';\n html += '
';\n html += ' ' + (trans.total_sales || 'Sales') + ':';\n html += '';\n html += '-';\n html += '';\n html += '
';\n html += '
';\n html += ' ' + (trans.turnover || 'Revenue') + ':';\n html += '';\n html += '-';\n html += '';\n html += '
';\n html += '';\n html += '
';\n html += '
';\n html += '
';\n html += ' ' + (trans.depth || 'Depth') + ':';\n html += '';\n html += '
';\n html += '';\n html += '';\n html += '';\n html += '';\n html += '
';\n html += '
';\n\n // Entity-specific filters: Manufacturers\n html += '
';\n html += '
';\n html += '
';\n html += ' ' + (trans.product_count || 'Products') + ':';\n html += '';\n html += '-';\n html += '';\n html += '
';\n html += '
';\n html += ' ' + (trans.total_sales || 'Sales') + ':';\n html += '';\n html += '-';\n html += '';\n html += '
';\n html += '
';\n html += ' ' + (trans.turnover || 'Revenue') + ':';\n html += '';\n html += '-';\n html += '';\n html += '
';\n html += '';\n html += '
';\n html += '
';\n html += '
';\n html += ' ' + (trans.date_added || 'Added') + ':';\n html += '';\n html += '-';\n html += '';\n html += '
';\n html += '
';\n html += ' ' + (trans.last_product || 'Last product') + ':';\n html += '';\n html += '-';\n html += '';\n html += '
';\n html += '';\n html += '
';\n html += '
';\n\n // Entity-specific filters: Suppliers\n html += '
';\n html += '
';\n html += '
';\n html += ' ' + (trans.product_count || 'Products') + ':';\n html += '';\n html += '-';\n html += '';\n html += '
';\n html += '
';\n html += ' ' + (trans.total_sales || 'Sales') + ':';\n html += '';\n html += '-';\n html += '';\n html += '
';\n html += '
';\n html += ' ' + (trans.turnover || 'Revenue') + ':';\n html += '';\n html += '-';\n html += '';\n html += '
';\n html += '';\n html += '
';\n html += '
';\n html += '
';\n html += ' ' + (trans.date_added || 'Added') + ':';\n html += '';\n html += '-';\n html += '';\n html += '
';\n html += '
';\n html += ' ' + (trans.last_product || 'Last product') + ':';\n html += '';\n html += '-';\n html += '';\n html += '
';\n html += '';\n html += '
';\n html += '
';\n\n // Entity-specific filters: Attributes\n html += '
';\n html += '
';\n html += '
';\n html += ' ' + (trans.product_count || 'Products') + ':';\n html += '';\n html += '-';\n html += '';\n html += '
';\n html += '
';\n html += ' ' + (trans.total_sales || 'Sales') + ':';\n html += '';\n html += '-';\n html += '';\n html += '
';\n html += '
';\n html += ' ' + (trans.turnover || 'Revenue') + ':';\n html += '';\n html += '-';\n html += '';\n html += '
';\n html += '
';\n html += '
';\n html += '
';\n html += ' ' + (trans.attribute_group || 'Group') + ':';\n html += '';\n html += '
';\n html += '';\n html += '';\n html += '
';\n html += '
';\n\n // Entity-specific filters: Features\n html += '
';\n html += '
';\n html += '
';\n html += ' ' + (trans.product_count || 'Products') + ':';\n html += '';\n html += '-';\n html += '';\n html += '
';\n html += '
';\n html += ' ' + (trans.total_sales || 'Sales') + ':';\n html += '';\n html += '-';\n html += '';\n html += '
';\n html += '
';\n html += ' ' + (trans.turnover || 'Revenue') + ':';\n html += '';\n html += '-';\n html += '';\n html += '
';\n html += '
';\n html += '
';\n html += '
';\n html += ' ' + (trans.feature_group || 'Group') + ':';\n html += '';\n html += '
';\n html += '';\n html += '';\n html += '
';\n html += '
';\n\n // Entity-specific filters: CMS Pages\n html += '
';\n html += '';\n html += '';\n html += '';\n html += '
';\n\n // Entity-specific filters: CMS Categories\n html += '
';\n html += '';\n html += '';\n html += '
';\n\n // Entity-specific filters: Countries\n html += '
';\n html += '';\n html += '';\n html += '';\n html += '
';\n html += ' ' + (trans.zone || 'Zone') + ':';\n html += '';\n html += '
';\n html += '';\n html += '
';\n\n html += '
'; // End filter-panel\n\n // Results header for list view (product columns)\n html += '
';\n html += '';\n html += '' + (trans.product || 'Product') + '';\n html += '' + (trans.price || 'Price') + '';\n html += '' + (trans.sale || 'Sale') + '';\n html += '' + (trans.stock || 'Stock') + '';\n html += '' + (trans.sold || 'Sold') + '';\n html += '
';\n\n // Results\n html += '
';\n\n // Footer - unified load more + actions\n html += '
';\n\n // Left side: load more\n html += '';\n\n // Right side: action buttons\n html += '';\n\n html += '
';\n\n html += '';\n\n this.$dropdown = $(html);\n $('body').append(this.$dropdown);\n },\n\n hideDropdown: function() {\n if (this.$dropdown) {\n this.$dropdown.removeClass('show');\n }\n this.activeGroup = null;\n },\n\n positionDropdown: function($input) {\n if (!this.$dropdown) return;\n\n var $picker = $input.closest('.value-picker');\n var $searchBox = $input.closest('.entity-search-box');\n\n // Get absolute positions (dropdown is appended to body)\n var searchBoxOffset = $searchBox.offset();\n var searchBoxHeight = $searchBox.outerHeight();\n var pickerOffset = $picker.offset();\n var pickerWidth = $picker.outerWidth();\n\n // Calculate position relative to document\n var dropdownTop = searchBoxOffset.top + searchBoxHeight + 4;\n var dropdownLeft = pickerOffset.left;\n var dropdownWidth = Math.max(pickerWidth, 400);\n\n // Ensure dropdown doesn't overflow the viewport horizontally\n var viewportWidth = $(window).width();\n if (dropdownLeft + dropdownWidth > viewportWidth - 10) {\n dropdownWidth = viewportWidth - dropdownLeft - 10;\n }\n\n // Ensure dropdown doesn't overflow viewport vertically\n var viewportHeight = $(window).height();\n var scrollTop = $(window).scrollTop();\n var maxHeight = viewportHeight - (dropdownTop - scrollTop) - 20;\n maxHeight = Math.max(maxHeight, 400);\n\n this.$dropdown.css({\n position: 'absolute',\n top: dropdownTop,\n left: dropdownLeft,\n width: dropdownWidth,\n maxHeight: maxHeight,\n zIndex: 10000\n });\n\n // Show the dropdown\n this.$dropdown.addClass('show');\n }\n };\n\n})(jQuery);\n","/**\n * Entity Selector - Search Module\n * AJAX search, results rendering, category tree, filters, search history\n * @partial _search.js\n */\n\n(function($) {\n 'use strict';\n\n window._EntitySelectorMixins = window._EntitySelectorMixins || {};\n\n window._EntitySelectorMixins.search = {\n\n // Category tree cache\n categoryTreeCache: null,\n\n /**\n * Perform AJAX search for entities\n */\n performSearch: function(appendMode) {\n var self = this;\n\n if (!this.activeGroup) return;\n\n this.isLoading = true;\n\n var searchEntity = this.activeGroup.searchEntity;\n\n // Build request data with sort and filter params\n var limit = appendMode && this.loadMoreCount ? this.loadMoreCount : 20;\n var requestData = {\n ajax: 1,\n action: 'searchTargetEntities',\n trait: 'EntitySelector',\n entity_type: searchEntity,\n q: this.searchQuery,\n limit: limit,\n offset: appendMode ? this.searchOffset : 0,\n sort_by: this.currentSort ? this.currentSort.field : 'name',\n sort_dir: this.currentSort ? this.currentSort.dir : 'ASC'\n };\n\n // Add product_selection_level if set\n if (this.config.productSelectionLevel && this.config.productSelectionLevel !== 'product') {\n requestData.product_selection_level = this.config.productSelectionLevel;\n }\n\n // Add refine query if present\n if (this.refineQuery) {\n requestData.refine = this.refineQuery;\n if (this.refineNegate) {\n requestData.refine_negate = 1;\n }\n }\n\n // Add product-specific filters\n if (searchEntity === 'products' && this.filters) {\n if (this.filters.inStock) {\n requestData.filter_in_stock = 1;\n }\n if (this.filters.discounted) {\n requestData.filter_discounted = 1;\n }\n if (this.filters.priceMin !== null && this.filters.priceMin !== '') {\n requestData.filter_price_min = this.filters.priceMin;\n }\n if (this.filters.priceMax !== null && this.filters.priceMax !== '') {\n requestData.filter_price_max = this.filters.priceMax;\n }\n if (this.filters.attributes && this.filters.attributes.length > 0) {\n requestData.filter_attributes = JSON.stringify(this.filters.attributes);\n }\n if (this.filters.features && this.filters.features.length > 0) {\n requestData.filter_features = JSON.stringify(this.filters.features);\n }\n }\n\n // Add entity-specific filters for non-product entities\n if (searchEntity !== 'products' && this.filters) {\n // Product count range (categories, manufacturers, suppliers, attributes, features)\n if (this.filters.productCountMin !== null && this.filters.productCountMin !== '') {\n requestData.filter_product_count_min = this.filters.productCountMin;\n }\n if (this.filters.productCountMax !== null && this.filters.productCountMax !== '') {\n requestData.filter_product_count_max = this.filters.productCountMax;\n }\n\n // Category-specific\n if (searchEntity === 'categories') {\n if (this.filters.depth) {\n requestData.filter_depth = this.filters.depth;\n }\n if (this.filters.hasProducts) {\n requestData.filter_has_products = 1;\n }\n if (this.filters.hasDescription) {\n requestData.filter_has_description = 1;\n }\n if (this.filters.hasImage) {\n requestData.filter_has_image = 1;\n }\n if (this.filters.salesMin !== null && this.filters.salesMin !== '') {\n requestData.filter_sales_min = this.filters.salesMin;\n }\n if (this.filters.salesMax !== null && this.filters.salesMax !== '') {\n requestData.filter_sales_max = this.filters.salesMax;\n }\n if (this.filters.turnoverMin !== null && this.filters.turnoverMin !== '') {\n requestData.filter_turnover_min = this.filters.turnoverMin;\n }\n if (this.filters.turnoverMax !== null && this.filters.turnoverMax !== '') {\n requestData.filter_turnover_max = this.filters.turnoverMax;\n }\n if (this.filters.activeOnly) {\n requestData.filter_active = 1;\n }\n }\n\n // Manufacturer-specific\n if (searchEntity === 'manufacturers') {\n if (this.filters.salesMin !== null && this.filters.salesMin !== '') {\n requestData.filter_sales_min = this.filters.salesMin;\n }\n if (this.filters.salesMax !== null && this.filters.salesMax !== '') {\n requestData.filter_sales_max = this.filters.salesMax;\n }\n if (this.filters.turnoverMin !== null && this.filters.turnoverMin !== '') {\n requestData.filter_turnover_min = this.filters.turnoverMin;\n }\n if (this.filters.turnoverMax !== null && this.filters.turnoverMax !== '') {\n requestData.filter_turnover_max = this.filters.turnoverMax;\n }\n if (this.filters.dateAddFrom) {\n requestData.filter_date_add_from = this.filters.dateAddFrom;\n }\n if (this.filters.dateAddTo) {\n requestData.filter_date_add_to = this.filters.dateAddTo;\n }\n if (this.filters.lastProductFrom) {\n requestData.filter_last_product_from = this.filters.lastProductFrom;\n }\n if (this.filters.lastProductTo) {\n requestData.filter_last_product_to = this.filters.lastProductTo;\n }\n if (this.filters.activeOnly) {\n requestData.filter_active = 1;\n }\n }\n\n // Supplier-specific\n if (searchEntity === 'suppliers') {\n if (this.filters.salesMin !== null && this.filters.salesMin !== '') {\n requestData.filter_sales_min = this.filters.salesMin;\n }\n if (this.filters.salesMax !== null && this.filters.salesMax !== '') {\n requestData.filter_sales_max = this.filters.salesMax;\n }\n if (this.filters.turnoverMin !== null && this.filters.turnoverMin !== '') {\n requestData.filter_turnover_min = this.filters.turnoverMin;\n }\n if (this.filters.turnoverMax !== null && this.filters.turnoverMax !== '') {\n requestData.filter_turnover_max = this.filters.turnoverMax;\n }\n if (this.filters.dateAddFrom) {\n requestData.filter_date_add_from = this.filters.dateAddFrom;\n }\n if (this.filters.dateAddTo) {\n requestData.filter_date_add_to = this.filters.dateAddTo;\n }\n if (this.filters.lastProductFrom) {\n requestData.filter_last_product_from = this.filters.lastProductFrom;\n }\n if (this.filters.lastProductTo) {\n requestData.filter_last_product_to = this.filters.lastProductTo;\n }\n if (this.filters.activeOnly) {\n requestData.filter_active = 1;\n }\n }\n\n // Attribute-specific\n if (searchEntity === 'attributes') {\n if (this.filters.salesMin !== null && this.filters.salesMin !== '') {\n requestData.filter_sales_min = this.filters.salesMin;\n }\n if (this.filters.salesMax !== null && this.filters.salesMax !== '') {\n requestData.filter_sales_max = this.filters.salesMax;\n }\n if (this.filters.turnoverMin !== null && this.filters.turnoverMin !== '') {\n requestData.filter_turnover_min = this.filters.turnoverMin;\n }\n if (this.filters.turnoverMax !== null && this.filters.turnoverMax !== '') {\n requestData.filter_turnover_max = this.filters.turnoverMax;\n }\n if (this.filters.attributeGroup) {\n requestData.filter_attribute_group = this.filters.attributeGroup;\n }\n if (this.filters.isColor) {\n requestData.filter_is_color = 1;\n }\n }\n\n // Feature-specific\n if (searchEntity === 'features') {\n if (this.filters.salesMin !== null && this.filters.salesMin !== '') {\n requestData.filter_sales_min = this.filters.salesMin;\n }\n if (this.filters.salesMax !== null && this.filters.salesMax !== '') {\n requestData.filter_sales_max = this.filters.salesMax;\n }\n if (this.filters.turnoverMin !== null && this.filters.turnoverMin !== '') {\n requestData.filter_turnover_min = this.filters.turnoverMin;\n }\n if (this.filters.turnoverMax !== null && this.filters.turnoverMax !== '') {\n requestData.filter_turnover_max = this.filters.turnoverMax;\n }\n if (this.filters.featureGroup) {\n requestData.filter_feature_group = this.filters.featureGroup;\n }\n if (this.filters.isCustom) {\n requestData.filter_is_custom = 1;\n }\n }\n\n // CMS-specific\n if (searchEntity === 'cms') {\n if (this.filters.activeOnly) {\n requestData.filter_active = 1;\n }\n if (this.filters.indexable) {\n requestData.filter_indexable = 1;\n }\n }\n\n // CMS Categories-specific\n if (searchEntity === 'cms_categories') {\n if (this.filters.activeOnly) {\n requestData.filter_active = 1;\n }\n }\n\n // Countries-specific\n if (searchEntity === 'countries') {\n if (this.filters.activeOnly) {\n requestData.filter_active = 1;\n }\n if (this.filters.hasHolidays) {\n requestData.filter_has_holidays = 1;\n }\n if (this.filters.containsStates) {\n requestData.filter_contains_states = 1;\n }\n if (this.filters.zone) {\n requestData.filter_zone = this.filters.zone;\n }\n }\n }\n\n $.ajax({\n url: this.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: requestData,\n success: function(response) {\n self.isLoading = false;\n\n if (!response.success) return;\n\n // Save to search history if query is not empty and has results\n if (self.searchQuery && self.searchQuery.length >= 2 && response.total > 0) {\n self.addToSearchHistory(searchEntity, self.searchQuery);\n }\n\n if (appendMode) {\n self.searchResults = self.searchResults.concat(response.results || []);\n } else {\n self.searchResults = response.results || [];\n }\n self.searchTotal = response.total || 0;\n self.searchOffset = appendMode ? self.searchOffset + (response.results || []).length : (response.results || []).length;\n\n self.renderSearchResults(appendMode);\n self.$dropdown.addClass('show');\n },\n error: function() {\n self.isLoading = false;\n }\n });\n },\n\n /**\n * Render search results in the dropdown\n */\n renderSearchResults: function(appendMode) {\n var self = this;\n var trans = this.config.trans || {};\n var $container = this.$dropdown.find('.dropdown-results');\n\n // Get selected IDs from current picker (to mark as selected)\n // and hidden IDs from sibling exclude pickers with same entity type (to hide completely)\n var selectedIds = [];\n var hiddenIds = [];\n if (this.activeGroup) {\n var $block = this.$wrapper.find('.target-block[data-block-type=\"' + this.activeGroup.blockType + '\"]');\n var $group = $block.find('.selection-group[data-group-index=\"' + this.activeGroup.groupIndex + '\"]');\n var currentSearchEntity = this.activeGroup.searchEntity;\n var currentExcludeIndex = this.activeGroup.excludeIndex;\n\n if (this.activeGroup.section === 'include') {\n // For include section, just get current picker's selections\n var $picker = $group.find('.include-picker');\n $picker.find('.entity-chip').each(function() {\n selectedIds.push(String($(this).data('id')));\n });\n } else {\n // For exclude section, get current picker's selections AND\n // collect IDs from sibling exclude rows with same entity type to hide\n var $currentExcludeRow = $group.find('.exclude-row[data-exclude-index=\"' + currentExcludeIndex + '\"]');\n var $currentPicker = $currentExcludeRow.find('.exclude-picker');\n\n // Get selected IDs from current exclude row\n $currentPicker.find('.entity-chip').each(function() {\n selectedIds.push(String($(this).data('id')));\n });\n\n // Get hidden IDs from OTHER exclude rows with the same entity type\n $group.find('.exclude-row').each(function() {\n var $row = $(this);\n var rowIndex = parseInt($row.data('excludeIndex'), 10);\n\n // Skip current exclude row\n if (rowIndex === currentExcludeIndex) return;\n\n var $picker = $row.find('.exclude-picker');\n var rowEntityType = $picker.attr('data-search-entity') || self.activeGroup.blockType;\n\n // Only collect if same entity type\n if (rowEntityType === currentSearchEntity) {\n $picker.find('.entity-chip').each(function() {\n hiddenIds.push(String($(this).data('id')));\n });\n }\n });\n }\n }\n\n // Check if this is a product search\n var isProductSearch = this.activeGroup && this.activeGroup.searchEntity === 'products';\n var isListView = this.viewMode === 'list';\n\n // Show/hide results header for products in list view\n this.$dropdown.find('.results-header').toggle(isProductSearch && isListView);\n\n // Build HTML - filter out items that are hidden (selected in sibling exclude rows)\n var visibleResults = this.searchResults.filter(function(item) {\n return hiddenIds.indexOf(String(item.id)) === -1;\n });\n\n // Update count (show visible count and total, noting hidden items if any)\n var hiddenCount = this.searchResults.length - visibleResults.length;\n var countText = visibleResults.length + ' / ' + this.searchTotal + ' results';\n if (hiddenCount > 0) {\n countText += ' (' + hiddenCount + ' hidden)';\n }\n this.$dropdown.find('.results-count').text(countText);\n\n var html = '';\n if (visibleResults.length === 0 && !appendMode) {\n html = '
' + (trans.no_results || 'No results found') + '
';\n } else {\n visibleResults.forEach(function(item) {\n var isSelected = selectedIds.indexOf(String(item.id)) !== -1;\n var itemClass = 'dropdown-item' + (isSelected ? ' selected' : '');\n if (item.type === 'product') itemClass += ' result-item-product';\n if (item.is_combination) itemClass += ' is-combination';\n if (item.is_parent) itemClass += ' is-parent-product';\n\n html += '
';\n } else if (item.image) {\n html += '
\"\"
';\n } else {\n // Entity-specific icons\n var iconClass = 'icon-cube'; // default\n if (searchEntity === 'categories') iconClass = 'icon-folder';\n else if (searchEntity === 'manufacturers') iconClass = 'icon-building';\n else if (searchEntity === 'suppliers') iconClass = 'icon-truck';\n else if (searchEntity === 'attributes') iconClass = 'icon-paint-brush';\n else if (searchEntity === 'features') iconClass = 'icon-list-ul';\n else if (searchEntity === 'cms') iconClass = 'icon-file-text-o';\n else if (searchEntity === 'cms_categories') iconClass = 'icon-folder-o';\n html += '
';\n }\n\n html += '
';\n html += '
' + self.escapeHtml(item.name) + '
';\n if (item.subtitle) {\n // Split multi-line subtitles into separate divs for styling\n var subtitleLines = item.subtitle.split('\\n');\n html += '
';\n subtitleLines.forEach(function(line, idx) {\n var lineClass = idx === 0 ? 'subtitle-line subtitle-line-primary' : 'subtitle-line subtitle-line-secondary';\n html += '
' + self.escapeHtml(line) + '
';\n });\n html += '
';\n }\n html += '
';\n\n // Add product-specific columns (price, sale price, stock, sold)\n if (item.type === 'product') {\n if (isListView) {\n // List view: full columns\n // Regular price\n html += '
';\n html += '' + (item.regular_price_formatted || item.price_formatted || '') + '';\n html += '
';\n\n // Sale price (only if discounted)\n if (item.has_discount) {\n html += '
';\n html += '' + (item.price_formatted || '') + '';\n html += '
';\n } else {\n html += '
';\n }\n\n // Stock column\n var stockClass = item.stock_status === 'out_of_stock' ? 'stock-out' :\n (item.stock_status === 'low_stock' ? 'stock-low' : 'stock-ok');\n html += '
';\n html += '' + (item.stock_qty !== undefined ? item.stock_qty : '') + '';\n html += '
';\n\n // Sales column\n html += '
';\n html += '' + (item.sales_qty !== undefined ? item.sales_qty : '0') + '';\n html += '
';\n } else {\n // Grid view: compact info line\n var gridStockClass = item.stock_status === 'out_of_stock' ? 'stock-out' :\n (item.stock_status === 'low_stock' ? 'stock-low' : '');\n html += '
';\n html += '' + (item.price_formatted || '') + '';\n if (item.stock_qty !== undefined) {\n html += '' + item.stock_qty + ' qty';\n }\n if (item.has_discount) {\n html += '-' + (item.discount_percent || '') + '%';\n }\n html += '
';\n }\n }\n\n html += '';\n });\n }\n\n if (appendMode) {\n $container.append(html);\n } else {\n $container.html(html);\n }\n\n // Show/hide load more controls and update remaining count\n var hasMore = this.searchResults.length < this.searchTotal;\n var $loadMoreControls = this.$dropdown.find('.load-more-controls');\n $loadMoreControls.toggle(hasMore);\n\n if (hasMore) {\n var remaining = this.searchTotal - this.searchResults.length;\n $loadMoreControls.find('.remaining-count').text(remaining);\n\n // Update \"All\" option in dropdown\n var $select = $loadMoreControls.find('.load-more-select');\n var $allOption = $select.find('option[data-all=\"true\"]');\n if ($allOption.length) {\n $allOption.val(remaining).text((trans.all || 'All') + ' (' + remaining + ')');\n } else {\n $select.find('option:last').after('');\n }\n }\n\n // Ensure dropdown-actions are visible and history button is deactivated\n this.$dropdown.find('.dropdown-actions').show();\n this.$dropdown.find('.btn-show-history').removeClass('active');\n\n // Disable history button if no search history for current entity type\n var entityType = this.activeGroup ? this.activeGroup.searchEntity : null;\n var hasHistory = entityType && this.getSearchHistory(entityType).length > 0;\n this.$dropdown.find('.btn-show-history').prop('disabled', !hasHistory);\n },\n\n // NOTE: Tree methods (loadCategoryTree, renderCategoryTree, filterCategoryTree,\n // findTreeDescendants, findTreeAncestors, updateSelectChildrenButtons) are\n // defined in _tree.js which is merged later and takes precedence.\n\n // =========================================================================\n // Search History\n // =========================================================================\n\n loadSearchHistory: function() {\n try {\n var stored = localStorage.getItem(this.searchHistoryKey);\n this.searchHistory = stored ? JSON.parse(stored) : {};\n } catch (e) {\n this.searchHistory = {};\n }\n },\n\n saveSearchHistory: function() {\n try {\n localStorage.setItem(this.searchHistoryKey, JSON.stringify(this.searchHistory));\n } catch (e) {\n // localStorage might be full or unavailable\n }\n },\n\n addToSearchHistory: function(entityType, query) {\n if (!query || query.length < 2) return;\n\n if (!this.searchHistory[entityType]) {\n this.searchHistory[entityType] = [];\n }\n\n var history = this.searchHistory[entityType];\n\n // Remove if already exists (will re-add at top)\n var existingIndex = history.indexOf(query);\n if (existingIndex !== -1) {\n history.splice(existingIndex, 1);\n }\n\n // Add at beginning\n history.unshift(query);\n\n // Trim to max\n if (history.length > this.searchHistoryMax) {\n history = history.slice(0, this.searchHistoryMax);\n }\n\n this.searchHistory[entityType] = history;\n this.saveSearchHistory();\n },\n\n removeFromSearchHistory: function(entityType, query) {\n if (!this.searchHistory[entityType]) return;\n\n var index = this.searchHistory[entityType].indexOf(query);\n if (index !== -1) {\n this.searchHistory[entityType].splice(index, 1);\n this.saveSearchHistory();\n }\n },\n\n getSearchHistory: function(entityType) {\n return this.searchHistory[entityType] || [];\n },\n\n showSearchHistory: function(entityType) {\n var history = this.getSearchHistory(entityType);\n var trans = this.config.trans || {};\n var $container = this.$dropdown.find('.dropdown-results');\n\n // Update header\n this.$dropdown.find('.results-count').text(trans.recent_searches || 'Recent searches');\n\n // Hide filters, actions, and results header for history view\n this.$dropdown.find('.dropdown-actions').hide();\n this.$dropdown.find('.filter-panel').removeClass('show');\n this.$dropdown.find('.btn-toggle-filters').removeClass('active');\n this.$dropdown.find('.results-header').hide();\n\n if (!history.length) {\n // No history - just do a regular search\n this.performSearch();\n return;\n }\n\n // Build history items\n var html = '
';\n for (var i = 0; i < history.length; i++) {\n var query = history[i];\n html += '
';\n html += '';\n html += '' + this.escapeHtml(query) + '';\n html += '';\n html += '
';\n }\n html += '
';\n\n $container.html(html);\n this.$dropdown.addClass('show');\n },\n\n // =========================================================================\n // Filter Methods\n // =========================================================================\n\n refreshSearch: function() {\n // In tree view mode, re-filter the tree instead of doing a flat AJAX search\n if (this.viewMode === 'tree') {\n this.filterCategoryTree(this.searchQuery || '');\n return;\n }\n\n this.searchOffset = 0;\n this.loadMoreCount = 20;\n // Reset load more select to default\n if (this.$dropdown) {\n this.$dropdown.find('.load-more-select').val('20');\n // Remove the dynamic \"All\" option\n this.$dropdown.find('.load-more-select option[data-all=\"true\"]').remove();\n }\n this.performSearch(false);\n },\n\n clearFilters: function() {\n this.refineQuery = '';\n this.refineNegate = false;\n this.filters = {\n inStock: false,\n discounted: false,\n priceMin: null,\n priceMax: null,\n attributes: [],\n features: [],\n // Entity-specific filters\n productCountMin: null,\n productCountMax: null,\n salesMin: null,\n salesMax: null,\n turnoverMin: null,\n turnoverMax: null,\n depth: null,\n hasProducts: false,\n hasDescription: false,\n hasImage: false,\n activeOnly: true,\n attributeGroup: null,\n featureGroup: null,\n dateAddFrom: null,\n dateAddTo: null,\n lastProductFrom: null,\n lastProductTo: null,\n // Country-specific filters\n hasHolidays: false,\n containsStates: false,\n zone: null\n };\n\n if (this.$dropdown) {\n var trans = this.config.trans || {};\n this.$dropdown.find('.refine-input').val('').attr('placeholder', trans.refine_short || 'Refine...');\n this.$dropdown.find('.btn-clear-refine').hide();\n this.$dropdown.find('.btn-refine-negate').removeClass('active');\n this.$dropdown.find('.filter-in-stock').prop('checked', false);\n this.$dropdown.find('.filter-discounted').prop('checked', false);\n this.$dropdown.find('.filter-price-min').val('');\n this.$dropdown.find('.filter-price-max').val('');\n this.$dropdown.find('.filter-attr-chip').removeClass('active');\n this.$dropdown.find('.filter-feat-chip').removeClass('active');\n this.$dropdown.find('.filter-group-toggle').removeClass('active has-selection');\n this.$dropdown.find('.filter-row-values').hide();\n\n // Clear entity-specific filter inputs\n this.$dropdown.find('.filter-product-count-min, .filter-product-count-max').val('');\n this.$dropdown.find('.filter-sales-min, .filter-sales-max').val('');\n this.$dropdown.find('.filter-turnover-min, .filter-turnover-max').val('');\n this.$dropdown.find('.filter-date-add-from, .filter-date-add-to').val('');\n this.$dropdown.find('.filter-last-product-from, .filter-last-product-to').val('');\n this.$dropdown.find('.filter-depth-select').val('');\n this.$dropdown.find('.filter-has-products').prop('checked', false);\n this.$dropdown.find('.filter-has-description').prop('checked', false);\n this.$dropdown.find('.filter-has-image').prop('checked', false);\n this.$dropdown.find('.filter-active-only').prop('checked', true);\n this.$dropdown.find('.filter-attribute-group-select, .filter-feature-group-select').val('');\n // Country filters\n this.$dropdown.find('.filter-has-holidays').prop('checked', false);\n this.$dropdown.find('.filter-contains-states').prop('checked', false);\n this.$dropdown.find('.filter-zone-select').val('');\n }\n\n this.refreshSearch();\n },\n\n // Reset filters without triggering a search (used when switching entity types)\n resetFiltersWithoutSearch: function() {\n this.refineQuery = '';\n this.refineNegate = false;\n this.filters = {\n inStock: false,\n discounted: false,\n priceMin: null,\n priceMax: null,\n attributes: [],\n features: [],\n productCountMin: null,\n productCountMax: null,\n salesMin: null,\n salesMax: null,\n turnoverMin: null,\n turnoverMax: null,\n depth: null,\n hasProducts: false,\n hasDescription: false,\n hasImage: false,\n activeOnly: true,\n attributeGroup: null,\n featureGroup: null,\n dateAddFrom: null,\n dateAddTo: null,\n lastProductFrom: null,\n lastProductTo: null,\n // Country-specific filters\n hasHolidays: false,\n containsStates: false,\n zone: null\n };\n\n if (this.$dropdown) {\n var trans = this.config.trans || {};\n this.$dropdown.find('.refine-input').val('').attr('placeholder', trans.refine_short || 'Refine...');\n this.$dropdown.find('.btn-clear-refine').hide();\n this.$dropdown.find('.btn-refine-negate').removeClass('active');\n this.$dropdown.find('.filter-in-stock').prop('checked', false);\n this.$dropdown.find('.filter-discounted').prop('checked', false);\n this.$dropdown.find('.filter-price-min').val('');\n this.$dropdown.find('.filter-price-max').val('');\n this.$dropdown.find('.filter-attr-chip').removeClass('active');\n this.$dropdown.find('.filter-feat-chip').removeClass('active');\n this.$dropdown.find('.filter-group-toggle').removeClass('active has-selection');\n this.$dropdown.find('.filter-row-values').hide();\n this.$dropdown.find('.filter-product-count-min, .filter-product-count-max').val('');\n this.$dropdown.find('.filter-sales-min, .filter-sales-max').val('');\n this.$dropdown.find('.filter-turnover-min, .filter-turnover-max').val('');\n this.$dropdown.find('.filter-date-add-from, .filter-date-add-to').val('');\n this.$dropdown.find('.filter-last-product-from, .filter-last-product-to').val('');\n this.$dropdown.find('.filter-depth-select').val('');\n this.$dropdown.find('.filter-has-products').prop('checked', false);\n this.$dropdown.find('.filter-has-description').prop('checked', false);\n this.$dropdown.find('.filter-has-image').prop('checked', false);\n this.$dropdown.find('.filter-active-only').prop('checked', true);\n this.$dropdown.find('.filter-attribute-group-select, .filter-feature-group-select').val('');\n // Country filters\n this.$dropdown.find('.filter-has-holidays').prop('checked', false);\n this.$dropdown.find('.filter-contains-states').prop('checked', false);\n this.$dropdown.find('.filter-zone-select').val('');\n }\n // Note: Does NOT call refreshSearch() - caller handles search/load\n },\n\n updateFilterPanelForEntity: function(entityType) {\n if (!this.$dropdown) {\n return;\n }\n\n var $panel = this.$dropdown.find('.filter-panel');\n\n // Hide all filter rows first\n $panel.find('.filter-row').hide();\n\n // Show/hide tree view option based on entity type\n var $treeOption = this.$dropdown.find('.view-mode-select option.tree-view-option');\n if (entityType === 'categories' || entityType === 'cms_categories') {\n $treeOption.prop('disabled', false).prop('hidden', false);\n // Auto-switch to tree view for categories\n if (this.viewMode !== 'tree') {\n this.viewMode = 'tree';\n this.$dropdown.find('.view-mode-select').val('tree');\n this.$dropdown.removeClass('view-list view-cols-2 view-cols-3 view-cols-4 view-cols-5 view-cols-6 view-cols-7 view-cols-8').addClass('view-tree');\n this.loadCategoryTree();\n } else {\n this.loadCategoryTree();\n }\n } else {\n $treeOption.prop('disabled', true).prop('hidden', true);\n // If currently in tree mode, switch back to list\n if (this.viewMode === 'tree') {\n this.viewMode = 'list';\n this.$dropdown.find('.view-mode-select').val('list');\n this.$dropdown.removeClass('view-tree').addClass('view-list');\n }\n }\n\n // Show entity-specific filter row (prepare visibility, but don't auto-expand panel)\n if (entityType === 'products') {\n // Prepare the correct rows to be visible when panel is shown\n $panel.find('.filter-row-quick').show();\n // Show attribute/feature rows if we have cached data\n if (this.filterableData) {\n if (this.filterableData.attributes && this.filterableData.attributes.length > 0) {\n this.$dropdown.find('.filter-row-attributes').show();\n }\n if (this.filterableData.features && this.filterableData.features.length > 0) {\n this.$dropdown.find('.filter-row-features').show();\n }\n }\n } else if (entityType === 'categories') {\n $panel.find('.filter-row-entity-categories').show();\n } else if (entityType === 'manufacturers') {\n $panel.find('.filter-row-entity-manufacturers').show();\n } else if (entityType === 'suppliers') {\n $panel.find('.filter-row-entity-suppliers').show();\n } else if (entityType === 'attributes') {\n $panel.find('.filter-row-entity-attributes').show();\n this.loadAttributeGroups();\n } else if (entityType === 'features') {\n $panel.find('.filter-row-entity-features').show();\n } else if (entityType === 'cms') {\n $panel.find('.filter-row-entity-cms').show();\n } else if (entityType === 'cms_categories') {\n $panel.find('.filter-row-entity-cms-categories').show();\n } else if (entityType === 'countries') {\n $panel.find('.filter-row-entity-countries').show();\n this.loadZonesForCountryFilter();\n }\n },\n\n loadAttributeGroups: function() {\n var self = this;\n var $select = this.$dropdown.find('.filter-attribute-group-select');\n\n // Already loaded?\n if ($select.find('option').length > 1) return;\n\n $.ajax({\n url: this.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'getAttributeGroups',\n trait: 'EntitySelector'\n },\n success: function(response) {\n if (response.success && response.groups) {\n $.each(response.groups, function(i, group) {\n $select.append('');\n });\n }\n }\n });\n },\n\n loadFeatureGroups: function() {\n var self = this;\n var $select = this.$dropdown.find('.filter-feature-group-select');\n\n // Already loaded?\n if ($select.find('option').length > 1) return;\n\n $.ajax({\n url: this.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'getFeatureGroups',\n trait: 'EntitySelector'\n },\n success: function(response) {\n if (response.success && response.groups) {\n $.each(response.groups, function(i, group) {\n $select.append('');\n });\n }\n }\n });\n }\n };\n\n})(jQuery);\n","/**\n * Entity Selector - Filters Module\n * Filter panel, filter state management\n * @partial _filters.js\n *\n * EXTRACTION SOURCE: assets/js/admin/entity-selector.js\n * Lines: 6605-6758 (filter methods)\n *\n * Contains:\n * - clearFilters() - Reset all filters\n * - resetFiltersWithoutSearch() - Reset without triggering search\n * - updateFilterPanelForEntity() - Show/hide filters based on entity type\n * - loadFilterableData() - Load attributes/features for filter panel\n * - renderFilterDropdowns() - Render attribute/feature group toggles\n * - showFilterGroupValues() - Show values for a filter group\n * - hideFilterGroupValues() - Hide filter values row\n * - updateFilterToggleStates() - Update toggle states based on selections\n */\n\n(function($) {\n 'use strict';\n\n window._EntitySelectorMixins = window._EntitySelectorMixins || {};\n\n window._EntitySelectorMixins.filters = {\n\n clearFilters: function() {\n this.refineQuery = '';\n this.refineNegate = false;\n this.filters = {\n inStock: false,\n discounted: false,\n priceMin: null,\n priceMax: null,\n attributes: [],\n features: [],\n productCountMin: null,\n productCountMax: null,\n salesMin: null,\n salesMax: null,\n turnoverMin: null,\n turnoverMax: null,\n depth: null,\n hasProducts: false,\n hasDescription: false,\n hasImage: false,\n activeOnly: true,\n attributeGroup: null,\n featureGroup: null,\n dateAddFrom: null,\n dateAddTo: null,\n lastProductFrom: null,\n lastProductTo: null,\n // Country-specific filters\n hasHolidays: false,\n containsStates: false,\n zone: null\n };\n\n if (this.$dropdown) {\n var trans = this.config.trans || {};\n this.$dropdown.find('.refine-input').val('');\n this.$dropdown.find('.btn-refine-negate').removeClass('active');\n this.$dropdown.find('.filter-in-stock').prop('checked', false);\n this.$dropdown.find('.filter-discounted').prop('checked', false);\n this.$dropdown.find('.filter-price-min, .filter-price-max').val('');\n this.$dropdown.find('.filter-attr-chip, .filter-feat-chip').removeClass('active');\n this.$dropdown.find('.filter-product-count-min, .filter-product-count-max').val('');\n this.$dropdown.find('.filter-sales-min, .filter-sales-max').val('');\n this.$dropdown.find('.filter-depth-select').val('');\n this.$dropdown.find('.filter-has-products').prop('checked', false);\n this.$dropdown.find('.filter-active-only').prop('checked', true);\n // Country filters\n this.$dropdown.find('.filter-has-holidays').prop('checked', false);\n this.$dropdown.find('.filter-contains-states').prop('checked', false);\n this.$dropdown.find('.filter-zone-select').val('');\n }\n\n this.refreshSearch();\n },\n\n resetFiltersWithoutSearch: function() {\n // Same as clearFilters but doesn't trigger search\n // Used when switching entity types\n this.refineQuery = '';\n this.refineNegate = false;\n this.filters = {\n inStock: false,\n discounted: false,\n priceMin: null,\n priceMax: null,\n attributes: [],\n features: [],\n productCountMin: null,\n productCountMax: null,\n salesMin: null,\n salesMax: null,\n turnoverMin: null,\n turnoverMax: null,\n depth: null,\n hasProducts: false,\n hasDescription: false,\n hasImage: false,\n activeOnly: true,\n attributeGroup: null,\n featureGroup: null,\n dateAddFrom: null,\n dateAddTo: null,\n lastProductFrom: null,\n lastProductTo: null,\n // Country-specific filters\n hasHolidays: false,\n containsStates: false,\n zone: null\n };\n },\n\n updateFilterPanelForEntity: function(entityType) {\n if (!this.$dropdown) {\n return;\n }\n\n var $panel = this.$dropdown.find('.filter-panel');\n\n // Hide all entity-specific filter rows\n $panel.find('.filter-row').hide();\n\n // Show filters for current entity type\n $panel.find('.filter-row[data-entity=\"' + entityType + '\"]').show();\n $panel.find('.filter-row-entity-' + entityType.replace('_', '-')).show();\n\n // Show/hide tree view option based on entity type\n var isCategory = (entityType === 'categories' || entityType === 'cms_categories');\n this.$dropdown.find('.tree-view-option').toggle(isCategory);\n\n // Default to tree view for categories (only if currently on list mode)\n if (isCategory && this.viewMode === 'list') {\n this.viewMode = 'tree';\n this.$dropdown.find('.view-mode-select').val('tree');\n this.$dropdown.removeClass('view-list view-cols-2 view-cols-3 view-cols-4 view-cols-5 view-cols-6 view-cols-7 view-cols-8').addClass('view-tree');\n } else if (!isCategory && this.viewMode === 'tree') {\n // If switching away from categories while in tree mode, switch to list\n this.viewMode = 'list';\n this.$dropdown.find('.view-mode-select').val('list');\n this.$dropdown.removeClass('view-tree view-cols-2 view-cols-3 view-cols-4 view-cols-5 view-cols-6 view-cols-7 view-cols-8').addClass('view-list');\n }\n\n // Load zones for countries filter\n if (entityType === 'countries') {\n this.loadZonesForCountryFilter();\n }\n\n // Update sort options for entity type\n this.updateSortOptionsForEntity(entityType);\n },\n\n /**\n * Show/hide sort options based on entity type\n * Options with data-entities attribute are only shown for matching entities\n */\n updateSortOptionsForEntity: function(entityType) {\n if (!this.$dropdown) {\n return;\n }\n\n var $select = this.$dropdown.find('.sort-field-select');\n var currentValue = $select.val();\n var hasCurrentOption = false;\n\n $select.find('option').each(function() {\n var $option = $(this);\n var entities = $option.data('entities');\n\n // Options without data-entities are universal (always shown)\n if (!entities) {\n $option.show();\n if ($option.val() === currentValue) {\n hasCurrentOption = true;\n }\n return;\n }\n\n // Check if this entity type is in the allowed list\n var allowedEntities = entities.split(',');\n var isAllowed = allowedEntities.indexOf(entityType) !== -1;\n\n $option.toggle(isAllowed);\n\n if (isAllowed && $option.val() === currentValue) {\n hasCurrentOption = true;\n }\n });\n\n // If current sort field is not available for this entity, reset to 'name'\n if (!hasCurrentOption) {\n $select.val('name');\n this.currentSort.field = 'name';\n }\n },\n\n loadFilterableData: function() {\n var self = this;\n\n if (this.filterableData) {\n this.renderFilterDropdowns();\n return;\n }\n\n $.ajax({\n url: this.config.ajaxUrl,\n type: 'POST',\n data: {\n ajax: 1,\n action: 'getTargetFilterableAttributes',\n trait: 'EntitySelector'\n },\n dataType: 'json',\n success: function(response) {\n if (response.success && response.data) {\n self.filterableData = response.data;\n self.renderFilterDropdowns();\n }\n }\n });\n },\n\n renderFilterDropdowns: function() {\n if (!this.$dropdown || !this.filterableData) return;\n\n var self = this;\n var previewLabel = self.config.trans && self.config.trans.preview || 'Preview';\n\n // Render attribute group toggle buttons\n var $attrContainer = this.$dropdown.find('.filter-attributes-container');\n $attrContainer.empty();\n\n if (this.filterableData.attributes && this.filterableData.attributes.length > 0) {\n this.filterableData.attributes.forEach(function(group) {\n var html = '';\n html += '';\n html += '';\n html += '';\n $attrContainer.append(html);\n });\n this.$dropdown.find('.filter-row-attributes').show();\n }\n\n // Render feature group toggle buttons\n var $featContainer = this.$dropdown.find('.filter-features-container');\n $featContainer.empty();\n\n if (this.filterableData.features && this.filterableData.features.length > 0) {\n this.filterableData.features.forEach(function(group) {\n var html = '';\n html += '';\n html += '';\n html += '';\n $featContainer.append(html);\n });\n this.$dropdown.find('.filter-row-features').show();\n }\n },\n\n showFilterGroupValues: function(groupId, type) {\n if (!this.filterableData) return;\n\n var self = this;\n var groups = type === 'attribute' ? this.filterableData.attributes : this.filterableData.features;\n var group = groups.find(function(g) { return g.id == groupId; });\n\n if (!group) return;\n\n // Hide all values rows first, then show the correct one\n this.$dropdown.find('.filter-row-values').hide();\n\n // Target the correct values row based on type\n var valuesRowClass = type === 'attribute' ? '.filter-row-attr-values' : '.filter-row-feat-values';\n var $filterRowValues = this.$dropdown.find(valuesRowClass);\n var $valuesContainer = $filterRowValues.find('.filter-values-container');\n $valuesContainer.empty();\n\n // Add group label\n var html = '' + group.name + ':';\n\n // Add chips\n group.values.forEach(function(val) {\n var isActive = type === 'attribute'\n ? self.filters.attributes.indexOf(val.id) !== -1\n : self.filters.features.indexOf(val.id) !== -1;\n var activeClass = isActive ? ' active' : '';\n var chipClass = type === 'attribute' ? 'filter-attr-chip' : 'filter-feat-chip';\n var colorStyle = val.color ? ' style=\"--chip-color: ' + val.color + '\"' : '';\n var colorClass = val.color ? ' has-color' : '';\n\n html += '';\n html += '';\n html += '';\n html += '';\n });\n\n $valuesContainer.html(html);\n\n // Add close button as sibling (outside filter-values-container, inside filter-row-values)\n $filterRowValues.find('.btn-close-values').remove();\n $filterRowValues.append('');\n $filterRowValues.show();\n\n // Scroll into view if needed\n var rowValues = $filterRowValues[0];\n if (rowValues) {\n rowValues.scrollIntoView({ behavior: 'smooth', block: 'nearest' });\n }\n },\n\n hideFilterGroupValues: function() {\n this.$dropdown.find('.filter-row-values').hide();\n this.$dropdown.find('.filter-group-toggle').removeClass('active');\n },\n\n updateFilterToggleStates: function() {\n if (!this.$dropdown || !this.filterableData) return;\n\n var self = this;\n\n // Update attribute group toggles\n if (this.filterableData.attributes) {\n this.filterableData.attributes.forEach(function(group) {\n var $toggle = self.$dropdown.find('.filter-group-toggle[data-group-id=\"' + group.id + '\"][data-type=\"attribute\"]');\n var hasActiveInGroup = group.values.some(function(val) {\n return self.filters.attributes.indexOf(val.id) !== -1;\n });\n $toggle.toggleClass('has-selection', hasActiveInGroup);\n });\n }\n\n // Update feature group toggles\n if (this.filterableData.features) {\n this.filterableData.features.forEach(function(group) {\n var $toggle = self.$dropdown.find('.filter-group-toggle[data-group-id=\"' + group.id + '\"][data-type=\"feature\"]');\n var hasActiveInGroup = group.values.some(function(val) {\n return self.filters.features.indexOf(val.id) !== -1;\n });\n $toggle.toggleClass('has-selection', hasActiveInGroup);\n });\n }\n },\n\n /**\n * Load zones for country filter dropdown\n */\n loadZonesForCountryFilter: function() {\n var self = this;\n\n if (this.zonesLoaded || !this.$dropdown) {\n return;\n }\n\n var $select = this.$dropdown.find('.filter-zone-select');\n if (!$select.length) {\n return;\n }\n\n $.ajax({\n url: this.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'getZonesForFilter',\n trait: 'EntitySelector'\n },\n success: function(response) {\n if (response.success && response.zones && response.zones.length > 0) {\n var trans = self.config.trans || {};\n $select.empty();\n $select.append('');\n\n response.zones.forEach(function(zone) {\n $select.append('');\n });\n\n self.zonesLoaded = true;\n }\n }\n });\n }\n };\n\n})(jQuery);\n","/**\n * Entity Selector - Chips Module\n * Entity chip rendering, selection management, and pattern tag handling\n * @partial _chips.js\n *\n * EXTRACTION SOURCE: assets/js/admin/entity-selector.js\n *\n * Contains:\n * - addSelection() / addSelectionNoUpdate() - Add entity chip to picker\n * - removeSelection() - Remove chip and update state\n * - updateChipsVisibility() - Show/hide based on count\n * - loadExistingSelections() - Load saved values on init\n * - collectPickerEntities() / loadPickerValues() - Entity loading helpers\n * - Pattern tag methods: addPatternTag, getPatternTags, updateDraftTagCount\n * - Single mode: getCurrentSingleSelection, showReplaceConfirmation\n * - Count updates: updateConditionCount, updateGroupCounts, updateGroupTotalCount\n */\n\n(function($) {\n 'use strict';\n\n window._EntitySelectorMixins = window._EntitySelectorMixins || {};\n\n window._EntitySelectorMixins.chips = {\n\n // =========================================================================\n // Selection Methods (Entity Chips)\n // =========================================================================\n\n addSelection: function($picker, id, name, data) {\n this.addSelectionNoUpdate($picker, id, name, data);\n var $chips = $picker.find('.entity-chips');\n this.updateChipsVisibility($chips);\n },\n\n addSelectionNoUpdate: function($picker, id, name, data) {\n var $chips = $picker.find('.entity-chips');\n var $block = $picker.closest('.target-block');\n\n // Check for global single mode (only ONE item across ALL entity types)\n var globalMode = this.config.mode || 'multi';\n\n if (globalMode === 'single') {\n // Clear ALL selections in ALL blocks (across all entity types)\n this.$wrapper.find('.entity-chips .entity-chip').remove();\n // Clear all selected states in dropdown\n if (this.$dropdown) {\n this.$dropdown.find('.dropdown-item.selected, .tree-item.selected').removeClass('selected');\n }\n // Clear tab badges (since we're clearing other blocks)\n this.$wrapper.find('.target-block-tab .tab-badge').remove();\n this.$wrapper.find('.target-block-tab').removeClass('has-data');\n } else {\n // Check if this block is in per-block single mode\n var blockMode = $block.data('mode') || 'multi';\n\n // In per-block single mode, clear chips in THIS block only\n if (blockMode === 'single') {\n $chips.find('.entity-chip').remove();\n // Also deselect all items in dropdown\n if (this.$dropdown) {\n this.$dropdown.find('.dropdown-item.selected, .tree-item.selected').removeClass('selected');\n }\n }\n }\n\n if ($chips.find('.entity-chip[data-id=\"' + id + '\"]').length) {\n return;\n }\n\n // Check if this is a country entity (for flag and holiday preview)\n var blockType = $block.data('blockType') || '';\n var searchEntity = $picker.attr('data-search-entity') || blockType;\n var isCountry = (searchEntity === 'countries');\n\n var html = '';\n } else if (data && data.image) {\n html += '\"\"';\n }\n\n html += '' + this.escapeHtml(name) + '';\n\n // Country: add holiday preview button\n if (isCountry) {\n html += '';\n }\n\n html += '';\n html += '
';\n\n $chips.append(html);\n },\n\n removeSelection: function($picker, id) {\n var $chips = $picker.find('.entity-chips');\n $picker.find('.entity-chip[data-id=\"' + id + '\"]').remove();\n this.updateChipsVisibility($chips);\n },\n\n updateChipsVisibility: function($chips) {\n var self = this;\n var trans = this.config.trans || {};\n var $picker = $chips.closest('.value-picker');\n var $allChips = $chips.find('.entity-chip');\n var totalCount = $allChips.length;\n\n // If no chips, remove the wrapper entirely\n var $existingWrapper = $chips.closest('.chips-wrapper');\n if (totalCount === 0) {\n if ($existingWrapper.length) {\n // Move chips out of wrapper before removing\n $existingWrapper.before($chips);\n $existingWrapper.remove();\n }\n return;\n }\n\n // Ensure chips wrapper structure exists\n this.ensureChipsWrapper($chips);\n\n var $wrapper = $chips.closest('.chips-wrapper');\n var $toolbar = $wrapper.find('.chips-toolbar');\n var $loadMore = $wrapper.find('.chips-load-more');\n\n // Get current search filter\n var searchTerm = $toolbar.find('.chips-search-input').val() || '';\n searchTerm = searchTerm.toLowerCase().trim();\n\n // Filter and paginate chips\n var visibleCount = 0;\n var filteredCount = 0;\n var isExpanded = $chips.hasClass('chips-expanded');\n var maxVisible = isExpanded ? 999999 : (this.maxVisibleChips || 12);\n\n $allChips.each(function() {\n var $chip = $(this);\n var chipName = ($chip.find('.chip-name').text() || '').toLowerCase();\n var matchesFilter = !searchTerm || chipName.indexOf(searchTerm) !== -1;\n\n $chip.removeClass('chip-filtered-out chip-paginated-out');\n\n if (!matchesFilter) {\n $chip.addClass('chip-filtered-out');\n } else {\n filteredCount++;\n if (filteredCount > maxVisible) {\n $chip.addClass('chip-paginated-out');\n } else {\n visibleCount++;\n }\n }\n });\n\n // Update toolbar (always show when we have chips)\n $toolbar.addClass('has-chips');\n this.updateChipsToolbar($toolbar, totalCount, filteredCount, searchTerm);\n\n // Update load more select dropdown\n var hiddenByPagination = filteredCount - visibleCount;\n if (hiddenByPagination > 0 && !isExpanded) {\n var loadText = trans.load || 'Load';\n var remainingText = (trans.remaining || '{count} remaining').replace('{count}', hiddenByPagination);\n var loadMoreHtml = '' + loadText + '' +\n '' +\n '' + remainingText + '';\n $loadMore.html(loadMoreHtml).show();\n } else if (isExpanded && filteredCount > (this.maxVisibleChips || 12)) {\n var collapseText = trans.collapse || 'Collapse';\n $loadMore.html(\n ''\n ).show();\n } else {\n $loadMore.hide();\n }\n },\n\n ensureChipsWrapper: function($chips) {\n // Check if already wrapped\n if ($chips.closest('.chips-wrapper').length) {\n return;\n }\n\n var trans = this.config.trans || {};\n var $picker = $chips.closest('.value-picker');\n\n // Create wrapper structure - integrated filter toolbar with sort\n var wrapperHtml = '
' +\n '
' +\n '' +\n '' +\n '' +\n '' +\n '
' +\n '
' +\n '
';\n\n var $wrapper = $(wrapperHtml);\n\n // Insert wrapper before chips and move chips inside\n $chips.before($wrapper);\n $wrapper.find('.chips-toolbar').after($chips);\n $wrapper.append($wrapper.find('.chips-load-more'));\n\n // Bind toolbar events\n this.bindChipsToolbarEvents($wrapper);\n },\n\n bindChipsToolbarEvents: function($wrapper) {\n var self = this;\n var $chips = $wrapper.find('.entity-chips');\n var searchTimeout;\n\n // Search input\n $wrapper.on('input', '.chips-search-input', function() {\n clearTimeout(searchTimeout);\n searchTimeout = setTimeout(function() {\n // Collapse when searching to show filtered results from start\n $chips.removeClass('chips-expanded');\n self.updateChipsVisibility($chips);\n }, 150);\n });\n\n // Sort select\n $wrapper.on('change', '.chips-sort-select', function() {\n var sortBy = $(this).val();\n self.sortChips($chips, sortBy);\n });\n\n // Clear all button\n $wrapper.on('click', '.btn-chips-clear', function() {\n var searchTerm = $wrapper.find('.chips-search-input').val() || '';\n var $chipsToRemove;\n\n if (searchTerm.trim()) {\n // Remove only filtered (visible) chips\n $chipsToRemove = $chips.find('.entity-chip:not(.chip-filtered-out)');\n } else {\n // Remove all chips\n $chipsToRemove = $chips.find('.entity-chip');\n }\n\n $chipsToRemove.each(function() {\n $(this).find('.chip-remove').trigger('click');\n });\n\n // Clear search\n $wrapper.find('.chips-search-input').val('');\n self.updateChipsVisibility($chips);\n });\n\n // Load more select dropdown\n $wrapper.on('change', '.load-more-select', function() {\n var loadCount = $(this).val();\n if (loadCount === 'all') {\n $chips.addClass('chips-expanded');\n self.maxVisibleChips = 999999;\n } else {\n self.maxVisibleChips = (self.maxVisibleChips || 12) + parseInt(loadCount, 10);\n }\n self.updateChipsVisibility($chips);\n });\n\n // Collapse button\n $wrapper.on('click', '.btn-collapse-chips', function() {\n $chips.removeClass('chips-expanded');\n self.maxVisibleChips = 12;\n self.updateChipsVisibility($chips);\n });\n },\n\n /**\n * Sort chips by specified criteria\n */\n sortChips: function($chips, sortBy) {\n var $allChips = $chips.find('.entity-chip');\n if ($allChips.length < 2) return;\n\n var sorted = $allChips.toArray().sort(function(a, b) {\n var $a = $(a);\n var $b = $(b);\n\n switch (sortBy) {\n case 'name_asc':\n var nameA = ($a.find('.chip-name').text() || '').toLowerCase();\n var nameB = ($b.find('.chip-name').text() || '').toLowerCase();\n return nameA.localeCompare(nameB);\n case 'name_desc':\n var nameA2 = ($a.find('.chip-name').text() || '').toLowerCase();\n var nameB2 = ($b.find('.chip-name').text() || '').toLowerCase();\n return nameB2.localeCompare(nameA2);\n case 'added':\n default:\n // Keep original DOM order (order added)\n return 0;\n }\n });\n\n // Re-append in sorted order\n $.each(sorted, function(i, chip) {\n $chips.append(chip);\n });\n\n this.updateChipsVisibility($chips);\n },\n\n updateChipsToolbar: function($toolbar, totalCount, filteredCount, searchTerm) {\n var trans = this.config.trans || {};\n var $count = $toolbar.find('.chips-count');\n var $clearBtn = $toolbar.find('.btn-chips-clear');\n var $clearText = $clearBtn.find('.clear-text');\n\n // Update count display\n if (searchTerm) {\n $count.addClass('has-filter').html(\n '' + filteredCount + '' +\n '/' +\n '' + totalCount + ''\n );\n $clearText.text((trans.clear || 'Clear') + ' ' + filteredCount);\n } else {\n $count.removeClass('has-filter').html(totalCount);\n $clearText.text(trans.clear_all || 'Clear all');\n }\n\n // Show/hide clear button\n if (searchTerm && filteredCount === 0) {\n $clearBtn.hide();\n } else if (totalCount > 0) {\n $clearBtn.show();\n } else {\n $clearBtn.hide();\n }\n },\n\n // =========================================================================\n // Loading/Initialization\n // =========================================================================\n\n loadExistingSelections: function() {\n var self = this;\n console.log('[EntitySelector] loadExistingSelections called for id:', this.config.id);\n\n // Collect all entity IDs to load, grouped by entity type\n var entitiesToLoad = {}; // { entity_type: { ids: [], pickers: [] } }\n\n console.log('[EntitySelector] Looking for .selection-group in wrapper:', this.$wrapper.length ? 'found' : 'NOT FOUND');\n this.$wrapper.find('.selection-group').each(function() {\n console.log('[EntitySelector] Found .selection-group, index:', $(this).data('groupIndex'));\n var $group = $(this);\n var $block = $group.closest('.target-block');\n var blockType = $block.data('blockType');\n\n // Load include values\n var $includePicker = $group.find('.include-picker');\n self.collectPickerEntities($includePicker, blockType, entitiesToLoad);\n\n // Enhance the include method select if not already enhanced\n self.enhanceMethodSelect($group.find('.include-method-select'));\n\n // Load exclude values from each exclude row\n $group.find('.exclude-row').each(function() {\n var $excludeRow = $(this);\n self.collectPickerEntities($excludeRow.find('.exclude-picker'), blockType, entitiesToLoad);\n\n // Enhance the exclude method select if not already enhanced\n self.enhanceMethodSelect($excludeRow.find('.exclude-method-select'));\n });\n\n // Lock method selector if excludes exist\n var hasExcludes = $group.find('.group-excludes.has-excludes').length > 0;\n if (hasExcludes) {\n self.updateMethodSelectorLock($group, true);\n }\n });\n\n // Build bulk request: { entityType: [uniqueIds], ... }\n var bulkRequest = {};\n var hasEntities = false;\n\n Object.keys(entitiesToLoad).forEach(function(entityType) {\n var data = entitiesToLoad[entityType];\n if (data.ids.length === 0) return;\n\n // Deduplicate IDs\n var uniqueIds = data.ids.filter(function(id, index, arr) {\n return arr.indexOf(id) === index;\n });\n\n bulkRequest[entityType] = uniqueIds;\n hasEntities = true;\n });\n\n // Skip AJAX if no entities to load\n if (!hasEntities) {\n console.log('[EntitySelector] No entities to load, skipping AJAX');\n return;\n }\n\n console.log('[EntitySelector] Making bulk AJAX request for entities:', JSON.stringify(bulkRequest));\n\n // Single bulk AJAX call for all entity types\n var bulkAjaxData = {\n ajax: 1,\n action: 'getTargetEntitiesByIdsBulk',\n trait: 'EntitySelector',\n entities: JSON.stringify(bulkRequest)\n };\n if (self.config.productSelectionLevel && self.config.productSelectionLevel !== 'product') {\n bulkAjaxData.product_selection_level = self.config.productSelectionLevel;\n }\n $.ajax({\n url: self.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: bulkAjaxData,\n success: function(response) {\n console.log('[EntitySelector] AJAX response:', response);\n if (!response.success || !response.entities) {\n console.log('[EntitySelector] Response failed or no entities');\n return;\n }\n try {\n\n // Process each entity type's results\n Object.keys(entitiesToLoad).forEach(function(entityType) {\n var data = entitiesToLoad[entityType];\n var entities = response.entities[entityType] || [];\n\n // Build a map of id -> entity for quick lookup\n var entityMap = {};\n entities.forEach(function(entity) {\n entityMap[entity.id] = entity;\n });\n\n // Update each picker that requested this entity type\n data.pickers.forEach(function(pickerData) {\n var $picker = pickerData.$picker;\n var $chips = $picker.find('.entity-chips');\n var $dataInput = $picker.find('.include-values-data, .exclude-values-data');\n var validIds = [];\n\n // Check if this is a country entity\n var isCountry = (entityType === 'countries');\n\n // Replace loading chips with real data\n pickerData.ids.forEach(function(id) {\n var $loadingChip = $chips.find('.entity-chip-loading[data-id=\"' + id + '\"]');\n if (entityMap[id]) {\n var entity = entityMap[id];\n validIds.push(entity.id);\n\n // Create real chip\n var html = '';\n } else if (entity.image) {\n html += '\"\"';\n }\n\n html += '' + self.escapeHtml(entity.name) + '';\n\n // Country: add holiday preview button\n if (isCountry) {\n html += '';\n }\n\n html += '';\n html += '
';\n\n $loadingChip.replaceWith(html);\n } else {\n // Entity not found, remove loading chip\n $loadingChip.remove();\n }\n });\n\n // Update chips visibility\n self.updateChipsVisibility($chips);\n\n // If some entities were not found, update the hidden input\n if (validIds.length !== pickerData.ids.length) {\n $dataInput.val(JSON.stringify(validIds));\n self.serializeAllBlocks();\n }\n\n self.updateBlockStatus($picker.closest('.target-block'));\n });\n });\n\n // Update condition counts after chips are loaded (for holiday counts, etc.)\n self.updateAllConditionCounts();\n\n } catch (e) {\n console.error('[EntitySelector] Error processing AJAX response:', e);\n }\n },\n error: function(xhr, status, error) {\n console.error('[EntitySelector] AJAX request failed:', status, error, xhr.responseText);\n }\n });\n },\n\n /**\n * Collect entity IDs from a picker for bulk loading\n * Also shows loading placeholders for entity_search types\n */\n collectPickerEntities: function($picker, blockType, entitiesToLoad) {\n console.log('[EntitySelector] collectPickerEntities called, blockType:', blockType, 'picker length:', $picker.length);\n if (!$picker.length) {\n console.log('[EntitySelector] Picker not found, returning');\n return;\n }\n\n var self = this;\n var $dataInput = $picker.find('.include-values-data, .exclude-values-data');\n console.log('[EntitySelector] Looking for values-data input, found:', $dataInput.length);\n if (!$dataInput.length) {\n console.log('[EntitySelector] No data input found, returning');\n return;\n }\n\n var valueType = $picker.attr('data-value-type');\n var rawValue = $dataInput.val() || '[]';\n console.log('[EntitySelector] valueType:', valueType, 'rawValue:', rawValue);\n\n var values = [];\n try {\n values = JSON.parse(rawValue);\n console.log('[EntitySelector] Parsed values:', values);\n } catch (e) {\n console.log('[EntitySelector] JSON parse error:', e);\n return;\n }\n\n // Handle non-entity types synchronously\n if (valueType === 'multi_numeric_range') {\n if (!Array.isArray(values) || values.length === 0) return;\n\n var $chipsContainer = $picker.find('.multi-range-chips');\n values.forEach(function(range) {\n if (!range || (range.min === null && range.max === null)) return;\n\n var chipText = '';\n if (range.min !== null && range.max !== null) {\n chipText = range.min + ' - ' + range.max;\n } else if (range.min !== null) {\n chipText = '≥ ' + range.min;\n } else {\n chipText = '≤ ' + range.max;\n }\n\n var $chip = $('', {\n class: 'range-chip',\n 'data-min': range.min !== null ? range.min : '',\n 'data-max': range.max !== null ? range.max : ''\n });\n $chip.append($('', { class: 'range-chip-text', text: chipText }));\n $chip.append($('';\n html += '' + this.escapeHtml(pattern) + '';\n html += '';\n html += '';\n $chipsContainer.append(html);\n },\n\n /**\n * Get all pattern tags from a wrapper\n * Returns array of objects: { pattern: string, caseSensitive: boolean }\n */\n getPatternTags: function($wrapper) {\n var patterns = [];\n // Exclude draft-tag which is the input field, not a saved pattern\n $wrapper.find('.pattern-tag:not(.draft-tag)').each(function() {\n var pattern = $(this).data('pattern');\n var caseSensitive = $(this).data('caseSensitive') === 1 || $(this).data('caseSensitive') === '1';\n if (pattern) {\n patterns.push({\n pattern: pattern,\n caseSensitive: caseSensitive\n });\n }\n });\n return patterns;\n },\n\n /**\n * Update the match count displayed in the draft tag while typing\n * Shows live preview with current case sensitivity setting\n */\n updateDraftTagCount: function($draftTag, pattern, caseSensitive) {\n var self = this;\n var $matchCount = $draftTag.find('.pattern-match-count');\n var $countValue = $matchCount.find('.count-value');\n\n // Get entity type from block\n var $block = $draftTag.closest('.target-block');\n var entityType = $block.data('blockType') || 'products';\n\n // Show loading - keep eye icon, update count value\n $countValue.html('');\n $matchCount.show();\n\n // Store pattern for click handler\n $matchCount.data('pattern', pattern);\n $matchCount.data('caseSensitive', caseSensitive);\n $matchCount.data('entityType', entityType);\n\n $.ajax({\n url: this.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'countPatternMatches',\n trait: 'EntitySelector',\n pattern: pattern,\n field: 'name',\n entity_type: entityType,\n case_sensitive: caseSensitive ? 1 : 0\n },\n success: function(response) {\n if (response.success) {\n var count = parseInt(response.count, 10) || 0;\n $countValue.text(count);\n $matchCount.show();\n // Add visual feedback based on count\n $matchCount.removeClass('count-zero count-found');\n $matchCount.addClass(count === 0 ? 'count-zero' : 'count-found');\n // Store count for preview\n $matchCount.data('count', count);\n // Update group total count to reflect draft pattern in calculation\n var $group = $draftTag.closest('.selection-group');\n if ($group.length) {\n self.updateGroupTotalCount($group);\n }\n } else {\n $countValue.text('?');\n $matchCount.show();\n }\n },\n error: function() {\n $countValue.text('?');\n $matchCount.show();\n }\n });\n },\n\n /**\n * Update condition count with a pending pattern (typed but not yet added as tag)\n * This shows a live preview of what the count would be if the user pressed Enter\n */\n updateConditionCountWithPendingPattern: function($row, pendingPattern) {\n var self = this;\n var trans = this.config.trans || {};\n\n // Find the count element - in method-selector-wrapper for include, in exclude-header-row for exclude\n var $countEl = $row.find('.method-selector-wrapper > .condition-match-count, > .exclude-header-row > .condition-match-count').first();\n if (!$countEl.length) return;\n\n var isExclude = $row.hasClass('exclude-row');\n var $methodSelect = isExclude\n ? $row.find('.exclude-method-select')\n : $row.find('.include-method-select');\n\n var method = $methodSelect.val();\n if (!method) {\n $countEl.hide();\n return;\n }\n\n var $picker = isExclude\n ? $row.find('.exclude-picker')\n : $row.find('.include-picker');\n\n var valueType = $picker.data('valueType') || 'none';\n\n // Only process for pattern value types\n if (valueType !== 'pattern') {\n return;\n }\n\n // Get existing pattern tags\n var values = this.getPatternTags($picker);\n\n // Add the pending pattern as a temporary tag (case-insensitive by default)\n if (pendingPattern) {\n values.push({ pattern: pendingPattern, caseSensitive: false });\n }\n\n if (values.length === 0) {\n $countEl.hide();\n return;\n }\n\n var $block = $row.closest('.target-block');\n var blockType = $block.data('blockType') || 'products';\n\n // Show loading\n $countEl.find('.preview-count').html('');\n $countEl.removeClass('clickable no-matches').show();\n\n // Store condition data on badge for popover\n $countEl.data('conditionData', {\n method: method,\n values: values,\n blockType: blockType,\n isExclude: isExclude\n });\n\n $.ajax({\n url: this.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'countConditionMatches',\n trait: 'EntitySelector',\n method: method,\n values: JSON.stringify(values),\n block_type: blockType\n },\n success: function(response) {\n if (response && response.success) {\n var count = response.count || 0;\n $countEl.removeClass('no-matches clickable');\n if (count === 0) {\n $countEl.find('.preview-count').text(count);\n $countEl.addClass('no-matches').show();\n } else {\n $countEl.find('.preview-count').text(count);\n $countEl.addClass('clickable').show();\n }\n } else {\n $countEl.hide().removeClass('clickable');\n }\n },\n error: function() {\n $countEl.hide().removeClass('clickable');\n }\n });\n },\n\n /**\n * Fetch pattern match count via AJAX\n */\n fetchPatternMatchCount: function($picker, pattern, $countEl) {\n // Determine field type from method select\n // Check if we're in an exclude row first, then fall back to include\n var $excludeRow = $picker.closest('.exclude-row');\n var $methodSelect;\n if ($excludeRow.length) {\n $methodSelect = $excludeRow.find('.exclude-method-select');\n } else {\n var $group = $picker.closest('.selection-group');\n $methodSelect = $group.find('.include-method-select');\n }\n var method = $methodSelect.val() || '';\n var field = method.indexOf('reference') !== -1 ? 'reference' : 'name';\n\n // Get entity type from block\n var $block = $picker.closest('.target-block');\n var entityType = $block.data('blockType') || 'products';\n\n // Show loading state\n $countEl.find('.preview-count').html('');\n $countEl.removeClass('clickable no-matches').show();\n\n $.ajax({\n url: this.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'countPatternMatches',\n trait: 'EntitySelector',\n pattern: pattern,\n field: field,\n entity_type: entityType,\n case_sensitive: 0\n },\n success: function(response) {\n if (response && response.success) {\n var count = response.count || 0;\n $countEl.find('.preview-count').text(count);\n $countEl.removeClass('no-matches clickable').show();\n if (count === 0) {\n $countEl.addClass('no-matches');\n } else {\n $countEl.addClass('clickable');\n }\n } else {\n $countEl.hide();\n }\n },\n error: function() {\n $countEl.hide();\n }\n });\n },\n\n // =========================================================================\n // Picker Value Extraction\n // =========================================================================\n\n /**\n * Get values from a picker based on its type\n */\n getPickerValues: function($picker, valueType) {\n switch (valueType) {\n case 'entity_search':\n var ids = [];\n $picker.find('.entity-chip').each(function() {\n var id = $(this).data('id');\n if (id) ids.push(id);\n });\n return ids;\n\n case 'pattern':\n var patternValues = this.getPatternTags($picker);\n // Also include draft pattern if it has content (not yet added as tag)\n var $draftPatternInput = $picker.find('.draft-tag .pattern-input');\n var draftPatternVal = $.trim($draftPatternInput.val());\n if (draftPatternVal) {\n var draftCaseSens = $draftPatternInput.closest('.draft-tag').attr('data-case-sensitive') === '1';\n patternValues.push({\n pattern: draftPatternVal,\n caseSensitive: draftCaseSens\n });\n }\n return patternValues;\n\n case 'numeric_range':\n var min = $picker.find('.range-min-input').val();\n var max = $picker.find('.range-max-input').val();\n return { min: min || null, max: max || null };\n\n case 'date_range':\n var from = $picker.find('.date-from-input').val();\n var to = $picker.find('.date-to-input').val();\n return { from: from || null, to: to || null };\n\n case 'select':\n return [$picker.find('.select-value-input').val()];\n\n case 'boolean':\n return [true];\n\n default:\n return [];\n }\n },\n\n // =========================================================================\n // Count/Status Updates\n // =========================================================================\n\n /**\n * Fetch and update condition match count for a row (include or exclude)\n */\n updateConditionCount: function($row) {\n var self = this;\n var trans = this.config.trans || {};\n\n // Find the count element - in method-selector-wrapper for include, in exclude-header-row for exclude\n var $countEl = $row.find('.method-selector-wrapper > .condition-match-count, > .exclude-header-row > .condition-match-count').first();\n if (!$countEl.length) return;\n\n // Determine if this is an include or exclude row\n var isExclude = $row.hasClass('exclude-row');\n var $methodSelect = isExclude\n ? $row.find('.exclude-method-select')\n : $row.find('.include-method-select');\n\n var method = $methodSelect.val();\n if (!method) {\n $countEl.hide();\n return;\n }\n\n // Get the picker and extract values\n var $picker = isExclude\n ? $row.find('.exclude-picker')\n : $row.find('.include-picker');\n\n var valueType = $picker.data('valueType') || 'none';\n var values = this.getPickerValues($picker, valueType);\n\n // Don't count if no values (except for boolean/all methods)\n var hasNoValues = !values ||\n (Array.isArray(values) && values.length === 0) ||\n (typeof values === 'object' && !Array.isArray(values) && (\n // For combination_attributes, check if attributes object is empty\n (valueType === 'combination_attributes' && values.attributes !== undefined && Object.keys(values.attributes).length === 0) ||\n // For other objects, check if completely empty\n (valueType !== 'combination_attributes' && Object.keys(values).length === 0)\n ));\n if (valueType !== 'none' && valueType !== 'boolean' && hasNoValues) {\n $countEl.hide();\n return;\n }\n\n // Get block type\n var $block = $row.closest('.target-block');\n var blockType = $block.data('blockType') || 'products';\n\n // Show loading\n $countEl.find('.preview-count').html('');\n $countEl.removeClass('clickable no-matches').show();\n\n // Store condition data on badge for popover\n $countEl.data('conditionData', {\n method: method,\n values: values,\n blockType: blockType,\n isExclude: isExclude\n });\n\n $.ajax({\n url: this.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'countConditionMatches',\n trait: 'EntitySelector',\n method: method,\n values: JSON.stringify(values),\n block_type: blockType\n },\n success: function(response) {\n if (response && response.success) {\n var count = response.count || 0;\n $countEl.removeClass('no-matches clickable');\n if (count === 0) {\n $countEl.find('.preview-count').text(count);\n $countEl.addClass('no-matches').show();\n } else {\n // Show count, make clickable for preview popover\n $countEl.find('.preview-count').text(count);\n $countEl.addClass('clickable').show();\n }\n } else {\n $countEl.hide().removeClass('clickable');\n }\n },\n error: function() {\n $countEl.hide().removeClass('clickable');\n }\n });\n },\n\n /**\n * Update all condition counts in a group\n */\n updateGroupCounts: function($group) {\n var self = this;\n\n // Update include count\n var $include = $group.find('.group-include');\n if ($include.length) {\n this.updateConditionCount($include);\n }\n\n // Update each exclude row count\n $group.find('.exclude-row').each(function() {\n self.updateConditionCount($(this));\n });\n\n // Update group total count (include - excludes)\n this.updateGroupTotalCount($group);\n },\n\n /**\n * Update the group total count badge (include - excludes)\n * Also updates the limit input placeholder\n */\n updateGroupTotalCount: function($group) {\n var self = this;\n var $block = $group.closest('.target-block');\n var blockType = $block.data('blockType') || 'products';\n var $badge = $group.find('.group-header .group-count-badge');\n var $limitInput = $group.find('.group-modifier-limit');\n\n // Build group data for AJAX\n var groupData = this.serializeGroup($group, blockType);\n\n // Check if include has valid data\n if (!groupData.include || !groupData.include.method) {\n $badge.hide();\n $limitInput.attr('placeholder', '–');\n return;\n }\n\n // Show loading\n $badge.html('').show();\n\n $.ajax({\n url: this.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'countGroupItems',\n trait: 'EntitySelector',\n group_data: JSON.stringify(groupData),\n block_type: blockType\n },\n success: function(response) {\n if (response && response.success) {\n var finalCount = response.final_count || 0;\n var excludeCount = response.exclude_count || 0;\n\n // Update badge with eye icon and count\n var badgeHtml = ' ' + finalCount;\n if (excludeCount > 0) {\n badgeHtml += ' (-' + excludeCount + ')';\n }\n $badge.html(badgeHtml);\n $badge.addClass('clickable').show();\n\n // Store group data on badge for preview popover\n $badge.data('groupData', groupData);\n $badge.data('blockType', blockType);\n $badge.data('finalCount', finalCount);\n\n // Update limit placeholder with the count\n $limitInput.attr('placeholder', finalCount);\n\n // Also update the group-preview-badge count (apply limit if set)\n var $previewBadge = $group.find('.group-preview-badge .preview-count');\n if ($previewBadge.length) {\n var limit = parseInt($limitInput.val(), 10);\n var displayCount = (limit > 0 && limit < finalCount) ? limit : finalCount;\n $previewBadge.text(displayCount);\n }\n } else {\n $badge.hide().removeClass('clickable');\n $limitInput.attr('placeholder', '–');\n }\n },\n error: function() {\n $badge.hide();\n $limitInput.attr('placeholder', '–');\n }\n });\n },\n\n /**\n * Update all condition counts for all visible groups\n */\n updateAllConditionCounts: function() {\n var self = this;\n this.$wrapper.find('.target-block.active .selection-group').each(function() {\n self.updateGroupCounts($(this));\n });\n },\n\n /**\n * Fetch category names by IDs and add chips to the picker\n * Used when adding selections from the tree modal\n * @param {jQuery} $picker - Picker element\n * @param {Array} ids - Category IDs to add\n * @param {string} entityType - 'categories' or 'cms_categories'\n * @param {Function} callback - Called when done\n */\n fetchCategoryNamesAndAddChips: function($picker, ids, entityType, callback) {\n var self = this;\n\n if (!ids || ids.length === 0) {\n if (typeof callback === 'function') {\n callback();\n }\n return;\n }\n\n $.ajax({\n url: this.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'getTargetEntitiesByIds',\n trait: 'EntitySelector',\n entity_type: entityType,\n ids: JSON.stringify(ids)\n },\n success: function(response) {\n if (response.success && response.entities) {\n response.entities.forEach(function(entity) {\n self.addSelectionNoUpdate($picker, entity.id, entity.name, entity);\n });\n }\n if (typeof callback === 'function') {\n callback();\n }\n },\n error: function() {\n if (typeof callback === 'function') {\n callback();\n }\n }\n });\n }\n };\n\n})(jQuery);\n","/**\n * Entity Selector - Groups Module\n * Selection group management, serialization, block/tab management\n * @partial _groups.js\n *\n * Contains:\n * - Group management: addGroup, removeGroup, clearAllConditions\n * - Block/Tab: switchToBlock, updateTabBadges, updateBlockStatus\n * - Serialization: serializeGroup, serializeAllBlocks, getBlockGroups\n * - Counts: fetchProductCount, updateHeaderTotalCount, updateAllConditionCounts\n * - Excludes: addFirstExcludeRow, addExcludeRow, removeExcludeRow\n * - Validation: validate, showValidationError, clearValidationError\n */\n\n(function($) {\n 'use strict';\n\n window._EntitySelectorMixins = window._EntitySelectorMixins || {};\n\n window._EntitySelectorMixins.groups = {\n\n addGroup: function($block, blockType) {\n var $container = $block.find('.groups-container');\n var trans = this.config.trans || {};\n var blockDef = this.config.blocks[blockType] || {};\n var methods = blockDef.selection_methods || {};\n\n // Remove empty state\n $container.find('.groups-empty-state').remove();\n\n // Get next group index\n var maxIndex = -1;\n $container.find('.selection-group').each(function() {\n var idx = parseInt($(this).data('groupIndex'), 10);\n if (idx > maxIndex) maxIndex = idx;\n });\n var groupIndex = maxIndex + 1;\n\n // Build method options with optgroups\n var methodOptions = this.buildMethodOptions(methods, false);\n\n // Build exclude method options (no \"all\") with optgroups\n var excludeMethodOptions = this.buildMethodOptions(methods, true);\n\n var defaultGroupName = (trans.group || 'Group') + ' ' + (groupIndex + 1);\n var html = '
';\n\n // Group header\n html += '
';\n html += '';\n html += '';\n html += '';\n html += '';\n html += '';\n html += '';\n html += '
';\n\n // Group body (collapsible content)\n html += '
';\n\n // Include section\n html += '
';\n html += '
';\n html += '
';\n html += '';\n html += ' 0';\n html += '';\n html += '
';\n var noItemsText = trans.no_items_selected || 'No items selected - use search below';\n html += '
';\n html += '
';\n html += '
';\n html += '';\n html += '';\n html += '';\n html += '
';\n html += '';\n html += '
';\n html += '
';\n html += '
';\n\n // Excludes section (collapsed by default)\n html += '
';\n html += '';\n html += '
';\n\n // Group-level modifiers (limit & sort)\n html += '
';\n html += '';\n html += '' + (trans.limit || 'Limit') + '';\n html += '';\n html += '';\n html += '';\n html += '' + (trans.sort || 'Sort') + '';\n html += '';\n html += '';\n html += '';\n html += '';\n html += ' ';\n html += '';\n html += '
';\n\n html += '
'; // Close group-body\n\n html += '
'; // Close selection-group\n\n $container.append(html);\n\n // Find the new group and set method to \"all\" by default\n var $newGroup = $container.find('.selection-group[data-group-index=\"' + groupIndex + '\"]');\n\n // Enhance the method select with styled dropdown\n this.enhanceMethodSelect($newGroup.find('.include-method-select'));\n\n $newGroup.find('.include-method-select').val('all').trigger('change');\n\n this.updateBlockStatus($block);\n this.serializeAllBlocks();\n },\n\n removeGroup: function($group, $block) {\n $group.remove();\n\n var $container = $block.find('.groups-container');\n var remainingGroups = $container.find('.selection-group').length;\n\n if (remainingGroups === 0) {\n var emptyText = this.getEmptyStateText($block);\n var emptyHtml = '
';\n emptyHtml += '' + emptyText + '';\n emptyHtml += '
';\n $container.html(emptyHtml);\n }\n\n this.updateBlockStatus($block);\n this.serializeAllBlocks();\n\n // Update tab badges and header total count\n this.updateTabBadges();\n },\n\n clearAllConditions: function() {\n var self = this;\n\n // Remove all groups from all blocks\n this.$wrapper.find('.target-block').each(function() {\n var $block = $(this);\n var $container = $block.find('.groups-container');\n\n // Remove all groups\n $container.find('.selection-group').remove();\n\n // Show empty state\n var emptyText = self.getEmptyStateText($block);\n var emptyHtml = '
';\n emptyHtml += '' + emptyText + '';\n emptyHtml += '
';\n $container.html(emptyHtml);\n\n self.updateBlockStatus($block);\n });\n\n // Update serialized data\n this.serializeAllBlocks();\n\n // Update tab badges and header count\n this.updateTabBadges();\n\n // Also update header total count immediately (since all cleared)\n this.updateHeaderTotalCount();\n },\n\n switchToBlock: function(blockType) {\n // Update tabs\n this.$wrapper.find('.target-block-tab').removeClass('active');\n this.$wrapper.find('.target-block-tab[data-block-type=\"' + blockType + '\"]').addClass('active');\n\n // Update blocks\n this.$wrapper.find('.target-block').removeClass('active').hide();\n this.$wrapper.find('.target-block[data-block-type=\"' + blockType + '\"]').addClass('active').show();\n\n // Close dropdown if open\n this.hideDropdown();\n },\n\n updateTabBadges: function() {\n var self = this;\n\n // Collect all block types with data and set loading state\n var blockTypesWithData = [];\n this.$wrapper.find('.target-block-tab').each(function() {\n var $tab = $(this);\n var blockType = $tab.data('blockType');\n var $block = self.$wrapper.find('.target-block[data-block-type=\"' + blockType + '\"]');\n var groupCount = $block.find('.selection-group').length;\n\n // Update or add badge\n var $badge = $tab.find('.tab-badge');\n if (groupCount > 0) {\n // Show loading state first\n if ($badge.length) {\n $badge.addClass('loading').html('');\n } else {\n $tab.append('');\n }\n $tab.addClass('has-data');\n blockTypesWithData.push(blockType);\n } else {\n $badge.remove();\n $tab.removeClass('has-data');\n }\n });\n\n // Update target switch state based on whether any data exists\n this.updateTargetSwitchState();\n\n // Fetch all counts in a single bulk request\n if (blockTypesWithData.length > 0) {\n this.fetchAllCounts(blockTypesWithData);\n }\n },\n\n updateTargetSwitchState: function() {\n var $switch = this.$wrapper.find('.prestashop-switch');\n if (!$switch.length) {\n return;\n }\n\n // Check if any block has data\n var hasData = false;\n this.$wrapper.find('.target-block').each(function() {\n if ($(this).find('.selection-group').length > 0) {\n hasData = true;\n return false; // break\n }\n });\n\n // Update switch: value=\"1\" is \"Everyone/All/None\", value=\"0\" is \"Specific/Selected\"\n if (hasData) {\n $switch.find('input[value=\"0\"]').prop('checked', true);\n } else {\n $switch.find('input[value=\"1\"]').prop('checked', true);\n }\n },\n\n /**\n * Fetch counts for all block types in a single bulk AJAX request\n * @param {Array} blockTypes - Array of block type strings to fetch counts for\n */\n fetchAllCounts: function(blockTypes) {\n var self = this;\n\n // Read saved data from hidden input\n var $hiddenInput = this.$wrapper.find('input[name=\"' + this.config.name + '\"]');\n var savedData = {};\n try {\n savedData = JSON.parse($hiddenInput.val() || '{}');\n } catch (e) {\n savedData = {};\n }\n\n // Build conditions object for all requested block types\n var conditions = {};\n blockTypes.forEach(function(blockType) {\n var groups = (savedData[blockType] && savedData[blockType].groups) ? savedData[blockType].groups : [];\n if (groups.length > 0) {\n conditions[blockType] = { groups: groups };\n }\n });\n\n // If no valid conditions, remove loading spinners\n if (Object.keys(conditions).length === 0) {\n blockTypes.forEach(function(blockType) {\n var $tab = self.$wrapper.find('.target-block-tab[data-block-type=\"' + blockType + '\"]');\n $tab.find('.tab-badge').remove();\n $tab.removeClass('has-data');\n });\n return;\n }\n\n // Single bulk AJAX request for all counts\n $.ajax({\n url: this.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'previewEntitySelectorBulk',\n trait: 'EntitySelector',\n conditions: JSON.stringify(conditions)\n },\n success: function(response) {\n if (response.success && response.counts) {\n // Update each tab with its count\n Object.keys(response.counts).forEach(function(blockType) {\n var count = response.counts[blockType];\n var $tab = self.$wrapper.find('.target-block-tab[data-block-type=\"' + blockType + '\"]');\n var $badge = $tab.find('.tab-badge');\n\n if ($badge.length) {\n $badge.removeClass('loading').html(' ' + count);\n // Store preview data for later popover use\n $tab.data('previewData', { count: count, success: true });\n }\n });\n\n // Handle any block types not in response (set count to 0 or remove badge)\n blockTypes.forEach(function(blockType) {\n if (!(blockType in response.counts)) {\n var $tab = self.$wrapper.find('.target-block-tab[data-block-type=\"' + blockType + '\"]');\n $tab.find('.tab-badge').remove();\n $tab.removeClass('has-data');\n }\n });\n\n self.updateHeaderTotalCount();\n } else {\n console.error('[EntitySelector] Bulk preview failed:', response.error || 'Unknown error');\n // Remove loading spinners on error\n blockTypes.forEach(function(blockType) {\n var $tab = self.$wrapper.find('.target-block-tab[data-block-type=\"' + blockType + '\"]');\n $tab.find('.tab-badge').remove();\n });\n }\n },\n error: function(xhr, status, error) {\n console.error('[EntitySelector] Bulk AJAX error:', status, error);\n // Remove loading spinners on error\n blockTypes.forEach(function(blockType) {\n var $tab = self.$wrapper.find('.target-block-tab[data-block-type=\"' + blockType + '\"]');\n $tab.find('.tab-badge').remove();\n });\n }\n });\n },\n\n /**\n * Fetch count for a single block type (legacy, used for single updates)\n */\n fetchProductCount: function(blockType, $tab) {\n var self = this;\n var data = {};\n\n // Read from hidden input (contains full saved data or freshly serialized data)\n var $hiddenInput = this.$wrapper.find('input[name=\"' + this.config.name + '\"]');\n var savedData = {};\n try {\n savedData = JSON.parse($hiddenInput.val() || '{}');\n } catch (e) {\n savedData = {};\n }\n\n // Get groups for the requested block type\n var groups = (savedData[blockType] && savedData[blockType].groups) ? savedData[blockType].groups : [];\n\n if (groups.length === 0) {\n $tab.find('.tab-badge').remove();\n $tab.removeClass('has-data');\n $tab.removeData('previewData');\n return;\n }\n\n // Show loading state\n var $badge = $tab.find('.tab-badge');\n if (!$badge.length) {\n $badge = $('');\n $tab.append($badge);\n } else {\n $badge.addClass('loading').html('');\n }\n $tab.addClass('has-data');\n\n data[blockType] = { groups: groups };\n\n $.ajax({\n url: this.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'previewEntitySelector',\n trait: 'EntitySelector',\n conditions: JSON.stringify(data),\n block_type: blockType,\n limit: 10\n },\n success: function(response) {\n if (response.success) {\n var $badge = $tab.find('.tab-badge');\n $badge.removeClass('loading').html(' ' + response.count);\n\n // Store preview data for popover\n $tab.data('previewData', response);\n\n // Update header total count\n self.updateHeaderTotalCount();\n } else {\n console.error('[EntitySelector] Preview failed for', blockType, ':', response.error || 'Unknown error');\n $tab.find('.tab-badge').remove();\n }\n },\n error: function(xhr, status, error) {\n console.error('[EntitySelector] AJAX error for', blockType, ':', status, error);\n $tab.find('.tab-badge').remove();\n self.updateHeaderTotalCount();\n }\n });\n },\n\n updateHeaderTotalCount: function() {\n var self = this;\n var total = 0;\n\n // Sum up all tab badge counts\n this.$wrapper.find('.target-block-tab .tab-badge').each(function() {\n var $badge = $(this);\n if (!$badge.hasClass('loading')) {\n var count = parseInt($badge.text(), 10);\n if (!isNaN(count)) {\n total += count;\n }\n }\n });\n\n var $totalBadge = this.$wrapper.find('.trait-total-count');\n if (total > 0) {\n $totalBadge.find('.count-value').text(total);\n $totalBadge.show();\n } else {\n $totalBadge.hide();\n }\n\n // Update show-all toggle state\n this.updateShowAllToggle();\n },\n\n updateShowAllToggle: function() {\n var $toggle = this.$wrapper.find('.trait-show-all-toggle');\n if (!$toggle.length) return;\n\n var $checkbox = $toggle.find('.show-all-checkbox');\n var hasData = this.$wrapper.find('.target-block-tab.has-data').length > 0;\n\n // If there's data, uncheck (not showing to all), otherwise check\n $checkbox.prop('checked', !hasData);\n },\n\n updateBlockStatus: function($block) {\n var $status = $block.find('.block-status');\n var blockType = $block.data('blockType');\n var blockDef = this.config.blocks[blockType] || {};\n var trans = this.config.trans || {};\n\n var groups = this.getBlockGroups($block);\n\n if (groups.length === 0) {\n var emptyMeansAll = this.config.emptyMeansAll !== false;\n if (emptyMeansAll) {\n $status.text((trans.all || 'All') + ' ' + (blockDef.entity_label_plural || 'items'));\n } else {\n $status.text(trans.nothing_selected || 'Nothing selected');\n }\n } else {\n $status.text(groups.length + ' ' + (groups.length === 1 ? (trans.group || 'group') : (trans.groups || 'groups')));\n }\n },\n\n getEmptyStateText: function($block) {\n var blockType = $block.data('blockType');\n var blockMode = $block.data('mode') || 'multi';\n var blockDef = this.config.blocks[blockType] || {};\n var trans = this.config.trans || {};\n var emptyMeansAll = this.config.emptyMeansAll !== false;\n\n if (blockMode === 'single') {\n return trans.no_item_selected || 'No item selected';\n }\n\n if (emptyMeansAll) {\n return (trans.all || 'All') + ' ' + (blockDef.entity_label_plural || 'items') + ' ' + (trans.included || 'included');\n }\n\n return trans.nothing_selected || 'Nothing selected';\n },\n\n serializeGroup: function($group, blockType) {\n var self = this;\n\n // Include\n var includeMethod = $group.find('.include-method-select').val() || 'all';\n var $includePicker = $group.find('.include-picker');\n var includeValues = this.getPickerValues($includePicker);\n\n // Excludes (multiple rows)\n var excludes = [];\n var $excludesSection = $group.find('.group-excludes.has-excludes');\n if ($excludesSection.length) {\n $group.find('.exclude-row').each(function() {\n var $row = $(this);\n var excludeMethod = $row.find('.exclude-method-select').val() || null;\n var $excludePicker = $row.find('.exclude-picker');\n var excludeValues = self.getPickerValues($excludePicker);\n\n if (excludeMethod && excludeValues && (Array.isArray(excludeValues) ? excludeValues.length > 0 : true)) {\n excludes.push({\n method: excludeMethod,\n values: excludeValues\n });\n }\n });\n }\n\n var groupData = {\n include: {\n method: includeMethod,\n values: includeValues\n }\n };\n\n if (excludes.length > 0) {\n groupData.excludes = excludes;\n }\n\n // Add modifiers if present\n var modifiers = this.getGroupModifiers($group);\n if (modifiers.limit || modifiers.sort_by) {\n groupData.modifiers = modifiers;\n }\n\n return groupData;\n },\n\n serializeAllBlocks: function($changedRow) {\n var self = this;\n var data = {};\n\n console.log('[EntitySelector] serializeAllBlocks called');\n\n this.$wrapper.find('.target-block').each(function() {\n var $block = $(this);\n var blockType = $block.data('blockType');\n var groups = self.getBlockGroups($block);\n\n console.log('[EntitySelector] Block:', blockType, 'Groups:', groups.length);\n\n // Groups now contain their own modifiers, no block-level modifiers\n if (groups.length > 0) {\n data[blockType] = { groups: groups };\n }\n\n self.updateBlockStatus($block);\n });\n\n // Update hidden input first\n var $input = this.$wrapper.find('input[name=\"' + this.config.name + '\"]');\n var jsonData = JSON.stringify(data);\n\n console.log('[EntitySelector] Hidden input name:', this.config.name);\n console.log('[EntitySelector] Hidden input found:', $input.length);\n console.log('[EntitySelector] Serialized data:', jsonData.substring(0, 500));\n\n $input.val(jsonData);\n\n // Then update tab badges (reads from hidden input)\n this.updateTabBadges();\n\n // Debounced update of condition count - only for changed row if specified\n if (this.countUpdateTimeout) {\n clearTimeout(this.countUpdateTimeout);\n }\n this.countUpdateTimeout = setTimeout(function() {\n if ($changedRow && $changedRow.length) {\n // Update the specific row that changed\n self.updateConditionCount($changedRow);\n // Also update the group total count (include - excludes)\n var $group = $changedRow.closest('.selection-group');\n if ($group.length) {\n self.updateGroupTotalCount($group);\n }\n } else {\n // Fallback: update all counts (initial load, structure changes)\n self.updateAllConditionCounts();\n }\n }, 500);\n },\n\n getBlockGroups: function($block) {\n var self = this;\n var groups = [];\n\n $block.find('.selection-group').each(function() {\n var $group = $(this);\n\n // Include\n var includeMethod = $group.find('.include-method-select').val() || 'all';\n var $includePicker = $group.find('.include-picker');\n var includeValues = self.getPickerValues($includePicker);\n\n // Skip groups with invalid include conditions (e.g., \"specific products\" with none selected)\n if (!self.isConditionValid(includeMethod, includeValues, $includePicker)) {\n return true; // continue to next group\n }\n\n // Excludes (multiple rows) - only include valid ones\n var excludes = [];\n var $excludesSection = $group.find('.group-excludes.has-excludes');\n if ($excludesSection.length) {\n $group.find('.exclude-row').each(function() {\n var $row = $(this);\n var excludeMethod = $row.find('.exclude-method-select').val() || null;\n var $excludePicker = $row.find('.exclude-picker');\n var excludeValues = self.getPickerValues($excludePicker);\n\n // Only include valid exclude conditions\n if (excludeMethod && self.isConditionValid(excludeMethod, excludeValues, $excludePicker)) {\n excludes.push({\n method: excludeMethod,\n values: excludeValues\n });\n }\n });\n }\n\n var groupData = {\n include: {\n method: includeMethod,\n values: includeValues\n }\n };\n\n // Group name (optional, for organizational purposes)\n var groupName = $.trim($group.attr('data-group-name') || '');\n if (groupName) {\n groupData.name = groupName;\n }\n\n if (excludes.length > 0) {\n groupData.excludes = excludes;\n }\n\n // Group-level modifiers\n var modifiers = self.getGroupModifiers($group);\n if (modifiers.limit || modifiers.sort_by) {\n groupData.modifiers = modifiers;\n }\n\n groups.push(groupData);\n });\n\n return groups;\n },\n\n getGroupModifiers: function($group) {\n var limit = $group.find('.group-modifier-limit').val();\n var sortBy = $group.find('.group-modifier-sort').val() || 'sales';\n var $sortDirBtn = $group.find('.group-modifiers .btn-sort-dir');\n var sortDir = $sortDirBtn.data('dir') || 'DESC';\n\n return {\n limit: limit ? parseInt(limit, 10) : null,\n sort_by: sortBy || null,\n sort_dir: sortDir || 'DESC'\n };\n },\n\n getPickerValues: function($picker) {\n var valueType = $picker.attr('data-value-type') || 'entity_search';\n var values = [];\n\n switch (valueType) {\n case 'entity_search':\n $picker.find('.entity-chip').each(function() {\n var id = $(this).data('id');\n values.push(isNaN(id) ? id : Number(id));\n });\n break;\n\n case 'pattern':\n values = this.getPatternTags($picker);\n // Also include draft pattern if it has content (not yet added as tag)\n var $draftInput = $picker.find('.draft-tag .pattern-input');\n var draftPattern = $.trim($draftInput.val());\n if (draftPattern) {\n var draftCaseSensitive = $draftInput.closest('.draft-tag').attr('data-case-sensitive') === '1';\n values.push({\n pattern: draftPattern,\n caseSensitive: draftCaseSensitive\n });\n }\n break;\n\n case 'numeric_range':\n var min = $picker.find('.range-min-input').val();\n var max = $picker.find('.range-max-input').val();\n if (min !== '' || max !== '') {\n values = {\n min: min !== '' ? parseFloat(min) : null,\n max: max !== '' ? parseFloat(max) : null\n };\n }\n break;\n\n case 'date_range':\n var from = $picker.find('.date-from-input').val();\n var to = $picker.find('.date-to-input').val();\n if (from || to) {\n values = {\n from: from || null,\n to: to || null\n };\n }\n break;\n\n case 'select':\n var selectVal = $picker.find('.select-value-input').val();\n if (selectVal) {\n values = [selectVal];\n }\n break;\n\n case 'boolean':\n values = [true];\n break;\n\n case 'multi_numeric_range':\n var ranges = [];\n $picker.find('.range-chip').each(function() {\n var $chip = $(this);\n var minVal = $chip.data('min');\n var maxVal = $chip.data('max');\n ranges.push({\n min: minVal !== '' && minVal !== undefined ? parseFloat(minVal) : null,\n max: maxVal !== '' && maxVal !== undefined ? parseFloat(maxVal) : null\n });\n });\n if (ranges.length > 0) {\n values = ranges;\n }\n break;\n\n case 'multi_select_tiles':\n $picker.find('.tile-option.selected').each(function() {\n values.push($(this).data('value'));\n });\n break;\n\n case 'combination_attributes':\n // Returns object: { mode: 'products'|'combinations', attributes: { groupId: [valueId1, valueId2], ... } }\n var combAttrs = {};\n $picker.find('.comb-attr-value.selected').each(function() {\n var groupId = $(this).data('groupId').toString();\n var valueId = $(this).data('valueId');\n if (!combAttrs[groupId]) {\n combAttrs[groupId] = [];\n }\n combAttrs[groupId].push(valueId);\n });\n if (Object.keys(combAttrs).length > 0) {\n // Get mode: from radio if toggle exists, otherwise from config\n var $combPicker = $picker.find('.combination-attributes-picker');\n var configMode = $combPicker.data('combinationMode') || this.config.combinationMode || 'products';\n var combMode;\n if (configMode === 'toggle') {\n combMode = $picker.find('.comb-mode-radio:checked').val() || 'products';\n } else {\n combMode = configMode;\n }\n values = {\n mode: combMode,\n attributes: combAttrs\n };\n }\n break;\n }\n\n return values;\n },\n\n isConditionValid: function(method, values, $picker) {\n // 'all' method never needs values\n if (method === 'all') {\n return true;\n }\n\n // Boolean methods are always valid (the value is implicit true)\n var valueType = $picker.attr('data-value-type') || 'entity_search';\n if (valueType === 'boolean') {\n return true;\n }\n\n // For other methods, check if values are meaningful\n if (Array.isArray(values)) {\n return values.length > 0;\n }\n\n // For object values (ranges, combination_attributes), check if meaningful\n if (typeof values === 'object' && values !== null) {\n // Special handling for combination_attributes: { mode, attributes }\n if (valueType === 'combination_attributes' && values.attributes !== undefined) {\n return Object.keys(values.attributes).length > 0;\n }\n // For ranges and other objects, check if at least one bound is set\n return Object.keys(values).some(function(key) {\n return values[key] !== null && values[key] !== '';\n });\n }\n\n return false;\n },\n\n /**\n * Update all condition counts using a single bulk AJAX request\n */\n updateAllConditionCounts: function() {\n var self = this;\n var conditions = {};\n var conditionElements = {};\n var conditionIndex = 0;\n\n // Collect all conditions from all active groups\n this.$wrapper.find('.target-block.active .selection-group').each(function() {\n var $group = $(this);\n var $block = $group.closest('.target-block');\n var blockType = $block.data('blockType') || 'products';\n\n // Process include row\n var $include = $group.find('.group-include');\n if ($include.length) {\n var includeData = self.getConditionData($include, blockType);\n if (includeData) {\n var id = 'c' + conditionIndex++;\n conditions[id] = includeData.condition;\n conditionElements[id] = includeData.$countEl;\n }\n }\n\n // Process exclude rows\n $group.find('.exclude-row').each(function() {\n var excludeData = self.getConditionData($(this), blockType);\n if (excludeData) {\n var id = 'c' + conditionIndex++;\n conditions[id] = excludeData.condition;\n conditionElements[id] = excludeData.$countEl;\n }\n });\n });\n\n // If no conditions, nothing to do\n if (Object.keys(conditions).length === 0) {\n return;\n }\n\n // Make single bulk AJAX request\n $.ajax({\n url: this.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'countConditionMatchesBulk',\n trait: 'EntitySelector',\n conditions: JSON.stringify(conditions)\n },\n success: function(response) {\n if (response && response.success && response.counts) {\n // Update each count element with its result\n Object.keys(response.counts).forEach(function(id) {\n var count = response.counts[id] || 0;\n var $countEl = conditionElements[id];\n if ($countEl && $countEl.length) {\n $countEl.removeClass('no-matches clickable');\n if (count === 0) {\n $countEl.find('.preview-count').text(count);\n $countEl.addClass('no-matches').show();\n } else {\n $countEl.find('.preview-count').text(count);\n $countEl.addClass('clickable').show();\n }\n }\n });\n }\n // Note: Group totals are updated on-demand when user interacts, not on initial load\n },\n error: function() {\n // Hide all count elements on error\n Object.keys(conditionElements).forEach(function(id) {\n var $countEl = conditionElements[id];\n if ($countEl && $countEl.length) {\n $countEl.hide().removeClass('clickable');\n }\n });\n }\n });\n },\n\n /**\n * Extract condition data from a row for bulk counting\n */\n getConditionData: function($row, blockType) {\n console.log('[getConditionData] Called with blockType:', blockType);\n var $countEl = $row.find('.method-selector-wrapper > .condition-match-count, > .exclude-header-row .condition-match-count').first();\n console.log('[getConditionData] $countEl found:', $countEl.length);\n if (!$countEl.length) return null;\n\n var isExclude = $row.hasClass('exclude-row');\n var $methodSelect = isExclude\n ? $row.find('.exclude-method-select')\n : $row.find('.include-method-select');\n\n var method = $methodSelect.val();\n console.log('[getConditionData] method:', method);\n if (!method) {\n $countEl.hide();\n return null;\n }\n\n var $picker = isExclude\n ? $row.find('.exclude-picker')\n : $row.find('.include-picker');\n console.log('[getConditionData] $picker found:', $picker.length, 'data-value-type attr:', $picker.attr('data-value-type'));\n\n var valueType = $picker.data('valueType') || $picker.attr('data-value-type') || 'none';\n console.log('[getConditionData] valueType:', valueType);\n\n // Special case: \"All countries\" method - needs separate handling for holidays\n if (valueType === 'none' && blockType === 'countries' && method === 'all') {\n console.log('[getConditionData] All countries detected - triggering updateConditionCount');\n // Trigger separate update for this special case (uses nested AJAX)\n var self = this;\n setTimeout(function() {\n self.updateConditionCount($row, blockType);\n }, 0);\n return null; // Skip bulk processing, handled separately\n }\n\n // Special case: Specific countries with entity_search - needs holiday counting, not entity counting\n var searchEntity = $picker.attr('data-search-entity') || '';\n if (blockType === 'countries' && valueType === 'entity_search' && searchEntity === 'countries') {\n console.log('[getConditionData] Specific countries detected - triggering updateConditionCount for holiday counting');\n var self = this;\n setTimeout(function() {\n self.updateConditionCount($row, blockType);\n }, 0);\n return null; // Skip bulk processing, handled separately\n }\n\n // Hide badge for other \"all\" type methods (valueType === 'none') since they don't filter\n if (valueType === 'none') {\n $countEl.hide();\n return null;\n }\n\n var values = this.getPickerValues($picker, valueType);\n\n // Don't count if no values (except for boolean methods)\n var hasNoValues = !values ||\n (Array.isArray(values) && values.length === 0) ||\n (typeof values === 'object' && !Array.isArray(values) && (\n (valueType === 'combination_attributes' && values.attributes !== undefined && Object.keys(values.attributes).length === 0) ||\n (valueType !== 'combination_attributes' && Object.keys(values).length === 0)\n ));\n if (valueType !== 'boolean' && hasNoValues) {\n $countEl.hide();\n return null;\n }\n\n // Show loading spinner\n $countEl.find('.preview-count').html('');\n $countEl.removeClass('clickable no-matches').show();\n\n // Store condition data on badge for popover\n $countEl.data('conditionData', {\n method: method,\n values: values,\n blockType: blockType,\n isExclude: isExclude\n });\n\n return {\n condition: {\n method: method,\n values: values,\n block_type: blockType\n },\n $countEl: $countEl\n };\n },\n\n updateGroupCounts: function($group) {\n var self = this;\n var $block = $group.closest('.target-block');\n var blockType = $block.data('blockType') || 'products';\n\n // Update include count\n var $include = $group.find('.group-include');\n if ($include.length) {\n this.updateConditionCount($include, blockType);\n }\n\n // Update each exclude row count\n $group.find('.exclude-row').each(function() {\n self.updateConditionCount($(this), blockType);\n });\n\n // Update group total count (include - excludes)\n this.updateGroupTotalCount($group);\n },\n\n /**\n * Update a single condition count (used for individual updates after user changes)\n */\n updateConditionCount: function($row, blockType) {\n var self = this;\n\n var $countEl = $row.find('.method-selector-wrapper > .condition-match-count, > .exclude-header-row .condition-match-count').first();\n if (!$countEl.length) {\n console.log('[updateConditionCount] No $countEl found');\n return;\n }\n\n var isExclude = $row.hasClass('exclude-row');\n var $methodSelect = isExclude\n ? $row.find('.exclude-method-select')\n : $row.find('.include-method-select');\n\n var method = $methodSelect.val();\n console.log('[updateConditionCount] method:', method, 'isExclude:', isExclude);\n if (!method) {\n console.log('[updateConditionCount] No method, hiding badge');\n $countEl.hide();\n return;\n }\n\n var $picker = isExclude\n ? $row.find('.exclude-picker')\n : $row.find('.include-picker');\n\n var valueType = $picker.data('valueType') || 'none';\n var searchEntity = $picker.attr('data-search-entity') || '';\n\n // Get the block type to check if this is a countries block\n if (!blockType) {\n var $block = $row.closest('.target-block');\n blockType = $block.data('blockType') || 'products';\n }\n\n console.log('[updateConditionCount] valueType:', valueType, 'searchEntity:', searchEntity, 'blockType:', blockType, 'method:', method);\n\n // Special case: \"All countries\" method - fetch holidays for all countries\n if (valueType === 'none' && blockType === 'countries' && method === 'all') {\n console.log('[updateConditionCount] All countries method - fetching all country holidays');\n $countEl.find('.preview-count').html('');\n $countEl.removeClass('clickable no-matches country-holidays').show();\n\n // First fetch all active country IDs, then get holidays\n $.ajax({\n url: self.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'searchTargetEntities',\n trait: 'EntitySelector',\n entity_type: 'countries',\n query: '',\n limit: 500\n },\n success: function(response) {\n var items = response.results || response.items || [];\n if (response && response.success && items.length > 0) {\n var allCountryIds = items.map(function(item) { return item.id; });\n console.log('[updateConditionCount] Found', allCountryIds.length, 'countries, fetching holidays');\n\n // Store condition data for click handler\n $countEl.data('conditionData', {\n method: method,\n values: allCountryIds,\n blockType: blockType,\n isExclude: isExclude,\n isCountryHolidays: true,\n countryIds: allCountryIds,\n isAllCountries: true\n });\n\n // Now fetch holiday count\n $.ajax({\n url: self.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'getHolidaysForCountries',\n trait: 'EntitySelector',\n country_ids: allCountryIds.join(','),\n count_only: 1\n },\n success: function(holidayResponse) {\n console.log('[updateConditionCount] All countries holiday response:', holidayResponse);\n if (holidayResponse && holidayResponse.success) {\n var count = holidayResponse.total_count || 0;\n $countEl.removeClass('no-matches clickable');\n $countEl.addClass('country-holidays');\n if (count === 0) {\n $countEl.find('.preview-count').text(count);\n $countEl.addClass('no-matches').show();\n } else {\n $countEl.find('.preview-count').text(count);\n $countEl.addClass('clickable').show();\n }\n $countEl.data('countriesInfo', holidayResponse.countries || []);\n } else {\n $countEl.hide().removeClass('clickable');\n }\n },\n error: function() {\n $countEl.hide().removeClass('clickable');\n }\n });\n } else {\n $countEl.hide().removeClass('clickable');\n }\n },\n error: function() {\n $countEl.hide().removeClass('clickable');\n }\n });\n return;\n }\n\n // Hide badge for other \"all\" type methods (valueType === 'none') since they don't filter\n if (valueType === 'none') {\n console.log('[updateConditionCount] valueType is none, hiding badge');\n $countEl.hide();\n return;\n }\n\n var values = this.getPickerValues($picker, valueType);\n\n var hasNoValues = !values ||\n (Array.isArray(values) && values.length === 0) ||\n (typeof values === 'object' && !Array.isArray(values) && (\n (valueType === 'combination_attributes' && values.attributes !== undefined && Object.keys(values.attributes).length === 0) ||\n (valueType !== 'combination_attributes' && Object.keys(values).length === 0)\n ));\n if (valueType !== 'boolean' && hasNoValues) {\n $countEl.hide();\n return;\n }\n\n if (!blockType) {\n var $block = $row.closest('.target-block');\n blockType = $block.data('blockType') || 'products';\n }\n\n // Check if this is a country selection - show holiday count instead\n var isCountrySelection = (searchEntity === 'countries' && valueType === 'entity_search');\n console.log('[updateConditionCount] isCountrySelection:', isCountrySelection, 'values:', values);\n\n $countEl.find('.preview-count').html('');\n $countEl.removeClass('clickable no-matches country-holidays').show();\n\n // For countries, fetch holiday count\n if (isCountrySelection && Array.isArray(values) && values.length > 0) {\n console.log('[updateConditionCount] Fetching holiday count for countries:', values);\n $countEl.data('conditionData', {\n method: method,\n values: values,\n blockType: blockType,\n isExclude: isExclude,\n isCountryHolidays: true,\n countryIds: values\n });\n\n $.ajax({\n url: self.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'getHolidaysForCountries',\n trait: 'EntitySelector',\n country_ids: values.join(','),\n count_only: 1\n },\n success: function(response) {\n console.log('[updateConditionCount] Holiday response:', response);\n if (response && response.success) {\n var count = response.total_count || 0;\n console.log('[updateConditionCount] Holiday count:', count);\n $countEl.removeClass('no-matches clickable');\n $countEl.addClass('country-holidays');\n if (count === 0) {\n $countEl.find('.preview-count').text(count);\n $countEl.addClass('no-matches').show();\n } else {\n $countEl.find('.preview-count').text(count);\n $countEl.addClass('clickable').show();\n }\n // Store countries info for popover\n $countEl.data('countriesInfo', response.countries || []);\n } else {\n console.log('[updateConditionCount] Holiday response failed:', response);\n $countEl.hide().removeClass('clickable');\n }\n },\n error: function() {\n $countEl.hide().removeClass('clickable');\n }\n });\n return;\n }\n\n // Default: count entities\n $countEl.data('conditionData', {\n method: method,\n values: values,\n blockType: blockType,\n isExclude: isExclude\n });\n\n $.ajax({\n url: this.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'countConditionMatches',\n trait: 'EntitySelector',\n method: method,\n values: JSON.stringify(values),\n block_type: blockType\n },\n success: function(response) {\n if (response && response.success) {\n var count = response.count || 0;\n $countEl.removeClass('no-matches clickable');\n if (count === 0) {\n $countEl.find('.preview-count').text(count);\n $countEl.addClass('no-matches').show();\n } else {\n $countEl.find('.preview-count').text(count);\n $countEl.addClass('clickable').show();\n }\n } else {\n $countEl.hide().removeClass('clickable');\n }\n },\n error: function() {\n $countEl.hide().removeClass('clickable');\n }\n });\n },\n\n updateGroupTotalCount: function($group) {\n var self = this;\n var $block = $group.closest('.target-block');\n var blockType = $block.data('blockType') || 'products';\n var $badge = $group.find('.group-header .group-count-badge');\n var $limitInput = $group.find('.group-modifier-limit');\n\n // Build group data for AJAX\n var groupData = this.serializeGroup($group, blockType);\n\n // Check if include has valid data\n if (!groupData.include || !groupData.include.method) {\n $badge.hide();\n $limitInput.attr('placeholder', '–');\n return;\n }\n\n // Show loading\n $badge.html('').show();\n\n $.ajax({\n url: this.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'countGroupItems',\n trait: 'EntitySelector',\n group_data: JSON.stringify(groupData),\n block_type: blockType\n },\n success: function(response) {\n if (response && response.success) {\n var finalCount = response.final_count || 0;\n var excludeCount = response.exclude_count || 0;\n\n // Update badge with eye icon and count\n var badgeHtml = ' ' + finalCount;\n if (excludeCount > 0) {\n badgeHtml += ' (-' + excludeCount + ')';\n }\n $badge.html(badgeHtml);\n $badge.addClass('clickable').show();\n\n // Store group data on badge for preview popover\n $badge.data('groupData', groupData);\n $badge.data('blockType', blockType);\n $badge.data('finalCount', finalCount);\n\n // Update limit placeholder with the count\n $limitInput.attr('placeholder', finalCount);\n\n // Also update the group-preview-badge count (apply limit if set)\n var $previewBadge = $group.find('.group-preview-badge .preview-count');\n if ($previewBadge.length) {\n var limit = parseInt($limitInput.val(), 10);\n var displayCount = (limit > 0 && limit < finalCount) ? limit : finalCount;\n $previewBadge.text(displayCount);\n }\n } else {\n $badge.hide().removeClass('clickable');\n $limitInput.attr('placeholder', '–');\n }\n },\n error: function() {\n $badge.hide();\n $limitInput.attr('placeholder', '–');\n }\n });\n },\n\n // Exclude row management\n addFirstExcludeRow: function($group, $block) {\n var $excludesDiv = $group.find('.group-excludes');\n var trans = this.config.trans || {};\n\n // Build the full excludes structure with first row\n var html = '
';\n html += ' ' + (trans.except || 'EXCEPT') + '';\n html += '
';\n\n html += '
';\n html += this.buildExcludeRowHtml($block, 0);\n html += '
';\n\n html += '';\n\n $excludesDiv.addClass('has-excludes').html(html);\n\n // Enhance the first exclude method select with styled dropdown\n var $firstRow = $excludesDiv.find('.exclude-row[data-exclude-index=\"0\"]');\n var $firstSelect = $firstRow.find('.exclude-method-select');\n this.enhanceMethodSelect($firstSelect);\n\n // Update method info placeholder for initial selection\n var blockType = $block.data('blockType');\n var initialMethod = $firstSelect.val();\n this.updateMethodInfoPlaceholder($firstRow.find('.method-selector-wrapper'), initialMethod, blockType);\n\n this.updateMethodSelectorLock($group, true);\n this.serializeAllBlocks();\n },\n\n addExcludeRow: function($group, $block) {\n var $container = $group.find('.exclude-rows-container');\n\n // Get next exclude index\n var maxIndex = -1;\n $container.find('.exclude-row').each(function() {\n var idx = parseInt($(this).data('excludeIndex'), 10);\n if (idx > maxIndex) maxIndex = idx;\n });\n var excludeIndex = maxIndex + 1;\n\n var html = this.buildExcludeRowHtml($block, excludeIndex);\n $container.append(html);\n\n // Enhance the exclude method select with styled dropdown\n var $newRow = $container.find('.exclude-row[data-exclude-index=\"' + excludeIndex + '\"]');\n var $newSelect = $newRow.find('.exclude-method-select');\n this.enhanceMethodSelect($newSelect);\n\n // Update method info placeholder for initial selection\n var blockType = $block.data('blockType');\n var initialMethod = $newSelect.val();\n this.updateMethodInfoPlaceholder($newRow.find('.method-selector-wrapper'), initialMethod, blockType);\n\n this.serializeAllBlocks();\n },\n\n buildExcludeRowHtml: function($block, excludeIndex) {\n var blockType = $block.data('blockType');\n var blockDef = this.config.blocks[blockType] || {};\n var methods = blockDef.selection_methods || {};\n var trans = this.config.trans || {};\n\n // Build exclude method options with optgroups (no \"all\")\n var excludeMethodOptions = this.buildMethodOptions(methods, true);\n\n // Find first non-all method for default search entity\n var firstSearchEntity = blockType;\n var firstValueType = 'entity_search';\n $.each(methods, function(methodKey, methodDef) {\n if (methodKey === 'all') return true;\n firstSearchEntity = methodDef.search_entity || blockType;\n firstValueType = methodDef.value_type || 'entity_search';\n return false; // break\n });\n\n var html = '
';\n\n // Header row with method select wrapped in method-selector-wrapper (same as include)\n html += '
';\n html += '
';\n html += '';\n html += ' 0';\n html += '';\n html += '
';\n html += '';\n html += '
';\n\n // Value picker based on first method's value type\n html += this.buildValuePickerHtml('exclude', firstValueType, firstSearchEntity, methods);\n\n html += '
';\n\n return html;\n },\n\n removeExcludeRow: function($excludeRow, $group, $block) {\n var $container = $group.find('.exclude-rows-container');\n var trans = this.config.trans || {};\n\n $excludeRow.remove();\n\n // Check if there are remaining exclude rows\n var remainingRows = $container.find('.exclude-row').length;\n\n if (remainingRows === 0) {\n // Remove entire excludes section and show \"Add exceptions\" button\n var $excludesDiv = $group.find('.group-excludes');\n $excludesDiv.removeClass('has-excludes').html(\n ''\n );\n // Unlock the method selector since no excludes exist\n this.updateMethodSelectorLock($group, false);\n }\n\n this.serializeAllBlocks();\n },\n\n // Method options building\n buildMethodOptions: function(methods, excludeAll) {\n var self = this;\n var trans = this.config.trans || {};\n var html = '';\n\n // Group labels\n var groupLabels = {\n 'select_by': trans.select_by || 'Select by...',\n 'filter_by': trans.filter_by || 'Filter by...'\n };\n\n // Separate methods by group\n var grouped = {};\n var ungrouped = {};\n\n $.each(methods, function(methodKey, methodDef) {\n if (excludeAll && methodKey === 'all') return true; // skip\n\n var group = methodDef.group || '';\n if (group) {\n if (!grouped[group]) {\n grouped[group] = {};\n }\n grouped[group][methodKey] = methodDef;\n } else {\n ungrouped[methodKey] = methodDef;\n }\n });\n\n // Render ungrouped options first\n $.each(ungrouped, function(methodKey, methodDef) {\n html += self.buildMethodOption(methodKey, methodDef);\n });\n\n // Render grouped options with optgroups\n $.each(grouped, function(groupKey, groupMethods) {\n var groupLabel = groupLabels[groupKey] || groupKey.replace(/_/g, ' ');\n html += '';\n $.each(groupMethods, function(methodKey, methodDef) {\n html += self.buildMethodOption(methodKey, methodDef);\n });\n html += '';\n });\n\n return html;\n },\n\n buildMethodOption: function(methodKey, methodDef) {\n var html = '
';\n\n $chips.append(html);\n },\n\n removeSelection: function($picker, id) {\n var $chips = $picker.find('.entity-chips');\n $picker.find('.entity-chip[data-id=\"' + id + '\"]').remove();\n this.updateChipsVisibility($chips);\n },\n\n updateChipsVisibility: function($chips) {\n var self = this;\n var trans = this.config.trans || {};\n var $picker = $chips.closest('.value-picker');\n var $allChips = $chips.find('.entity-chip');\n var totalCount = $allChips.length;\n\n // If no chips, remove the wrapper entirely\n var $existingWrapper = $chips.closest('.chips-wrapper');\n if (totalCount === 0) {\n if ($existingWrapper.length) {\n // Move chips out of wrapper before removing\n $existingWrapper.before($chips);\n $existingWrapper.remove();\n }\n return;\n }\n\n // Ensure chips wrapper structure exists\n this.ensureChipsWrapper($chips);\n\n var $wrapper = $chips.closest('.chips-wrapper');\n var $toolbar = $wrapper.find('.chips-toolbar');\n var $loadMore = $wrapper.find('.chips-load-more');\n\n // Get current search filter\n var searchTerm = $toolbar.find('.chips-search-input').val() || '';\n searchTerm = searchTerm.toLowerCase().trim();\n\n // Filter and paginate chips\n var visibleCount = 0;\n var filteredCount = 0;\n var isExpanded = $chips.hasClass('chips-expanded');\n var maxVisible = isExpanded ? 999999 : (this.maxVisibleChips || 12);\n\n $allChips.each(function() {\n var $chip = $(this);\n var chipName = ($chip.find('.chip-name').text() || '').toLowerCase();\n var matchesFilter = !searchTerm || chipName.indexOf(searchTerm) !== -1;\n\n $chip.removeClass('chip-filtered-out chip-paginated-out');\n\n if (!matchesFilter) {\n $chip.addClass('chip-filtered-out');\n } else {\n filteredCount++;\n if (filteredCount > maxVisible) {\n $chip.addClass('chip-paginated-out');\n } else {\n visibleCount++;\n }\n }\n });\n\n // Update toolbar (always show when we have chips)\n $toolbar.addClass('has-chips');\n this.updateChipsToolbar($toolbar, totalCount, filteredCount, searchTerm);\n\n // Update load more select dropdown\n var hiddenByPagination = filteredCount - visibleCount;\n if (hiddenByPagination > 0 && !isExpanded) {\n var loadText = trans.load || 'Load';\n var remainingText = (trans.remaining || '{count} remaining').replace('{count}', hiddenByPagination);\n var loadMoreHtml = '' + loadText + '' +\n '' +\n '' + remainingText + '';\n $loadMore.html(loadMoreHtml).show();\n } else if (isExpanded && filteredCount > (this.maxVisibleChips || 12)) {\n var collapseText = trans.collapse || 'Collapse';\n $loadMore.html(\n ''\n ).show();\n } else {\n $loadMore.hide();\n }\n },\n\n ensureChipsWrapper: function($chips) {\n // Check if already wrapped\n if ($chips.closest('.chips-wrapper').length) {\n return;\n }\n\n var trans = this.config.trans || {};\n var $picker = $chips.closest('.value-picker');\n\n // Create wrapper structure - integrated filter toolbar with sort\n var wrapperHtml = '
' +\n '
' +\n '' +\n '' +\n '' +\n '' +\n '
' +\n '
' +\n '
';\n\n var $wrapper = $(wrapperHtml);\n\n // Insert wrapper before chips and move chips inside\n $chips.before($wrapper);\n $wrapper.find('.chips-toolbar').after($chips);\n $wrapper.append($wrapper.find('.chips-load-more'));\n\n // Bind toolbar events\n this.bindChipsToolbarEvents($wrapper);\n },\n\n bindChipsToolbarEvents: function($wrapper) {\n var self = this;\n var $chips = $wrapper.find('.entity-chips');\n var searchTimeout;\n\n // Search input\n $wrapper.on('input', '.chips-search-input', function() {\n clearTimeout(searchTimeout);\n searchTimeout = setTimeout(function() {\n // Collapse when searching to show filtered results from start\n $chips.removeClass('chips-expanded');\n self.updateChipsVisibility($chips);\n }, 150);\n });\n\n // Sort select\n $wrapper.on('change', '.chips-sort-select', function() {\n var sortBy = $(this).val();\n self.sortChips($chips, sortBy);\n });\n\n // Clear all button\n $wrapper.on('click', '.btn-chips-clear', function() {\n var searchTerm = $wrapper.find('.chips-search-input').val() || '';\n var $chipsToRemove;\n\n if (searchTerm.trim()) {\n // Remove only filtered (visible) chips\n $chipsToRemove = $chips.find('.entity-chip:not(.chip-filtered-out)');\n } else {\n // Remove all chips\n $chipsToRemove = $chips.find('.entity-chip');\n }\n\n $chipsToRemove.each(function() {\n $(this).find('.chip-remove').trigger('click');\n });\n\n // Clear search\n $wrapper.find('.chips-search-input').val('');\n self.updateChipsVisibility($chips);\n });\n\n // Load more select dropdown\n $wrapper.on('change', '.load-more-select', function() {\n var loadCount = $(this).val();\n if (loadCount === 'all') {\n $chips.addClass('chips-expanded');\n self.maxVisibleChips = 999999;\n } else {\n self.maxVisibleChips = (self.maxVisibleChips || 12) + parseInt(loadCount, 10);\n }\n self.updateChipsVisibility($chips);\n });\n\n // Collapse button\n $wrapper.on('click', '.btn-collapse-chips', function() {\n $chips.removeClass('chips-expanded');\n self.maxVisibleChips = 12;\n self.updateChipsVisibility($chips);\n });\n },\n\n /**\n * Sort chips by specified criteria\n */\n sortChips: function($chips, sortBy) {\n var $allChips = $chips.find('.entity-chip');\n if ($allChips.length < 2) return;\n\n var sorted = $allChips.toArray().sort(function(a, b) {\n var $a = $(a);\n var $b = $(b);\n\n switch (sortBy) {\n case 'name_asc':\n var nameA = ($a.find('.chip-name').text() || '').toLowerCase();\n var nameB = ($b.find('.chip-name').text() || '').toLowerCase();\n return nameA.localeCompare(nameB);\n case 'name_desc':\n var nameA2 = ($a.find('.chip-name').text() || '').toLowerCase();\n var nameB2 = ($b.find('.chip-name').text() || '').toLowerCase();\n return nameB2.localeCompare(nameA2);\n case 'added':\n default:\n // Keep original DOM order (order added)\n return 0;\n }\n });\n\n // Re-append in sorted order\n $.each(sorted, function(i, chip) {\n $chips.append(chip);\n });\n\n this.updateChipsVisibility($chips);\n },\n\n updateChipsToolbar: function($toolbar, totalCount, filteredCount, searchTerm) {\n var trans = this.config.trans || {};\n var $count = $toolbar.find('.chips-count');\n var $clearBtn = $toolbar.find('.btn-chips-clear');\n var $clearText = $clearBtn.find('.clear-text');\n\n // Update count display\n if (searchTerm) {\n $count.addClass('has-filter').html(\n '' + filteredCount + '' +\n '/' +\n '' + totalCount + ''\n );\n $clearText.text((trans.clear || 'Clear') + ' ' + filteredCount);\n } else {\n $count.removeClass('has-filter').html(totalCount);\n $clearText.text(trans.clear_all || 'Clear all');\n }\n\n // Show/hide clear button\n if (searchTerm && filteredCount === 0) {\n $clearBtn.hide();\n } else if (totalCount > 0) {\n $clearBtn.show();\n } else {\n $clearBtn.hide();\n }\n },\n\n // =========================================================================\n // Loading/Initialization\n // =========================================================================\n\n loadExistingSelections: function() {\n var self = this;\n console.log('[EntitySelector] loadExistingSelections called for id:', this.config.id);\n\n // Collect all entity IDs to load, grouped by entity type\n var entitiesToLoad = {}; // { entity_type: { ids: [], pickers: [] } }\n\n console.log('[EntitySelector] Looking for .selection-group in wrapper:', this.$wrapper.length ? 'found' : 'NOT FOUND');\n this.$wrapper.find('.selection-group').each(function() {\n console.log('[EntitySelector] Found .selection-group, index:', $(this).data('groupIndex'));\n var $group = $(this);\n var $block = $group.closest('.target-block');\n var blockType = $block.data('blockType');\n\n // Load include values\n var $includePicker = $group.find('.include-picker');\n self.collectPickerEntities($includePicker, blockType, entitiesToLoad);\n\n // Enhance the include method select if not already enhanced\n self.enhanceMethodSelect($group.find('.include-method-select'));\n\n // Load exclude values from each exclude row\n $group.find('.exclude-row').each(function() {\n var $excludeRow = $(this);\n self.collectPickerEntities($excludeRow.find('.exclude-picker'), blockType, entitiesToLoad);\n\n // Enhance the exclude method select if not already enhanced\n self.enhanceMethodSelect($excludeRow.find('.exclude-method-select'));\n });\n\n // Lock method selector if excludes exist\n var hasExcludes = $group.find('.group-excludes.has-excludes').length > 0;\n if (hasExcludes) {\n self.updateMethodSelectorLock($group, true);\n }\n });\n\n // Build bulk request: { entityType: [uniqueIds], ... }\n var bulkRequest = {};\n var hasEntities = false;\n\n Object.keys(entitiesToLoad).forEach(function(entityType) {\n var data = entitiesToLoad[entityType];\n if (data.ids.length === 0) return;\n\n // Deduplicate IDs\n var uniqueIds = data.ids.filter(function(id, index, arr) {\n return arr.indexOf(id) === index;\n });\n\n bulkRequest[entityType] = uniqueIds;\n hasEntities = true;\n });\n\n // Skip AJAX if no entities to load\n if (!hasEntities) {\n console.log('[EntitySelector] No entities to load, skipping AJAX');\n return;\n }\n\n console.log('[EntitySelector] Making bulk AJAX request for entities:', JSON.stringify(bulkRequest));\n\n // Single bulk AJAX call for all entity types\n $.ajax({\n url: self.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'getTargetEntitiesByIdsBulk',\n trait: 'EntitySelector',\n entities: JSON.stringify(bulkRequest)\n },\n success: function(response) {\n console.log('[EntitySelector] AJAX response:', response);\n if (!response.success || !response.entities) {\n console.log('[EntitySelector] Response failed or no entities');\n return;\n }\n try {\n\n // Process each entity type's results\n Object.keys(entitiesToLoad).forEach(function(entityType) {\n var data = entitiesToLoad[entityType];\n var entities = response.entities[entityType] || [];\n\n // Build a map of id -> entity for quick lookup\n var entityMap = {};\n entities.forEach(function(entity) {\n entityMap[entity.id] = entity;\n });\n\n // Update each picker that requested this entity type\n data.pickers.forEach(function(pickerData) {\n var $picker = pickerData.$picker;\n var $chips = $picker.find('.entity-chips');\n var $dataInput = $picker.find('.include-values-data, .exclude-values-data');\n var validIds = [];\n\n // Check if this is a country entity\n var isCountry = (entityType === 'countries');\n\n // Replace loading chips with real data\n pickerData.ids.forEach(function(id) {\n var $loadingChip = $chips.find('.entity-chip-loading[data-id=\"' + id + '\"]');\n if (entityMap[id]) {\n var entity = entityMap[id];\n validIds.push(entity.id);\n\n // Create real chip\n var html = '' + self.esIcon('flag', 'flag-fallback').replace('>', ' style=\"display:none\">') + '';\n } else if (entity.image) {\n html += '\"\"';\n }\n\n html += '' + self.escapeHtml(entity.name) + '';\n\n // Country: add holiday preview button\n if (isCountry) {\n html += '';\n }\n\n html += '';\n html += '
';\n\n $loadingChip.replaceWith(html);\n } else {\n // Entity not found, remove loading chip\n $loadingChip.remove();\n }\n });\n\n // Update chips visibility\n self.updateChipsVisibility($chips);\n\n // If some entities were not found, update the hidden input\n if (validIds.length !== pickerData.ids.length) {\n $dataInput.val(JSON.stringify(validIds));\n self.serializeAllBlocks();\n }\n\n self.updateBlockStatus($picker.closest('.target-block'));\n });\n });\n\n // Update condition counts after chips are loaded (for holiday counts, etc.)\n self.updateAllConditionCounts();\n\n } catch (e) {\n console.error('[EntitySelector] Error processing AJAX response:', e);\n }\n },\n error: function(xhr, status, error) {\n console.error('[EntitySelector] AJAX request failed:', status, error, xhr.responseText);\n }\n });\n },\n\n /**\n * Collect entity IDs from a picker for bulk loading\n * Also shows loading placeholders for entity_search types\n */\n collectPickerEntities: function($picker, blockType, entitiesToLoad) {\n console.log('[EntitySelector] collectPickerEntities called, blockType:', blockType, 'picker length:', $picker.length);\n if (!$picker.length) {\n console.log('[EntitySelector] Picker not found, returning');\n return;\n }\n\n var self = this;\n var $dataInput = $picker.find('.include-values-data, .exclude-values-data');\n console.log('[EntitySelector] Looking for values-data input, found:', $dataInput.length);\n if (!$dataInput.length) {\n console.log('[EntitySelector] No data input found, returning');\n return;\n }\n\n var valueType = $picker.attr('data-value-type');\n var rawValue = $dataInput.val() || '[]';\n console.log('[EntitySelector] valueType:', valueType, 'rawValue:', rawValue);\n\n var values = [];\n try {\n values = JSON.parse(rawValue);\n console.log('[EntitySelector] Parsed values:', values);\n } catch (e) {\n console.log('[EntitySelector] JSON parse error:', e);\n return;\n }\n\n // Handle non-entity types synchronously\n if (valueType === 'multi_numeric_range') {\n if (!Array.isArray(values) || values.length === 0) return;\n\n var $chipsContainer = $picker.find('.multi-range-chips');\n values.forEach(function(range) {\n if (!range || (range.min === null && range.max === null)) return;\n\n var chipText = '';\n if (range.min !== null && range.max !== null) {\n chipText = range.min + ' - ' + range.max;\n } else if (range.min !== null) {\n chipText = '≥ ' + range.min;\n } else {\n chipText = '≤ ' + range.max;\n }\n\n var $chip = $('', {\n class: 'range-chip',\n 'data-min': range.min !== null ? range.min : '',\n 'data-max': range.max !== null ? range.max : ''\n });\n $chip.append($('', { class: 'range-chip-text', text: chipText }));\n $chip.append($('';\n html += '' + this.escapeHtml(pattern) + '';\n html += '';\n html += '';\n $chipsContainer.append(html);\n },\n\n /**\n * Get all pattern tags from a wrapper\n * Returns array of objects: { pattern: string, caseSensitive: boolean }\n */\n getPatternTags: function($wrapper) {\n var patterns = [];\n // Exclude draft-tag which is the input field, not a saved pattern\n $wrapper.find('.pattern-tag:not(.draft-tag)').each(function() {\n var pattern = $(this).data('pattern');\n var caseSensitive = $(this).data('caseSensitive') === 1 || $(this).data('caseSensitive') === '1';\n if (pattern) {\n patterns.push({\n pattern: pattern,\n caseSensitive: caseSensitive\n });\n }\n });\n return patterns;\n },\n\n /**\n * Update the match count displayed in the draft tag while typing\n * Shows live preview with current case sensitivity setting\n */\n updateDraftTagCount: function($draftTag, pattern, caseSensitive) {\n var self = this;\n var $matchCount = $draftTag.find('.pattern-match-count');\n var $countValue = $matchCount.find('.count-value');\n\n // Get entity type from block\n var $block = $draftTag.closest('.target-block');\n var entityType = $block.data('blockType') || 'products';\n\n // Show loading - keep eye icon, update count value\n $countValue.html(this.esIcon('progress_activity', 'es-spin'));\n $matchCount.show();\n\n // Store pattern for click handler\n $matchCount.data('pattern', pattern);\n $matchCount.data('caseSensitive', caseSensitive);\n $matchCount.data('entityType', entityType);\n\n $.ajax({\n url: this.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'countPatternMatches',\n trait: 'EntitySelector',\n pattern: pattern,\n field: 'name',\n entity_type: entityType,\n case_sensitive: caseSensitive ? 1 : 0\n },\n success: function(response) {\n if (response.success) {\n var count = parseInt(response.count, 10) || 0;\n $countValue.text(count);\n $matchCount.show();\n // Add visual feedback based on count\n $matchCount.removeClass('count-zero count-found');\n $matchCount.addClass(count === 0 ? 'count-zero' : 'count-found');\n // Store count for preview\n $matchCount.data('count', count);\n // Update group total count to reflect draft pattern in calculation\n var $group = $draftTag.closest('.selection-group');\n if ($group.length) {\n self.updateGroupTotalCount($group);\n }\n } else {\n $countValue.text('?');\n $matchCount.show();\n }\n },\n error: function() {\n $countValue.text('?');\n $matchCount.show();\n }\n });\n },\n\n /**\n * Update condition count with a pending pattern (typed but not yet added as tag)\n * This shows a live preview of what the count would be if the user pressed Enter\n */\n updateConditionCountWithPendingPattern: function($row, pendingPattern) {\n var self = this;\n var trans = this.config.trans || {};\n\n // Find the count element - in method-selector-wrapper for include, in exclude-header-row for exclude\n var $countEl = $row.find('.method-selector-wrapper > .condition-match-count, > .exclude-header-row > .condition-match-count').first();\n if (!$countEl.length) return;\n\n var isExclude = $row.hasClass('exclude-row');\n var $methodSelect = isExclude\n ? $row.find('.exclude-method-select')\n : $row.find('.include-method-select');\n\n var method = $methodSelect.val();\n if (!method) {\n $countEl.hide();\n return;\n }\n\n var $picker = isExclude\n ? $row.find('.exclude-picker')\n : $row.find('.include-picker');\n\n var valueType = $picker.data('valueType') || 'none';\n\n // Only process for pattern value types\n if (valueType !== 'pattern') {\n return;\n }\n\n // Get existing pattern tags\n var values = this.getPatternTags($picker);\n\n // Add the pending pattern as a temporary tag (case-insensitive by default)\n if (pendingPattern) {\n values.push({ pattern: pendingPattern, caseSensitive: false });\n }\n\n if (values.length === 0) {\n $countEl.hide();\n return;\n }\n\n var $block = $row.closest('.target-block');\n var blockType = $block.data('blockType') || 'products';\n\n // Show loading\n $countEl.find('.preview-count').html(this.esIcon('progress_activity', 'es-spin'));\n $countEl.removeClass('clickable no-matches').show();\n\n // Store condition data on badge for popover\n $countEl.data('conditionData', {\n method: method,\n values: values,\n blockType: blockType,\n isExclude: isExclude\n });\n\n $.ajax({\n url: this.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'countConditionMatches',\n trait: 'EntitySelector',\n method: method,\n values: JSON.stringify(values),\n block_type: blockType\n },\n success: function(response) {\n if (response && response.success) {\n var count = response.count || 0;\n $countEl.removeClass('no-matches clickable');\n if (count === 0) {\n $countEl.find('.preview-count').text(count);\n $countEl.addClass('no-matches').show();\n } else {\n $countEl.find('.preview-count').text(count);\n $countEl.addClass('clickable').show();\n }\n } else {\n $countEl.hide().removeClass('clickable');\n }\n },\n error: function() {\n $countEl.hide().removeClass('clickable');\n }\n });\n },\n\n /**\n * Fetch pattern match count via AJAX\n */\n fetchPatternMatchCount: function($picker, pattern, $countEl) {\n // Determine field type from method select\n // Check if we're in an exclude row first, then fall back to include\n var $excludeRow = $picker.closest('.exclude-row');\n var $methodSelect;\n if ($excludeRow.length) {\n $methodSelect = $excludeRow.find('.exclude-method-select');\n } else {\n var $group = $picker.closest('.selection-group');\n $methodSelect = $group.find('.include-method-select');\n }\n var method = $methodSelect.val() || '';\n var field = method.indexOf('reference') !== -1 ? 'reference' : 'name';\n\n // Get entity type from block\n var $block = $picker.closest('.target-block');\n var entityType = $block.data('blockType') || 'products';\n\n // Show loading state\n $countEl.find('.preview-count').html(this.esIcon('progress_activity', 'es-spin'));\n $countEl.removeClass('clickable no-matches').show();\n\n $.ajax({\n url: this.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'countPatternMatches',\n trait: 'EntitySelector',\n pattern: pattern,\n field: field,\n entity_type: entityType,\n case_sensitive: 0\n },\n success: function(response) {\n if (response && response.success) {\n var count = response.count || 0;\n $countEl.find('.preview-count').text(count);\n $countEl.removeClass('no-matches clickable').show();\n if (count === 0) {\n $countEl.addClass('no-matches');\n } else {\n $countEl.addClass('clickable');\n }\n } else {\n $countEl.hide();\n }\n },\n error: function() {\n $countEl.hide();\n }\n });\n },\n\n // =========================================================================\n // Picker Value Extraction\n // =========================================================================\n\n /**\n * Get values from a picker based on its type\n */\n getPickerValues: function($picker, valueType) {\n switch (valueType) {\n case 'entity_search':\n var ids = [];\n $picker.find('.entity-chip').each(function() {\n var id = $(this).data('id');\n if (id) ids.push(id);\n });\n return ids;\n\n case 'pattern':\n var patternValues = this.getPatternTags($picker);\n // Also include draft pattern if it has content (not yet added as tag)\n var $draftPatternInput = $picker.find('.draft-tag .pattern-input');\n var draftPatternVal = $.trim($draftPatternInput.val());\n if (draftPatternVal) {\n var draftCaseSens = $draftPatternInput.closest('.draft-tag').attr('data-case-sensitive') === '1';\n patternValues.push({\n pattern: draftPatternVal,\n caseSensitive: draftCaseSens\n });\n }\n return patternValues;\n\n case 'numeric_range':\n var min = $picker.find('.range-min-input').val();\n var max = $picker.find('.range-max-input').val();\n return { min: min || null, max: max || null };\n\n case 'date_range':\n var from = $picker.find('.date-from-input').val();\n var to = $picker.find('.date-to-input').val();\n return { from: from || null, to: to || null };\n\n case 'select':\n return [$picker.find('.select-value-input').val()];\n\n case 'boolean':\n return [true];\n\n default:\n return [];\n }\n },\n\n // =========================================================================\n // Count/Status Updates\n // =========================================================================\n\n /**\n * Fetch and update condition match count for a row (include or exclude)\n */\n updateConditionCount: function($row) {\n var self = this;\n var trans = this.config.trans || {};\n\n // Find the count element - in method-selector-wrapper for include, in exclude-header-row for exclude\n var $countEl = $row.find('.method-selector-wrapper > .condition-match-count, > .exclude-header-row > .condition-match-count').first();\n if (!$countEl.length) return;\n\n // Determine if this is an include or exclude row\n var isExclude = $row.hasClass('exclude-row');\n var $methodSelect = isExclude\n ? $row.find('.exclude-method-select')\n : $row.find('.include-method-select');\n\n var method = $methodSelect.val();\n if (!method) {\n $countEl.hide();\n return;\n }\n\n // Get the picker and extract values\n var $picker = isExclude\n ? $row.find('.exclude-picker')\n : $row.find('.include-picker');\n\n var valueType = $picker.data('valueType') || 'none';\n var values = this.getPickerValues($picker, valueType);\n\n // Don't count if no values (except for boolean/all methods)\n var hasNoValues = !values ||\n (Array.isArray(values) && values.length === 0) ||\n (typeof values === 'object' && !Array.isArray(values) && (\n // For combination_attributes, check if attributes object is empty\n (valueType === 'combination_attributes' && values.attributes !== undefined && Object.keys(values.attributes).length === 0) ||\n // For other objects, check if completely empty\n (valueType !== 'combination_attributes' && Object.keys(values).length === 0)\n ));\n if (valueType !== 'none' && valueType !== 'boolean' && hasNoValues) {\n $countEl.hide();\n return;\n }\n\n // Get block type\n var $block = $row.closest('.target-block');\n var blockType = $block.data('blockType') || 'products';\n\n // Show loading\n $countEl.find('.preview-count').html(this.esIcon('progress_activity', 'es-spin'));\n $countEl.removeClass('clickable no-matches').show();\n\n // Store condition data on badge for popover\n $countEl.data('conditionData', {\n method: method,\n values: values,\n blockType: blockType,\n isExclude: isExclude\n });\n\n $.ajax({\n url: this.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'countConditionMatches',\n trait: 'EntitySelector',\n method: method,\n values: JSON.stringify(values),\n block_type: blockType\n },\n success: function(response) {\n if (response && response.success) {\n var count = response.count || 0;\n $countEl.removeClass('no-matches clickable');\n if (count === 0) {\n $countEl.find('.preview-count').text(count);\n $countEl.addClass('no-matches').show();\n } else {\n // Show count, make clickable for preview popover\n $countEl.find('.preview-count').text(count);\n $countEl.addClass('clickable').show();\n }\n } else {\n $countEl.hide().removeClass('clickable');\n }\n },\n error: function() {\n $countEl.hide().removeClass('clickable');\n }\n });\n },\n\n /**\n * Update all condition counts in a group\n */\n updateGroupCounts: function($group) {\n var self = this;\n\n // Update include count\n var $include = $group.find('.group-include');\n if ($include.length) {\n this.updateConditionCount($include);\n }\n\n // Update each exclude row count\n $group.find('.exclude-row').each(function() {\n self.updateConditionCount($(this));\n });\n\n // Update group total count (include - excludes)\n this.updateGroupTotalCount($group);\n },\n\n /**\n * Update the group total count badge (include - excludes)\n * Also updates the limit input placeholder\n */\n updateGroupTotalCount: function($group) {\n var self = this;\n var $block = $group.closest('.target-block');\n var blockType = $block.data('blockType') || 'products';\n var $badge = $group.find('.group-header .group-count-badge');\n var $limitInput = $group.find('.group-modifier-limit');\n\n // Build group data for AJAX\n var groupData = this.serializeGroup($group, blockType);\n\n // Check if include has valid data\n if (!groupData.include || !groupData.include.method) {\n $badge.hide();\n $limitInput.attr('placeholder', '–');\n return;\n }\n\n // Show loading\n $badge.html(this.esIcon('progress_activity', 'es-spin')).show();\n\n $.ajax({\n url: this.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'countGroupItems',\n trait: 'EntitySelector',\n group_data: JSON.stringify(groupData),\n block_type: blockType\n },\n success: function(response) {\n if (response && response.success) {\n var finalCount = response.final_count || 0;\n var excludeCount = response.exclude_count || 0;\n\n // Update badge with eye icon and count\n var badgeHtml = self.esIcon('visibility') + ' ' + finalCount;\n if (excludeCount > 0) {\n badgeHtml += ' (-' + excludeCount + ')';\n }\n $badge.html(badgeHtml);\n $badge.addClass('clickable').show();\n\n // Store group data on badge for preview popover\n $badge.data('groupData', groupData);\n $badge.data('blockType', blockType);\n $badge.data('finalCount', finalCount);\n\n // Update limit placeholder with the count\n $limitInput.attr('placeholder', finalCount);\n\n // Also update the group-preview-badge count (apply limit if set)\n var $previewBadge = $group.find('.group-preview-badge .preview-count');\n if ($previewBadge.length) {\n var limit = parseInt($limitInput.val(), 10);\n var displayCount = (limit > 0 && limit < finalCount) ? limit : finalCount;\n $previewBadge.text(displayCount);\n }\n } else {\n $badge.hide().removeClass('clickable');\n $limitInput.attr('placeholder', '–');\n }\n },\n error: function() {\n $badge.hide();\n $limitInput.attr('placeholder', '–');\n }\n });\n },\n\n /**\n * Update all condition counts for all visible groups\n */\n updateAllConditionCounts: function() {\n var self = this;\n this.$wrapper.find('.target-block.active .selection-group').each(function() {\n self.updateGroupCounts($(this));\n });\n },\n\n /**\n * Fetch category names by IDs and add chips to the picker\n * Used when adding selections from the tree modal\n * @param {jQuery} $picker - Picker element\n * @param {Array} ids - Category IDs to add\n * @param {string} entityType - 'categories' or 'cms_categories'\n * @param {Function} callback - Called when done\n */\n fetchCategoryNamesAndAddChips: function($picker, ids, entityType, callback) {\n var self = this;\n\n if (!ids || ids.length === 0) {\n if (typeof callback === 'function') {\n callback();\n }\n return;\n }\n\n $.ajax({\n url: this.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'getTargetEntitiesByIds',\n trait: 'EntitySelector',\n entity_type: entityType,\n ids: JSON.stringify(ids)\n },\n success: function(response) {\n if (response.success && response.entities) {\n response.entities.forEach(function(entity) {\n self.addSelectionNoUpdate($picker, entity.id, entity.name, entity);\n });\n }\n if (typeof callback === 'function') {\n callback();\n }\n },\n error: function() {\n if (typeof callback === 'function') {\n callback();\n }\n }\n });\n }\n };\n\n})(jQuery);\n","/**\n * Entity Selector - Groups Module\n * Selection group management, serialization, block/tab management\n * @partial _groups.js\n *\n * Contains:\n * - Group management: addGroup, removeGroup, clearAllConditions\n * - Block/Tab: switchToBlock, updateTabBadges, updateBlockStatus\n * - Serialization: serializeGroup, serializeAllBlocks, getBlockGroups\n * - Counts: fetchProductCount, updateHeaderTotalCount, updateAllConditionCounts\n * - Excludes: addFirstExcludeRow, addExcludeRow, removeExcludeRow\n * - Validation: validate, showValidationError, clearValidationError\n */\n\n(function($) {\n 'use strict';\n\n window._EntitySelectorMixins = window._EntitySelectorMixins || {};\n\n window._EntitySelectorMixins.groups = {\n\n addGroup: function($block, blockType) {\n var $container = $block.find('.groups-container');\n var trans = this.config.trans || {};\n var blockDef = this.config.blocks[blockType] || {};\n var methods = blockDef.selection_methods || {};\n\n // Remove empty state\n $container.find('.groups-empty-state').remove();\n\n // Get next group index\n var maxIndex = -1;\n $container.find('.selection-group').each(function() {\n var idx = parseInt($(this).data('groupIndex'), 10);\n if (idx > maxIndex) maxIndex = idx;\n });\n var groupIndex = maxIndex + 1;\n\n // Build method options with optgroups\n var methodOptions = this.buildMethodOptions(methods, false);\n\n // Build exclude method options (no \"all\") with optgroups\n var excludeMethodOptions = this.buildMethodOptions(methods, true);\n\n var defaultGroupName = (trans.group || 'Group') + ' ' + (groupIndex + 1);\n var html = '
';\n\n // Group header\n html += '
';\n html += '' + this.esIcon('expand_less') + '';\n html += '';\n html += '';\n html += '' + this.esIcon('progress_activity', 'es-spin') + '';\n html += '';\n html += '';\n html += '
';\n\n // Group body (collapsible content)\n html += '
';\n\n // Include section\n html += '
';\n html += '
';\n html += '
';\n html += '';\n html += '' + this.esIcon('visibility') + ' 0';\n html += '';\n html += '
';\n var noItemsText = trans.no_items_selected || 'No items selected - use search below';\n html += '
';\n html += '
';\n html += '
';\n html += this.esIcon('search', 'entity-search-icon');\n html += '';\n html += '' + this.esIcon('progress_activity', 'es-spin') + '';\n html += '
';\n html += '';\n html += '
';\n html += '
';\n html += '
';\n\n // Excludes section (collapsed by default)\n html += '
';\n html += '';\n html += '
';\n\n // Group-level modifiers (limit & sort)\n html += '
';\n html += '';\n html += '' + (trans.limit || 'Limit') + '';\n html += '';\n html += '';\n html += '';\n html += '' + (trans.sort || 'Sort') + '';\n html += '';\n html += '';\n html += '';\n html += '';\n html += this.esIcon('visibility') + ' ';\n html += '';\n html += '
';\n\n html += '
'; // Close group-body\n\n html += '
'; // Close selection-group\n\n $container.append(html);\n\n // Find the new group and set method to \"all\" by default\n var $newGroup = $container.find('.selection-group[data-group-index=\"' + groupIndex + '\"]');\n\n // Enhance the method select with styled dropdown\n this.enhanceMethodSelect($newGroup.find('.include-method-select'));\n\n $newGroup.find('.include-method-select').val('all').trigger('change');\n\n this.updateBlockStatus($block);\n this.serializeAllBlocks();\n },\n\n removeGroup: function($group, $block) {\n $group.remove();\n\n var $container = $block.find('.groups-container');\n var remainingGroups = $container.find('.selection-group').length;\n\n if (remainingGroups === 0) {\n var emptyText = this.getEmptyStateText($block);\n var emptyHtml = '
';\n emptyHtml += '' + emptyText + '';\n emptyHtml += '
';\n $container.html(emptyHtml);\n }\n\n this.updateBlockStatus($block);\n this.serializeAllBlocks();\n\n // Update tab badges and header total count\n this.updateTabBadges();\n },\n\n clearAllConditions: function() {\n var self = this;\n\n // Remove all groups from all blocks\n this.$wrapper.find('.target-block').each(function() {\n var $block = $(this);\n var $container = $block.find('.groups-container');\n\n // Remove all groups\n $container.find('.selection-group').remove();\n\n // Show empty state\n var emptyText = self.getEmptyStateText($block);\n var emptyHtml = '
';\n emptyHtml += '' + emptyText + '';\n emptyHtml += '
';\n $container.html(emptyHtml);\n\n self.updateBlockStatus($block);\n });\n\n // Update serialized data\n this.serializeAllBlocks();\n\n // Update tab badges and header count\n this.updateTabBadges();\n\n // Also update header total count immediately (since all cleared)\n this.updateHeaderTotalCount();\n },\n\n switchToBlock: function(blockType) {\n // Update tabs\n this.$wrapper.find('.target-block-tab').removeClass('active');\n this.$wrapper.find('.target-block-tab[data-block-type=\"' + blockType + '\"]').addClass('active');\n\n // Update blocks\n this.$wrapper.find('.target-block').removeClass('active').hide();\n this.$wrapper.find('.target-block[data-block-type=\"' + blockType + '\"]').addClass('active').show();\n\n // Close dropdown if open\n this.hideDropdown();\n },\n\n updateTabBadges: function() {\n var self = this;\n\n // Collect all block types with data and set loading state\n var blockTypesWithData = [];\n this.$wrapper.find('.target-block-tab').each(function() {\n var $tab = $(this);\n var blockType = $tab.data('blockType');\n var $block = self.$wrapper.find('.target-block[data-block-type=\"' + blockType + '\"]');\n var groupCount = $block.find('.selection-group').length;\n\n // Update or add badge\n var $badge = $tab.find('.tab-badge');\n if (groupCount > 0) {\n // Show loading state first\n if ($badge.length) {\n $badge.addClass('loading').html(self.esIcon('progress_activity', 'es-spin'));\n } else {\n $tab.append('' + self.esIcon('progress_activity', 'es-spin') + '');\n }\n $tab.addClass('has-data');\n blockTypesWithData.push(blockType);\n } else if ($block.hasClass('custom-block')) {\n // Custom blocks: check if any input/textarea/select has a non-empty value\n var hasCustomValue = false;\n $block.find('.custom-block-content').find('input, textarea, select').each(function() {\n if ($(this).val() && $(this).val().trim() !== '') {\n hasCustomValue = true;\n return false;\n }\n });\n if (hasCustomValue) {\n if ($badge.length) {\n $badge.removeClass('loading').html(self.esIcon('check'));\n } else {\n $tab.append('' + self.esIcon('check') + '');\n }\n $tab.addClass('has-data');\n } else {\n $badge.remove();\n $tab.removeClass('has-data');\n }\n } else {\n $badge.remove();\n $tab.removeClass('has-data');\n }\n });\n\n // Update target switch state based on whether any data exists\n this.updateTargetSwitchState();\n\n // Fetch all counts in a single bulk request\n if (blockTypesWithData.length > 0) {\n this.fetchAllCounts(blockTypesWithData);\n }\n },\n\n updateTargetSwitchState: function() {\n var $switch = this.$wrapper.find('.prestashop-switch');\n if (!$switch.length) {\n return;\n }\n\n // Check if any block has data\n var hasData = false;\n this.$wrapper.find('.target-block').each(function() {\n if ($(this).find('.selection-group').length > 0) {\n hasData = true;\n return false; // break\n }\n });\n\n // Update switch: value=\"1\" is \"Everyone/All/None\", value=\"0\" is \"Specific/Selected\"\n if (hasData) {\n $switch.find('input[value=\"0\"]').prop('checked', true);\n } else {\n $switch.find('input[value=\"1\"]').prop('checked', true);\n }\n },\n\n /**\n * Fetch counts for all block types in a single bulk AJAX request\n * @param {Array} blockTypes - Array of block type strings to fetch counts for\n */\n fetchAllCounts: function(blockTypes) {\n var self = this;\n\n // Read saved data from hidden input\n var $hiddenInput = this.$wrapper.find('input[name=\"' + this.config.name + '\"]');\n var savedData = {};\n try {\n savedData = JSON.parse($hiddenInput.val() || '{}');\n } catch (e) {\n savedData = {};\n }\n\n // Build conditions object for all requested block types\n var conditions = {};\n blockTypes.forEach(function(blockType) {\n var groups = (savedData[blockType] && savedData[blockType].groups) ? savedData[blockType].groups : [];\n if (groups.length > 0) {\n conditions[blockType] = { groups: groups };\n }\n });\n\n // If no valid conditions, remove loading spinners\n if (Object.keys(conditions).length === 0) {\n blockTypes.forEach(function(blockType) {\n var $tab = self.$wrapper.find('.target-block-tab[data-block-type=\"' + blockType + '\"]');\n $tab.find('.tab-badge').remove();\n $tab.removeClass('has-data');\n });\n return;\n }\n\n // Single bulk AJAX request for all counts\n $.ajax({\n url: this.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'previewEntitySelectorBulk',\n trait: 'EntitySelector',\n conditions: JSON.stringify(conditions)\n },\n success: function(response) {\n if (response.success && response.counts) {\n // Update each tab with its count\n Object.keys(response.counts).forEach(function(blockType) {\n var count = response.counts[blockType];\n var $tab = self.$wrapper.find('.target-block-tab[data-block-type=\"' + blockType + '\"]');\n var $badge = $tab.find('.tab-badge');\n\n if ($badge.length) {\n $badge.removeClass('loading').html(self.esIcon('visibility') + ' ' + count);\n // Store preview data for later popover use\n $tab.data('previewData', { count: count, success: true });\n }\n });\n\n // Handle any block types not in response (set count to 0 or remove badge)\n blockTypes.forEach(function(blockType) {\n if (!(blockType in response.counts)) {\n var $tab = self.$wrapper.find('.target-block-tab[data-block-type=\"' + blockType + '\"]');\n $tab.find('.tab-badge').remove();\n $tab.removeClass('has-data');\n }\n });\n\n self.updateHeaderTotalCount();\n } else {\n console.error('[EntitySelector] Bulk preview failed:', response.error || 'Unknown error');\n // Remove loading spinners on error\n blockTypes.forEach(function(blockType) {\n var $tab = self.$wrapper.find('.target-block-tab[data-block-type=\"' + blockType + '\"]');\n $tab.find('.tab-badge').remove();\n });\n }\n },\n error: function(xhr, status, error) {\n console.error('[EntitySelector] Bulk AJAX error:', status, error);\n // Remove loading spinners on error\n blockTypes.forEach(function(blockType) {\n var $tab = self.$wrapper.find('.target-block-tab[data-block-type=\"' + blockType + '\"]');\n $tab.find('.tab-badge').remove();\n });\n }\n });\n },\n\n /**\n * Fetch count for a single block type (legacy, used for single updates)\n */\n fetchProductCount: function(blockType, $tab) {\n var self = this;\n var data = {};\n\n // Read from hidden input (contains full saved data or freshly serialized data)\n var $hiddenInput = this.$wrapper.find('input[name=\"' + this.config.name + '\"]');\n var savedData = {};\n try {\n savedData = JSON.parse($hiddenInput.val() || '{}');\n } catch (e) {\n savedData = {};\n }\n\n // Get groups for the requested block type\n var groups = (savedData[blockType] && savedData[blockType].groups) ? savedData[blockType].groups : [];\n\n if (groups.length === 0) {\n $tab.find('.tab-badge').remove();\n $tab.removeClass('has-data');\n $tab.removeData('previewData');\n return;\n }\n\n // Show loading state\n var $badge = $tab.find('.tab-badge');\n if (!$badge.length) {\n $badge = $('' + this.esIcon('progress_activity', 'es-spin') + '');\n $tab.append($badge);\n } else {\n $badge.addClass('loading').html(this.esIcon('progress_activity', 'es-spin'));\n }\n $tab.addClass('has-data');\n\n data[blockType] = { groups: groups };\n\n $.ajax({\n url: this.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'previewEntitySelector',\n trait: 'EntitySelector',\n conditions: JSON.stringify(data),\n block_type: blockType,\n limit: 10\n },\n success: function(response) {\n if (response.success) {\n var $badge = $tab.find('.tab-badge');\n $badge.removeClass('loading').html(self.esIcon('visibility') + ' ' + response.count);\n\n // Store preview data for popover\n $tab.data('previewData', response);\n\n // Update header total count\n self.updateHeaderTotalCount();\n } else {\n console.error('[EntitySelector] Preview failed for', blockType, ':', response.error || 'Unknown error');\n $tab.find('.tab-badge').remove();\n }\n },\n error: function(xhr, status, error) {\n console.error('[EntitySelector] AJAX error for', blockType, ':', status, error);\n $tab.find('.tab-badge').remove();\n self.updateHeaderTotalCount();\n }\n });\n },\n\n updateHeaderTotalCount: function() {\n var self = this;\n var total = 0;\n\n // Sum up all tab badge counts\n this.$wrapper.find('.target-block-tab .tab-badge').each(function() {\n var $badge = $(this);\n if (!$badge.hasClass('loading')) {\n var count = parseInt($badge.text(), 10);\n if (!isNaN(count)) {\n total += count;\n }\n }\n });\n\n var $totalBadge = this.$wrapper.find('.trait-total-count');\n if (total > 0) {\n $totalBadge.find('.count-value').text(total);\n $totalBadge.show();\n } else {\n $totalBadge.hide();\n }\n\n // Update show-all toggle state\n this.updateShowAllToggle();\n },\n\n updateShowAllToggle: function() {\n var $toggle = this.$wrapper.find('.trait-show-all-toggle');\n if (!$toggle.length) return;\n\n var $checkbox = $toggle.find('.show-all-checkbox');\n var hasData = this.$wrapper.find('.target-block-tab.has-data').length > 0;\n\n // If there's data, uncheck (not showing to all), otherwise check\n $checkbox.prop('checked', !hasData);\n },\n\n updateBlockStatus: function($block) {\n var $status = $block.find('.block-status');\n var blockType = $block.data('blockType');\n var blockDef = this.config.blocks[blockType] || {};\n var trans = this.config.trans || {};\n\n var groups = this.getBlockGroups($block);\n\n if (groups.length === 0) {\n var emptyMeansAll = this.config.emptyMeansAll !== false;\n if (emptyMeansAll) {\n $status.text((trans.all || 'All') + ' ' + (blockDef.entity_label_plural || 'items'));\n } else {\n $status.text(trans.nothing_selected || 'Nothing selected');\n }\n } else {\n $status.text(groups.length + ' ' + (groups.length === 1 ? (trans.group || 'group') : (trans.groups || 'groups')));\n }\n },\n\n getEmptyStateText: function($block) {\n var blockType = $block.data('blockType');\n var blockMode = $block.data('mode') || 'multi';\n var blockDef = this.config.blocks[blockType] || {};\n var trans = this.config.trans || {};\n var emptyMeansAll = this.config.emptyMeansAll !== false;\n\n if (blockMode === 'single') {\n return trans.no_item_selected || 'No item selected';\n }\n\n if (emptyMeansAll) {\n return (trans.all || 'All') + ' ' + (blockDef.entity_label_plural || 'items') + ' ' + (trans.included || 'included');\n }\n\n return trans.nothing_selected || 'Nothing selected';\n },\n\n serializeGroup: function($group, blockType) {\n var self = this;\n\n // Include\n var includeMethod = $group.find('.include-method-select').val() || 'all';\n var $includePicker = $group.find('.include-picker');\n var includeValues = this.getPickerValues($includePicker);\n\n // Excludes (multiple rows)\n var excludes = [];\n var $excludesSection = $group.find('.group-excludes.has-excludes');\n if ($excludesSection.length) {\n $group.find('.exclude-row').each(function() {\n var $row = $(this);\n var excludeMethod = $row.find('.exclude-method-select').val() || null;\n var $excludePicker = $row.find('.exclude-picker');\n var excludeValues = self.getPickerValues($excludePicker);\n\n if (excludeMethod && excludeValues && (Array.isArray(excludeValues) ? excludeValues.length > 0 : true)) {\n excludes.push({\n method: excludeMethod,\n values: excludeValues\n });\n }\n });\n }\n\n var groupData = {\n include: {\n method: includeMethod,\n values: includeValues\n }\n };\n\n if (excludes.length > 0) {\n groupData.excludes = excludes;\n }\n\n // Add modifiers if present\n var modifiers = this.getGroupModifiers($group);\n if (modifiers.limit || modifiers.sort_by) {\n groupData.modifiers = modifiers;\n }\n\n return groupData;\n },\n\n serializeAllBlocks: function($changedRow) {\n var self = this;\n var data = {};\n\n console.log('[EntitySelector] serializeAllBlocks called');\n\n this.$wrapper.find('.target-block').each(function() {\n var $block = $(this);\n var blockType = $block.data('blockType');\n var groups = self.getBlockGroups($block);\n\n console.log('[EntitySelector] Block:', blockType, 'Groups:', groups.length);\n\n // Groups now contain their own modifiers, no block-level modifiers\n if (groups.length > 0) {\n data[blockType] = { groups: groups };\n }\n\n self.updateBlockStatus($block);\n });\n\n // Update hidden input first\n var $input = this.$wrapper.find('input[name=\"' + this.config.name + '\"]');\n var jsonData = JSON.stringify(data);\n\n console.log('[EntitySelector] Hidden input name:', this.config.name);\n console.log('[EntitySelector] Hidden input found:', $input.length);\n console.log('[EntitySelector] Serialized data:', jsonData.substring(0, 500));\n\n $input.val(jsonData);\n\n // Then update tab badges (reads from hidden input)\n this.updateTabBadges();\n\n // Debounced update of condition count - only for changed row if specified\n if (this.countUpdateTimeout) {\n clearTimeout(this.countUpdateTimeout);\n }\n this.countUpdateTimeout = setTimeout(function() {\n if ($changedRow && $changedRow.length) {\n // Update the specific row that changed\n self.updateConditionCount($changedRow);\n // Also update the group total count (include - excludes)\n var $group = $changedRow.closest('.selection-group');\n if ($group.length) {\n self.updateGroupTotalCount($group);\n }\n } else {\n // Fallback: update all counts (initial load, structure changes)\n self.updateAllConditionCounts();\n }\n }, 500);\n },\n\n getBlockGroups: function($block) {\n var self = this;\n var groups = [];\n\n $block.find('.selection-group').each(function() {\n var $group = $(this);\n\n // Include\n var includeMethod = $group.find('.include-method-select').val() || 'all';\n var $includePicker = $group.find('.include-picker');\n var includeValues = self.getPickerValues($includePicker);\n\n // Skip groups with invalid include conditions (e.g., \"specific products\" with none selected)\n if (!self.isConditionValid(includeMethod, includeValues, $includePicker)) {\n return true; // continue to next group\n }\n\n // Excludes (multiple rows) - only include valid ones\n var excludes = [];\n var $excludesSection = $group.find('.group-excludes.has-excludes');\n if ($excludesSection.length) {\n $group.find('.exclude-row').each(function() {\n var $row = $(this);\n var excludeMethod = $row.find('.exclude-method-select').val() || null;\n var $excludePicker = $row.find('.exclude-picker');\n var excludeValues = self.getPickerValues($excludePicker);\n\n // Only include valid exclude conditions\n if (excludeMethod && self.isConditionValid(excludeMethod, excludeValues, $excludePicker)) {\n excludes.push({\n method: excludeMethod,\n values: excludeValues\n });\n }\n });\n }\n\n var groupData = {\n include: {\n method: includeMethod,\n values: includeValues\n }\n };\n\n // Group name (optional, for organizational purposes)\n var groupName = $.trim($group.attr('data-group-name') || '');\n if (groupName) {\n groupData.name = groupName;\n }\n\n if (excludes.length > 0) {\n groupData.excludes = excludes;\n }\n\n // Group-level modifiers\n var modifiers = self.getGroupModifiers($group);\n if (modifiers.limit || modifiers.sort_by) {\n groupData.modifiers = modifiers;\n }\n\n groups.push(groupData);\n });\n\n return groups;\n },\n\n getGroupModifiers: function($group) {\n var limit = $group.find('.group-modifier-limit').val();\n var sortBy = $group.find('.group-modifier-sort').val() || 'sales';\n var $sortDirBtn = $group.find('.group-modifiers .btn-sort-dir');\n var sortDir = $sortDirBtn.data('dir') || 'DESC';\n\n return {\n limit: limit ? parseInt(limit, 10) : null,\n sort_by: sortBy || null,\n sort_dir: sortDir || 'DESC'\n };\n },\n\n getPickerValues: function($picker) {\n var valueType = $picker.attr('data-value-type') || 'entity_search';\n var values = [];\n\n switch (valueType) {\n case 'entity_search':\n $picker.find('.entity-chip').each(function() {\n var id = $(this).data('id');\n values.push(isNaN(id) ? id : Number(id));\n });\n break;\n\n case 'pattern':\n values = this.getPatternTags($picker);\n // Also include draft pattern if it has content (not yet added as tag)\n var $draftInput = $picker.find('.draft-tag .pattern-input');\n var draftPattern = $.trim($draftInput.val());\n if (draftPattern) {\n var draftCaseSensitive = $draftInput.closest('.draft-tag').attr('data-case-sensitive') === '1';\n values.push({\n pattern: draftPattern,\n caseSensitive: draftCaseSensitive\n });\n }\n break;\n\n case 'numeric_range':\n var min = $picker.find('.range-min-input').val();\n var max = $picker.find('.range-max-input').val();\n if (min !== '' || max !== '') {\n values = {\n min: min !== '' ? parseFloat(min) : null,\n max: max !== '' ? parseFloat(max) : null\n };\n }\n break;\n\n case 'date_range':\n var from = $picker.find('.date-from-input').val();\n var to = $picker.find('.date-to-input').val();\n if (from || to) {\n values = {\n from: from || null,\n to: to || null\n };\n }\n break;\n\n case 'select':\n var selectVal = $picker.find('.select-value-input').val();\n if (selectVal) {\n values = [selectVal];\n }\n break;\n\n case 'boolean':\n values = [true];\n break;\n\n case 'multi_numeric_range':\n var ranges = [];\n $picker.find('.range-chip').each(function() {\n var $chip = $(this);\n var minVal = $chip.data('min');\n var maxVal = $chip.data('max');\n ranges.push({\n min: minVal !== '' && minVal !== undefined ? parseFloat(minVal) : null,\n max: maxVal !== '' && maxVal !== undefined ? parseFloat(maxVal) : null\n });\n });\n if (ranges.length > 0) {\n values = ranges;\n }\n break;\n\n case 'multi_select_tiles':\n $picker.find('.tile-option.selected').each(function() {\n values.push($(this).data('value'));\n });\n break;\n\n case 'combination_attributes':\n // Returns object: { mode: 'products'|'combinations', attributes: { groupId: [valueId1, valueId2], ... } }\n var combAttrs = {};\n $picker.find('.comb-attr-value.selected').each(function() {\n var groupId = $(this).data('groupId').toString();\n var valueId = $(this).data('valueId');\n if (!combAttrs[groupId]) {\n combAttrs[groupId] = [];\n }\n combAttrs[groupId].push(valueId);\n });\n if (Object.keys(combAttrs).length > 0) {\n // Get mode: from radio if toggle exists, otherwise from config\n var $combPicker = $picker.find('.combination-attributes-picker');\n var configMode = $combPicker.data('combinationMode') || this.config.combinationMode || 'products';\n var combMode;\n if (configMode === 'toggle') {\n combMode = $picker.find('.comb-mode-radio:checked').val() || 'products';\n } else {\n combMode = configMode;\n }\n values = {\n mode: combMode,\n attributes: combAttrs\n };\n }\n break;\n }\n\n return values;\n },\n\n isConditionValid: function(method, values, $picker) {\n // 'all' method never needs values\n if (method === 'all') {\n return true;\n }\n\n // Boolean methods are always valid (the value is implicit true)\n var valueType = $picker.attr('data-value-type') || 'entity_search';\n if (valueType === 'boolean') {\n return true;\n }\n\n // For other methods, check if values are meaningful\n if (Array.isArray(values)) {\n return values.length > 0;\n }\n\n // For object values (ranges, combination_attributes), check if meaningful\n if (typeof values === 'object' && values !== null) {\n // Special handling for combination_attributes: { mode, attributes }\n if (valueType === 'combination_attributes' && values.attributes !== undefined) {\n return Object.keys(values.attributes).length > 0;\n }\n // For ranges and other objects, check if at least one bound is set\n return Object.keys(values).some(function(key) {\n return values[key] !== null && values[key] !== '';\n });\n }\n\n return false;\n },\n\n /**\n * Update all condition counts using a single bulk AJAX request\n */\n updateAllConditionCounts: function() {\n var self = this;\n var conditions = {};\n var conditionElements = {};\n var conditionIndex = 0;\n\n // Collect all conditions from all active groups\n this.$wrapper.find('.target-block.active .selection-group').each(function() {\n var $group = $(this);\n var $block = $group.closest('.target-block');\n var blockType = $block.data('blockType') || 'products';\n\n // Process include row\n var $include = $group.find('.group-include');\n if ($include.length) {\n var includeData = self.getConditionData($include, blockType);\n if (includeData) {\n var id = 'c' + conditionIndex++;\n conditions[id] = includeData.condition;\n conditionElements[id] = includeData.$countEl;\n }\n }\n\n // Process exclude rows\n $group.find('.exclude-row').each(function() {\n var excludeData = self.getConditionData($(this), blockType);\n if (excludeData) {\n var id = 'c' + conditionIndex++;\n conditions[id] = excludeData.condition;\n conditionElements[id] = excludeData.$countEl;\n }\n });\n });\n\n // If no conditions, nothing to do\n if (Object.keys(conditions).length === 0) {\n return;\n }\n\n // Make single bulk AJAX request\n $.ajax({\n url: this.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'countConditionMatchesBulk',\n trait: 'EntitySelector',\n conditions: JSON.stringify(conditions)\n },\n success: function(response) {\n if (response && response.success && response.counts) {\n // Update each count element with its result\n Object.keys(response.counts).forEach(function(id) {\n var count = response.counts[id] || 0;\n var $countEl = conditionElements[id];\n if ($countEl && $countEl.length) {\n $countEl.removeClass('no-matches clickable');\n if (count === 0) {\n $countEl.find('.preview-count').text(count);\n $countEl.addClass('no-matches').show();\n } else {\n $countEl.find('.preview-count').text(count);\n $countEl.addClass('clickable').show();\n }\n }\n });\n }\n // Note: Group totals are updated on-demand when user interacts, not on initial load\n },\n error: function() {\n // Hide all count elements on error\n Object.keys(conditionElements).forEach(function(id) {\n var $countEl = conditionElements[id];\n if ($countEl && $countEl.length) {\n $countEl.hide().removeClass('clickable');\n }\n });\n }\n });\n },\n\n /**\n * Extract condition data from a row for bulk counting\n */\n getConditionData: function($row, blockType) {\n console.log('[getConditionData] Called with blockType:', blockType);\n var $countEl = $row.find('.method-selector-wrapper > .condition-match-count, > .exclude-header-row .condition-match-count').first();\n console.log('[getConditionData] $countEl found:', $countEl.length);\n if (!$countEl.length) return null;\n\n var isExclude = $row.hasClass('exclude-row');\n var $methodSelect = isExclude\n ? $row.find('.exclude-method-select')\n : $row.find('.include-method-select');\n\n var method = $methodSelect.val();\n console.log('[getConditionData] method:', method);\n if (!method) {\n $countEl.hide();\n return null;\n }\n\n var $picker = isExclude\n ? $row.find('.exclude-picker')\n : $row.find('.include-picker');\n console.log('[getConditionData] $picker found:', $picker.length, 'data-value-type attr:', $picker.attr('data-value-type'));\n\n var valueType = $picker.data('valueType') || $picker.attr('data-value-type') || 'none';\n console.log('[getConditionData] valueType:', valueType);\n\n // Special case: \"All countries\" method - needs separate handling for holidays\n if (valueType === 'none' && blockType === 'countries' && method === 'all') {\n console.log('[getConditionData] All countries detected - triggering updateConditionCount');\n // Trigger separate update for this special case (uses nested AJAX)\n var self = this;\n setTimeout(function() {\n self.updateConditionCount($row, blockType);\n }, 0);\n return null; // Skip bulk processing, handled separately\n }\n\n // Special case: Specific countries with entity_search - needs holiday counting, not entity counting\n var searchEntity = $picker.attr('data-search-entity') || '';\n if (blockType === 'countries' && valueType === 'entity_search' && searchEntity === 'countries') {\n console.log('[getConditionData] Specific countries detected - triggering updateConditionCount for holiday counting');\n var self = this;\n setTimeout(function() {\n self.updateConditionCount($row, blockType);\n }, 0);\n return null; // Skip bulk processing, handled separately\n }\n\n // Hide badge for other \"all\" type methods (valueType === 'none') since they don't filter\n if (valueType === 'none') {\n $countEl.hide();\n return null;\n }\n\n var values = this.getPickerValues($picker, valueType);\n\n // Don't count if no values (except for boolean methods)\n var hasNoValues = !values ||\n (Array.isArray(values) && values.length === 0) ||\n (typeof values === 'object' && !Array.isArray(values) && (\n (valueType === 'combination_attributes' && values.attributes !== undefined && Object.keys(values.attributes).length === 0) ||\n (valueType !== 'combination_attributes' && Object.keys(values).length === 0)\n ));\n if (valueType !== 'boolean' && hasNoValues) {\n $countEl.hide();\n return null;\n }\n\n // Show loading spinner\n $countEl.find('.preview-count').html(this.esIcon('progress_activity', 'es-spin'));\n $countEl.removeClass('clickable no-matches').show();\n\n // Store condition data on badge for popover\n $countEl.data('conditionData', {\n method: method,\n values: values,\n blockType: blockType,\n isExclude: isExclude\n });\n\n return {\n condition: {\n method: method,\n values: values,\n block_type: blockType\n },\n $countEl: $countEl\n };\n },\n\n updateGroupCounts: function($group) {\n var self = this;\n var $block = $group.closest('.target-block');\n var blockType = $block.data('blockType') || 'products';\n\n // Update include count\n var $include = $group.find('.group-include');\n if ($include.length) {\n this.updateConditionCount($include, blockType);\n }\n\n // Update each exclude row count\n $group.find('.exclude-row').each(function() {\n self.updateConditionCount($(this), blockType);\n });\n\n // Update group total count (include - excludes)\n this.updateGroupTotalCount($group);\n },\n\n /**\n * Update a single condition count (used for individual updates after user changes)\n */\n updateConditionCount: function($row, blockType) {\n var self = this;\n\n var $countEl = $row.find('.method-selector-wrapper > .condition-match-count, > .exclude-header-row .condition-match-count').first();\n if (!$countEl.length) {\n console.log('[updateConditionCount] No $countEl found');\n return;\n }\n\n var isExclude = $row.hasClass('exclude-row');\n var $methodSelect = isExclude\n ? $row.find('.exclude-method-select')\n : $row.find('.include-method-select');\n\n var method = $methodSelect.val();\n console.log('[updateConditionCount] method:', method, 'isExclude:', isExclude);\n if (!method) {\n console.log('[updateConditionCount] No method, hiding badge');\n $countEl.hide();\n return;\n }\n\n var $picker = isExclude\n ? $row.find('.exclude-picker')\n : $row.find('.include-picker');\n\n var valueType = $picker.data('valueType') || 'none';\n var searchEntity = $picker.attr('data-search-entity') || '';\n\n // Get the block type to check if this is a countries block\n if (!blockType) {\n var $block = $row.closest('.target-block');\n blockType = $block.data('blockType') || 'products';\n }\n\n console.log('[updateConditionCount] valueType:', valueType, 'searchEntity:', searchEntity, 'blockType:', blockType, 'method:', method);\n\n // Special case: \"All countries\" method - fetch holidays for all countries\n if (valueType === 'none' && blockType === 'countries' && method === 'all') {\n console.log('[updateConditionCount] All countries method - fetching all country holidays');\n $countEl.find('.preview-count').html(this.esIcon('progress_activity', 'es-spin'));\n $countEl.removeClass('clickable no-matches country-holidays').show();\n\n // First fetch all active country IDs, then get holidays\n $.ajax({\n url: self.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'searchTargetEntities',\n trait: 'EntitySelector',\n entity_type: 'countries',\n query: '',\n limit: 500\n },\n success: function(response) {\n var items = response.results || response.items || [];\n if (response && response.success && items.length > 0) {\n var allCountryIds = items.map(function(item) { return item.id; });\n console.log('[updateConditionCount] Found', allCountryIds.length, 'countries, fetching holidays');\n\n // Store condition data for click handler\n $countEl.data('conditionData', {\n method: method,\n values: allCountryIds,\n blockType: blockType,\n isExclude: isExclude,\n isCountryHolidays: true,\n countryIds: allCountryIds,\n isAllCountries: true\n });\n\n // Now fetch holiday count\n $.ajax({\n url: self.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'getHolidaysForCountries',\n trait: 'EntitySelector',\n country_ids: allCountryIds.join(','),\n count_only: 1\n },\n success: function(holidayResponse) {\n console.log('[updateConditionCount] All countries holiday response:', holidayResponse);\n if (holidayResponse && holidayResponse.success) {\n var count = holidayResponse.total_count || 0;\n $countEl.removeClass('no-matches clickable');\n $countEl.addClass('country-holidays');\n if (count === 0) {\n $countEl.find('.preview-count').text(count);\n $countEl.addClass('no-matches').show();\n } else {\n $countEl.find('.preview-count').text(count);\n $countEl.addClass('clickable').show();\n }\n $countEl.data('countriesInfo', holidayResponse.countries || []);\n } else {\n $countEl.hide().removeClass('clickable');\n }\n },\n error: function() {\n $countEl.hide().removeClass('clickable');\n }\n });\n } else {\n $countEl.hide().removeClass('clickable');\n }\n },\n error: function() {\n $countEl.hide().removeClass('clickable');\n }\n });\n return;\n }\n\n // Hide badge for other \"all\" type methods (valueType === 'none') since they don't filter\n if (valueType === 'none') {\n console.log('[updateConditionCount] valueType is none, hiding badge');\n $countEl.hide();\n return;\n }\n\n var values = this.getPickerValues($picker, valueType);\n\n var hasNoValues = !values ||\n (Array.isArray(values) && values.length === 0) ||\n (typeof values === 'object' && !Array.isArray(values) && (\n (valueType === 'combination_attributes' && values.attributes !== undefined && Object.keys(values.attributes).length === 0) ||\n (valueType !== 'combination_attributes' && Object.keys(values).length === 0)\n ));\n if (valueType !== 'boolean' && hasNoValues) {\n $countEl.hide();\n return;\n }\n\n if (!blockType) {\n var $block = $row.closest('.target-block');\n blockType = $block.data('blockType') || 'products';\n }\n\n // Check if this is a country selection - show holiday count instead\n var isCountrySelection = (searchEntity === 'countries' && valueType === 'entity_search');\n console.log('[updateConditionCount] isCountrySelection:', isCountrySelection, 'values:', values);\n\n $countEl.find('.preview-count').html(this.esIcon('progress_activity', 'es-spin'));\n $countEl.removeClass('clickable no-matches country-holidays').show();\n\n // For countries, fetch holiday count\n if (isCountrySelection && Array.isArray(values) && values.length > 0) {\n console.log('[updateConditionCount] Fetching holiday count for countries:', values);\n $countEl.data('conditionData', {\n method: method,\n values: values,\n blockType: blockType,\n isExclude: isExclude,\n isCountryHolidays: true,\n countryIds: values\n });\n\n $.ajax({\n url: self.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'getHolidaysForCountries',\n trait: 'EntitySelector',\n country_ids: values.join(','),\n count_only: 1\n },\n success: function(response) {\n console.log('[updateConditionCount] Holiday response:', response);\n if (response && response.success) {\n var count = response.total_count || 0;\n console.log('[updateConditionCount] Holiday count:', count);\n $countEl.removeClass('no-matches clickable');\n $countEl.addClass('country-holidays');\n if (count === 0) {\n $countEl.find('.preview-count').text(count);\n $countEl.addClass('no-matches').show();\n } else {\n $countEl.find('.preview-count').text(count);\n $countEl.addClass('clickable').show();\n }\n // Store countries info for popover\n $countEl.data('countriesInfo', response.countries || []);\n } else {\n console.log('[updateConditionCount] Holiday response failed:', response);\n $countEl.hide().removeClass('clickable');\n }\n },\n error: function() {\n $countEl.hide().removeClass('clickable');\n }\n });\n return;\n }\n\n // Default: count entities\n $countEl.data('conditionData', {\n method: method,\n values: values,\n blockType: blockType,\n isExclude: isExclude\n });\n\n $.ajax({\n url: this.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'countConditionMatches',\n trait: 'EntitySelector',\n method: method,\n values: JSON.stringify(values),\n block_type: blockType\n },\n success: function(response) {\n if (response && response.success) {\n var count = response.count || 0;\n $countEl.removeClass('no-matches clickable');\n if (count === 0) {\n $countEl.find('.preview-count').text(count);\n $countEl.addClass('no-matches').show();\n } else {\n $countEl.find('.preview-count').text(count);\n $countEl.addClass('clickable').show();\n }\n } else {\n $countEl.hide().removeClass('clickable');\n }\n },\n error: function() {\n $countEl.hide().removeClass('clickable');\n }\n });\n },\n\n updateGroupTotalCount: function($group) {\n var self = this;\n var $block = $group.closest('.target-block');\n var blockType = $block.data('blockType') || 'products';\n var $badge = $group.find('.group-header .group-count-badge');\n var $limitInput = $group.find('.group-modifier-limit');\n\n // Build group data for AJAX\n var groupData = this.serializeGroup($group, blockType);\n\n // Check if include has valid data\n if (!groupData.include || !groupData.include.method) {\n $badge.hide();\n $limitInput.attr('placeholder', '–');\n return;\n }\n\n // Show loading\n $badge.html(this.esIcon('progress_activity', 'es-spin')).show();\n\n $.ajax({\n url: this.config.ajaxUrl,\n type: 'POST',\n dataType: 'json',\n data: {\n ajax: 1,\n action: 'countGroupItems',\n trait: 'EntitySelector',\n group_data: JSON.stringify(groupData),\n block_type: blockType\n },\n success: function(response) {\n if (response && response.success) {\n var finalCount = response.final_count || 0;\n var excludeCount = response.exclude_count || 0;\n\n // Update badge with eye icon and count\n var badgeHtml = self.esIcon('visibility') + ' ' + finalCount;\n if (excludeCount > 0) {\n badgeHtml += ' (-' + excludeCount + ')';\n }\n $badge.html(badgeHtml);\n $badge.addClass('clickable').show();\n\n // Store group data on badge for preview popover\n $badge.data('groupData', groupData);\n $badge.data('blockType', blockType);\n $badge.data('finalCount', finalCount);\n\n // Update limit placeholder with the count\n $limitInput.attr('placeholder', finalCount);\n\n // Also update the group-preview-badge count (apply limit if set)\n var $previewBadge = $group.find('.group-preview-badge .preview-count');\n if ($previewBadge.length) {\n var limit = parseInt($limitInput.val(), 10);\n var displayCount = (limit > 0 && limit < finalCount) ? limit : finalCount;\n $previewBadge.text(displayCount);\n }\n } else {\n $badge.hide().removeClass('clickable');\n $limitInput.attr('placeholder', '–');\n }\n },\n error: function() {\n $badge.hide();\n $limitInput.attr('placeholder', '–');\n }\n });\n },\n\n // Exclude row management\n addFirstExcludeRow: function($group, $block) {\n var $excludesDiv = $group.find('.group-excludes');\n var trans = this.config.trans || {};\n\n // Build the full excludes structure with first row\n var html = '
';\n html += '' + this.esIcon('block') + ' ' + (trans.except || 'EXCEPT') + '';\n html += '
';\n\n html += '
';\n html += this.buildExcludeRowHtml($block, 0);\n html += '
';\n\n html += '';\n\n $excludesDiv.addClass('has-excludes').html(html);\n\n // Enhance the first exclude method select with styled dropdown\n var $firstRow = $excludesDiv.find('.exclude-row[data-exclude-index=\"0\"]');\n var $firstSelect = $firstRow.find('.exclude-method-select');\n this.enhanceMethodSelect($firstSelect);\n\n // Update method info placeholder for initial selection\n var blockType = $block.data('blockType');\n var initialMethod = $firstSelect.val();\n this.updateMethodInfoPlaceholder($firstRow.find('.method-selector-wrapper'), initialMethod, blockType);\n\n this.updateMethodSelectorLock($group, true);\n this.serializeAllBlocks();\n },\n\n addExcludeRow: function($group, $block) {\n var $container = $group.find('.exclude-rows-container');\n\n // Get next exclude index\n var maxIndex = -1;\n $container.find('.exclude-row').each(function() {\n var idx = parseInt($(this).data('excludeIndex'), 10);\n if (idx > maxIndex) maxIndex = idx;\n });\n var excludeIndex = maxIndex + 1;\n\n var html = this.buildExcludeRowHtml($block, excludeIndex);\n $container.append(html);\n\n // Enhance the exclude method select with styled dropdown\n var $newRow = $container.find('.exclude-row[data-exclude-index=\"' + excludeIndex + '\"]');\n var $newSelect = $newRow.find('.exclude-method-select');\n this.enhanceMethodSelect($newSelect);\n\n // Update method info placeholder for initial selection\n var blockType = $block.data('blockType');\n var initialMethod = $newSelect.val();\n this.updateMethodInfoPlaceholder($newRow.find('.method-selector-wrapper'), initialMethod, blockType);\n\n this.serializeAllBlocks();\n },\n\n buildExcludeRowHtml: function($block, excludeIndex) {\n var blockType = $block.data('blockType');\n var blockDef = this.config.blocks[blockType] || {};\n var methods = blockDef.selection_methods || {};\n var trans = this.config.trans || {};\n\n // Build exclude method options with optgroups (no \"all\")\n var excludeMethodOptions = this.buildMethodOptions(methods, true);\n\n // Find first non-all method for default search entity\n var firstSearchEntity = blockType;\n var firstValueType = 'entity_search';\n $.each(methods, function(methodKey, methodDef) {\n if (methodKey === 'all') return true;\n firstSearchEntity = methodDef.search_entity || blockType;\n firstValueType = methodDef.value_type || 'entity_search';\n return false; // break\n });\n\n var html = '
';\n\n // Header row with method select wrapped in method-selector-wrapper (same as include)\n html += '
';\n html += '
';\n html += '';\n html += '' + this.esIcon('visibility') + ' 0';\n html += '';\n html += '
';\n html += '';\n html += '
';\n\n // Value picker based on first method's value type\n html += this.buildValuePickerHtml('exclude', firstValueType, firstSearchEntity, methods);\n\n html += '
';\n\n return html;\n },\n\n removeExcludeRow: function($excludeRow, $group, $block) {\n var $container = $group.find('.exclude-rows-container');\n var trans = this.config.trans || {};\n\n $excludeRow.remove();\n\n // Check if there are remaining exclude rows\n var remainingRows = $container.find('.exclude-row').length;\n\n if (remainingRows === 0) {\n // Remove entire excludes section and show \"Add exceptions\" button\n var $excludesDiv = $group.find('.group-excludes');\n $excludesDiv.removeClass('has-excludes').html(\n ''\n );\n // Unlock the method selector since no excludes exist\n this.updateMethodSelectorLock($group, false);\n }\n\n this.serializeAllBlocks();\n },\n\n // Method options building\n buildMethodOptions: function(methods, excludeAll) {\n var self = this;\n var trans = this.config.trans || {};\n var html = '';\n\n // Group labels\n var groupLabels = {\n 'select_by': trans.select_by || 'Select by...',\n 'filter_by': trans.filter_by || 'Filter by...'\n };\n\n // Separate methods by group\n var grouped = {};\n var ungrouped = {};\n\n $.each(methods, function(methodKey, methodDef) {\n if (excludeAll && methodKey === 'all') return true; // skip\n\n var group = methodDef.group || '';\n if (group) {\n if (!grouped[group]) {\n grouped[group] = {};\n }\n grouped[group][methodKey] = methodDef;\n } else {\n ungrouped[methodKey] = methodDef;\n }\n });\n\n // Render ungrouped options first\n $.each(ungrouped, function(methodKey, methodDef) {\n html += self.buildMethodOption(methodKey, methodDef);\n });\n\n // Render grouped options with optgroups\n $.each(grouped, function(groupKey, groupMethods) {\n var groupLabel = groupLabels[groupKey] || groupKey.replace(/_/g, ' ');\n html += '';\n $.each(groupMethods, function(methodKey, methodDef) {\n html += self.buildMethodOption(methodKey, methodDef);\n });\n html += '';\n });\n\n return html;\n },\n\n buildMethodOption: function(methodKey, methodDef) {\n var html = '
'; $chips.append(html); @@ -183,7 +183,7 @@ '' ).show(); } else { @@ -211,7 +211,7 @@ '' + '' + '' + '' + '' + @@ -422,20 +422,16 @@ 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: bulkAjaxData, + data: { + ajax: 1, + action: 'getTargetEntitiesByIdsBulk', + trait: 'EntitySelector', + entities: JSON.stringify(bulkRequest) + }, success: function(response) { console.log('[EntitySelector] AJAX response:', response); if (!response.success || !response.entities) { @@ -481,7 +477,7 @@ // Country: show flag if (isCountry && entity.iso_code) { - html += '' + self.escapeAttr(entity.iso_code) + ''; + html += '' + self.escapeAttr(entity.iso_code) + '' + self.esIcon('flag', 'flag-fallback').replace('>', ' style="display:none">') + ''; } else if (entity.image) { html += ''; } @@ -490,10 +486,10 @@ // Country: add holiday preview button if (isCountry) { - html += ''; + html += ''; } - html += ''; + html += ''; html += '
'; $loadingChip.replaceWith(html); @@ -587,7 +583,7 @@ $chip.append($(''; html += '' + this.escapeHtml(pattern) + ''; - html += ''; + html += ''; html += ''; $chipsContainer.append(html); }, @@ -857,7 +849,7 @@ var entityType = $block.data('blockType') || 'products'; // Show loading - keep eye icon, update count value - $countValue.html(''); + $countValue.html(this.esIcon('progress_activity', 'es-spin')); $matchCount.show(); // Store pattern for click handler @@ -956,7 +948,7 @@ var blockType = $block.data('blockType') || 'products'; // Show loading - $countEl.find('.preview-count').html(''); + $countEl.find('.preview-count').html(this.esIcon('progress_activity', 'es-spin')); $countEl.removeClass('clickable no-matches').show(); // Store condition data on badge for popover @@ -1022,7 +1014,7 @@ var entityType = $block.data('blockType') || 'products'; // Show loading state - $countEl.find('.preview-count').html(''); + $countEl.find('.preview-count').html(this.esIcon('progress_activity', 'es-spin')); $countEl.removeClass('clickable no-matches').show(); $.ajax({ @@ -1164,7 +1156,7 @@ var blockType = $block.data('blockType') || 'products'; // Show loading - $countEl.find('.preview-count').html(''); + $countEl.find('.preview-count').html(this.esIcon('progress_activity', 'es-spin')); $countEl.removeClass('clickable no-matches').show(); // Store condition data on badge for popover @@ -1252,7 +1244,7 @@ } // Show loading - $badge.html('').show(); + $badge.html(this.esIcon('progress_activity', 'es-spin')).show(); $.ajax({ url: this.config.ajaxUrl, @@ -1271,7 +1263,7 @@ var excludeCount = response.exclude_count || 0; // Update badge with eye icon and count - var badgeHtml = ' ' + finalCount; + var badgeHtml = self.esIcon('visibility') + ' ' + finalCount; if (excludeCount > 0) { badgeHtml += ' (-' + excludeCount + ')'; } diff --git a/sources/js/admin/entity-selector/_core.js b/sources/js/admin/entity-selector/_core.js index 9803f94..671285d 100644 --- a/sources/js/admin/entity-selector/_core.js +++ b/sources/js/admin/entity-selector/_core.js @@ -127,16 +127,11 @@ // Add fullwidth class to parent form-group (skip for form-group layout) var hasLayoutFormGroup = this.$wrapper.hasClass('layout-form-group'); var $entitySelectorFormGroup = this.$wrapper.closest('.entity-selector-form-group'); - console.log('[EntitySelector] hasLayoutFormGroup:', hasLayoutFormGroup); - console.log('[EntitySelector] closest .entity-selector-form-group:', $entitySelectorFormGroup.length); if (!hasLayoutFormGroup && !$entitySelectorFormGroup.length) { - console.log('[EntitySelector] Adding condition-trait-fullwidth to form-group'); var $formGroup = this.$wrapper.closest('.form-group'); $formGroup.addClass('condition-trait-fullwidth'); $formGroup.find('.col-lg-offset-3').removeClass('col-lg-offset-3'); - } else { - console.log('[EntitySelector] SKIPPING fullwidth - form-group layout detected'); } this.createDropdown(); diff --git a/sources/js/admin/entity-selector/_dropdown.js b/sources/js/admin/entity-selector/_dropdown.js index a43774e..6895358 100644 --- a/sources/js/admin/entity-selector/_dropdown.js +++ b/sources/js/admin/entity-selector/_dropdown.js @@ -26,10 +26,10 @@ // Select all / Clear buttons with keyboard shortcuts html += ''; html += ''; // Sort controls - options with data-entities attribute for entity-specific filtering @@ -50,7 +50,7 @@ html += ''; html += ''; html += ''; // View mode selector - Tree option always present, shown for categories @@ -69,19 +69,19 @@ // Refine search html += '
'; - html += ''; + html += ''; html += ''; - html += ''; + html += ''; html += '
'; // Filter toggle button html += ''; // History button html += ''; html += ''; // End dropdown-actions @@ -104,13 +104,13 @@ html += ''; html += ''; html += ''; // Attribute/Feature filter toggles for products html += ''; html += ''; html += ''; html += ''; html += ''; } @@ -181,7 +181,7 @@ if ($btn.hasClass('loading')) return; $btn.addClass('loading'); - $btn.find('i').removeClass('icon-plus').addClass('icon-spinner icon-spin'); + $btn.find('i').replaceWith(self.esIcon('progress_activity', 'es-spin')); $select.prop('disabled', true); // Get selected load count @@ -192,8 +192,23 @@ }); } - // Position popover relative to badge (handles viewport overflow) - this.positionPopover($popover, $badge); + // 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 + }); // Show with transition $popover.addClass('show'); @@ -201,61 +216,6 @@ 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 */ @@ -276,7 +236,7 @@ // Reset button state $btn.removeClass('loading'); - $btn.find('i').removeClass('icon-spinner icon-spin').addClass('icon-plus'); + $btn.find('i').replaceWith(this.esIcon('add')); $select.prop('disabled', false); // Update remaining count @@ -326,7 +286,7 @@ if (item.image) { html += ''; } else { - html += '
inventory_2
'; + html += '
' + self.esIcon('inventory_2') + '
'; } // Info section @@ -418,7 +378,7 @@ $list.addClass('filtering'); // Add overlay if not exists if (!$list.find('.filter-loading-overlay').length) { - $list.append('
'); + $list.append('
' + this.esIcon('progress_activity', 'es-spin') + '
'); } } else { $list.removeClass('filtering'); @@ -470,7 +430,7 @@ var $select = $controls.find('.load-more-select'); $btn.removeClass('loading'); - $btn.find('i').removeClass('icon-spinner icon-spin').addClass('icon-plus'); + $btn.find('i').replaceWith(self.esIcon('add')); $select.prop('disabled', false); $controls.find('.remaining-count').text(remaining); @@ -493,7 +453,7 @@ footerHtml += ''; footerHtml += ''; footerHtml += '' + (trans.of || 'of') + ' ' + remaining + ' ' + (trans.remaining || 'remaining') + ''; - footerHtml += ''; + footerHtml += ''; footerHtml += ''; footerHtml += ''; @@ -511,7 +471,7 @@ if ($btn.hasClass('loading')) return; $btn.addClass('loading'); - $btn.find('i').removeClass('icon-plus').addClass('icon-spinner icon-spin'); + $btn.find('i').replaceWith(self.esIcon('progress_activity', 'es-spin')); $select.prop('disabled', true); var loadCount = parseInt($select.val(), 10) || 20; @@ -783,7 +743,7 @@ var $controls = $btn.closest('.load-more-controls'); var $select = $controls.find('.load-more-select'); $btn.removeClass('loading'); - $btn.find('i').removeClass('icon-spinner icon-spin').addClass('icon-plus'); + $btn.find('i').replaceWith(self.esIcon('add')); $select.prop('disabled', false); } }); @@ -932,7 +892,7 @@ var $controls = $btn.closest('.load-more-controls'); var $select = $controls.find('.load-more-select'); $btn.removeClass('loading'); - $btn.find('i').removeClass('icon-spinner icon-spin').addClass('icon-plus'); + $btn.find('i').replaceWith(self.esIcon('add')); $select.prop('disabled', false); } }); @@ -1220,144 +1180,6 @@ }); }, - // ========================================================================= - // 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) // ========================================================================= @@ -1425,7 +1247,7 @@ var isProducts = (ctx.entityType === 'categories'); var action = isProducts ? 'previewCategoryProducts' : 'previewCategoryPages'; - $btn.prop('disabled', true).find('i').addClass('icon-spin'); + $btn.prop('disabled', true).find('i').addClass('es-spin'); $.ajax({ url: this.config.ajaxUrl, @@ -1441,7 +1263,7 @@ query: this.previewFilterQuery || '' }, success: function(response) { - $btn.prop('disabled', false).find('i').removeClass('icon-spin'); + $btn.prop('disabled', false).find('i').removeClass('es-spin'); if (response.success && response.items) { self.appendPreviewItems(response.items); @@ -1453,7 +1275,7 @@ } }, error: function() { - $btn.prop('disabled', false).find('i').removeClass('icon-spin'); + $btn.prop('disabled', false).find('i').removeClass('es-spin'); } }); }, @@ -1513,13 +1335,13 @@ html += '
'; html += '
'; html += ''; - html += ' ' + (trans.preview || 'Preview') + ': ' + this.escapeHtml(pattern) + ''; + html += this.esIcon('visibility') + ' ' + (trans.preview || 'Preview') + ': ' + this.escapeHtml(pattern) + ''; html += ''; html += '' + count + ' ' + (count === 1 ? entityLabelSingular : entityLabelPlural) + ''; - html += ''; + html += ''; html += '
'; html += '
'; - html += '
' + (trans.loading || 'Loading...') + '
'; + html += '
' + this.esIcon('progress_activity', 'es-spin') + ' ' + (trans.loading || 'Loading...') + '
'; html += '
'; html += '
'; html += ''; @@ -1650,7 +1472,7 @@ if (count > 0) { var blockConfig = self.config.blocks && self.config.blocks[blockType] ? self.config.blocks[blockType] : {}; - var icon = $tab.find('.tab-label').prev('i').attr('class') || 'icon-cube'; + var icon = $tab.find('.tab-label').prev('i').text() || 'widgets'; var label = $tab.find('.tab-label').text() || blockType; summaryItems.push({ @@ -1675,7 +1497,7 @@ for (var i = 0; i < summaryItems.length; i++) { var item = summaryItems[i]; popoverHtml += '
  • '; - popoverHtml += ''; + popoverHtml += this.esIcon(item.icon); popoverHtml += '' + self.escapeHtml(item.label) + ''; popoverHtml += '' + item.count + ''; popoverHtml += '
  • '; @@ -1695,9 +1517,28 @@ self.switchToBlock(blockType); }); - // Position popover relative to badge (handles viewport overflow) + // Position popover $('body').append($popover); - this.positionPopover($popover, $badge); + 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); + } $popover.hide().fadeIn(150); }, @@ -1729,10 +1570,10 @@ } popoverHtml += this.escapeHtml(countryName) + ' - ' + (trans.holidays || 'Holidays'); popoverHtml += ''; - popoverHtml += ''; + popoverHtml += ''; popoverHtml += ''; popoverHtml += '
    '; - popoverHtml += '
    sync ' + (trans.loading || 'Loading...') + '
    '; + popoverHtml += '
    ' + this.esIcon('sync', 'es-spin') + ' ' + (trans.loading || 'Loading...') + '
    '; popoverHtml += '
    '; popoverHtml += ''; @@ -1819,7 +1660,7 @@ $popover.find('.popover-body').html(listHtml); } else { var noDataHtml = '
    '; - noDataHtml += 'event_busy'; + noDataHtml += self.esIcon('event_busy'); noDataHtml += '

    ' + (trans.no_holidays || 'No holidays found') + '

    '; noDataHtml += '
    '; $popover.find('.popover-body').html(noDataHtml); @@ -1836,7 +1677,7 @@ }, error: function() { var errorHtml = '
    '; - errorHtml += 'error_outline'; + errorHtml += self.esIcon('error'); errorHtml += '

    ' + (trans.error_loading || 'Error loading holidays') + '

    '; errorHtml += '
    '; $popover.find('.popover-body').html(errorHtml); @@ -1864,15 +1705,15 @@ // Create popover HTML with placeholder title (will update after AJAX) var popoverHtml = '
    '; popoverHtml += '
    '; - popoverHtml += 'sync ' + (trans.loading || 'Loading...') + ''; - popoverHtml += ''; + popoverHtml += '' + this.esIcon('sync', 'es-spin') + ' ' + (trans.loading || 'Loading...') + ''; + popoverHtml += ''; popoverHtml += '
    '; popoverHtml += '
    '; - popoverHtml += 'search'; + popoverHtml += this.esIcon('search'); popoverHtml += ''; popoverHtml += '
    '; popoverHtml += '
    '; - popoverHtml += '
    sync ' + (trans.loading || 'Loading...') + '
    '; + popoverHtml += '
    ' + this.esIcon('sync', 'es-spin') + ' ' + (trans.loading || 'Loading...') + '
    '; popoverHtml += '
    '; popoverHtml += '
    '; @@ -2060,7 +1901,7 @@ $popover.find('.popover-title').html('0 ' + (trans.holidays || 'Holidays')); var noDataHtml = '
    '; - noDataHtml += 'event_busy'; + noDataHtml += self.esIcon('event_busy'); noDataHtml += '

    ' + (trans.no_holidays || 'No holidays found') + '

    '; noDataHtml += '
    '; $popover.find('.popover-body').html(noDataHtml); @@ -2077,10 +1918,10 @@ }, error: function() { // Update header for error state - $popover.find('.popover-title').html('error_outline ' + (trans.error || 'Error')); + $popover.find('.popover-title').html(self.esIcon('error') + ' ' + (trans.error || 'Error')); var errorHtml = '
    '; - errorHtml += 'error_outline'; + errorHtml += self.esIcon('error'); errorHtml += '

    ' + (trans.error_loading || 'Error loading holidays') + '

    '; errorHtml += '
    '; $popover.find('.popover-body').html(errorHtml); diff --git a/sources/js/admin/entity-selector/_search.js b/sources/js/admin/entity-selector/_search.js index 6eb5169..ea05103 100644 --- a/sources/js/admin/entity-selector/_search.js +++ b/sources/js/admin/entity-selector/_search.js @@ -40,11 +40,6 @@ 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; @@ -366,14 +361,12 @@ var html = ''; if (visibleResults.length === 0 && !appendMode) { - html = '
    ' + (trans.no_results || 'No results found') + '
    '; + html = '
    ' + this.esIcon('search') + ' ' + (trans.no_results || 'No results found') + '
    '; } else { visibleResults.forEach(function(item) { 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 += '
    '; var searchEntity = self.activeGroup ? self.activeGroup.searchEntity : null; // Countries show flags if (searchEntity === 'countries' && item.iso_code) { var flagUrl = 'https://flagcdn.com/w40/' + item.iso_code.toLowerCase() + '.png'; - html += '
    ' + self.escapeAttr(item.iso_code) + '
    '; + html += '
    ' + self.escapeAttr(item.iso_code) + '
    '; } else if (item.image) { html += '
    '; } else { // Entity-specific icons - var iconClass = 'icon-cube'; // default - if (searchEntity === 'categories') iconClass = 'icon-folder'; - else if (searchEntity === 'manufacturers') iconClass = 'icon-building'; - else if (searchEntity === 'suppliers') iconClass = 'icon-truck'; - else if (searchEntity === 'attributes') iconClass = 'icon-paint-brush'; - else if (searchEntity === 'features') iconClass = 'icon-list-ul'; - else if (searchEntity === 'cms') iconClass = 'icon-file-text-o'; - else if (searchEntity === 'cms_categories') iconClass = 'icon-folder-o'; - html += '
    '; + var iconName = 'widgets'; // default + if (searchEntity === 'categories') iconName = 'folder'; + else if (searchEntity === 'manufacturers') iconName = 'business'; + else if (searchEntity === 'suppliers') iconName = 'local_shipping'; + else if (searchEntity === 'attributes') iconName = 'brush'; + else if (searchEntity === 'features') iconName = 'list'; + else if (searchEntity === 'cms') iconName = 'description'; + else if (searchEntity === 'cms_categories') iconName = 'folder'; + html += '
    ' + self.esIcon(iconName) + '
    '; } html += '
    '; @@ -596,10 +588,10 @@ for (var i = 0; i < history.length; i++) { var query = history[i]; html += '
    '; - html += ''; + html += this.esIcon('schedule'); html += '' + this.escapeHtml(query) + ''; html += ''; html += '
    '; } diff --git a/sources/js/admin/entity-selector/_tree.js b/sources/js/admin/entity-selector/_tree.js index 9e0a4fe..bd57557 100644 --- a/sources/js/admin/entity-selector/_tree.js +++ b/sources/js/admin/entity-selector/_tree.js @@ -36,7 +36,7 @@ var searchEntity = this.activeGroup ? this.activeGroup.searchEntity : 'categories'; // Show loading - $results.html('
    ' + + $results.html('
    ' + this.esIcon('progress_activity', 'es-spin') + ' ' + this.escapeHtml(trans.loading || 'Loading...') + '
    '); // Fetch tree data @@ -115,11 +115,11 @@ html += '
    '; html += ''; html += ''; html += '
    '; @@ -178,21 +178,21 @@ // Toggle button (expand/collapse) if (hasChildren) { - html += ''; + html += '' + self.esIcon('arrow_drop_down') + ''; // Select with children button (next to toggle on the left) html += ''; } else { html += ''; } // Checkbox indicator - html += ''; + html += '' + self.esIcon('check') + ''; // Category icon - html += ''; + html += '' + self.esIcon('folder') + ''; // Name html += '' + self.escapeHtml(node.name) + ''; @@ -203,7 +203,7 @@ var countLabel = node.page_count ? (trans.pages || 'pages') : (trans.products || 'products'); html += ''; - html += ' ' + itemCount; + html += self.esIcon('visibility') + ' ' + itemCount; html += ''; } @@ -346,10 +346,10 @@ }); if (isParentSelected && allChildrenSelected) { - $btn.find('i').removeClass('icon-plus-square').addClass('icon-minus-square'); + $btn.find('i').replaceWith(self.esIcon('indeterminate_check_box')); $btn.attr('title', trans.deselect_with_children || 'Deselect with all children'); } else { - $btn.find('i').removeClass('icon-minus-square').addClass('icon-plus-square'); + $btn.find('i').replaceWith(self.esIcon('add_box')); $btn.attr('title', trans.select_with_children || 'Select with all children'); } }); diff --git a/sources/js/admin/entity-selector/_utils.js b/sources/js/admin/entity-selector/_utils.js index 9c7d2ea..bc235a5 100644 --- a/sources/js/admin/entity-selector/_utils.js +++ b/sources/js/admin/entity-selector/_utils.js @@ -19,6 +19,97 @@ // Create mixin namespace window._EntitySelectorMixins = window._EntitySelectorMixins || {}; + // --------------------------------------------------------------- + // Icon framework detection & FA4 mapping (module-level singleton) + // --------------------------------------------------------------- + var _iconMode = null; + + /** + * Material Icons → FontAwesome 4 class mapping. + * FA4 uses class-based icons (icon-name), Material uses text content. + */ + var FA4_MAP = { + 'account_tree': 'icon-sitemap', + 'add': 'icon-plus', + 'add_box': 'icon-plus-square', + 'arrow_downward': 'icon-sort-desc', + 'arrow_drop_down': 'icon-caret-down', + 'arrow_right': 'icon-chevron-right', + 'arrow_upward': 'icon-sort-asc', + 'block': 'icon-ban', + 'brush': 'icon-paint-brush', + 'business': 'icon-building', + 'check': 'icon-check', + 'check_box': 'icon-check-square', + 'check_box_outline_blank': 'icon-square-o', + 'check_circle': 'icon-check-circle', + 'close': 'icon-times', + 'delete': 'icon-trash', + 'description': 'icon-file-text', + 'error': 'icon-exclamation-circle', + 'event': 'icon-calendar', + 'event_busy': 'icon-calendar-times-o', + 'expand_less': 'icon-chevron-up', + 'expand_more': 'icon-chevron-down', + 'filter_list': 'icon-filter', + 'flag': 'icon-flag', + 'folder': 'icon-folder', + 'folder_open': 'icon-folder-open', + 'indeterminate_check_box': 'icon-minus-square', + 'info': 'icon-info-circle', + 'inventory_2': 'icon-archive', + 'label': 'icon-tag', + 'language': 'icon-globe', + 'lightbulb': 'icon-lightbulb-o', + 'list': 'icon-list', + 'list_alt': 'icon-list-alt', + 'local_shipping': 'icon-truck', + 'lock': 'icon-lock', + 'my_location': 'icon-crosshairs', + 'open_in_full': 'icon-expand', + 'payments': 'icon-credit-card', + 'progress_activity': 'icon-circle-o-notch', + 'schedule': 'icon-clock-o', + 'search': 'icon-search', + 'shopping_cart': 'icon-shopping-cart', + 'shuffle': 'icon-random', + 'sort': 'icon-sort', + 'sort_by_alpha': 'icon-sort-alpha-asc', + 'star': 'icon-star', + 'sync': 'icon-refresh', + 'tune': 'icon-sliders', + 'visibility': 'icon-eye', + 'warning': 'icon-warning', + 'widgets': 'icon-th-large' + }; + + /** + * Detect icon framework: 'material' (PS 8+/9+) or 'fa4' (PS 1.6/1.7). + * Checks PHP-set data attribute first, falls back to font detection. + */ + function detectIconMode() { + if (_iconMode !== null) return _iconMode; + + // 1. PHP sets data-icon-mode on the wrapper + var $w = $('.entity-selector-trait[data-icon-mode], .target-conditions-trait[data-icon-mode]').first(); + if ($w.length && $w.data('icon-mode')) { + _iconMode = $w.data('icon-mode'); + return _iconMode; + } + + // 2. Fallback: probe whether Material Icons font is loaded + var test = document.createElement('i'); + test.className = 'material-icons'; + test.style.cssText = 'position:absolute;left:-9999px;top:-9999px;font-size:16px;pointer-events:none'; + test.textContent = 'check'; + (document.body || document.documentElement).appendChild(test); + var family = (window.getComputedStyle(test).fontFamily || '').toLowerCase(); + test.parentNode.removeChild(test); + + _iconMode = (family.indexOf('material') !== -1) ? 'material' : 'fa4'; + return _iconMode; + } + // Utility functions mixin window._EntitySelectorMixins.utils = { @@ -60,18 +151,62 @@ .replace(/'/g, '''); }, + /** + * Icon helper — returns HTML for an icon that works on PS 1.6 through 9.x. + * Automatically uses Material Icons (PS 8+/9+) or FontAwesome 4 (PS 1.6/1.7). + * + * @param {string} name - Canonical icon name (Material Icons name, e.g. 'lock', 'search', 'delete') + * @param {string} [extraClass] - Additional CSS class(es) (e.g. 'es-spin', 'method-trigger-icon') + * @returns {string} HTML string for an element + */ + esIcon: function(name, extraClass) { + var mode = detectIconMode(); + if (mode === 'material') { + var cls = 'material-icons es-icon'; + if (extraClass) cls += ' ' + extraClass; + return '' + name + ''; + } + // FA4: icon is encoded in the class name, no text content + var mapped = FA4_MAP[name] || 'icon-circle'; + var cls = mapped + ' es-icon'; + if (extraClass) cls += ' ' + extraClass; + return ''; + }, + + /** + * Update an existing icon element to show a different icon. + * Handles both Material Icons and FA4 modes. + * + * @param {jQuery} $el - The element to update + * @param {string} name - Canonical icon name + * @param {string} [extraClass] - Additional CSS class(es) to preserve + */ + esIconUpdate: function($el, name, extraClass) { + var mode = detectIconMode(); + if (mode === 'material') { + var cls = 'material-icons es-icon'; + if (extraClass) cls += ' ' + extraClass; + $el.attr('class', cls).text(name); + } else { + var mapped = FA4_MAP[name] || 'icon-circle'; + var cls = mapped + ' es-icon'; + if (extraClass) cls += ' ' + extraClass; + $el.attr('class', cls).text(''); + } + }, + getEntityTypeIcon: function(entityType) { var icons = { - 'products': 'icon-shopping-cart', - 'categories': 'icon-folder-open', - 'manufacturers': 'icon-building', - 'suppliers': 'icon-truck', - 'attributes': 'icon-list-alt', - 'features': 'icon-tags', - 'cms': 'icon-file-text', - 'cms_categories': 'icon-folder' + 'products': 'shopping_cart', + 'categories': 'folder_open', + 'manufacturers': 'business', + 'suppliers': 'local_shipping', + 'attributes': 'list_alt', + 'features': 'label', + 'cms': 'description', + 'cms_categories': 'folder' }; - return icons[entityType] || 'icon-cube'; + return icons[entityType] || 'widgets'; }, getEntityTypeLabel: function(entityType) { @@ -116,7 +251,7 @@ this.$wrapper.find('.trait-validation-error').remove(); var $error = $('
    ', { class: 'trait-validation-error', - html: ' ' + message + html: this.esIcon('warning') + ' ' + message }); this.$wrapper.find('.condition-trait-header').after($error); $('html, body').animate({ scrollTop: this.$wrapper.offset().top - 100 }, 300); diff --git a/sources/js/admin/entity-selector/_validation.js b/sources/js/admin/entity-selector/_validation.js index 5cfecab..089a57b 100644 --- a/sources/js/admin/entity-selector/_validation.js +++ b/sources/js/admin/entity-selector/_validation.js @@ -297,12 +297,12 @@ // Create toast HTML var html = '
    '; - html += '
    '; + html += '
    ' + this.esIcon('warning') + '
    '; html += '
    '; html += '
    ' + this.escapeHtml(title) + '
    '; html += '
    ' + this.escapeHtml(message) + '
    '; html += '
    '; - html += ''; + html += ''; html += '
    '; var $toast = $(html); diff --git a/sources/scss/components/_chips.scss b/sources/scss/components/_chips.scss index aec406c..3f34566 100644 --- a/sources/scss/components/_chips.scss +++ b/sources/scss/components/_chips.scss @@ -332,7 +332,7 @@ color: darken($es-primary, 10%); } - i.material-icons { + i { font-size: 14px; } } @@ -831,7 +831,7 @@ color: $es-text-secondary; } - i.material-icons { + i { font-size: 18px; } } @@ -853,7 +853,7 @@ color: $es-text-muted; font-size: $es-font-size-sm; - i.material-icons { + i { font-size: 20px; } @@ -868,7 +868,7 @@ padding: $es-spacing-xl 0; color: $es-text-muted; - i.material-icons { + i { font-size: 48px; opacity: 0.4; margin-bottom: $es-spacing-sm; @@ -978,7 +978,7 @@ border-bottom: 1px solid $es-border-color; background: $es-slate-50; - i.material-icons { + i { font-size: 18px; color: $es-text-muted; } diff --git a/sources/scss/components/_entity-selector.scss b/sources/scss/components/_entity-selector.scss index 2b3599e..89de97d 100644 --- a/sources/scss/components/_entity-selector.scss +++ b/sources/scss/components/_entity-selector.scss @@ -261,7 +261,7 @@ color: $es-primary; } - .material-icons { + > i { font-size: 20px !important; } } diff --git a/sources/scss/components/_list-preview.scss b/sources/scss/components/_list-preview.scss index dd9af79..0c1b3f3 100644 --- a/sources/scss/components/_list-preview.scss +++ b/sources/scss/components/_list-preview.scss @@ -579,7 +579,6 @@ } // Icon styles - > .material-icons, > i:first-child { flex-shrink: 0; width: 16px; @@ -639,7 +638,7 @@ opacity: 0.8; } - .material-icons { + > i { font-size: 12px; line-height: 1; } diff --git a/sources/scss/components/_modal.scss b/sources/scss/components/_modal.scss index 094aa3b..a77ee30 100644 --- a/sources/scss/components/_modal.scss +++ b/sources/scss/components/_modal.scss @@ -24,8 +24,8 @@ } } -// Modal container -.mpr-modal { +// Modal container (exclude Bootstrap .modal to prevent collision) +.mpr-modal:not(.modal) { position: fixed; top: 50%; left: 50%; @@ -337,7 +337,7 @@ color: $es-text-primary; margin: 0; - i.material-icons { + i> i { font-size: 20px; color: $es-primary; } @@ -392,7 +392,7 @@ padding: $es-spacing-xl 0; color: $es-text-muted; - i.material-icons { + i> i { font-size: 48px; opacity: 0.5; margin-bottom: $es-spacing-md; diff --git a/sources/scss/components/_schedule.scss b/sources/scss/components/_schedule.scss index 82fc33c..ce29362 100644 --- a/sources/scss/components/_schedule.scss +++ b/sources/scss/components/_schedule.scss @@ -329,7 +329,7 @@ background: $es-slate-200; } - .material-icons { + > i { color: $es-slate-400; font-size: 20px; } @@ -357,7 +357,7 @@ border-radius: $es-radius-full; white-space: nowrap; - .material-icons { + > i { font-size: 14px; opacity: 0.7; } diff --git a/sources/scss/components/_tooltip.scss b/sources/scss/components/_tooltip.scss index 48b918b..aaaeade 100644 --- a/sources/scss/components/_tooltip.scss +++ b/sources/scss/components/_tooltip.scss @@ -17,13 +17,13 @@ vertical-align: middle; margin-left: 0.25rem; - .material-icons { - font-size: 16px; + > i { + font-size: 14px; color: $es-text-muted; transition: color 0.15s ease; } - &:hover .material-icons { + &:hover > i { color: $es-primary; } } @@ -92,7 +92,7 @@ line-height: 1; transition: background-color 0.15s ease; - .material-icons { + > i { font-size: 16px; color: $es-text-muted; } @@ -100,7 +100,7 @@ &:hover { background: $es-slate-100; - .material-icons { + > i { color: $es-slate-700; } } diff --git a/sources/sources/index.php b/sources/sources/index.php new file mode 100644 index 0000000..c4f371f --- /dev/null +++ b/sources/sources/index.php @@ -0,0 +1 @@ +'; + + // Country: show flag + if (isCountry && data && data.iso_code) { + html += '' + this.escapeAttr(data.iso_code) + '' + this.esIcon('flag', 'flag-fallback').replace('>', ' style="display:none">') + ''; + } else if (data && data.image) { + html += ''; + } + + html += '' + this.escapeHtml(name) + ''; + + // Country: add holiday preview button + if (isCountry) { + html += ''; + } + + html += ''; + html += ''; + + $chips.append(html); + }, + + removeSelection: function($picker, id) { + var $chips = $picker.find('.entity-chips'); + $picker.find('.entity-chip[data-id="' + id + '"]').remove(); + this.updateChipsVisibility($chips); + }, + + updateChipsVisibility: function($chips) { + var self = this; + var trans = this.config.trans || {}; + var $picker = $chips.closest('.value-picker'); + var $allChips = $chips.find('.entity-chip'); + var totalCount = $allChips.length; + + // If no chips, remove the wrapper entirely + var $existingWrapper = $chips.closest('.chips-wrapper'); + if (totalCount === 0) { + if ($existingWrapper.length) { + // Move chips out of wrapper before removing + $existingWrapper.before($chips); + $existingWrapper.remove(); + } + return; + } + + // Ensure chips wrapper structure exists + this.ensureChipsWrapper($chips); + + var $wrapper = $chips.closest('.chips-wrapper'); + var $toolbar = $wrapper.find('.chips-toolbar'); + var $loadMore = $wrapper.find('.chips-load-more'); + + // Get current search filter + var searchTerm = $toolbar.find('.chips-search-input').val() || ''; + searchTerm = searchTerm.toLowerCase().trim(); + + // Filter and paginate chips + var visibleCount = 0; + var filteredCount = 0; + var isExpanded = $chips.hasClass('chips-expanded'); + var maxVisible = isExpanded ? 999999 : (this.maxVisibleChips || 12); + + $allChips.each(function() { + var $chip = $(this); + var chipName = ($chip.find('.chip-name').text() || '').toLowerCase(); + var matchesFilter = !searchTerm || chipName.indexOf(searchTerm) !== -1; + + $chip.removeClass('chip-filtered-out chip-paginated-out'); + + if (!matchesFilter) { + $chip.addClass('chip-filtered-out'); + } else { + filteredCount++; + if (filteredCount > maxVisible) { + $chip.addClass('chip-paginated-out'); + } else { + visibleCount++; + } + } + }); + + // Update toolbar (always show when we have chips) + $toolbar.addClass('has-chips'); + this.updateChipsToolbar($toolbar, totalCount, filteredCount, searchTerm); + + // Update load more select dropdown + var hiddenByPagination = filteredCount - visibleCount; + if (hiddenByPagination > 0 && !isExpanded) { + var loadText = trans.load || 'Load'; + var remainingText = (trans.remaining || '{count} remaining').replace('{count}', hiddenByPagination); + var loadMoreHtml = '' + loadText + '' + + '' + + '' + remainingText + ''; + $loadMore.html(loadMoreHtml).show(); + } else if (isExpanded && filteredCount > (this.maxVisibleChips || 12)) { + var collapseText = trans.collapse || 'Collapse'; + $loadMore.html( + '' + ).show(); + } else { + $loadMore.hide(); + } + }, + + ensureChipsWrapper: function($chips) { + // Check if already wrapped + if ($chips.closest('.chips-wrapper').length) { + return; + } + + var trans = this.config.trans || {}; + var $picker = $chips.closest('.value-picker'); + + // Create wrapper structure - integrated filter toolbar with sort + var wrapperHtml = '
    ' + + '
    ' + + '' + + '' + + '' + + '' + + '
    ' + + '' + + '
    '; + + var $wrapper = $(wrapperHtml); + + // Insert wrapper before chips and move chips inside + $chips.before($wrapper); + $wrapper.find('.chips-toolbar').after($chips); + $wrapper.append($wrapper.find('.chips-load-more')); + + // Bind toolbar events + this.bindChipsToolbarEvents($wrapper); + }, + + bindChipsToolbarEvents: function($wrapper) { + var self = this; + var $chips = $wrapper.find('.entity-chips'); + var searchTimeout; + + // Search input + $wrapper.on('input', '.chips-search-input', function() { + clearTimeout(searchTimeout); + searchTimeout = setTimeout(function() { + // Collapse when searching to show filtered results from start + $chips.removeClass('chips-expanded'); + self.updateChipsVisibility($chips); + }, 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() || ''; + var $chipsToRemove; + + if (searchTerm.trim()) { + // Remove only filtered (visible) chips + $chipsToRemove = $chips.find('.entity-chip:not(.chip-filtered-out)'); + } else { + // Remove all chips + $chipsToRemove = $chips.find('.entity-chip'); + } + + $chipsToRemove.each(function() { + $(this).find('.chip-remove').trigger('click'); + }); + + // Clear search + $wrapper.find('.chips-search-input').val(''); + self.updateChipsVisibility($chips); + }); + + // 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) { + var trans = this.config.trans || {}; + var $count = $toolbar.find('.chips-count'); + var $clearBtn = $toolbar.find('.btn-chips-clear'); + var $clearText = $clearBtn.find('.clear-text'); + + // Update count display + if (searchTerm) { + $count.addClass('has-filter').html( + '' + filteredCount + '' + + '/' + + '' + totalCount + '' + ); + $clearText.text((trans.clear || 'Clear') + ' ' + filteredCount); + } else { + $count.removeClass('has-filter').html(totalCount); + $clearText.text(trans.clear_all || 'Clear all'); + } + + // Show/hide clear button + if (searchTerm && filteredCount === 0) { + $clearBtn.hide(); + } else if (totalCount > 0) { + $clearBtn.show(); + } else { + $clearBtn.hide(); + } + }, + + // ========================================================================= + // Loading/Initialization + // ========================================================================= + + loadExistingSelections: function() { + var self = this; + console.log('[EntitySelector] loadExistingSelections called for id:', this.config.id); + + // Collect all entity IDs to load, grouped by entity type + var entitiesToLoad = {}; // { entity_type: { ids: [], pickers: [] } } + + console.log('[EntitySelector] Looking for .selection-group in wrapper:', this.$wrapper.length ? 'found' : 'NOT FOUND'); + this.$wrapper.find('.selection-group').each(function() { + console.log('[EntitySelector] Found .selection-group, index:', $(this).data('groupIndex')); + var $group = $(this); + var $block = $group.closest('.target-block'); + var blockType = $block.data('blockType'); + + // Load include values + var $includePicker = $group.find('.include-picker'); + self.collectPickerEntities($includePicker, blockType, entitiesToLoad); + + // Enhance the include method select if not already enhanced + self.enhanceMethodSelect($group.find('.include-method-select')); + + // Load exclude values from each exclude row + $group.find('.exclude-row').each(function() { + var $excludeRow = $(this); + self.collectPickerEntities($excludeRow.find('.exclude-picker'), blockType, entitiesToLoad); + + // Enhance the exclude method select if not already enhanced + self.enhanceMethodSelect($excludeRow.find('.exclude-method-select')); + }); + + // Lock method selector if excludes exist + var hasExcludes = $group.find('.group-excludes.has-excludes').length > 0; + if (hasExcludes) { + self.updateMethodSelectorLock($group, true); + } + }); + + // Build bulk request: { entityType: [uniqueIds], ... } + var bulkRequest = {}; + var hasEntities = false; + + Object.keys(entitiesToLoad).forEach(function(entityType) { + var data = entitiesToLoad[entityType]; + if (data.ids.length === 0) return; + + // Deduplicate IDs + var uniqueIds = data.ids.filter(function(id, index, arr) { + return arr.indexOf(id) === index; + }); + + bulkRequest[entityType] = uniqueIds; + hasEntities = true; + }); + + // Skip AJAX if no entities to load + if (!hasEntities) { + console.log('[EntitySelector] No entities to load, skipping AJAX'); + return; + } + + console.log('[EntitySelector] Making bulk AJAX request for entities:', JSON.stringify(bulkRequest)); + + // Single bulk AJAX call for all entity types + $.ajax({ + url: self.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'getTargetEntitiesByIdsBulk', + trait: 'EntitySelector', + entities: JSON.stringify(bulkRequest) + }, + success: function(response) { + console.log('[EntitySelector] AJAX response:', response); + if (!response.success || !response.entities) { + console.log('[EntitySelector] Response failed or no entities'); + return; + } + try { + + // Process each entity type's results + Object.keys(entitiesToLoad).forEach(function(entityType) { + var data = entitiesToLoad[entityType]; + var entities = response.entities[entityType] || []; + + // Build a map of id -> entity for quick lookup + var entityMap = {}; + entities.forEach(function(entity) { + entityMap[entity.id] = entity; + }); + + // Update each picker that requested this entity type + data.pickers.forEach(function(pickerData) { + var $picker = pickerData.$picker; + var $chips = $picker.find('.entity-chips'); + var $dataInput = $picker.find('.include-values-data, .exclude-values-data'); + var validIds = []; + + // Check if this is a country entity + var isCountry = (entityType === 'countries'); + + // Replace loading chips with real data + pickerData.ids.forEach(function(id) { + var $loadingChip = $chips.find('.entity-chip-loading[data-id="' + id + '"]'); + if (entityMap[id]) { + var entity = entityMap[id]; + validIds.push(entity.id); + + // Create real chip + var html = '' + self.esIcon('flag', 'flag-fallback').replace('>', ' style="display:none">') + ''; + } else if (entity.image) { + html += ''; + } + + html += '' + self.escapeHtml(entity.name) + ''; + + // Country: add holiday preview button + if (isCountry) { + html += ''; + } + + html += ''; + html += ''; + + $loadingChip.replaceWith(html); + } else { + // Entity not found, remove loading chip + $loadingChip.remove(); + } + }); + + // Update chips visibility + self.updateChipsVisibility($chips); + + // If some entities were not found, update the hidden input + if (validIds.length !== pickerData.ids.length) { + $dataInput.val(JSON.stringify(validIds)); + self.serializeAllBlocks(); + } + + self.updateBlockStatus($picker.closest('.target-block')); + }); + }); + + // Update condition counts after chips are loaded (for holiday counts, etc.) + self.updateAllConditionCounts(); + + } catch (e) { + console.error('[EntitySelector] Error processing AJAX response:', e); + } + }, + error: function(xhr, status, error) { + console.error('[EntitySelector] AJAX request failed:', status, error, xhr.responseText); + } + }); + }, + + /** + * Collect entity IDs from a picker for bulk loading + * Also shows loading placeholders for entity_search types + */ + collectPickerEntities: function($picker, blockType, entitiesToLoad) { + console.log('[EntitySelector] collectPickerEntities called, blockType:', blockType, 'picker length:', $picker.length); + if (!$picker.length) { + console.log('[EntitySelector] Picker not found, returning'); + return; + } + + var self = this; + var $dataInput = $picker.find('.include-values-data, .exclude-values-data'); + console.log('[EntitySelector] Looking for values-data input, found:', $dataInput.length); + if (!$dataInput.length) { + console.log('[EntitySelector] No data input found, returning'); + return; + } + + var valueType = $picker.attr('data-value-type'); + var rawValue = $dataInput.val() || '[]'; + console.log('[EntitySelector] valueType:', valueType, 'rawValue:', rawValue); + + var values = []; + try { + values = JSON.parse(rawValue); + console.log('[EntitySelector] Parsed values:', values); + } catch (e) { + console.log('[EntitySelector] JSON parse error:', e); + return; + } + + // Handle non-entity types synchronously + if (valueType === 'multi_numeric_range') { + if (!Array.isArray(values) || values.length === 0) return; + + var $chipsContainer = $picker.find('.multi-range-chips'); + values.forEach(function(range) { + if (!range || (range.min === null && range.max === null)) return; + + var chipText = ''; + if (range.min !== null && range.max !== null) { + chipText = range.min + ' - ' + range.max; + } else if (range.min !== null) { + chipText = '≥ ' + range.min; + } else { + chipText = '≤ ' + range.max; + } + + var $chip = $('', { + class: 'range-chip', + 'data-min': range.min !== null ? range.min : '', + 'data-max': range.max !== null ? range.max : '' + }); + $chip.append($('', { class: 'range-chip-text', text: chipText })); + $chip.append($(''; + html += '' + this.escapeHtml(pattern) + ''; + html += ''; + html += '
    '; + $chipsContainer.append(html); + }, + + /** + * Get all pattern tags from a wrapper + * Returns array of objects: { pattern: string, caseSensitive: boolean } + */ + getPatternTags: function($wrapper) { + var patterns = []; + // Exclude draft-tag which is the input field, not a saved pattern + $wrapper.find('.pattern-tag:not(.draft-tag)').each(function() { + var pattern = $(this).data('pattern'); + var caseSensitive = $(this).data('caseSensitive') === 1 || $(this).data('caseSensitive') === '1'; + if (pattern) { + patterns.push({ + pattern: pattern, + caseSensitive: caseSensitive + }); + } + }); + return patterns; + }, + + /** + * Update the match count displayed in the draft tag while typing + * Shows live preview with current case sensitivity setting + */ + updateDraftTagCount: function($draftTag, pattern, caseSensitive) { + var self = this; + var $matchCount = $draftTag.find('.pattern-match-count'); + var $countValue = $matchCount.find('.count-value'); + + // Get entity type from block + var $block = $draftTag.closest('.target-block'); + var entityType = $block.data('blockType') || 'products'; + + // Show loading - keep eye icon, update count value + $countValue.html(this.esIcon('progress_activity', 'es-spin')); + $matchCount.show(); + + // Store pattern for click handler + $matchCount.data('pattern', pattern); + $matchCount.data('caseSensitive', caseSensitive); + $matchCount.data('entityType', entityType); + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'countPatternMatches', + trait: 'EntitySelector', + pattern: pattern, + field: 'name', + entity_type: entityType, + case_sensitive: caseSensitive ? 1 : 0 + }, + success: function(response) { + if (response.success) { + var count = parseInt(response.count, 10) || 0; + $countValue.text(count); + $matchCount.show(); + // Add visual feedback based on count + $matchCount.removeClass('count-zero count-found'); + $matchCount.addClass(count === 0 ? 'count-zero' : 'count-found'); + // Store count for preview + $matchCount.data('count', count); + // Update group total count to reflect draft pattern in calculation + var $group = $draftTag.closest('.selection-group'); + if ($group.length) { + self.updateGroupTotalCount($group); + } + } else { + $countValue.text('?'); + $matchCount.show(); + } + }, + error: function() { + $countValue.text('?'); + $matchCount.show(); + } + }); + }, + + /** + * Update condition count with a pending pattern (typed but not yet added as tag) + * This shows a live preview of what the count would be if the user pressed Enter + */ + updateConditionCountWithPendingPattern: function($row, pendingPattern) { + var self = this; + var trans = this.config.trans || {}; + + // Find the count element - in method-selector-wrapper for include, in exclude-header-row for exclude + var $countEl = $row.find('.method-selector-wrapper > .condition-match-count, > .exclude-header-row > .condition-match-count').first(); + if (!$countEl.length) return; + + var isExclude = $row.hasClass('exclude-row'); + var $methodSelect = isExclude + ? $row.find('.exclude-method-select') + : $row.find('.include-method-select'); + + var method = $methodSelect.val(); + if (!method) { + $countEl.hide(); + return; + } + + var $picker = isExclude + ? $row.find('.exclude-picker') + : $row.find('.include-picker'); + + var valueType = $picker.data('valueType') || 'none'; + + // Only process for pattern value types + if (valueType !== 'pattern') { + return; + } + + // Get existing pattern tags + var values = this.getPatternTags($picker); + + // Add the pending pattern as a temporary tag (case-insensitive by default) + if (pendingPattern) { + values.push({ pattern: pendingPattern, caseSensitive: false }); + } + + if (values.length === 0) { + $countEl.hide(); + return; + } + + var $block = $row.closest('.target-block'); + var blockType = $block.data('blockType') || 'products'; + + // Show loading + $countEl.find('.preview-count').html(this.esIcon('progress_activity', 'es-spin')); + $countEl.removeClass('clickable no-matches').show(); + + // Store condition data on badge for popover + $countEl.data('conditionData', { + method: method, + values: values, + blockType: blockType, + isExclude: isExclude + }); + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'countConditionMatches', + trait: 'EntitySelector', + method: method, + values: JSON.stringify(values), + block_type: blockType + }, + success: function(response) { + if (response && response.success) { + var count = response.count || 0; + $countEl.removeClass('no-matches clickable'); + if (count === 0) { + $countEl.find('.preview-count').text(count); + $countEl.addClass('no-matches').show(); + } else { + $countEl.find('.preview-count').text(count); + $countEl.addClass('clickable').show(); + } + } else { + $countEl.hide().removeClass('clickable'); + } + }, + error: function() { + $countEl.hide().removeClass('clickable'); + } + }); + }, + + /** + * Fetch pattern match count via AJAX + */ + fetchPatternMatchCount: function($picker, pattern, $countEl) { + // Determine field type from method select + // Check if we're in an exclude row first, then fall back to include + var $excludeRow = $picker.closest('.exclude-row'); + var $methodSelect; + if ($excludeRow.length) { + $methodSelect = $excludeRow.find('.exclude-method-select'); + } else { + var $group = $picker.closest('.selection-group'); + $methodSelect = $group.find('.include-method-select'); + } + var method = $methodSelect.val() || ''; + var field = method.indexOf('reference') !== -1 ? 'reference' : 'name'; + + // Get entity type from block + var $block = $picker.closest('.target-block'); + var entityType = $block.data('blockType') || 'products'; + + // Show loading state + $countEl.find('.preview-count').html(this.esIcon('progress_activity', 'es-spin')); + $countEl.removeClass('clickable no-matches').show(); + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'countPatternMatches', + trait: 'EntitySelector', + pattern: pattern, + field: field, + entity_type: entityType, + case_sensitive: 0 + }, + success: function(response) { + if (response && response.success) { + var count = response.count || 0; + $countEl.find('.preview-count').text(count); + $countEl.removeClass('no-matches clickable').show(); + if (count === 0) { + $countEl.addClass('no-matches'); + } else { + $countEl.addClass('clickable'); + } + } else { + $countEl.hide(); + } + }, + error: function() { + $countEl.hide(); + } + }); + }, + + // ========================================================================= + // Picker Value Extraction + // ========================================================================= + + /** + * Get values from a picker based on its type + */ + getPickerValues: function($picker, valueType) { + switch (valueType) { + case 'entity_search': + var ids = []; + $picker.find('.entity-chip').each(function() { + var id = $(this).data('id'); + if (id) ids.push(id); + }); + return ids; + + case 'pattern': + var patternValues = this.getPatternTags($picker); + // Also include draft pattern if it has content (not yet added as tag) + var $draftPatternInput = $picker.find('.draft-tag .pattern-input'); + var draftPatternVal = $.trim($draftPatternInput.val()); + if (draftPatternVal) { + var draftCaseSens = $draftPatternInput.closest('.draft-tag').attr('data-case-sensitive') === '1'; + patternValues.push({ + pattern: draftPatternVal, + caseSensitive: draftCaseSens + }); + } + return patternValues; + + case 'numeric_range': + var min = $picker.find('.range-min-input').val(); + var max = $picker.find('.range-max-input').val(); + return { min: min || null, max: max || null }; + + case 'date_range': + var from = $picker.find('.date-from-input').val(); + var to = $picker.find('.date-to-input').val(); + return { from: from || null, to: to || null }; + + case 'select': + return [$picker.find('.select-value-input').val()]; + + case 'boolean': + return [true]; + + default: + return []; + } + }, + + // ========================================================================= + // Count/Status Updates + // ========================================================================= + + /** + * Fetch and update condition match count for a row (include or exclude) + */ + updateConditionCount: function($row) { + var self = this; + var trans = this.config.trans || {}; + + // Find the count element - in method-selector-wrapper for include, in exclude-header-row for exclude + var $countEl = $row.find('.method-selector-wrapper > .condition-match-count, > .exclude-header-row > .condition-match-count').first(); + if (!$countEl.length) return; + + // Determine if this is an include or exclude row + var isExclude = $row.hasClass('exclude-row'); + var $methodSelect = isExclude + ? $row.find('.exclude-method-select') + : $row.find('.include-method-select'); + + var method = $methodSelect.val(); + if (!method) { + $countEl.hide(); + return; + } + + // Get the picker and extract values + var $picker = isExclude + ? $row.find('.exclude-picker') + : $row.find('.include-picker'); + + var valueType = $picker.data('valueType') || 'none'; + var values = this.getPickerValues($picker, valueType); + + // Don't count if no values (except for boolean/all methods) + var hasNoValues = !values || + (Array.isArray(values) && values.length === 0) || + (typeof values === 'object' && !Array.isArray(values) && ( + // For combination_attributes, check if attributes object is empty + (valueType === 'combination_attributes' && values.attributes !== undefined && Object.keys(values.attributes).length === 0) || + // For other objects, check if completely empty + (valueType !== 'combination_attributes' && Object.keys(values).length === 0) + )); + if (valueType !== 'none' && valueType !== 'boolean' && hasNoValues) { + $countEl.hide(); + return; + } + + // Get block type + var $block = $row.closest('.target-block'); + var blockType = $block.data('blockType') || 'products'; + + // Show loading + $countEl.find('.preview-count').html(this.esIcon('progress_activity', 'es-spin')); + $countEl.removeClass('clickable no-matches').show(); + + // Store condition data on badge for popover + $countEl.data('conditionData', { + method: method, + values: values, + blockType: blockType, + isExclude: isExclude + }); + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'countConditionMatches', + trait: 'EntitySelector', + method: method, + values: JSON.stringify(values), + block_type: blockType + }, + success: function(response) { + if (response && response.success) { + var count = response.count || 0; + $countEl.removeClass('no-matches clickable'); + if (count === 0) { + $countEl.find('.preview-count').text(count); + $countEl.addClass('no-matches').show(); + } else { + // Show count, make clickable for preview popover + $countEl.find('.preview-count').text(count); + $countEl.addClass('clickable').show(); + } + } else { + $countEl.hide().removeClass('clickable'); + } + }, + error: function() { + $countEl.hide().removeClass('clickable'); + } + }); + }, + + /** + * Update all condition counts in a group + */ + updateGroupCounts: function($group) { + var self = this; + + // Update include count + var $include = $group.find('.group-include'); + if ($include.length) { + this.updateConditionCount($include); + } + + // Update each exclude row count + $group.find('.exclude-row').each(function() { + self.updateConditionCount($(this)); + }); + + // Update group total count (include - excludes) + this.updateGroupTotalCount($group); + }, + + /** + * Update the group total count badge (include - excludes) + * Also updates the limit input placeholder + */ + updateGroupTotalCount: function($group) { + var self = this; + var $block = $group.closest('.target-block'); + var blockType = $block.data('blockType') || 'products'; + var $badge = $group.find('.group-header .group-count-badge'); + var $limitInput = $group.find('.group-modifier-limit'); + + // Build group data for AJAX + var groupData = this.serializeGroup($group, blockType); + + // Check if include has valid data + if (!groupData.include || !groupData.include.method) { + $badge.hide(); + $limitInput.attr('placeholder', '–'); + return; + } + + // Show loading + $badge.html(this.esIcon('progress_activity', 'es-spin')).show(); + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'countGroupItems', + trait: 'EntitySelector', + group_data: JSON.stringify(groupData), + block_type: blockType + }, + success: function(response) { + if (response && response.success) { + var finalCount = response.final_count || 0; + var excludeCount = response.exclude_count || 0; + + // Update badge with eye icon and count + var badgeHtml = self.esIcon('visibility') + ' ' + finalCount; + if (excludeCount > 0) { + badgeHtml += ' (-' + excludeCount + ')'; + } + $badge.html(badgeHtml); + $badge.addClass('clickable').show(); + + // Store group data on badge for preview popover + $badge.data('groupData', groupData); + $badge.data('blockType', blockType); + $badge.data('finalCount', finalCount); + + // Update limit placeholder with the count + $limitInput.attr('placeholder', finalCount); + + // Also update the group-preview-badge count (apply limit if set) + var $previewBadge = $group.find('.group-preview-badge .preview-count'); + if ($previewBadge.length) { + var limit = parseInt($limitInput.val(), 10); + var displayCount = (limit > 0 && limit < finalCount) ? limit : finalCount; + $previewBadge.text(displayCount); + } + } else { + $badge.hide().removeClass('clickable'); + $limitInput.attr('placeholder', '–'); + } + }, + error: function() { + $badge.hide(); + $limitInput.attr('placeholder', '–'); + } + }); + }, + + /** + * Update all condition counts for all visible groups + */ + updateAllConditionCounts: function() { + var self = this; + this.$wrapper.find('.target-block.active .selection-group').each(function() { + self.updateGroupCounts($(this)); + }); + }, + + /** + * Fetch category names by IDs and add chips to the picker + * Used when adding selections from the tree modal + * @param {jQuery} $picker - Picker element + * @param {Array} ids - Category IDs to add + * @param {string} entityType - 'categories' or 'cms_categories' + * @param {Function} callback - Called when done + */ + fetchCategoryNamesAndAddChips: function($picker, ids, entityType, callback) { + var self = this; + + if (!ids || ids.length === 0) { + if (typeof callback === 'function') { + callback(); + } + return; + } + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'getTargetEntitiesByIds', + trait: 'EntitySelector', + entity_type: entityType, + ids: JSON.stringify(ids) + }, + success: function(response) { + if (response.success && response.entities) { + response.entities.forEach(function(entity) { + self.addSelectionNoUpdate($picker, entity.id, entity.name, entity); + }); + } + if (typeof callback === 'function') { + callback(); + } + }, + error: function() { + if (typeof callback === 'function') { + callback(); + } + } + }); + } + }; + +})(jQuery); diff --git a/sources/sources/js/admin/entity-selector/_core.js b/sources/sources/js/admin/entity-selector/_core.js new file mode 100644 index 0000000..671285d --- /dev/null +++ b/sources/sources/js/admin/entity-selector/_core.js @@ -0,0 +1,307 @@ +/** + * Entity Selector - Core Module + * Factory, initialization, state management + * @partial _core.js + * + * IMPORTANT: This file must be loaded LAST in the concatenation order + * as it combines all mixins from other partials. + * + * EXTRACTION SOURCE: assets/js/admin/entity-selector.js + * Lines: 15-55 (createTargetConditionsInstance, state variables) + * 56-110 (init method) + * 108-132 (observeNewSelects) + * 7889-7951 (Factory object, window export, document ready) + * + * Contains: + * - createTargetConditionsInstance() - Factory function + * - State variable initialization + * - init() - Main initialization method + * - observeNewSelects() - MutationObserver for dynamic selects + * - loadExistingSelections() - Restore saved state + * - TargetConditions factory object + * - window.TargetConditions export + * - Document ready auto-initialization + */ + +(function($) { + 'use strict'; + + /** + * Create a new TargetConditions instance + * Each instance is independent and manages its own wrapper/state + */ + function createTargetConditionsInstance() { + // Base instance object with state variables + var instance = { + config: {}, + $wrapper: null, + $dropdown: null, + activeGroup: null, // { blockType, groupIndex, section: 'include'|'exclude' } + searchTimeout: null, + searchResults: [], + searchTotal: 0, + searchOffset: 0, + searchQuery: '', + isLoading: false, + loadMoreCount: 20, + // Sort, filter, view state + viewMode: 'list', + currentSort: { field: 'name', dir: 'ASC' }, + refineQuery: '', + refineNegate: false, + filters: { + inStock: false, + discounted: false, + priceMin: null, + priceMax: null, + attributes: [], + features: [], + // Entity-specific filters + productCountMin: null, + productCountMax: null, + salesMin: null, + salesMax: null, + turnoverMin: null, + turnoverMax: null, + depth: null, + hasProducts: false, + hasDescription: false, + hasImage: false, + activeOnly: true, // Default to active only + attributeGroup: null, + featureGroup: null, + dateAddFrom: null, + dateAddTo: null, + lastProductFrom: null, + lastProductTo: null, + // Country-specific filters + hasHolidays: false, + containsStates: false, + zone: null + }, + filterableData: null, + // Search history + searchHistory: {}, + searchHistoryMax: 10, + searchHistoryKey: 'targetConditionsSearchHistory', + // Chips visibility + maxVisibleChips: 20, + // Method dropdown references + $methodDropdownMenu: null, + $methodDropdownSelect: null, + $methodDropdownTrigger: null, + // Preview state + $previewPopover: null, + $activeBadge: null, + $previewList: null, + previewLoadedCount: 0, + previewBlockType: null, + allPreviewData: null, + // Count update timeout + countUpdateTimeout: null, + + init: function(options) { + this.config = $.extend({ + id: 'target-conditions', + name: 'target_conditions', + namePrefix: 'target_', + mode: 'multi', // Global mode: 'multi' or 'single' + blocks: {}, + ajaxUrl: '', + trans: {} + }, options); + + this.$wrapper = $('[data-entity-selector-id="' + this.config.id + '"]'); + + if (!this.$wrapper.length) { + return; + } + + // Global single mode - hide "Add Group" buttons + if (this.config.mode === 'single') { + this.$wrapper.find('.btn-add-group').hide(); + this.$wrapper.find('.group-excludes').hide(); + this.$wrapper.find('.group-modifiers').hide(); + } + + // Add fullwidth class to parent form-group (skip for form-group layout) + var hasLayoutFormGroup = this.$wrapper.hasClass('layout-form-group'); + var $entitySelectorFormGroup = this.$wrapper.closest('.entity-selector-form-group'); + + if (!hasLayoutFormGroup && !$entitySelectorFormGroup.length) { + var $formGroup = this.$wrapper.closest('.form-group'); + $formGroup.addClass('condition-trait-fullwidth'); + $formGroup.find('.col-lg-offset-3').removeClass('col-lg-offset-3'); + } + + this.createDropdown(); + this.bindEvents(); + this.loadExistingSelections(); + this.loadSearchHistory(); + + // Initialize styled method dropdowns + this.initMethodDropdowns(); + + // Watch for dynamically added selects + this.observeNewSelects(); + + // Update counts on page load + var self = this; + setTimeout(function() { + self.updateTabBadges(); + self.updateAllConditionCounts(); + }, 100); + }, + + observeNewSelects: function() { + var self = this; + + if (typeof MutationObserver === 'undefined') { + return; + } + + var observer = new MutationObserver(function(mutations) { + mutations.forEach(function(mutation) { + if (mutation.addedNodes.length) { + $(mutation.addedNodes).find('.include-method-select, .exclude-method-select').each(function() { + self.enhanceMethodSelect($(this)); + }); + } + }); + }); + + observer.observe(this.$wrapper[0], { + childList: true, + subtree: true + }); + }, + + loadExistingSelections: function() { + // TODO: Extract full implementation from original + // Reads JSON from hidden input and populates chips + } + }; + + // Merge all mixins into the instance + // Each mixin adds its methods to window._EntitySelectorMixins + var mixins = window._EntitySelectorMixins || {}; + + // Merge utils mixin + if (mixins.utils) { + $.extend(instance, mixins.utils); + } + + // Merge events mixin + if (mixins.events) { + $.extend(instance, mixins.events); + } + + // Merge dropdown mixin + if (mixins.dropdown) { + $.extend(instance, mixins.dropdown); + } + + // Merge search mixin + if (mixins.search) { + $.extend(instance, mixins.search); + } + + // Merge filters mixin + if (mixins.filters) { + $.extend(instance, mixins.filters); + } + + // Merge chips mixin + if (mixins.chips) { + $.extend(instance, mixins.chips); + } + + // Merge groups mixin + if (mixins.groups) { + $.extend(instance, mixins.groups); + } + + // Merge methods mixin + if (mixins.methods) { + $.extend(instance, mixins.methods); + } + + // Merge preview mixin + if (mixins.preview) { + $.extend(instance, mixins.preview); + } + + // Merge tree mixin + if (mixins.tree) { + $.extend(instance, mixins.tree); + } + + // Merge validation mixin + if (mixins.validation) { + $.extend(instance, mixins.validation); + } + + return instance; + } + + // Factory object for creating and managing instances + var TargetConditions = { + instances: [], + + // Create and initialize a new instance + create: function(options) { + var instance = createTargetConditionsInstance(); + instance.init(options); + this.instances.push(instance); + return instance; + }, + + // For backwards compatibility - init creates a new instance + init: function(options) { + return this.create(options); + }, + + // Validate all instances - returns true if all valid + validateAll: function() { + var allValid = true; + for (var i = 0; i < this.instances.length; i++) { + if (!this.instances[i].validate()) { + allValid = false; + } + } + return allValid; + } + }; + + // Export to window + window.TargetConditions = TargetConditions; + + // Auto-initialize on document ready + $(document).ready(function() { + // Auto-initialize from data-config attributes on wrapper elements + $('[data-entity-selector-id]').each(function() { + var configData = $(this).data('config'); + if (configData) { + TargetConditions.create(configData); + } + }); + + // Tips box toggle handler + $(document).on('click', '.target-tips-box .tips-header', function(e) { + e.preventDefault(); + $(this).closest('.target-tips-box').toggleClass('expanded'); + }); + + // Form submission validation for required target conditions + $(document).on('submit', 'form', function(e) { + var $form = $(this); + if ($form.find('.target-conditions-trait[data-required]').length > 0) { + if (!TargetConditions.validateAll()) { + e.preventDefault(); + return false; + } + } + }); + }); + +})(jQuery); diff --git a/sources/sources/js/admin/entity-selector/_dropdown.js b/sources/sources/js/admin/entity-selector/_dropdown.js new file mode 100644 index 0000000..6895358 --- /dev/null +++ b/sources/sources/js/admin/entity-selector/_dropdown.js @@ -0,0 +1,438 @@ +/** + * Entity Selector - Dropdown Module + * Search dropdown UI creation and positioning + * @partial _dropdown.js + */ + +(function($) { + 'use strict'; + + window._EntitySelectorMixins = window._EntitySelectorMixins || {}; + + window._EntitySelectorMixins.dropdown = { + + createDropdown: function() { + this.$wrapper.find('.target-search-dropdown').remove(); + + var trans = this.config.trans || {}; + + var html = '
    '; + + // Header with results count, actions, sort controls, view mode + html += ''; // End dropdown-header + + // Filter panel + html += '
    '; + + // Quick filters row (for products) + html += '
    '; + html += ''; + html += ''; + + // Price range + html += '
    '; + html += '' + (trans.price || 'Price') + ':'; + html += ''; + html += '-'; + html += ''; + html += '
    '; + + html += ''; + html += '
    '; + + // Attribute/Feature filter toggles for products + html += ''; + html += ''; + + html += ''; + html += ''; + + // Entity-specific filters: Categories + html += ''; + + // Entity-specific filters: Manufacturers + html += ''; + + // Entity-specific filters: Suppliers + html += ''; + + // Entity-specific filters: Attributes + html += ''; + + // Entity-specific filters: Features + html += ''; + + // Entity-specific filters: CMS Pages + html += ''; + + // Entity-specific filters: CMS Categories + html += ''; + + // Entity-specific filters: Countries + html += ''; + + html += '
    '; // End filter-panel + + // Results header for list view (product columns) + html += '
    '; + html += ''; + html += '' + (trans.product || 'Product') + ''; + html += '' + (trans.price || 'Price') + ''; + html += '' + (trans.sale || 'Sale') + ''; + html += '' + (trans.stock || 'Stock') + ''; + html += '' + (trans.sold || 'Sold') + ''; + html += '
    '; + + // Results + html += ''; + + // Footer - unified load more + actions + html += ''; + + html += '
    '; + + this.$dropdown = $(html); + $('body').append(this.$dropdown); + }, + + hideDropdown: function() { + if (this.$dropdown) { + this.$dropdown.removeClass('show'); + } + this.activeGroup = null; + }, + + positionDropdown: function($input) { + if (!this.$dropdown) return; + + var $picker = $input.closest('.value-picker'); + var $searchBox = $input.closest('.entity-search-box'); + + // Get absolute positions (dropdown is appended to body) + var searchBoxOffset = $searchBox.offset(); + var searchBoxHeight = $searchBox.outerHeight(); + var pickerOffset = $picker.offset(); + var pickerWidth = $picker.outerWidth(); + + // Calculate position relative to document + var dropdownTop = searchBoxOffset.top + searchBoxHeight + 4; + var dropdownLeft = pickerOffset.left; + var dropdownWidth = Math.max(pickerWidth, 400); + + // Ensure dropdown doesn't overflow the viewport horizontally + var viewportWidth = $(window).width(); + if (dropdownLeft + dropdownWidth > viewportWidth - 10) { + dropdownWidth = viewportWidth - dropdownLeft - 10; + } + + // Ensure dropdown doesn't overflow viewport vertically + var viewportHeight = $(window).height(); + var scrollTop = $(window).scrollTop(); + var maxHeight = viewportHeight - (dropdownTop - scrollTop) - 20; + maxHeight = Math.max(maxHeight, 400); + + this.$dropdown.css({ + position: 'absolute', + top: dropdownTop, + left: dropdownLeft, + width: dropdownWidth, + maxHeight: maxHeight, + zIndex: 10000 + }); + + // Show the dropdown + this.$dropdown.addClass('show'); + } + }; + +})(jQuery); diff --git a/sources/sources/js/admin/entity-selector/_events.js b/sources/sources/js/admin/entity-selector/_events.js new file mode 100644 index 0000000..127e3d5 --- /dev/null +++ b/sources/sources/js/admin/entity-selector/_events.js @@ -0,0 +1,1934 @@ +/** + * Entity Selector - Events Module + * All event binding and handlers + * @partial _events.js + * + * Contains event handlers for: + * - Tab switching + * - Block/group collapse toggle + * - Dropdown open/close + * - Search input handling + * - Item selection/deselection + * - Group add/remove + * - Exclude row add/remove + * - Method select changes + * - Filter panel toggles + * - Keyboard shortcuts (Ctrl+A, Ctrl+D, Esc, Enter) + * - Load more pagination + * - Sort controls + * - View mode switching + * - Tree view events + * - Preview badge clicks + * - Pattern tag interactions + * - Combination picker events + * - Group modifier events + */ + +(function($) { + 'use strict'; + + window._EntitySelectorMixins = window._EntitySelectorMixins || {}; + + window._EntitySelectorMixins.events = { + + bindEvents: function() { + var self = this; + + // Tab switching + this.$wrapper.on('click', '.target-block-tab', function(e) { + e.preventDefault(); + var blockType = $(this).data('blockType'); + self.switchToBlock(blockType); + }); + + // Tab badge click for preview popover (toggle) + this.$wrapper.on('click', '.target-block-tab .tab-badge', function(e) { + e.stopPropagation(); + e.preventDefault(); + + var $tab = $(this).closest('.target-block-tab'); + var $badge = $(this); + + if ($badge.hasClass('popover-open')) { + self.hidePreviewPopover(); + } else { + self.showPreviewPopover($tab); + } + }); + + // Condition count badge click for preview popover + this.$wrapper.on('click', '.condition-match-count.clickable', function(e) { + e.stopPropagation(); + e.preventDefault(); + + var $badge = $(this); + + if ($badge.hasClass('popover-open')) { + self.hidePreviewPopover(); + } else { + self.showConditionPreviewPopover($badge); + } + }); + + // Group count badge click for preview popover + this.$wrapper.on('click', '.group-count-badge.clickable', function(e) { + e.stopPropagation(); + e.preventDefault(); + + var $badge = $(this); + + if ($badge.hasClass('popover-open')) { + self.hidePreviewPopover(); + } else { + self.showGroupPreviewPopover($badge); + } + }); + + // Total count badge click for summary popover + this.$wrapper.on('click', '.trait-total-count', function(e) { + e.stopPropagation(); + e.preventDefault(); + + var $badge = $(this); + + if ($badge.hasClass('popover-open')) { + self.hidePreviewPopover(); + } else { + self.showTotalPreviewPopover($badge); + } + }); + + // Close popover when clicking outside + $(document).on('click', function(e) { + if (!$(e.target).closest('.target-preview-popover').length && + !$(e.target).closest('.holiday-preview-popover').length && + !$(e.target).closest('.tab-badge').length && + !$(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('.toggle-count.clickable').length && + !$(e.target).closest('.trait-total-count').length && + !$(e.target).closest('.chip-preview-holidays').length) { + self.hidePreviewPopover(); + // Also close holiday popover + $('.holiday-preview-popover').remove(); + } + }); + + // Block-level collapse toggle (click on header) + this.$wrapper.on('click', '.condition-trait-header', function(e) { + if ($(e.target).closest('.target-block-tabs').length || + $(e.target).closest('.trait-header-actions').length || + $(e.target).closest('.prestashop-switch').length || + $(e.target).closest('.trait-total-count').length) { + return; + } + var $body = self.$wrapper.find('.condition-trait-body'); + $body.stop(true, true); + if ($body.is(':visible')) { + $body.slideUp(200); + self.$wrapper.addClass('collapsed'); + } else { + $body.slideDown(200); + self.$wrapper.removeClass('collapsed'); + } + }); + + // Toggle blocks content (form-content layout) + this.$wrapper.on('click', '.btn-toggle-blocks', function(e) { + e.preventDefault(); + var $blocksContent = self.$wrapper.find('.entity-selector-blocks-content'); + var $icon = $(this).find('.es-icon'); + $blocksContent.stop(true, true); + if ($blocksContent.is(':visible')) { + $blocksContent.slideUp(200); + self.$wrapper.addClass('blocks-collapsed'); + $icon.text('expand_more'); + } else { + $blocksContent.slideDown(200); + self.$wrapper.removeClass('blocks-collapsed'); + $icon.text('expand_less'); + } + }); + + // Custom block input changes — update tab badge when value changes + this.$wrapper.on('input change', '.custom-block-content input, .custom-block-content textarea, .custom-block-content select', function() { + self.updateTabBadges(); + }); + + // 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) { + return; + } + if (self.$wrapper.data('mode') === 'single') { + return; + } + var $group = $(this).closest('.selection-group'); + $group.toggleClass('collapsed'); + }); + + // Toggle all groups (single button that switches between expand/collapse) + console.log('[ES-DEBUG] Binding .btn-toggle-groups click on wrapper:', self.$wrapper.attr('id'), 'found buttons:', self.$wrapper.find('.btn-toggle-groups').length); + this.$wrapper.on('click', '.btn-toggle-groups', function(e) { + e.preventDefault(); + e.stopPropagation(); + var $btn = $(this); + var currentState = $btn.attr('data-state') || 'collapsed'; + var trans = self.config.trans || {}; + console.log('[ES-DEBUG] .btn-toggle-groups CLICKED! currentState:', currentState, 'btn parent:', $btn.parent().attr('class'), 'groups found:', self.$wrapper.find('.selection-group').length); + + if (currentState === 'collapsed') { + self.$wrapper.find('.selection-group').removeClass('collapsed'); + $btn.attr('data-state', 'expanded'); + $btn.attr('title', trans.collapse_all || 'Collapse all groups'); + $btn.find('i').text('close_fullscreen'); + console.log('[ES-DEBUG] Expanded all groups'); + } else { + self.$wrapper.find('.selection-group').addClass('collapsed'); + $btn.attr('data-state', 'collapsed'); + $btn.attr('title', trans.expand_all || 'Expand all groups'); + $btn.find('i').text('open_in_full'); + console.log('[ES-DEBUG] Collapsed all groups'); + } + }); + + // Show all toggle change (legacy checkbox) + this.$wrapper.on('change', '.trait-show-all-toggle .show-all-checkbox', function(e) { + e.stopPropagation(); + var isChecked = $(this).prop('checked'); + if (isChecked) { + self.clearAllConditions(); + } + }); + + // Target switch change (PrestaShop native switch) + this.$wrapper.on('change', '.target-switch-toggle', function(e) { + e.stopPropagation(); + var value = $(this).val(); + if (value === '1') { + self.clearAllConditions(); + self.$wrapper.find('.condition-trait-body').slideUp(200); + self.$wrapper.addClass('collapsed'); + } else { + self.$wrapper.find('.condition-trait-body').slideDown(200); + self.$wrapper.removeClass('collapsed'); + } + }); + + // Add group + this.$wrapper.on('click', '.btn-add-group', function(e) { + e.preventDefault(); + var $block = $(this).closest('.target-block'); + var blockType = $block.data('blockType'); + self.addGroup($block, blockType); + }); + + // Remove group + this.$wrapper.on('click', '.btn-remove-group', function(e) { + e.preventDefault(); + var $group = $(this).closest('.selection-group'); + var $block = $(this).closest('.target-block'); + self.removeGroup($group, $block); + }); + + // Group name input - stop propagation to prevent collapse + this.$wrapper.on('click focus', '.group-name-input', function(e) { + e.stopPropagation(); + }); + + // Group name change + this.$wrapper.on('change blur', '.group-name-input', function() { + var $input = $(this); + var $group = $input.closest('.selection-group'); + var name = $.trim($input.val()); + $group.attr('data-group-name', name); + self.serializeAllBlocks(); + }); + + // Add exceptions (first exclude row) + this.$wrapper.on('click', '.btn-add-exclude', function(e) { + e.preventDefault(); + var $group = $(this).closest('.selection-group'); + var $block = $(this).closest('.target-block'); + self.addFirstExcludeRow($group, $block); + }); + + // Add another exclude row + this.$wrapper.on('click', '.btn-add-another-exclude', function(e) { + e.preventDefault(); + var $group = $(this).closest('.selection-group'); + var $block = $(this).closest('.target-block'); + self.addExcludeRow($group, $block); + }); + + // Remove individual exclude row + this.$wrapper.on('click', '.btn-remove-exclude-row', function(e) { + e.preventDefault(); + var $excludeRow = $(this).closest('.exclude-row'); + var $group = $(this).closest('.selection-group'); + var $block = $(this).closest('.target-block'); + self.removeExcludeRow($excludeRow, $group, $block); + }); + + // Include method change + this.$wrapper.on('change', '.include-method-select', function() { + self.hideDropdown(); + + var $group = $(this).closest('.selection-group'); + var $block = $(this).closest('.target-block'); + var $row = $group.find('.group-include'); + var blockType = $block.data('blockType'); + var blockDef = self.config.blocks[blockType] || {}; + var methods = blockDef.selection_methods || {}; + + var $option = $(this).find('option:selected'); + var valueType = $option.data('valueType') || 'none'; + var searchEntity = $option.data('searchEntity') || ''; + var methodOptions = $option.data('options') || null; + + var $oldPicker = $group.find('.include-picker'); + var newPickerHtml = self.buildValuePickerHtml('include', valueType, searchEntity, methods); + $oldPicker.replaceWith(newPickerHtml); + + if (valueType === 'select' && methodOptions) { + var $newPicker = $group.find('.include-picker'); + var $select = $newPicker.find('.select-value-input'); + $select.empty(); + $.each(methodOptions, function(key, label) { + $select.append(''); + }); + } + + if (valueType === 'multi_select_tiles' && methodOptions) { + var $newPicker = $group.find('.include-picker'); + var isExclusive = $option.data('exclusive') === true; + self.populateTiles($newPicker, methodOptions, isExclusive); + } + + if (valueType === 'multi_numeric_range') { + var $newPicker = $group.find('.include-picker'); + var step = $option.data('step'); + var min = $option.data('min'); + self.applyRangeInputConstraints($newPicker, step, min); + } + + if (valueType === 'combination_attributes') { + var $newPicker = $group.find('.include-picker'); + self.loadCombinationAttributeGroups($newPicker); + } + + var selectedMethod = $(this).val(); + self.updateMethodInfoPlaceholder($group.find('.method-selector-wrapper'), selectedMethod, blockType); + + self.updateBlockStatus($block); + self.serializeAllBlocks($row); + }); + + // Exclude method change (within an exclude row) + this.$wrapper.on('change', '.exclude-method-select', function() { + self.hideDropdown(); + + var $excludeRow = $(this).closest('.exclude-row'); + var $group = $(this).closest('.selection-group'); + var $block = $(this).closest('.target-block'); + var blockType = $block.data('blockType'); + var blockDef = self.config.blocks[blockType] || {}; + var methods = blockDef.selection_methods || {}; + + var $option = $(this).find('option:selected'); + var valueType = $option.data('valueType') || 'entity_search'; + var searchEntity = $option.data('searchEntity') || blockType; + var methodOptions = $option.data('options') || null; + + var $oldPicker = $excludeRow.find('.exclude-picker'); + var newPickerHtml = self.buildValuePickerHtml('exclude', valueType, searchEntity, methods); + $oldPicker.replaceWith(newPickerHtml); + + if (valueType === 'select' && methodOptions) { + var $newPicker = $excludeRow.find('.exclude-picker'); + var $select = $newPicker.find('.select-value-input'); + $select.empty(); + $.each(methodOptions, function(key, label) { + $select.append(''); + }); + } + + if (valueType === 'multi_select_tiles' && methodOptions) { + var $newPicker = $excludeRow.find('.exclude-picker'); + var isExclusive = $option.data('exclusive') === true; + self.populateTiles($newPicker, methodOptions, isExclusive); + } + + if (valueType === 'multi_numeric_range') { + var $newPicker = $excludeRow.find('.exclude-picker'); + var step = $option.data('step'); + var min = $option.data('min'); + self.applyRangeInputConstraints($newPicker, step, min); + } + + if (valueType === 'combination_attributes') { + var $newPicker = $excludeRow.find('.exclude-picker'); + self.loadCombinationAttributeGroups($newPicker); + } + + var selectedMethod = $(this).val(); + self.updateMethodInfoPlaceholder($excludeRow.find('.exclude-header-row'), selectedMethod, blockType); + + self.serializeAllBlocks($excludeRow); + }); + + // Handle pattern input Enter key - adds pattern as tag + this.$wrapper.on('keydown', '.pattern-input', function(e) { + if (e.keyCode === 13) { + e.preventDefault(); + var $btn = $(this).closest('.draft-tag').find('.btn-add-pattern'); + $btn.click(); + } + }); + + // Handle add pattern button click (in draft tag) + this.$wrapper.on('click', '.draft-tag .btn-add-pattern', function(e) { + e.preventDefault(); + e.stopPropagation(); + var $draftTag = $(this).closest('.draft-tag'); + var $picker = $draftTag.closest('.value-picker'); + var $row = $draftTag.closest('.group-include, .exclude-row'); + var $input = $draftTag.find('.pattern-input'); + var pattern = $.trim($input.val()); + + if (pattern) { + var caseSensitive = $draftTag.attr('data-case-sensitive') === '1'; + self.addPatternTag($picker, pattern, caseSensitive); + + $input.val('').focus(); + $draftTag.find('.pattern-match-count').removeClass('count-found count-zero').hide(); + $draftTag.find('.pattern-match-count .count-value').text(''); + + self.serializeAllBlocks($row); + } + }); + + // Handle pattern input live typing - update match count in draft tag + this.$wrapper.on('input', '.pattern-input', function() { + var $input = $(this); + var $draftTag = $input.closest('.draft-tag'); + if (!$draftTag.length) return; + + var pattern = $.trim($input.val()); + + if ($input.data('countTimeout')) { + clearTimeout($input.data('countTimeout')); + } + + var $matchCount = $draftTag.find('.pattern-match-count'); + + if (!pattern) { + $matchCount.removeClass('count-found count-zero').hide(); + $matchCount.find('.count-value').text(''); + var $group = $draftTag.closest('.selection-group'); + if ($group.length) { + self.updateGroupTotalCount($group); + } + return; + } + + var timeout = setTimeout(function() { + var caseSensitive = $draftTag.attr('data-case-sensitive') === '1'; + self.updateDraftTagCount($draftTag, pattern, caseSensitive); + }, 300); + $input.data('countTimeout', timeout); + }); + + // Handle pattern tag remove + this.$wrapper.on('click', '.pattern-tag .btn-remove-pattern', function(e) { + e.preventDefault(); + e.stopPropagation(); + var $row = $(this).closest('.group-include, .exclude-row'); + $(this).closest('.pattern-tag').remove(); + self.serializeAllBlocks($row); + }); + + // Handle pattern tag case-sensitivity toggle + this.$wrapper.on('click', '.pattern-tag .btn-toggle-case', function(e) { + e.preventDefault(); + e.stopPropagation(); + var $tag = $(this).closest('.pattern-tag'); + var $btn = $(this); + var trans = self.config.trans || {}; + var isDraftTag = $tag.hasClass('draft-tag'); + + var isCaseSensitive = $tag.data('caseSensitive') === 1 || $tag.data('caseSensitive') === '1' || $tag.attr('data-case-sensitive') === '1'; + var newCaseSensitive = !isCaseSensitive; + + $tag.data('caseSensitive', newCaseSensitive ? 1 : 0); + $tag.attr('data-case-sensitive', newCaseSensitive ? '1' : '0'); + $tag.toggleClass('case-sensitive', newCaseSensitive); + + $btn.find('.case-icon').text(newCaseSensitive ? 'Aa' : 'aa'); + var caseTitle = newCaseSensitive + ? (trans.case_sensitive || 'Case sensitive - click to toggle') + : (trans.case_insensitive || 'Case insensitive - click to toggle'); + $btn.attr('title', caseTitle); + + if (isDraftTag) { + var pattern = $.trim($tag.find('.pattern-input').val()); + if (pattern) { + self.updateDraftTagCount($tag, pattern, newCaseSensitive); + } + } else { + var $row = $tag.closest('.group-include, .exclude-row'); + self.serializeAllBlocks($row); + } + }); + + // Handle pattern match count click - show preview modal + this.$wrapper.on('click', '.pattern-match-count', function(e) { + e.preventDefault(); + e.stopPropagation(); + + var $matchCount = $(this); + var count = $matchCount.data('count'); + var pattern = $matchCount.data('pattern'); + var entityType = $matchCount.data('entityType'); + var caseSensitive = $matchCount.data('caseSensitive'); + + if (!count || count <= 0 || !pattern) { + return; + } + + self.showPatternPreviewModal(pattern, entityType, caseSensitive, count); + }); + + // Handle pattern tag edit (click on tag text) + this.$wrapper.on('click', '.pattern-tag .pattern-tag-text', function(e) { + e.preventDefault(); + var $tag = $(this).closest('.pattern-tag'); + if ($tag.hasClass('editing')) return; + + var currentPattern = $tag.data('pattern'); + + var $editInput = $('').val(currentPattern); + var $saveBtn = $(''); + var $cancelBtn = $(''); + var $editActions = $('').append($saveBtn, $cancelBtn); + + $tag.addClass('editing').find('.pattern-tag-text').hide(); + $tag.find('.btn-remove-pattern').hide(); + $tag.prepend($editActions).prepend($editInput); + $editInput.focus().select(); + + $editInput.on('keydown', function(ev) { + if (ev.keyCode === 13) { + ev.preventDefault(); + $saveBtn.click(); + } else if (ev.keyCode === 27) { + ev.preventDefault(); + $cancelBtn.click(); + } + }); + }); + + // Pattern edit - Save button + this.$wrapper.on('click', '.pattern-tag .btn-pattern-save', function(e) { + e.preventDefault(); + e.stopPropagation(); + var $tag = $(this).closest('.pattern-tag'); + var $editInput = $tag.find('.pattern-tag-edit'); + var currentPattern = $tag.data('pattern'); + var newPattern = $.trim($editInput.val()); + + if (newPattern && newPattern !== currentPattern) { + $tag.data('pattern', newPattern); + $tag.find('.pattern-tag-text').text(newPattern); + } + $editInput.remove(); + $tag.find('.pattern-edit-actions').remove(); + $tag.removeClass('editing').find('.pattern-tag-text, .btn-remove-pattern').show(); + var $row = $tag.closest('.group-include, .exclude-row'); + self.serializeAllBlocks($row); + }); + + // Pattern edit - Cancel button + this.$wrapper.on('click', '.pattern-tag .btn-pattern-cancel', function(e) { + e.preventDefault(); + e.stopPropagation(); + var $tag = $(this).closest('.pattern-tag'); + $tag.find('.pattern-tag-edit').remove(); + $tag.find('.pattern-edit-actions').remove(); + $tag.removeClass('editing').find('.pattern-tag-text, .btn-remove-pattern').show(); + }); + + // Handle numeric range input changes + this.$wrapper.on('change', '.range-min-input, .range-max-input', function() { + var $row = $(this).closest('.group-include, .exclude-row'); + self.serializeAllBlocks($row); + }); + + // Handle date range input changes + this.$wrapper.on('change', '.date-from-input, .date-to-input', function() { + var $row = $(this).closest('.group-include, .exclude-row'); + self.serializeAllBlocks($row); + }); + + // Handle select value changes + this.$wrapper.on('change', '.select-value-input', function() { + var $row = $(this).closest('.group-include, .exclude-row'); + self.serializeAllBlocks($row); + }); + + // Handle multi-range add button click + this.$wrapper.on('click', '.btn-add-range', function(e) { + e.preventDefault(); + var $picker = $(this).closest('.value-picker'); + var $row = $(this).closest('.group-include, .exclude-row'); + var $container = $picker.find('.multi-range-container'); + var $chipsContainer = $container.find('.multi-range-chips'); + var $minInput = $container.find('.range-min-input'); + var $maxInput = $container.find('.range-max-input'); + + var minVal = $minInput.val().trim(); + var maxVal = $maxInput.val().trim(); + + if (minVal === '' && maxVal === '') { + return; + } + + var step = parseFloat($minInput.attr('step')) || 0.01; + var minAllowed = $minInput.attr('min'); + var hasMinConstraint = typeof minAllowed !== 'undefined' && minAllowed !== ''; + minAllowed = hasMinConstraint ? parseFloat(minAllowed) : null; + + var minNum = minVal !== '' ? parseFloat(minVal) : null; + var maxNum = maxVal !== '' ? parseFloat(maxVal) : null; + + if (hasMinConstraint) { + if (minNum !== null && minNum < minAllowed) { + self.showRangeInputError($minInput, self.config.trans.min_value_error || 'Minimum value is ' + minAllowed); + return; + } + if (maxNum !== null && maxNum < minAllowed) { + self.showRangeInputError($maxInput, self.config.trans.min_value_error || 'Minimum value is ' + minAllowed); + return; + } + } + + if (minNum !== null && maxNum !== null && minNum > maxNum) { + self.showRangeInputError($minInput, self.config.trans.min_greater_than_max || 'Min cannot be greater than max'); + return; + } + + var decimals = step < 1 ? String(step).split('.')[1].length : 0; + if (minNum !== null) { + if (step >= 1) { + minNum = Math.round(minNum); + } else { + minNum = parseFloat(minNum.toFixed(decimals)); + } + minVal = String(minNum); + } + if (maxNum !== null) { + if (step >= 1) { + maxNum = Math.round(maxNum); + } else { + maxNum = parseFloat(maxNum.toFixed(decimals)); + } + maxVal = String(maxNum); + } + + var chipText = ''; + if (minVal !== '' && maxVal !== '') { + chipText = minVal + ' - ' + maxVal; + } else if (minVal !== '') { + chipText = '≥ ' + minVal; + } else { + chipText = '≤ ' + maxVal; + } + + var $chip = $('', { + class: 'range-chip', + 'data-min': minVal, + 'data-max': maxVal + }); + $chip.append($('', { class: 'range-chip-text', text: chipText })); + $chip.append($(''; + $attrContainer.append(html); + }); + this.$dropdown.find('.filter-row-attributes').show(); + } + + // Render feature group toggle buttons + var $featContainer = this.$dropdown.find('.filter-features-container'); + $featContainer.empty(); + + if (this.filterableData.features && this.filterableData.features.length > 0) { + this.filterableData.features.forEach(function(group) { + var html = ''; + $featContainer.append(html); + }); + this.$dropdown.find('.filter-row-features').show(); + } + }, + + showFilterGroupValues: function(groupId, type) { + if (!this.filterableData) return; + + var self = this; + var groups = type === 'attribute' ? this.filterableData.attributes : this.filterableData.features; + var group = groups.find(function(g) { return g.id == groupId; }); + + if (!group) return; + + // Hide all values rows first, then show the correct one + this.$dropdown.find('.filter-row-values').hide(); + + // Target the correct values row based on type + var valuesRowClass = type === 'attribute' ? '.filter-row-attr-values' : '.filter-row-feat-values'; + var $filterRowValues = this.$dropdown.find(valuesRowClass); + var $valuesContainer = $filterRowValues.find('.filter-values-container'); + $valuesContainer.empty(); + + // Add group label + var html = '' + group.name + ':'; + + // Add chips + group.values.forEach(function(val) { + var isActive = type === 'attribute' + ? self.filters.attributes.indexOf(val.id) !== -1 + : self.filters.features.indexOf(val.id) !== -1; + var activeClass = isActive ? ' active' : ''; + var chipClass = type === 'attribute' ? 'filter-attr-chip' : 'filter-feat-chip'; + var colorStyle = val.color ? ' style="--chip-color: ' + val.color + '"' : ''; + var colorClass = val.color ? ' has-color' : ''; + + html += ''; + }); + + $valuesContainer.html(html); + + // Add close button as sibling (outside filter-values-container, inside filter-row-values) + $filterRowValues.find('.btn-close-values').remove(); + $filterRowValues.append(''); + $filterRowValues.show(); + + // Scroll into view if needed + var rowValues = $filterRowValues[0]; + if (rowValues) { + rowValues.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); + } + }, + + hideFilterGroupValues: function() { + this.$dropdown.find('.filter-row-values').hide(); + this.$dropdown.find('.filter-group-toggle').removeClass('active'); + }, + + updateFilterToggleStates: function() { + if (!this.$dropdown || !this.filterableData) return; + + var self = this; + + // Update attribute group toggles + if (this.filterableData.attributes) { + this.filterableData.attributes.forEach(function(group) { + var $toggle = self.$dropdown.find('.filter-group-toggle[data-group-id="' + group.id + '"][data-type="attribute"]'); + var hasActiveInGroup = group.values.some(function(val) { + return self.filters.attributes.indexOf(val.id) !== -1; + }); + $toggle.toggleClass('has-selection', hasActiveInGroup); + }); + } + + // Update feature group toggles + if (this.filterableData.features) { + this.filterableData.features.forEach(function(group) { + var $toggle = self.$dropdown.find('.filter-group-toggle[data-group-id="' + group.id + '"][data-type="feature"]'); + var hasActiveInGroup = group.values.some(function(val) { + return self.filters.features.indexOf(val.id) !== -1; + }); + $toggle.toggleClass('has-selection', hasActiveInGroup); + }); + } + }, + + /** + * Load zones for country filter dropdown + */ + loadZonesForCountryFilter: function() { + var self = this; + + if (this.zonesLoaded || !this.$dropdown) { + return; + } + + var $select = this.$dropdown.find('.filter-zone-select'); + if (!$select.length) { + return; + } + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'getZonesForFilter', + trait: 'EntitySelector' + }, + success: function(response) { + if (response.success && response.zones && response.zones.length > 0) { + var trans = self.config.trans || {}; + $select.empty(); + $select.append(''); + + response.zones.forEach(function(zone) { + $select.append(''); + }); + + self.zonesLoaded = true; + } + } + }); + } + }; + +})(jQuery); diff --git a/sources/sources/js/admin/entity-selector/_groups.js b/sources/sources/js/admin/entity-selector/_groups.js new file mode 100644 index 0000000..ec3f81a --- /dev/null +++ b/sources/sources/js/admin/entity-selector/_groups.js @@ -0,0 +1,1864 @@ +/** + * Entity Selector - Groups Module + * Selection group management, serialization, block/tab management + * @partial _groups.js + * + * Contains: + * - Group management: addGroup, removeGroup, clearAllConditions + * - Block/Tab: switchToBlock, updateTabBadges, updateBlockStatus + * - Serialization: serializeGroup, serializeAllBlocks, getBlockGroups + * - Counts: fetchProductCount, updateHeaderTotalCount, updateAllConditionCounts + * - Excludes: addFirstExcludeRow, addExcludeRow, removeExcludeRow + * - Validation: validate, showValidationError, clearValidationError + */ + +(function($) { + 'use strict'; + + window._EntitySelectorMixins = window._EntitySelectorMixins || {}; + + window._EntitySelectorMixins.groups = { + + addGroup: function($block, blockType) { + var $container = $block.find('.groups-container'); + var trans = this.config.trans || {}; + var blockDef = this.config.blocks[blockType] || {}; + var methods = blockDef.selection_methods || {}; + + // Remove empty state + $container.find('.groups-empty-state').remove(); + + // Get next group index + var maxIndex = -1; + $container.find('.selection-group').each(function() { + var idx = parseInt($(this).data('groupIndex'), 10); + if (idx > maxIndex) maxIndex = idx; + }); + var groupIndex = maxIndex + 1; + + // Build method options with optgroups + var methodOptions = this.buildMethodOptions(methods, false); + + // Build exclude method options (no "all") with optgroups + var excludeMethodOptions = this.buildMethodOptions(methods, true); + + var defaultGroupName = (trans.group || 'Group') + ' ' + (groupIndex + 1); + var html = '
    '; + + // Group header + html += '
    '; + html += '' + this.esIcon('expand_less') + ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += '
    '; + + // Group body (collapsible content) + html += '
    '; + + // Include section + html += '
    '; + html += '
    '; + html += '
    '; + html += ''; + html += '' + this.esIcon('visibility') + ' 0'; + html += ''; + html += '
    '; + var noItemsText = trans.no_items_selected || 'No items selected - use search below'; + html += ''; + html += '
    '; + html += '
    '; + + // Excludes section (collapsed by default) + html += '
    '; + html += ''; + html += '
    '; + + // Group-level modifiers (limit & sort) + html += '
    '; + html += ''; + html += '' + (trans.limit || 'Limit') + ''; + html += ''; + html += ''; + html += ''; + html += '' + (trans.sort || 'Sort') + ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += this.esIcon('visibility') + ' '; + html += ''; + html += '
    '; + + html += '
    '; // Close group-body + + html += '
    '; // Close selection-group + + $container.append(html); + + // Find the new group and set method to "all" by default + var $newGroup = $container.find('.selection-group[data-group-index="' + groupIndex + '"]'); + + // Enhance the method select with styled dropdown + this.enhanceMethodSelect($newGroup.find('.include-method-select')); + + $newGroup.find('.include-method-select').val('all').trigger('change'); + + this.updateBlockStatus($block); + this.serializeAllBlocks(); + }, + + removeGroup: function($group, $block) { + $group.remove(); + + var $container = $block.find('.groups-container'); + var remainingGroups = $container.find('.selection-group').length; + + if (remainingGroups === 0) { + var emptyText = this.getEmptyStateText($block); + var emptyHtml = '
    '; + emptyHtml += '' + emptyText + ''; + emptyHtml += '
    '; + $container.html(emptyHtml); + } + + this.updateBlockStatus($block); + this.serializeAllBlocks(); + + // Update tab badges and header total count + this.updateTabBadges(); + }, + + clearAllConditions: function() { + var self = this; + + // Remove all groups from all blocks + this.$wrapper.find('.target-block').each(function() { + var $block = $(this); + var $container = $block.find('.groups-container'); + + // Remove all groups + $container.find('.selection-group').remove(); + + // Show empty state + var emptyText = self.getEmptyStateText($block); + var emptyHtml = '
    '; + emptyHtml += '' + emptyText + ''; + emptyHtml += '
    '; + $container.html(emptyHtml); + + self.updateBlockStatus($block); + }); + + // Update serialized data + this.serializeAllBlocks(); + + // Update tab badges and header count + this.updateTabBadges(); + + // Also update header total count immediately (since all cleared) + this.updateHeaderTotalCount(); + }, + + switchToBlock: function(blockType) { + // Update tabs + this.$wrapper.find('.target-block-tab').removeClass('active'); + this.$wrapper.find('.target-block-tab[data-block-type="' + blockType + '"]').addClass('active'); + + // Update blocks + this.$wrapper.find('.target-block').removeClass('active').hide(); + this.$wrapper.find('.target-block[data-block-type="' + blockType + '"]').addClass('active').show(); + + // Close dropdown if open + this.hideDropdown(); + }, + + updateTabBadges: function() { + var self = this; + + // Collect all block types with data and set loading state + var blockTypesWithData = []; + this.$wrapper.find('.target-block-tab').each(function() { + var $tab = $(this); + var blockType = $tab.data('blockType'); + var $block = self.$wrapper.find('.target-block[data-block-type="' + blockType + '"]'); + var groupCount = $block.find('.selection-group').length; + + // Update or add badge + var $badge = $tab.find('.tab-badge'); + if (groupCount > 0) { + // Show loading state first + if ($badge.length) { + $badge.addClass('loading').html(self.esIcon('progress_activity', 'es-spin')); + } else { + $tab.append('' + self.esIcon('progress_activity', 'es-spin') + ''); + } + $tab.addClass('has-data'); + blockTypesWithData.push(blockType); + } else if ($block.hasClass('custom-block')) { + // Custom blocks: check if any input/textarea/select has a non-empty value + var hasCustomValue = false; + $block.find('.custom-block-content').find('input, textarea, select').each(function() { + if ($(this).val() && $(this).val().trim() !== '') { + hasCustomValue = true; + return false; + } + }); + if (hasCustomValue) { + if ($badge.length) { + $badge.removeClass('loading').html(self.esIcon('check')); + } else { + $tab.append('' + self.esIcon('check') + ''); + } + $tab.addClass('has-data'); + } else { + $badge.remove(); + $tab.removeClass('has-data'); + } + } else { + $badge.remove(); + $tab.removeClass('has-data'); + } + }); + + // Update target switch state based on whether any data exists + this.updateTargetSwitchState(); + + // Fetch all counts in a single bulk request + if (blockTypesWithData.length > 0) { + this.fetchAllCounts(blockTypesWithData); + } + }, + + updateTargetSwitchState: function() { + var $switch = this.$wrapper.find('.prestashop-switch'); + if (!$switch.length) { + return; + } + + // Check if any block has data + var hasData = false; + this.$wrapper.find('.target-block').each(function() { + if ($(this).find('.selection-group').length > 0) { + hasData = true; + return false; // break + } + }); + + // Update switch: value="1" is "Everyone/All/None", value="0" is "Specific/Selected" + if (hasData) { + $switch.find('input[value="0"]').prop('checked', true); + } else { + $switch.find('input[value="1"]').prop('checked', true); + } + }, + + /** + * Fetch counts for all block types in a single bulk AJAX request + * @param {Array} blockTypes - Array of block type strings to fetch counts for + */ + fetchAllCounts: function(blockTypes) { + var self = this; + + // Read saved data from hidden input + var $hiddenInput = this.$wrapper.find('input[name="' + this.config.name + '"]'); + var savedData = {}; + try { + savedData = JSON.parse($hiddenInput.val() || '{}'); + } catch (e) { + savedData = {}; + } + + // Build conditions object for all requested block types + var conditions = {}; + blockTypes.forEach(function(blockType) { + var groups = (savedData[blockType] && savedData[blockType].groups) ? savedData[blockType].groups : []; + if (groups.length > 0) { + conditions[blockType] = { groups: groups }; + } + }); + + // If no valid conditions, remove loading spinners + if (Object.keys(conditions).length === 0) { + blockTypes.forEach(function(blockType) { + var $tab = self.$wrapper.find('.target-block-tab[data-block-type="' + blockType + '"]'); + $tab.find('.tab-badge').remove(); + $tab.removeClass('has-data'); + }); + return; + } + + // Single bulk AJAX request for all counts + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'previewEntitySelectorBulk', + trait: 'EntitySelector', + conditions: JSON.stringify(conditions) + }, + success: function(response) { + if (response.success && response.counts) { + // Update each tab with its count + Object.keys(response.counts).forEach(function(blockType) { + var count = response.counts[blockType]; + var $tab = self.$wrapper.find('.target-block-tab[data-block-type="' + blockType + '"]'); + var $badge = $tab.find('.tab-badge'); + + if ($badge.length) { + $badge.removeClass('loading').html(self.esIcon('visibility') + ' ' + count); + // Store preview data for later popover use + $tab.data('previewData', { count: count, success: true }); + } + }); + + // Handle any block types not in response (set count to 0 or remove badge) + blockTypes.forEach(function(blockType) { + if (!(blockType in response.counts)) { + var $tab = self.$wrapper.find('.target-block-tab[data-block-type="' + blockType + '"]'); + $tab.find('.tab-badge').remove(); + $tab.removeClass('has-data'); + } + }); + + self.updateHeaderTotalCount(); + } else { + console.error('[EntitySelector] Bulk preview failed:', response.error || 'Unknown error'); + // Remove loading spinners on error + blockTypes.forEach(function(blockType) { + var $tab = self.$wrapper.find('.target-block-tab[data-block-type="' + blockType + '"]'); + $tab.find('.tab-badge').remove(); + }); + } + }, + error: function(xhr, status, error) { + console.error('[EntitySelector] Bulk AJAX error:', status, error); + // Remove loading spinners on error + blockTypes.forEach(function(blockType) { + var $tab = self.$wrapper.find('.target-block-tab[data-block-type="' + blockType + '"]'); + $tab.find('.tab-badge').remove(); + }); + } + }); + }, + + /** + * Fetch count for a single block type (legacy, used for single updates) + */ + fetchProductCount: function(blockType, $tab) { + var self = this; + var data = {}; + + // Read from hidden input (contains full saved data or freshly serialized data) + var $hiddenInput = this.$wrapper.find('input[name="' + this.config.name + '"]'); + var savedData = {}; + try { + savedData = JSON.parse($hiddenInput.val() || '{}'); + } catch (e) { + savedData = {}; + } + + // Get groups for the requested block type + var groups = (savedData[blockType] && savedData[blockType].groups) ? savedData[blockType].groups : []; + + if (groups.length === 0) { + $tab.find('.tab-badge').remove(); + $tab.removeClass('has-data'); + $tab.removeData('previewData'); + return; + } + + // Show loading state + var $badge = $tab.find('.tab-badge'); + if (!$badge.length) { + $badge = $('' + this.esIcon('progress_activity', 'es-spin') + ''); + $tab.append($badge); + } else { + $badge.addClass('loading').html(this.esIcon('progress_activity', 'es-spin')); + } + $tab.addClass('has-data'); + + data[blockType] = { groups: groups }; + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'previewEntitySelector', + trait: 'EntitySelector', + conditions: JSON.stringify(data), + block_type: blockType, + limit: 10 + }, + success: function(response) { + if (response.success) { + var $badge = $tab.find('.tab-badge'); + $badge.removeClass('loading').html(self.esIcon('visibility') + ' ' + response.count); + + // Store preview data for popover + $tab.data('previewData', response); + + // Update header total count + self.updateHeaderTotalCount(); + } else { + console.error('[EntitySelector] Preview failed for', blockType, ':', response.error || 'Unknown error'); + $tab.find('.tab-badge').remove(); + } + }, + error: function(xhr, status, error) { + console.error('[EntitySelector] AJAX error for', blockType, ':', status, error); + $tab.find('.tab-badge').remove(); + self.updateHeaderTotalCount(); + } + }); + }, + + updateHeaderTotalCount: function() { + var self = this; + var total = 0; + + // Sum up all tab badge counts + this.$wrapper.find('.target-block-tab .tab-badge').each(function() { + var $badge = $(this); + if (!$badge.hasClass('loading')) { + var count = parseInt($badge.text(), 10); + if (!isNaN(count)) { + total += count; + } + } + }); + + var $totalBadge = this.$wrapper.find('.trait-total-count'); + if (total > 0) { + $totalBadge.find('.count-value').text(total); + $totalBadge.show(); + } else { + $totalBadge.hide(); + } + + // Update show-all toggle state + this.updateShowAllToggle(); + }, + + updateShowAllToggle: function() { + var $toggle = this.$wrapper.find('.trait-show-all-toggle'); + if (!$toggle.length) return; + + var $checkbox = $toggle.find('.show-all-checkbox'); + var hasData = this.$wrapper.find('.target-block-tab.has-data').length > 0; + + // If there's data, uncheck (not showing to all), otherwise check + $checkbox.prop('checked', !hasData); + }, + + updateBlockStatus: function($block) { + var $status = $block.find('.block-status'); + var blockType = $block.data('blockType'); + var blockDef = this.config.blocks[blockType] || {}; + var trans = this.config.trans || {}; + + var groups = this.getBlockGroups($block); + + if (groups.length === 0) { + var emptyMeansAll = this.config.emptyMeansAll !== false; + if (emptyMeansAll) { + $status.text((trans.all || 'All') + ' ' + (blockDef.entity_label_plural || 'items')); + } else { + $status.text(trans.nothing_selected || 'Nothing selected'); + } + } else { + $status.text(groups.length + ' ' + (groups.length === 1 ? (trans.group || 'group') : (trans.groups || 'groups'))); + } + }, + + getEmptyStateText: function($block) { + var blockType = $block.data('blockType'); + var blockMode = $block.data('mode') || 'multi'; + var blockDef = this.config.blocks[blockType] || {}; + var trans = this.config.trans || {}; + var emptyMeansAll = this.config.emptyMeansAll !== false; + + if (blockMode === 'single') { + return trans.no_item_selected || 'No item selected'; + } + + if (emptyMeansAll) { + return (trans.all || 'All') + ' ' + (blockDef.entity_label_plural || 'items') + ' ' + (trans.included || 'included'); + } + + return trans.nothing_selected || 'Nothing selected'; + }, + + serializeGroup: function($group, blockType) { + var self = this; + + // Include + var includeMethod = $group.find('.include-method-select').val() || 'all'; + var $includePicker = $group.find('.include-picker'); + var includeValues = this.getPickerValues($includePicker); + + // Excludes (multiple rows) + var excludes = []; + var $excludesSection = $group.find('.group-excludes.has-excludes'); + if ($excludesSection.length) { + $group.find('.exclude-row').each(function() { + var $row = $(this); + var excludeMethod = $row.find('.exclude-method-select').val() || null; + var $excludePicker = $row.find('.exclude-picker'); + var excludeValues = self.getPickerValues($excludePicker); + + if (excludeMethod && excludeValues && (Array.isArray(excludeValues) ? excludeValues.length > 0 : true)) { + excludes.push({ + method: excludeMethod, + values: excludeValues + }); + } + }); + } + + var groupData = { + include: { + method: includeMethod, + values: includeValues + } + }; + + if (excludes.length > 0) { + groupData.excludes = excludes; + } + + // Add modifiers if present + var modifiers = this.getGroupModifiers($group); + if (modifiers.limit || modifiers.sort_by) { + groupData.modifiers = modifiers; + } + + return groupData; + }, + + serializeAllBlocks: function($changedRow) { + var self = this; + var data = {}; + + console.log('[EntitySelector] serializeAllBlocks called'); + + this.$wrapper.find('.target-block').each(function() { + var $block = $(this); + var blockType = $block.data('blockType'); + var groups = self.getBlockGroups($block); + + console.log('[EntitySelector] Block:', blockType, 'Groups:', groups.length); + + // Groups now contain their own modifiers, no block-level modifiers + if (groups.length > 0) { + data[blockType] = { groups: groups }; + } + + self.updateBlockStatus($block); + }); + + // Update hidden input first + var $input = this.$wrapper.find('input[name="' + this.config.name + '"]'); + var jsonData = JSON.stringify(data); + + console.log('[EntitySelector] Hidden input name:', this.config.name); + console.log('[EntitySelector] Hidden input found:', $input.length); + console.log('[EntitySelector] Serialized data:', jsonData.substring(0, 500)); + + $input.val(jsonData); + + // Then update tab badges (reads from hidden input) + this.updateTabBadges(); + + // Debounced update of condition count - only for changed row if specified + if (this.countUpdateTimeout) { + clearTimeout(this.countUpdateTimeout); + } + this.countUpdateTimeout = setTimeout(function() { + if ($changedRow && $changedRow.length) { + // Update the specific row that changed + self.updateConditionCount($changedRow); + // Also update the group total count (include - excludes) + var $group = $changedRow.closest('.selection-group'); + if ($group.length) { + self.updateGroupTotalCount($group); + } + } else { + // Fallback: update all counts (initial load, structure changes) + self.updateAllConditionCounts(); + } + }, 500); + }, + + getBlockGroups: function($block) { + var self = this; + var groups = []; + + $block.find('.selection-group').each(function() { + var $group = $(this); + + // Include + var includeMethod = $group.find('.include-method-select').val() || 'all'; + var $includePicker = $group.find('.include-picker'); + var includeValues = self.getPickerValues($includePicker); + + // Skip groups with invalid include conditions (e.g., "specific products" with none selected) + if (!self.isConditionValid(includeMethod, includeValues, $includePicker)) { + return true; // continue to next group + } + + // Excludes (multiple rows) - only include valid ones + var excludes = []; + var $excludesSection = $group.find('.group-excludes.has-excludes'); + if ($excludesSection.length) { + $group.find('.exclude-row').each(function() { + var $row = $(this); + var excludeMethod = $row.find('.exclude-method-select').val() || null; + var $excludePicker = $row.find('.exclude-picker'); + var excludeValues = self.getPickerValues($excludePicker); + + // Only include valid exclude conditions + if (excludeMethod && self.isConditionValid(excludeMethod, excludeValues, $excludePicker)) { + excludes.push({ + method: excludeMethod, + values: excludeValues + }); + } + }); + } + + var groupData = { + include: { + method: includeMethod, + values: includeValues + } + }; + + // Group name (optional, for organizational purposes) + var groupName = $.trim($group.attr('data-group-name') || ''); + if (groupName) { + groupData.name = groupName; + } + + if (excludes.length > 0) { + groupData.excludes = excludes; + } + + // Group-level modifiers + var modifiers = self.getGroupModifiers($group); + if (modifiers.limit || modifiers.sort_by) { + groupData.modifiers = modifiers; + } + + groups.push(groupData); + }); + + return groups; + }, + + getGroupModifiers: function($group) { + var limit = $group.find('.group-modifier-limit').val(); + var sortBy = $group.find('.group-modifier-sort').val() || 'sales'; + var $sortDirBtn = $group.find('.group-modifiers .btn-sort-dir'); + var sortDir = $sortDirBtn.data('dir') || 'DESC'; + + return { + limit: limit ? parseInt(limit, 10) : null, + sort_by: sortBy || null, + sort_dir: sortDir || 'DESC' + }; + }, + + getPickerValues: function($picker) { + var valueType = $picker.attr('data-value-type') || 'entity_search'; + var values = []; + + switch (valueType) { + case 'entity_search': + $picker.find('.entity-chip').each(function() { + var id = $(this).data('id'); + values.push(isNaN(id) ? id : Number(id)); + }); + break; + + case 'pattern': + values = this.getPatternTags($picker); + // Also include draft pattern if it has content (not yet added as tag) + var $draftInput = $picker.find('.draft-tag .pattern-input'); + var draftPattern = $.trim($draftInput.val()); + if (draftPattern) { + var draftCaseSensitive = $draftInput.closest('.draft-tag').attr('data-case-sensitive') === '1'; + values.push({ + pattern: draftPattern, + caseSensitive: draftCaseSensitive + }); + } + break; + + case 'numeric_range': + var min = $picker.find('.range-min-input').val(); + var max = $picker.find('.range-max-input').val(); + if (min !== '' || max !== '') { + values = { + min: min !== '' ? parseFloat(min) : null, + max: max !== '' ? parseFloat(max) : null + }; + } + break; + + case 'date_range': + var from = $picker.find('.date-from-input').val(); + var to = $picker.find('.date-to-input').val(); + if (from || to) { + values = { + from: from || null, + to: to || null + }; + } + break; + + case 'select': + var selectVal = $picker.find('.select-value-input').val(); + if (selectVal) { + values = [selectVal]; + } + break; + + case 'boolean': + values = [true]; + break; + + case 'multi_numeric_range': + var ranges = []; + $picker.find('.range-chip').each(function() { + var $chip = $(this); + var minVal = $chip.data('min'); + var maxVal = $chip.data('max'); + ranges.push({ + min: minVal !== '' && minVal !== undefined ? parseFloat(minVal) : null, + max: maxVal !== '' && maxVal !== undefined ? parseFloat(maxVal) : null + }); + }); + if (ranges.length > 0) { + values = ranges; + } + break; + + case 'multi_select_tiles': + $picker.find('.tile-option.selected').each(function() { + values.push($(this).data('value')); + }); + break; + + case 'combination_attributes': + // Returns object: { mode: 'products'|'combinations', attributes: { groupId: [valueId1, valueId2], ... } } + var combAttrs = {}; + $picker.find('.comb-attr-value.selected').each(function() { + var groupId = $(this).data('groupId').toString(); + var valueId = $(this).data('valueId'); + if (!combAttrs[groupId]) { + combAttrs[groupId] = []; + } + combAttrs[groupId].push(valueId); + }); + if (Object.keys(combAttrs).length > 0) { + // Get mode: from radio if toggle exists, otherwise from config + var $combPicker = $picker.find('.combination-attributes-picker'); + var configMode = $combPicker.data('combinationMode') || this.config.combinationMode || 'products'; + var combMode; + if (configMode === 'toggle') { + combMode = $picker.find('.comb-mode-radio:checked').val() || 'products'; + } else { + combMode = configMode; + } + values = { + mode: combMode, + attributes: combAttrs + }; + } + break; + } + + return values; + }, + + isConditionValid: function(method, values, $picker) { + // 'all' method never needs values + if (method === 'all') { + return true; + } + + // Boolean methods are always valid (the value is implicit true) + var valueType = $picker.attr('data-value-type') || 'entity_search'; + if (valueType === 'boolean') { + return true; + } + + // For other methods, check if values are meaningful + if (Array.isArray(values)) { + return values.length > 0; + } + + // For object values (ranges, combination_attributes), check if meaningful + if (typeof values === 'object' && values !== null) { + // Special handling for combination_attributes: { mode, attributes } + if (valueType === 'combination_attributes' && values.attributes !== undefined) { + return Object.keys(values.attributes).length > 0; + } + // For ranges and other objects, check if at least one bound is set + return Object.keys(values).some(function(key) { + return values[key] !== null && values[key] !== ''; + }); + } + + return false; + }, + + /** + * Update all condition counts using a single bulk AJAX request + */ + updateAllConditionCounts: function() { + var self = this; + var conditions = {}; + var conditionElements = {}; + var conditionIndex = 0; + + // Collect all conditions from all active groups + this.$wrapper.find('.target-block.active .selection-group').each(function() { + var $group = $(this); + var $block = $group.closest('.target-block'); + var blockType = $block.data('blockType') || 'products'; + + // Process include row + var $include = $group.find('.group-include'); + if ($include.length) { + var includeData = self.getConditionData($include, blockType); + if (includeData) { + var id = 'c' + conditionIndex++; + conditions[id] = includeData.condition; + conditionElements[id] = includeData.$countEl; + } + } + + // Process exclude rows + $group.find('.exclude-row').each(function() { + var excludeData = self.getConditionData($(this), blockType); + if (excludeData) { + var id = 'c' + conditionIndex++; + conditions[id] = excludeData.condition; + conditionElements[id] = excludeData.$countEl; + } + }); + }); + + // If no conditions, nothing to do + if (Object.keys(conditions).length === 0) { + return; + } + + // Make single bulk AJAX request + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'countConditionMatchesBulk', + trait: 'EntitySelector', + conditions: JSON.stringify(conditions) + }, + success: function(response) { + if (response && response.success && response.counts) { + // Update each count element with its result + Object.keys(response.counts).forEach(function(id) { + var count = response.counts[id] || 0; + var $countEl = conditionElements[id]; + if ($countEl && $countEl.length) { + $countEl.removeClass('no-matches clickable'); + if (count === 0) { + $countEl.find('.preview-count').text(count); + $countEl.addClass('no-matches').show(); + } else { + $countEl.find('.preview-count').text(count); + $countEl.addClass('clickable').show(); + } + } + }); + } + // Note: Group totals are updated on-demand when user interacts, not on initial load + }, + error: function() { + // Hide all count elements on error + Object.keys(conditionElements).forEach(function(id) { + var $countEl = conditionElements[id]; + if ($countEl && $countEl.length) { + $countEl.hide().removeClass('clickable'); + } + }); + } + }); + }, + + /** + * Extract condition data from a row for bulk counting + */ + getConditionData: function($row, blockType) { + console.log('[getConditionData] Called with blockType:', blockType); + var $countEl = $row.find('.method-selector-wrapper > .condition-match-count, > .exclude-header-row .condition-match-count').first(); + console.log('[getConditionData] $countEl found:', $countEl.length); + if (!$countEl.length) return null; + + var isExclude = $row.hasClass('exclude-row'); + var $methodSelect = isExclude + ? $row.find('.exclude-method-select') + : $row.find('.include-method-select'); + + var method = $methodSelect.val(); + console.log('[getConditionData] method:', method); + if (!method) { + $countEl.hide(); + return null; + } + + var $picker = isExclude + ? $row.find('.exclude-picker') + : $row.find('.include-picker'); + console.log('[getConditionData] $picker found:', $picker.length, 'data-value-type attr:', $picker.attr('data-value-type')); + + var valueType = $picker.data('valueType') || $picker.attr('data-value-type') || 'none'; + console.log('[getConditionData] valueType:', valueType); + + // Special case: "All countries" method - needs separate handling for holidays + if (valueType === 'none' && blockType === 'countries' && method === 'all') { + console.log('[getConditionData] All countries detected - triggering updateConditionCount'); + // Trigger separate update for this special case (uses nested AJAX) + var self = this; + setTimeout(function() { + self.updateConditionCount($row, blockType); + }, 0); + return null; // Skip bulk processing, handled separately + } + + // Special case: Specific countries with entity_search - needs holiday counting, not entity counting + var searchEntity = $picker.attr('data-search-entity') || ''; + if (blockType === 'countries' && valueType === 'entity_search' && searchEntity === 'countries') { + console.log('[getConditionData] Specific countries detected - triggering updateConditionCount for holiday counting'); + var self = this; + setTimeout(function() { + self.updateConditionCount($row, blockType); + }, 0); + return null; // Skip bulk processing, handled separately + } + + // Hide badge for other "all" type methods (valueType === 'none') since they don't filter + if (valueType === 'none') { + $countEl.hide(); + return null; + } + + var values = this.getPickerValues($picker, valueType); + + // Don't count if no values (except for boolean methods) + var hasNoValues = !values || + (Array.isArray(values) && values.length === 0) || + (typeof values === 'object' && !Array.isArray(values) && ( + (valueType === 'combination_attributes' && values.attributes !== undefined && Object.keys(values.attributes).length === 0) || + (valueType !== 'combination_attributes' && Object.keys(values).length === 0) + )); + if (valueType !== 'boolean' && hasNoValues) { + $countEl.hide(); + return null; + } + + // Show loading spinner + $countEl.find('.preview-count').html(this.esIcon('progress_activity', 'es-spin')); + $countEl.removeClass('clickable no-matches').show(); + + // Store condition data on badge for popover + $countEl.data('conditionData', { + method: method, + values: values, + blockType: blockType, + isExclude: isExclude + }); + + return { + condition: { + method: method, + values: values, + block_type: blockType + }, + $countEl: $countEl + }; + }, + + updateGroupCounts: function($group) { + var self = this; + var $block = $group.closest('.target-block'); + var blockType = $block.data('blockType') || 'products'; + + // Update include count + var $include = $group.find('.group-include'); + if ($include.length) { + this.updateConditionCount($include, blockType); + } + + // Update each exclude row count + $group.find('.exclude-row').each(function() { + self.updateConditionCount($(this), blockType); + }); + + // Update group total count (include - excludes) + this.updateGroupTotalCount($group); + }, + + /** + * Update a single condition count (used for individual updates after user changes) + */ + updateConditionCount: function($row, blockType) { + var self = this; + + var $countEl = $row.find('.method-selector-wrapper > .condition-match-count, > .exclude-header-row .condition-match-count').first(); + if (!$countEl.length) { + console.log('[updateConditionCount] No $countEl found'); + return; + } + + var isExclude = $row.hasClass('exclude-row'); + var $methodSelect = isExclude + ? $row.find('.exclude-method-select') + : $row.find('.include-method-select'); + + var method = $methodSelect.val(); + console.log('[updateConditionCount] method:', method, 'isExclude:', isExclude); + if (!method) { + console.log('[updateConditionCount] No method, hiding badge'); + $countEl.hide(); + return; + } + + var $picker = isExclude + ? $row.find('.exclude-picker') + : $row.find('.include-picker'); + + var valueType = $picker.data('valueType') || 'none'; + var searchEntity = $picker.attr('data-search-entity') || ''; + + // Get the block type to check if this is a countries block + if (!blockType) { + var $block = $row.closest('.target-block'); + blockType = $block.data('blockType') || 'products'; + } + + console.log('[updateConditionCount] valueType:', valueType, 'searchEntity:', searchEntity, 'blockType:', blockType, 'method:', method); + + // Special case: "All countries" method - fetch holidays for all countries + if (valueType === 'none' && blockType === 'countries' && method === 'all') { + console.log('[updateConditionCount] All countries method - fetching all country holidays'); + $countEl.find('.preview-count').html(this.esIcon('progress_activity', 'es-spin')); + $countEl.removeClass('clickable no-matches country-holidays').show(); + + // First fetch all active country IDs, then get holidays + $.ajax({ + url: self.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'searchTargetEntities', + trait: 'EntitySelector', + entity_type: 'countries', + query: '', + limit: 500 + }, + success: function(response) { + var items = response.results || response.items || []; + if (response && response.success && items.length > 0) { + var allCountryIds = items.map(function(item) { return item.id; }); + console.log('[updateConditionCount] Found', allCountryIds.length, 'countries, fetching holidays'); + + // Store condition data for click handler + $countEl.data('conditionData', { + method: method, + values: allCountryIds, + blockType: blockType, + isExclude: isExclude, + isCountryHolidays: true, + countryIds: allCountryIds, + isAllCountries: true + }); + + // Now fetch holiday count + $.ajax({ + url: self.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'getHolidaysForCountries', + trait: 'EntitySelector', + country_ids: allCountryIds.join(','), + count_only: 1 + }, + success: function(holidayResponse) { + console.log('[updateConditionCount] All countries holiday response:', holidayResponse); + if (holidayResponse && holidayResponse.success) { + var count = holidayResponse.total_count || 0; + $countEl.removeClass('no-matches clickable'); + $countEl.addClass('country-holidays'); + if (count === 0) { + $countEl.find('.preview-count').text(count); + $countEl.addClass('no-matches').show(); + } else { + $countEl.find('.preview-count').text(count); + $countEl.addClass('clickable').show(); + } + $countEl.data('countriesInfo', holidayResponse.countries || []); + } else { + $countEl.hide().removeClass('clickable'); + } + }, + error: function() { + $countEl.hide().removeClass('clickable'); + } + }); + } else { + $countEl.hide().removeClass('clickable'); + } + }, + error: function() { + $countEl.hide().removeClass('clickable'); + } + }); + return; + } + + // Hide badge for other "all" type methods (valueType === 'none') since they don't filter + if (valueType === 'none') { + console.log('[updateConditionCount] valueType is none, hiding badge'); + $countEl.hide(); + return; + } + + var values = this.getPickerValues($picker, valueType); + + var hasNoValues = !values || + (Array.isArray(values) && values.length === 0) || + (typeof values === 'object' && !Array.isArray(values) && ( + (valueType === 'combination_attributes' && values.attributes !== undefined && Object.keys(values.attributes).length === 0) || + (valueType !== 'combination_attributes' && Object.keys(values).length === 0) + )); + if (valueType !== 'boolean' && hasNoValues) { + $countEl.hide(); + return; + } + + if (!blockType) { + var $block = $row.closest('.target-block'); + blockType = $block.data('blockType') || 'products'; + } + + // Check if this is a country selection - show holiday count instead + var isCountrySelection = (searchEntity === 'countries' && valueType === 'entity_search'); + console.log('[updateConditionCount] isCountrySelection:', isCountrySelection, 'values:', values); + + $countEl.find('.preview-count').html(this.esIcon('progress_activity', 'es-spin')); + $countEl.removeClass('clickable no-matches country-holidays').show(); + + // For countries, fetch holiday count + if (isCountrySelection && Array.isArray(values) && values.length > 0) { + console.log('[updateConditionCount] Fetching holiday count for countries:', values); + $countEl.data('conditionData', { + method: method, + values: values, + blockType: blockType, + isExclude: isExclude, + isCountryHolidays: true, + countryIds: values + }); + + $.ajax({ + url: self.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'getHolidaysForCountries', + trait: 'EntitySelector', + country_ids: values.join(','), + count_only: 1 + }, + success: function(response) { + console.log('[updateConditionCount] Holiday response:', response); + if (response && response.success) { + var count = response.total_count || 0; + console.log('[updateConditionCount] Holiday count:', count); + $countEl.removeClass('no-matches clickable'); + $countEl.addClass('country-holidays'); + if (count === 0) { + $countEl.find('.preview-count').text(count); + $countEl.addClass('no-matches').show(); + } else { + $countEl.find('.preview-count').text(count); + $countEl.addClass('clickable').show(); + } + // Store countries info for popover + $countEl.data('countriesInfo', response.countries || []); + } else { + console.log('[updateConditionCount] Holiday response failed:', response); + $countEl.hide().removeClass('clickable'); + } + }, + error: function() { + $countEl.hide().removeClass('clickable'); + } + }); + return; + } + + // Default: count entities + $countEl.data('conditionData', { + method: method, + values: values, + blockType: blockType, + isExclude: isExclude + }); + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'countConditionMatches', + trait: 'EntitySelector', + method: method, + values: JSON.stringify(values), + block_type: blockType + }, + success: function(response) { + if (response && response.success) { + var count = response.count || 0; + $countEl.removeClass('no-matches clickable'); + if (count === 0) { + $countEl.find('.preview-count').text(count); + $countEl.addClass('no-matches').show(); + } else { + $countEl.find('.preview-count').text(count); + $countEl.addClass('clickable').show(); + } + } else { + $countEl.hide().removeClass('clickable'); + } + }, + error: function() { + $countEl.hide().removeClass('clickable'); + } + }); + }, + + updateGroupTotalCount: function($group) { + var self = this; + var $block = $group.closest('.target-block'); + var blockType = $block.data('blockType') || 'products'; + var $badge = $group.find('.group-header .group-count-badge'); + var $limitInput = $group.find('.group-modifier-limit'); + + // Build group data for AJAX + var groupData = this.serializeGroup($group, blockType); + + // Check if include has valid data + if (!groupData.include || !groupData.include.method) { + $badge.hide(); + $limitInput.attr('placeholder', '–'); + return; + } + + // Show loading + $badge.html(this.esIcon('progress_activity', 'es-spin')).show(); + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'countGroupItems', + trait: 'EntitySelector', + group_data: JSON.stringify(groupData), + block_type: blockType + }, + success: function(response) { + if (response && response.success) { + var finalCount = response.final_count || 0; + var excludeCount = response.exclude_count || 0; + + // Update badge with eye icon and count + var badgeHtml = self.esIcon('visibility') + ' ' + finalCount; + if (excludeCount > 0) { + badgeHtml += ' (-' + excludeCount + ')'; + } + $badge.html(badgeHtml); + $badge.addClass('clickable').show(); + + // Store group data on badge for preview popover + $badge.data('groupData', groupData); + $badge.data('blockType', blockType); + $badge.data('finalCount', finalCount); + + // Update limit placeholder with the count + $limitInput.attr('placeholder', finalCount); + + // Also update the group-preview-badge count (apply limit if set) + var $previewBadge = $group.find('.group-preview-badge .preview-count'); + if ($previewBadge.length) { + var limit = parseInt($limitInput.val(), 10); + var displayCount = (limit > 0 && limit < finalCount) ? limit : finalCount; + $previewBadge.text(displayCount); + } + } else { + $badge.hide().removeClass('clickable'); + $limitInput.attr('placeholder', '–'); + } + }, + error: function() { + $badge.hide(); + $limitInput.attr('placeholder', '–'); + } + }); + }, + + // Exclude row management + addFirstExcludeRow: function($group, $block) { + var $excludesDiv = $group.find('.group-excludes'); + var trans = this.config.trans || {}; + + // Build the full excludes structure with first row + var html = '
    '; + html += '' + this.esIcon('block') + ' ' + (trans.except || 'EXCEPT') + ''; + html += '
    '; + + html += '
    '; + html += this.buildExcludeRowHtml($block, 0); + html += '
    '; + + html += ''; + + $excludesDiv.addClass('has-excludes').html(html); + + // Enhance the first exclude method select with styled dropdown + var $firstRow = $excludesDiv.find('.exclude-row[data-exclude-index="0"]'); + var $firstSelect = $firstRow.find('.exclude-method-select'); + this.enhanceMethodSelect($firstSelect); + + // Update method info placeholder for initial selection + var blockType = $block.data('blockType'); + var initialMethod = $firstSelect.val(); + this.updateMethodInfoPlaceholder($firstRow.find('.method-selector-wrapper'), initialMethod, blockType); + + this.updateMethodSelectorLock($group, true); + this.serializeAllBlocks(); + }, + + addExcludeRow: function($group, $block) { + var $container = $group.find('.exclude-rows-container'); + + // Get next exclude index + var maxIndex = -1; + $container.find('.exclude-row').each(function() { + var idx = parseInt($(this).data('excludeIndex'), 10); + if (idx > maxIndex) maxIndex = idx; + }); + var excludeIndex = maxIndex + 1; + + var html = this.buildExcludeRowHtml($block, excludeIndex); + $container.append(html); + + // Enhance the exclude method select with styled dropdown + var $newRow = $container.find('.exclude-row[data-exclude-index="' + excludeIndex + '"]'); + var $newSelect = $newRow.find('.exclude-method-select'); + this.enhanceMethodSelect($newSelect); + + // Update method info placeholder for initial selection + var blockType = $block.data('blockType'); + var initialMethod = $newSelect.val(); + this.updateMethodInfoPlaceholder($newRow.find('.method-selector-wrapper'), initialMethod, blockType); + + this.serializeAllBlocks(); + }, + + buildExcludeRowHtml: function($block, excludeIndex) { + var blockType = $block.data('blockType'); + var blockDef = this.config.blocks[blockType] || {}; + var methods = blockDef.selection_methods || {}; + var trans = this.config.trans || {}; + + // Build exclude method options with optgroups (no "all") + var excludeMethodOptions = this.buildMethodOptions(methods, true); + + // Find first non-all method for default search entity + var firstSearchEntity = blockType; + var firstValueType = 'entity_search'; + $.each(methods, function(methodKey, methodDef) { + if (methodKey === 'all') return true; + firstSearchEntity = methodDef.search_entity || blockType; + firstValueType = methodDef.value_type || 'entity_search'; + return false; // break + }); + + var html = '
    '; + + // Header row with method select wrapped in method-selector-wrapper (same as include) + html += '
    '; + html += '
    '; + html += ''; + html += '' + this.esIcon('visibility') + ' 0'; + html += ''; + html += '
    '; + html += ''; + html += '
    '; + + // Value picker based on first method's value type + html += this.buildValuePickerHtml('exclude', firstValueType, firstSearchEntity, methods); + + html += '
    '; + + return html; + }, + + removeExcludeRow: function($excludeRow, $group, $block) { + var $container = $group.find('.exclude-rows-container'); + var trans = this.config.trans || {}; + + $excludeRow.remove(); + + // Check if there are remaining exclude rows + var remainingRows = $container.find('.exclude-row').length; + + if (remainingRows === 0) { + // Remove entire excludes section and show "Add exceptions" button + var $excludesDiv = $group.find('.group-excludes'); + $excludesDiv.removeClass('has-excludes').html( + '' + ); + // Unlock the method selector since no excludes exist + this.updateMethodSelectorLock($group, false); + } + + this.serializeAllBlocks(); + }, + + // Method options building + buildMethodOptions: function(methods, excludeAll) { + var self = this; + var trans = this.config.trans || {}; + var html = ''; + + // Group labels + var groupLabels = { + 'select_by': trans.select_by || 'Select by...', + 'filter_by': trans.filter_by || 'Filter by...' + }; + + // Separate methods by group + var grouped = {}; + var ungrouped = {}; + + $.each(methods, function(methodKey, methodDef) { + if (excludeAll && methodKey === 'all') return true; // skip + + var group = methodDef.group || ''; + if (group) { + if (!grouped[group]) { + grouped[group] = {}; + } + grouped[group][methodKey] = methodDef; + } else { + ungrouped[methodKey] = methodDef; + } + }); + + // Render ungrouped options first + $.each(ungrouped, function(methodKey, methodDef) { + html += self.buildMethodOption(methodKey, methodDef); + }); + + // Render grouped options with optgroups + $.each(grouped, function(groupKey, groupMethods) { + var groupLabel = groupLabels[groupKey] || groupKey.replace(/_/g, ' '); + html += ''; + $.each(groupMethods, function(methodKey, methodDef) { + html += self.buildMethodOption(methodKey, methodDef); + }); + html += ''; + }); + + return html; + }, + + buildMethodOption: function(methodKey, methodDef) { + var html = '
    '; + + // Create and append popover + var $popover = $(html); + $('body').append($popover); + + // Store references + this.$previewPopover = $popover; + this.$previewList = $popover.find('.preview-list'); + this.previewLoadedCount = items.length; + this.previewTotalCount = totalCount; + this.previewContext = options.context || {}; + this.previewOnLoadMore = options.onLoadMore || null; + this.previewOnFilter = options.onFilter || null; + this.previewCurrentFilter = ''; + this.previewEntityLabel = entityLabel; + + // Event handlers + $popover.find('.preview-close').on('click', function() { + self.hidePreviewPopover(); + }); + + // Filter input with AJAX support + var $filterInput = $popover.find('.preview-filter-input'); + if (options.onFilter) { + // Use AJAX filtering with debounce + var debouncedFilter = this.debounce(function(query) { + self.previewCurrentFilter = query; + self.showFilterLoading(true); + options.onFilter.call(self, query); + }, 300); + + $filterInput.on('input', function() { + var query = $(this).val().trim(); + if (query === self.previewCurrentFilter) return; + debouncedFilter(query); + }); + } else { + // Fallback to client-side filtering + $filterInput.on('input', function() { + var query = $(this).val().toLowerCase().trim(); + self.filterPreviewItems(query); + }); + } + + if (options.onLoadMore) { + $popover.find('.btn-load-more').on('click', function() { + var $btn = $(this); + var $controls = $btn.closest('.load-more-controls'); + var $select = $controls.find('.load-more-select'); + + if ($btn.hasClass('loading')) return; + + $btn.addClass('loading'); + $btn.find('i').replaceWith(self.esIcon('progress_activity', 'es-spin')); + $select.prop('disabled', true); + + // Get selected load count + var loadCount = parseInt($select.val(), 10) || 20; + self.previewLoadCount = loadCount; + + options.onLoadMore.call(self, $btn); + }); + } + + // 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 + }); + + // Show with transition + $popover.addClass('show'); + + return $popover; + }, + + /** + * Update popover after loading more items + */ + updatePreviewPopover: function(items, hasMore) { + var trans = this.config.trans || {}; + + // Update list + this.$previewList.html(this.renderPreviewItems(items)); + this.previewLoadedCount = items.length; + + // Update or remove load more controls + var $footer = this.$previewPopover.find('.preview-footer'); + if (hasMore) { + var remaining = this.previewTotalCount - items.length; + var $controls = $footer.find('.load-more-controls'); + var $btn = $controls.find('.btn-load-more'); + var $select = $controls.find('.load-more-select'); + + // Reset button state + $btn.removeClass('loading'); + $btn.find('i').replaceWith(this.esIcon('add')); + $select.prop('disabled', false); + + // Update remaining count + $controls.find('.remaining-count').text(remaining); + + // Update select options + $select.empty(); + if (remaining >= 10) $select.append(''); + if (remaining >= 20) $select.append(''); + if (remaining >= 50) $select.append(''); + if (remaining >= 100) $select.append(''); + $select.append(''); + } else { + $footer.remove(); + } + + // Re-apply filter if active + var filterQuery = this.$previewPopover.find('.preview-filter-input').val(); + if (filterQuery) { + this.filterPreviewItems(filterQuery.toLowerCase().trim()); + } + }, + + /** + * Render preview items HTML with consistent format + */ + renderPreviewItems: function(items) { + var self = this; + var html = ''; + + for (var i = 0; i < items.length; i++) { + var item = items[i]; + var itemClass = 'preview-item'; + if (item.isCombination) itemClass += ' is-combination'; + + // Build data attributes for filtering + var dataAttrs = ''; + dataAttrs += ' data-name="' + this.escapeAttr((item.name || '').toLowerCase()) + '"'; + dataAttrs += ' data-ref="' + this.escapeAttr((item.reference || '').toLowerCase()) + '"'; + if (item.attributes) { + dataAttrs += ' data-attrs="' + this.escapeAttr((item.attributes || '').toLowerCase()) + '"'; + } + + html += '
    '; + + // Image or placeholder + if (item.image) { + html += ''; + } else { + html += '
    ' + self.esIcon('inventory_2') + '
    '; + } + + // Info section + html += '
    '; + html += '
    ' + this.escapeHtml(item.name || 'Unnamed') + '
    '; + + // Meta line (reference, manufacturer, category, attributes) + var meta = []; + if (item.reference) { + meta.push('Ref: ' + item.reference); + } + if (item.manufacturer) { + meta.push(item.manufacturer); + } + if (item.category) { + meta.push(item.category); + } + if (item.attributes) { + meta.push(item.attributes); + } + + if (meta.length > 0) { + html += '
    ' + this.escapeHtml(meta.join(' • ')) + '
    '; + } + + html += '
    '; // .preview-item-info + + // Price column (always show if available) + if (typeof item.price !== 'undefined' && item.price !== null) { + html += '
    ' + this.formatPrice(item.price) + '
    '; + } else if (item.price_formatted) { + html += '
    ' + this.escapeHtml(item.price_formatted) + '
    '; + } + + // Status badge if inactive + if (typeof item.active !== 'undefined' && !item.active) { + html += 'Inactive'; + } + + html += '
    '; // .preview-item + } + + return html; + }, + + /** + * Filter preview items by query (client-side fallback) + */ + filterPreviewItems: function(query) { + if (!this.$previewList) return; + + var $items = this.$previewList.find('.preview-item'); + + if (!query) { + $items.show(); + return; + } + + $items.each(function() { + var $item = $(this); + var name = $item.data('name') || ''; + var ref = $item.data('ref') || ''; + var attrs = $item.data('attrs') || ''; + + var matches = name.indexOf(query) !== -1 || + ref.indexOf(query) !== -1 || + attrs.indexOf(query) !== -1; + + $item.toggle(matches); + }); + }, + + /** + * Show/hide loading indicator during AJAX filter + */ + showFilterLoading: function(show) { + if (!this.$previewPopover) return; + + var $list = this.$previewList; + if (!$list) return; + + if (show) { + // Lock the popover width before filtering to prevent resize + if (!this.previewLockedWidth) { + this.previewLockedWidth = this.$previewPopover.outerWidth(); + this.$previewPopover.css('width', this.previewLockedWidth + 'px'); + } + + $list.addClass('filtering'); + // Add overlay if not exists + if (!$list.find('.filter-loading-overlay').length) { + $list.append('
    ' + self.esIcon('progress_activity', 'es-spin') + '
    '); + } + } else { + $list.removeClass('filtering'); + $list.find('.filter-loading-overlay').remove(); + } + }, + + /** + * Update preview popover with filtered AJAX results + * @param {Object} response - AJAX response with items, count, hasMore + */ + updatePreviewPopoverFiltered: function(response) { + var trans = this.config.trans || {}; + + this.showFilterLoading(false); + + if (!response.success) { + return; + } + + var items = response.items || []; + var filteredCount = response.count || 0; + var hasMore = response.hasMore || false; + + // Update header count to show filtered count + var $header = this.$previewPopover.find('.preview-header'); + var entityLabel = this.previewEntityLabel || 'items'; + $header.find('.preview-count').text(filteredCount + ' ' + entityLabel); + + // Update list + if (items.length > 0) { + this.$previewList.html(this.renderPreviewItems(items)); + this.previewLoadedCount = items.length; + this.previewTotalCount = filteredCount; + } else { + var noResultsText = trans.no_filter_results || 'No matching items found'; + this.$previewList.html('
    ' + noResultsText + '
    '); + this.previewLoadedCount = 0; + this.previewTotalCount = 0; + } + + // Update or create footer for load more + var $footer = this.$previewPopover.find('.preview-footer'); + if (hasMore && items.length > 0) { + var remaining = filteredCount - items.length; + if ($footer.length) { + var $controls = $footer.find('.load-more-controls'); + var $btn = $controls.find('.btn-load-more'); + var $select = $controls.find('.load-more-select'); + + $btn.removeClass('loading'); + $btn.find('i').replaceWith(self.esIcon('add')); + $select.prop('disabled', false); + $controls.find('.remaining-count').text(remaining); + + $select.empty(); + if (remaining >= 10) $select.append(''); + if (remaining >= 20) $select.append(''); + if (remaining >= 50) $select.append(''); + if (remaining >= 100) $select.append(''); + $select.append(''); + } else { + // Create footer + var footerHtml = ''; + + var $newFooter = $(footerHtml); + this.$previewList.after($newFooter); + + // Rebind load more click + var self = this; + if (this.previewOnLoadMore) { + $newFooter.find('.btn-load-more').on('click', function() { + var $btn = $(this); + var $controls = $btn.closest('.load-more-controls'); + var $select = $controls.find('.load-more-select'); + + if ($btn.hasClass('loading')) return; + + $btn.addClass('loading'); + $btn.find('i').replaceWith(self.esIcon('progress_activity', 'es-spin')); + $select.prop('disabled', true); + + var loadCount = parseInt($select.val(), 10) || 20; + self.previewLoadCount = loadCount; + + self.previewOnLoadMore.call(self, $btn); + }); + } + } + } else { + $footer.remove(); + } + }, + + /** + * Format price for display + */ + formatPrice: function(price) { + if (typeof price !== 'number') { + price = parseFloat(price) || 0; + } + // Use currency format from config if available + var currencySign = (this.config && this.config.currency_sign) || '€'; + var currencyFormat = (this.config && this.config.currency_format) || 'right'; + + var formatted = price.toFixed(2); + + if (currencyFormat === 'left') { + return currencySign + ' ' + formatted; + } else { + return formatted + ' ' + currencySign; + } + }, + + /** + * Hide and clean up preview popover + */ + hidePreviewPopover: function() { + if (this.$activeBadge) { + this.$activeBadge.removeClass('popover-open loading'); + this.$activeBadge = null; + } + if (this.$previewPopover) { + this.$previewPopover.remove(); + this.$previewPopover = null; + } + this.$previewList = null; + this.previewContext = null; + this.previewOnLoadMore = null; + this.previewOnFilter = null; + this.previewCurrentFilter = ''; + this.previewEntityLabel = null; + this.previewLockedWidth = null; + }, + + // ========================================================================= + // TAB PREVIEW (Block tab badge click) + // ========================================================================= + + showPreviewPopover: function($tab) { + var self = this; + var previewData = $tab.data('previewData'); + + if (!previewData) { + return; + } + + this.hidePreviewPopover(); + + var $badge = $tab.find('.tab-badge'); + $badge.addClass('popover-open'); + this.$activeBadge = $badge; + + var items = previewData.items || previewData.products || []; + var blockType = $tab.data('blockType'); + var blockConfig = this.config.blocks && this.config.blocks[blockType] ? this.config.blocks[blockType] : {}; + var entityLabelPlural = blockConfig.entity_label_plural || 'items'; + + this.previewBlockType = blockType; + + // If items not loaded yet, fetch them first + if (items.length === 0 && previewData.count > 0) { + $badge.addClass('loading'); + this.fetchTabPreviewItems($tab, function(fetchedItems, hasMore) { + $badge.removeClass('loading'); + self.createPreviewPopover({ + $badge: $badge, + items: fetchedItems, + totalCount: previewData.count, + hasMore: hasMore, + entityLabel: entityLabelPlural, + previewType: 'tab', + context: { $tab: $tab, blockType: blockType }, + onLoadMore: function($btn) { + self.loadMoreTabPreviewItems($tab, $btn); + }, + onFilter: function(query) { + self.filterTabPreviewItems($tab, query); + } + }); + }); + return; + } + + this.createPreviewPopover({ + $badge: $badge, + items: items, + totalCount: previewData.count, + hasMore: previewData.hasMore, + entityLabel: entityLabelPlural, + previewType: 'tab', + context: { $tab: $tab, blockType: blockType }, + onLoadMore: function($btn) { + self.loadMoreTabPreviewItems($tab, $btn); + }, + onFilter: function(query) { + self.filterTabPreviewItems($tab, query); + } + }); + }, + + /** + * Fetch preview items for a tab via AJAX + */ + fetchTabPreviewItems: function($tab, callback) { + var self = this; + var blockType = $tab.data('blockType'); + + var $hiddenInput = this.$wrapper.find('input[name="' + this.config.name + '"]'); + var savedData = {}; + try { + savedData = JSON.parse($hiddenInput.val() || '{}'); + } catch (e) { + callback([], false); + return; + } + + var groups = (savedData[blockType] && savedData[blockType].groups) ? savedData[blockType].groups : []; + if (groups.length === 0) { + callback([], false); + return; + } + + var data = {}; + data[blockType] = { groups: groups }; + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'previewEntitySelector', + trait: 'EntitySelector', + conditions: JSON.stringify(data), + block_type: blockType, + limit: 20, + offset: 0 + }, + success: function(response) { + var items = response.items || response.products || []; + var hasMore = response.hasMore || (response.count > items.length); + // Update stored preview data with items + $tab.data('previewData', response); + callback(items, hasMore); + }, + error: function() { + callback([], false); + } + }); + }, + + /** + * AJAX filter handler for tab preview + */ + filterTabPreviewItems: function($tab, query) { + var self = this; + var blockType = this.previewBlockType; + + var $hiddenInput = this.$wrapper.find('input[name="' + this.config.name + '"]'); + var savedData = {}; + try { + savedData = JSON.parse($hiddenInput.val() || '{}'); + } catch (e) { + self.showFilterLoading(false); + return; + } + + var groups = (savedData[blockType] && savedData[blockType].groups) ? savedData[blockType].groups : []; + if (groups.length === 0) { + self.showFilterLoading(false); + return; + } + + var data = {}; + data[blockType] = { groups: groups }; + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'previewTargetConditions', + trait: 'TargetConditions', + conditions: JSON.stringify(data), + block_type: blockType, + filter: query, + limit: 20, + offset: 0 + }, + success: function(response) { + self.updatePreviewPopoverFiltered(response); + }, + error: function() { + self.showFilterLoading(false); + } + }); + }, + + loadMoreTabPreviewItems: function($tab, $btn) { + var self = this; + var blockType = this.previewBlockType; + + var $hiddenInput = this.$wrapper.find('input[name="' + this.config.name + '"]'); + var savedData = {}; + try { + savedData = JSON.parse($hiddenInput.val() || '{}'); + } catch (e) { + return; + } + + var groups = (savedData[blockType] && savedData[blockType].groups) ? savedData[blockType].groups : []; + if (groups.length === 0) return; + + var data = {}; + data[blockType] = { groups: groups }; + + var loadCount = this.previewLoadCount || 20; + + // Include current filter in load more request + var ajaxData = { + ajax: 1, + action: 'previewTargetConditions', + trait: 'TargetConditions', + conditions: JSON.stringify(data), + block_type: blockType, + limit: self.previewLoadedCount + loadCount, + offset: 0 + }; + if (self.previewCurrentFilter) { + ajaxData.filter = self.previewCurrentFilter; + } + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: ajaxData, + success: function(response) { + var items = response.items || response.products || []; + if (response.success && items.length > 0) { + $tab.data('previewData', response); + self.previewTotalCount = response.count; + self.updatePreviewPopover(items, response.hasMore); + } + }, + error: function() { + var $controls = $btn.closest('.load-more-controls'); + var $select = $controls.find('.load-more-select'); + $btn.removeClass('loading'); + $btn.find('i').replaceWith(self.esIcon('add')); + $select.prop('disabled', false); + } + }); + }, + + // ========================================================================= + // CONDITION PREVIEW (Single condition badge click) + // ========================================================================= + + showConditionPreviewPopover: function($badge) { + var self = this; + var conditionData = $badge.data('conditionData'); + + if (!conditionData) { + return; + } + + // Check if this is a country holidays badge + if (conditionData.isCountryHolidays && conditionData.countryIds) { + this.showCountriesHolidayPreview($badge, conditionData.countryIds); + return; + } + + this.hidePreviewPopover(); + + $badge.addClass('popover-open loading'); + this.$activeBadge = $badge; + + var blockType = conditionData.blockType || 'products'; + var blockConfig = this.config.blocks && this.config.blocks[blockType] ? this.config.blocks[blockType] : {}; + var entityLabelPlural = blockConfig.entity_label_plural || 'products'; + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'previewConditionItems', + trait: 'EntitySelector', + method: conditionData.method, + values: JSON.stringify(conditionData.values), + block_type: blockType, + limit: 10 + }, + success: function(response) { + $badge.removeClass('loading'); + + if (response.success) { + self.createPreviewPopover({ + $badge: $badge, + items: response.items || [], + totalCount: response.count, + hasMore: response.hasMore, + entityLabel: entityLabelPlural, + previewType: 'condition', + context: { conditionData: conditionData, blockType: blockType }, + onLoadMore: function($btn) { + self.loadMoreConditionItems($btn); + }, + onFilter: function(query) { + self.filterConditionItems(query); + } + }); + } else { + $badge.removeClass('popover-open'); + self.$activeBadge = null; + } + }, + error: function() { + $badge.removeClass('loading popover-open'); + self.$activeBadge = null; + } + }); + }, + + /** + * AJAX filter handler for condition preview + */ + filterConditionItems: function(query) { + var self = this; + var ctx = this.previewContext; + + if (!ctx || !ctx.conditionData) { + self.showFilterLoading(false); + return; + } + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'previewConditionItems', + trait: 'EntitySelector', + method: ctx.conditionData.method, + values: JSON.stringify(ctx.conditionData.values), + block_type: ctx.blockType, + filter: query, + limit: 20 + }, + success: function(response) { + self.updatePreviewPopoverFiltered(response); + }, + error: function() { + self.showFilterLoading(false); + } + }); + }, + + loadMoreConditionItems: function($btn) { + var self = this; + var ctx = this.previewContext; + + if (!ctx || !ctx.conditionData) return; + + var loadCount = this.previewLoadCount || 20; + + // Include current filter in load more request + var ajaxData = { + ajax: 1, + action: 'previewConditionItems', + trait: 'EntitySelector', + method: ctx.conditionData.method, + values: JSON.stringify(ctx.conditionData.values), + block_type: ctx.blockType, + 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() { + var $controls = $btn.closest('.load-more-controls'); + var $select = $controls.find('.load-more-select'); + $btn.removeClass('loading'); + $btn.find('i').replaceWith(self.esIcon('add')); + $select.prop('disabled', false); + } + }); + }, + + // ========================================================================= + // GROUP PREVIEW (Selection group badge click) + // ========================================================================= + + showGroupPreviewPopover: function($badge, $group, blockType) { + var self = this; + + if (!$group) { + $group = $badge.closest('.selection-group'); + } + + if (!blockType) { + var $block = $badge.closest('.target-block'); + blockType = $block.data('blockType') || 'products'; + } + + var groupData = $badge.data('groupData'); + + if (!groupData) { + groupData = this.serializeGroup($group, blockType); + } + + if (!groupData || !groupData.include) { + return; + } + + this.hidePreviewPopover(); + + $badge.addClass('popover-open loading'); + this.$activeBadge = $badge; + + var blockConfig = this.config.blocks && this.config.blocks[blockType] ? this.config.blocks[blockType] : {}; + var entityLabelPlural = blockConfig.entity_label_plural || 'products'; + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'previewGroupItems', + trait: 'EntitySelector', + group_data: JSON.stringify(groupData), + block_type: blockType, + limit: 10 + }, + success: function(response) { + $badge.removeClass('loading'); + + if (response.success) { + self.createPreviewPopover({ + $badge: $badge, + items: response.items || [], + totalCount: response.count, + hasMore: response.hasMore, + entityLabel: entityLabelPlural, + previewType: 'group', + context: { groupData: groupData, blockType: blockType, $group: $group }, + onLoadMore: function($btn) { + self.loadMoreGroupItems($btn); + }, + onFilter: function(query) { + self.filterGroupItems(query); + } + }); + } else { + $badge.removeClass('popover-open'); + self.$activeBadge = null; + } + }, + error: function() { + $badge.removeClass('loading popover-open'); + self.$activeBadge = null; + } + }); + }, + + /** + * AJAX filter handler for group preview + */ + filterGroupItems: function(query) { + var self = this; + var ctx = this.previewContext; + + if (!ctx || !ctx.groupData) { + self.showFilterLoading(false); + return; + } + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'previewGroupItems', + trait: 'EntitySelector', + group_data: JSON.stringify(ctx.groupData), + block_type: ctx.blockType, + filter: query, + limit: 20 + }, + success: function(response) { + self.updatePreviewPopoverFiltered(response); + }, + error: function() { + self.showFilterLoading(false); + } + }); + }, + + loadMoreGroupItems: function($btn) { + var self = this; + var ctx = this.previewContext; + + if (!ctx || !ctx.groupData) return; + + var loadCount = this.previewLoadCount || 20; + + // Include current filter in load more request + var ajaxData = { + ajax: 1, + action: 'previewGroupItems', + trait: 'EntitySelector', + group_data: JSON.stringify(ctx.groupData), + block_type: ctx.blockType, + 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('.load-more-text').show(); + $btn.find('.load-more-loading').hide(); + } + }); + }, + + // ========================================================================= + // FILTER GROUP PREVIEW (Attribute/Feature group toggle badge) + // ========================================================================= + + showFilterGroupPreviewPopover: function($badge, groupId, groupType, groupName) { + var self = this; + + this.hidePreviewPopover(); + + $badge.addClass('popover-open loading'); + this.$activeBadge = $badge; + + var entityLabelPlural = 'products'; + + $.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) { + self.createPreviewPopover({ + $badge: $badge, + items: response.items || [], + totalCount: response.count || 0, + hasMore: response.hasMore || false, + entityLabel: entityLabelPlural, + previewType: 'filter-group', + context: { groupId: groupId, groupType: groupType, groupName: groupName }, + onLoadMore: function($btn) { + self.loadMoreFilterGroupItems($btn); + }, + onFilter: function(query) { + self.filterFilterGroupItems(query); + } + }); + } else { + $badge.removeClass('popover-open'); + self.$activeBadge = null; + } + }, + error: function() { + $badge.removeClass('loading popover-open'); + self.$activeBadge = null; + } + }); + }, + + /** + * AJAX filter handler for filter group preview + */ + filterFilterGroupItems: function(query) { + var self = this; + var ctx = this.previewContext; + + if (!ctx || !ctx.groupId) { + self.showFilterLoading(false); + return; + } + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'previewFilterGroupProducts', + trait: 'EntitySelector', + group_id: ctx.groupId, + group_type: ctx.groupType, + filter: query, + limit: 20 + }, + success: function(response) { + self.updatePreviewPopoverFiltered(response); + }, + error: function() { + self.showFilterLoading(false); + } + }); + }, + + loadMoreFilterGroupItems: function($btn) { + var self = this; + var ctx = this.previewContext; + + if (!ctx || !ctx.groupId) return; + + var loadCount = this.previewLoadCount || 20; + + // Include current filter in load more request + var ajaxData = { + ajax: 1, + action: 'previewFilterGroupProducts', + trait: 'EntitySelector', + group_id: ctx.groupId, + group_type: ctx.groupType, + 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('.load-more-text').show(); + $btn.find('.load-more-loading').hide(); + } + }); + }, + + // ========================================================================= + // CATEGORY ITEMS PREVIEW (products/pages in a category) + // ========================================================================= + + showCategoryItemsPreview: function($badge, categoryId, categoryName, entityType) { + var self = this; + + this.hidePreviewPopover(); + + $badge.addClass('popover-open loading'); + this.$activeBadge = $badge; + + var isProducts = (entityType === 'categories'); + var entityLabelPlural = isProducts ? 'products' : 'pages'; + var action = isProducts ? 'previewCategoryProducts' : 'previewCategoryPages'; + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: action, + trait: 'EntitySelector', + category_id: categoryId, + 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: entityLabelPlural, + previewType: 'category-items', + context: { categoryId: categoryId, categoryName: categoryName, entityType: entityType }, + onLoadMore: function($btn) { + self.loadMoreCategoryItems($btn); + }, + onFilter: function(query) { + self.filterCategoryItems(query); + } + }); + } else { + $badge.removeClass('popover-open'); + self.$activeBadge = null; + } + }, + error: function() { + $badge.removeClass('loading popover-open'); + self.$activeBadge = null; + } + }); + }, + + loadMoreCategoryItems: function($btn) { + var self = this; + var ctx = this.previewContext; + + if (!ctx || !ctx.categoryId) return; + + var isProducts = (ctx.entityType === 'categories'); + var action = isProducts ? 'previewCategoryProducts' : 'previewCategoryPages'; + + $btn.prop('disabled', true).find('i').addClass('es-spin'); + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: action, + trait: 'EntitySelector', + category_id: ctx.categoryId, + offset: this.previewOffset, + limit: 10, + query: this.previewFilterQuery || '' + }, + success: function(response) { + $btn.prop('disabled', false).find('i').removeClass('es-spin'); + + if (response.success && response.items) { + self.appendPreviewItems(response.items); + self.previewOffset += response.items.length; + + if (!response.hasMore) { + $btn.hide(); + } + } + }, + error: function() { + $btn.prop('disabled', false).find('i').removeClass('es-spin'); + } + }); + }, + + filterCategoryItems: function(query) { + var self = this; + var ctx = this.previewContext; + + if (!ctx || !ctx.categoryId) { + self.showFilterLoading(false); + return; + } + + var isProducts = (ctx.entityType === 'categories'); + var action = isProducts ? 'previewCategoryProducts' : 'previewCategoryPages'; + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: action, + trait: 'EntitySelector', + category_id: ctx.categoryId, + query: query, + limit: 10 + }, + success: function(response) { + self.showFilterLoading(false); + + if (response.success) { + self.replacePreviewItems(response.items || [], response.count || 0, response.hasMore || false); + self.previewOffset = response.items ? response.items.length : 0; + self.previewFilterQuery = query; + } + }, + error: function() { + self.showFilterLoading(false); + } + }); + }, + + // ========================================================================= + // PATTERN PREVIEW MODAL (for regex/pattern matching) + // ========================================================================= + + showPatternPreviewModal: function(pattern, entityType, caseSensitive, count) { + var self = this; + var trans = this.config.trans || {}; + + var blockConfig = this.config.blocks && this.config.blocks[entityType] ? this.config.blocks[entityType] : {}; + var entityLabelPlural = blockConfig.entity_label_plural || 'items'; + var entityLabelSingular = blockConfig.entity_label || 'item'; + + var html = '
    '; + html += '
    '; + html += '
    '; + html += ''; + html += this.esIcon('visibility') + ' ' + (trans.preview || 'Preview') + ': ' + this.escapeHtml(pattern) + ''; + html += ''; + html += '' + count + ' ' + (count === 1 ? entityLabelSingular : entityLabelPlural) + ''; + html += ''; + html += '
    '; + html += '
    '; + html += '
    ' + this.esIcon('progress_activity', 'es-spin') + ' ' + (trans.loading || 'Loading...') + '
    '; + html += '
    '; + html += '
    '; + html += '
    '; + + var $modal = $(html); + $('body').append($modal); + + $modal.find('.pattern-preview-close').on('click', function() { + $modal.remove(); + }); + $modal.on('click', function(e) { + if ($(e.target).hasClass('pattern-preview-modal-overlay')) { + $modal.remove(); + } + }); + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'previewPatternMatches', + trait: 'TargetConditions', + pattern: pattern, + entity_type: entityType, + case_sensitive: caseSensitive ? 1 : 0, + limit: 50 + }, + success: function(response) { + if (response.success && response.items) { + var items = response.items; + var listHtml = '
    '; + + if (items.length === 0) { + listHtml += '
    ' + (trans.no_matches || 'No matches found') + '
    '; + } else { + for (var i = 0; i < items.length; i++) { + var item = items[i]; + listHtml += '
    '; + if (item.image) { + listHtml += ''; + } + listHtml += '' + self.escapeHtml(item.name) + ''; + if (item.id) { + listHtml += '#' + item.id + ''; + } + listHtml += '
    '; + } + + if (count > items.length) { + listHtml += '
    ... ' + (trans.and || 'and') + ' ' + (count - items.length) + ' ' + (trans.more || 'more') + '
    '; + } + } + + listHtml += '
    '; + $modal.find('.pattern-preview-content').html(listHtml); + } else { + $modal.find('.pattern-preview-content').html('
    ' + (trans.error_loading || 'Error loading preview') + '
    '); + } + }, + error: function() { + $modal.find('.pattern-preview-content').html('
    ' + (trans.error_loading || 'Error loading preview') + '
    '); + } + }); + }, + + // ========================================================================= + // HELPER METHODS + // ========================================================================= + + refreshGroupPreviewIfOpen: function($group) { + // Check if preview is for this group and refresh if needed + if (!this.$activeBadge || !this.$previewPopover) { + return; + } + }, + + /** + * Escape HTML special characters + */ + escapeHtml: function(str) { + if (!str) return ''; + return String(str) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); + }, + + /** + * Escape attribute value + */ + escapeAttr: function(str) { + if (!str) return ''; + return String(str) + .replace(/&/g, '&') + .replace(/"/g, '"') + .replace(/'/g, '''); + }, + + // ========================================================================= + // TOTAL COUNT PREVIEW (Header total badge click) + // ========================================================================= + + /** + * Show preview popover for total count badge + * Displays a summary of all entity types with their counts + */ + showTotalPreviewPopover: function($badge) { + var self = this; + var trans = this.config.trans || {}; + + this.hidePreviewPopover(); + + $badge.addClass('popover-open'); + this.$activeBadge = $badge; + + // Collect all entity types with data + var summaryItems = []; + this.$wrapper.find('.target-block-tab.has-data').each(function() { + var $tab = $(this); + var blockType = $tab.data('blockType'); + var $tabBadge = $tab.find('.tab-badge'); + var countText = $tabBadge.text().replace(/[^0-9]/g, ''); + var count = parseInt(countText, 10) || 0; + + if (count > 0) { + var blockConfig = self.config.blocks && self.config.blocks[blockType] ? self.config.blocks[blockType] : {}; + var icon = $tab.find('.tab-label').prev('i').text() || 'widgets'; + var label = $tab.find('.tab-label').text() || blockType; + + summaryItems.push({ + blockType: blockType, + label: label, + icon: icon, + count: count + }); + } + }); + + // Build popover HTML + var totalCount = parseInt($badge.find('.count-value').text(), 10) || 0; + var popoverHtml = '
    '; + popoverHtml += '
    '; + popoverHtml += '' + (trans.total_summary || 'Selection Summary') + ''; + popoverHtml += '' + totalCount + ' ' + (trans.total_items || 'total items') + ''; + popoverHtml += '
    '; + popoverHtml += '
    '; + popoverHtml += '
      '; + + for (var i = 0; i < summaryItems.length; i++) { + var item = summaryItems[i]; + popoverHtml += '
    • '; + popoverHtml += this.esIcon(item.icon); + popoverHtml += '' + self.escapeHtml(item.label) + ''; + popoverHtml += '' + item.count + ''; + popoverHtml += '
    • '; + } + + popoverHtml += '
    '; + popoverHtml += '
    '; + popoverHtml += '
    '; + + var $popover = $(popoverHtml); + this.$previewPopover = $popover; + + // Click on item to switch to that tab + $popover.on('click', '.total-summary-item', function() { + var blockType = $(this).data('blockType'); + self.hidePreviewPopover(); + self.switchToBlock(blockType); + }); + + // Position popover + $('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); + } + + $popover.hide().fadeIn(150); + }, + + // ========================================================================= + // HOLIDAY PREVIEW (Country chip eye button click) + // ========================================================================= + + /** + * Show holiday preview popover for a country + * @param {number} countryId - Country ID + * @param {string} countryName - Country name + * @param {string} countryIso - Country ISO code + * @param {jQuery} $trigger - The button element that triggered this + */ + showHolidayPreview: function(countryId, countryName, countryIso, $trigger) { + var self = this; + var trans = this.config.trans || {}; + + // Close any existing holiday popover + $('.holiday-preview-popover').remove(); + + // Create popover HTML + var popoverHtml = '
    '; + popoverHtml += '
    '; + popoverHtml += ''; + if (countryIso) { + popoverHtml += ' '; + } + popoverHtml += this.escapeHtml(countryName) + ' - ' + (trans.holidays || 'Holidays'); + popoverHtml += ''; + popoverHtml += ''; + popoverHtml += '
    '; + popoverHtml += '
    '; + popoverHtml += '
    ' + this.esIcon('sync', 'es-spin') + ' ' + (trans.loading || 'Loading...') + '
    '; + popoverHtml += '
    '; + popoverHtml += '
    '; + + var $popover = $(popoverHtml); + $('body').append($popover); + + // Position popover near the trigger button + 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(); + + // Default: position below and to the right of the trigger + var top = triggerRect.bottom + scrollTop + 8; + var left = triggerRect.left + scrollLeft; + + // Adjust horizontal position if it goes off-screen + if (left + popoverWidth > windowWidth - 10) { + left = windowWidth - popoverWidth - 10; + } + if (left < 10) { + left = 10; + } + + // Adjust vertical position if it goes below viewport + if (triggerRect.bottom + popoverHeight > windowHeight - 10) { + // Position above the trigger instead + top = triggerRect.top + scrollTop - popoverHeight - 8; + } + + $popover.css({ + position: 'absolute', + top: top, + left: left, + zIndex: 10001 + }); + + // Close button handler + $popover.find('.popover-close').on('click', function() { + $popover.remove(); + }); + + // Fetch holidays via AJAX + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'getHolidaysPreview', + trait: 'EntitySelector', + id_country: countryId + }, + success: function(response) { + if (response.success && response.holidays && response.holidays.length > 0) { + var listHtml = '
    '; + for (var i = 0; i < response.holidays.length; i++) { + var h = response.holidays[i]; + var typeClass = h.type ? 'holiday-type-' + h.type.toLowerCase().replace(/\s+/g, '-') : ''; + listHtml += '
    '; + listHtml += '
    '; + listHtml += '' + self.escapeHtml(h.date_formatted || h.date) + ''; + if (h.day_of_week) { + listHtml += '' + self.escapeHtml(h.day_of_week) + ''; + } + listHtml += '
    '; + listHtml += '
    '; + listHtml += '' + self.escapeHtml(h.name) + ''; + if (h.type) { + listHtml += '' + self.escapeHtml(h.type) + ''; + } + listHtml += '
    '; + listHtml += '
    '; + } + listHtml += '
    '; + + if (response.total_count) { + listHtml += '
    ' + response.total_count + ' ' + (trans.upcoming_holidays || 'upcoming holidays') + '
    '; + } + + $popover.find('.popover-body').html(listHtml); + } else { + var noDataHtml = '
    '; + noDataHtml += self.esIcon('event_busy'); + noDataHtml += '

    ' + (trans.no_holidays || 'No holidays found') + '

    '; + noDataHtml += '
    '; + $popover.find('.popover-body').html(noDataHtml); + } + + // Re-adjust position after content loaded + var newPopoverHeight = $popover.outerHeight(); + if (triggerRect.bottom + newPopoverHeight > windowHeight - 10) { + var newTop = triggerRect.top + scrollTop - newPopoverHeight - 8; + if (newTop > 10) { + $popover.css('top', newTop); + } + } + }, + error: function() { + var errorHtml = '
    '; + errorHtml += self.esIcon('error'); + errorHtml += '

    ' + (trans.error_loading || 'Error loading holidays') + '

    '; + errorHtml += '
    '; + $popover.find('.popover-body').html(errorHtml); + } + }); + }, + + // ========================================================================= + // COUNTRIES HOLIDAY PREVIEW (Condition badge for multiple countries) + // ========================================================================= + + /** + * Show holiday preview popover for multiple selected countries + * @param {jQuery} $badge - The condition-match-count badge element + * @param {Array} countryIds - Array of country IDs + */ + showCountriesHolidayPreview: function($badge, countryIds) { + var self = this; + var trans = this.config.trans || {}; + + // Close any existing popovers + this.hidePreviewPopover(); + $('.holiday-preview-popover').remove(); + + // Create popover HTML with placeholder title (will update after AJAX) + var popoverHtml = '
    '; + popoverHtml += '
    '; + popoverHtml += '' + this.esIcon('sync', 'es-spin') + ' ' + (trans.loading || 'Loading...') + ''; + popoverHtml += ''; + popoverHtml += '
    '; + popoverHtml += '
    '; + popoverHtml += this.esIcon('search'); + popoverHtml += ''; + popoverHtml += '
    '; + popoverHtml += '
    '; + popoverHtml += '
    ' + this.esIcon('sync', 'es-spin') + ' ' + (trans.loading || 'Loading...') + '
    '; + popoverHtml += '
    '; + popoverHtml += '
    '; + + var $popover = $(popoverHtml); + $('body').append($popover); + + // Position popover near the badge + var badgeRect = $badge[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(); + + // Default: position below the badge + var top = badgeRect.bottom + scrollTop + 8; + var left = badgeRect.left + scrollLeft; + + // Adjust horizontal position + if (left + popoverWidth > windowWidth - 10) { + left = windowWidth - popoverWidth - 10; + } + if (left < 10) { + left = 10; + } + + // Adjust vertical position if it goes below viewport + if (badgeRect.bottom + popoverHeight > windowHeight - 10) { + top = badgeRect.top + scrollTop - popoverHeight - 8; + } + + $popover.css({ + position: 'absolute', + top: top, + left: left, + zIndex: 10001 + }); + + // Mark badge as open + $badge.addClass('popover-open'); + this.$activeBadge = $badge; + + // Close button handler + $popover.find('.popover-close').on('click', function() { + $popover.remove(); + $badge.removeClass('popover-open'); + self.$activeBadge = null; + }); + + // Fetch holidays via AJAX + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'getHolidaysForCountries', + trait: 'EntitySelector', + country_ids: countryIds.join(','), + count_only: 0 + }, + success: function(response) { + if (response.success && response.holidays && response.holidays.length > 0) { + // Count holidays per country to determine which flags to show + var countryHolidayCounts = {}; + var countriesMap = {}; + + // Build map of countries from response + if (response.countries) { + for (var ci = 0; ci < response.countries.length; ci++) { + var cInfo = response.countries[ci]; + countriesMap[cInfo.id] = cInfo; + countryHolidayCounts[cInfo.id] = 0; + } + } + + // Count holidays per country + for (var hi = 0; hi < response.holidays.length; hi++) { + var hol = response.holidays[hi]; + if (hol.country_id && typeof countryHolidayCounts[hol.country_id] !== 'undefined') { + countryHolidayCounts[hol.country_id]++; + } + } + + // Sort countries by holiday count (descending) + var sortedCountries = Object.keys(countriesMap).sort(function(a, b) { + return (countryHolidayCounts[b] || 0) - (countryHolidayCounts[a] || 0); + }).map(function(id) { + return countriesMap[id]; + }); + + // Build header title with flags for countries with most holidays + var titleHtml = ''; + var numCountries = sortedCountries.length; + if (numCountries <= 3) { + for (var fi = 0; fi < numCountries; fi++) { + var fc = sortedCountries[fi]; + if (fc && fc.iso_code) { + titleHtml += '' + self.escapeAttr(fc.iso_code) + ' '; + } + } + } else { + // Show top 2 flags (countries with most holidays) + count + for (var fj = 0; fj < 2; fj++) { + var fcc = sortedCountries[fj]; + if (fcc && fcc.iso_code) { + titleHtml += ' '; + } + } + titleHtml += '+' + (numCountries - 2) + ' '; + } + titleHtml += response.total_count + ' ' + (trans.holidays || 'Holidays'); + + // Update header title + $popover.find('.popover-title').html(titleHtml); + + var listHtml = '
    '; + for (var i = 0; i < response.holidays.length; i++) { + var h = response.holidays[i]; + var typeClass = h.type ? 'holiday-type-' + h.type.toLowerCase().replace(/\s+/g, '-') : ''; + // Build search text for filtering + var searchText = [ + h.name || '', + h.date_formatted || h.date || '', + h.day_of_week || '', + h.country_name || '', + h.type || '' + ].join(' ').toLowerCase(); + listHtml += '
    '; + listHtml += '
    '; + listHtml += '' + self.escapeHtml(h.date_formatted || h.date) + ''; + if (h.day_of_week) { + listHtml += '' + self.escapeHtml(h.day_of_week) + ''; + } + listHtml += '
    '; + listHtml += '
    '; + // Show country flag before holiday name when multiple countries + if (h.country_iso && countryIds.length > 1) { + listHtml += ' '; + } + listHtml += '' + self.escapeHtml(h.name) + ''; + if (h.type) { + listHtml += '' + self.escapeHtml(h.type) + ''; + } + listHtml += '
    '; + listHtml += '
    '; + } + listHtml += '
    '; + + if (response.total_count && countryIds.length > 1) { + var noteText = (trans.across_countries || 'across') + ' ' + countryIds.length + ' ' + (trans.countries || 'countries'); + listHtml += '
    ' + noteText + '
    '; + } + + $popover.find('.popover-body').html(listHtml); + + // Setup filter input handler + $popover.find('.holiday-filter-input').on('input', function() { + var query = $(this).val().toLowerCase().trim(); + var $items = $popover.find('.holiday-item'); + var visibleCount = 0; + + $items.each(function() { + var searchData = $(this).attr('data-search') || ''; + if (!query || searchData.indexOf(query) !== -1) { + $(this).show(); + visibleCount++; + } else { + $(this).hide(); + } + }); + + // Update note with filtered count + var $note = $popover.find('.holiday-preview-note'); + if (query && $note.length) { + $note.text(visibleCount + ' ' + (trans.matches || 'matches')); + } else if ($note.length && countryIds.length > 1) { + var noteText = (trans.across_countries || 'across') + ' ' + countryIds.length + ' ' + (trans.countries || 'countries'); + $note.text(noteText); + } + }); + } else { + // Update header for empty state + $popover.find('.popover-title').html('0 ' + (trans.holidays || 'Holidays')); + + var noDataHtml = '
    '; + noDataHtml += self.esIcon('event_busy'); + noDataHtml += '

    ' + (trans.no_holidays || 'No holidays found') + '

    '; + noDataHtml += '
    '; + $popover.find('.popover-body').html(noDataHtml); + } + + // Re-adjust position after content loaded + var newPopoverHeight = $popover.outerHeight(); + if (badgeRect.bottom + newPopoverHeight > windowHeight - 10) { + var newTop = badgeRect.top + scrollTop - newPopoverHeight - 8; + if (newTop > 10) { + $popover.css('top', newTop); + } + } + }, + error: function() { + // Update header for error state + $popover.find('.popover-title').html(self.esIcon('error') + ' ' + (trans.error || 'Error')); + + var errorHtml = '
    '; + errorHtml += self.esIcon('error'); + errorHtml += '

    ' + (trans.error_loading || 'Error loading holidays') + '

    '; + errorHtml += '
    '; + $popover.find('.popover-body').html(errorHtml); + } + }); + } + }; + +})(jQuery); diff --git a/sources/sources/js/admin/entity-selector/_search.js b/sources/sources/js/admin/entity-selector/_search.js new file mode 100644 index 0000000..ea05103 --- /dev/null +++ b/sources/sources/js/admin/entity-selector/_search.js @@ -0,0 +1,881 @@ +/** + * Entity Selector - Search Module + * AJAX search, results rendering, category tree, filters, search history + * @partial _search.js + */ + +(function($) { + 'use strict'; + + window._EntitySelectorMixins = window._EntitySelectorMixins || {}; + + window._EntitySelectorMixins.search = { + + // Category tree cache + categoryTreeCache: null, + + /** + * Perform AJAX search for entities + */ + performSearch: function(appendMode) { + var self = this; + + if (!this.activeGroup) return; + + this.isLoading = true; + + var searchEntity = this.activeGroup.searchEntity; + + // Build request data with sort and filter params + var limit = appendMode && this.loadMoreCount ? this.loadMoreCount : 20; + var requestData = { + ajax: 1, + action: 'searchTargetEntities', + trait: 'EntitySelector', + entity_type: searchEntity, + q: this.searchQuery, + limit: limit, + offset: appendMode ? this.searchOffset : 0, + sort_by: this.currentSort ? this.currentSort.field : 'name', + sort_dir: this.currentSort ? this.currentSort.dir : 'ASC' + }; + + // Add refine query if present + if (this.refineQuery) { + requestData.refine = this.refineQuery; + if (this.refineNegate) { + requestData.refine_negate = 1; + } + } + + // Add product-specific filters + if (searchEntity === 'products' && this.filters) { + if (this.filters.inStock) { + requestData.filter_in_stock = 1; + } + if (this.filters.discounted) { + requestData.filter_discounted = 1; + } + if (this.filters.priceMin !== null && this.filters.priceMin !== '') { + requestData.filter_price_min = this.filters.priceMin; + } + if (this.filters.priceMax !== null && this.filters.priceMax !== '') { + requestData.filter_price_max = this.filters.priceMax; + } + if (this.filters.attributes && this.filters.attributes.length > 0) { + requestData.filter_attributes = JSON.stringify(this.filters.attributes); + } + if (this.filters.features && this.filters.features.length > 0) { + requestData.filter_features = JSON.stringify(this.filters.features); + } + } + + // Add entity-specific filters for non-product entities + if (searchEntity !== 'products' && this.filters) { + // Product count range (categories, manufacturers, suppliers, attributes, features) + if (this.filters.productCountMin !== null && this.filters.productCountMin !== '') { + requestData.filter_product_count_min = this.filters.productCountMin; + } + if (this.filters.productCountMax !== null && this.filters.productCountMax !== '') { + requestData.filter_product_count_max = this.filters.productCountMax; + } + + // Category-specific + if (searchEntity === 'categories') { + if (this.filters.depth) { + requestData.filter_depth = this.filters.depth; + } + if (this.filters.hasProducts) { + requestData.filter_has_products = 1; + } + if (this.filters.hasDescription) { + requestData.filter_has_description = 1; + } + if (this.filters.hasImage) { + requestData.filter_has_image = 1; + } + if (this.filters.salesMin !== null && this.filters.salesMin !== '') { + requestData.filter_sales_min = this.filters.salesMin; + } + if (this.filters.salesMax !== null && this.filters.salesMax !== '') { + requestData.filter_sales_max = this.filters.salesMax; + } + if (this.filters.turnoverMin !== null && this.filters.turnoverMin !== '') { + requestData.filter_turnover_min = this.filters.turnoverMin; + } + if (this.filters.turnoverMax !== null && this.filters.turnoverMax !== '') { + requestData.filter_turnover_max = this.filters.turnoverMax; + } + if (this.filters.activeOnly) { + requestData.filter_active = 1; + } + } + + // Manufacturer-specific + if (searchEntity === 'manufacturers') { + if (this.filters.salesMin !== null && this.filters.salesMin !== '') { + requestData.filter_sales_min = this.filters.salesMin; + } + if (this.filters.salesMax !== null && this.filters.salesMax !== '') { + requestData.filter_sales_max = this.filters.salesMax; + } + if (this.filters.turnoverMin !== null && this.filters.turnoverMin !== '') { + requestData.filter_turnover_min = this.filters.turnoverMin; + } + if (this.filters.turnoverMax !== null && this.filters.turnoverMax !== '') { + requestData.filter_turnover_max = this.filters.turnoverMax; + } + if (this.filters.dateAddFrom) { + requestData.filter_date_add_from = this.filters.dateAddFrom; + } + if (this.filters.dateAddTo) { + requestData.filter_date_add_to = this.filters.dateAddTo; + } + if (this.filters.lastProductFrom) { + requestData.filter_last_product_from = this.filters.lastProductFrom; + } + if (this.filters.lastProductTo) { + requestData.filter_last_product_to = this.filters.lastProductTo; + } + if (this.filters.activeOnly) { + requestData.filter_active = 1; + } + } + + // Supplier-specific + if (searchEntity === 'suppliers') { + if (this.filters.salesMin !== null && this.filters.salesMin !== '') { + requestData.filter_sales_min = this.filters.salesMin; + } + if (this.filters.salesMax !== null && this.filters.salesMax !== '') { + requestData.filter_sales_max = this.filters.salesMax; + } + if (this.filters.turnoverMin !== null && this.filters.turnoverMin !== '') { + requestData.filter_turnover_min = this.filters.turnoverMin; + } + if (this.filters.turnoverMax !== null && this.filters.turnoverMax !== '') { + requestData.filter_turnover_max = this.filters.turnoverMax; + } + if (this.filters.dateAddFrom) { + requestData.filter_date_add_from = this.filters.dateAddFrom; + } + if (this.filters.dateAddTo) { + requestData.filter_date_add_to = this.filters.dateAddTo; + } + if (this.filters.lastProductFrom) { + requestData.filter_last_product_from = this.filters.lastProductFrom; + } + if (this.filters.lastProductTo) { + requestData.filter_last_product_to = this.filters.lastProductTo; + } + if (this.filters.activeOnly) { + requestData.filter_active = 1; + } + } + + // Attribute-specific + if (searchEntity === 'attributes') { + if (this.filters.salesMin !== null && this.filters.salesMin !== '') { + requestData.filter_sales_min = this.filters.salesMin; + } + if (this.filters.salesMax !== null && this.filters.salesMax !== '') { + requestData.filter_sales_max = this.filters.salesMax; + } + if (this.filters.turnoverMin !== null && this.filters.turnoverMin !== '') { + requestData.filter_turnover_min = this.filters.turnoverMin; + } + if (this.filters.turnoverMax !== null && this.filters.turnoverMax !== '') { + requestData.filter_turnover_max = this.filters.turnoverMax; + } + if (this.filters.attributeGroup) { + requestData.filter_attribute_group = this.filters.attributeGroup; + } + if (this.filters.isColor) { + requestData.filter_is_color = 1; + } + } + + // Feature-specific + if (searchEntity === 'features') { + if (this.filters.salesMin !== null && this.filters.salesMin !== '') { + requestData.filter_sales_min = this.filters.salesMin; + } + if (this.filters.salesMax !== null && this.filters.salesMax !== '') { + requestData.filter_sales_max = this.filters.salesMax; + } + if (this.filters.turnoverMin !== null && this.filters.turnoverMin !== '') { + requestData.filter_turnover_min = this.filters.turnoverMin; + } + if (this.filters.turnoverMax !== null && this.filters.turnoverMax !== '') { + requestData.filter_turnover_max = this.filters.turnoverMax; + } + if (this.filters.featureGroup) { + requestData.filter_feature_group = this.filters.featureGroup; + } + if (this.filters.isCustom) { + requestData.filter_is_custom = 1; + } + } + + // CMS-specific + if (searchEntity === 'cms') { + if (this.filters.activeOnly) { + requestData.filter_active = 1; + } + if (this.filters.indexable) { + requestData.filter_indexable = 1; + } + } + + // CMS Categories-specific + if (searchEntity === 'cms_categories') { + if (this.filters.activeOnly) { + requestData.filter_active = 1; + } + } + + // Countries-specific + if (searchEntity === 'countries') { + if (this.filters.activeOnly) { + requestData.filter_active = 1; + } + if (this.filters.hasHolidays) { + requestData.filter_has_holidays = 1; + } + if (this.filters.containsStates) { + requestData.filter_contains_states = 1; + } + if (this.filters.zone) { + requestData.filter_zone = this.filters.zone; + } + } + } + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: requestData, + success: function(response) { + self.isLoading = false; + + if (!response.success) return; + + // Save to search history if query is not empty and has results + if (self.searchQuery && self.searchQuery.length >= 2 && response.total > 0) { + self.addToSearchHistory(searchEntity, self.searchQuery); + } + + if (appendMode) { + self.searchResults = self.searchResults.concat(response.results || []); + } else { + self.searchResults = response.results || []; + } + self.searchTotal = response.total || 0; + self.searchOffset = appendMode ? self.searchOffset + (response.results || []).length : (response.results || []).length; + + self.renderSearchResults(appendMode); + self.$dropdown.addClass('show'); + }, + error: function() { + self.isLoading = false; + } + }); + }, + + /** + * Render search results in the dropdown + */ + renderSearchResults: function(appendMode) { + var self = this; + var trans = this.config.trans || {}; + var $container = this.$dropdown.find('.dropdown-results'); + + // Get selected IDs from current picker (to mark as selected) + // and hidden IDs from sibling exclude pickers with same entity type (to hide completely) + var selectedIds = []; + var hiddenIds = []; + if (this.activeGroup) { + var $block = this.$wrapper.find('.target-block[data-block-type="' + this.activeGroup.blockType + '"]'); + var $group = $block.find('.selection-group[data-group-index="' + this.activeGroup.groupIndex + '"]'); + var currentSearchEntity = this.activeGroup.searchEntity; + var currentExcludeIndex = this.activeGroup.excludeIndex; + + if (this.activeGroup.section === 'include') { + // For include section, just get current picker's selections + var $picker = $group.find('.include-picker'); + $picker.find('.entity-chip').each(function() { + selectedIds.push(String($(this).data('id'))); + }); + } else { + // For exclude section, get current picker's selections AND + // collect IDs from sibling exclude rows with same entity type to hide + var $currentExcludeRow = $group.find('.exclude-row[data-exclude-index="' + currentExcludeIndex + '"]'); + var $currentPicker = $currentExcludeRow.find('.exclude-picker'); + + // Get selected IDs from current exclude row + $currentPicker.find('.entity-chip').each(function() { + selectedIds.push(String($(this).data('id'))); + }); + + // Get hidden IDs from OTHER exclude rows with the same entity type + $group.find('.exclude-row').each(function() { + var $row = $(this); + var rowIndex = parseInt($row.data('excludeIndex'), 10); + + // Skip current exclude row + if (rowIndex === currentExcludeIndex) return; + + var $picker = $row.find('.exclude-picker'); + var rowEntityType = $picker.attr('data-search-entity') || self.activeGroup.blockType; + + // Only collect if same entity type + if (rowEntityType === currentSearchEntity) { + $picker.find('.entity-chip').each(function() { + hiddenIds.push(String($(this).data('id'))); + }); + } + }); + } + } + + // Check if this is a product search + var isProductSearch = this.activeGroup && this.activeGroup.searchEntity === 'products'; + var isListView = this.viewMode === 'list'; + + // Show/hide results header for products in list view + this.$dropdown.find('.results-header').toggle(isProductSearch && isListView); + + // Build HTML - filter out items that are hidden (selected in sibling exclude rows) + var visibleResults = this.searchResults.filter(function(item) { + return hiddenIds.indexOf(String(item.id)) === -1; + }); + + // Update count (show visible count and total, noting hidden items if any) + var hiddenCount = this.searchResults.length - visibleResults.length; + var countText = visibleResults.length + ' / ' + this.searchTotal + ' results'; + if (hiddenCount > 0) { + countText += ' (' + hiddenCount + ' hidden)'; + } + this.$dropdown.find('.results-count').text(countText); + + var html = ''; + if (visibleResults.length === 0 && !appendMode) { + html = '
    ' + this.esIcon('search') + ' ' + (trans.no_results || 'No results found') + '
    '; + } else { + visibleResults.forEach(function(item) { + var isSelected = selectedIds.indexOf(String(item.id)) !== -1; + var itemClass = 'dropdown-item' + (isSelected ? ' selected' : ''); + if (item.type === 'product') itemClass += ' result-item-product'; + + html += '
    '; + + var searchEntity = self.activeGroup ? self.activeGroup.searchEntity : null; + + // Countries show flags + if (searchEntity === 'countries' && item.iso_code) { + var flagUrl = 'https://flagcdn.com/w40/' + item.iso_code.toLowerCase() + '.png'; + html += '
    ' + self.escapeAttr(item.iso_code) + '
    '; + } else if (item.image) { + html += '
    '; + } else { + // Entity-specific icons + var iconName = 'widgets'; // default + if (searchEntity === 'categories') iconName = 'folder'; + else if (searchEntity === 'manufacturers') iconName = 'business'; + else if (searchEntity === 'suppliers') iconName = 'local_shipping'; + else if (searchEntity === 'attributes') iconName = 'brush'; + else if (searchEntity === 'features') iconName = 'list'; + else if (searchEntity === 'cms') iconName = 'description'; + else if (searchEntity === 'cms_categories') iconName = 'folder'; + html += '
    ' + self.esIcon(iconName) + '
    '; + } + + html += '
    '; + html += '
    ' + self.escapeHtml(item.name) + '
    '; + if (item.subtitle) { + // Split multi-line subtitles into separate divs for styling + var subtitleLines = item.subtitle.split('\n'); + html += '
    '; + subtitleLines.forEach(function(line, idx) { + var lineClass = idx === 0 ? 'subtitle-line subtitle-line-primary' : 'subtitle-line subtitle-line-secondary'; + html += '
    ' + self.escapeHtml(line) + '
    '; + }); + html += '
    '; + } + html += '
    '; + + // Add product-specific columns (price, sale price, stock, sold) + if (item.type === 'product') { + if (isListView) { + // List view: full columns + // Regular price + html += '
    '; + html += '' + (item.regular_price_formatted || item.price_formatted || '') + ''; + html += '
    '; + + // Sale price (only if discounted) + if (item.has_discount) { + html += '
    '; + html += '' + (item.price_formatted || '') + ''; + html += '
    '; + } else { + html += '
    '; + } + + // Stock column + var stockClass = item.stock_status === 'out_of_stock' ? 'stock-out' : + (item.stock_status === 'low_stock' ? 'stock-low' : 'stock-ok'); + html += '
    '; + html += '' + (item.stock_qty !== undefined ? item.stock_qty : '') + ''; + html += '
    '; + + // Sales column + html += '
    '; + html += '' + (item.sales_qty !== undefined ? item.sales_qty : '0') + ''; + html += '
    '; + } else { + // Grid view: compact info line + var gridStockClass = item.stock_status === 'out_of_stock' ? 'stock-out' : + (item.stock_status === 'low_stock' ? 'stock-low' : ''); + html += '
    '; + html += '' + (item.price_formatted || '') + ''; + if (item.stock_qty !== undefined) { + html += '' + item.stock_qty + ' qty'; + } + if (item.has_discount) { + html += '-' + (item.discount_percent || '') + '%'; + } + html += '
    '; + } + } + + html += '
    '; + }); + } + + if (appendMode) { + $container.append(html); + } else { + $container.html(html); + } + + // Show/hide load more controls and update remaining count + var hasMore = this.searchResults.length < this.searchTotal; + var $loadMoreControls = this.$dropdown.find('.load-more-controls'); + $loadMoreControls.toggle(hasMore); + + if (hasMore) { + var remaining = this.searchTotal - this.searchResults.length; + $loadMoreControls.find('.remaining-count').text(remaining); + + // Update "All" option in dropdown + var $select = $loadMoreControls.find('.load-more-select'); + var $allOption = $select.find('option[data-all="true"]'); + if ($allOption.length) { + $allOption.val(remaining).text((trans.all || 'All') + ' (' + remaining + ')'); + } else { + $select.find('option:last').after(''); + } + } + + // Ensure dropdown-actions are visible and history button is deactivated + this.$dropdown.find('.dropdown-actions').show(); + this.$dropdown.find('.btn-show-history').removeClass('active'); + + // Disable history button if no search history for current entity type + var entityType = this.activeGroup ? this.activeGroup.searchEntity : null; + var hasHistory = entityType && this.getSearchHistory(entityType).length > 0; + this.$dropdown.find('.btn-show-history').prop('disabled', !hasHistory); + }, + + // NOTE: Tree methods (loadCategoryTree, renderCategoryTree, filterCategoryTree, + // findTreeDescendants, findTreeAncestors, updateSelectChildrenButtons) are + // defined in _tree.js which is merged later and takes precedence. + + // ========================================================================= + // Search History + // ========================================================================= + + loadSearchHistory: function() { + try { + var stored = localStorage.getItem(this.searchHistoryKey); + this.searchHistory = stored ? JSON.parse(stored) : {}; + } catch (e) { + this.searchHistory = {}; + } + }, + + saveSearchHistory: function() { + try { + localStorage.setItem(this.searchHistoryKey, JSON.stringify(this.searchHistory)); + } catch (e) { + // localStorage might be full or unavailable + } + }, + + addToSearchHistory: function(entityType, query) { + if (!query || query.length < 2) return; + + if (!this.searchHistory[entityType]) { + this.searchHistory[entityType] = []; + } + + var history = this.searchHistory[entityType]; + + // Remove if already exists (will re-add at top) + var existingIndex = history.indexOf(query); + if (existingIndex !== -1) { + history.splice(existingIndex, 1); + } + + // Add at beginning + history.unshift(query); + + // Trim to max + if (history.length > this.searchHistoryMax) { + history = history.slice(0, this.searchHistoryMax); + } + + this.searchHistory[entityType] = history; + this.saveSearchHistory(); + }, + + removeFromSearchHistory: function(entityType, query) { + if (!this.searchHistory[entityType]) return; + + var index = this.searchHistory[entityType].indexOf(query); + if (index !== -1) { + this.searchHistory[entityType].splice(index, 1); + this.saveSearchHistory(); + } + }, + + getSearchHistory: function(entityType) { + return this.searchHistory[entityType] || []; + }, + + showSearchHistory: function(entityType) { + var history = this.getSearchHistory(entityType); + var trans = this.config.trans || {}; + var $container = this.$dropdown.find('.dropdown-results'); + + // Update header + this.$dropdown.find('.results-count').text(trans.recent_searches || 'Recent searches'); + + // Hide filters, actions, and results header for history view + this.$dropdown.find('.dropdown-actions').hide(); + this.$dropdown.find('.filter-panel').removeClass('show'); + this.$dropdown.find('.btn-toggle-filters').removeClass('active'); + this.$dropdown.find('.results-header').hide(); + + if (!history.length) { + // No history - just do a regular search + this.performSearch(); + return; + } + + // Build history items + var html = '
    '; + for (var i = 0; i < history.length; i++) { + var query = history[i]; + html += '
    '; + html += this.esIcon('schedule'); + html += '' + this.escapeHtml(query) + ''; + html += ''; + html += '
    '; + } + html += '
    '; + + $container.html(html); + this.$dropdown.addClass('show'); + }, + + // ========================================================================= + // Filter Methods + // ========================================================================= + + refreshSearch: function() { + // In tree view mode, re-filter the tree instead of doing a flat AJAX search + if (this.viewMode === 'tree') { + this.filterCategoryTree(this.searchQuery || ''); + return; + } + + this.searchOffset = 0; + this.loadMoreCount = 20; + // Reset load more select to default + if (this.$dropdown) { + this.$dropdown.find('.load-more-select').val('20'); + // Remove the dynamic "All" option + this.$dropdown.find('.load-more-select option[data-all="true"]').remove(); + } + this.performSearch(false); + }, + + clearFilters: function() { + this.refineQuery = ''; + this.refineNegate = false; + this.filters = { + inStock: false, + discounted: false, + priceMin: null, + priceMax: null, + attributes: [], + features: [], + // Entity-specific filters + productCountMin: null, + productCountMax: null, + salesMin: null, + salesMax: null, + turnoverMin: null, + turnoverMax: null, + depth: null, + hasProducts: false, + hasDescription: false, + hasImage: false, + activeOnly: true, + attributeGroup: null, + featureGroup: null, + dateAddFrom: null, + dateAddTo: null, + lastProductFrom: null, + lastProductTo: null, + // Country-specific filters + hasHolidays: false, + containsStates: false, + zone: null + }; + + if (this.$dropdown) { + var trans = this.config.trans || {}; + this.$dropdown.find('.refine-input').val('').attr('placeholder', trans.refine_short || 'Refine...'); + this.$dropdown.find('.btn-clear-refine').hide(); + this.$dropdown.find('.btn-refine-negate').removeClass('active'); + this.$dropdown.find('.filter-in-stock').prop('checked', false); + this.$dropdown.find('.filter-discounted').prop('checked', false); + this.$dropdown.find('.filter-price-min').val(''); + this.$dropdown.find('.filter-price-max').val(''); + this.$dropdown.find('.filter-attr-chip').removeClass('active'); + this.$dropdown.find('.filter-feat-chip').removeClass('active'); + this.$dropdown.find('.filter-group-toggle').removeClass('active has-selection'); + this.$dropdown.find('.filter-row-values').hide(); + + // Clear entity-specific filter inputs + this.$dropdown.find('.filter-product-count-min, .filter-product-count-max').val(''); + this.$dropdown.find('.filter-sales-min, .filter-sales-max').val(''); + this.$dropdown.find('.filter-turnover-min, .filter-turnover-max').val(''); + this.$dropdown.find('.filter-date-add-from, .filter-date-add-to').val(''); + this.$dropdown.find('.filter-last-product-from, .filter-last-product-to').val(''); + this.$dropdown.find('.filter-depth-select').val(''); + this.$dropdown.find('.filter-has-products').prop('checked', false); + this.$dropdown.find('.filter-has-description').prop('checked', false); + this.$dropdown.find('.filter-has-image').prop('checked', false); + this.$dropdown.find('.filter-active-only').prop('checked', true); + this.$dropdown.find('.filter-attribute-group-select, .filter-feature-group-select').val(''); + // Country filters + this.$dropdown.find('.filter-has-holidays').prop('checked', false); + this.$dropdown.find('.filter-contains-states').prop('checked', false); + this.$dropdown.find('.filter-zone-select').val(''); + } + + this.refreshSearch(); + }, + + // Reset filters without triggering a search (used when switching entity types) + resetFiltersWithoutSearch: function() { + this.refineQuery = ''; + this.refineNegate = false; + this.filters = { + inStock: false, + discounted: false, + priceMin: null, + priceMax: null, + attributes: [], + features: [], + productCountMin: null, + productCountMax: null, + salesMin: null, + salesMax: null, + turnoverMin: null, + turnoverMax: null, + depth: null, + hasProducts: false, + hasDescription: false, + hasImage: false, + activeOnly: true, + attributeGroup: null, + featureGroup: null, + dateAddFrom: null, + dateAddTo: null, + lastProductFrom: null, + lastProductTo: null, + // Country-specific filters + hasHolidays: false, + containsStates: false, + zone: null + }; + + if (this.$dropdown) { + var trans = this.config.trans || {}; + this.$dropdown.find('.refine-input').val('').attr('placeholder', trans.refine_short || 'Refine...'); + this.$dropdown.find('.btn-clear-refine').hide(); + this.$dropdown.find('.btn-refine-negate').removeClass('active'); + this.$dropdown.find('.filter-in-stock').prop('checked', false); + this.$dropdown.find('.filter-discounted').prop('checked', false); + this.$dropdown.find('.filter-price-min').val(''); + this.$dropdown.find('.filter-price-max').val(''); + this.$dropdown.find('.filter-attr-chip').removeClass('active'); + this.$dropdown.find('.filter-feat-chip').removeClass('active'); + this.$dropdown.find('.filter-group-toggle').removeClass('active has-selection'); + this.$dropdown.find('.filter-row-values').hide(); + this.$dropdown.find('.filter-product-count-min, .filter-product-count-max').val(''); + this.$dropdown.find('.filter-sales-min, .filter-sales-max').val(''); + this.$dropdown.find('.filter-turnover-min, .filter-turnover-max').val(''); + this.$dropdown.find('.filter-date-add-from, .filter-date-add-to').val(''); + this.$dropdown.find('.filter-last-product-from, .filter-last-product-to').val(''); + this.$dropdown.find('.filter-depth-select').val(''); + this.$dropdown.find('.filter-has-products').prop('checked', false); + this.$dropdown.find('.filter-has-description').prop('checked', false); + this.$dropdown.find('.filter-has-image').prop('checked', false); + this.$dropdown.find('.filter-active-only').prop('checked', true); + this.$dropdown.find('.filter-attribute-group-select, .filter-feature-group-select').val(''); + // Country filters + this.$dropdown.find('.filter-has-holidays').prop('checked', false); + this.$dropdown.find('.filter-contains-states').prop('checked', false); + this.$dropdown.find('.filter-zone-select').val(''); + } + // Note: Does NOT call refreshSearch() - caller handles search/load + }, + + updateFilterPanelForEntity: function(entityType) { + if (!this.$dropdown) { + return; + } + + var $panel = this.$dropdown.find('.filter-panel'); + + // Hide all filter rows first + $panel.find('.filter-row').hide(); + + // Show/hide tree view option based on entity type + var $treeOption = this.$dropdown.find('.view-mode-select option.tree-view-option'); + if (entityType === 'categories' || entityType === 'cms_categories') { + $treeOption.prop('disabled', false).prop('hidden', false); + // Auto-switch to tree view for categories + if (this.viewMode !== 'tree') { + this.viewMode = 'tree'; + this.$dropdown.find('.view-mode-select').val('tree'); + this.$dropdown.removeClass('view-list view-cols-2 view-cols-3 view-cols-4 view-cols-5 view-cols-6 view-cols-7 view-cols-8').addClass('view-tree'); + this.loadCategoryTree(); + } else { + this.loadCategoryTree(); + } + } else { + $treeOption.prop('disabled', true).prop('hidden', true); + // If currently in tree mode, switch back to list + if (this.viewMode === 'tree') { + this.viewMode = 'list'; + this.$dropdown.find('.view-mode-select').val('list'); + this.$dropdown.removeClass('view-tree').addClass('view-list'); + } + } + + // Show entity-specific filter row (prepare visibility, but don't auto-expand panel) + if (entityType === 'products') { + // Prepare the correct rows to be visible when panel is shown + $panel.find('.filter-row-quick').show(); + // Show attribute/feature rows if we have cached data + if (this.filterableData) { + if (this.filterableData.attributes && this.filterableData.attributes.length > 0) { + this.$dropdown.find('.filter-row-attributes').show(); + } + if (this.filterableData.features && this.filterableData.features.length > 0) { + this.$dropdown.find('.filter-row-features').show(); + } + } + } else if (entityType === 'categories') { + $panel.find('.filter-row-entity-categories').show(); + } else if (entityType === 'manufacturers') { + $panel.find('.filter-row-entity-manufacturers').show(); + } else if (entityType === 'suppliers') { + $panel.find('.filter-row-entity-suppliers').show(); + } else if (entityType === 'attributes') { + $panel.find('.filter-row-entity-attributes').show(); + this.loadAttributeGroups(); + } else if (entityType === 'features') { + $panel.find('.filter-row-entity-features').show(); + } else if (entityType === 'cms') { + $panel.find('.filter-row-entity-cms').show(); + } else if (entityType === 'cms_categories') { + $panel.find('.filter-row-entity-cms-categories').show(); + } else if (entityType === 'countries') { + $panel.find('.filter-row-entity-countries').show(); + this.loadZonesForCountryFilter(); + } + }, + + loadAttributeGroups: function() { + var self = this; + var $select = this.$dropdown.find('.filter-attribute-group-select'); + + // Already loaded? + if ($select.find('option').length > 1) return; + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'getAttributeGroups', + trait: 'EntitySelector' + }, + success: function(response) { + if (response.success && response.groups) { + $.each(response.groups, function(i, group) { + $select.append(''); + }); + } + } + }); + }, + + loadFeatureGroups: function() { + var self = this; + var $select = this.$dropdown.find('.filter-feature-group-select'); + + // Already loaded? + if ($select.find('option').length > 1) return; + + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'getFeatureGroups', + trait: 'EntitySelector' + }, + success: function(response) { + if (response.success && response.groups) { + $.each(response.groups, function(i, group) { + $select.append(''); + }); + } + } + }); + } + }; + +})(jQuery); diff --git a/sources/sources/js/admin/entity-selector/_tree.js b/sources/sources/js/admin/entity-selector/_tree.js new file mode 100644 index 0000000..5625eb8 --- /dev/null +++ b/sources/sources/js/admin/entity-selector/_tree.js @@ -0,0 +1,359 @@ +/** + * Entity Selector - Category Tree Module + * Hierarchical tree view for category selection inside the dropdown + * @partial _tree.js + * + * Features: + * - Expand/collapse individual nodes + * - Expand all / Collapse all + * - Select parent with all children button + * - Visual tree with indentation + * - Product count display + * - Search/filter within tree + */ + +(function($) { + 'use strict'; + + // Create mixin namespace + window._EntitySelectorMixins = window._EntitySelectorMixins || {}; + + // Tree mixin + window._EntitySelectorMixins.tree = { + + // Tree state + treeData: null, + treeFlatData: null, + + /** + * Load and display category tree in the dropdown + * Called when view mode is changed to "tree" + */ + loadCategoryTree: function() { + var self = this; + var $results = this.$dropdown.find('.dropdown-results'); + var trans = this.config.trans || {}; + var searchEntity = this.activeGroup ? this.activeGroup.searchEntity : 'categories'; + + // Show loading + $results.html('
    ' + this.esIcon('progress_activity', 'es-spin') + ' ' + + this.escapeHtml(trans.loading || 'Loading...') + '
    '); + + // Fetch tree data + $.ajax({ + url: this.config.ajaxUrl, + type: 'POST', + dataType: 'json', + data: { + ajax: 1, + action: 'getCategoryTree', + trait: 'EntitySelector', + entity_type: searchEntity + }, + success: function(response) { + if (response.success && response.categories && response.categories.length > 0) { + self.treeFlatData = response.categories; + self.treeData = self.buildTreeStructure(response.categories); + self.renderCategoryTree($results, searchEntity); + } else { + $results.html(''); + } + }, + error: function() { + $results.html(''); + } + }); + }, + + /** + * Build nested tree structure from flat array + * @param {Array} flatData - Flat array with parent_id references + * @returns {Array} Nested tree structure + */ + buildTreeStructure: function(flatData) { + var lookup = {}; + var tree = []; + + // Create lookup and initialize children arrays + flatData.forEach(function(item) { + lookup[item.id] = $.extend({}, item, { children: [] }); + }); + + // Build tree by assigning children to parents + flatData.forEach(function(item) { + var node = lookup[item.id]; + var parentId = parseInt(item.parent_id, 10); + + if (parentId && lookup[parentId]) { + lookup[parentId].children.push(node); + } else { + tree.push(node); + } + }); + + return tree; + }, + + /** + * Render the category tree inside dropdown results + * @param {jQuery} $container - The dropdown-results container + * @param {string} entityType - 'categories' or 'cms_categories' + */ + renderCategoryTree: function($container, entityType) { + var self = this; + var trans = this.config.trans || {}; + + // Get currently selected IDs from chips + var selectedIds = this.getSelectedIdsFromChips(); + + // Build tree HTML + var html = '
    '; + + // Tree toolbar + html += '
    '; + html += ''; + html += ''; + html += '
    '; + + // Tree items + html += '
    '; + html += this.renderTreeItems(this.treeData, 0, selectedIds); + html += '
    '; + + html += '
    '; + + $container.html(html); + + // Update count + var totalCount = this.treeFlatData ? this.treeFlatData.length : 0; + var selectedCount = selectedIds.length; + var categoryLabel = entityType === 'cms_categories' ? 'CMS categories' : 'categories'; + var countText = totalCount + ' ' + categoryLabel; + if (selectedCount > 0) { + countText += ' (' + selectedCount + ' selected)'; + } + this.$dropdown.find('.results-count').text(countText); + + // Update select children button states + this.updateSelectChildrenButtons(this.$dropdown.find('.tree-item')); + }, + + /** + * Render tree items recursively + * @param {Array} nodes - Tree nodes + * @param {number} level - Current depth level + * @param {Array} selectedIds - Currently selected IDs + * @returns {string} HTML string + */ + renderTreeItems: function(nodes, level, selectedIds) { + var self = this; + var html = ''; + var trans = this.config.trans || {}; + + nodes.forEach(function(node) { + var hasChildren = node.children && node.children.length > 0; + var isSelected = selectedIds.indexOf(parseInt(node.id, 10)) !== -1; + var indent = level * 20; + + var itemClass = 'tree-item'; + if (hasChildren) itemClass += ' has-children'; + if (isSelected) itemClass += ' selected'; + if (!node.active) itemClass += ' inactive'; + + html += '
    '; + + // Indentation + html += ''; + + // Toggle button (expand/collapse) + if (hasChildren) { + html += '' + self.esIcon('arrow_drop_down') + ''; + // Select with children button (next to toggle on the left) + html += ''; + } else { + html += ''; + } + + // Checkbox indicator + html += '' + this.esIcon('check') + ''; + + // Category icon + html += '' + this.esIcon('folder') + ''; + + // Name + html += '' + self.escapeHtml(node.name) + ''; + + // Product/page count with clickable preview + var itemCount = node.product_count || node.page_count || 0; + if (itemCount > 0) { + var countLabel = node.page_count ? (trans.pages || 'pages') : (trans.products || 'products'); + html += ''; + html += self.esIcon('visibility') + ' ' + itemCount; + html += ''; + } + + // Inactive badge + if (!node.active) { + html += '' + + self.escapeHtml(trans.inactive || 'Inactive') + ''; + } + + html += '
    '; + + // Render children + if (hasChildren) { + html += '
    '; + html += self.renderTreeItems(node.children, level + 1, selectedIds); + html += '
    '; + } + }); + + return html; + }, + + /** + * Get selected IDs from the current picker's chips + * @returns {Array} Array of selected IDs + */ + getSelectedIdsFromChips: function() { + var selectedIds = []; + + if (!this.activeGroup) return selectedIds; + + var $block = this.$wrapper.find('.target-block[data-block-type="' + this.activeGroup.blockType + '"]'); + var $group = $block.find('.selection-group[data-group-index="' + this.activeGroup.groupIndex + '"]'); + var $picker; + + if (this.activeGroup.section === 'include') { + $picker = $group.find('.include-picker'); + } else { + var $excludeRow = $group.find('.exclude-row[data-exclude-index="' + this.activeGroup.excludeIndex + '"]'); + $picker = $excludeRow.find('.exclude-picker'); + } + + $picker.find('.entity-chip').each(function() { + selectedIds.push(parseInt($(this).data('id'), 10)); + }); + + return selectedIds; + }, + + /** + * Filter category tree by search query + * @param {string} query - Search query + */ + filterCategoryTree: function(query) { + var $tree = this.$dropdown.find('.category-tree'); + if (!$tree.length) return; + + var $items = $tree.find('.tree-item'); + var $children = $tree.find('.tree-children'); + query = (query || '').toLowerCase().trim(); + + // Remove any inline display styles set by jQuery .toggle() + $items.css('display', ''); + + if (!query) { + $items.removeClass('filtered-out filter-match'); + $children.removeClass('filter-expanded'); + return; + } + + // Mark all as filtered out first + $items.addClass('filtered-out').removeClass('filter-match'); + + // Find matching items and show them with their parents + $items.each(function() { + var $item = $(this); + var name = ($item.data('name') || '').toLowerCase(); + + if (name.indexOf(query) !== -1) { + $item.removeClass('filtered-out'); + + // Show parent containers + $item.parents('.tree-children').addClass('filter-expanded'); + $item.parents('.tree-item').removeClass('filtered-out'); + + // Show children of matching item + $item.next('.tree-children').find('.tree-item').removeClass('filtered-out'); + $item.next('.tree-children').addClass('filter-expanded'); + } + }); + }, + + /** + * Find all descendant tree items of a given item + * @param {jQuery} $item - Parent tree item + * @param {jQuery} $allItems - All tree items (for performance) + * @returns {Array} Array of descendant jQuery elements + */ + findTreeDescendants: function($item, $allItems) { + var descendants = []; + var parentId = parseInt($item.data('id'), 10); + var level = parseInt($item.data('level'), 10); + + // Find immediate children first + var $next = $item.next('.tree-children'); + if ($next.length) { + $next.find('.tree-item').each(function() { + descendants.push(this); + }); + } + + return descendants; + }, + + /** + * Update the state of select-children buttons based on selection + * @param {jQuery} $allItems - All tree items + */ + updateSelectChildrenButtons: function($allItems) { + var self = this; + var trans = this.config.trans || {}; + + $allItems.filter('.has-children').each(function() { + var $item = $(this); + var $btn = $item.find('.btn-select-children'); + if (!$btn.length) return; + + var $children = $item.next('.tree-children'); + if (!$children.length) return; + + var $childItems = $children.find('.tree-item'); + var isParentSelected = $item.hasClass('selected'); + var allChildrenSelected = true; + + $childItems.each(function() { + if (!$(this).hasClass('selected')) { + allChildrenSelected = false; + return false; + } + }); + + if (isParentSelected && allChildrenSelected) { + $btn.find('i').replaceWith(self.esIcon('indeterminate_check_box')); + $btn.attr('title', trans.deselect_with_children || 'Deselect with all children'); + } else { + $btn.find('i').replaceWith(self.esIcon('add_box')); + $btn.attr('title', trans.select_with_children || 'Select with all children'); + } + }); + } + }; + +})(jQuery); diff --git a/sources/sources/js/admin/entity-selector/_utils.js b/sources/sources/js/admin/entity-selector/_utils.js new file mode 100644 index 0000000..1713e7a --- /dev/null +++ b/sources/sources/js/admin/entity-selector/_utils.js @@ -0,0 +1,407 @@ +/** + * Entity Selector - Utilities Module + * Helper functions: escape, validation, icons, search history + * @partial _utils.js (must be loaded first) + * + * EXTRACTION SOURCE: assets/js/admin/entity-selector.js + * Lines: 7552-7570 (escapeHtml, escapeAttr) + * 7577-7590 (getEntityTypeLabel) + * 6289-6350 (validate, showValidationError, clearValidationError) + * 7115-7137 (showRangeInputError) + * 7728-7745 (getBlockMode, isBlockSingleMode) + * 7707-7723 (getCurrentSingleSelection) + * 5411-5467 (search history methods) + */ + +(function($) { + 'use strict'; + + // Create mixin namespace + window._EntitySelectorMixins = window._EntitySelectorMixins || {}; + + // --------------------------------------------------------------- + // Icon framework detection & FA4 mapping (module-level singleton) + // --------------------------------------------------------------- + var _iconMode = null; + + /** + * Material Icons → FontAwesome 4 class mapping. + * FA4 uses class-based icons (icon-name), Material uses text content. + */ + var FA4_MAP = { + 'account_tree': 'icon-sitemap', + 'add': 'icon-plus', + 'add_box': 'icon-plus-square', + 'arrow_downward': 'icon-sort-desc', + 'arrow_drop_down': 'icon-caret-down', + 'arrow_right': 'icon-chevron-right', + 'arrow_upward': 'icon-sort-asc', + 'block': 'icon-ban', + 'brush': 'icon-paint-brush', + 'business': 'icon-building', + 'check': 'icon-check', + 'check_box': 'icon-check-square', + 'check_box_outline_blank': 'icon-square-o', + 'check_circle': 'icon-check-circle', + 'close': 'icon-times', + 'delete': 'icon-trash', + 'description': 'icon-file-text', + 'error': 'icon-exclamation-circle', + 'event': 'icon-calendar', + 'event_busy': 'icon-calendar-times-o', + 'expand_less': 'icon-chevron-up', + 'expand_more': 'icon-chevron-down', + 'filter_list': 'icon-filter', + 'flag': 'icon-flag', + 'folder': 'icon-folder', + 'folder_open': 'icon-folder-open', + 'indeterminate_check_box': 'icon-minus-square', + 'info': 'icon-info-circle', + 'inventory_2': 'icon-archive', + 'label': 'icon-tag', + 'language': 'icon-globe', + 'lightbulb': 'icon-lightbulb-o', + 'list': 'icon-list', + 'list_alt': 'icon-list-alt', + 'local_shipping': 'icon-truck', + 'lock': 'icon-lock', + 'my_location': 'icon-crosshairs', + 'open_in_full': 'icon-expand', + 'payments': 'icon-credit-card', + 'progress_activity': 'icon-circle-o-notch', + 'schedule': 'icon-clock-o', + 'search': 'icon-search', + 'shopping_cart': 'icon-shopping-cart', + 'shuffle': 'icon-random', + 'sort': 'icon-sort', + 'sort_by_alpha': 'icon-sort-alpha-asc', + 'star': 'icon-star', + 'sync': 'icon-refresh', + 'tune': 'icon-sliders', + 'visibility': 'icon-eye', + 'warning': 'icon-warning', + 'widgets': 'icon-th-large' + }; + + /** + * Reverse map: FontAwesome 4 class → Material Icons name. + * Built once lazily from FA4_MAP + extra mappings for FA4 names + * that don't appear as values in FA4_MAP. + */ + var _REVERSE_FA4_MAP = null; + + var EXTRA_REVERSE_MAPPINGS = { + 'icon-cube': 'inventory', + 'icon-folder-o': 'folder', + 'icon-file-text-o': 'description', + 'icon-briefcase': 'work', + 'icon-user': 'person', + 'icon-users': 'group', + 'icon-money': 'payments', + 'icon-tasks': 'checklist', + 'icon-calculator': 'calculate', + 'icon-asterisk': 'star', + 'icon-bar-chart': 'bar_chart', + 'icon-cogs': 'settings', + 'icon-cog': 'settings', + 'icon-tags': 'label', + 'icon-list-ul': 'list', + 'icon-th': 'grid_view', + 'icon-certificate': 'verified', + 'icon-power-off': 'power_settings_new', + 'icon-circle-o': 'radio_button_unchecked' + }; + + function getReverseFa4Map() { + if (_REVERSE_FA4_MAP !== null) return _REVERSE_FA4_MAP; + _REVERSE_FA4_MAP = {}; + // Invert FA4_MAP: value → key + for (var material in FA4_MAP) { + if (FA4_MAP.hasOwnProperty(material)) { + var fa4Class = FA4_MAP[material]; + if (!_REVERSE_FA4_MAP[fa4Class]) { + _REVERSE_FA4_MAP[fa4Class] = material; + } + } + } + // Merge extras + for (var fa4 in EXTRA_REVERSE_MAPPINGS) { + if (EXTRA_REVERSE_MAPPINGS.hasOwnProperty(fa4) && !_REVERSE_FA4_MAP[fa4]) { + _REVERSE_FA4_MAP[fa4] = EXTRA_REVERSE_MAPPINGS[fa4]; + } + } + return _REVERSE_FA4_MAP; + } + + /** + * Normalize an icon name — handles both Material and FA4 class names. + * @param {string} name - Icon name (Material or FA4 format) + * @param {string} mode - 'material' or 'fa4' + * @returns {object} { name: string, extra: string, rawFa4: boolean } + */ + function normalizeIconName(name, mode) { + var extra = ''; + var rawFa4 = false; + + if (name.indexOf('icon-') === 0) { + // FA4 class name input — may have extra classes (e.g. "icon-power-off text-success") + var spaceIdx = name.indexOf(' '); + var fa4Class = (spaceIdx !== -1) ? name.substring(0, spaceIdx) : name; + if (spaceIdx !== -1) extra = name.substring(spaceIdx + 1); + + if (mode === 'material') { + var reverseMap = getReverseFa4Map(); + var materialName = reverseMap[fa4Class]; + if (materialName) { + return { name: materialName, extra: extra, rawFa4: false }; + } + // Fallback: strip 'icon-' and convert hyphens to underscores + var fallback = fa4Class.substring(5).replace(/-/g, '_'); + return { name: fallback, extra: extra, rawFa4: false }; + } + + // FA4 mode + FA4 input — use as-is + return { name: fa4Class, extra: extra, rawFa4: true }; + } + + // Material Icons name — pass through + return { name: name, extra: extra, rawFa4: false }; + } + + /** + * Detect icon framework: 'material' (PS 8+/9+) or 'fa4' (PS 1.6/1.7). + * Checks PHP-set data attribute first, falls back to font detection. + */ + function detectIconMode() { + if (_iconMode !== null) return _iconMode; + + // 1. PHP sets data-icon-mode on the wrapper + var $w = $('.entity-selector-trait[data-icon-mode], .target-conditions-trait[data-icon-mode]').first(); + if ($w.length && $w.data('icon-mode')) { + _iconMode = $w.data('icon-mode'); + return _iconMode; + } + + // 2. Fallback: probe whether Material Icons font is loaded + var test = document.createElement('i'); + test.className = 'material-icons'; + test.style.cssText = 'position:absolute;left:-9999px;top:-9999px;font-size:16px;pointer-events:none'; + test.textContent = 'check'; + (document.body || document.documentElement).appendChild(test); + var family = (window.getComputedStyle(test).fontFamily || '').toLowerCase(); + test.parentNode.removeChild(test); + + _iconMode = (family.indexOf('material') !== -1) ? 'material' : 'fa4'; + return _iconMode; + } + + // Utility functions mixin + window._EntitySelectorMixins.utils = { + + /** + * Debounce function - delays execution until after wait milliseconds + * @param {Function} func - Function to debounce + * @param {number} wait - Milliseconds to wait + * @returns {Function} Debounced function + */ + debounce: function(func, wait) { + var timeout; + return function() { + var context = this; + var args = arguments; + clearTimeout(timeout); + timeout = setTimeout(function() { + func.apply(context, args); + }, wait); + }; + }, + + escapeHtml: function(str) { + if (str === null || str === undefined) return ''; + return String(str) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); + }, + + escapeAttr: function(str) { + if (str === null || str === undefined) return ''; + return String(str) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); + }, + + /** + * Icon helper — returns HTML for an icon that works on PS 1.6 through 9.x. + * Accepts both Material Icons names and FA4 class names as input. + * Automatically uses Material Icons (PS 8+/9+) or FontAwesome 4 (PS 1.6/1.7). + * + * @param {string} name - Icon name (Material or FA4 format, e.g. 'search', 'icon-cube') + * @param {string} [extraClass] - Additional CSS class(es) (e.g. 'es-spin', 'method-trigger-icon') + * @returns {string} HTML string for an element + */ + esIcon: function(name, extraClass) { + var mode = detectIconMode(); + var normalized = normalizeIconName(name, mode); + var iconName = normalized.name; + // Merge extra classes from normalization + if (normalized.extra) { + extraClass = extraClass ? extraClass + ' ' + normalized.extra : normalized.extra; + } + + if (mode === 'material') { + var cls = 'material-icons es-icon'; + if (extraClass) cls += ' ' + extraClass; + return '' + iconName + ''; + } + // FA4 mode + if (normalized.rawFa4) { + // Input was already an FA4 class — use directly + var cls = iconName + ' es-icon'; + } else { + // Input was Material — map to FA4 + var cls = (FA4_MAP[iconName] || 'icon-circle') + ' es-icon'; + } + if (extraClass) cls += ' ' + extraClass; + return ''; + }, + + /** + * Update an existing icon element to show a different icon. + * Handles both Material Icons and FA4 modes. + * Accepts both Material Icons names and FA4 class names as input. + * + * @param {jQuery} $el - The element to update + * @param {string} name - Icon name (Material or FA4 format) + * @param {string} [extraClass] - Additional CSS class(es) to preserve + */ + esIconUpdate: function($el, name, extraClass) { + var mode = detectIconMode(); + var normalized = normalizeIconName(name, mode); + var iconName = normalized.name; + if (normalized.extra) { + extraClass = extraClass ? extraClass + ' ' + normalized.extra : normalized.extra; + } + + if (mode === 'material') { + var cls = 'material-icons es-icon'; + if (extraClass) cls += ' ' + extraClass; + $el.attr('class', cls).text(iconName); + } else { + if (normalized.rawFa4) { + var cls = iconName + ' es-icon'; + } else { + var cls = (FA4_MAP[iconName] || 'icon-circle') + ' es-icon'; + } + if (extraClass) cls += ' ' + extraClass; + $el.attr('class', cls).text(''); + } + }, + + getEntityTypeIcon: function(entityType) { + var icons = { + 'products': 'shopping_cart', + 'categories': 'folder_open', + 'manufacturers': 'business', + 'suppliers': 'local_shipping', + 'attributes': 'list_alt', + 'features': 'label', + 'cms': 'description', + 'cms_categories': 'folder' + }; + return icons[entityType] || 'widgets'; + }, + + getEntityTypeLabel: function(entityType) { + var trans = this.config.trans || {}; + var labels = { + 'products': trans.product || 'Product', + 'categories': trans.category || 'Category', + 'manufacturers': trans.manufacturer || 'Manufacturer', + 'suppliers': trans.supplier || 'Supplier', + 'attributes': trans.attribute || 'Attribute', + 'features': trans.feature || 'Feature', + 'cms': trans.cms_page || 'CMS Page', + 'cms_categories': trans.cms_category || 'CMS Category' + }; + return labels[entityType] || entityType; + }, + + validate: function() { + var isRequired = this.$wrapper.data('required') === 1 || this.$wrapper.data('required') === '1'; + if (!isRequired) return true; + + var hasData = false; + this.$wrapper.find('.target-block').each(function() { + if ($(this).find('.selection-group').length > 0) { + hasData = true; + return false; + } + }); + + if (!hasData) { + this.showValidationError(); + return false; + } + + this.clearValidationError(); + return true; + }, + + showValidationError: function() { + this.$wrapper.addClass('has-validation-error'); + var message = this.$wrapper.data('required-message') || 'Please select at least one item'; + this.$wrapper.find('.trait-validation-error').remove(); + var $error = $('
    ', { + class: 'trait-validation-error', + html: this.esIcon('warning') + ' ' + message + }); + this.$wrapper.find('.condition-trait-header').after($error); + $('html, body').animate({ scrollTop: this.$wrapper.offset().top - 100 }, 300); + if (!this.$wrapper.find('.condition-trait-body').is(':visible')) { + this.$wrapper.find('.condition-trait-body').slideDown(200); + this.$wrapper.removeClass('collapsed'); + } + }, + + clearValidationError: function() { + this.$wrapper.removeClass('has-validation-error'); + this.$wrapper.find('.trait-validation-error').remove(); + }, + + getBlockMode: function(blockType) { + var blockDef = this.config.blocks[blockType]; + return (blockDef && blockDef.mode) ? blockDef.mode : 'multi'; + }, + + isBlockSingleMode: function(blockType) { + return this.getBlockMode(blockType) === 'single'; + }, + + getCurrentSingleSelection: function() { + if ((this.config.mode || 'multi') !== 'single') return null; + var $chip = this.$wrapper.find('.entity-chips .entity-chip').first(); + if ($chip.length) { + var $block = $chip.closest('.target-block'); + return { + name: $chip.find('.chip-name').text() || $chip.data('id'), + entityType: $block.data('block-type') || 'item' + }; + } + return null; + }, + + /** + * Check if entity type supports tree browsing + */ + supportsTreeBrowsing: function(entityType) { + return entityType === 'categories' || entityType === 'cms_categories'; + } + }; + +})(jQuery); diff --git a/sources/sources/js/admin/entity-selector/_validation.js b/sources/sources/js/admin/entity-selector/_validation.js new file mode 100644 index 0000000..089a57b --- /dev/null +++ b/sources/sources/js/admin/entity-selector/_validation.js @@ -0,0 +1,365 @@ +/** + * Entity Selector - Validation Module + * Conflict detection and prevention for entity selections + * @partial _validation.js + * + * Features: + * - Same entity in include & exclude detection + * - Parent-child conflict detection for tree entities + * - Redundant selection detection + * - Error message display + */ + +(function($) { + 'use strict'; + + window._EntitySelectorMixins = window._EntitySelectorMixins || {}; + + window._EntitySelectorMixins.validation = { + + /** + * Validate a selection before adding it + * Returns { valid: true } or { valid: false, error: 'message', type: 'conflict_type' } + * + * @param {number|string} id - Entity ID to validate + * @param {string} name - Entity name (for error messages) + * @param {string} section - 'include' or 'exclude' + * @param {Object} data - Additional data (parent_id, etc.) + * @returns {Object} Validation result + */ + validateSelection: function(id, name, section, data) { + if (!this.activeGroup) { + return { valid: true }; + } + + var trans = this.config.trans || {}; + id = parseInt(id, 10); + + var $block = this.$wrapper.find('.target-block[data-block-type="' + this.activeGroup.blockType + '"]'); + var $group = $block.find('.selection-group[data-group-index="' + this.activeGroup.groupIndex + '"]'); + + // Get include chips + var includeIds = this.getChipIds($group.find('.include-picker')); + + // Get all exclude chips (from all exclude rows) + var excludeIds = []; + $group.find('.exclude-row').each(function() { + var $excludePicker = $(this).find('.exclude-picker'); + var ids = []; + $excludePicker.find('.entity-chip').each(function() { + ids.push(parseInt($(this).data('id'), 10)); + }); + excludeIds = excludeIds.concat(ids); + }); + + // 1. Check for same entity in include & exclude + var conflictResult = this.checkIncludeExcludeConflict(id, name, section, includeIds, excludeIds, trans); + if (!conflictResult.valid) { + return conflictResult; + } + + // 2. Check for redundant selection (already selected in same section) + var redundantResult = this.checkRedundantSelection(id, name, section, includeIds, excludeIds, trans); + if (!redundantResult.valid) { + return redundantResult; + } + + // 3. Check for parent-child conflicts (only for tree entities) + var searchEntity = this.activeGroup.searchEntity; + if (searchEntity === 'categories' || searchEntity === 'cms_categories') { + var treeResult = this.checkTreeConflicts(id, name, section, data, includeIds, excludeIds, trans); + if (!treeResult.valid) { + return treeResult; + } + } + + return { valid: true }; + }, + + /** + * Check if entity is in both include and exclude + */ + checkIncludeExcludeConflict: function(id, name, section, includeIds, excludeIds, trans) { + if (section === 'include' && excludeIds.indexOf(id) !== -1) { + return { + valid: false, + type: 'include_exclude_conflict', + error: (trans.error_in_exclude || '"{name}" is already in the exclude list. Remove it from exclude first.').replace('{name}', name) + }; + } + + if (section === 'exclude' && includeIds.indexOf(id) !== -1) { + return { + valid: false, + type: 'include_exclude_conflict', + error: (trans.error_in_include || '"{name}" is already in the include list. Remove it from include first.').replace('{name}', name) + }; + } + + return { valid: true }; + }, + + /** + * Check for redundant selection (already selected) + */ + checkRedundantSelection: function(id, name, section, includeIds, excludeIds, trans) { + if (section === 'include' && includeIds.indexOf(id) !== -1) { + return { + valid: false, + type: 'redundant', + error: (trans.error_already_selected || '"{name}" is already selected.').replace('{name}', name) + }; + } + + if (section === 'exclude' && excludeIds.indexOf(id) !== -1) { + return { + valid: false, + type: 'redundant', + error: (trans.error_already_excluded || '"{name}" is already in an exclude list.').replace('{name}', name) + }; + } + + return { valid: true }; + }, + + /** + * Check for parent-child conflicts in tree entities + */ + checkTreeConflicts: function(id, name, section, data, includeIds, excludeIds, trans) { + // Need tree data for parent-child lookups + if (!this.treeFlatData) { + return { valid: true }; + } + + var parentId = data && data.parentId ? parseInt(data.parentId, 10) : null; + + // Build lookup for quick access + var lookup = {}; + this.treeFlatData.forEach(function(item) { + lookup[parseInt(item.id, 10)] = item; + }); + + // Get all ancestor IDs + var ancestorIds = this.getAncestorIds(id, lookup); + + // Get all descendant IDs + var descendantIds = this.getDescendantIds(id, lookup); + + if (section === 'include') { + // Check if any ancestor is excluded + for (var i = 0; i < ancestorIds.length; i++) { + if (excludeIds.indexOf(ancestorIds[i]) !== -1) { + var ancestorName = lookup[ancestorIds[i]] ? lookup[ancestorIds[i]].name : 'Parent'; + return { + valid: false, + type: 'parent_excluded', + error: (trans.error_parent_excluded || 'Cannot include "{name}" because its parent "{parent}" is excluded.').replace('{name}', name).replace('{parent}', ancestorName) + }; + } + } + + // Check if any descendant is excluded + for (var j = 0; j < descendantIds.length; j++) { + if (excludeIds.indexOf(descendantIds[j]) !== -1) { + var descendantName = lookup[descendantIds[j]] ? lookup[descendantIds[j]].name : 'Child'; + return { + valid: false, + type: 'child_excluded', + error: (trans.error_child_excluded || 'Cannot include "{name}" because its child "{child}" is excluded. Remove the child from exclude first.').replace('{name}', name).replace('{child}', descendantName) + }; + } + } + } + + if (section === 'exclude') { + // Check if any ancestor is included + for (var k = 0; k < ancestorIds.length; k++) { + if (includeIds.indexOf(ancestorIds[k]) !== -1) { + var parentName = lookup[ancestorIds[k]] ? lookup[ancestorIds[k]].name : 'Parent'; + return { + valid: false, + type: 'parent_included', + error: (trans.error_parent_included || 'Cannot exclude "{name}" because its parent "{parent}" is included. This would create a contradiction.').replace('{name}', name).replace('{parent}', parentName) + }; + } + } + + // Check if any descendant is included (warning about implicit exclusion) + var includedDescendants = []; + for (var m = 0; m < descendantIds.length; m++) { + if (includeIds.indexOf(descendantIds[m]) !== -1) { + var childName = lookup[descendantIds[m]] ? lookup[descendantIds[m]].name : 'Child'; + includedDescendants.push(childName); + } + } + + if (includedDescendants.length > 0) { + return { + valid: false, + type: 'children_included', + error: (trans.error_children_included || 'Cannot exclude "{name}" because its children ({children}) are included. Remove them from include first.').replace('{name}', name).replace('{children}', includedDescendants.slice(0, 3).join(', ') + (includedDescendants.length > 3 ? '...' : '')) + }; + } + } + + return { valid: true }; + }, + + /** + * Get all ancestor IDs for a given item + */ + getAncestorIds: function(id, lookup) { + var ancestors = []; + var current = lookup[id]; + + while (current && current.parent_id) { + var parentId = parseInt(current.parent_id, 10); + if (parentId && lookup[parentId]) { + ancestors.push(parentId); + current = lookup[parentId]; + } else { + break; + } + } + + return ancestors; + }, + + /** + * Get all descendant IDs for a given item + */ + getDescendantIds: function(id, lookup) { + var descendants = []; + var self = this; + + // Find direct children + Object.keys(lookup).forEach(function(key) { + var item = lookup[key]; + if (parseInt(item.parent_id, 10) === id) { + var childId = parseInt(item.id, 10); + descendants.push(childId); + // Recursively get children's descendants + var childDescendants = self.getDescendantIds(childId, lookup); + descendants = descendants.concat(childDescendants); + } + }); + + return descendants; + }, + + /** + * Get chip IDs from a picker + */ + getChipIds: function($picker) { + var ids = []; + $picker.find('.entity-chip').each(function() { + ids.push(parseInt($(this).data('id'), 10)); + }); + return ids; + }, + + /** + * Validate pending selections (for tree view bulk operations) + * Returns array of invalid items + */ + validatePendingSelections: function(pendingSelections, section) { + var self = this; + var errors = []; + + if (!pendingSelections || !pendingSelections.length) { + return errors; + } + + pendingSelections.forEach(function(sel) { + var result = self.validateSelection(sel.id, sel.name, section, sel.data || {}); + if (!result.valid) { + errors.push({ + id: sel.id, + name: sel.name, + error: result.error, + type: result.type + }); + } + }); + + return errors; + }, + + /** + * Show validation error toast + */ + showValidationError: function(message) { + var trans = this.config.trans || {}; + var title = trans.validation_error || 'Selection Conflict'; + + // Remove existing toast + $('.es-validation-toast').remove(); + + // Create toast HTML + var html = '
    '; + html += '
    ' + this.esIcon('warning') + '
    '; + html += '
    '; + html += '
    ' + this.escapeHtml(title) + '
    '; + html += '
    ' + this.escapeHtml(message) + '
    '; + html += '
    '; + html += ''; + html += '
    '; + + var $toast = $(html); + $('body').append($toast); + + // Position near dropdown if visible + if (this.$dropdown && this.$dropdown.hasClass('show')) { + var dropdownOffset = this.$dropdown.offset(); + $toast.css({ + position: 'fixed', + top: dropdownOffset.top - $toast.outerHeight() - 10, + left: dropdownOffset.left, + zIndex: 10001 + }); + } else { + $toast.css({ + position: 'fixed', + top: 20, + right: 20, + zIndex: 10001 + }); + } + + // Animate in + $toast.hide().fadeIn(200); + + // Auto-dismiss after 5 seconds + setTimeout(function() { + $toast.fadeOut(200, function() { + $(this).remove(); + }); + }, 5000); + + // Close button + $toast.on('click', '.es-toast-close', function() { + $toast.fadeOut(200, function() { + $(this).remove(); + }); + }); + }, + + /** + * Validate and add selection (wrapper that validates before adding) + * Returns true if added successfully, false if validation failed + */ + validateAndAddSelection: function($picker, id, name, data, section) { + var result = this.validateSelection(id, name, section, data || {}); + + if (!result.valid) { + this.showValidationError(result.error); + return false; + } + + // Validation passed, add the selection + this.addSelection($picker, id, name, data); + return true; + } + }; + +})(jQuery); diff --git a/sources/sources/js/admin/entity-selector/index.php b/sources/sources/js/admin/entity-selector/index.php new file mode 100644 index 0000000..c4f371f --- /dev/null +++ b/sources/sources/js/admin/entity-selector/index.php @@ -0,0 +1 @@ +visibility
    +@mixin count-badge($bg: $es-primary) { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.25rem; + min-width: 20px; + height: 20px; + padding: 0 0.5rem; + background: $bg; + color: $es-white; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-semibold; + border-radius: $es-radius-full; + cursor: pointer; + transition: all $es-transition-fast; + flex-shrink: 0; + + &:hover { + transform: scale(1.05); + box-shadow: 0 2px 8px rgba($bg, 0.4); + } + + // Focus state - maintain styled appearance + &:focus { + outline: none; + box-shadow: 0 0 0 2px rgba($bg, 0.3), 0 2px 8px rgba($bg, 0.4); + } + + // Loading state - spinner icon replaces eye + &.loading { + cursor: wait; + + i { + font-size: 10px; + animation: spin 0.6s linear infinite; + } + + &:hover { + transform: none; + box-shadow: none; + } + } + + // Inactive/empty state + &.inactive, + &.no-matches { + background: $es-slate-400; + cursor: default; + + &:hover { + transform: none; + box-shadow: none; + } + } + + // Popover open state + &.popover-open { + background: color.adjust($bg, $lightness: -10%); + box-shadow: 0 2px 8px rgba($bg, 0.4); + } + + // Icon inside badge (eye, spinner, etc.) + i { + font-size: 10px; + line-height: 1; + opacity: 0.8; + } + + &:hover i { + opacity: 1; + } + + .preview-count { + font-weight: $es-font-weight-bold; + } +} + +@keyframes spin { + from { transform: rotate(0deg); } + to { transform: rotate(360deg); } +} + +@keyframes spin-pulse { + 0% { transform: rotate(0deg); opacity: 1; } + 50% { opacity: 0.4; } + 100% { transform: rotate(360deg); opacity: 1; } +} + +// Global spin utility classes (Material Icons replacement for icon-spin / icon-spin-pulse) +.es-spin { + animation: spin 1s linear infinite; +} + +.es-spin-pulse { + animation: spin-pulse 1s ease-in-out infinite; +} + +@mixin chip { + display: inline-flex; + align-items: center; + gap: $es-spacing-xs; + padding: $es-spacing-xs $es-spacing-sm; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + background: $es-gray-200; + color: $es-gray-700; + border-radius: $es-radius-full; + + .chip-remove { + @include button-reset; + @include flex-center; + width: 14px; + height: 14px; + font-size: 10px; + color: $es-text-muted; + border-radius: 50%; + + &:hover { + background: rgba(0, 0, 0, 0.1); + color: $es-danger; + } + } +} + +// ============================================================================= +// Toggle Switch +// ============================================================================= + +@mixin toggle-switch($width: 36px, $height: 20px) { + position: relative; + width: $width; + height: $height; + border-radius: $height; + background: $es-gray-400; + transition: background-color $es-transition-normal; + cursor: pointer; + + &::after { + content: ''; + position: absolute; + top: 2px; + left: 2px; + width: $height - 4px; + height: $height - 4px; + background: $es-white; + border-radius: 50%; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); + transition: transform $es-transition-normal; + } + + &.active { + background: $es-success; + + &::after { + transform: translateX($width - $height); + } + } +} + +// ============================================================================= +// Screen Reader Only +// ============================================================================= + +@mixin sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} diff --git a/sources/sources/scss/_variables.scss b/sources/sources/scss/_variables.scss new file mode 100644 index 0000000..26b9598 --- /dev/null +++ b/sources/sources/scss/_variables.scss @@ -0,0 +1,154 @@ +/** + * Entity Selector Variables + * Bootstrap 4 compatible values for PrestaShop admin theme + * + * Imports shared variables from prestashop-admin package + * and maps them to $es-* prefixed aliases for this package + */ + +// Import shared variables from prestashop-admin +@use '../../../prestashop-admin/assets/scss/variables' as admin; + +// ============================================================================= +// Base Colors +// ============================================================================= + +$es-white: #ffffff !default; +$es-black: #000000 !default; + +// Primary (from prestashop-admin) +$es-primary: admin.$primary !default; +$es-primary-hover: #1a9ab7 !default; +$es-primary-light: rgba(37, 185, 215, 0.1) !default; + +// Semantic colors (from prestashop-admin) +$es-success: admin.$success !default; +$es-success-light: #d4edda !default; +$es-success-dark: #1e7e34 !default; + +$es-danger: admin.$danger !default; +$es-danger-light: #f8d7da !default; +$es-danger-dark: #bd2130 !default; + +$es-warning: admin.$warning !default; +$es-warning-light: #fff3cd !default; + +$es-info: admin.$info !default; +$es-info-light: #d1ecf1 !default; + +// ============================================================================= +// Gray Scale (Bootstrap 4) +// ============================================================================= + +$es-gray-100: admin.$light !default; +$es-gray-200: #e9ecef !default; +$es-gray-300: admin.$border-color !default; +$es-gray-400: #ced4da !default; +$es-gray-500: #adb5bd !default; +$es-gray-600: admin.$secondary !default; +$es-gray-700: #495057 !default; +$es-gray-800: admin.$dark !default; +$es-gray-900: #212529 !default; + +// Slate (subtle variations) +$es-slate-50: #f8fafc !default; +$es-slate-100: #f1f5f9 !default; +$es-slate-200: #e2e8f0 !default; +$es-slate-300: #cbd5e1 !default; +$es-slate-400: #94a3b8 !default; +$es-slate-500: #64748b !default; +$es-slate-600: #475569 !default; +$es-slate-700: #334155 !default; +$es-slate-800: #1e293b !default; +$es-slate-900: #0f172a !default; + +// Cyan +$es-cyan-50: #ecfeff !default; +$es-cyan-100: #cffafe !default; +$es-cyan-200: #a5f3fc !default; +$es-cyan-500: #06b6d4 !default; +$es-cyan-600: #0891b2 !default; +$es-cyan-700: #0e7490 !default; + +// ============================================================================= +// Semantic Aliases +// ============================================================================= + +$es-bg-header: $es-gray-100 !default; +$es-bg-hover: $es-gray-200 !default; +$es-bg-active: $es-gray-200 !default; +$es-bg-body: $es-white !default; + +$es-border-color: admin.$border-color !default; +$es-border-light: $es-gray-200 !default; +$es-border-dark: $es-gray-400 !default; + +$es-text-primary: $es-gray-900 !default; +$es-text-secondary: $es-gray-700 !default; +$es-text-muted: $es-gray-600 !default; +$es-text-light: $es-gray-500 !default; + +// ============================================================================= +// Spacing (Bootstrap 4 compatible, derived from admin.$spacer) +// ============================================================================= + +$es-spacing-xs: admin.$spacer * 0.25 !default; // 4px +$es-spacing-sm: admin.$spacer * 0.5 !default; // 8px +$es-spacing-md: admin.$spacer !default; // 16px +$es-spacing-lg: admin.$spacer * 1.5 !default; // 24px +$es-spacing-xl: admin.$spacer * 2 !default; // 32px + +// ============================================================================= +// Border Radius (from prestashop-admin) +// ============================================================================= + +$es-radius-sm: admin.$border-radius-sm !default; +$es-radius-md: admin.$border-radius !default; +$es-radius-lg: admin.$border-radius-lg !default; +$es-radius-xl: 0.5rem !default; +$es-radius-full: 50rem !default; + +// ============================================================================= +// Box Shadows (Bootstrap 4 compatible) +// ============================================================================= + +$es-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) !default; +$es-shadow-md: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !default; +$es-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175) !default; +$es-shadow-xl: 0 1.5rem 4rem rgba(0, 0, 0, 0.2) !default; + +// ============================================================================= +// Transitions +// ============================================================================= + +$es-transition-fast: 0.15s ease-in-out !default; +$es-transition-normal: 0.2s ease-in-out !default; +$es-transition-slow: 0.3s ease-in-out !default; + +// ============================================================================= +// Z-Index (below Bootstrap modal) +// ============================================================================= + +$es-z-dropdown: 1000 !default; +$es-z-modal: 1050 !default; +$es-z-popover: 1060 !default; +$es-z-tooltip: 1070 !default; + +// ============================================================================= +// Typography +// ============================================================================= + +$es-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !default; + +$es-font-size-xs: 0.75rem !default; // 12px +$es-font-size-sm: 0.875rem !default; // 14px +$es-font-size-base: 1rem !default; // 16px +$es-font-size-lg: 1.125rem !default; // 18px + +$es-font-weight-normal: 400 !default; +$es-font-weight-medium: 500 !default; +$es-font-weight-semibold: 600 !default; +$es-font-weight-bold: 700 !default; + +$es-line-height-tight: 1.25 !default; +$es-line-height-normal: 1.5 !default; diff --git a/sources/sources/scss/components/_chips.scss b/sources/sources/scss/components/_chips.scss new file mode 100644 index 0000000..835bec6 --- /dev/null +++ b/sources/sources/scss/components/_chips.scss @@ -0,0 +1,1071 @@ +/** + * Chips Component + * Entity chips, selection pills, tags + */ + +@use "sass:color"; +@use '../variables' as *; +@use '../mixins' as *; + +.target-conditions-trait, +.entity-selector-trait { + + // Chips container wrapper with toolbar + .chips-wrapper { + display: flex; + flex-direction: column; + margin-top: $es-spacing-sm; + background: $es-slate-50; + border: 1px solid $es-border-color; + border-radius: $es-radius-md; + overflow: hidden; + } + + // Chips toolbar - integrated filter bar inside chips area + .chips-toolbar { + display: none; + align-items: center; + flex-wrap: nowrap; + gap: $es-spacing-sm; + padding: $es-spacing-sm $es-spacing-md; + padding-bottom: 0; + background: transparent; + + &.has-chips { + display: flex; + } + + // Filter input - takes available space, icon embedded as background + // Using [type="text"] for specificity over .bootstrap input[type="text"] + input[type="text"].chips-search-input { + all: unset; + display: block; + flex: 1 1 auto; + min-width: 80px; + width: auto; + height: auto; + padding: 0.2rem 0.5rem 0.2rem 1.5rem; + background: $es-white url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.35-4.35'/%3E%3C/svg%3E") no-repeat 0.375rem center; + background-size: 10px; + border: 1px solid $es-slate-300; + border-radius: $es-radius-sm; + font-size: 11px; + line-height: 1.4; + color: $es-text-primary; + box-sizing: border-box; + transition: all $es-transition-fast; + + &::placeholder { + color: $es-text-muted; + font-size: 11px; + } + + &:focus { + outline: none; + border-color: $es-primary; + box-shadow: 0 0 0 2px rgba($es-primary, 0.1); + } + } + + // Sort dropdown - compact, auto width + select.chips-sort-select { + all: unset; + flex: 0 0 auto; + padding: 0.2rem 1.25rem 0.2rem 0.5rem; + border: 1px solid $es-border-color; + border-radius: $es-radius-sm; + 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.375rem center; + background-size: 8px; + font-size: 10px; + line-height: 1.4; + color: $es-text-secondary; + cursor: pointer; + box-sizing: border-box; + white-space: nowrap; + + &:hover { + border-color: $es-primary; + } + + &:focus { + outline: none; + border-color: $es-primary; + box-shadow: 0 0 0 2px rgba($es-primary, 0.1); + } + } + } + + // Count badge - smaller, pill style + .chips-count { + display: inline-flex; + align-items: center; + flex-shrink: 0; // Don't shrink + gap: 0.125rem; + padding: 0.2rem 0.5rem; + background: $es-slate-200; + color: $es-text-secondary; + font-size: 10px; + font-weight: $es-font-weight-semibold; + border-radius: $es-radius-sm; + white-space: nowrap; + line-height: 1.4; + + &.has-filter { + background: $es-cyan-100; + color: $es-cyan-700; + } + + .count-filtered { + font-weight: $es-font-weight-bold; + } + + .count-separator { + opacity: 0.6; + margin: 0 0.125rem; + } + } + + .chips-actions { + display: flex; + align-items: center; + gap: $es-spacing-xs; + margin-left: auto; + } + + // Clear button - subtle, chip-like + .btn-chips-clear { + @include button-reset; + display: inline-flex; + align-items: center; + flex-shrink: 0; // Don't shrink + gap: 0.25rem; + padding: 0.2rem 0.5rem; + color: $es-danger; + font-size: 10px; + font-weight: $es-font-weight-medium; + background: rgba($es-danger, 0.1); + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + white-space: nowrap; // Prevent text wrapping + line-height: 1.4; + + &:hover { + background: $es-danger; + color: $es-white; + } + + i { + font-size: 9px; + flex-shrink: 0; + } + + .clear-text { + // Hide text on small screens, keep icon + @media (max-width: 480px) { + display: none; + } + } + } + + // Chips container - flows naturally from toolbar + .entity-chips { + display: flex; + flex-wrap: wrap; + gap: $es-spacing-xs; + padding: $es-spacing-sm $es-spacing-md $es-spacing-md; + min-height: 40px; + max-height: 300px; + overflow-y: auto; + + &:empty { + display: none; + } + } + + // 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: transparent; + border-top: 1px dashed $es-border-color; + + .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 { + border-color: $es-primary !important; + background-color: $es-primary-light !important; + } + + &: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 + .entity-chip { + display: inline-flex; + align-items: center; + gap: 0.375rem; + padding: 0.25rem 0.5rem; + background: $es-slate-100; + color: $es-text-secondary; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + border-radius: $es-radius-full; + transition: all $es-transition-fast; + + &:hover { + background: $es-slate-200; + } + + // Chip with image + &.has-image { + padding-left: 0.25rem; + } + + // Hidden by search filter or pagination + &.chip-filtered-out, + &.chip-paginated-out { + display: none; + } + } + + .chip-image { + width: 20px; + height: 20px; + object-fit: cover; + border-radius: 50%; + flex-shrink: 0; + } + + .chip-icon { + display: flex; + align-items: center; + justify-content: center; + font-size: 12px; + color: $es-text-muted; + flex-shrink: 0; + + // Product/entity images inside chip + img { + width: 20px; + height: 20px; + object-fit: cover; + border-radius: $es-radius-sm; + } + } + + // Country flag in chip + .chip-flag { + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + + img { + width: 18px; + height: 12px; + object-fit: cover; + border-radius: 2px; + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1); + } + + .flag-fallback { + width: 18px; + height: 12px; + display: inline-flex; + align-items: center; + justify-content: center; + background: linear-gradient(135deg, #e8eaed 0%, #dadce0 100%); + border-radius: 2px; + font-size: 10px; + color: #5f6368; + } + } + + // Holiday preview button in country chip + .chip-preview-holidays { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: 18px; + height: 18px; + color: $es-primary; + border-radius: 50%; + flex-shrink: 0; + transition: all $es-transition-fast; + + &:hover { + background: rgba($es-primary, 0.15); + color: darken($es-primary, 10%); + } + + i.material-icons { + font-size: 14px !important; + } + } + + .chip-text, + .chip-name { + // Show full name, no truncation + word-break: break-word; + } + + .chip-remove { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: 16px; + height: 16px; + margin-left: 0.125rem; + color: $es-text-muted; + border-radius: 50%; + flex-shrink: 0; + transition: all $es-transition-fast; + + &:hover { + background: rgba(0, 0, 0, 0.1); + color: $es-danger; + } + + i { + font-size: 10px; + } + } + + // Chip variants + .entity-chip.chip-primary { + background: $es-primary-light; + color: $es-primary; + + &:hover { + background: rgba($es-primary, 0.2); + } + } + + .entity-chip.chip-success { + background: $es-success-light; + color: $es-success-dark; + + &:hover { + background: rgba($es-success, 0.2); + } + } + + .entity-chip.chip-danger { + background: $es-danger-light; + color: $es-danger; + + &:hover { + background: rgba($es-danger, 0.2); + } + } + + .entity-chip.chip-warning { + background: $es-warning-light; + color: color.adjust($es-warning, $lightness: -20%); + + &:hover { + background: rgba($es-warning, 0.3); + } + } + + // Chip loading state + .entity-chip.loading, + .entity-chip-loading { + opacity: 0.7; + + .chip-remove { + display: none; + } + + .chip-icon i { + animation: spin 0.6s linear infinite; + } + } + + // Hidden chip (collapsed view) + .entity-chip.chip-hidden { + display: none; + } + + // Chips expanded/collapsed states + .entity-chips.chips-collapsed, + .entity-chips.chips-expanded { + position: relative; + } + + // Show more/less toggle + .chips-show-more-toggle { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + color: $es-primary; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + cursor: pointer; + transition: color $es-transition-fast; + + &:hover { + color: $es-primary-hover; + } + + i { + font-size: 10px; + } + } + + .chips-collapse-toggle, + .chips-expand-toggle { + // Specific variants inherit from .chips-show-more-toggle + } + + // More chips indicator + .chips-more { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.25rem 0.5rem; + background: $es-slate-200; + color: $es-text-secondary; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-semibold; + border-radius: $es-radius-full; + cursor: pointer; + transition: all $es-transition-fast; + + &:hover { + background: $es-slate-300; + } + } + + // Add chip button + .chip-add-btn { + @include button-reset; + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + background: transparent; + color: $es-primary; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + border: 1px dashed $es-primary; + border-radius: $es-radius-full; + transition: all $es-transition-fast; + + &:hover { + background: $es-primary-light; + } + + i { + font-size: 10px; + } + } + + // Inline chips (compact mode) + .entity-chips.inline { + display: inline-flex; + padding: 0; + min-height: auto; + + .entity-chip { + padding: 0.125rem 0.375rem; + font-size: 11px; + } + } + + // Selected chips section in include/exclude + .selected-chips-container { + display: flex; + flex-direction: column; + gap: $es-spacing-xs; + } + + .selected-chips-label { + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + color: $es-text-muted; + } + + // Pattern chips (for name/reference patterns) + .entity-chip.chip-pattern { + background: #fef3c7; + color: #92400e; + font-family: monospace; + + &:hover { + background: #fde68a; + } + + .chip-icon { + color: #d97706; + } + } + + // Range chips (price, quantity, etc.) + .entity-chip.chip-range, + .range-chip { + display: inline-flex; + align-items: center; + gap: 0.375rem; + padding: 0.25rem 0.5rem; + background: $es-cyan-50; + color: $es-cyan-600; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + border-radius: $es-radius-full; + transition: all $es-transition-fast; + + &:hover { + background: $es-cyan-100; + } + } + + .range-chip-text { + font-family: monospace; + } + + .btn-remove-range { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: 16px; + height: 16px; + color: $es-cyan-600; + border-radius: 50%; + transition: all $es-transition-fast; + + &:hover { + background: rgba(0, 0, 0, 0.1); + color: $es-danger; + } + + i { + font-size: 10px; + } + } + + // Multi-range chips container + .multi-range-chips { + display: flex; + flex-wrap: wrap; + gap: $es-spacing-xs; + margin-bottom: $es-spacing-xs; + + &:empty { + display: none; + } + } + + // Pattern chips container + .pattern-chips { + display: flex; + flex-wrap: wrap; + gap: $es-spacing-xs; + padding: $es-spacing-sm 0; + min-height: 32px; + + &:empty::before { + content: attr(data-placeholder); + color: $es-text-muted; + font-size: $es-font-size-xs; + font-style: italic; + } + } + + // Pattern tag + .pattern-tag { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + background: #fef3c7; + color: #92400e; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + &:hover { + background: #fde68a; + } + + &.case-sensitive { + .case-icon { + color: $es-success; + font-weight: $es-font-weight-bold; + } + } + + &.draft-tag { + background: $es-white; + border: 1px solid $es-border-color; + padding: 0; + flex: 1; + min-width: 150px; + + &:hover { + background: $es-white; + } + + .pattern-input { + flex: 1; + min-width: 100px; + padding: 0.375rem; + border: 0; + background: transparent; + font-size: $es-font-size-sm; + font-family: inherit; + + &:focus { + outline: none; + } + + &::placeholder { + color: $es-text-muted; + font-style: italic; + } + } + } + } + + .pattern-tag-text { + font-family: monospace; + max-width: 200px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .btn-toggle-case { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + color: $es-text-muted; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + &:hover { + background: rgba(0, 0, 0, 0.1); + } + } + + .case-icon { + font-size: 11px; + font-weight: $es-font-weight-semibold; + font-family: monospace; + } + + .btn-remove-pattern { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: 18px; + height: 18px; + color: #d97706; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + &:hover { + background: rgba(0, 0, 0, 0.1); + color: $es-danger; + } + + i { + font-size: 10px; + } + } + + .btn-add-pattern { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + color: $es-primary; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + &:hover { + background: $es-primary-light; + } + + i { + font-size: 12px; + } + } + + // Pattern match count (in draft tag) + .pattern-match-count { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0 0.375rem; + color: $es-text-muted; + font-size: $es-font-size-xs; + cursor: pointer; + + &.count-zero { + color: $es-warning; + } + + &.count-found { + color: $es-success; + } + + .count-value { + font-weight: $es-font-weight-semibold; + } + } + + // Pattern input row + .pattern-input-row { + display: flex; + align-items: stretch; + gap: $es-spacing-xs; + } +} + +// ========================================================================== +// Holiday Preview Popover (Country chip eye button) +// ========================================================================== + +.holiday-preview-popover { + position: absolute; + z-index: 10001; + width: 320px; + max-width: 90vw; + background: $es-white; + border-radius: $es-radius-lg; + box-shadow: $es-shadow-xl; + overflow: hidden; + + .popover-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: $es-spacing-sm; + padding: $es-spacing-sm $es-spacing-md; + background: $es-bg-header; + border-bottom: 1px solid $es-border-color; + } + + .popover-title { + display: flex; + align-items: center; + gap: $es-spacing-sm; + font-size: $es-font-size-sm; + font-weight: $es-font-weight-semibold; + color: $es-text-primary; + } + + .popover-flag { + border-radius: 2px; + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1); + } + + .popover-close { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + color: $es-text-muted; + border-radius: $es-radius-md; + transition: all $es-transition-fast; + + &:hover { + background: $es-slate-200; + color: $es-text-secondary; + } + + i.material-icons { + font-size: 18px !important; + } + } + + .popover-body { + max-height: 350px; + overflow-y: auto; + padding: $es-spacing-sm; + @include custom-scrollbar; + } + + // Loading state + .holiday-preview-loading { + display: flex; + align-items: center; + justify-content: center; + gap: $es-spacing-sm; + padding: $es-spacing-xl 0; + color: $es-text-muted; + font-size: $es-font-size-sm; + + i.material-icons { + font-size: 20px !important; + } + + .es-spin { + animation: spin 1s linear infinite; + } + } + + // Empty state + .holiday-preview-empty { + text-align: center; + padding: $es-spacing-xl 0; + color: $es-text-muted; + + i.material-icons { + font-size: 48px !important; + opacity: 0.4; + margin-bottom: $es-spacing-sm; + display: block; + } + + p { + margin: 0; + font-size: $es-font-size-sm; + } + } + + // Holiday list + .holiday-list { + display: flex; + flex-direction: column; + gap: $es-spacing-xs; + } + + .holiday-item { + display: flex; + align-items: flex-start; + gap: $es-spacing-md; + padding: $es-spacing-sm $es-spacing-md; + background: $es-slate-50; + border-radius: $es-radius-md; + border-left: 3px solid $es-success; + + &.holiday-type-bank, + &.holiday-type-bank-holiday { + border-left-color: $es-info; + } + + &.holiday-type-observance { + border-left-color: $es-warning; + } + + &.holiday-type-regional, + &.holiday-type-local-holiday { + border-left-color: #8b5cf6; + } + } + + .holiday-date { + flex-shrink: 0; + min-width: 80px; + + .holiday-day { + display: block; + font-size: $es-font-size-sm; + font-weight: $es-font-weight-semibold; + color: $es-text-primary; + } + + .holiday-weekday { + display: block; + font-size: $es-font-size-xs; + color: $es-text-muted; + } + } + + .holiday-info { + flex: 1; + min-width: 0; + } + + .holiday-country-flag { + vertical-align: middle; + margin-right: 0.25rem; + border-radius: 2px; + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1); + } + + .holiday-name { + display: inline; + font-size: $es-font-size-sm; + color: $es-text-primary; + word-wrap: break-word; + } + + .holiday-type-badge { + display: inline-block; + margin-left: $es-spacing-sm; + padding: 0.125rem 0.375rem; + font-size: 10px; + font-weight: $es-font-weight-medium; + text-transform: capitalize; + background: $es-slate-200; + color: $es-text-secondary; + border-radius: $es-radius-sm; + vertical-align: middle; + } + + .holiday-preview-note { + margin-top: $es-spacing-md; + font-size: $es-font-size-xs; + color: $es-text-muted; + text-align: center; + } + + // Filter input + .popover-filter { + display: flex; + align-items: center; + gap: $es-spacing-xs; + padding: $es-spacing-xs $es-spacing-md; + border-bottom: 1px solid $es-border-color; + background: $es-slate-50; + + i.material-icons { + font-size: 18px !important; + color: $es-text-muted; + } + + .holiday-filter-input { + flex: 1; + border: none; + background: transparent; + font-size: $es-font-size-sm; + color: $es-text-primary; + outline: none; + padding: $es-spacing-xs 0; + + &::placeholder { + color: $es-text-muted; + } + } + } +} + +// Spin animation for loading icons +@keyframes spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +// Bootstrap specificity overrides for chips toolbar form elements +// PrestaShop admin uses #content .mpr-config-form... with high specificity +// We need to match or exceed that specificity +#content.bootstrap, +#content .bootstrap, +.bootstrap #content { + .target-conditions-trait, + .entity-selector-trait { + .chips-wrapper .chips-toolbar { + // Double class for extra specificity + input[type="text"].chips-search-input.chips-search-input { + all: unset; + display: block; + flex: 1 1 auto; + min-width: 80px; + width: auto; + height: auto; + padding: 0.2rem 0.5rem 0.2rem 1.5rem; + background: $es-white url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.35-4.35'/%3E%3C/svg%3E") no-repeat 0.375rem center; + background-size: 10px; + border: 1px solid $es-slate-300; + border-radius: $es-radius-sm; + font-size: 11px; + line-height: 1.4; + color: $es-text-primary; + box-sizing: border-box; + transition: all $es-transition-fast; + + &::placeholder { + color: $es-text-muted; + font-size: 11px; + } + + &:focus { + outline: none; + border-color: $es-primary; + box-shadow: 0 0 0 2px rgba($es-primary, 0.1); + } + } + + // Double class for extra specificity + select.chips-sort-select.chips-sort-select { + all: unset; + flex: 0 0 auto; + padding: 0.2rem 1.25rem 0.2rem 0.5rem; + border: 1px solid $es-border-color; + border-radius: $es-radius-sm; + 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.375rem center; + background-size: 8px; + font-size: 10px; + line-height: 1.4; + color: $es-text-secondary; + cursor: pointer; + box-sizing: border-box; + white-space: nowrap; + height: auto; + + &:hover { + border-color: $es-primary; + } + + &:focus { + outline: none; + border-color: $es-primary; + box-shadow: 0 0 0 2px rgba($es-primary, 0.1); + } + } + } + } +} diff --git a/sources/sources/scss/components/_combinations.scss b/sources/sources/scss/components/_combinations.scss new file mode 100644 index 0000000..f130032 --- /dev/null +++ b/sources/sources/scss/components/_combinations.scss @@ -0,0 +1,396 @@ +/** + * Combination Attributes Picker Component + * Product attribute combination selection styles + */ + +@use "sass:color"; +@use '../variables' as *; +@use '../mixins' as *; + +.target-conditions-trait, +.entity-selector-trait { + + // Main container + .combination-attributes-picker { + display: flex; + flex-direction: column; + gap: 0.625rem; + } + + // Mode toggle (Any/All) + .combination-mode-toggle { + display: inline-flex; + gap: 0.25rem; + padding: 0.125rem; + background: $es-slate-100; + border-radius: $es-radius-md; + margin-bottom: 0.5rem; + } + + .combination-mode-option { + display: flex; + align-items: center; + gap: 0.25rem; + cursor: pointer; + font-size: 11px; + color: $es-text-muted; + padding: 0.25rem 0.625rem; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + input[type="radio"] { + display: none; + } + + .mode-label { + user-select: none; + } + + &:hover { + color: $es-primary; + background: rgba($es-primary, 0.1); + } + + &:has(input[type="radio"]:checked) { + background: $es-primary; + color: $es-white; + font-weight: $es-font-weight-medium; + } + } + + // Groups container + .combination-groups-container { + display: flex; + flex-wrap: wrap; + gap: $es-spacing-md; + } + + // Loading/Empty/Error states + .combination-loading, + .combination-empty, + .combination-error { + color: $es-text-muted; + font-style: italic; + padding: 0.5rem; + } + + .combination-error { + color: $es-danger; + } + + // Section header + .combinations-section { + margin-bottom: $es-spacing-md; + } + + .combinations-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: $es-spacing-sm; + } + + .combinations-label { + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + color: $es-text-muted; + } + + .combinations-help { + font-size: 11px; + color: $es-slate-400; + } + + // Toggle combinations button + .btn-toggle-combinations { + @include button-reset; + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + font-size: $es-font-size-xs; + color: $es-primary; + background: transparent; + border: 1px solid $es-primary; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + &:hover { + background: $es-primary-light; + } + } + + .btn-remove-combinations { + @include button-reset; + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + font-size: $es-font-size-xs; + color: $es-danger; + background: transparent; + + &:hover { + text-decoration: underline; + } + } + + // ============================================================================= + // Attribute Group + // ============================================================================= + + .comb-attr-group { + flex: none; + min-width: 120px; + max-width: 200px; + background: $es-white; + border: 1px solid $es-gray-300; + border-radius: $es-radius-sm; + overflow: hidden; + + &.has-selections { + border-color: $es-primary; + } + } + + .comb-attr-group-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.375rem 0.625rem; + background: $es-slate-100; + border-bottom: 1px solid $es-gray-300; + font-weight: $es-font-weight-semibold; + font-size: $es-font-size-xs; + color: $es-slate-800; + + .comb-attr-group.has-selections & { + background: $es-cyan-50; + border-bottom-color: $es-cyan-200; + } + } + + .comb-attr-group-name { + flex: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .comb-attr-group-count { + flex-shrink: 0; + min-width: 18px; + height: 18px; + padding: 0 0.25rem; + background: $es-gray-300; + border-radius: $es-radius-full; + font-size: 11px; + font-weight: $es-font-weight-semibold; + line-height: 18px; + text-align: center; + color: $es-text-muted; + + .comb-attr-group.has-selections & { + background: $es-primary; + color: $es-white; + } + } + + // Toolbar + .comb-attr-toolbar { + display: flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.375rem; + background: $es-slate-50; + border-bottom: 1px solid $es-slate-100; + } + + .comb-toolbar-btn { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: 22px; + height: 22px; + padding: 0; + background: $es-white; + border: 1px solid $es-gray-300; + border-radius: $es-radius-sm; + color: $es-text-muted; + cursor: pointer; + font-size: $es-font-size-xs; + transition: all $es-transition-fast; + + &:hover { + background: $es-slate-100; + border-color: $es-slate-400; + color: $es-slate-800; + } + } + + .comb-attr-search { + flex: 1; + min-width: 60px; + padding: 0.125rem 0.375rem; + border: 1px solid $es-gray-300; + border-radius: $es-radius-sm; + font-size: 11px; + outline: none; + + &:focus { + border-color: $es-primary; + } + + &::placeholder { + color: $es-slate-400; + } + } + + // Values container + .comb-attr-values { + display: flex; + flex-wrap: wrap; + gap: 0.25rem; + padding: 0.375rem; + max-height: 150px; + overflow-y: auto; + @include custom-scrollbar; + } + + .comb-attr-loading, + .comb-attr-empty, + .comb-attr-error { + width: 100%; + text-align: center; + color: $es-slate-400; + font-size: 11px; + padding: 0.25rem; + } + + .comb-attr-error { + color: $es-danger; + } + + // Individual value + .comb-attr-value { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.125rem 0.5rem; + background: $es-white; + border: 1px solid $es-slate-400; + border-radius: 0.75rem; + font-size: 11px; + color: $es-slate-600; + cursor: pointer; + transition: all $es-transition-fast; + white-space: nowrap; + + &:hover { + background: $es-slate-100; + border-color: $es-text-muted; + } + + &.selected { + background: $es-primary; + border-color: $es-primary-hover; + color: $es-white; + + &:hover { + background: $es-primary-hover; + border-color: color.adjust($es-primary-hover, $lightness: -5%); + } + } + } + + .comb-attr-value-count { + font-size: 9px; + color: $es-slate-400; + background: $es-slate-100; + padding: 1px 0.25rem; + border-radius: 0.5rem; + min-width: 14px; + text-align: center; + + .comb-attr-value.selected & { + color: $es-white; + background: rgba(255, 255, 255, 0.3); + } + } + + // ============================================================================= + // Combination Conditions (Row-based) + // ============================================================================= + + .combination-conditions-container { + display: flex; + flex-direction: column; + gap: $es-spacing-sm; + } + + .combination-condition-row { + display: flex; + align-items: center; + gap: $es-spacing-sm; + padding: $es-spacing-sm; + background: $es-slate-50; + border-radius: $es-radius-sm; + } + + .combination-group-select, + .combination-values-select { + flex: 1; + min-width: 120px; + } + + .combination-equals { + font-size: $es-font-size-xs; + color: $es-text-muted; + padding: 0 0.25rem; + } + + .btn-add-combination-condition { + @include button-reset; + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.375rem 0.75rem; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + color: $es-primary; + background: transparent; + border: 1px dashed $es-primary; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + &:hover { + background: $es-primary-light; + } + + i { + font-size: 10px; + } + } + + .btn-remove-combination-row { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + color: $es-text-muted; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + &:hover { + background: rgba($es-danger, 0.1); + color: $es-danger; + } + + i { + font-size: 12px; + } + } +} diff --git a/sources/sources/scss/components/_condition-trait.scss b/sources/sources/scss/components/_condition-trait.scss new file mode 100644 index 0000000..a87e124 --- /dev/null +++ b/sources/sources/scss/components/_condition-trait.scss @@ -0,0 +1,358 @@ +/** + * Condition Trait Base Styles + * Shared styling for all condition trait components + */ + +@use '../variables' as *; +@use '../mixins' as *; + +// Base condition trait container +.condition-trait { + background: $es-white; + border: 1px solid $es-border-color; + border-radius: $es-radius-lg; + margin-bottom: $es-spacing-lg; + + &:last-child { + margin-bottom: 0; + } +} + +// Collapsed state +.condition-trait.collapsed { + .condition-trait-header { + border-bottom-color: transparent; + border-radius: $es-radius-lg; + } + + .collapse-icon { + transform: rotate(180deg); + } +} + +// ============================================================================= +// Trait Header +// ============================================================================= + +.condition-trait-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: $es-spacing-lg; + flex-wrap: wrap; + padding: 0.875rem $es-spacing-lg; + background: $es-slate-50; + border-bottom: 1px solid $es-border-color; + border-radius: $es-radius-lg $es-radius-lg 0 0; + cursor: pointer; + transition: background-color $es-transition-fast; + + &:hover { + background: $es-slate-100; + } +} + +.trait-header-left { + display: flex; + align-items: center; + gap: $es-spacing-md; + min-width: 0; + flex: 1; +} + +.trait-icon { + font-size: 1.125rem; + color: $es-text-muted; + flex-shrink: 0; +} + +.trait-title-group { + display: flex; + flex-direction: column; + gap: 0.125rem; + min-width: 0; +} + +.trait-title { + font-size: $es-font-size-sm; + font-weight: $es-font-weight-semibold; + color: $es-slate-800; + white-space: nowrap; +} + +.trait-subtitle { + font-size: $es-font-size-xs; + color: $es-text-muted; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +// Schedule summary (shows current config at a glance) +.trait-summary { + display: inline-flex; + align-items: center; + gap: 0.375rem; + padding: 0.25rem 0.625rem; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + color: $es-primary; + background: rgba($es-primary, 0.08); + border-radius: $es-radius-full; + white-space: nowrap; + margin-left: $es-spacing-md; + flex-shrink: 0; + max-width: 320px; + overflow: hidden; + text-overflow: ellipsis; + + &:empty { + display: none; + } +} + +.trait-header-right { + display: flex; + align-items: center; + gap: $es-spacing-md; + flex-shrink: 0; + margin-left: auto; +} + +.trait-header-actions { + display: flex; + align-items: center; + gap: $es-spacing-sm; +} + +// Collapse icon +.collapse-icon { + display: inline-flex; + align-items: center; + justify-content: center; + width: 1.5rem; + height: 1.5rem; + font-size: $es-font-size-sm; + color: $es-text-muted; + cursor: pointer; + transition: all 0.2s; + border-radius: $es-radius-sm; + background: transparent; + + &:hover { + color: $es-primary; + background: rgba($es-primary, 0.08); + } +} + +// Show all toggle +.trait-show-all-toggle { + display: inline-flex; + align-items: center; + gap: 0.25rem; + font-size: $es-font-size-xs; + color: $es-primary; + cursor: pointer; + + &:hover { + text-decoration: underline; + } +} + +// Trait total count badge (global fallback) +.trait-total-count { + @include count-badge($es-primary); +} + +// Required indicator +.trait-required { + color: $es-danger; + font-size: $es-font-size-xs; +} + +// Validation error +.trait-validation-error { + color: $es-danger; + font-size: $es-font-size-xs; + margin-top: 0.25rem; +} + +// Trait toggle button +.trait-toggle { + @include button-reset; + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.375rem 0.75rem; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + color: $es-text-secondary; + background: $es-white; + border: 1px solid $es-border-color; + border-radius: $es-radius-md; + transition: all $es-transition-fast; + + &:hover { + background: $es-slate-50; + border-color: $es-gray-300; + } + + &.active { + color: $es-primary; + border-color: $es-primary; + background: $es-primary-light; + } +} + +// ============================================================================= +// Trait Body +// ============================================================================= + +.condition-trait-body { + padding: $es-spacing-lg; + border-radius: 0 0 $es-radius-lg $es-radius-lg; + background: $es-white; + animation: slideDown 0.2s ease-out; +} + +// Condition trait collapsed - hide body +.condition-trait.collapsed .condition-trait-body { + display: none; +} + +// ============================================================================= +// Section Styles +// ============================================================================= + +.schedule-section, +.context-section { + margin-bottom: 1.25rem; + padding-bottom: 1.25rem; + border-bottom: 1px solid $es-slate-100; + + &:last-child { + margin-bottom: 0; + padding-bottom: 0; + border-bottom: 0; + } +} + +.section-label { + display: flex; + align-items: center; + gap: 0.5rem; + font-size: 13px; + font-weight: $es-font-weight-semibold; + color: $es-slate-600; + margin-bottom: $es-spacing-md; + + i { + font-size: $es-font-size-sm; + color: $es-slate-400; + margin-right: 0.25rem; + } +} + +.section-content { + // Container for section content +} + +.section-hint { + margin-top: 0.5rem; + font-size: 11px; + color: $es-slate-400; +} + +// ============================================================================= +// Full-width Form Group Override +// ============================================================================= + +.form-group.condition-trait-fullwidth { + display: block !important; + + > .control-label { + display: none !important; + } + + > .col-lg-8, + > .col-lg-8.col-lg-offset-3 { + width: 100% !important; + max-width: 100% !important; + flex: 0 0 100% !important; + padding-left: $es-spacing-lg !important; + padding-right: $es-spacing-lg !important; + margin: 0 !important; + margin-left: 0 !important; + } +} + +// Condition traits group label +.condition-traits-group-label { + font-size: $es-font-size-sm; + font-weight: $es-font-weight-semibold; + color: $es-slate-700; + margin-bottom: $es-spacing-md; +} + +.condition-traits-wrapper { + display: flex; + flex-direction: column; + gap: $es-spacing-md; +} + +// ============================================================================= +// Collapse Header (form-content layout) +// ============================================================================= + +.entity-selector-collapse-header { + padding: 0; + margin-bottom: $es-spacing-sm; + + .btn-collapse-toggle { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0; + background: none; + border: none; + color: $es-primary; + font-size: $es-font-size-sm; + cursor: pointer; + transition: color $es-transition-fast; + + &:hover { + color: $es-primary-hover; + } + + .collapse-icon { + font-size: 1.25rem; + transition: transform 0.2s; + } + + .collapse-label { + font-weight: $es-font-weight-medium; + } + } +} + +// When collapsed, rotate icon +.condition-trait.collapsed .entity-selector-collapse-header { + .collapse-icon { + // Icon already shows expand_more when collapsed + } +} + +// ============================================================================= +// Animations +// ============================================================================= + +@keyframes slideDown { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} diff --git a/sources/sources/scss/components/_dropdown.scss b/sources/sources/scss/components/_dropdown.scss new file mode 100644 index 0000000..17a6fc1 --- /dev/null +++ b/sources/sources/scss/components/_dropdown.scss @@ -0,0 +1,2547 @@ +/** + * Search Dropdown Component + * Includes search input, filter panel, results grid + */ + +@use '../variables' as *; +@use '../mixins' as *; + +.target-conditions-trait, +.entity-selector-trait { + + // Search wrapper + .target-search-wrapper { + position: relative; + } + + // Search dropdown + .target-search-dropdown { + @include dropdown-container; + display: none; + width: 600px; + max-width: calc(100vw - 40px); + + &.show { + display: block; + } + } + + // Dropdown header + .dropdown-header { + display: flex; + align-items: center; + gap: $es-spacing-sm; + padding: $es-spacing-md; + background: $es-bg-header; + border-bottom: 1px solid $es-border-color; + border-radius: $es-radius-lg $es-radius-lg 0 0; + } + + .dropdown-search-input { + @include input-base; + flex: 1; + padding: $es-spacing-sm $es-spacing-md; + } + + .dropdown-close-btn { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + color: $es-text-muted; + border-radius: $es-radius-md; + transition: all $es-transition-fast; + + &:hover { + background: $es-slate-200; + color: $es-text-secondary; + } + } + + // Dropdown controls bar + .dropdown-controls { + display: flex; + align-items: center; + justify-content: space-between; + gap: $es-spacing-sm; + padding: $es-spacing-sm $es-spacing-md; + background: $es-white; + border-bottom: 1px solid $es-border-color; + } + + .dropdown-controls-left, + .dropdown-controls-right { + display: flex; + align-items: center; + gap: $es-spacing-sm; + } + + // View mode buttons + .view-mode-btn { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + color: $es-text-muted; + background: transparent; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + &:hover { + background: $es-slate-100; + color: $es-text-secondary; + } + + &.active { + background: $es-primary; + color: $es-white; + } + } + + // Results count + .dropdown-results-count { + font-size: $es-font-size-xs; + color: $es-text-muted; + } + + // Dropdown body + .dropdown-body { + max-height: 400px; + overflow-y: auto; + @include custom-scrollbar; + } + + // Results container + .dropdown-results { + padding: 0 $es-spacing-sm; + } + + // Results count text + .results-count { + font-size: $es-font-size-xs; + color: $es-text-muted; + padding: $es-spacing-xs $es-spacing-sm; + } + + // Results header (for list view columns) + .results-header { + display: flex; + align-items: center; + gap: $es-spacing-sm; + padding: $es-spacing-xs $es-spacing-md; + background: $es-slate-100; + border-bottom: 1px solid $es-border-color; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-semibold; + color: $es-text-secondary; + } + + // Grid view + .dropdown-results-grid { + display: grid; + gap: $es-spacing-sm; + + &.view-list { + grid-template-columns: 1fr; + } + + &.view-grid-2 { + grid-template-columns: repeat(2, 1fr); + } + + &.view-grid-3 { + grid-template-columns: repeat(3, 1fr); + } + } + + // Result item (both class names for compatibility) + // Note: Main dropdown-item styling is in the global .target-search-dropdown section below + .dropdown-result-item { + display: flex; + align-items: center; + gap: $es-spacing-sm; + padding: $es-spacing-sm 0; + background: $es-white; + border: none; + border-bottom: 1px solid $es-border-color; + border-radius: 0; + cursor: pointer; + transition: background $es-transition-fast; + + &:last-child { + border-bottom: none; + } + + &:hover { + background: $es-bg-hover; + } + + &.selected { + background: $es-primary-light; + } + + &.disabled { + opacity: 0.5; + cursor: not-allowed; + + &:hover { + background: $es-white; + } + } + } + + .result-item-image, + .result-image { + flex-shrink: 0; + width: 40px; + height: 40px; + overflow: hidden; + border-radius: $es-radius-sm; + background: $es-slate-100; + + img { + width: 100%; + height: 100%; + object-fit: cover; + } + + &.result-flag { + width: 32px; + height: 24px; + border-radius: 2px; + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1); + background: transparent; + + img { + object-fit: contain; + } + + .flag-fallback { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + background: linear-gradient(135deg, #e8eaed 0%, #dadce0 100%); + font-size: 14px; + color: #5f6368; + } + } + } + + .result-icon { + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + width: 40px; + height: 40px; + background: $es-slate-100; + border-radius: $es-radius-sm; + color: $es-text-muted; + + i { + font-size: 16px; + } + } + + .result-item-info, + .result-info { + flex: 1; + min-width: 0; + } + + .result-item-name, + .result-name { + font-size: $es-font-size-sm; + font-weight: $es-font-weight-medium; + color: $es-text-primary; + @include text-truncate; + } + + .result-item-meta, + .result-subtitle { + font-size: $es-font-size-xs; + color: $es-text-muted; + } + + .subtitle-line { + @include text-truncate; + } + + .subtitle-line-primary { + color: $es-text-secondary; + } + + .subtitle-line-secondary { + color: $es-text-muted; + font-size: 11px; + } + + // Result columns (for product list view) + .result-col { + flex-shrink: 0; + width: 70px; + text-align: right; + font-size: $es-font-size-xs; + } + + .result-col-price { + color: $es-text-secondary; + } + + .result-col-sale { + color: $es-danger; + font-weight: $es-font-weight-semibold; + } + + .result-col-stock { + .col-value { + &.stock-ok { + color: $es-success; + } + + &.stock-low { + color: $es-warning; + } + + &.stock-out { + color: $es-danger; + } + } + } + + .result-col-sales { + color: $es-text-muted; + } + + .col-value { + display: block; + } + + .result-item-checkbox, + .result-checkbox { + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + width: 18px; + height: 18px; + border: 2px solid $es-border-dark; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + i { + display: none; + font-size: 10px; + color: $es-white; + } + + .dropdown-result-item.selected &, + .dropdown-item.selected & { + background: $es-primary; + border-color: $es-primary; + + i { + display: block; + } + } + } + + // Product-specific result item + .result-item-product { + display: flex; + align-items: center; + gap: $es-spacing-sm; + } + + // No results state + .no-results { + display: flex; + align-items: center; + justify-content: center; + gap: $es-spacing-sm; + padding: $es-spacing-xl; + color: $es-text-muted; + font-size: $es-font-size-sm; + + i { + font-size: 1.25rem; + opacity: 0.5; + } + } + + // Empty state + .dropdown-empty { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: $es-spacing-sm; + padding: $es-spacing-xl; + text-align: center; + color: $es-text-muted; + + i { + font-size: 2rem; + opacity: 0.5; + } + + p { + margin: 0; + font-size: $es-font-size-sm; + } + } + + // Loading state + .dropdown-loading { + display: flex; + align-items: center; + justify-content: center; + padding: $es-spacing-xl; + color: $es-text-muted; + + i { + font-size: 1.5rem; + animation: spin 1s linear infinite; + } + } + + // Unified dropdown footer - combines load more and actions + .dropdown-footer { + display: flex; + align-items: center; + justify-content: space-between; + gap: $es-spacing-md; + padding: $es-spacing-sm $es-spacing-md; + background: $es-slate-50; + border-top: 1px solid $es-border-color; + border-radius: 0 0 $es-radius-lg $es-radius-lg; + } + + // Left side: load more controls + .dropdown-footer-left { + display: flex; + align-items: center; + gap: $es-spacing-xs; + font-size: $es-font-size-xs; + color: $es-text-muted; + + .load-label { + color: $es-text-muted; + } + + .load-more-select, + select.load-more-select { + appearance: none; + padding: 0.25rem 1.5rem 0.25rem 0.5rem; + border: 1px solid $es-border-color; + border-radius: $es-radius-sm; + 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.4rem center; + background-size: 8px; + font-size: $es-font-size-xs; + color: $es-text-secondary; + cursor: pointer; + min-width: 55px; + + &:hover { + border-color: $es-primary; + } + + &:focus { + outline: none; + border-color: $es-primary; + } + } + + .remaining-text { + color: $es-text-muted; + + strong { + color: $es-text-secondary; + font-weight: $es-font-weight-semibold; + } + } + + .btn-load-all { + @include button-reset; + padding: 0.25rem 0.5rem; + font-size: $es-font-size-xs; + color: $es-primary; + background: transparent; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + &:hover { + background: $es-primary-light; + } + } + } + + // Right side: action buttons + .dropdown-footer-right { + display: flex; + align-items: center; + gap: $es-spacing-sm; + } + + .dropdown-action-btn { + @include button-reset; + display: inline-flex; + align-items: center; + gap: 0.375rem; + padding: 0.375rem 0.75rem; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + .btn-shortcut { + font-size: 10px; + padding: 0.125rem 0.25rem; + background: rgba(0, 0, 0, 0.08); + border-radius: 3px; + font-weight: $es-font-weight-normal; + } + + &.btn-cancel { + color: $es-text-secondary; + background: $es-white; + border: 1px solid $es-border-color; + + &:hover { + background: $es-slate-100; + border-color: $es-border-dark; + } + } + + &.btn-apply, + &.btn-save { + color: $es-white; + background: $es-primary; + border: 1px solid $es-primary; + + &:hover { + background: $es-primary-hover; + border-color: $es-primary-hover; + } + + .btn-shortcut { + background: rgba(255, 255, 255, 0.2); + } + } + } + + // Legacy support - hide old load more section when new footer exists + .dropdown-load-more { + display: none; + } + + .load-more-controls { + display: none; + } + + // Filter panel + .dropdown-filter-panel { + padding: $es-spacing-md; + background: $es-slate-50; + border-bottom: 1px solid $es-border-color; + } + + .filter-panel-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: $es-spacing-sm; + } + + .filter-panel-title { + font-size: $es-font-size-sm; + font-weight: $es-font-weight-semibold; + color: $es-text-primary; + } + + .filter-panel-toggle { + @include button-reset; + font-size: $es-font-size-xs; + color: $es-primary; + + &:hover { + text-decoration: underline; + } + } + + .filter-panel-content { + display: grid; + gap: $es-spacing-sm; + grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); + } + + .filter-group { + display: flex; + flex-direction: column; + gap: 0.25rem; + } + + .filter-label { + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + color: $es-text-secondary; + } + + .filter-select, + .filter-input { + @include input-base; + padding: 0.375rem $es-spacing-sm; + font-size: $es-font-size-xs; + } +} + +// Category tree view +.target-conditions-trait, +.entity-selector-trait { + .category-tree { + padding: $es-spacing-sm; + } + + .tree-container { + // Contains tree items + } + + .tree-loading { + display: flex; + align-items: center; + justify-content: center; + gap: $es-spacing-sm; + padding: $es-spacing-xl; + color: $es-text-muted; + font-size: $es-font-size-sm; + + i { + animation: spin 0.6s linear infinite; + } + } + + // Tree item (used by JavaScript) + .tree-item { + display: flex; + align-items: center; + gap: $es-spacing-xs; + padding: 0.375rem $es-spacing-sm; + border-radius: $es-radius-sm; + cursor: pointer; + transition: background-color $es-transition-fast; + + &:hover { + background: $es-bg-hover; + } + + &.selected { + background: $es-primary-light; + + .tree-checkbox { + background: $es-primary; + border-color: $es-primary; + + i { + display: block; + } + } + } + + &.has-children { + // Parent node styling + } + } + + // tree-toggle, btn-select-children, tree-checkbox, tree-icon styles in _tree.scss + + .tree-info { + display: flex; + align-items: center; + gap: $es-spacing-xs; + flex: 1; + min-width: 0; + } + + .tree-name { + font-size: $es-font-size-sm; + color: $es-text-primary; + @include text-truncate; + } + + .tree-subtitle { + font-size: $es-font-size-xs; + color: $es-text-muted; + } + + // Legacy category tree classes (for compatibility) + .category-tree-item { + padding: 0.25rem 0; + } + + .category-tree-node { + display: flex; + align-items: center; + gap: $es-spacing-sm; + padding: $es-spacing-xs $es-spacing-sm; + border-radius: $es-radius-sm; + cursor: pointer; + transition: background-color $es-transition-fast; + + &:hover { + background: $es-bg-hover; + } + + &.selected { + background: $es-primary-light; + } + } + + .category-tree-toggle { + display: flex; + align-items: center; + justify-content: center; + width: 16px; + height: 16px; + color: $es-text-muted; + transition: transform $es-transition-fast; + + &.expanded { + transform: rotate(90deg); + } + + &.empty { + visibility: hidden; + } + } + + .category-tree-checkbox { + flex-shrink: 0; + width: 16px; + height: 16px; + border: 2px solid $es-border-dark; + border-radius: 3px; + transition: all $es-transition-fast; + + &.checked { + background: $es-primary; + border-color: $es-primary; + + &::after { + content: '\2713'; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + color: $es-white; + font-size: 10px; + } + } + + &.indeterminate { + background: $es-primary; + border-color: $es-primary; + + &::after { + content: '\2212'; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + color: $es-white; + font-size: 10px; + } + } + } + + .category-tree-name { + flex: 1; + font-size: $es-font-size-sm; + color: $es-text-primary; + @include text-truncate; + } + + .category-tree-count { + font-size: $es-font-size-xs; + color: $es-text-muted; + } + + .category-tree-children { + margin-left: 24px; + } + + // Search history + .search-history-list { + padding: $es-spacing-sm; + } + + .history-item { + display: flex; + align-items: center; + gap: $es-spacing-sm; + padding: $es-spacing-sm; + border-radius: $es-radius-sm; + cursor: pointer; + transition: background-color $es-transition-fast; + + &:hover { + background: $es-bg-hover; + } + + > i { + color: $es-text-muted; + font-size: 14px; + } + } + + .history-query { + flex: 1; + font-size: $es-font-size-sm; + color: $es-text-primary; + } + + .btn-delete-history { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + color: $es-text-muted; + border-radius: $es-radius-sm; + opacity: 0; + transition: all $es-transition-fast; + + .history-item:hover & { + opacity: 1; + } + + &:hover { + background: $es-danger-light; + color: $es-danger; + } + + i { + font-size: 12px; + } + } + + // Filter panel + .filter-panel { + display: none; + padding: $es-spacing-md; + background: $es-slate-50; + border-bottom: 1px solid $es-border-color; + + &.show { + display: block; + } + } + + .filter-row { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: $es-spacing-sm; + margin-bottom: $es-spacing-sm; + + &:last-child { + margin-bottom: 0; + } + } + + // View mode select + .view-mode-select { + @include input-base; + padding: 0.25rem 0.5rem; + font-size: $es-font-size-xs; + min-width: 80px; + } +} + +// ============================================================================= +// Global dropdown styles (when appended to body instead of inside wrapper) +// Duplicates key styles for when dropdown is outside .entity-selector-trait +// ============================================================================= +body > .target-search-dropdown, +.target-search-dropdown { + @include dropdown-container; + display: none; + width: 600px; + max-width: calc(100vw - 40px); + + &.show { + display: block; + } + + // Dropdown header + .dropdown-header { + display: flex; + align-items: center; + gap: $es-spacing-sm; + padding: $es-spacing-md; + background: $es-bg-header; + border-bottom: 1px solid $es-border-color; + border-radius: $es-radius-lg $es-radius-lg 0 0; + flex-wrap: wrap; + } + + .results-count { + font-size: $es-font-size-sm; + font-weight: $es-font-weight-semibold; + color: $es-text-primary; + white-space: nowrap; + } + + .dropdown-actions { + display: flex; + align-items: center; + gap: $es-spacing-xs; + flex-wrap: wrap; + flex: 1; + justify-content: flex-end; + } + + .btn-select-all, + .btn-clear-selection { + @include button-reset; + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + font-size: $es-font-size-xs; + color: $es-text-secondary; + background: $es-white; + border: 1px solid $es-border-color; + border-radius: $es-radius-sm; + cursor: pointer; + transition: all $es-transition-fast; + + &:hover { + background: $es-bg-hover; + border-color: $es-slate-300; + } + + kbd { + font-size: 0.65rem; + padding: 0.125rem 0.25rem; + background: $es-slate-100; + border-radius: 2px; + color: $es-text-muted; + } + } + + .sort-controls { + display: flex; + align-items: center; + // No gap - elements are connected + } + + .sort-field-select { + @include input-base; + padding: 0.25rem 0.5rem; + font-size: $es-font-size-xs; + min-width: 80px; + height: 28px; // Match btn-sort-dir height + border-radius: $es-radius-sm 0 0 $es-radius-sm; + border-right: none; + } + + .btn-sort-dir { + display: flex; + align-items: center; + justify-content: center; + width: 38px; + min-width: 38px; + flex-shrink: 0; + height: 28px; + padding: 0; + margin: 0; + color: $es-text-muted; + background: $es-white; + border: 1px solid $es-border-color; + border-radius: 0 $es-radius-sm $es-radius-sm 0; + cursor: pointer; + transition: all $es-transition-fast; + + i { + font-size: 14px; + } + + &:hover { + background: $es-bg-hover; + color: $es-text-primary; + } + + &.active { + background: $es-primary-light; + border-color: $es-primary; + color: $es-primary; + } + } + + .view-mode-select { + @include input-base; + padding: 0.25rem 0.5rem; + font-size: $es-font-size-xs; + min-width: 80px; + margin-left: 0.25rem; + } + + .btn-toggle-filters, + .btn-show-history { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + min-width: 32px; + flex-shrink: 0; + height: 28px; + padding: 0; + margin: 0; + color: $es-text-muted; + background: $es-white; + border: 1px solid $es-border-color; + border-radius: $es-radius-sm; + cursor: pointer; + transition: all $es-transition-fast; + + i { + font-size: 14px; + } + + &:hover { + background: $es-bg-hover; + color: $es-text-primary; + } + + &.active { + background: $es-primary-light; + border-color: $es-primary; + color: $es-primary; + } + } + + .refine-compact { + display: flex; + align-items: center; + // No gap - elements are connected + + // Connected to refine-input + .btn-refine-negate { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + min-width: 32px; + flex-shrink: 0; + height: 28px; + padding: 0; + margin: 0; + color: $es-text-muted; + background: $es-white; + border: 1px solid $es-border-color; + border-right: none; + border-radius: $es-radius-sm 0 0 $es-radius-sm; + cursor: pointer; + transition: all $es-transition-fast; + + &:hover { + background: $es-bg-hover; + color: $es-text-primary; + } + + &.active { + background: $es-danger-light; + color: $es-danger; + border-color: $es-danger; + } + } + + .refine-input { + @include input-base; + width: 100px; + padding: 0.25rem 0.5rem; + font-size: $es-font-size-xs; + border-radius: 0 $es-radius-sm $es-radius-sm 0; + } + + .btn-clear-refine { + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + padding: 0; + margin: 0; + margin-left: -1px; // Overlap input border when visible + color: $es-text-muted; + background: $es-white; + border: 1px solid $es-border-color; + border-radius: 0 $es-radius-sm $es-radius-sm 0; + cursor: pointer; + transition: all $es-transition-fast; + + &:hover { + background: $es-bg-hover; + color: $es-text-primary; + } + } + } + + // Filter panel + .filter-panel { + display: none; + padding: $es-spacing-md; + background: $es-slate-50; + border-bottom: 1px solid $es-border-color; + + &.show { + display: block; + } + } + + .filter-row { + display: flex; + align-items: center; + gap: $es-spacing-sm; + flex-wrap: wrap; + margin-bottom: $es-spacing-sm; + + &:last-child { + margin-bottom: 0; + } + } + + .filter-label { + display: inline-flex; + align-items: center; + gap: 0.25rem; + font-size: $es-font-size-xs; + color: $es-text-secondary; + cursor: pointer; + + input[type="checkbox"] { + margin: 0; + } + } + + .filter-price-range { + display: flex; + align-items: center; + gap: 0.25rem; + + .filter-price-label { + font-size: $es-font-size-xs; + color: $es-text-muted; + } + + .filter-price-min, + .filter-price-max { + @include input-base; + width: 70px; + padding: 0.25rem 0.5rem; + font-size: $es-font-size-xs; + } + + .filter-price-sep { + color: $es-text-muted; + } + } + + .btn-clear-filters { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + color: $es-text-muted; + border-radius: $es-radius-sm; + cursor: pointer; + margin-left: auto; + + &:hover { + background: $es-slate-200; + color: $es-text-primary; + } + } + + // Multi-row filters + .filter-row-multi { + flex-direction: column; + align-items: stretch; + gap: $es-spacing-sm; + } + + .filter-subrow { + display: flex; + align-items: center; + gap: $es-spacing-sm; + flex-wrap: wrap; + } + + .filter-range-group, + .filter-date-group, + .filter-select-group { + display: flex; + align-items: center; + gap: 0.25rem; + } + + .filter-range-label, + .filter-date-label, + .filter-select-label, + .filter-row-label { + font-size: $es-font-size-xs; + color: $es-text-muted; + white-space: nowrap; + + i { + margin-right: 0.25rem; + } + } + + .filter-range-sep { + color: $es-text-muted; + } + + .filter-product-count-min, + .filter-product-count-max, + .filter-sales-min, + .filter-sales-max, + .filter-turnover-min, + .filter-turnover-max, + .filter-date-add-from, + .filter-date-add-to, + .filter-last-product-from, + .filter-last-product-to { + @include input-base; + width: 70px; + padding: 0.25rem 0.5rem; + font-size: $es-font-size-xs; + } + + .filter-depth-select, + .filter-attribute-group-select, + .filter-feature-group-select { + @include input-base; + padding: 0.25rem 0.5rem; + font-size: $es-font-size-xs; + min-width: 100px; + } + + .filter-attributes-container, + .filter-features-container, + .filter-values-container { + display: flex; + flex-wrap: wrap; + gap: 0.25rem; + } + + // Filter group toggle buttons (attribute/feature groups) + .filter-group-toggle { + @include button-reset; + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + font-size: $es-font-size-xs; + color: $es-text-secondary; + background: $es-white; + border: 1px solid $es-border-color; + border-radius: $es-radius-sm; + cursor: pointer; + transition: all $es-transition-fast; + + &:hover { + background: $es-bg-hover; + border-color: $es-slate-300; + } + + &.active { + background: $es-primary-light; + border-color: $es-primary; + color: $es-primary; + + .toggle-count { + color: $es-primary; + } + } + + &.has-selection { + border-color: $es-success; + background: rgba($es-success, 0.05); + + .toggle-count { + color: $es-success; + font-weight: $es-font-weight-semibold; + } + } + + .toggle-name { + font-weight: $es-font-weight-medium; + } + + // Count with eye icon (like group-count-badge) + .toggle-count { + display: inline-flex; + align-items: center; + gap: 0.125rem; + color: $es-text-muted; + font-size: 0.65rem; + + i { + font-size: 10px; + color: $es-primary; + } + + // Clickable preview badge + &.clickable { + cursor: pointer; + padding: 0.125rem 0.25rem; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + &:hover { + background: rgba($es-primary, 0.1); + color: $es-primary; + + i { + color: $es-primary; + } + } + + &.popover-open { + background: $es-primary; + color: $es-white; + + i { + color: $es-white; + } + } + + &.loading { + i { + animation: spin 0.6s linear infinite; + } + } + } + } + } + + // Filter value chips + .filter-chip { + @include button-reset; + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + font-size: $es-font-size-xs; + color: $es-text-secondary; + background: $es-slate-100; + border: 1px solid transparent; + border-radius: $es-radius-sm; + cursor: pointer; + transition: all $es-transition-fast; + + &:hover { + background: $es-slate-200; + } + + &.active { + background: $es-primary; + color: $es-white; + } + } + + // Filter attribute chip (specific) + .filter-attr-chip, + .filter-feat-chip { + @extend .filter-chip; + } + + // Filter row for values (expandable) + .filter-row-values { + display: flex; + align-items: center; + gap: $es-spacing-sm; + padding: $es-spacing-sm; + background: $es-white; + border: 1px solid $es-border-color; + border-radius: $es-radius-sm; + + .filter-values-container { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 0.25rem; + flex: 1; + } + + .filter-values-label { + font-size: $es-font-size-xs; + font-weight: $es-font-weight-semibold; + color: $es-text-secondary; + white-space: nowrap; + } + + .btn-close-values { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + width: 20px; + height: 20px; + color: $es-text-muted; + border-radius: $es-radius-sm; + + &:hover { + background: $es-slate-200; + color: $es-text-primary; + } + } + } + + // Filter chip name and count + .chip-name { + font-weight: $es-font-weight-medium; + } + + .chip-count { + font-size: 0.6rem; + color: $es-text-muted; + margin-left: 0.125rem; + } + + .filter-chip.active .chip-count { + color: rgba(255, 255, 255, 0.8); + } + + // Dropdown content + .dropdown-content { + max-height: 400px; + overflow-y: auto; + @include custom-scrollbar; + } + + .dropdown-items { + display: flex; + flex-direction: column; + gap: $es-spacing-xs; + padding: $es-spacing-sm; + } + + .item-checkbox { + flex-shrink: 0; + width: 16px; + height: 16px; + border: 2px solid $es-border-dark; + border-radius: 3px; + transition: all $es-transition-fast; + + .dropdown-item.selected & { + background: $es-primary; + border-color: $es-primary; + } + } + + .item-image { + flex-shrink: 0; + width: 40px; + height: 40px; + object-fit: cover; + border-radius: $es-radius-sm; + background: $es-slate-100; + } + + .item-info { + flex: 1; + min-width: 0; + } + + .item-name { + font-size: $es-font-size-sm; + font-weight: $es-font-weight-medium; + color: $es-text-primary; + @include text-truncate; + } + + .item-meta { + font-size: $es-font-size-xs; + color: $es-text-muted; + @include text-truncate; + } + + // Dropdown footer - unified structure + .dropdown-footer { + display: flex; + align-items: center; + justify-content: space-between; + gap: $es-spacing-md; + padding: $es-spacing-sm $es-spacing-md; + background: $es-slate-50; + border-top: 1px solid $es-border-color; + border-radius: 0 0 $es-radius-lg $es-radius-lg; + } + + .dropdown-footer-left { + display: flex; + align-items: center; + gap: $es-spacing-xs; + font-size: $es-font-size-xs; + color: $es-text-muted; + + .load-label { + color: $es-text-muted; + } + + .load-more-select, + select.load-more-select { + appearance: none; + padding: 0.25rem 1.5rem 0.25rem 0.5rem; + border: 1px solid $es-border-color; + border-radius: $es-radius-sm; + 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.4rem center; + background-size: 8px; + font-size: $es-font-size-xs; + color: $es-text-secondary; + cursor: pointer; + min-width: 55px; + + &:hover { + border-color: $es-primary; + } + + &:focus { + outline: none; + border-color: $es-primary; + } + } + + .remaining-text { + color: $es-text-muted; + + strong { + color: $es-text-secondary; + font-weight: $es-font-weight-semibold; + } + } + } + + .dropdown-footer-right { + display: flex; + align-items: center; + gap: $es-spacing-sm; + } + + .dropdown-action-btn { + @include button-reset; + display: inline-flex; + align-items: center; + gap: 0.375rem; + padding: 0.375rem 0.75rem; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + white-space: nowrap; + + .btn-shortcut { + font-size: 10px; + padding: 0.125rem 0.25rem; + background: rgba(0, 0, 0, 0.08); + border-radius: 3px; + font-weight: $es-font-weight-normal; + } + + &.btn-cancel { + color: $es-text-secondary; + background: $es-white; + border: 1px solid $es-border-color; + + &:hover { + background: $es-slate-100; + border-color: $es-border-dark; + } + } + + &.btn-apply, + &.btn-save { + color: $es-white; + background: $es-primary; + border: 1px solid $es-primary; + + &:hover { + background: $es-primary-hover; + border-color: $es-primary-hover; + } + + .btn-shortcut { + background: rgba(255, 255, 255, 0.2); + } + } + } + + .dropdown-footer-info { + font-size: $es-font-size-xs; + color: $es-text-muted; + } + + // Legacy button support + .btn-cancel-dropdown { + @include button-reset; + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.375rem 0.75rem; + font-size: $es-font-size-sm; + color: $es-white; + background: $es-primary; + border: 1px solid $es-primary; + border-radius: $es-radius-sm; + cursor: pointer; + + &:hover { + background: $es-primary-hover; + border-color: $es-primary-hover; + } + + i { + font-size: 10px; + } + + kbd { + font-size: 0.65rem; + padding: 0.125rem 0.25rem; + background: rgba(255, 255, 255, 0.2); + border-radius: 2px; + color: rgba(255, 255, 255, 0.8); + } + } + + // Filter chips in dropdown + .filter-chips-row { + display: flex; + flex-wrap: wrap; + gap: $es-spacing-xs; + padding: $es-spacing-xs $es-spacing-md; + border-bottom: 1px solid $es-border-color; + } + + .filter-chip { + @include chip; + } + + // Empty and loading states + .dropdown-empty, + .dropdown-loading { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: $es-spacing-xl; + text-align: center; + color: $es-text-muted; + font-size: $es-font-size-sm; + + i { + font-size: 2rem; + opacity: 0.5; + margin-bottom: $es-spacing-sm; + } + } + + // Search history panel + .search-history-panel { + display: none; + padding: $es-spacing-sm; + background: $es-white; + border-bottom: 1px solid $es-border-color; + + &.show { + display: block; + } + } + + .history-item { + display: flex; + align-items: center; + gap: $es-spacing-sm; + padding: $es-spacing-xs $es-spacing-sm; + border-radius: $es-radius-sm; + cursor: pointer; + transition: background $es-transition-fast; + + &:hover { + background: $es-bg-hover; + } + + i { + color: $es-text-muted; + font-size: $es-font-size-sm; + } + + span { + flex: 1; + font-size: $es-font-size-sm; + color: $es-text-primary; + } + + .btn-remove-history, + .btn-delete-history { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: 20px; + height: 20px; + color: $es-text-muted; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + &:hover { + background: $es-slate-200; + color: $es-danger; + } + } + } + + // Search history list container + .search-history-list { + display: flex; + flex-direction: column; + gap: $es-spacing-xs; + } + + // Results header (for list view columns) + .results-header { + display: flex; + align-items: center; + gap: $es-spacing-sm; + padding: $es-spacing-xs $es-spacing-md; + background: $es-slate-100; + border-bottom: 1px solid $es-border-color; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-semibold; + color: $es-text-secondary; + + .header-spacer { + width: 58px; // checkbox + image width + flex-shrink: 0; + } + + .header-col { + flex-shrink: 0; + width: 70px; + text-align: right; + } + + .header-col-name { + flex: 1; + text-align: left; + } + } + + // Results container + .dropdown-results { + padding: 0 $es-spacing-sm; + background: $es-white; + min-height: 200px; + } + + // Dropdown item (search result) + .dropdown-item { + position: relative; + display: flex; + align-items: center; + gap: $es-spacing-sm; + padding: $es-spacing-sm 0; + background: $es-white; + border: none; + border-bottom: 1px solid $es-border-color; + border-radius: 0; + cursor: pointer; + transition: background $es-transition-fast; + + &:last-child { + border-bottom: none; + } + + &:hover { + background: $es-bg-hover; + } + + &.selected { + background: $es-primary-light; + + .result-checkbox { + background: $es-primary; + border-color: $es-primary; + color: $es-white; + + i { + display: block; + } + } + } + + &.disabled { + opacity: 0.5; + cursor: not-allowed; + } + } + + // Checkbox indicator + .result-checkbox { + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + width: 18px; + height: 18px; + background: $es-white; + border: 2px solid $es-border-dark; + border-radius: 3px; + transition: all $es-transition-fast; + + i { + display: none; + font-size: 10px; + } + } + + // View mode classes (applied to dropdown container) - no gap/padding for shared borders + &.view-cols-2 .dropdown-results { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0; padding: 0; border-top: 1px solid $es-border-color; border-left: 1px solid $es-border-color; } + &.view-cols-3 .dropdown-results { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0; padding: 0; border-top: 1px solid $es-border-color; border-left: 1px solid $es-border-color; } + &.view-cols-4 .dropdown-results { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0; padding: 0; border-top: 1px solid $es-border-color; border-left: 1px solid $es-border-color; } + &.view-cols-5 .dropdown-results { display: grid; grid-template-columns: repeat(5, 1fr); gap: 0; padding: 0; border-top: 1px solid $es-border-color; border-left: 1px solid $es-border-color; } + &.view-cols-6 .dropdown-results { display: grid; grid-template-columns: repeat(6, 1fr); gap: 0; padding: 0; border-top: 1px solid $es-border-color; border-left: 1px solid $es-border-color; } + &.view-cols-7 .dropdown-results { display: grid; grid-template-columns: repeat(7, 1fr); gap: 0; padding: 0; border-top: 1px solid $es-border-color; border-left: 1px solid $es-border-color; } + &.view-cols-8 .dropdown-results { display: grid; grid-template-columns: repeat(8, 1fr); gap: 0; padding: 0; border-top: 1px solid $es-border-color; border-left: 1px solid $es-border-color; } + + // Grid view item styling (compact cards with shared borders) + &.view-cols-2, + &.view-cols-3, + &.view-cols-4, + &.view-cols-5, + &.view-cols-6, + &.view-cols-7, + &.view-cols-8 { + .dropdown-item { + flex-direction: column; + align-items: center; + text-align: center; + padding: $es-spacing-sm; + border: none; + border-right: 1px solid $es-border-color; + border-bottom: 1px solid $es-border-color; + border-radius: 0; + + .result-checkbox { + position: absolute; + top: $es-spacing-xs; + left: $es-spacing-xs; + } + + .result-image, + .result-icon { + width: 48px; + height: 48px; + margin-bottom: $es-spacing-xs; + } + + .result-info { + width: 100%; + } + + .result-name { + font-size: $es-font-size-xs; + line-height: 1.3; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + } + + .result-subtitle { + display: none; + } + + // Show compact product info in grid + .result-col { + display: none; + } + + .result-grid-info { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 0.25rem; + margin-top: $es-spacing-xs; + font-size: 0.65rem; + + .grid-price { + color: $es-text-primary; + font-weight: $es-font-weight-semibold; + } + + .grid-stock { + color: $es-text-muted; + + &.stock-out { color: $es-danger; } + &.stock-low { color: $es-warning; } + } + + .grid-discount { + color: $es-success; + font-weight: $es-font-weight-medium; + } + } + } + + // Hide results header in grid views + .results-header { + display: none; + } + } + + // Remove right border from last item in each row (per column count) + &.view-cols-2 .dropdown-results .dropdown-item:nth-child(2n) { border-right: none; } + &.view-cols-3 .dropdown-results .dropdown-item:nth-child(3n) { border-right: none; } + &.view-cols-4 .dropdown-results .dropdown-item:nth-child(4n) { border-right: none; } + &.view-cols-5 .dropdown-results .dropdown-item:nth-child(5n) { border-right: none; } + &.view-cols-6 .dropdown-results .dropdown-item:nth-child(6n) { border-right: none; } + &.view-cols-7 .dropdown-results .dropdown-item:nth-child(7n) { border-right: none; } + &.view-cols-8 .dropdown-results .dropdown-item:nth-child(8n) { border-right: none; } + + // Smaller items for higher column counts + &.view-cols-5, + &.view-cols-6, + &.view-cols-7, + &.view-cols-8 { + .dropdown-item { + .result-image, + .result-icon { + width: 40px; + height: 40px; + } + + .result-name { + font-size: 0.65rem; + } + } + } + + // Product-specific result item + .result-item-product { + display: flex; + align-items: center; + gap: $es-spacing-sm; + flex: 1; + min-width: 0; + } + + .result-item-image, + .result-image { + flex-shrink: 0; + width: 40px; + height: 40px; + overflow: hidden; + border-radius: $es-radius-sm; + background: $es-slate-100; + + img { + width: 100%; + height: 100%; + object-fit: cover; + } + } + + .result-icon { + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + width: 40px; + height: 40px; + background: $es-slate-100; + border-radius: $es-radius-sm; + color: $es-text-muted; + + i { + font-size: 16px; + } + } + + .result-item-info, + .result-info { + flex: 1; + min-width: 0; + } + + .result-item-name, + .result-name { + font-size: $es-font-size-sm; + font-weight: $es-font-weight-medium; + color: $es-text-primary; + @include text-truncate; + } + + .result-item-meta, + .result-subtitle { + font-size: $es-font-size-xs; + color: $es-text-muted; + } + + .subtitle-line { + @include text-truncate; + } + + .subtitle-line-primary { + color: $es-text-secondary; + } + + .subtitle-line-secondary { + color: $es-text-muted; + font-size: 11px; + } + + // Result columns (for product list view) + .result-col { + flex-shrink: 0; + width: 70px; + text-align: right; + font-size: $es-font-size-xs; + } + + .result-col-price { + color: $es-text-secondary; + } + + .result-col-sale { + color: $es-danger; + font-weight: $es-font-weight-semibold; + } + + .result-col-stock { + .col-value { + &.stock-ok { + color: $es-success; + } + + &.stock-low { + color: $es-warning; + } + + &.stock-out { + color: $es-danger; + } + } + } + + .result-col-sales { + color: $es-text-muted; + } + + .col-value { + display: block; + } + + // Result checkbox + .result-item-checkbox, + .result-checkbox { + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + width: 18px; + height: 18px; + border: 2px solid $es-border-dark; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + i { + display: none; + font-size: 10px; + color: $es-white; + } + + .dropdown-result-item.selected &, + .dropdown-item.selected & { + background: $es-primary; + border-color: $es-primary; + + i { + display: block; + } + } + } + + // No results state + .no-results { + display: flex; + align-items: center; + justify-content: center; + gap: $es-spacing-sm; + padding: $es-spacing-xl; + color: $es-text-muted; + font-size: $es-font-size-sm; + + i { + font-size: 1.25rem; + opacity: 0.5; + } + } + + // Load more controls + .load-more-controls { + display: flex; + align-items: center; + justify-content: center; + gap: $es-spacing-sm; + padding: $es-spacing-sm $es-spacing-md; + font-size: $es-font-size-xs; + color: $es-text-muted; + + .load-more-label, + .load-more-of { + white-space: nowrap; + } + + .remaining-count { + font-weight: $es-font-weight-semibold; + color: $es-text-secondary; + } + + .load-more-select { + @include input-base; + padding: 0.25rem 0.5rem; + font-size: $es-font-size-xs; + min-width: 60px; + } + + .btn-load-more { + display: flex; + align-items: center; + justify-content: center; + padding: $es-spacing-xs; + margin: 0; + border: none; + color: $es-primary; + background: $es-primary-light !important; + border-radius: $es-radius-sm; + cursor: pointer; + transition: all $es-transition-fast; + font: inherit; + + i { + font-size: 14px; + } + + &:hover { + background: rgba($es-primary, 0.2) !important; + } + } + } + + // Load more button + .dropdown-load-more { + display: flex; + justify-content: center; + padding: $es-spacing-md; + border-top: 1px solid $es-border-color; + + .load-more-btn { + @include button-reset; + display: inline-flex; + align-items: center; + gap: $es-spacing-xs; + padding: $es-spacing-sm $es-spacing-md; + font-size: $es-font-size-sm; + font-weight: $es-font-weight-medium; + color: $es-primary; + background: $es-primary-light; + border-radius: $es-radius-md; + transition: all $es-transition-fast; + + &:hover { + background: rgba($es-primary, 0.2); + } + + &.loading { + opacity: 0.7; + cursor: wait; + } + } + } + + // Dropdown body + .dropdown-body { + max-height: 400px; + overflow-y: auto; + @include custom-scrollbar; + } + + // Tree view styles (for categories) + .tree-container { + padding: $es-spacing-sm; + } + + .tree-loading { + display: flex; + align-items: center; + justify-content: center; + gap: $es-spacing-sm; + padding: $es-spacing-xl; + color: $es-text-muted; + font-size: $es-font-size-sm; + + i { + animation: spin 0.6s linear infinite; + } + } + + .tree-item { + display: flex; + align-items: center; + gap: $es-spacing-xs; + padding: 0.375rem $es-spacing-sm; + border-radius: $es-radius-sm; + cursor: pointer; + transition: background-color $es-transition-fast; + + &:hover { + background: $es-bg-hover; + } + + &.selected { + background: $es-primary-light; + + .tree-checkbox { + background: $es-primary; + border-color: $es-primary; + + i { + display: block; + } + } + } + } + + // tree-toggle, btn-select-children, tree-checkbox, tree-icon styles in _tree.scss + + .tree-info { + display: flex; + align-items: center; + gap: $es-spacing-xs; + flex: 1; + min-width: 0; + } + + .tree-name { + font-size: $es-font-size-sm; + color: $es-text-primary; + @include text-truncate; + } + + .tree-subtitle { + font-size: $es-font-size-xs; + color: $es-text-muted; + } +} + +// ============================================================================ +// Standalone dropdown styles (for when dropdown is appended to body) +// These selectors work because .target-search-dropdown is on the dropdown itself +// ============================================================================ + +.target-search-dropdown { + // Results container - scrollable + .dropdown-results { + max-height: 400px; + overflow-y: auto; + padding: 0 $es-spacing-sm; + @include custom-scrollbar; + } + + // Results header (for list view columns) + .results-header { + display: flex; + align-items: center; + gap: $es-spacing-sm; + padding: $es-spacing-xs $es-spacing-md; + background: $es-slate-100; + border-bottom: 1px solid $es-border-color; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-semibold; + color: $es-text-secondary; + + .header-spacer { + width: 58px; // checkbox + image width + flex-shrink: 0; + } + + .header-col { + flex-shrink: 0; + width: 70px; + text-align: right; + } + + .header-col-name { + flex: 1; + text-align: left; + } + } + + // Hide results-header by default, show only for products in list view + &:not(.view-list) .results-header, + &.view-tree .results-header { + display: none; + } + + // Result item for products + .result-item-product { + display: flex; + align-items: center; + gap: $es-spacing-sm; + flex: 1; + min-width: 0; + } + + // Result columns for product data + .result-col { + flex-shrink: 0; + width: 70px; + text-align: right; + font-size: $es-font-size-xs; + } + + .result-col-price { + color: $es-text-secondary; + } + + .result-col-sale { + color: $es-danger; + font-weight: $es-font-weight-semibold; + } + + .result-col-stock { + .col-value { + &.stock-ok { color: $es-success; } + &.stock-low { color: $es-warning; } + &.stock-out { color: $es-danger; } + } + } + + .result-col-sales { + color: $es-text-muted; + } + + // Dropdown item styling + .dropdown-item { + display: flex; + align-items: center; + gap: $es-spacing-sm; + padding: 0; + border: none; + border-bottom: 1px solid $es-border-color; + border-radius: 0; + cursor: pointer; + transition: background-color $es-transition-fast; + + &:last-child { + border-bottom: none; + } + + &:hover { + background: $es-bg-hover; + } + + &.selected { + background: $es-primary-light; + } + } + + // Result checkbox styling + .result-checkbox { + flex-shrink: 0; + display: flex; + align-items: center; + justify-content: center; + width: 18px; + height: 18px; + border: 2px solid $es-border-dark; + border-radius: 3px; + transition: all $es-transition-fast; + + i { + font-size: 10px; + color: transparent; + } + + .dropdown-item.selected & { + background: $es-primary; + border-color: $es-primary; + + i { + color: $es-white; + } + } + } + + // Result image + .result-image { + flex-shrink: 0; + width: 40px; + height: 40px; + overflow: hidden; + border-radius: $es-radius-sm; + background: $es-slate-100; + + img { + width: 100%; + height: 100%; + object-fit: cover; + } + } + + // Result icon (for non-image entities) + .result-icon { + flex-shrink: 0; + display: flex; + align-items: center; + justify-content: center; + width: 40px; + height: 40px; + background: $es-slate-100; + border-radius: $es-radius-sm; + + i { + font-size: 16px; + color: $es-text-muted; + } + } + + // Result info container + .result-info { + flex: 1; + min-width: 0; + } + + .result-name { + font-size: $es-font-size-sm; + font-weight: $es-font-weight-medium; + color: $es-text-primary; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .result-subtitle { + font-size: $es-font-size-xs; + color: $es-text-muted; + } + + .subtitle-line { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .subtitle-line-primary { + color: $es-text-secondary; + } + + .subtitle-line-secondary { + color: $es-text-muted; + font-size: 11px; + } + + // Hide columns in grid/tree views + &[class*="view-cols-"] .result-col, + &.view-tree .result-col { + display: none; + } + + // Entity search box - full width + .entity-search-box { + display: flex; + align-items: center; + gap: $es-spacing-sm; + width: 100%; + padding: $es-spacing-sm $es-spacing-md; + background: $es-white; + border: none; + border-bottom: 1px solid $es-border-color; + border-radius: 0; + + .entity-search-icon { + color: $es-text-muted; + flex-shrink: 0; + margin-left: $es-spacing-xs; + } + + // Override Bootstrap/parent form input styles + input.entity-search-input, + input.entity-search-input[type="text"] { + flex: 1; + min-width: 0; + width: auto !important; + max-width: none !important; + height: auto; + padding: 0; + margin: 0; + border: none !important; + outline: none; + background: transparent !important; + font-size: $es-font-size-sm; + color: $es-text-primary; + box-shadow: none !important; + + &::placeholder { + color: $es-text-muted; + } + + &:focus { + border: none !important; + box-shadow: none !important; + outline: none; + } + } + + .search-loading { + color: $es-text-muted; + } + } +} + +// Body-level dropdown (when appended to body for z-index) +body > .target-search-dropdown { + // Override dropdown-item border when inside body-appended dropdown + .dropdown-item { + border: none; + border-radius: 0; + + &:not(:last-child) { + border-bottom: 1px solid $es-border-color; + } + } +} + +@keyframes spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} diff --git a/sources/sources/scss/components/_entity-item.scss b/sources/sources/scss/components/_entity-item.scss new file mode 100644 index 0000000..dc82f9d --- /dev/null +++ b/sources/sources/scss/components/_entity-item.scss @@ -0,0 +1,516 @@ +/** + * Entity Item - Shared Base Component + * Unified styling for entity items in chips, lists, and previews + * + * Variants: + * - .entity-item (base) - default list-row style + * - .entity-item.chip-style - pill/chip style (compact) + * - .entity-item.card-style - card/grid style + */ + +@use '../variables' as *; +@use '../mixins' as *; + +// ============================================================================= +// Entity Item Sizing +// ============================================================================= + +$entity-item-image-sm: 20px; +$entity-item-image-md: 32px; +$entity-item-image-lg: 48px; + +// ============================================================================= +// Base Entity Item (list-row layout) +// ============================================================================= + +.entity-item { + display: flex; + align-items: center; + gap: $es-spacing-sm; + padding: $es-spacing-sm; + background: $es-white; + border-radius: $es-radius-sm; + transition: background $es-transition-fast; + + &:hover { + background: $es-bg-hover; + } + + // Clickable variant + &.clickable { + cursor: pointer; + } + + // Selected state + &.selected { + background: $es-primary-light; + } +} + +// ----------------------------------------------------------------------------- +// Entity Item Image +// ----------------------------------------------------------------------------- + +.entity-item-image { + flex-shrink: 0; + width: $entity-item-image-md; + height: $entity-item-image-md; + object-fit: cover; + border-radius: $es-radius-sm; + background: $es-slate-100; +} + +// Size variants +.entity-item-image--sm { + width: $entity-item-image-sm; + height: $entity-item-image-sm; + border-radius: 50%; +} + +.entity-item-image--lg { + width: $entity-item-image-lg; + height: $entity-item-image-lg; +} + +// No-image placeholder +.entity-item-no-image { + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + width: $entity-item-image-md; + height: $entity-item-image-md; + background: $es-slate-100; + color: $es-text-muted; + border-radius: $es-radius-sm; + font-size: $es-font-size-sm; + + &--sm { + width: $entity-item-image-sm; + height: $entity-item-image-sm; + font-size: 10px; + border-radius: 50%; + } +} + +// ----------------------------------------------------------------------------- +// Entity Item Info (name + meta) +// ----------------------------------------------------------------------------- + +.entity-item-info { + flex: 1; + min-width: 0; + display: flex; + flex-direction: column; + gap: 0.125rem; +} + +.entity-item-name { + font-size: $es-font-size-sm; + font-weight: $es-font-weight-medium; + color: $es-text-primary; + @include text-truncate; +} + +.entity-item-meta { + font-size: $es-font-size-xs; + color: $es-text-muted; + @include text-truncate; +} + +// ----------------------------------------------------------------------------- +// Entity Item Badge/Price (right side) +// ----------------------------------------------------------------------------- + +.entity-item-badge { + flex-shrink: 0; + padding: 0.125rem 0.5rem; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + background: $es-slate-100; + color: $es-text-muted; + border-radius: $es-radius-sm; +} + +.entity-item-price { + flex-shrink: 0; + font-size: $es-font-size-sm; + font-weight: $es-font-weight-semibold; + color: $es-primary; +} + +// ----------------------------------------------------------------------------- +// Entity Item Actions (remove button, etc.) +// ----------------------------------------------------------------------------- + +.entity-item-action { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + width: 20px; + height: 20px; + color: $es-text-muted; + border-radius: 50%; + transition: all $es-transition-fast; + + &:hover { + background: rgba(0, 0, 0, 0.1); + color: $es-danger; + } + + i { + font-size: 10px; + } +} + +// ============================================================================= +// Chip Style Variant (compact pill) +// ============================================================================= + +.entity-item.chip-style { + display: inline-flex; + gap: 0.375rem; + padding: 0.25rem 0.5rem; + background: $es-slate-100; + border-radius: $es-radius-full; + + &:hover { + background: $es-slate-200; + } + + .entity-item-image { + width: $entity-item-image-sm; + height: $entity-item-image-sm; + border-radius: 50%; + } + + .entity-item-no-image { + width: $entity-item-image-sm; + height: $entity-item-image-sm; + font-size: 10px; + border-radius: 50%; + } + + .entity-item-info { + flex-direction: row; + align-items: center; + gap: 0.25rem; + } + + .entity-item-name { + font-size: $es-font-size-xs; + } + + .entity-item-meta { + display: none; + } + + .entity-item-action { + width: 16px; + height: 16px; + margin-left: 0.125rem; + } +} + +// ============================================================================= +// List Style Variant (bordered rows) +// ============================================================================= + +.entity-item.list-style { + padding: $es-spacing-sm 0; + background: transparent; + border-bottom: 1px solid $es-border-color; + border-radius: 0; + + &:last-child { + border-bottom: none; + } + + &:hover { + background: $es-bg-hover; + } +} + +// ============================================================================= +// Entity Item Container (wrapper for multiple items) +// ============================================================================= + +.entity-items-container { + display: flex; + flex-direction: column; + background: $es-slate-50; + border: 1px solid $es-border-color; + border-radius: $es-radius-md; + overflow: hidden; +} + +// Toolbar (filter, sort, count, clear) +.entity-items-toolbar { + display: none; + align-items: center; + flex-wrap: nowrap; + gap: $es-spacing-sm; + padding: $es-spacing-sm $es-spacing-md; + padding-bottom: 0; + background: transparent; + + &.has-items { + display: flex; + } +} + +// Filter input +.entity-items-filter { + all: unset; + display: block; + flex: 1 1 auto; + min-width: 80px; + width: auto; + height: auto; + padding: 0.2rem 0.5rem 0.2rem 1.5rem; + background: $es-white url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.35-4.35'/%3E%3C/svg%3E") no-repeat 0.375rem center; + background-size: 10px; + border: 1px solid $es-slate-300; + border-radius: $es-radius-sm; + font-size: 11px; + line-height: 1.4; + color: $es-text-primary; + box-sizing: border-box; + transition: all $es-transition-fast; + + &::placeholder { + color: $es-text-muted; + font-size: 11px; + } + + &:focus { + outline: none; + border-color: $es-primary; + box-shadow: 0 0 0 2px rgba($es-primary, 0.1); + } +} + +// Sort dropdown +.entity-items-sort { + all: unset; + flex: 0 0 auto; + padding: 0.2rem 1.25rem 0.2rem 0.5rem; + border: 1px solid $es-border-color; + border-radius: $es-radius-sm; + 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.375rem center; + background-size: 8px; + font-size: 10px; + line-height: 1.4; + color: $es-text-secondary; + cursor: pointer; + box-sizing: border-box; + white-space: nowrap; + + &:hover { + border-color: $es-primary; + } + + &:focus { + outline: none; + border-color: $es-primary; + box-shadow: 0 0 0 2px rgba($es-primary, 0.1); + } +} + +// Count badge +.entity-items-count { + display: inline-flex; + align-items: center; + flex-shrink: 0; + gap: 0.125rem; + padding: 0.2rem 0.5rem; + background: $es-slate-200; + color: $es-text-secondary; + font-size: 10px; + font-weight: $es-font-weight-semibold; + border-radius: $es-radius-sm; + white-space: nowrap; + line-height: 1.4; + + &.has-filter { + background: $es-cyan-100; + color: $es-cyan-700; + } +} + +// Clear button +.entity-items-clear { + @include button-reset; + display: inline-flex; + align-items: center; + flex-shrink: 0; + gap: 0.25rem; + padding: 0.2rem 0.5rem; + color: $es-danger; + font-size: 10px; + font-weight: $es-font-weight-medium; + background: rgba($es-danger, 0.1); + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + white-space: nowrap; + line-height: 1.4; + + &:hover { + background: $es-danger; + color: $es-white; + } + + i { + font-size: 9px; + flex-shrink: 0; + } +} + +// Items list area +.entity-items-list { + display: flex; + flex-wrap: wrap; + gap: $es-spacing-xs; + padding: $es-spacing-sm $es-spacing-md $es-spacing-md; + min-height: 40px; + max-height: 300px; + overflow-y: auto; + @include custom-scrollbar; + + &:empty { + display: none; + } + + // List layout (vertical) + &.list-layout { + flex-direction: column; + flex-wrap: nowrap; + gap: 0; + padding: $es-spacing-sm; + } +} + +// Load more section +.entity-items-load-more { + display: flex; + align-items: center; + justify-content: center; + gap: $es-spacing-sm; + padding: $es-spacing-sm $es-spacing-md; + background: transparent; + border-top: 1px dashed $es-border-color; + + .load-more-label { + font-size: $es-font-size-xs; + color: $es-text-muted; + } + + .load-more-select { + appearance: none; + padding: 0.25rem 1.75rem 0.25rem 0.5rem; + border: 1px solid $es-border-color; + border-radius: $es-radius-sm; + 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; + background-size: 8px; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + color: $es-primary; + cursor: pointer; + transition: all $es-transition-fast; + height: auto; + min-height: 0; + line-height: 1.3; + + &:hover { + border-color: $es-primary; + background-color: $es-primary-light; + } + + &:focus { + outline: none; + border-color: $es-primary; + box-shadow: 0 0 0 2px rgba($es-primary, 0.1); + } + } + + .load-more-remaining { + font-size: $es-font-size-xs; + color: $es-text-muted; + + .remaining-count { + font-weight: $es-font-weight-semibold; + color: $es-text-secondary; + } + } + + .btn-load-more { + display: flex; + align-items: center; + justify-content: center; + padding: $es-spacing-xs; + margin: 0; + border: none; + color: $es-primary; + background: $es-primary-light; + border-radius: $es-radius-sm; + cursor: pointer; + transition: all $es-transition-fast; + font: inherit; + + i { + font-size: 14px; + } + + &:hover { + background: rgba($es-primary, 0.2); + } + + &.loading { + cursor: wait; + + i { + animation: spin 0.6s linear infinite; + } + } + } +} + +// ============================================================================= +// Empty & Loading States +// ============================================================================= + +.entity-items-empty { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: $es-spacing-sm; + padding: $es-spacing-xl; + text-align: center; + color: $es-text-muted; + + i { + font-size: 2rem; + opacity: 0.5; + } + + p { + margin: 0; + font-size: $es-font-size-sm; + } +} + +.entity-items-loading { + display: flex; + align-items: center; + justify-content: center; + padding: $es-spacing-xl; + color: $es-text-muted; + + i { + font-size: 20px; + animation: spin 0.6s linear infinite; + } +} diff --git a/sources/sources/scss/components/_entity-selector.scss b/sources/sources/scss/components/_entity-selector.scss new file mode 100644 index 0000000..2b69857 --- /dev/null +++ b/sources/sources/scss/components/_entity-selector.scss @@ -0,0 +1,450 @@ +/** + * Entity Selector - Main Component Styles + * Wrapper, header, body, tabs, blocks + */ + +@use '../variables' as *; +@use '../mixins' as *; + +// Main wrapper (supports both .target-conditions-trait and .entity-selector-trait) +.target-conditions-trait, +.entity-selector-trait { + position: relative; + overflow: visible; + background: $es-white; + border: 1px solid $es-border-color; + border-radius: $es-radius-lg; + + // Base Material Icons sizing — 18px throughout entity-selector + // !important needed to override .bootstrap .material-icons:not(.js-mobile-menu) { font-size: inherit } + .material-icons { + font-size: 18px !important; + } + + // Trait Header (collapsible) + .condition-trait-header { + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; + gap: $es-spacing-md; + padding: 0.875rem $es-spacing-md; + background: $es-bg-header; + border-bottom: 1px solid $es-border-color; + border-radius: $es-radius-lg $es-radius-lg 0 0; + cursor: pointer; + user-select: none; + transition: background-color $es-transition-fast; + + &:hover { + background: $es-bg-hover; + } + } + + .trait-header-left { + display: flex; + align-items: center; + gap: 0.75rem; + min-width: 0; + flex: 1; + } + + .trait-icon { + font-size: $es-font-size-lg; + color: $es-text-muted; + flex-shrink: 0; + } + + .trait-title-group { + display: flex; + flex-direction: column; + gap: 0.125rem; + min-width: 0; + } + + .trait-title { + font-size: $es-font-size-sm; + font-weight: $es-font-weight-semibold; + color: $es-text-primary; + white-space: nowrap; + } + + .trait-subtitle { + font-size: $es-font-size-xs; + color: $es-text-muted; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + // Total count badge in header + .trait-total-count { + @include count-badge($es-primary); + margin-left: $es-spacing-sm; + } + + // Show all toggle switch + .trait-show-all-toggle { + display: inline-flex; + align-items: center; + gap: $es-spacing-sm; + margin-right: 0.75rem; + padding: 0.25rem $es-spacing-sm; + border-radius: $es-radius-sm; + cursor: pointer; + user-select: none; + transition: background-color $es-transition-fast; + + &:hover { + background: rgba(0, 0, 0, 0.05); + } + + .toggle-label { + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + color: $es-text-muted; + } + + .show-all-checkbox { + display: none; + } + + .toggle-slider { + position: relative; + width: 36px; + height: 20px; + background: $es-slate-300; + border-radius: $es-radius-full; + transition: background-color $es-transition-normal; + + &::after { + content: ''; + position: absolute; + top: 2px; + left: 2px; + width: 16px; + height: 16px; + background: $es-white; + border-radius: 50%; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); + transition: transform $es-transition-normal; + } + } + + .show-all-checkbox:checked + .toggle-slider { + background: $es-success; + + &::after { + transform: translateX(16px); + } + } + } + + // Validation error states + &.has-validation-error { + border-color: $es-danger; + box-shadow: 0 0 0 3px rgba($es-danger, 0.1); + + .condition-trait-header { + border-bottom-color: $es-danger; + } + } + + .trait-validation-error { + display: flex; + align-items: center; + gap: $es-spacing-sm; + padding: 0.625rem $es-spacing-md; + background: $es-danger-light; + color: #b91c1c; + font-size: $es-font-size-sm; + font-weight: $es-font-weight-medium; + border-bottom: 1px solid #fecaca; + + i { + color: $es-danger; + } + } + + // Required indicator + &.trait-required .trait-title::after { + content: ' *'; + color: $es-danger; + } + + // Body + .condition-trait-body { + padding: 0; + background: $es-white; + border-radius: 0 0 $es-radius-lg $es-radius-lg; + } + + // Block type tabs + .target-block-tabs { + display: flex; + flex-wrap: wrap; + gap: 0; + padding: 0; + background: $es-slate-100; + border-bottom: 1px solid $es-border-color; + } + + .target-block-tab { + position: relative; + display: flex; + align-items: center; + gap: $es-spacing-sm; + flex: none; + min-width: 0; + padding: 0.625rem $es-spacing-md; + margin-bottom: -1px; + background: transparent; + border: 0; + border-bottom: 2px solid transparent; + color: $es-text-muted; + font-size: $es-font-size-sm; + font-weight: $es-font-weight-medium; + cursor: pointer; + transition: all $es-transition-fast; + + &:hover { + background: $es-slate-200; + color: $es-slate-700; + } + + &.active { + background: $es-white; + border-bottom-color: $es-cyan-500; + color: $es-primary; + } + + i.material-icons { + font-size: 18px !important; + } + + .tab-label { + white-space: nowrap; + } + + .tab-badge { + @include count-badge($es-primary); + } + + &.has-data:not(.active) .tab-badge { + @include count-badge($es-slate-400); + } + } + + // Tabs row with actions (form-content layout) + .entity-selector-tabs-row { + display: flex; + align-items: stretch; + background: $es-slate-100; + border-bottom: 1px solid $es-border-color; + border-radius: $es-radius-lg $es-radius-lg 0 0; + + .target-block-tabs { + flex: 1; + border-bottom: 0; + border-radius: $es-radius-lg 0 0 0; + } + } + + // Expand/collapse groups button (standalone, in tabs row) + .entity-selector-actions:not(.btn-toggle-blocks) { + display: flex; + align-items: center; + padding: $es-spacing-xs $es-spacing-md; + border-left: 1px solid $es-border-color; + + .btn-toggle-groups { + display: flex; + align-items: center; + justify-content: center; + width: 34px; + height: 34px; + padding: 0; + background: $es-white; + border: 1px solid $es-slate-400; + border-radius: $es-radius-md; + color: $es-slate-700; + cursor: pointer; + transition: all $es-transition-fast; + + &:hover { + background: $es-primary-light; + color: $es-primary; + border-color: $es-primary; + } + + .material-icons { + font-size: 18px !important; + } + } + } + + // Expand/collapse toggle area (entire section is clickable) + .entity-selector-actions.btn-toggle-blocks { + display: flex; + align-items: center; + justify-content: center; + padding: 0 $es-spacing-md; + background: $es-slate-100; + border-left: 1px solid $es-border-color; + color: $es-slate-400; + cursor: pointer; + transition: all $es-transition-fast; + + &:hover { + background: $es-slate-200; + color: $es-primary; + } + + .material-icons { + font-size: 20px !important; + } + } + + // When expanded - highlight the toggle area + .entity-selector-trait:not(.blocks-collapsed) .entity-selector-actions.btn-toggle-blocks { + background: $es-primary-light; + border-left-color: $es-primary; + color: $es-primary; + } + + // Blocks content wrapper (for form-content layout collapse) + .entity-selector-blocks-content { + // Inherits styles from condition-trait-body context + } + + // Block container + .target-block-container { + display: none; + + &.active { + display: block; + } + } + + .target-block-content { + padding: $es-spacing-md; + } + + .target-block-groups { + display: flex; + flex-direction: column; + gap: $es-spacing-md; + } + + // Block header (for standalone blocks) + .target-block-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: $es-spacing-sm $es-spacing-md; + background: $es-bg-header; + border-bottom: 1px solid $es-border-color; + } + + // Empty state + .target-block-empty { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: $es-spacing-sm; + padding: $es-spacing-xl; + text-align: center; + color: $es-text-muted; + + i { + font-size: 2rem !important; + opacity: 0.5; + } + + p { + margin: 0; + font-size: $es-font-size-sm; + } + } + + // Collapse toggle + .trait-collapse-toggle, + .collapse-toggle { + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + color: $es-text-muted; + cursor: pointer; + transition: transform $es-transition-normal; + + &.collapsed { + transform: rotate(-90deg); + } + } + + // Header actions + .trait-header-right { + display: flex; + align-items: center; + gap: $es-spacing-sm; + } + + // Collapsed state + &.collapsed { + .condition-trait-body { + display: none; + } + + .condition-trait-header { + border-radius: $es-radius-lg; + } + } +} + +// Single mode specific styles +.target-conditions-trait.single-mode, +.entity-selector-trait.single-mode { + .target-block-tabs { + display: none; + } + + .target-block-container { + display: block; + } +} + +// Header action buttons +.target-conditions-trait, +.entity-selector-trait { + .header-actions { + display: flex; + align-items: center; + gap: $es-spacing-xs; + } + + .header-action-btn { + @include button-reset; + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem $es-spacing-sm; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + color: $es-text-muted; + background: transparent; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + &:hover { + background: $es-slate-200; + color: $es-text-secondary; + } + + i { + font-size: 14px !important; + } + } +} diff --git a/sources/sources/scss/components/_groups.scss b/sources/sources/scss/components/_groups.scss new file mode 100644 index 0000000..4c17f30 --- /dev/null +++ b/sources/sources/scss/components/_groups.scss @@ -0,0 +1,982 @@ +/** + * Groups Component + * Selection groups, include/exclude sections, method selectors + */ + +@use '../variables' as *; +@use '../mixins' as *; + +.target-conditions-trait, +.entity-selector-trait { + + // Group container + .target-group { + background: $es-white; + border: 1px solid $es-border-color; + border-radius: $es-radius-lg; + overflow: hidden; + } + + // Group header + .target-group-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: $es-spacing-md; + padding: $es-spacing-sm $es-spacing-md; + background: $es-bg-header; + border-bottom: 1px solid $es-border-color; + } + + .target-group-title { + display: flex; + align-items: center; + gap: $es-spacing-sm; + font-size: $es-font-size-sm; + font-weight: $es-font-weight-semibold; + color: $es-text-primary; + + .group-number { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 20px; + height: 20px; + padding: 0 0.25rem; + background: $es-primary; + color: $es-white; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-bold; + border-radius: $es-radius-full; + } + } + + .target-group-actions { + display: flex; + align-items: center; + gap: $es-spacing-xs; + } + + .group-action-btn { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + color: $es-text-muted; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + &:hover { + background: $es-slate-200; + color: $es-text-secondary; + } + + &.danger:hover { + background: $es-danger-light; + color: $es-danger; + } + } + + // Group body + .target-group-body, + .group-body { + padding: $es-spacing-md; + } + + // Include section + .include-section { + margin-bottom: $es-spacing-md; + } + + .section-label { + display: flex; + align-items: center; + gap: $es-spacing-xs; + margin-bottom: $es-spacing-sm; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-semibold; + text-transform: uppercase; + letter-spacing: 0.05em; + + &.label-include { + color: $es-success-dark; + + i { + color: $es-success; + } + } + + &.label-exclude { + color: $es-danger; + + i { + color: $es-danger; + } + } + } + + // Method selector + .method-selector { + display: flex; + align-items: center; + gap: $es-spacing-sm; + margin-bottom: $es-spacing-sm; + } + + .method-selector-wrapper { + flex: 1; + position: relative; + } + + .method-select { + @include input-base; + padding-right: 2rem; + cursor: pointer; + appearance: none; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E"); + background-position: right 0.5rem center; + background-repeat: no-repeat; + background-size: 1.5em 1.5em; + } + + .method-help-btn { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + color: $es-text-muted; + border-radius: $es-radius-full; + transition: all $es-transition-fast; + + &:hover { + background: $es-slate-100; + color: $es-primary; + } + } + + // Value picker (search trigger) + .value-picker { + position: relative; + } + + .value-picker-trigger { + @include button-reset; + display: flex; + align-items: center; + gap: $es-spacing-sm; + width: 100%; + padding: $es-spacing-sm $es-spacing-md; + background: $es-white; + border: 1px solid $es-border-color; + border-radius: $es-radius-md; + color: $es-text-muted; + font-size: $es-font-size-sm; + text-align: left; + transition: all $es-transition-fast; + + &:hover { + border-color: $es-slate-300; + } + + &:focus { + border-color: $es-primary; + @include focus-ring($es-primary); + } + + i { + color: $es-text-light; + } + } + + // Pattern input (text input for patterns) + .pattern-input-wrapper { + position: relative; + } + + .pattern-input { + @include input-base; + font-family: monospace; + } + + .pattern-add-btn { + @include button-reset; + position: absolute; + right: 0.25rem; + top: 50%; + transform: translateY(-50%); + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + color: $es-primary; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + &:hover { + background: $es-primary-light; + } + } + + // Multi-range input (price ranges) + .multi-range-container { + display: flex; + flex-direction: column; + gap: $es-spacing-sm; + } + + .range-row { + display: flex; + align-items: center; + gap: $es-spacing-sm; + } + + .range-input { + @include input-base; + width: 100px; + text-align: center; + } + + .range-separator { + color: $es-text-muted; + font-size: $es-font-size-sm; + } + + .range-remove-btn { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + color: $es-text-muted; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + &:hover { + background: $es-danger-light; + color: $es-danger; + } + } + + .range-add-btn { + @include button-reset; + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + color: $es-primary; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + &:hover { + background: $es-primary-light; + } + } + + // Multi-select tiles (stock status, etc.) + .multi-select-tiles { + display: flex; + flex-wrap: wrap; + gap: $es-spacing-xs; + } + + .multi-select-tile { + @include button-reset; + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.375rem 0.75rem; + background: $es-slate-100; + color: $es-text-secondary; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + border: 1px solid transparent; + border-radius: $es-radius-full; + transition: all $es-transition-fast; + + &:hover { + background: $es-slate-200; + } + + &.selected { + background: $es-primary-light; + color: $es-primary; + border-color: $es-primary; + } + } + + // Exclude section + .exclude-section { + margin-top: $es-spacing-md; + padding-top: $es-spacing-md; + border-top: 1px dashed $es-border-color; + } + + // Legacy exclude-rows (if used elsewhere) + .exclude-rows { + display: flex; + flex-direction: column; + gap: $es-spacing-sm; + } + + .exclude-row-content { + flex: 1; + } + + .exclude-remove-btn { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + color: $es-text-muted; + border-radius: $es-radius-sm; + flex-shrink: 0; + transition: all $es-transition-fast; + + &:hover { + background: $es-danger-light; + color: $es-danger; + } + } + + .add-exclude-btn { + @include button-reset; + display: inline-flex; + align-items: center; + gap: 0.25rem; + margin-top: $es-spacing-sm; + padding: 0.25rem 0.5rem; + color: $es-danger; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + border: 1px dashed $es-danger; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + &:hover { + background: $es-danger-light; + } + } + + // Add group button (used in block-footer) + .btn-add-group { + @include button-reset; + display: inline-flex; + align-items: center; + gap: 0.375rem; + padding: 0.5rem 0.875rem; + color: $es-primary; + font-size: $es-font-size-sm; + font-weight: $es-font-weight-medium; + background: rgba($es-primary, 0.05); + border: 1px dashed $es-primary; + border-radius: 0.375rem; + cursor: pointer; + transition: all $es-transition-fast; + + &:hover { + background: rgba($es-primary, 0.1); + } + + i { + font-size: 12px; + } + } + + // Block footer + .block-footer { + display: flex; + align-items: center; + gap: $es-spacing-sm; + padding: $es-spacing-md; + border-top: 1px solid $es-border-color; + } + + // Block body + .block-body { + padding: 0; + } + + // Groups container + .groups-container { + padding: $es-spacing-md; + } + + // Groups empty state + .groups-empty-state { + display: flex; + align-items: center; + justify-content: center; + padding: $es-spacing-xl; + color: $es-text-muted; + font-size: $es-font-size-sm; + } + + // Selection group + .selection-group { + background: $es-white; + border: 1px solid $es-border-color; + border-radius: $es-radius-lg; + margin-bottom: $es-spacing-md; + + &:last-child { + margin-bottom: 0; + } + + &.collapsed { + .group-body { + display: none; + } + + .group-collapse-toggle i { + transform: rotate(-90deg); + } + } + } + + // Group header + .group-header { + display: flex; + align-items: center; + gap: $es-spacing-sm; + padding: $es-spacing-sm $es-spacing-md; + background: $es-bg-header; + border-bottom: 1px solid $es-border-color; + border-radius: $es-radius-lg $es-radius-lg 0 0; + cursor: pointer; + + &.group-header-single { + padding: $es-spacing-xs $es-spacing-md; + background: transparent; + border-bottom: none; + } + } + + .group-collapse-toggle { + display: flex; + align-items: center; + justify-content: center; + width: 24px; + color: $es-text-muted; + + i { + font-size: 20px !important; + transition: transform $es-transition-fast; + } + } + + .group-name-wrapper { + flex: 1; + display: flex; + align-items: center; + gap: $es-spacing-sm; + } + + .group-name-input { + flex: 1; + padding: 0.25rem 0.5rem; + font-size: $es-font-size-sm; + font-weight: $es-font-weight-semibold; + color: $es-text-primary; + background: transparent; + border: 1px solid transparent; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + &:hover, + &:focus { + background: $es-white; + border-color: $es-border-color; + outline: none; + } + + &::placeholder { + color: $es-text-muted; + font-weight: $es-font-weight-medium; + } + } + + .group-count-badge { + @include count-badge($es-primary); + } + + .btn-remove-group { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + color: $es-text-muted; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + &:hover { + background: $es-danger-light; + color: $es-danger; + } + } + + // Group include section - green accent to distinguish from exclude + .group-include { + margin-bottom: $es-spacing-md; + padding: $es-spacing-sm; + background: rgba($es-success, 0.03); + border: 1px solid rgba($es-success, 0.2); + border-radius: $es-radius-md; + } + + .section-row { + display: flex; + flex-direction: column; + gap: $es-spacing-sm; + } + + // Method selector wrapper (from PHP) + .method-selector-wrapper { + display: flex; + align-items: center; + gap: $es-spacing-sm; + } + + .method-info-placeholder { + display: flex; + align-items: center; + min-width: 20px; + } + + .include-method-select, + .exclude-method-select { + flex: 1; + @include input-base; + cursor: pointer; + } + + // Lock indicator for method selector (when excludes are present) + .selector-locked { + .include-method-select { + opacity: 0.7; + cursor: not-allowed; + } + } + + .lock-indicator { + display: inline-flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + color: $es-warning; + cursor: help; + + i { + font-size: 16px !important; + } + + .mpr-tooltip { + display: none; + position: absolute; + bottom: calc(100% + 8px); + left: 50%; + transform: translateX(-50%); + padding: $es-spacing-xs $es-spacing-sm; + background: $es-slate-800; + color: $es-white; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-normal; + white-space: nowrap; + border-radius: $es-radius-sm; + z-index: 100; + } + + &:hover .mpr-tooltip { + display: block; + } + } + + // Group excludes section + .group-excludes { + margin-top: $es-spacing-md; + } + + .except-separator { + display: flex; + align-items: center; + gap: $es-spacing-sm; + margin: 0 0 $es-spacing-sm 0; + + // Lines on both sides + &::before, + &::after { + content: ''; + flex: 1; + height: 1px; + background: rgba($es-danger, 0.3); + } + } + + .except-label { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.75rem; + background: $es-danger-light; + color: $es-danger; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-semibold; + border-radius: $es-radius-full; + white-space: nowrap; + flex-shrink: 0; + + i { + font-size: 12px !important; + } + } + + .exclude-rows-container { + display: flex; + flex-direction: column; + gap: $es-spacing-sm; + } + + .exclude-row { + display: flex; + flex-direction: column; + padding: $es-spacing-sm; + background: rgba($es-danger, 0.03); + border: 1px solid rgba($es-danger, 0.15); + border-radius: $es-radius-md; + + // Value picker inside exclude row - full width + .value-picker { + width: 100%; + margin-top: $es-spacing-sm; + } + } + + .exclude-header-row { + display: flex; + align-items: center; + justify-content: space-between; + gap: $es-spacing-sm; + width: 100%; + + .method-selector-wrapper { + flex: 1; + } + + // Delete button at the far right + .btn-remove-exclude-row { + flex-shrink: 0; + margin-left: auto; + } + } + + .btn-remove-exclude-row { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + color: $es-text-muted; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + &:hover { + background: $es-danger-light; + color: $es-danger; + } + } + + .btn-add-exclude, + .btn-add-another-exclude { + @include button-reset; + display: inline-flex; + align-items: center; + gap: 0.25rem; + margin-top: $es-spacing-sm; + padding: 0.375rem 0.625rem; + color: $es-danger; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + background: transparent; + border: 1px dashed rgba($es-danger, 0.5); + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + &:hover { + background: $es-danger-light; + border-color: $es-danger; + } + + i { + font-size: 12px !important; + } + } + + // Group modifiers (inline version from PHP) + // Uses negative margins to break out of .group-body padding + // Elements use .mpr-input-compact class to opt out of admin.css global sizing + .group-modifiers { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: $es-spacing-md; + padding: $es-spacing-sm $es-spacing-md; + margin: $es-spacing-md (-$es-spacing-md) (-$es-spacing-md); + background: $es-slate-50; + border-top: 1px solid $es-border-color; + border-radius: 0 0 $es-radius-lg $es-radius-lg; + } + + .modifier-inline { + display: inline-flex; + align-items: center; + gap: 0.375rem; + flex-shrink: 0; + } + + // Common height for all modifier controls + $modifier-height: 26px; + + .group-modifier-limit { + width: 50px; + max-width: 50px; + min-width: 50px; + height: $modifier-height; + padding: 0 0.375rem; + font-size: $es-font-size-xs; + text-align: center; + border: 1px solid $es-border-color; + border-radius: $es-radius-sm; + box-sizing: border-box; + + &:focus { + border-color: $es-primary; + outline: none; + } + } + + // Sort modifier - input group style (select + button glued together) + .modifier-sort { + gap: 0; // Remove gap to glue select + button together + + .modifier-label { + margin-right: 0.375rem; // Keep space between label and input group + } + + .group-modifier-sort { + width: auto; + height: $modifier-height; + padding: 0 1.25rem 0 0.5rem; + font-size: $es-font-size-xs; + border: 1px solid $es-border-color; + border-radius: $es-radius-sm 0 0 $es-radius-sm; + border-right: none; + cursor: pointer; + box-sizing: border-box; + + &:focus { + border-color: $es-primary; + outline: none; + position: relative; + z-index: 1; + } + } + + .btn-sort-dir { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: $modifier-height; + height: $modifier-height; + color: $es-text-muted; + background: $es-slate-100; + border: 1px solid $es-border-color; + border-radius: 0 $es-radius-sm $es-radius-sm 0; + transition: all $es-transition-fast; + + &:hover { + background: $es-slate-200; + color: $es-text-secondary; + } + + i { + font-size: 14px !important; + } + } + } + + // Fallback for elements outside .modifier-sort context + .group-modifier-sort { + height: $modifier-height; + padding: 0 0.5rem; + font-size: $es-font-size-xs; + border: 1px solid $es-border-color; + border-radius: $es-radius-sm; + cursor: pointer; + + &:focus { + border-color: $es-primary; + outline: none; + } + } + + .btn-sort-dir { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: $modifier-height; + height: $modifier-height; + color: $es-text-muted; + border: 1px solid $es-border-color; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + &:hover { + background: $es-slate-100; + color: $es-text-secondary; + } + } + + .group-preview-badge { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + background: $es-slate-100; + color: $es-text-muted; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + border-radius: $es-radius-full; + transition: all $es-transition-fast; + + &.clickable { + cursor: pointer; + + &:hover { + background: $es-primary-light; + color: $es-primary; + } + } + } + + // OR separator between groups + .group-separator { + display: flex; + align-items: center; + justify-content: center; + padding: $es-spacing-sm 0; + color: $es-text-muted; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-semibold; + text-transform: uppercase; + letter-spacing: 0.1em; + + &::before, + &::after { + content: ''; + flex: 1; + height: 1px; + background: $es-border-color; + margin: 0 $es-spacing-md; + } + } + + // Group modifiers (limit, sort) + .group-modifiers { + display: flex; + flex-wrap: wrap; + gap: $es-spacing-md; + padding-top: $es-spacing-md; + margin-top: $es-spacing-md; + border-top: 1px solid $es-border-color; + } + + .modifier-group { + display: flex; + align-items: center; + gap: $es-spacing-sm; + } + + .modifier-label { + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + color: $es-text-muted; + white-space: nowrap; + } + + .modifier-input { + @include input-base; + width: 80px; + padding: 0.25rem 0.5rem; + font-size: $es-font-size-xs; + } + + .modifier-select { + @include input-base; + width: auto; + padding: 0.25rem 1.5rem 0.25rem 0.5rem; + font-size: $es-font-size-xs; + cursor: pointer; + appearance: none; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E"); + background-position: right 0.25rem center; + background-repeat: no-repeat; + background-size: 1.25em 1.25em; + } + + // Condition match count badge + .condition-match-count { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.125rem 0.375rem; + background: $es-slate-100; + color: $es-text-muted; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + border-radius: $es-radius-full; + cursor: pointer; + transition: all $es-transition-fast; + + &:hover { + background: $es-slate-200; + } + + &.has-results { + background: $es-primary-light; + color: $es-primary; + } + + // Country holidays variant - use calendar icon style + &.country-holidays { + background: rgba(139, 92, 246, 0.1); + color: #8b5cf6; + + &:hover { + background: rgba(139, 92, 246, 0.2); + } + + &.clickable { + background: rgba(139, 92, 246, 0.15); + } + } + + i { + font-size: 12px !important; + } + } +} diff --git a/sources/sources/scss/components/_list-preview.scss b/sources/sources/scss/components/_list-preview.scss new file mode 100644 index 0000000..fd1e064 --- /dev/null +++ b/sources/sources/scss/components/_list-preview.scss @@ -0,0 +1,644 @@ +/** + * List Preview Component + * Popover and modal views for entity preview + * + * Uses shared entity-item base for item styling. + * This file only contains popover/modal container styles. + */ + +@use '../variables' as *; +@use '../mixins' as *; + +// ============================================================================= +// Preview Popover Container +// ============================================================================= + +.target-preview-popover, +.target-list-preview-popover { + position: absolute; + z-index: 10000; + min-width: 320px; + max-width: 480px; + background: $es-white; + border: 1px solid $es-border-color; + border-radius: $es-radius-lg; + box-shadow: $es-shadow-lg; + overflow: hidden; + + // Arrow pointing to badge + &::before { + content: ''; + position: absolute; + top: -8px; + left: 50%; + transform: translateX(-50%); + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-bottom: 8px solid $es-border-color; + } + + &::after { + content: ''; + position: absolute; + top: -6px; + left: 50%; + transform: translateX(-50%); + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid $es-white; + } + + // Positioned to the right - arrow on left + &.position-right { + &::before, + &::after { + left: 20px; + transform: none; + } + } + + // Positioned to the left - arrow on right + &.position-left { + &::before, + &::after { + left: auto; + right: 20px; + transform: none; + } + } +} + +// ============================================================================= +// Preview Header +// ============================================================================= + +.preview-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: $es-spacing-sm $es-spacing-md; + background: $es-bg-header; + border-bottom: 1px solid $es-border-color; + + .preview-title { + font-size: $es-font-size-sm; + font-weight: $es-font-weight-semibold; + color: $es-text-primary; + } + + .preview-close { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + color: $es-text-muted; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + &:hover { + background: $es-slate-200; + color: $es-text-primary; + } + } +} + +// ============================================================================= +// Preview Tabs (entity type switcher) +// ============================================================================= + +.preview-tabs { + display: flex; + flex-wrap: wrap; + gap: 0; + padding: 0; + background: $es-slate-50; + border-bottom: 1px solid $es-border-color; +} + +.preview-tab { + display: flex; + align-items: center; + gap: 0.375rem; + padding: 0.5rem 0.75rem; + background: transparent; + border: 0; + border-bottom: 2px solid transparent; + margin-bottom: -1px; + color: $es-text-muted; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + cursor: pointer; + transition: all $es-transition-fast; + white-space: nowrap; + + &:hover { + background: $es-slate-100; + color: $es-text-secondary; + } + + &.active { + background: $es-white; + border-bottom-color: $es-primary; + color: $es-primary; + } + + i { + font-size: 12px; + } +} + +// ============================================================================= +// Preview Filter +// ============================================================================= + +.preview-filter { + display: flex; + align-items: center; + gap: $es-spacing-sm; + padding: $es-spacing-sm $es-spacing-md; + background: $es-white; + border-bottom: 1px solid $es-border-color; + + i { + color: $es-text-muted; + font-size: 12px; + } + + .preview-filter-input { + all: unset; + flex: 1; + padding: 0.25rem 0; + font-size: $es-font-size-xs; + color: $es-text-primary; + box-sizing: border-box; + + &::placeholder { + color: $es-text-muted; + } + } +} + +// ============================================================================= +// Preview Contents (tabbed content areas) +// ============================================================================= + +.preview-contents { + max-height: 350px; + overflow: hidden; +} + +.preview-content { + display: none; + max-height: 350px; + overflow-y: auto; + @include custom-scrollbar; + + &.active { + display: block; + } +} + +// ============================================================================= +// Preview Items Container +// ============================================================================= + +.preview-items { + display: flex; + flex-direction: column; + padding: $es-spacing-xs $es-spacing-sm; +} + +// ============================================================================= +// Preview Item - Uses entity-item patterns +// Maps legacy classes to shared styling +// ============================================================================= + +.preview-item { + display: flex; + align-items: center; + gap: $es-spacing-sm; + padding: $es-spacing-sm; + background: $es-white; + border-radius: $es-radius-sm; + transition: background $es-transition-fast; + + &:hover { + background: $es-bg-hover; + } + + // Clickable items + &[data-id] { + cursor: pointer; + } +} + +// Image - matches chip image sizing for consistency +.preview-item-image { + flex-shrink: 0; + width: 32px; + height: 32px; + object-fit: cover; + border-radius: $es-radius-sm; + background: $es-slate-100; +} + +// No-image placeholder +.preview-item-no-image { + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + width: 32px; + height: 32px; + background: $es-slate-100; + color: $es-text-muted; + border-radius: $es-radius-sm; + font-size: $es-font-size-sm; +} + +// Info container +.preview-item-info { + flex: 1; + min-width: 0; + display: flex; + flex-direction: column; + gap: 0.125rem; +} + +// Name +.preview-item-name { + font-size: $es-font-size-sm; + font-weight: $es-font-weight-medium; + color: $es-text-primary; + @include text-truncate; +} + +// Meta/ref (category, email, etc.) +.preview-item-ref, +.preview-item-meta { + font-size: $es-font-size-xs; + color: $es-text-muted; + @include text-truncate; +} + +// Price badge +.preview-item-price { + flex-shrink: 0; + padding: 0.25rem 0.5rem; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-semibold; + color: $es-primary; + background: $es-primary-light; + border-radius: $es-radius-sm; +} + +// ============================================================================= +// Preview Footer (load more) +// ============================================================================= + +.preview-footer { + padding: $es-spacing-sm $es-spacing-md; + background: $es-slate-50; + border-top: 1px solid $es-border-color; +} + +.load-more-controls { + display: flex; + align-items: center; + justify-content: center; + gap: $es-spacing-sm; + font-size: $es-font-size-xs; + color: $es-text-muted; + + .load-more-label { + white-space: nowrap; + } + + .load-more-select { + appearance: none; + padding: 0.25rem 1.75rem 0.25rem 0.5rem; + border: 1px solid $es-border-color; + border-radius: $es-radius-sm; + 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; + background-size: 8px; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + color: $es-primary; + cursor: pointer; + transition: all $es-transition-fast; + height: auto; + min-height: 0; + line-height: 1.3; + + &:hover { + border-color: $es-primary; + background-color: $es-primary-light; + } + + &:focus { + outline: none; + border-color: $es-primary; + box-shadow: 0 0 0 2px rgba($es-primary, 0.1); + } + } + + .load-more-of { + white-space: nowrap; + } + + .remaining-count { + font-weight: $es-font-weight-semibold; + color: $es-text-secondary; + } + + .btn-load-more { + display: flex; + align-items: center; + justify-content: center; + padding: $es-spacing-xs; + margin: 0; + border: none; + color: $es-primary; + background: $es-primary-light; + border-radius: $es-radius-sm; + cursor: pointer; + transition: all $es-transition-fast; + font: inherit; + + i { + font-size: 14px; + } + + &:hover { + background: rgba($es-primary, 0.2); + } + + &.loading { + cursor: wait; + + i { + animation: spin 0.6s linear infinite; + } + } + } +} + +// ============================================================================= +// Preview States +// ============================================================================= + +.preview-empty { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: $es-spacing-sm; + padding: $es-spacing-xl; + text-align: center; + color: $es-text-muted; + + i { + font-size: 2rem; + opacity: 0.5; + } + + p { + margin: 0; + font-size: $es-font-size-sm; + } +} + +.preview-loading { + display: flex; + align-items: center; + justify-content: center; + padding: $es-spacing-xl; + color: $es-text-muted; + + i { + font-size: 20px; + color: $es-primary; + animation: spin 0.6s linear infinite; + } +} + +// ============================================================================= +// Total Summary Popover (header total badge click) +// ============================================================================= + +.total-preview-popover { + min-width: 240px; + max-width: 320px; + + .preview-popover-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: $es-spacing-md; + padding: $es-spacing-sm $es-spacing-md; + background: $es-bg-header; + border-bottom: 1px solid $es-border-color; + + .preview-popover-title { + font-weight: $es-font-weight-semibold; + color: $es-text-primary; + font-size: $es-font-size-sm; + } + + .preview-popover-count { + flex-shrink: 0; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + color: $es-text-muted; + background: $es-slate-200; + padding: 0.125rem 0.5rem; + border-radius: $es-radius-sm; + } + } + + .preview-popover-body { + padding: $es-spacing-xs 0; + } + + .total-summary-list { + list-style: none; + margin: 0; + padding: 0; + } + + .total-summary-item { + display: flex; + align-items: center; + gap: $es-spacing-sm; + padding: $es-spacing-sm $es-spacing-md; + cursor: pointer; + transition: background-color 0.15s ease; + + &:hover { + background: $es-slate-50; + } + + i { + width: 18px; + text-align: center; + color: $es-text-muted; + font-size: 14px; + } + + .summary-item-label { + flex: 1; + font-size: $es-font-size-sm; + color: $es-text-primary; + } + + .summary-item-count { + font-size: $es-font-size-sm; + font-weight: $es-font-weight-semibold; + color: $es-primary; + background: rgba($es-primary, 0.1); + padding: 2px 8px; + border-radius: $es-radius-sm; + } + } +} + +// Make trait-total-count clickable +.trait-total-count { + cursor: pointer; + transition: all 0.15s ease; + + &:hover { + opacity: 0.8; + } + + &.popover-open { + opacity: 0.9; + } +} + +// ============================================================================= +// Schedule Dropdown Preview +// Inline dropdown for schedule details in admin list +// ============================================================================= + +.mpr-dropdown-preview { + display: none; + position: absolute; + top: 100%; + left: 50%; + transform: translateX(-50%); + margin-top: 6px; + z-index: 1000; + padding: 0.625rem 0.75rem; + background: $es-white; + border: 1px solid $es-border-color; + border-radius: $es-radius-lg; + box-shadow: $es-shadow-lg; + font-size: 12px; + text-align: left; + text-transform: none; + font-weight: normal; + white-space: nowrap; // Allow dropdown to grow as needed + + &.is-open { + display: block; + } +} + +.mpr-dropdown-preview__item { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.375rem 0; + color: #666; + line-height: 1.4; + + &:not(:last-child) { + margin-bottom: 0.25rem; + padding-bottom: 0.5rem; + border-bottom: 1px solid rgba($es-border-color, 0.5); + } + + // Icon styles + > .material-icons, + > i:first-child { + flex-shrink: 0; + width: 16px; + font-size: 14px !important; + color: #999; + text-align: center; + } +} + +.mpr-dropdown-preview__muted { + color: #999; +} + +// Schedule inline layout +.mpr-dropdown-preview__schedule { + display: inline; +} + +.mpr-dropdown-preview__schedule-row { + display: inline; + + &:not(:last-child)::after { + content: ','; + margin-right: 0.5rem; + } +} + +.mpr-dropdown-preview__day { + color: #666; +} + +.mpr-dropdown-preview__hours { + color: $es-primary; + font-weight: 500; + margin-left: 0.25rem; +} + +// Badge trigger for preview dropdown/popover +.mpr-badge--preview { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.25rem; + position: relative; + min-width: 20px; + height: 20px; + padding: 0 0.5rem; + font-size: 0.75rem; + font-weight: 600; + border-radius: 50rem; + cursor: pointer; + text-transform: none; + + .material-icons { + font-size: 12px !important; + line-height: 1; + opacity: 0.8; + } +} + +.mpr-badge--preview-primary { + background: $es-primary; + color: $es-white; +} + +.mpr-badge--preview-success { + background: #d4edda; + color: #155724; +} + +.mpr-badge--preview-warning { + background: #fff3cd; + color: #856404; +} + +.mpr-badge--preview-muted { + background: $es-slate-200; + color: $es-text-muted; +} diff --git a/sources/sources/scss/components/_method-dropdown.scss b/sources/sources/scss/components/_method-dropdown.scss new file mode 100644 index 0000000..9d31d11 --- /dev/null +++ b/sources/sources/scss/components/_method-dropdown.scss @@ -0,0 +1,225 @@ +/** + * Method Dropdown Component + * Custom select dropdown with icons for method selection + */ + +@use '../variables' as *; +@use '../mixins' as *; + +.target-conditions-trait, +.entity-selector-trait { + + // Method dropdown trigger button + .method-dropdown-trigger { + display: inline-flex; + align-items: center; + gap: 0.5rem; + height: 36px; + padding: 0 $es-spacing-md; + border-radius: $es-radius-md; + background: $es-white; + color: $es-slate-800; + font-size: $es-font-size-sm; + cursor: pointer; + transition: all $es-transition-fast; + min-width: 180px; + max-width: 320px; + border: 1px solid $es-border-color; + + &:hover { + background: $es-slate-50; + border-color: $es-gray-300; + } + + &:focus, + &:active { + outline: none; + border-color: $es-primary; + box-shadow: 0 0 0 3px rgba($es-primary, 0.1); + } + } + + .method-trigger-icon { + font-size: $es-font-size-sm; + color: $es-text-muted; + flex-shrink: 0; + width: 18px; + text-align: center; + } + + .method-trigger-label { + flex: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + font-weight: $es-font-weight-medium; + } + + .method-trigger-caret { + font-size: $es-font-size-xs; + color: $es-slate-400; + flex-shrink: 0; + margin-left: auto; + } + + // Locked state + .selector-locked .method-dropdown-trigger { + background: $es-slate-100; + color: $es-slate-400; + cursor: not-allowed; + border-color: $es-border-color; + + &:hover { + background: $es-slate-100; + border-color: $es-border-color; + } + } + + // Method selector wrapper + .method-selector-wrapper { + position: relative; + } + + // Hidden select (for form submission) + .method-select-hidden { + position: absolute !important; + opacity: 0 !important; + pointer-events: none !important; + width: 0 !important; + height: 0 !important; + overflow: hidden !important; + } +} + +// Global fallback for hidden method selects +.method-select-hidden { + position: absolute !important; + opacity: 0 !important; + pointer-events: none !important; + width: 0 !important; + height: 0 !important; + overflow: hidden !important; +} + +// ============================================================================= +// Method Dropdown Menu (appended to body, outside trait wrappers) +// ============================================================================= + +.method-dropdown-menu { + position: absolute; + z-index: $es-z-dropdown + 1; + min-width: 200px; + max-width: 360px; + max-height: 400px; + overflow-y: auto; + background: $es-white; + border-radius: $es-radius-lg; + padding: 0.375rem 0; + border: 1px solid $es-border-color; + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15); + animation: methodDropdownFadeIn 0.15s ease; + @include custom-scrollbar; +} + +@keyframes methodDropdownFadeIn { + from { + opacity: 0; + transform: translateY(-4px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +// Method dropdown item +.method-dropdown-item { + display: flex; + align-items: center; + gap: 0.625rem; + padding: 0.5rem $es-spacing-md; + cursor: pointer; + transition: background-color 0.1s; + position: relative; + + &:hover { + background: $es-slate-100; + } + + &.selected { + background: rgba($es-primary, 0.08); + } + + .method-item-icon { + font-size: $es-font-size-sm; + color: $es-text-muted; + width: 18px; + text-align: center; + flex-shrink: 0; + } + + &.selected .method-item-icon { + color: $es-primary; + } + + .method-item-label { + flex: 1; + font-size: $es-font-size-sm; + color: $es-slate-700; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + &.selected .method-item-label { + color: $es-cyan-700; + font-weight: $es-font-weight-medium; + } + + .method-item-check { + font-size: $es-font-size-xs; + flex-shrink: 0; + margin-left: auto; + color: $es-primary; + } +} + +// Method dropdown optgroup +.method-dropdown-optgroup { + margin-top: 0.25rem; + + &:first-child { + margin-top: 0; + } +} + +.method-optgroup-label { + padding: 0.5rem $es-spacing-md; + font-size: 11px; + font-weight: $es-font-weight-semibold; + color: $es-text-muted; + text-transform: uppercase; + letter-spacing: 0.05em; + background: $es-slate-50; + border-top: 1px solid $es-slate-100; + border-bottom: 1px solid $es-slate-100; + + .method-dropdown-optgroup:first-child & { + border-top: 0; + } +} + +.method-optgroup-items { + padding: 0.25rem 0; + + .method-dropdown-item { + padding-left: $es-spacing-lg; + } +} + +// Method info placeholder +.method-info-placeholder { + font-size: $es-font-size-xs; + color: $es-text-muted; + font-style: italic; +} diff --git a/sources/sources/scss/components/_modal.scss b/sources/sources/scss/components/_modal.scss new file mode 100644 index 0000000..9d699e0 --- /dev/null +++ b/sources/sources/scss/components/_modal.scss @@ -0,0 +1,488 @@ +/** + * Modal Component + * Preview modals, confirmation dialogs + */ + +@use "sass:color"; +@use '../variables' as *; +@use '../mixins' as *; + +// Modal backdrop +.mpr-modal-backdrop { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); + z-index: $es-z-modal; + opacity: 0; + transition: opacity $es-transition-normal; + + &.show { + opacity: 1; + } +} + +// Modal container +.mpr-modal { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%) scale(0.95); + z-index: $es-z-modal + 1; + width: 90%; + max-width: 600px; + max-height: 90vh; + background: $es-white; + border-radius: $es-radius-xl; + box-shadow: $es-shadow-xl; + opacity: 0; + transition: all $es-transition-normal; + overflow: hidden; + display: flex; + flex-direction: column; + + &.show { + opacity: 1; + transform: translate(-50%, -50%) scale(1); + } + + &.modal-sm { + max-width: 400px; + } + + &.modal-lg { + max-width: 800px; + } + + &.modal-xl { + max-width: 1000px; + } + + &.modal-fullscreen { + width: 95%; + max-width: none; + height: 90vh; + max-height: none; + } +} + +// Modal header +.mpr-modal-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: $es-spacing-md; + padding: $es-spacing-md $es-spacing-lg; + background: $es-bg-header; + border-bottom: 1px solid $es-border-color; + flex-shrink: 0; +} + +.mpr-modal-title { + font-size: $es-font-size-base; + font-weight: $es-font-weight-semibold; + color: $es-text-primary; + margin: 0; +} + +.mpr-modal-close { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + color: $es-text-muted; + border-radius: $es-radius-md; + transition: all $es-transition-fast; + + &:hover { + background: $es-slate-200; + color: $es-text-secondary; + } + + i { + font-size: $es-font-size-lg; + } +} + +// Modal body +.mpr-modal-body { + flex: 1; + overflow-y: auto; + padding: $es-spacing-lg; + @include custom-scrollbar; +} + +// Modal footer +.mpr-modal-footer { + display: flex; + align-items: center; + justify-content: flex-end; + gap: $es-spacing-sm; + padding: $es-spacing-md $es-spacing-lg; + background: $es-bg-header; + border-top: 1px solid $es-border-color; + flex-shrink: 0; +} + +.mpr-modal-btn { + @include button-reset; + display: inline-flex; + align-items: center; + justify-content: center; + gap: $es-spacing-xs; + padding: $es-spacing-sm $es-spacing-md; + font-size: $es-font-size-sm; + font-weight: $es-font-weight-medium; + border-radius: $es-radius-md; + transition: all $es-transition-fast; + + &.btn-secondary { + color: $es-text-secondary; + background: $es-slate-100; + + &:hover { + background: $es-slate-200; + } + } + + &.btn-primary { + color: $es-white; + background: $es-primary; + + &:hover { + background: $es-primary-hover; + } + } + + &.btn-danger { + color: $es-white; + background: $es-danger; + + &:hover { + background: color.adjust($es-danger, $lightness: -10%); + } + } + + &:disabled { + opacity: 0.5; + cursor: not-allowed; + } +} + +// Preview popover styles moved to _list-preview.scss + +.popover-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: $es-spacing-sm; + padding: $es-spacing-sm $es-spacing-md; + background: $es-bg-header; + border-bottom: 1px solid $es-border-color; + border-radius: $es-radius-lg $es-radius-lg 0 0; +} + +.popover-title { + font-size: $es-font-size-sm; + font-weight: $es-font-weight-semibold; + color: $es-text-primary; +} + +.popover-close { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + color: $es-text-muted; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + &:hover { + background: $es-slate-200; + color: $es-text-secondary; + } +} + +.popover-body { + max-height: 300px; + overflow-y: auto; + padding: $es-spacing-sm; + @include custom-scrollbar; +} + +.popover-footer { + display: flex; + align-items: center; + justify-content: space-between; + gap: $es-spacing-sm; + padding: $es-spacing-sm $es-spacing-md; + background: $es-bg-header; + border-top: 1px solid $es-border-color; + border-radius: 0 0 $es-radius-lg $es-radius-lg; +} + +.popover-info { + font-size: $es-font-size-xs; + color: $es-text-muted; +} + +.popover-load-more { + @include button-reset; + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + color: $es-primary; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + &:hover { + background: $es-primary-light; + } +} + +// Popover arrow +.popover-arrow { + position: absolute; + width: 12px; + height: 12px; + background: $es-white; + border: 1px solid $es-border-color; + transform: rotate(45deg); + + &.arrow-top { + top: -7px; + left: 50%; + margin-left: -6px; + border-right: none; + border-bottom: none; + } + + &.arrow-bottom { + bottom: -7px; + left: 50%; + margin-left: -6px; + border-left: none; + border-top: none; + } +} + +// ========================================================================== +// Holiday Preview Modal +// ========================================================================== + +#mpr-holiday-preview-modal { + display: none; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: $es-z-modal; + + &.show { + display: flex; + align-items: center; + justify-content: center; + } + + .mpr-modal-backdrop { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); + cursor: pointer; + } + + .mpr-modal-dialog { + position: relative; + width: 90%; + max-width: 480px; + max-height: 80vh; + background: $es-white; + border-radius: $es-radius-lg; + box-shadow: $es-shadow-xl; + display: flex; + flex-direction: column; + overflow: hidden; + } + + .mpr-modal-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: $es-spacing-md; + padding: $es-spacing-md $es-spacing-lg; + background: $es-bg-header; + border-bottom: 1px solid $es-border-color; + flex-shrink: 0; + } + + .mpr-modal-title { + display: flex; + align-items: center; + gap: $es-spacing-sm; + font-size: $es-font-size-base; + font-weight: $es-font-weight-semibold; + color: $es-text-primary; + margin: 0; + + i.material-icons { + font-size: 20px !important; + color: $es-primary; + } + } + + .mpr-modal-close { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + color: $es-text-muted; + border-radius: $es-radius-md; + transition: all $es-transition-fast; + + &:hover { + background: $es-slate-200; + color: $es-text-secondary; + } + + i { + font-size: 18px; + } + } + + .mpr-modal-body { + flex: 1; + overflow-y: auto; + padding: $es-spacing-lg; + @include custom-scrollbar; + } + + // Loading state + .holiday-preview-loading { + display: flex; + align-items: center; + justify-content: center; + gap: $es-spacing-sm; + padding: $es-spacing-xl 0; + color: $es-text-muted; + font-size: $es-font-size-sm; + + i { + font-size: $es-font-size-lg; + } + } + + // Empty state + .holiday-preview-empty { + text-align: center; + padding: $es-spacing-xl 0; + color: $es-text-muted; + + i.material-icons { + font-size: 48px !important; + opacity: 0.5; + margin-bottom: $es-spacing-md; + } + + p { + margin: 0 0 $es-spacing-xs; + } + + .hint { + font-size: $es-font-size-xs; + color: $es-text-muted; + } + } + + // Holiday list + .holiday-list { + display: flex; + flex-direction: column; + gap: $es-spacing-sm; + } + + .holiday-item { + display: flex; + align-items: flex-start; + gap: $es-spacing-md; + padding: $es-spacing-sm $es-spacing-md; + background: $es-slate-50; + border-radius: $es-radius-md; + border-left: 3px solid $es-success; + + &.holiday-type-bank { + border-left-color: $es-info; + } + + &.holiday-type-observance { + border-left-color: $es-warning; + } + + &.holiday-type-regional { + border-left-color: #8b5cf6; + } + } + + .holiday-date { + flex-shrink: 0; + min-width: 100px; + + .holiday-day { + display: block; + font-size: $es-font-size-sm; + font-weight: $es-font-weight-semibold; + color: $es-text-primary; + } + + .holiday-weekday { + display: block; + font-size: $es-font-size-xs; + color: $es-text-muted; + } + } + + .holiday-info { + flex: 1; + min-width: 0; + } + + .holiday-name { + display: block; + font-size: $es-font-size-sm; + color: $es-text-primary; + word-wrap: break-word; + } + + .holiday-type-badge { + display: inline-block; + margin-top: $es-spacing-xs; + padding: 0.125rem 0.375rem; + font-size: 10px; + font-weight: $es-font-weight-medium; + text-transform: capitalize; + background: $es-slate-200; + color: $es-text-secondary; + border-radius: $es-radius-sm; + } + + .holiday-preview-note { + margin-top: $es-spacing-md; + font-size: $es-font-size-xs; + color: $es-text-muted; + text-align: center; + } +} diff --git a/sources/sources/scss/components/_schedule.scss b/sources/sources/scss/components/_schedule.scss new file mode 100644 index 0000000..e6d1c7f --- /dev/null +++ b/sources/sources/scss/components/_schedule.scss @@ -0,0 +1,369 @@ +/** + * Schedule Conditions Component + * DateTime picker, weekly timeline, holidays + */ + +@use '../variables' as *; +@use '../mixins' as *; + +// Schedule conditions wrapper +.schedule-conditions-trait { + background: $es-white; + border: 1px solid $es-border-color; + border-radius: $es-radius-lg; +} + +// Schedule header +.schedule-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: $es-spacing-md; + padding: 0.875rem $es-spacing-md; + background: $es-bg-header; + border-bottom: 1px solid $es-border-color; + border-radius: $es-radius-lg $es-radius-lg 0 0; + cursor: pointer; + user-select: none; + transition: background-color $es-transition-fast; + + &:hover { + background: $es-bg-hover; + } +} + +.schedule-title { + display: flex; + align-items: center; + gap: 0.75rem; + font-size: $es-font-size-sm; + font-weight: $es-font-weight-semibold; + color: $es-text-primary; + + i { + color: $es-text-muted; + } +} + +// Schedule body +.schedule-body { + padding: $es-spacing-md; +} + +// Schedule section +.schedule-section { + margin-bottom: $es-spacing-lg; + + &:last-child { + margin-bottom: 0; + } +} + +.schedule-section-title { + display: flex; + align-items: center; + gap: $es-spacing-sm; + margin-bottom: $es-spacing-sm; + font-size: $es-font-size-sm; + font-weight: $es-font-weight-semibold; + color: $es-text-primary; + + i { + color: $es-text-muted; + } +} + +.schedule-section-description { + margin-bottom: $es-spacing-md; + font-size: $es-font-size-xs; + color: $es-text-muted; +} + +// DateTime range picker +.datetime-range { + display: flex; + flex-wrap: wrap; + gap: $es-spacing-md; +} + +.datetime-field { + flex: 1; + min-width: 200px; +} + +.datetime-label { + display: block; + margin-bottom: 0.25rem; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + color: $es-text-secondary; +} + +.datetime-input { + @include input-base; +} + +// Weekly schedule +.weekly-schedule { + display: flex; + flex-direction: column; + gap: $es-spacing-sm; +} + +.day-row { + display: flex; + align-items: center; + gap: $es-spacing-md; + padding: $es-spacing-sm; + background: $es-slate-50; + border-radius: $es-radius-md; + + &.disabled { + opacity: 0.5; + } +} + +.day-toggle { + display: flex; + align-items: center; + gap: $es-spacing-sm; + min-width: 100px; +} + +.day-checkbox { + width: 18px; + height: 18px; + cursor: pointer; +} + +.day-name { + font-size: $es-font-size-sm; + font-weight: $es-font-weight-medium; + color: $es-text-primary; +} + +// Timeline slider +.timeline-slider { + flex: 1; + position: relative; + height: 24px; + background: $es-slate-200; + border-radius: $es-radius-full; + cursor: pointer; +} + +.timeline-fill { + position: absolute; + top: 0; + height: 100%; + background: $es-primary; + border-radius: $es-radius-full; + transition: all $es-transition-fast; +} + +.timeline-handle { + position: absolute; + top: 50%; + width: 16px; + height: 16px; + background: $es-white; + border: 2px solid $es-primary; + border-radius: 50%; + transform: translate(-50%, -50%); + cursor: grab; + box-shadow: $es-shadow-sm; + transition: box-shadow $es-transition-fast; + + &:hover { + box-shadow: $es-shadow-md; + } + + &:active { + cursor: grabbing; + } + + &.handle-start { + z-index: 2; + } + + &.handle-end { + z-index: 1; + } +} + +// Time display +.day-times { + display: flex; + align-items: center; + gap: $es-spacing-xs; + min-width: 120px; + font-size: $es-font-size-xs; + font-family: monospace; + color: $es-text-secondary; +} + +.time-separator { + color: $es-text-muted; +} + +// Holiday exclusions +.holiday-section { + padding: $es-spacing-md; + background: $es-slate-50; + border-radius: $es-radius-md; +} + +.holiday-toggle { + display: flex; + align-items: center; + gap: $es-spacing-sm; + margin-bottom: $es-spacing-md; +} + +.holiday-checkbox { + width: 18px; + height: 18px; + cursor: pointer; +} + +.holiday-label { + font-size: $es-font-size-sm; + font-weight: $es-font-weight-medium; + color: $es-text-primary; +} + +.holiday-countries { + display: flex; + flex-wrap: wrap; + gap: $es-spacing-xs; +} + +.holiday-country-chip { + @include chip; + cursor: pointer; + + &.selected { + background: $es-primary-light; + color: $es-primary; + } +} + +// Server time display +.server-time { + display: flex; + align-items: center; + gap: $es-spacing-sm; + padding: $es-spacing-sm $es-spacing-md; + background: $es-info-light; + border-radius: $es-radius-md; + font-size: $es-font-size-xs; + color: $es-info; + + i { + font-size: $es-font-size-sm; + } + + .time-value { + font-family: monospace; + font-weight: $es-font-weight-semibold; + } +} + +// Schedule summary +.schedule-summary { + display: flex; + flex-direction: column; + gap: $es-spacing-xs; + padding: $es-spacing-md; + background: $es-slate-50; + border-radius: $es-radius-md; + font-size: $es-font-size-sm; + color: $es-text-secondary; + + .summary-item { + display: flex; + align-items: center; + gap: $es-spacing-sm; + + i { + color: $es-success; + font-size: $es-font-size-sm; + } + + &.inactive i { + color: $es-text-muted; + } + } +} + +// Collapsed state +.schedule-conditions-trait.collapsed { + .schedule-body { + display: none; + } + + .schedule-header { + border-radius: $es-radius-lg; + } +} + +// Schedule toggle row (form-content layout) +.schedule-toggle-row { + display: flex; + align-items: center; + background: $es-slate-100; + border: 1px solid $es-border-color; + border-radius: $es-radius-lg; + + .schedule-toggle-switch { + padding: $es-spacing-sm $es-spacing-md; + } + + .schedule-toggle-actions { + padding: $es-spacing-sm $es-spacing-md; + border-left: 1px solid $es-border-color; + cursor: pointer; + transition: background-color $es-transition-fast; + + &:hover { + background: $es-slate-200; + } + + .material-icons { + color: $es-slate-400; + font-size: 20px !important; + } + } +} + +// Schedule summary badges (read-only indicators in header) +.schedule-summary-badges { + display: flex; + align-items: center; + gap: 0.5rem; + margin-left: auto; + padding: 0 $es-spacing-sm; +} + +.schedule-badge { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + background: $es-slate-200; + color: $es-slate-600; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + border-radius: $es-radius-full; + white-space: nowrap; + + .material-icons { + font-size: 14px !important; + opacity: 0.7; + } +} + +// Section hint after embedded entity selector - add margin +.schedule-holidays .section-hint { + margin-top: $es-spacing-md; +} diff --git a/sources/sources/scss/components/_tips.scss b/sources/sources/scss/components/_tips.scss new file mode 100644 index 0000000..8762bd5 --- /dev/null +++ b/sources/sources/scss/components/_tips.scss @@ -0,0 +1,142 @@ +/** + * Tips Box Component + * Pro tips and help information display + */ + +@use '../variables' as *; +@use '../mixins' as *; + +.target-conditions-trait, +.entity-selector-trait { + + // Tips box container + .target-tips-box { + margin: $es-spacing-lg $es-spacing-md $es-spacing-md; + border: 1px solid $es-border-color; + border-radius: $es-radius-lg; + overflow: hidden; + background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%); + } + + // Tips header (clickable to expand/collapse) + .tips-header { + display: flex; + align-items: center; + gap: 0.625rem; + padding: $es-spacing-md $es-spacing-lg; + cursor: pointer; + user-select: none; + transition: background-color $es-transition-fast; + + &:hover { + background: rgba(0, 0, 0, 0.02); + } + + // Lightbulb icon + > i:first-child { + font-size: 1rem; + color: $es-warning; + } + + // Title text + > span { + flex: 1; + font-size: 13px; + font-weight: $es-font-weight-semibold; + color: $es-slate-600; + } + } + + // Toggle chevron icon + .tips-toggle { + font-size: $es-font-size-xs; + color: $es-slate-400; + transition: transform 0.2s; + } + + // Expanded state + .target-tips-box.expanded { + .tips-toggle { + transform: rotate(180deg); + } + + .tips-content { + display: block; + } + } + + // Tips content (hidden by default) + .tips-content { + display: none; + padding: 0 $es-spacing-lg $es-spacing-lg; + } + + // Tips grid layout + .tips-grid { + display: grid; + gap: $es-spacing-md; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + } + + // Individual tip item + .tip-item { + display: flex; + gap: $es-spacing-md; + padding: $es-spacing-md; + background: $es-white; + border-radius: $es-radius-md; + border: 1px solid $es-border-color; + } + + // Tip icon + .tip-icon { + flex-shrink: 0; + width: 2rem; + height: 2rem; + display: flex; + align-items: center; + justify-content: center; + background: $es-primary-light; + border-radius: $es-radius-md; + color: $es-primary; + font-size: $es-font-size-sm; + } + + // Tip text content + .tip-text { + flex: 1; + min-width: 0; + + strong { + display: block; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-semibold; + color: $es-slate-700; + margin-bottom: 0.25rem; + } + + p { + font-size: 11px; + color: $es-text-muted; + line-height: 1.625; + margin: 0; + } + } + + // Tips footer + .tips-footer { + margin-top: $es-spacing-md; + padding: 0.625rem $es-spacing-md; + background: $es-white; + border-radius: $es-radius-md; + border: 1px dashed $es-gray-300; + font-size: 11px; + color: $es-text-muted; + line-height: 1.625; + + i { + color: $es-primary; + margin-right: 0.25rem; + } + } +} diff --git a/sources/sources/scss/components/_tooltip.scss b/sources/sources/scss/components/_tooltip.scss new file mode 100644 index 0000000..750d8b9 --- /dev/null +++ b/sources/sources/scss/components/_tooltip.scss @@ -0,0 +1,107 @@ +/** + * Tooltip Component + * Info tooltips for method help + */ + +@use '../variables' as *; + +// ============================================================================= +// Info Wrapper (tooltip trigger) +// ============================================================================= + +.mpr-info-wrapper { + display: inline-flex; + align-items: center; + position: relative; + cursor: help; + vertical-align: middle; + margin-left: 0.25rem; + + .material-icons { + font-size: 16px !important; + color: $es-text-muted; + transition: color 0.15s ease; + } + + &:hover .material-icons { + color: $es-primary; + } +} + +// ============================================================================= +// Fixed Tooltip (appended to body on hover) +// ============================================================================= + +.mpr-tooltip-fixed { + position: fixed; + background: $es-white; + color: $es-slate-800; + padding: $es-spacing-md $es-spacing-lg; + border-radius: $es-radius-md; + font-size: 13px; + line-height: 1.5; + white-space: normal; + z-index: 10500; + max-width: 320px; + min-width: 180px; + text-align: left; + box-shadow: rgba(0, 0, 0, 0.12) 0px 1px 1px 0px, + rgba(64, 68, 82, 0.16) 0px 0px 0px 1px, + rgba(64, 68, 82, 0.08) 0px 2px 5px 0px; + pointer-events: none; + + // Pinned tooltip allows interaction + &.pinned { + pointer-events: auto; + padding-right: $es-spacing-xl + 1rem; + } + + strong { + display: block; + margin-bottom: 0.375rem; + font-weight: $es-font-weight-semibold; + color: $es-primary; + } + + p { + margin: 0; + color: $es-text-secondary; + } + + ul { + margin: 0.5rem 0 0; + padding-left: 1.25rem; + + li { + margin: 0.25rem 0; + color: $es-text-secondary; + } + } +} + +// Close button for pinned tooltips +.mpr-tooltip-close { + position: absolute; + top: 0.375rem; + right: 0.375rem; + padding: 0.125rem; + border: none; + background: transparent; + cursor: pointer; + border-radius: $es-radius-sm; + line-height: 1; + transition: background-color 0.15s ease; + + .material-icons { + font-size: 16px !important; + color: $es-text-muted; + } + + &:hover { + background: $es-slate-100; + + .material-icons { + color: $es-slate-700; + } + } +} diff --git a/sources/sources/scss/components/_tree.scss b/sources/sources/scss/components/_tree.scss new file mode 100644 index 0000000..d6e9214 --- /dev/null +++ b/sources/sources/scss/components/_tree.scss @@ -0,0 +1,343 @@ +/** + * Category Tree Component + * Hierarchical tree view for category selection inside dropdown + */ + +@use "sass:color"; +@use '../variables' as *; +@use '../mixins' as *; + +// Category tree container (inside dropdown) +.category-tree { + display: flex; + flex-direction: column; +} + +// Tree toolbar inside dropdown +.category-tree .tree-toolbar { + display: flex; + align-items: center; + gap: $es-spacing-sm; + padding: $es-spacing-xs $es-spacing-sm; + background: $es-slate-50; + border-bottom: 1px solid $es-border-light; + flex-shrink: 0; + + .btn-expand-all, + .btn-collapse-all { + @include button-reset; + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: $es-spacing-xs $es-spacing-sm; + font-size: $es-font-size-xs; + font-weight: $es-font-weight-medium; + color: $es-text-secondary; + background: $es-white; + border: 1px solid $es-border-color; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + + &:hover { + background: $es-slate-100; + border-color: $es-slate-300; + } + + i { + font-size: 12px; + } + } +} + +// Tree items container +.category-tree .tree-items { + padding: 0; +} + +// Tree item +.tree-item { + display: flex; + align-items: center; + gap: $es-spacing-xs; + padding: $es-spacing-xs $es-spacing-sm; + cursor: pointer; + transition: background $es-transition-fast; + border-radius: 0; + + &:hover { + background: $es-slate-100; + } + + &.selected { + background: $es-primary-light; + + .tree-name { + font-weight: $es-font-weight-semibold; + color: $es-primary; + } + + .tree-checkbox { + color: $es-primary; + + i { + opacity: 1; + } + } + } + + &.inactive { + opacity: 0.6; + + .tree-name { + font-style: italic; + } + } + + &.filtered-out { + display: none; + } + + &.filter-match { + background: $es-warning-light; + + &.selected { + background: $es-primary-light; + } + } +} + +// All tree element styles nested under .category-tree for specificity +.category-tree { + // Tree indentation + .tree-indent { + flex-shrink: 0; + } + + // Tree toggle (expand/collapse) + .tree-toggle { + display: flex; + align-items: center; + justify-content: center; + width: 12px; + height: 12px; + box-sizing: border-box; + color: $es-text-secondary; + flex-shrink: 0; + border-radius: $es-radius-sm; + transition: all $es-transition-fast; + cursor: pointer; + + &:hover { + background: $es-slate-200; + color: $es-text-primary; + } + + &.tree-leaf { + cursor: default; + visibility: hidden; + + &:hover { + background: transparent; + } + } + + i { + font-size: 10px; + transition: transform $es-transition-fast; + } + } + + .tree-item.collapsed > .tree-toggle i { + transform: rotate(-90deg); + } + + // Tree checkbox indicator - 12x12 to match PrestaShop admin standards + .tree-checkbox { + display: flex; + align-items: center; + justify-content: center; + width: 12px; + height: 12px; + box-sizing: border-box; + flex-shrink: 0; + border: 1px solid $es-border-color; + border-radius: 2px; + background: $es-white; + + i { + font-size: 8px; + opacity: 0; + color: $es-white; + transition: opacity $es-transition-fast; + } + } + + .tree-item.selected .tree-checkbox { + background: $es-primary; + border-color: $es-primary; + + i { + opacity: 1; + } + } + + // Tree icon + .tree-icon { + display: flex; + align-items: center; + justify-content: center; + width: 12px; + height: 12px; + box-sizing: border-box; + color: $es-text-muted; + flex-shrink: 0; + + i { + font-size: 12px; // match visual weight of other icons + } + } + + .tree-item.selected .tree-icon { + color: $es-primary; + } + + // Tree name + .tree-name { + flex: 1; + font-size: $es-font-size-sm; + color: $es-text-primary; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + // Tree product/page count with preview + .tree-count { + @include count-badge($es-primary); + height: 18px; + min-width: 18px; + padding: 0 $es-spacing-sm; + + i { + font-size: 10px; + } + + &.clickable { + &.loading { + pointer-events: none; + + i { + animation: spin 1s linear infinite; + } + } + + &.popover-open { + background: color.adjust($es-primary, $lightness: -10%); + } + } + } + + // Select children button - positioned on the left next to toggle + .btn-select-children { + @include button-reset; + display: inline-flex; + align-items: center; + justify-content: center; + width: 12px; + height: 12px; + box-sizing: border-box; + color: $es-text-muted; + border-radius: $es-radius-sm; + opacity: 0.3; + transition: all $es-transition-fast; + flex-shrink: 0; + + i { + font-size: 14px; // larger to visually match other icons + } + + &:hover { + color: $es-primary; + opacity: 1; + } + } + + .tree-item:hover .btn-select-children { + opacity: 0.6; + } + + // Tree badge (inactive, etc.) + .tree-badge { + display: inline-flex; + align-items: center; + padding: 0.125rem $es-spacing-xs; + font-size: 9px; + font-weight: $es-font-weight-semibold; + text-transform: uppercase; + letter-spacing: 0.025em; + border-radius: $es-radius-sm; + flex-shrink: 0; + + &.inactive { + color: $es-warning; + background: $es-warning-light; + } + } + + // Tree children container + .tree-children { + display: block; + + &.filter-expanded { + display: block !important; + } + } + + .tree-item.collapsed + .tree-children { + display: none; + } + + // Filtering - must be inside .category-tree for specificity + .tree-item.filtered-out { + display: none !important; + } +} // end .category-tree + +// Loading/empty/error states +.category-tree .tree-loading, +.category-tree .dropdown-empty, +.category-tree .dropdown-error { + display: flex; + align-items: center; + justify-content: center; + padding: $es-spacing-xl; + color: $es-text-muted; + font-size: $es-font-size-sm; + + i { + margin-right: $es-spacing-sm; + } +} + +.category-tree .dropdown-error { + color: $es-danger; +} + +// Tree view mode in dropdown +.target-search-dropdown.view-tree { + .dropdown-results { + padding: 0; + } + + .category-tree { + max-height: 100%; + overflow-y: auto; + @include custom-scrollbar; + } + + .tree-items { + max-height: calc(100% - 40px); + overflow-y: auto; + @include custom-scrollbar; + } +} diff --git a/sources/sources/scss/components/_validation.scss b/sources/sources/scss/components/_validation.scss new file mode 100644 index 0000000..a076fb2 --- /dev/null +++ b/sources/sources/scss/components/_validation.scss @@ -0,0 +1,87 @@ +/** + * Validation Toast Component + * Error notifications for selection conflicts + */ + +@use '../variables' as *; +@use '../mixins' as *; + +// Validation error toast +.es-validation-toast { + display: flex; + align-items: flex-start; + gap: $es-spacing-sm; + padding: $es-spacing-md; + background: $es-white; + border: 1px solid $es-danger; + border-left: 4px solid $es-danger; + border-radius: $es-radius-md; + box-shadow: $es-shadow-lg; + max-width: 400px; + animation: es-toast-slide-in 0.2s ease-out; + + .es-toast-icon { + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + color: $es-danger; + flex-shrink: 0; + + i { + font-size: 18px; + } + } + + .es-toast-content { + flex: 1; + min-width: 0; + } + + .es-toast-title { + font-size: $es-font-size-sm; + font-weight: $es-font-weight-semibold; + color: $es-danger; + margin-bottom: 2px; + } + + .es-toast-message { + font-size: $es-font-size-xs; + color: $es-text-secondary; + line-height: 1.4; + } + + .es-toast-close { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: 20px; + height: 20px; + color: $es-text-muted; + border-radius: $es-radius-sm; + flex-shrink: 0; + transition: all $es-transition-fast; + + &:hover { + background: $es-slate-100; + color: $es-text-primary; + } + + i { + font-size: 12px; + } + } +} + +@keyframes es-toast-slide-in { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} diff --git a/sources/sources/scss/components/_value-picker.scss b/sources/sources/scss/components/_value-picker.scss new file mode 100644 index 0000000..fe94aff --- /dev/null +++ b/sources/sources/scss/components/_value-picker.scss @@ -0,0 +1,281 @@ +/** + * Value Picker Component + * Search boxes, input types, range inputs + */ + +@use '../variables' as *; +@use '../mixins' as *; + +.target-conditions-trait, +.entity-selector-trait { + + // Value picker container + .value-picker { + padding: $es-spacing-sm 0; + + &[style*="display: none"], + &[style*="display:none"] { + padding: 0; + } + } + + .include-picker, + .exclude-picker { + // Section-specific picker styles + } + + // Entity search box + .entity-search-box { + position: relative; + display: flex; + align-items: center; + gap: $es-spacing-sm; + padding: $es-spacing-xs; + background: $es-white; + border: 1px solid $es-border-color; + border-radius: $es-radius-md; + transition: all $es-transition-fast; + + &:focus-within { + border-color: $es-primary; + box-shadow: 0 0 0 2px rgba($es-primary, 0.1); + } + } + + // Separation between chips and search box + .chips-wrapper + .entity-search-box { + margin-top: $es-spacing-md; + } + + .entity-search-icon { + color: $es-text-muted; + font-size: 14px; + flex-shrink: 0; + margin-left: $es-spacing-xs; + } + + // Override parent form's max-width on search input + input.entity-search-input, + input.entity-search-input[type="text"] { + @include input-reset; + flex: 1; + min-width: 0; + width: auto !important; + max-width: none !important; + padding: 0.375rem; + font-size: $es-font-size-sm; + color: $es-text-primary; + border: none !important; + background: transparent !important; + box-shadow: none !important; + + &::placeholder { + color: $es-text-muted; + } + + &:focus { + border: none !important; + box-shadow: none !important; + outline: none; + } + } + + .search-loading { + display: flex; + align-items: center; + justify-content: center; + color: $es-primary; + + i { + animation: spin 0.6s linear infinite; + } + } + + // Browse tree button (for categories) + .btn-browse-tree { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + margin-left: auto; + color: $es-primary; + background: $es-primary-light; + border-radius: $es-radius-sm; + flex-shrink: 0; + transition: all $es-transition-fast; + + &:hover { + background: $es-primary; + color: $es-white; + } + + i { + font-size: 14px; + } + } + + // Numeric range box + .numeric-range-box, + .multi-range-input-row { + display: flex; + align-items: center; + gap: $es-spacing-xs; + } + + .range-min-input, + .range-max-input { + @include input-base; + width: 100px; + padding: $es-spacing-sm; + text-align: center; + font-size: $es-font-size-sm; + + &::-webkit-inner-spin-button, + &::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; + } + -moz-appearance: textfield; + } + + .range-separator { + color: $es-text-muted; + font-size: $es-font-size-sm; + font-weight: $es-font-weight-medium; + } + + .btn-add-range { + @include button-reset; + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + color: $es-white; + background: $es-primary; + border-radius: $es-radius-md; + transition: all $es-transition-fast; + + &:hover { + background: $es-primary-hover; + } + + i { + font-size: 12px; + } + } + + // Multi-range container + .multi-range-container { + display: flex; + flex-direction: column; + gap: $es-spacing-sm; + } + + // Date range box + .date-range-box { + display: flex; + align-items: center; + gap: $es-spacing-xs; + } + + .date-from-input, + .date-to-input { + @include input-base; + width: 140px; + padding: $es-spacing-sm; + font-size: $es-font-size-sm; + } + + // Multi-select tiles + .multi-select-tiles { + display: flex; + flex-wrap: wrap; + gap: $es-spacing-xs; + } + + .tile-option { + @include button-reset; + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.375rem 0.75rem; + color: $es-text-muted; + background: transparent; + border: 1px dashed $es-border-color; + border-radius: 100px; // Pill shape + font-size: $es-font-size-xs; + font-weight: $es-font-weight-normal; + cursor: pointer; + transition: all $es-transition-fast; + + &:hover { + color: $es-text-secondary; + border-color: $es-slate-400; + border-style: solid; + } + + &.selected { + color: $es-primary; + background: $es-primary-light; + border: 1px solid $es-primary; + font-weight: $es-font-weight-medium; + } + + i { + font-size: 11px; + opacity: 0.6; + } + + &.selected i { + opacity: 1; + } + } + + .tile-label { + white-space: nowrap; + } + + // Select input box + .select-input-box { + display: inline-block; + } + + .select-value-input { + @include input-base; + padding: $es-spacing-sm $es-spacing-md; + font-size: $es-font-size-sm; + min-width: 150px; + } + + // Boolean input box + .boolean-input-box { + display: inline-flex; + align-items: center; + padding: $es-spacing-sm $es-spacing-md; + background: $es-success-light; + color: $es-success-dark; + border-radius: $es-radius-md; + font-size: $es-font-size-sm; + font-weight: $es-font-weight-medium; + } + + .boolean-label { + display: flex; + align-items: center; + gap: 0.25rem; + + &::before { + content: '\2713'; + font-weight: bold; + } + } + + // Condition match count badge + .condition-match-count { + @include count-badge($es-primary); + margin-left: $es-spacing-sm; + } +} diff --git a/sources/sources/scss/components/index.php b/sources/sources/scss/components/index.php new file mode 100644 index 0000000..c4f371f --- /dev/null +++ b/sources/sources/scss/components/index.php @@ -0,0 +1 @@ + .control-label { + display: none; + } + + > .col-lg-8 { + width: 100%; + max-width: 100%; + padding-left: $es-spacing-md; + padding-right: $es-spacing-md; + flex: 0 0 100% !important; + } +} + +// Fallback class for browsers without :has() support +.form-group.condition-trait-fullwidth { + display: block; + + > .control-label { + display: none; + } + + > .col-lg-8 { + width: 100%; + max-width: 100%; + padding-left: $es-spacing-md; + padding-right: $es-spacing-md; + flex: 0 0 100% !important; + } +} + +// SAFEGUARD: Force label visibility for form-group layout widgets +// This overrides any conflicting rules (including fallback class rules) +// when the widget has layout-form-group class indicating standard form integration +.form-group:has(.layout-form-group) > .control-label { + display: flex !important; +} + +// Dropdown overflow fix +// When dropdown is open, parent containers must allow overflow +.panel:has(.target-search-dropdown.show), +.card:has(.target-search-dropdown.show), +.form-wrapper:has(.target-search-dropdown.show), +.panel-body:has(.target-search-dropdown.show), +.card-body:has(.target-search-dropdown.show), +.form-group:has(.target-search-dropdown.show), +.col-lg-8:has(.target-search-dropdown.show), +.col-lg-12:has(.target-search-dropdown.show) { + overflow: visible !important; +} + +// Target conditions wrapper hierarchy overflow fix +.target-conditions-trait:has(.target-search-dropdown.show), +.entity-selector-trait:has(.target-search-dropdown.show), +.condition-trait-body:has(.target-search-dropdown.show), +.target-block-content:has(.target-search-dropdown.show), +.target-block-groups:has(.target-search-dropdown.show), +.target-group:has(.target-search-dropdown.show), +.target-group-body:has(.target-search-dropdown.show), +.target-search-wrapper:has(.target-search-dropdown.show) { + overflow: visible !important; +} + +// ============================================================================= +// Embedded Layout +// ============================================================================= +// Use .layout-embedded for entity selectors nested inside other components +// Removes outer wrapper styling to avoid redundant borders/backgrounds + +.target-conditions-trait.layout-embedded, +.entity-selector-trait.layout-embedded { + background: transparent; + border: none; + border-radius: 0; + + // Remove padding from groups container when embedded + .groups-container { + padding: 0; + } + + // Remove block body padding + .block-body { + padding: 0; + } + + // Remove block footer border when embedded + .block-footer { + border-top: none; + padding: $es-spacing-sm 0 0; + } + + // Simplify selection group when embedded - single thin border only + .selection-group { + background: $es-white; + border: 1px solid $es-slate-200; + border-radius: $es-radius-md; + + // Lighter group header in embedded mode + .group-header { + background: $es-slate-50; + border-bottom-color: $es-slate-200; + padding: $es-spacing-xs $es-spacing-sm; + border-radius: $es-radius-md $es-radius-md 0 0; + } + + // Reduce group body padding (slightly more than $es-spacing-sm for readability) + .group-body { + padding: 0.75rem; + } + + // Reduce group-include section padding + .group-include { + padding: $es-spacing-xs; + margin-bottom: $es-spacing-sm; + } + + // Smaller modifiers section + .group-modifiers { + padding: $es-spacing-xs $es-spacing-sm; + margin: $es-spacing-sm (-$es-spacing-sm) (-$es-spacing-sm); + } + } + + // Empty state - smaller padding + .groups-empty-state { + padding: $es-spacing-md; + } + + // Smaller add group button + .btn-add-group { + padding: 0.375rem 0.625rem; + font-size: $es-font-size-xs; + } +} diff --git a/sources/sources/scss/layouts/_responsive.scss b/sources/sources/scss/layouts/_responsive.scss new file mode 100644 index 0000000..358933d --- /dev/null +++ b/sources/sources/scss/layouts/_responsive.scss @@ -0,0 +1,63 @@ +/** + * Responsive Styles + * Media query adjustments for different screen sizes + */ + +@use '../variables' as *; + +// Tablet and below +@media (max-width: 991px) { + .target-conditions-trait, + .entity-selector-trait { + .condition-trait-header { + flex-direction: column; + align-items: flex-start; + gap: $es-spacing-sm; + } + + .trait-header-right { + width: 100%; + justify-content: flex-end; + } + + .target-block-tabs { + flex-wrap: wrap; + } + } +} + +// Mobile +@media (max-width: 767px) { + .target-conditions-trait, + .entity-selector-trait { + .target-block-tab { + padding: $es-spacing-sm; + font-size: $es-font-size-xs; + } + + .target-group-header { + flex-direction: column; + align-items: flex-start; + } + + .target-search-dropdown { + width: 100% !important; + left: 0 !important; + right: 0 !important; + } + + .dropdown-results-grid { + grid-template-columns: 1fr !important; + } + } +} + +// High-resolution displays +@media (min-width: 1600px) { + .target-conditions-trait, + .entity-selector-trait { + .dropdown-results-grid.view-grid-3 { + grid-template-columns: repeat(4, 1fr); + } + } +} diff --git a/sources/sources/scss/layouts/index.php b/sources/sources/scss/layouts/index.php new file mode 100644 index 0000000..c4f371f --- /dev/null +++ b/sources/sources/scss/layouts/index.php @@ -0,0 +1 @@ +getFileName(); - - // Go from src/EntitySelector.php up to package root, then to assets/ - $packageDir = dirname(dirname($traitFile)); - $assetsDir = $packageDir . '/assets/'; + // Derive path from the calling module, not the trait file location. + // __TRAIT__ reflection returns wherever PHP's autoloader first loaded the trait from, + // which may be a completely different module. $this->module is always correct. + $modulePath = $this->module->getLocalPath(); + $assetsDir = $modulePath . 'vendor/myprestarocks/prestashop-entity-selector/assets/'; // Convert filesystem path to URL path relative to PS root - // Use realpath() on PS root to handle symlinks consistently - $psRoot = realpath(_PS_ROOT_DIR_) . '/'; - $assetsReal = realpath($packageDir . '/assets'); - $relativePath = $assetsReal ? str_replace($psRoot, '', $assetsReal . '/') : null; - - // If symlink resolution caused the path to escape PS root, fall back to module URI - if (!$relativePath || strpos($relativePath, '/') === 0 || strpos($relativePath, '..') !== false) { - // Use module's web-accessible path as base - $modulePath = $this->module->getPathUri(); - return $modulePath . 'vendor/myprestarocks/prestashop-entity-selector/assets/'; - } + $psRoot = _PS_ROOT_DIR_ . '/'; + $relativePath = str_replace($psRoot, '', $assetsDir); return __PS_BASE_URI__ . $relativePath; } @@ -213,13 +199,16 @@ trait EntitySelector $assetPath = $this->getEntitySelectorAssetPath(); + // Cache-busting version — bump when assets change + $v = '?v=' . filemtime(dirname(__DIR__) . '/assets/js/admin/entity-selector.js'); + // Load compiled CSS (SCSS-based, Bootstrap 4 compatible) - $this->addCSS($assetPath . 'css/admin/entity-selector.css'); + $this->addCSS($assetPath . 'css/admin/entity-selector.css' . $v); // Note: modal.js is NOT loaded here - MPRAdminController already provides MPRModal // If using EntitySelector outside of MPRAdminController context, you may need to load modal separately - $this->addJS($assetPath . 'js/admin/entity-selector.js'); + $this->addJS($assetPath . 'js/admin/entity-selector.js' . $v); $this->entitySelectorAssetsLoaded = true; } @@ -287,9 +276,6 @@ trait EntitySelector case 'previewFilterGroupProducts': $this->ajaxPreviewFilterGroupProducts(); return true; - case 'previewFilterValueProducts': - $this->ajaxPreviewFilterValueProducts(); - return true; case 'previewCategoryProducts': $this->ajaxPreviewCategoryProducts(); return true; @@ -852,114 +838,6 @@ trait EntitySelector } } - /** - * AJAX: Preview products for a specific attribute/feature value - * Used by filter chip eye button - */ - protected function ajaxPreviewFilterValueProducts() - { - $valueId = (int) Tools::getValue('value_id'); - $valueType = Tools::getValue('value_type'); // 'attribute' or 'feature' - $groupId = (int) Tools::getValue('group_id'); - $limit = (int) Tools::getValue('limit', 10); - $filter = Tools::getValue('filter', ''); - - if (!$valueId || !in_array($valueType, ['attribute', 'feature'])) { - die(json_encode([ - 'success' => false, - 'error' => 'Invalid parameters' - ])); - } - - $idLang = (int) Context::getContext()->language->id; - $idShop = (int) Context::getContext()->shop->id; - - try { - $db = Db::getInstance(); - - if ($valueType === 'attribute') { - $sql = new DbQuery(); - $sql->select('DISTINCT p.id_product'); - $sql->from('product', 'p'); - $sql->innerJoin('product_shop', 'ps', 'ps.id_product = p.id_product AND ps.id_shop = ' . $idShop); - $sql->innerJoin('product_attribute', 'pa', 'pa.id_product = p.id_product'); - $sql->innerJoin('product_attribute_combination', 'pac', 'pac.id_product_attribute = pa.id_product_attribute'); - $sql->where('pac.id_attribute = ' . $valueId); - $sql->where('ps.active = 1'); - } else { - $sql = new DbQuery(); - $sql->select('DISTINCT p.id_product'); - $sql->from('product', 'p'); - $sql->innerJoin('product_shop', 'ps', 'ps.id_product = p.id_product AND ps.id_shop = ' . $idShop); - $sql->innerJoin('feature_product', 'fp', 'fp.id_product = p.id_product'); - $sql->where('fp.id_feature_value = ' . $valueId); - $sql->where('ps.active = 1'); - } - - $results = $db->executeS($sql); - $productIds = array_column($results, 'id_product'); - - if (!empty($filter) && !empty($productIds)) { - $productIds = $this->getEntityPreviewHandler()->filterProductIdsByQuery($productIds, $filter, $idLang, $idShop); - } - - $totalCount = count($productIds); - $previewIds = array_slice($productIds, 0, $limit); - - $items = []; - if (!empty($previewIds)) { - $productSql = new DbQuery(); - $productSql->select('p.id_product, pl.name, p.reference, i.id_image, m.name as manufacturer'); - $productSql->from('product', 'p'); - $productSql->innerJoin('product_lang', 'pl', 'pl.id_product = p.id_product AND pl.id_lang = ' . $idLang . ' AND pl.id_shop = ' . $idShop); - $productSql->leftJoin('image', 'i', 'i.id_product = p.id_product AND i.cover = 1'); - $productSql->leftJoin('manufacturer', 'm', 'm.id_manufacturer = p.id_manufacturer'); - $productSql->where('p.id_product IN (' . implode(',', array_map('intval', $previewIds)) . ')'); - - $products = $db->executeS($productSql); - - $productsById = []; - foreach ($products as $product) { - $imageUrl = null; - if ($product['id_image']) { - $imageUrl = Context::getContext()->link->getImageLink( - Tools::link_rewrite($product['name']), - $product['id_product'] . '-' . $product['id_image'], - 'small_default' - ); - } - - $productsById[(int) $product['id_product']] = [ - 'id' => (int) $product['id_product'], - 'name' => $product['name'], - 'reference' => $product['reference'], - 'manufacturer' => $product['manufacturer'], - 'image' => $imageUrl - ]; - } - - foreach ($previewIds as $id) { - if (isset($productsById[(int) $id])) { - $items[] = $productsById[(int) $id]; - } - } - } - - die(json_encode([ - 'success' => true, - 'items' => $items, - 'count' => $totalCount, - 'hasMore' => $totalCount > count($items) - ])); - - } catch (\Exception $e) { - die(json_encode([ - 'success' => false, - 'error' => $e->getMessage() - ])); - } - } - /** * AJAX: Preview products in a category * Used by tree view product count click @@ -1402,8 +1280,6 @@ trait EntitySelector // Sorting 'sort_by' => $sortBy, 'sort_dir' => $sortDir, - // Product selection level - 'product_selection_level' => Tools::getValue('product_selection_level', 'product'), ]; // Delegate to EntitySearchEngine @@ -1427,7 +1303,6 @@ trait EntitySelector protected function ajaxGetTargetEntitiesByIds() { $entityType = Tools::getValue('entity_type', ''); - $productSelectionLevel = Tools::getValue('product_selection_level', 'product'); $ids = Tools::getValue('ids', ''); if (is_string($ids)) { $ids = json_decode($ids, true); @@ -1437,7 +1312,7 @@ trait EntitySelector } // Delegate to EntitySearchEngine - $entities = $this->getEntitySearchEngine()->getByIds($entityType, $ids, $productSelectionLevel); + $entities = $this->getEntitySearchEngine()->getByIds($entityType, $ids); $this->ajaxDie(json_encode([ 'success' => true, @@ -1453,7 +1328,7 @@ trait EntitySelector protected function ajaxGetTargetEntitiesByIdsBulk() { $entitiesParam = Tools::getValue('entities', ''); - $productSelectionLevel = Tools::getValue('product_selection_level', 'product'); + \PrestaShopLogger::addLog('[EntitySelector] ajaxGetTargetEntitiesByIdsBulk called, raw param: ' . substr($entitiesParam, 0, 500), 1); if (is_string($entitiesParam)) { $entitiesParam = json_decode($entitiesParam, true); @@ -1462,20 +1337,21 @@ trait EntitySelector $entitiesParam = []; } + \PrestaShopLogger::addLog('[EntitySelector] Parsed entities param: ' . json_encode($entitiesParam), 1); + $result = []; $searchEngine = $this->getEntitySearchEngine(); foreach ($entitiesParam as $entityType => $ids) { if (!is_array($ids) || empty($ids)) { + \PrestaShopLogger::addLog('[EntitySelector] Skipping entityType=' . $entityType . ' - empty or not array', 1); continue; } - // For combination-level products, keep string IDs (c:32, p:17); otherwise intval - if ($entityType === 'products' && ($productSelectionLevel === 'combination' || $productSelectionLevel === 'both')) { - $ids = array_unique(array_map('strval', $ids)); - } else { - $ids = array_unique(array_map('intval', $ids)); - } - $result[$entityType] = $searchEngine->getByIds($entityType, $ids, $productSelectionLevel); + // Deduplicate and sanitize IDs + $ids = array_unique(array_map('intval', $ids)); + \PrestaShopLogger::addLog('[EntitySelector] Fetching entityType=' . $entityType . ' ids=' . implode(',', $ids), 1); + $result[$entityType] = $searchEngine->getByIds($entityType, $ids); + \PrestaShopLogger::addLog('[EntitySelector] Got ' . count($result[$entityType]) . ' results for ' . $entityType, 1); } $this->ajaxDie(json_encode([ @@ -1492,42 +1368,42 @@ trait EntitySelector return [ 'products' => [ 'label' => $this->transEntitySelector('Products'), - 'icon' => 'icon-cube', + 'icon' => 'inventory', 'entity_label' => $this->transEntitySelector('product'), 'entity_label_plural' => $this->transEntitySelector('products'), 'selection_methods' => $this->getProductSelectionMethods(), ], 'categories' => [ 'label' => $this->transEntitySelector('Categories'), - 'icon' => 'icon-folder-open', + 'icon' => 'folder_open', 'entity_label' => $this->transEntitySelector('category'), 'entity_label_plural' => $this->transEntitySelector('categories'), 'selection_methods' => $this->getCategorySelectionMethods(), ], 'manufacturers' => [ 'label' => $this->transEntitySelector('Manufacturers'), - 'icon' => 'icon-building', + 'icon' => 'business', 'entity_label' => $this->transEntitySelector('manufacturer'), 'entity_label_plural' => $this->transEntitySelector('manufacturers'), 'selection_methods' => $this->getManufacturerSelectionMethods(), ], 'suppliers' => [ 'label' => $this->transEntitySelector('Suppliers'), - 'icon' => 'icon-archive', + 'icon' => 'inventory_2', 'entity_label' => $this->transEntitySelector('supplier'), 'entity_label_plural' => $this->transEntitySelector('suppliers'), 'selection_methods' => $this->getSupplierSelectionMethods(), ], 'cms' => [ 'label' => $this->transEntitySelector('CMS Pages'), - 'icon' => 'icon-file-text-o', + 'icon' => 'description', 'entity_label' => $this->transEntitySelector('CMS page'), 'entity_label_plural' => $this->transEntitySelector('CMS pages'), 'selection_methods' => $this->getCmsSelectionMethods(), ], 'cms_categories' => [ 'label' => $this->transEntitySelector('CMS Categories'), - 'icon' => 'icon-folder-o', + 'icon' => 'folder', 'entity_label' => $this->transEntitySelector('CMS category'), 'entity_label_plural' => $this->transEntitySelector('CMS categories'), 'selection_methods' => $this->getCmsCategorySelectionMethods(), @@ -1535,84 +1411,84 @@ trait EntitySelector // Transactional / System entities 'employees' => [ 'label' => $this->transEntitySelector('Employees'), - 'icon' => 'icon-briefcase', + 'icon' => 'work', 'entity_label' => $this->transEntitySelector('employee'), 'entity_label_plural' => $this->transEntitySelector('employees'), 'selection_methods' => $this->getEmployeeSelectionMethods(), ], 'customers' => [ 'label' => $this->transEntitySelector('Customers'), - 'icon' => 'icon-user', + 'icon' => 'person', 'entity_label' => $this->transEntitySelector('customer'), 'entity_label_plural' => $this->transEntitySelector('customers'), 'selection_methods' => $this->getCustomerSelectionMethods(), ], 'customer_groups' => [ 'label' => $this->transEntitySelector('Customer Groups'), - 'icon' => 'icon-users', + 'icon' => 'group', 'entity_label' => $this->transEntitySelector('customer group'), 'entity_label_plural' => $this->transEntitySelector('customer groups'), 'selection_methods' => $this->getCustomerGroupSelectionMethods(), ], 'carriers' => [ 'label' => $this->transEntitySelector('Carriers'), - 'icon' => 'icon-truck', + 'icon' => 'local_shipping', 'entity_label' => $this->transEntitySelector('carrier'), 'entity_label_plural' => $this->transEntitySelector('carriers'), 'selection_methods' => $this->getCarrierSelectionMethods(), ], 'zones' => [ 'label' => $this->transEntitySelector('Zones'), - 'icon' => 'icon-globe', + 'icon' => 'public', 'entity_label' => $this->transEntitySelector('zone'), 'entity_label_plural' => $this->transEntitySelector('zones'), 'selection_methods' => $this->getZoneSelectionMethods(), ], 'countries' => [ 'label' => $this->transEntitySelector('Countries'), - 'icon' => 'icon-flag', + 'icon' => 'flag', 'entity_label' => $this->transEntitySelector('country'), 'entity_label_plural' => $this->transEntitySelector('countries'), 'selection_methods' => $this->getCountrySelectionMethods(), ], 'currencies' => [ 'label' => $this->transEntitySelector('Currencies'), - 'icon' => 'icon-money', + 'icon' => 'payments', 'entity_label' => $this->transEntitySelector('currency'), 'entity_label_plural' => $this->transEntitySelector('currencies'), 'selection_methods' => $this->getCurrencySelectionMethods(), ], 'languages' => [ 'label' => $this->transEntitySelector('Languages'), - 'icon' => 'icon-language', + 'icon' => 'language', 'entity_label' => $this->transEntitySelector('language'), 'entity_label_plural' => $this->transEntitySelector('languages'), 'selection_methods' => $this->getLanguageSelectionMethods(), ], 'shops' => [ 'label' => $this->transEntitySelector('Shops'), - 'icon' => 'icon-shopping-cart', + 'icon' => 'shopping_cart', 'entity_label' => $this->transEntitySelector('shop'), 'entity_label_plural' => $this->transEntitySelector('shops'), 'selection_methods' => $this->getShopSelectionMethods(), ], 'profiles' => [ 'label' => $this->transEntitySelector('Employee Profiles'), - 'icon' => 'icon-key', + 'icon' => 'key', 'entity_label' => $this->transEntitySelector('profile'), 'entity_label_plural' => $this->transEntitySelector('profiles'), 'selection_methods' => $this->getProfileSelectionMethods(), ], 'order_states' => [ 'label' => $this->transEntitySelector('Order States'), - 'icon' => 'icon-tasks', + 'icon' => 'task_alt', 'entity_label' => $this->transEntitySelector('order state'), 'entity_label_plural' => $this->transEntitySelector('order states'), 'selection_methods' => $this->getOrderStateSelectionMethods(), ], 'taxes' => [ 'label' => $this->transEntitySelector('Taxes'), - 'icon' => 'icon-calculator', + 'icon' => 'calculate', 'entity_label' => $this->transEntitySelector('tax'), 'entity_label_plural' => $this->transEntitySelector('taxes'), 'selection_methods' => $this->getTaxSelectionMethods(), @@ -1629,7 +1505,7 @@ trait EntitySelector // No group - always first 'all' => [ 'label' => $this->transEntitySelector('All products'), - 'icon' => 'icon-asterisk', + 'icon' => 'star', 'value_type' => 'none', 'group' => '', ], @@ -1637,56 +1513,56 @@ trait EntitySelector // ===== BY ENTITY ===== 'specific' => [ 'label' => $this->transEntitySelector('Specific products'), - 'icon' => 'icon-cube', + 'icon' => 'inventory', 'value_type' => 'entity_search', 'search_entity' => 'products', 'group' => 'by_entity', ], 'by_category' => [ 'label' => $this->transEntitySelector('Category'), - 'icon' => 'icon-folder-open', + 'icon' => 'folder_open', 'value_type' => 'entity_search', 'search_entity' => 'categories', 'group' => 'by_entity', ], 'by_manufacturer' => [ 'label' => $this->transEntitySelector('Manufacturer'), - 'icon' => 'icon-building', + 'icon' => 'business', 'value_type' => 'entity_search', 'search_entity' => 'manufacturers', 'group' => 'by_entity', ], 'by_supplier' => [ 'label' => $this->transEntitySelector('Supplier'), - 'icon' => 'icon-truck', + 'icon' => 'local_shipping', 'value_type' => 'entity_search', 'search_entity' => 'suppliers', 'group' => 'by_entity', ], 'by_tag' => [ 'label' => $this->transEntitySelector('Tag'), - 'icon' => 'icon-tags', + 'icon' => 'sell', 'value_type' => 'entity_search', 'search_entity' => 'tags', 'group' => 'by_entity', ], 'by_attribute' => [ 'label' => $this->transEntitySelector('Attribute'), - 'icon' => 'icon-paint-brush', + 'icon' => 'brush', 'value_type' => 'entity_search', 'search_entity' => 'attributes', 'group' => 'by_entity', ], 'by_feature' => [ 'label' => $this->transEntitySelector('Feature'), - 'icon' => 'icon-list-ul', + 'icon' => 'format_list_bulleted', 'value_type' => 'entity_search', 'search_entity' => 'features', 'group' => 'by_entity', ], 'by_combination' => [ 'label' => $this->transEntitySelector('Combination'), - 'icon' => 'icon-th', + 'icon' => 'grid_view', 'value_type' => 'combination_attributes', 'group' => 'by_entity', ], @@ -1694,205 +1570,205 @@ trait EntitySelector // ===== BY PROPERTY ===== 'by_condition' => [ 'label' => $this->transEntitySelector('Condition'), - 'icon' => 'icon-certificate', + 'icon' => 'verified', 'value_type' => 'multi_select_tiles', 'options' => [ - 'new' => ['label' => $this->transEntitySelector('New'), 'icon' => 'icon-star'], - 'used' => ['label' => $this->transEntitySelector('Used'), 'icon' => 'icon-recycle'], - 'refurbished' => ['label' => $this->transEntitySelector('Refurbished'), 'icon' => 'icon-refresh'], + 'new' => ['label' => $this->transEntitySelector('New'), 'icon' => 'star'], + 'used' => ['label' => $this->transEntitySelector('Used'), 'icon' => 'recycling'], + 'refurbished' => ['label' => $this->transEntitySelector('Refurbished'), 'icon' => 'refresh'], ], 'group' => 'by_property', ], 'by_visibility' => [ 'label' => $this->transEntitySelector('Visibility'), - 'icon' => 'icon-eye', + 'icon' => 'visibility', 'value_type' => 'multi_select_tiles', 'options' => [ - 'both' => ['label' => $this->transEntitySelector('Everywhere'), 'icon' => 'icon-globe'], - 'catalog' => ['label' => $this->transEntitySelector('Catalog only'), 'icon' => 'icon-book'], - 'search' => ['label' => $this->transEntitySelector('Search only'), 'icon' => 'icon-search'], - 'none' => ['label' => $this->transEntitySelector('Nowhere'), 'icon' => 'icon-eye-slash'], + 'both' => ['label' => $this->transEntitySelector('Everywhere'), 'icon' => 'public'], + 'catalog' => ['label' => $this->transEntitySelector('Catalog only'), 'icon' => 'menu_book'], + 'search' => ['label' => $this->transEntitySelector('Search only'), 'icon' => 'search'], + 'none' => ['label' => $this->transEntitySelector('Nowhere'), 'icon' => 'visibility_off'], ], 'group' => 'by_property', ], 'by_active_status' => [ 'label' => $this->transEntitySelector('Active status'), - 'icon' => 'icon-toggle-on', + 'icon' => 'toggle_on', 'value_type' => 'multi_select_tiles', 'options' => [ - 'active' => ['label' => $this->transEntitySelector('Active'), 'icon' => 'icon-check'], - 'inactive' => ['label' => $this->transEntitySelector('Inactive'), 'icon' => 'icon-times'], + 'active' => ['label' => $this->transEntitySelector('Active'), 'icon' => 'check'], + 'inactive' => ['label' => $this->transEntitySelector('Inactive'), 'icon' => 'close'], ], 'group' => 'by_property', ], 'by_stock_status' => [ 'label' => $this->transEntitySelector('Stock status'), - 'icon' => 'icon-archive', + 'icon' => 'inventory_2', 'value_type' => 'multi_select_tiles', 'options' => [ - 'in_stock' => ['label' => $this->transEntitySelector('In stock'), 'icon' => 'icon-check-circle'], - 'out_of_stock' => ['label' => $this->transEntitySelector('Out of stock'), 'icon' => 'icon-times-circle'], - 'low_stock' => ['label' => $this->transEntitySelector('Low stock'), 'icon' => 'icon-exclamation-triangle'], + 'in_stock' => ['label' => $this->transEntitySelector('In stock'), 'icon' => 'check_circle'], + 'out_of_stock' => ['label' => $this->transEntitySelector('Out of stock'), 'icon' => 'cancel'], + 'low_stock' => ['label' => $this->transEntitySelector('Low stock'), 'icon' => 'warning'], ], 'group' => 'by_property', ], 'by_on_sale' => [ 'label' => $this->transEntitySelector('On sale'), - 'icon' => 'icon-tag', + 'icon' => 'label', 'value_type' => 'multi_select_tiles', 'exclusive' => true, 'options' => [ - 'yes' => ['label' => $this->transEntitySelector('Yes'), 'icon' => 'icon-check', 'color' => 'green'], - 'no' => ['label' => $this->transEntitySelector('No'), 'icon' => 'icon-times', 'color' => 'red'], + 'yes' => ['label' => $this->transEntitySelector('Yes'), 'icon' => 'check', 'color' => 'green'], + 'no' => ['label' => $this->transEntitySelector('No'), 'icon' => 'close', 'color' => 'red'], ], 'group' => 'by_property', ], 'by_has_specific_price' => [ 'label' => $this->transEntitySelector('Has discount'), - 'icon' => 'icon-ticket', + 'icon' => 'confirmation_number', 'value_type' => 'multi_select_tiles', 'exclusive' => true, 'options' => [ - 'yes' => ['label' => $this->transEntitySelector('Yes'), 'icon' => 'icon-check', 'color' => 'green'], - 'no' => ['label' => $this->transEntitySelector('No'), 'icon' => 'icon-times', 'color' => 'red'], + 'yes' => ['label' => $this->transEntitySelector('Yes'), 'icon' => 'check', 'color' => 'green'], + 'no' => ['label' => $this->transEntitySelector('No'), 'icon' => 'close', 'color' => 'red'], ], 'group' => 'by_property', ], 'by_is_virtual' => [ 'label' => $this->transEntitySelector('Virtual product'), - 'icon' => 'icon-cloud-download', + 'icon' => 'cloud_download', 'value_type' => 'multi_select_tiles', 'exclusive' => true, 'options' => [ - 'yes' => ['label' => $this->transEntitySelector('Yes'), 'icon' => 'icon-check', 'color' => 'green'], - 'no' => ['label' => $this->transEntitySelector('No'), 'icon' => 'icon-times', 'color' => 'red'], + 'yes' => ['label' => $this->transEntitySelector('Yes'), 'icon' => 'check', 'color' => 'green'], + 'no' => ['label' => $this->transEntitySelector('No'), 'icon' => 'close', 'color' => 'red'], ], 'group' => 'by_property', ], 'by_is_pack' => [ 'label' => $this->transEntitySelector('Pack product'), - 'icon' => 'icon-gift', + 'icon' => 'redeem', 'value_type' => 'multi_select_tiles', 'exclusive' => true, 'options' => [ - 'yes' => ['label' => $this->transEntitySelector('Yes'), 'icon' => 'icon-check', 'color' => 'green'], - 'no' => ['label' => $this->transEntitySelector('No'), 'icon' => 'icon-times', 'color' => 'red'], + 'yes' => ['label' => $this->transEntitySelector('Yes'), 'icon' => 'check', 'color' => 'green'], + 'no' => ['label' => $this->transEntitySelector('No'), 'icon' => 'close', 'color' => 'red'], ], 'group' => 'by_property', ], 'by_has_combinations' => [ 'label' => $this->transEntitySelector('Has combinations'), - 'icon' => 'icon-sitemap', + 'icon' => 'account_tree', 'value_type' => 'multi_select_tiles', 'exclusive' => true, 'options' => [ - 'yes' => ['label' => $this->transEntitySelector('Yes'), 'icon' => 'icon-check', 'color' => 'green'], - 'no' => ['label' => $this->transEntitySelector('No'), 'icon' => 'icon-times', 'color' => 'red'], + 'yes' => ['label' => $this->transEntitySelector('Yes'), 'icon' => 'check', 'color' => 'green'], + 'no' => ['label' => $this->transEntitySelector('No'), 'icon' => 'close', 'color' => 'red'], ], 'group' => 'by_property', ], 'by_available_for_order' => [ 'label' => $this->transEntitySelector('Available for order'), - 'icon' => 'icon-shopping-cart', + 'icon' => 'shopping_cart', 'value_type' => 'multi_select_tiles', 'exclusive' => true, 'options' => [ - 'yes' => ['label' => $this->transEntitySelector('Yes'), 'icon' => 'icon-check', 'color' => 'green'], - 'no' => ['label' => $this->transEntitySelector('No'), 'icon' => 'icon-times', 'color' => 'red'], + 'yes' => ['label' => $this->transEntitySelector('Yes'), 'icon' => 'check', 'color' => 'green'], + 'no' => ['label' => $this->transEntitySelector('No'), 'icon' => 'close', 'color' => 'red'], ], 'group' => 'by_property', ], 'by_online_only' => [ 'label' => $this->transEntitySelector('Online only'), - 'icon' => 'icon-laptop', + 'icon' => 'laptop', 'value_type' => 'multi_select_tiles', 'exclusive' => true, 'options' => [ - 'yes' => ['label' => $this->transEntitySelector('Yes'), 'icon' => 'icon-check', 'color' => 'green'], - 'no' => ['label' => $this->transEntitySelector('No'), 'icon' => 'icon-times', 'color' => 'red'], + 'yes' => ['label' => $this->transEntitySelector('Yes'), 'icon' => 'check', 'color' => 'green'], + 'no' => ['label' => $this->transEntitySelector('No'), 'icon' => 'close', 'color' => 'red'], ], 'group' => 'by_property', ], 'by_has_related' => [ 'label' => $this->transEntitySelector('Has related products'), - 'icon' => 'icon-link', + 'icon' => 'link', 'value_type' => 'multi_select_tiles', 'exclusive' => true, 'options' => [ - 'yes' => ['label' => $this->transEntitySelector('Yes'), 'icon' => 'icon-check', 'color' => 'green'], - 'no' => ['label' => $this->transEntitySelector('No'), 'icon' => 'icon-times', 'color' => 'red'], + 'yes' => ['label' => $this->transEntitySelector('Yes'), 'icon' => 'check', 'color' => 'green'], + 'no' => ['label' => $this->transEntitySelector('No'), 'icon' => 'close', 'color' => 'red'], ], 'group' => 'by_property', ], 'by_has_customization' => [ 'label' => $this->transEntitySelector('Has customization'), - 'icon' => 'icon-pencil-square-o', + 'icon' => 'edit_note', 'value_type' => 'multi_select_tiles', 'exclusive' => true, 'options' => [ - 'yes' => ['label' => $this->transEntitySelector('Yes'), 'icon' => 'icon-check', 'color' => 'green'], - 'no' => ['label' => $this->transEntitySelector('No'), 'icon' => 'icon-times', 'color' => 'red'], + 'yes' => ['label' => $this->transEntitySelector('Yes'), 'icon' => 'check', 'color' => 'green'], + 'no' => ['label' => $this->transEntitySelector('No'), 'icon' => 'close', 'color' => 'red'], ], 'group' => 'by_property', ], 'by_has_attachments' => [ 'label' => $this->transEntitySelector('Has attachments'), - 'icon' => 'icon-paperclip', + 'icon' => 'attach_file', 'value_type' => 'multi_select_tiles', 'exclusive' => true, 'options' => [ - 'yes' => ['label' => $this->transEntitySelector('Yes'), 'icon' => 'icon-check', 'color' => 'green'], - 'no' => ['label' => $this->transEntitySelector('No'), 'icon' => 'icon-times', 'color' => 'red'], + 'yes' => ['label' => $this->transEntitySelector('Yes'), 'icon' => 'check', 'color' => 'green'], + 'no' => ['label' => $this->transEntitySelector('No'), 'icon' => 'close', 'color' => 'red'], ], 'group' => 'by_property', ], 'by_out_of_stock_behavior' => [ 'label' => $this->transEntitySelector('Out of stock behavior'), - 'icon' => 'icon-ban', + 'icon' => 'block', 'value_type' => 'multi_select_tiles', 'options' => [ - 'deny' => ['label' => $this->transEntitySelector('Deny orders'), 'icon' => 'icon-times-circle'], - 'allow' => ['label' => $this->transEntitySelector('Allow orders'), 'icon' => 'icon-check-circle'], - 'default' => ['label' => $this->transEntitySelector('Use default'), 'icon' => 'icon-cog'], + 'deny' => ['label' => $this->transEntitySelector('Deny orders'), 'icon' => 'cancel'], + 'allow' => ['label' => $this->transEntitySelector('Allow orders'), 'icon' => 'check_circle'], + 'default' => ['label' => $this->transEntitySelector('Use default'), 'icon' => 'settings'], ], 'group' => 'by_property', ], 'by_delivery_time' => [ 'label' => $this->transEntitySelector('Delivery time setting'), - 'icon' => 'icon-clock-o', + 'icon' => 'schedule', 'value_type' => 'multi_select_tiles', 'options' => [ - 'none' => ['label' => $this->transEntitySelector('None'), 'icon' => 'icon-times'], - 'default' => ['label' => $this->transEntitySelector('Default'), 'icon' => 'icon-cog'], - 'specific' => ['label' => $this->transEntitySelector('Specific'), 'icon' => 'icon-pencil'], + 'none' => ['label' => $this->transEntitySelector('None'), 'icon' => 'close'], + 'default' => ['label' => $this->transEntitySelector('Default'), 'icon' => 'settings'], + 'specific' => ['label' => $this->transEntitySelector('Specific'), 'icon' => 'edit'], ], 'group' => 'by_property', ], 'by_has_additional_shipping' => [ 'label' => $this->transEntitySelector('Has additional shipping cost'), - 'icon' => 'icon-truck', + 'icon' => 'local_shipping', 'value_type' => 'multi_select_tiles', 'exclusive' => true, 'options' => [ - 'yes' => ['label' => $this->transEntitySelector('Yes'), 'icon' => 'icon-check', 'color' => 'green'], - 'no' => ['label' => $this->transEntitySelector('No'), 'icon' => 'icon-times', 'color' => 'red'], + 'yes' => ['label' => $this->transEntitySelector('Yes'), 'icon' => 'check', 'color' => 'green'], + 'no' => ['label' => $this->transEntitySelector('No'), 'icon' => 'close', 'color' => 'red'], ], 'group' => 'by_property', ], 'by_carrier_restriction' => [ 'label' => $this->transEntitySelector('Carrier restriction'), - 'icon' => 'icon-truck', + 'icon' => 'local_shipping', 'value_type' => 'multi_select_tiles', 'exclusive' => true, 'options' => [ - 'restricted' => ['label' => $this->transEntitySelector('Has restriction'), 'icon' => 'icon-lock', 'color' => 'red'], - 'all' => ['label' => $this->transEntitySelector('All carriers'), 'icon' => 'icon-unlock', 'color' => 'green'], + 'restricted' => ['label' => $this->transEntitySelector('Has restriction'), 'icon' => 'lock', 'color' => 'red'], + 'all' => ['label' => $this->transEntitySelector('All carriers'), 'icon' => 'lock_open', 'color' => 'green'], ], 'group' => 'by_property', ], 'by_carrier' => [ 'label' => $this->transEntitySelector('Specific carrier'), - 'icon' => 'icon-truck', + 'icon' => 'local_shipping', 'value_type' => 'entity_search', 'search_entity' => 'carriers', 'group' => 'by_entity', @@ -1901,61 +1777,61 @@ trait EntitySelector // ===== BY TEXT ===== 'by_name_pattern' => [ 'label' => $this->transEntitySelector('Name contains'), - 'icon' => 'icon-font', + 'icon' => 'text_fields', 'value_type' => 'pattern', 'group' => 'by_text', ], 'by_reference_pattern' => [ 'label' => $this->transEntitySelector('Reference contains'), - 'icon' => 'icon-barcode', + 'icon' => 'qr_code', 'value_type' => 'pattern', 'group' => 'by_text', ], 'by_description_pattern' => [ 'label' => $this->transEntitySelector('Description contains'), - 'icon' => 'icon-align-left', + 'icon' => 'format_align_left', 'value_type' => 'pattern', 'group' => 'by_text', ], 'by_long_description_pattern' => [ 'label' => $this->transEntitySelector('Long description contains'), - 'icon' => 'icon-file-text-o', + 'icon' => 'description', 'value_type' => 'pattern', 'group' => 'by_text', ], 'by_ean13_pattern' => [ 'label' => $this->transEntitySelector('EAN-13 contains'), - 'icon' => 'icon-barcode', + 'icon' => 'qr_code', 'value_type' => 'pattern', 'group' => 'by_text', ], 'by_upc_pattern' => [ 'label' => $this->transEntitySelector('UPC contains'), - 'icon' => 'icon-barcode', + 'icon' => 'qr_code', 'value_type' => 'pattern', 'group' => 'by_text', ], 'by_isbn_pattern' => [ 'label' => $this->transEntitySelector('ISBN contains'), - 'icon' => 'icon-book', + 'icon' => 'menu_book', 'value_type' => 'pattern', 'group' => 'by_text', ], 'by_mpn_pattern' => [ 'label' => $this->transEntitySelector('MPN contains'), - 'icon' => 'icon-cog', + 'icon' => 'settings', 'value_type' => 'pattern', 'group' => 'by_text', ], 'by_meta_title_pattern' => [ 'label' => $this->transEntitySelector('Meta title contains'), - 'icon' => 'icon-header', + 'icon' => 'title', 'value_type' => 'pattern', 'group' => 'by_text', ], 'by_meta_description_pattern' => [ 'label' => $this->transEntitySelector('Meta description contains'), - 'icon' => 'icon-file-text-o', + 'icon' => 'description', 'value_type' => 'pattern', 'group' => 'by_text', ], @@ -1963,7 +1839,7 @@ trait EntitySelector // ===== BY RANGE ===== 'by_id_range' => [ 'label' => $this->transEntitySelector('ID range'), - 'icon' => 'icon-list-ol', + 'icon' => 'format_list_numbered', 'value_type' => 'multi_numeric_range', 'step' => 1, 'min' => 1, @@ -1971,7 +1847,7 @@ trait EntitySelector ], 'by_price_range' => [ 'label' => $this->transEntitySelector('Price range'), - 'icon' => 'icon-money', + 'icon' => 'payments', 'value_type' => 'multi_numeric_range', 'step' => 0.01, 'min' => 0, @@ -1979,7 +1855,7 @@ trait EntitySelector ], 'by_weight_range' => [ 'label' => $this->transEntitySelector('Weight range'), - 'icon' => 'icon-dashboard', + 'icon' => 'dashboard', 'value_type' => 'multi_numeric_range', 'step' => 0.001, 'min' => 0, @@ -1987,14 +1863,14 @@ trait EntitySelector ], 'by_quantity_range' => [ 'label' => $this->transEntitySelector('Quantity range'), - 'icon' => 'icon-cubes', + 'icon' => 'view_in_ar', 'value_type' => 'multi_numeric_range', 'step' => 1, 'group' => 'by_range', ], 'by_position_range' => [ 'label' => $this->transEntitySelector('Position range'), - 'icon' => 'icon-sort-numeric-asc', + 'icon' => 'sort', 'value_type' => 'multi_numeric_range', 'step' => 1, 'min' => 0, @@ -2002,13 +1878,13 @@ trait EntitySelector ], 'by_date_added' => [ 'label' => $this->transEntitySelector('Date added'), - 'icon' => 'icon-calendar', + 'icon' => 'calendar_today', 'value_type' => 'date_range', 'group' => 'by_range', ], 'by_date_updated' => [ 'label' => $this->transEntitySelector('Date modified'), - 'icon' => 'icon-calendar-o', + 'icon' => 'event', 'value_type' => 'date_range', 'group' => 'by_range', ], @@ -2036,38 +1912,38 @@ trait EntitySelector return [ 'all' => [ 'label' => $this->transEntitySelector('All categories'), - 'icon' => 'icon-asterisk', + 'icon' => 'star', 'value_type' => 'none', 'group' => '', ], 'specific' => [ 'label' => $this->transEntitySelector('Specific categories'), - 'icon' => 'icon-folder-open', + 'icon' => 'folder_open', 'value_type' => 'entity_search', 'search_entity' => 'categories', 'group' => 'select_by', ], 'by_name_pattern' => [ 'label' => $this->transEntitySelector('Name contains'), - 'icon' => 'icon-font', + 'icon' => 'text_fields', 'value_type' => 'pattern', 'group' => 'filter_by', ], 'by_product_count' => [ 'label' => $this->transEntitySelector('Product count'), - 'icon' => 'icon-cubes', + 'icon' => 'view_in_ar', 'value_type' => 'numeric_range', 'group' => 'filter_by', ], 'by_depth_level' => [ 'label' => $this->transEntitySelector('Depth level'), - 'icon' => 'icon-sitemap', + 'icon' => 'account_tree', 'value_type' => 'numeric_range', 'group' => 'filter_by', ], 'by_active_status' => [ 'label' => $this->transEntitySelector('Status'), - 'icon' => 'icon-toggle-on', + 'icon' => 'toggle_on', 'value_type' => 'select', 'options' => [ 'active' => $this->transEntitySelector('Active'), @@ -2086,32 +1962,32 @@ trait EntitySelector return [ 'all' => [ 'label' => $this->transEntitySelector('All manufacturers'), - 'icon' => 'icon-asterisk', + 'icon' => 'star', 'value_type' => 'none', 'group' => '', ], 'specific' => [ 'label' => $this->transEntitySelector('Specific manufacturers'), - 'icon' => 'icon-building', + 'icon' => 'business', 'value_type' => 'entity_search', 'search_entity' => 'manufacturers', 'group' => 'select_by', ], 'by_name_pattern' => [ 'label' => $this->transEntitySelector('Name contains'), - 'icon' => 'icon-font', + 'icon' => 'text_fields', 'value_type' => 'pattern', 'group' => 'filter_by', ], 'by_product_count' => [ 'label' => $this->transEntitySelector('Product count'), - 'icon' => 'icon-cubes', + 'icon' => 'view_in_ar', 'value_type' => 'numeric_range', 'group' => 'filter_by', ], 'by_active_status' => [ 'label' => $this->transEntitySelector('Status'), - 'icon' => 'icon-toggle-on', + 'icon' => 'toggle_on', 'value_type' => 'select', 'options' => [ 'active' => $this->transEntitySelector('Active'), @@ -2130,32 +2006,32 @@ trait EntitySelector return [ 'all' => [ 'label' => $this->transEntitySelector('All suppliers'), - 'icon' => 'icon-asterisk', + 'icon' => 'star', 'value_type' => 'none', 'group' => '', ], 'specific' => [ 'label' => $this->transEntitySelector('Specific suppliers'), - 'icon' => 'icon-truck', + 'icon' => 'local_shipping', 'value_type' => 'entity_search', 'search_entity' => 'suppliers', 'group' => 'select_by', ], 'by_name_pattern' => [ 'label' => $this->transEntitySelector('Name contains'), - 'icon' => 'icon-font', + 'icon' => 'text_fields', 'value_type' => 'pattern', 'group' => 'filter_by', ], 'by_product_count' => [ 'label' => $this->transEntitySelector('Product count'), - 'icon' => 'icon-cubes', + 'icon' => 'view_in_ar', 'value_type' => 'numeric_range', 'group' => 'filter_by', ], 'by_active_status' => [ 'label' => $this->transEntitySelector('Status'), - 'icon' => 'icon-toggle-on', + 'icon' => 'toggle_on', 'value_type' => 'select', 'options' => [ 'active' => $this->transEntitySelector('Active'), @@ -2174,33 +2050,33 @@ trait EntitySelector return [ 'all' => [ 'label' => $this->transEntitySelector('All CMS pages'), - 'icon' => 'icon-asterisk', + 'icon' => 'star', 'value_type' => 'none', 'group' => '', ], 'specific' => [ 'label' => $this->transEntitySelector('Specific CMS pages'), - 'icon' => 'icon-file-text-o', + 'icon' => 'description', 'value_type' => 'entity_search', 'search_entity' => 'cms', 'group' => 'select_by', ], 'by_cms_category' => [ 'label' => $this->transEntitySelector('CMS pages in category'), - 'icon' => 'icon-folder-o', + 'icon' => 'folder', 'value_type' => 'entity_search', 'search_entity' => 'cms_categories', 'group' => 'select_by', ], 'by_name_pattern' => [ 'label' => $this->transEntitySelector('Title contains'), - 'icon' => 'icon-font', + 'icon' => 'text_fields', 'value_type' => 'pattern', 'group' => 'filter_by', ], 'by_active_status' => [ 'label' => $this->transEntitySelector('Status'), - 'icon' => 'icon-toggle-on', + 'icon' => 'toggle_on', 'value_type' => 'select', 'options' => [ 'active' => $this->transEntitySelector('Active'), @@ -2210,7 +2086,7 @@ trait EntitySelector ], 'by_indexable' => [ 'label' => $this->transEntitySelector('Indexable'), - 'icon' => 'icon-search', + 'icon' => 'search', 'value_type' => 'select', 'options' => [ 'yes' => $this->transEntitySelector('Yes'), @@ -2229,26 +2105,26 @@ trait EntitySelector return [ 'all' => [ 'label' => $this->transEntitySelector('All CMS categories'), - 'icon' => 'icon-asterisk', + 'icon' => 'star', 'value_type' => 'none', 'group' => '', ], 'specific' => [ 'label' => $this->transEntitySelector('Specific CMS categories'), - 'icon' => 'icon-folder-o', + 'icon' => 'folder', 'value_type' => 'entity_search', 'search_entity' => 'cms_categories', 'group' => 'select_by', ], 'by_name_pattern' => [ 'label' => $this->transEntitySelector('Name contains'), - 'icon' => 'icon-font', + 'icon' => 'text_fields', 'value_type' => 'pattern', 'group' => 'filter_by', ], 'by_active_status' => [ 'label' => $this->transEntitySelector('Status'), - 'icon' => 'icon-toggle-on', + 'icon' => 'toggle_on', 'value_type' => 'select', 'options' => [ 'active' => $this->transEntitySelector('Active'), @@ -2258,7 +2134,7 @@ trait EntitySelector ], 'by_page_count' => [ 'label' => $this->transEntitySelector('Page count'), - 'icon' => 'icon-file-text-o', + 'icon' => 'description', 'value_type' => 'numeric_range', 'group' => 'filter_by', ], @@ -2273,33 +2149,33 @@ trait EntitySelector return [ 'all' => [ 'label' => $this->transEntitySelector('All employees'), - 'icon' => 'icon-asterisk', + 'icon' => 'star', 'value_type' => 'none', 'group' => '', ], 'specific' => [ 'label' => $this->transEntitySelector('Specific employees'), - 'icon' => 'icon-user-secret', + 'icon' => 'admin_panel_settings', 'value_type' => 'entity_search', 'search_entity' => 'employees', 'group' => 'select_by', ], 'by_profile' => [ 'label' => $this->transEntitySelector('By profile'), - 'icon' => 'icon-key', + 'icon' => 'key', 'value_type' => 'entity_search', 'search_entity' => 'profiles', 'group' => 'filter_by', ], 'by_name_pattern' => [ 'label' => $this->transEntitySelector('Name contains'), - 'icon' => 'icon-font', + 'icon' => 'text_fields', 'value_type' => 'pattern', 'group' => 'filter_by', ], 'by_active_status' => [ 'label' => $this->transEntitySelector('Status'), - 'icon' => 'icon-toggle-on', + 'icon' => 'toggle_on', 'value_type' => 'select', 'options' => [ 'active' => $this->transEntitySelector('Active'), @@ -2318,39 +2194,39 @@ trait EntitySelector return [ 'all' => [ 'label' => $this->transEntitySelector('All customers'), - 'icon' => 'icon-asterisk', + 'icon' => 'star', 'value_type' => 'none', 'group' => '', ], 'specific' => [ 'label' => $this->transEntitySelector('Specific customers'), - 'icon' => 'icon-user', + 'icon' => 'person', 'value_type' => 'entity_search', 'search_entity' => 'customers', 'group' => 'select_by', ], 'by_group' => [ 'label' => $this->transEntitySelector('By customer group'), - 'icon' => 'icon-group', + 'icon' => 'group', 'value_type' => 'entity_search', 'search_entity' => 'customer_groups', 'group' => 'filter_by', ], 'by_name_pattern' => [ 'label' => $this->transEntitySelector('Name contains'), - 'icon' => 'icon-user', + 'icon' => 'person', 'value_type' => 'pattern', 'group' => 'filter_by', ], 'by_email_pattern' => [ 'label' => $this->transEntitySelector('Email contains'), - 'icon' => 'icon-at', + 'icon' => 'alternate_email', 'value_type' => 'pattern', 'group' => 'filter_by', ], 'by_company' => [ 'label' => $this->transEntitySelector('Has company'), - 'icon' => 'icon-building', + 'icon' => 'business', 'value_type' => 'select', 'options' => [ 'yes' => $this->transEntitySelector('Has company'), @@ -2360,31 +2236,31 @@ trait EntitySelector ], 'by_company_pattern' => [ 'label' => $this->transEntitySelector('Company name contains'), - 'icon' => 'icon-building', + 'icon' => 'business', 'value_type' => 'pattern', 'group' => 'filter_by', ], 'by_address_count' => [ 'label' => $this->transEntitySelector('Number of addresses'), - 'icon' => 'icon-map-marker', + 'icon' => 'location_on', 'value_type' => 'numeric_range', 'group' => 'filter_by', ], 'by_order_count' => [ 'label' => $this->transEntitySelector('Number of orders'), - 'icon' => 'icon-shopping-cart', + 'icon' => 'shopping_cart', 'value_type' => 'numeric_range', 'group' => 'filter_by', ], 'by_turnover' => [ 'label' => $this->transEntitySelector('Total spent'), - 'icon' => 'icon-money', + 'icon' => 'payments', 'value_type' => 'numeric_range', 'group' => 'filter_by', ], 'by_active_status' => [ 'label' => $this->transEntitySelector('Status'), - 'icon' => 'icon-toggle-on', + 'icon' => 'toggle_on', 'value_type' => 'select', 'options' => [ 'active' => $this->transEntitySelector('Active'), @@ -2394,7 +2270,7 @@ trait EntitySelector ], 'by_newsletter' => [ 'label' => $this->transEntitySelector('Newsletter'), - 'icon' => 'icon-envelope', + 'icon' => 'email', 'value_type' => 'select', 'options' => [ 'subscribed' => $this->transEntitySelector('Subscribed'), @@ -2404,7 +2280,7 @@ trait EntitySelector ], 'by_guest' => [ 'label' => $this->transEntitySelector('Account type'), - 'icon' => 'icon-user-times', + 'icon' => 'person_off', 'value_type' => 'select', 'options' => [ 'guest' => $this->transEntitySelector('Guest'), @@ -2423,26 +2299,26 @@ trait EntitySelector return [ 'all' => [ 'label' => $this->transEntitySelector('All customer groups'), - 'icon' => 'icon-asterisk', + 'icon' => 'star', 'value_type' => 'none', 'group' => '', ], 'specific' => [ 'label' => $this->transEntitySelector('Specific groups'), - 'icon' => 'icon-group', + 'icon' => 'group', 'value_type' => 'entity_search', 'search_entity' => 'customer_groups', 'group' => 'select_by', ], 'by_name_pattern' => [ 'label' => $this->transEntitySelector('Name contains'), - 'icon' => 'icon-font', + 'icon' => 'text_fields', 'value_type' => 'pattern', 'group' => 'filter_by', ], 'by_price_display' => [ 'label' => $this->transEntitySelector('Price display'), - 'icon' => 'icon-money', + 'icon' => 'payments', 'value_type' => 'select', 'options' => [ 'tax_excl' => $this->transEntitySelector('Tax excluded'), @@ -2461,26 +2337,26 @@ trait EntitySelector return [ 'all' => [ 'label' => $this->transEntitySelector('All carriers'), - 'icon' => 'icon-asterisk', + 'icon' => 'star', 'value_type' => 'none', 'group' => '', ], 'specific' => [ 'label' => $this->transEntitySelector('Specific carriers'), - 'icon' => 'icon-truck', + 'icon' => 'local_shipping', 'value_type' => 'entity_search', 'search_entity' => 'carriers', 'group' => 'select_by', ], 'by_name_pattern' => [ 'label' => $this->transEntitySelector('Name contains'), - 'icon' => 'icon-font', + 'icon' => 'text_fields', 'value_type' => 'pattern', 'group' => 'filter_by', ], 'by_active_status' => [ 'label' => $this->transEntitySelector('Status'), - 'icon' => 'icon-toggle-on', + 'icon' => 'toggle_on', 'value_type' => 'select', 'options' => [ 'active' => $this->transEntitySelector('Active'), @@ -2490,7 +2366,7 @@ trait EntitySelector ], 'by_shipping_handling' => [ 'label' => $this->transEntitySelector('Shipping handling'), - 'icon' => 'icon-cog', + 'icon' => 'settings', 'value_type' => 'select', 'options' => [ 'with_handling' => $this->transEntitySelector('With handling'), @@ -2500,7 +2376,7 @@ trait EntitySelector ], 'by_free_shipping' => [ 'label' => $this->transEntitySelector('Free shipping'), - 'icon' => 'icon-gift', + 'icon' => 'redeem', 'value_type' => 'select', 'options' => [ 'free' => $this->transEntitySelector('Free shipping'), @@ -2510,27 +2386,27 @@ trait EntitySelector ], 'by_zone' => [ 'label' => $this->transEntitySelector('By zone'), - 'icon' => 'icon-globe', + 'icon' => 'public', 'value_type' => 'entity_search', 'search_entity' => 'zones', 'group' => 'filter_by', ], 'by_customer_group' => [ 'label' => $this->transEntitySelector('By customer group'), - 'icon' => 'icon-group', + 'icon' => 'group', 'value_type' => 'entity_search', 'search_entity' => 'customer_groups', 'group' => 'filter_by', ], 'by_price_range' => [ 'label' => $this->transEntitySelector('Shipping price range'), - 'icon' => 'icon-money', + 'icon' => 'payments', 'value_type' => 'numeric_range', 'group' => 'filter_by', ], 'by_weight_range' => [ 'label' => $this->transEntitySelector('Max weight'), - 'icon' => 'icon-dashboard', + 'icon' => 'dashboard', 'value_type' => 'numeric_range', 'group' => 'filter_by', ], @@ -2545,26 +2421,26 @@ trait EntitySelector return [ 'all' => [ 'label' => $this->transEntitySelector('All zones'), - 'icon' => 'icon-asterisk', + 'icon' => 'star', 'value_type' => 'none', 'group' => '', ], 'specific' => [ 'label' => $this->transEntitySelector('Specific zones'), - 'icon' => 'icon-globe', + 'icon' => 'public', 'value_type' => 'entity_search', 'search_entity' => 'zones', 'group' => 'select_by', ], 'by_name_pattern' => [ 'label' => $this->transEntitySelector('Name contains'), - 'icon' => 'icon-font', + 'icon' => 'text_fields', 'value_type' => 'pattern', 'group' => 'filter_by', ], 'by_active_status' => [ 'label' => $this->transEntitySelector('Status'), - 'icon' => 'icon-toggle-on', + 'icon' => 'toggle_on', 'value_type' => 'select', 'options' => [ 'active' => $this->transEntitySelector('Active'), @@ -2583,33 +2459,33 @@ trait EntitySelector return [ 'all' => [ 'label' => $this->transEntitySelector('All countries'), - 'icon' => 'icon-asterisk', + 'icon' => 'star', 'value_type' => 'none', 'group' => '', ], 'specific' => [ 'label' => $this->transEntitySelector('Specific countries'), - 'icon' => 'icon-flag', + 'icon' => 'flag', 'value_type' => 'entity_search', 'search_entity' => 'countries', 'group' => 'select_by', ], 'by_zone' => [ 'label' => $this->transEntitySelector('By zone'), - 'icon' => 'icon-globe', + 'icon' => 'public', 'value_type' => 'entity_search', 'search_entity' => 'zones', 'group' => 'filter_by', ], 'by_name_pattern' => [ 'label' => $this->transEntitySelector('Name contains'), - 'icon' => 'icon-font', + 'icon' => 'text_fields', 'value_type' => 'pattern', 'group' => 'filter_by', ], 'by_active_status' => [ 'label' => $this->transEntitySelector('Status'), - 'icon' => 'icon-toggle-on', + 'icon' => 'toggle_on', 'value_type' => 'select', 'options' => [ 'active' => $this->transEntitySelector('Active'), @@ -2619,7 +2495,7 @@ trait EntitySelector ], 'by_contains_states' => [ 'label' => $this->transEntitySelector('Has states'), - 'icon' => 'icon-map-marker', + 'icon' => 'location_on', 'value_type' => 'select', 'options' => [ 'yes' => $this->transEntitySelector('Yes'), @@ -2629,7 +2505,7 @@ trait EntitySelector ], 'by_need_zip_code' => [ 'label' => $this->transEntitySelector('Requires ZIP code'), - 'icon' => 'icon-envelope', + 'icon' => 'email', 'value_type' => 'select', 'options' => [ 'yes' => $this->transEntitySelector('Yes'), @@ -2639,13 +2515,13 @@ trait EntitySelector ], 'by_zip_format' => [ 'label' => $this->transEntitySelector('ZIP format contains'), - 'icon' => 'icon-barcode', + 'icon' => 'qr_code', 'value_type' => 'pattern', 'group' => 'filter_by', ], 'by_need_identification' => [ 'label' => $this->transEntitySelector('Requires ID number'), - 'icon' => 'icon-credit-card', + 'icon' => 'credit_card', 'value_type' => 'select', 'options' => [ 'yes' => $this->transEntitySelector('Yes'), @@ -2664,26 +2540,26 @@ trait EntitySelector return [ 'all' => [ 'label' => $this->transEntitySelector('All currencies'), - 'icon' => 'icon-asterisk', + 'icon' => 'star', 'value_type' => 'none', 'group' => '', ], 'specific' => [ 'label' => $this->transEntitySelector('Specific currencies'), - 'icon' => 'icon-money', + 'icon' => 'payments', 'value_type' => 'entity_search', 'search_entity' => 'currencies', 'group' => 'select_by', ], 'by_name_pattern' => [ 'label' => $this->transEntitySelector('Name/code contains'), - 'icon' => 'icon-font', + 'icon' => 'text_fields', 'value_type' => 'pattern', 'group' => 'filter_by', ], 'by_active_status' => [ 'label' => $this->transEntitySelector('Status'), - 'icon' => 'icon-toggle-on', + 'icon' => 'toggle_on', 'value_type' => 'select', 'options' => [ 'active' => $this->transEntitySelector('Active'), @@ -2702,26 +2578,26 @@ trait EntitySelector return [ 'all' => [ 'label' => $this->transEntitySelector('All languages'), - 'icon' => 'icon-asterisk', + 'icon' => 'star', 'value_type' => 'none', 'group' => '', ], 'specific' => [ 'label' => $this->transEntitySelector('Specific languages'), - 'icon' => 'icon-language', + 'icon' => 'language', 'value_type' => 'entity_search', 'search_entity' => 'languages', 'group' => 'select_by', ], 'by_name_pattern' => [ 'label' => $this->transEntitySelector('Name/code contains'), - 'icon' => 'icon-font', + 'icon' => 'text_fields', 'value_type' => 'pattern', 'group' => 'filter_by', ], 'by_active_status' => [ 'label' => $this->transEntitySelector('Status'), - 'icon' => 'icon-toggle-on', + 'icon' => 'toggle_on', 'value_type' => 'select', 'options' => [ 'active' => $this->transEntitySelector('Active'), @@ -2731,7 +2607,7 @@ trait EntitySelector ], 'by_rtl' => [ 'label' => $this->transEntitySelector('Text direction'), - 'icon' => 'icon-align-left', + 'icon' => 'format_align_left', 'value_type' => 'select', 'options' => [ 'ltr' => $this->transEntitySelector('LTR (Left-to-right)'), @@ -2750,26 +2626,26 @@ trait EntitySelector return [ 'all' => [ 'label' => $this->transEntitySelector('All shops'), - 'icon' => 'icon-asterisk', + 'icon' => 'star', 'value_type' => 'none', 'group' => '', ], 'specific' => [ 'label' => $this->transEntitySelector('Specific shops'), - 'icon' => 'icon-shopping-cart', + 'icon' => 'shopping_cart', 'value_type' => 'entity_search', 'search_entity' => 'shops', 'group' => 'select_by', ], 'by_name_pattern' => [ 'label' => $this->transEntitySelector('Name contains'), - 'icon' => 'icon-font', + 'icon' => 'text_fields', 'value_type' => 'pattern', 'group' => 'filter_by', ], 'by_active_status' => [ 'label' => $this->transEntitySelector('Status'), - 'icon' => 'icon-toggle-on', + 'icon' => 'toggle_on', 'value_type' => 'select', 'options' => [ 'active' => $this->transEntitySelector('Active'), @@ -2788,20 +2664,20 @@ trait EntitySelector return [ 'all' => [ 'label' => $this->transEntitySelector('All profiles'), - 'icon' => 'icon-asterisk', + 'icon' => 'star', 'value_type' => 'none', 'group' => '', ], 'specific' => [ 'label' => $this->transEntitySelector('Specific profiles'), - 'icon' => 'icon-key', + 'icon' => 'key', 'value_type' => 'entity_search', 'search_entity' => 'profiles', 'group' => 'select_by', ], 'by_name_pattern' => [ 'label' => $this->transEntitySelector('Name contains'), - 'icon' => 'icon-font', + 'icon' => 'text_fields', 'value_type' => 'pattern', 'group' => 'filter_by', ], @@ -2816,26 +2692,26 @@ trait EntitySelector return [ 'all' => [ 'label' => $this->transEntitySelector('All order states'), - 'icon' => 'icon-asterisk', + 'icon' => 'star', 'value_type' => 'none', 'group' => '', ], 'specific' => [ 'label' => $this->transEntitySelector('Specific states'), - 'icon' => 'icon-tasks', + 'icon' => 'task_alt', 'value_type' => 'entity_search', 'search_entity' => 'order_states', 'group' => 'select_by', ], 'by_name_pattern' => [ 'label' => $this->transEntitySelector('Name contains'), - 'icon' => 'icon-font', + 'icon' => 'text_fields', 'value_type' => 'pattern', 'group' => 'filter_by', ], 'by_paid' => [ 'label' => $this->transEntitySelector('Payment status'), - 'icon' => 'icon-money', + 'icon' => 'payments', 'value_type' => 'select', 'options' => [ 'paid' => $this->transEntitySelector('Paid'), @@ -2845,7 +2721,7 @@ trait EntitySelector ], 'by_shipped' => [ 'label' => $this->transEntitySelector('Shipping status'), - 'icon' => 'icon-truck', + 'icon' => 'local_shipping', 'value_type' => 'select', 'options' => [ 'shipped' => $this->transEntitySelector('Shipped'), @@ -2855,7 +2731,7 @@ trait EntitySelector ], 'by_delivery' => [ 'label' => $this->transEntitySelector('Delivery status'), - 'icon' => 'icon-check-circle', + 'icon' => 'check_circle', 'value_type' => 'select', 'options' => [ 'delivered' => $this->transEntitySelector('Delivered'), @@ -2874,32 +2750,32 @@ trait EntitySelector return [ 'all' => [ 'label' => $this->transEntitySelector('All taxes'), - 'icon' => 'icon-asterisk', + 'icon' => 'star', 'value_type' => 'none', 'group' => '', ], 'specific' => [ 'label' => $this->transEntitySelector('Specific taxes'), - 'icon' => 'icon-money', + 'icon' => 'payments', 'value_type' => 'entity_search', 'search_entity' => 'taxes', 'group' => 'select_by', ], 'by_name_pattern' => [ 'label' => $this->transEntitySelector('Name contains'), - 'icon' => 'icon-font', + 'icon' => 'text_fields', 'value_type' => 'pattern', 'group' => 'filter_by', ], 'by_rate_range' => [ 'label' => $this->transEntitySelector('Rate range'), - 'icon' => 'icon-calculator', + 'icon' => 'calculate', 'value_type' => 'numeric_range', 'group' => 'filter_by', ], 'by_active_status' => [ 'label' => $this->transEntitySelector('Status'), - 'icon' => 'icon-toggle-on', + 'icon' => 'toggle_on', 'value_type' => 'select', 'options' => [ 'active' => $this->transEntitySelector('Active'), diff --git a/src/EntitySelector/EntitySelectorRenderer.php b/src/EntitySelector/EntitySelectorRenderer.php index 1408f32..c4a2b95 100644 --- a/src/EntitySelector/EntitySelectorRenderer.php +++ b/src/EntitySelector/EntitySelectorRenderer.php @@ -53,6 +53,210 @@ class EntitySelectorRenderer $this->translator = $translator; } + // --------------------------------------------------------------- + // Icon framework abstraction (Material Icons vs FontAwesome 4) + // --------------------------------------------------------------- + + /** + * Material Icons → FontAwesome 4 class mapping + */ + private static $fa4Map = [ + 'account_tree' => 'icon-sitemap', + 'add' => 'icon-plus', + 'add_box' => 'icon-plus-square', + 'arrow_downward' => 'icon-sort-desc', + 'arrow_drop_down' => 'icon-caret-down', + 'arrow_right' => 'icon-chevron-right', + 'arrow_upward' => 'icon-sort-asc', + 'block' => 'icon-ban', + 'brush' => 'icon-paint-brush', + 'business' => 'icon-building', + 'check' => 'icon-check', + 'check_box' => 'icon-check-square', + 'check_box_outline_blank' => 'icon-square-o', + 'check_circle' => 'icon-check-circle', + 'close' => 'icon-times', + 'delete' => 'icon-trash', + 'description' => 'icon-file-text', + 'error' => 'icon-exclamation-circle', + 'event' => 'icon-calendar', + 'event_busy' => 'icon-calendar-times-o', + 'expand_less' => 'icon-chevron-up', + 'expand_more' => 'icon-chevron-down', + 'filter_list' => 'icon-filter', + 'flag' => 'icon-flag', + 'folder' => 'icon-folder', + 'folder_open' => 'icon-folder-open', + 'indeterminate_check_box' => 'icon-minus-square', + 'info' => 'icon-info-circle', + 'inventory_2' => 'icon-archive', + 'label' => 'icon-tag', + 'language' => 'icon-globe', + 'lightbulb' => 'icon-lightbulb-o', + 'list' => 'icon-list', + 'list_alt' => 'icon-list-alt', + 'local_shipping' => 'icon-truck', + 'lock' => 'icon-lock', + 'my_location' => 'icon-crosshairs', + 'open_in_full' => 'icon-expand', + 'payments' => 'icon-credit-card', + 'progress_activity' => 'icon-circle-o-notch', + 'schedule' => 'icon-clock-o', + 'search' => 'icon-search', + 'shopping_cart' => 'icon-shopping-cart', + 'sort' => 'icon-sort', + 'sort_by_alpha' => 'icon-sort-alpha-asc', + 'star' => 'icon-star', + 'sync' => 'icon-refresh', + 'tune' => 'icon-sliders', + 'visibility' => 'icon-eye', + 'warning' => 'icon-warning', + 'widgets' => 'icon-th-large', + ]; + + /** + * FontAwesome 4 class → Material Icons reverse mapping. + * Built once from $fa4Map on first use. + * @var array|null + */ + private static $reverseFa4Map = null; + + /** + * Extra FA4→Material mappings for icon names used in block configs + * that don't appear in the standard fa4Map (e.g. icon-cube, icon-folder-o). + */ + private static $extraReverseMappings = [ + 'icon-cube' => 'inventory', + 'icon-folder-o' => 'folder', + 'icon-file-text-o' => 'description', + 'icon-briefcase' => 'work', + 'icon-user' => 'person', + 'icon-users' => 'group', + 'icon-money' => 'payments', + 'icon-tasks' => 'checklist', + 'icon-calculator' => 'calculate', + 'icon-asterisk' => 'star', + 'icon-bar-chart' => 'bar_chart', + 'icon-cogs' => 'settings', + 'icon-cog' => 'settings', + 'icon-tags' => 'label', + 'icon-list-ul' => 'list', + 'icon-th' => 'grid_view', + 'icon-certificate' => 'verified', + 'icon-power-off' => 'power_settings_new', + 'icon-circle-o' => 'radio_button_unchecked', + ]; + + /** + * Get the reverse FA4→Material mapping (built lazily from $fa4Map + extras). + * + * @return array + */ + private static function getReverseFa4Map() + { + if (self::$reverseFa4Map === null) { + self::$reverseFa4Map = array_flip(self::$fa4Map); + // Merge extras (extras take priority for icons not in the flipped map) + foreach (self::$extraReverseMappings as $fa4Class => $materialName) { + if (!isset(self::$reverseFa4Map[$fa4Class])) { + self::$reverseFa4Map[$fa4Class] = $materialName; + } + } + } + return self::$reverseFa4Map; + } + + /** + * Normalize an icon name to the canonical format for the current mode. + * Handles both Material Icons names and FA4 class names as input. + * + * @param string $name Icon name (Material or FA4 format) + * @return array ['name' => string, 'extra' => string] normalized name + any extra classes + */ + protected function normalizeIconName($name) + { + $extra = ''; + + // If name starts with 'icon-', it's an FA4 class name + if (strpos($name, 'icon-') === 0) { + // Extract extra CSS classes (e.g. "icon-power-off text-success" → "icon-power-off" + "text-success") + $parts = explode(' ', $name, 2); + $fa4Class = $parts[0]; + if (isset($parts[1])) { + $extra = $parts[1]; + } + + if ($this->getIconMode() === 'material') { + // Reverse map FA4→Material + $reverseMap = self::getReverseFa4Map(); + $materialName = $reverseMap[$fa4Class] ?? null; + if ($materialName) { + return ['name' => $materialName, 'extra' => $extra]; + } + // Last resort: strip 'icon-' prefix and convert hyphens to underscores + $fallback = str_replace('-', '_', substr($fa4Class, 5)); + return ['name' => $fallback, 'extra' => $extra]; + } + + // Already FA4 and mode is FA4 — use as-is + return ['name' => $fa4Class, 'extra' => $extra, 'raw_fa4' => true]; + } + + // Material Icons name — use as-is for material mode, map for FA4 mode + return ['name' => $name, 'extra' => $extra]; + } + + /** + * Detect icon mode based on PrestaShop version. + * PS 8+ / 9+ → material, PS 1.6 / 1.7 → fa4. + * + * @return string 'material' or 'fa4' + */ + protected function getIconMode() + { + return version_compare(_PS_VERSION_, '8.0.0', '>=') ? 'material' : 'fa4'; + } + + /** + * Render an icon element that works on both legacy and modern PS. + * Accepts both Material Icons names and FA4 class names as input. + * + * @param string $name Icon name (Material or FA4 format, e.g. 'shopping_cart' or 'icon-cube') + * @param string $extraClass Additional CSS class(es) + * @return string HTML + */ + protected function renderIcon($name, $extraClass = '') + { + $normalized = $this->normalizeIconName($name); + $iconName = $normalized['name']; + // Merge extra classes from normalization (e.g. "text-success" from "icon-power-off text-success") + if (!empty($normalized['extra'])) { + $extraClass = $extraClass ? $extraClass . ' ' . $normalized['extra'] : $normalized['extra']; + } + + if ($this->getIconMode() === 'material') { + $cls = 'material-icons es-icon'; + if ($extraClass) { + $cls .= ' ' . $extraClass; + } + return '' . htmlspecialchars($iconName, ENT_QUOTES, 'UTF-8') . ''; + } + + // FA4 mode + if (!empty($normalized['raw_fa4'])) { + // Input was already an FA4 class name — use directly + $cls = $iconName . ' es-icon'; + } else { + // Input was a Material name — map to FA4 + $mapped = self::$fa4Map[$iconName] ?? 'icon-circle'; + $cls = $mapped . ' es-icon'; + } + if ($extraClass) { + $cls .= ' ' . $extraClass; + } + return ''; + } + /** * Set block definitions * @@ -121,7 +325,6 @@ class EntitySelectorRenderer 'show_cms' => true, 'show_cms_categories' => true, 'combination_mode' => 'products', - 'product_selection_level' => 'product', 'mode' => 'multi', 'blocks' => [], 'customBlocks' => [], @@ -140,9 +343,6 @@ class EntitySelectorRenderer if (is_string($savedData)) { $savedData = json_decode($savedData, true) ?: []; } - if (!is_array($savedData)) { - $savedData = []; - } // Determine which block is active $enabledBlocks = []; @@ -166,7 +366,7 @@ class EntitySelectorRenderer 'label' => $blockDef['label'] ?? $blockType, 'entity_label' => $blockDef['label'] ?? $blockType, 'entity_label_plural' => $blockDef['label'] ?? $blockType, - 'icon' => $blockDef['icon'] ?? 'icon-cog', + 'icon' => $blockDef['icon'] ?? 'settings', 'search_entity' => $blockType, 'selection_methods' => [], ], $blockDef); @@ -217,6 +417,7 @@ class EntitySelectorRenderer $html = '
    escapeAttr($config['id']) . '"'; $html .= ' data-mode="' . $this->escapeAttr($globalMode) . '"'; + $html .= ' data-icon-mode="' . $this->getIconMode() . '"'; if (!empty($config['required'])) { $html .= ' data-required="1"'; $requiredMsg = !empty($config['required_message']) @@ -246,6 +447,7 @@ class EntitySelectorRenderer $html .= ''; $html .= '
    '; // End condition-trait-body + $html .= '
    '; // End target-conditions-trait return $html; @@ -284,6 +486,7 @@ class EntitySelectorRenderer $html .= '
    escapeAttr($config['id']) . '"'; $html .= ' data-mode="' . $this->escapeAttr($globalMode) . '"'; + $html .= ' data-icon-mode="' . $this->getIconMode() . '"'; if (!empty($config['required'])) { $html .= ' data-required="1"'; $requiredMsg = !empty($config['required_message']) @@ -304,7 +507,7 @@ class EntitySelectorRenderer if ($globalMode !== 'single') { $html .= '
    '; $html .= ''; $html .= '
    '; } @@ -320,6 +523,7 @@ class EntitySelectorRenderer $html .= ''; $html .= '
    '; // End condition-trait-body + $html .= '
    '; // End target-conditions-trait // Subtitle as help text @@ -358,6 +562,7 @@ class EntitySelectorRenderer $html = '
    escapeAttr($config['id']) . '"'; $html .= ' data-mode="' . $this->escapeAttr($globalMode) . '"'; + $html .= ' data-icon-mode="' . $this->getIconMode() . '"'; if (!empty($config['required'])) { $html .= ' data-required="1"'; $requiredMsg = !empty($config['required_message']) @@ -373,7 +578,7 @@ class EntitySelectorRenderer // Actions: expand/collapse toggle (entire area is clickable) $html .= '
    '; - $html .= '' . ($collapsed ? 'expand_more' : 'expand_less') . ''; + $html .= $this->renderIcon($collapsed ? 'expand_more' : 'expand_less'); $html .= '
    '; $html .= '
    '; // End tabs-row @@ -392,6 +597,7 @@ class EntitySelectorRenderer // Hidden input (outside collapsed area) $html .= ''; + $html .= '
    '; // End target-conditions-trait return $html; @@ -409,12 +615,12 @@ class EntitySelectorRenderer { $html = '
    '; $html .= '
    '; - $html .= ''; + $html .= $this->renderIcon('my_location', 'trait-icon'); $html .= '
    '; $html .= '' . $this->escapeAttr($config['title']) . ''; $html .= '' . $this->escapeAttr($config['subtitle']) . ''; $html .= '
    '; - $html .= ''; + $html .= ''; $html .= '
    '; $html .= '
    '; @@ -429,7 +635,7 @@ class EntitySelectorRenderer if ($globalMode !== 'single') { $html .= '
    '; $html .= ''; $html .= '
    '; } @@ -513,11 +719,11 @@ class EntitySelectorRenderer $blockMode = $blockSettings[$blockType]['mode'] ?? 'multi'; $html .= ''; } @@ -562,16 +768,16 @@ class EntitySelectorRenderer { $html = '
    '; $html .= '
    '; - $html .= ''; + $html .= $this->renderIcon('lightbulb'); $html .= '' . $this->trans('Pro Tips: Combine include & exclude for powerful targeting') . ''; - $html .= ''; + $html .= $this->renderIcon('expand_more', 'tips-toggle'); $html .= '
    '; $html .= '
    '; $html .= '
    '; // Example 1 $html .= '
    '; - $html .= '
    '; + $html .= '
    ' . $this->renderIcon('check_circle') . '
    '; $html .= '
    '; $html .= '' . $this->trans('Target entire catalog with exceptions') . ''; $html .= '

    ' . $this->trans('Select "All products", then exclude specific categories like "Sale" or "Clearance" where you don\'t want the rule to apply.') . '

    '; @@ -580,7 +786,7 @@ class EntitySelectorRenderer // Example 2 $html .= '
    '; - $html .= '
    '; + $html .= '
    ' . $this->renderIcon('filter_list') . '
    '; $html .= '
    '; $html .= '' . $this->trans('Combine features for precise filtering') . ''; $html .= '

    ' . $this->trans('Target all "Cotton" products, then exclude those with "Black" color feature. Perfect for material-specific promotions.') . '

    '; @@ -589,7 +795,7 @@ class EntitySelectorRenderer // Example 3 $html .= '
    '; - $html .= '
    '; + $html .= '
    ' . $this->renderIcon('account_tree') . '
    '; $html .= '
    '; $html .= '' . $this->trans('Category-based targeting') . ''; $html .= '

    ' . $this->trans('Include entire "Men\'s Clothing" category, exclude "Accessories" subcategory. Hierarchy is respected automatically.') . '

    '; @@ -598,7 +804,7 @@ class EntitySelectorRenderer // Example 4 $html .= '
    '; - $html .= '
    '; + $html .= '
    ' . $this->renderIcon('business') . '
    '; $html .= '
    '; $html .= '' . $this->trans('Brand exclusions') . ''; $html .= '

    ' . $this->trans('Target all products from "Nike" manufacturer, but exclude items already on sale (by price range or specific products).') . '

    '; @@ -607,7 +813,7 @@ class EntitySelectorRenderer $html .= '
    '; // End tips-grid $html .= ''; $html .= '
    '; // End tips-content @@ -707,10 +913,10 @@ class EntitySelectorRenderer $html .= ''; } @@ -768,11 +974,11 @@ class EntitySelectorRenderer $html = '
    '; $html .= '
    '; - $html .= ' '; + $html .= $this->renderIcon('tune') . ' '; $html .= '' . $this->trans('Result modifiers') . ''; $html .= '' . $this->trans('(optional)') . ''; - $html .= ''; - $html .= 'info'; + $html .= ''; + $html .= $this->renderIcon('info'); $html .= ''; $html .= '
    '; @@ -911,17 +1117,17 @@ class EntitySelectorRenderer // Group header if ($mode === 'single') { $html .= '
    '; - $html .= ''; + $html .= ''; $html .= '
    '; } else { $html .= '
    '; - $html .= ''; + $html .= '' . $this->renderIcon('expand_less') . ''; $html .= ''; $html .= ''; - $html .= ''; + $html .= ''; $html .= ''; $html .= ''; $html .= '
    '; } @@ -938,15 +1144,15 @@ class EntitySelectorRenderer $methodHelp = $this->getMethodHelpTooltip($includeMethod, $blockType); $html .= ''; if (!empty($methodHelp)) { - $html .= ''; - $html .= 'info'; + $html .= ''; + $html .= $this->renderIcon('info'); $html .= ''; } $html .= ''; $html .= ''; - $html .= ' 0'; + $html .= '' . $this->renderIcon('visibility') . ' 0'; $html .= '
    '; // Value picker @@ -961,7 +1167,7 @@ class EntitySelectorRenderer if ($hasExcludes) { $html .= '
    '; - $html .= ' ' . $this->trans('EXCEPT') . ''; + $html .= '' . $this->renderIcon('block') . ' ' . $this->trans('EXCEPT') . ''; $html .= '
    '; $html .= '
    '; @@ -971,11 +1177,11 @@ class EntitySelectorRenderer $html .= '
    '; $html .= ''; } else { $html .= ''; } @@ -1033,15 +1239,15 @@ class EntitySelectorRenderer $html .= ''; } $html .= ''; - $sortDirIcon = ($sortDir === 'ASC') ? 'icon-sort-amount-asc' : 'icon-sort-amount-desc'; + $sortDirIcon = ($sortDir === 'ASC') ? 'arrow_upward' : 'arrow_downward'; $html .= ''; $html .= ''; // Preview badge $html .= ''; - $html .= ' '; + $html .= $this->renderIcon('visibility') . ' '; $html .= ''; $html .= '
    '; @@ -1155,8 +1361,8 @@ class EntitySelectorRenderer $methodHelp = $this->getMethodHelpTooltip($excludeMethod, $blockType); $html .= ''; if (!empty($methodHelp)) { - $html .= ''; - $html .= 'info'; + $html .= ''; + $html .= $this->renderIcon('info'); $html .= ''; } $html .= ''; @@ -1165,11 +1371,11 @@ class EntitySelectorRenderer $html .= $this->renderMethodOptions($methods, $excludeMethod, true); $html .= ''; - $html .= ' 0'; + $html .= '' . $this->renderIcon('visibility') . ' 0'; $html .= '
    '; // End method-selector-wrapper $html .= ''; $html .= '
    '; @@ -1215,9 +1421,9 @@ class EntitySelectorRenderer // Don't pre-wrap chips - JS will create the wrapper with toolbar when chips are added $html .= '
    '; $html .= ''; $html .= ''; break; @@ -1229,7 +1435,7 @@ class EntitySelectorRenderer $html .= ''; $html .= ''; $html .= ''; - $html .= ''; + $html .= ''; $html .= '
    '; $html .= '
    '; $html .= ''; @@ -1258,7 +1464,7 @@ class EntitySelectorRenderer $html .= ''; $html .= '-'; $html .= ''; - $html .= ''; + $html .= ''; $html .= '
    '; $html .= '
    '; $html .= ''; @@ -1275,7 +1481,7 @@ class EntitySelectorRenderer $optIcon = is_array($optData) ? ($optData['icon'] ?? '') : ''; $html .= ''; @@ -1546,7 +1752,6 @@ class EntitySelectorRenderer ], 'methodHelp' => $this->getAllMethodHelpContent(), 'combinationMode' => $config['combination_mode'] ?? 'products', - 'productSelectionLevel' => $config['product_selection_level'] ?? 'product', 'emptyMeansAll' => $config['empty_means_all'] ?? true, ]; } @@ -1582,23 +1787,23 @@ class EntitySelectorRenderer switch ($sortBy) { case 'name': - return $isAsc ? 'icon-sort-alpha-asc' : 'icon-sort-alpha-desc'; + return $isAsc ? 'sort_by_alpha' : 'sort_by_alpha'; case 'price': case 'quantity': case 'product_count': - return $isAsc ? 'icon-sort-numeric-asc' : 'icon-sort-numeric-desc'; + return $isAsc ? 'sort' : 'sort'; case 'date_add': case 'newest_products': - return $isAsc ? 'icon-sort-numeric-asc' : 'icon-sort-numeric-desc'; + return $isAsc ? 'sort' : 'sort'; case 'sales': case 'total_sales': - return $isAsc ? 'icon-sort-amount-asc' : 'icon-sort-amount-desc'; + return $isAsc ? 'arrow_upward' : 'arrow_downward'; case 'position': - return $isAsc ? 'icon-sort-numeric-asc' : 'icon-sort-numeric-desc'; + return $isAsc ? 'sort' : 'sort'; case 'random': - return 'icon-random'; + return 'shuffle'; default: - return $isAsc ? 'icon-sort-amount-asc' : 'icon-sort-amount-desc'; + return $isAsc ? 'arrow_upward' : 'arrow_downward'; } } } diff --git a/src/ScheduleConditions.php b/src/ScheduleConditions.php index 344b929..fafb6cb 100755 --- a/src/ScheduleConditions.php +++ b/src/ScheduleConditions.php @@ -855,8 +855,8 @@ trait ScheduleConditions $html .= ''; - $html .= ''; - $html .= 'info'; + $html .= ''; + $html .= ''; $html .= ''; $html .= '
    ';