/** * Schedule Conditions - JavaScript * Handles the interactive functionality for schedule-based conditions. * Features: * - Datetime range inputs * - Visual per-day timelines with draggable handles */ (function($) { 'use strict'; var ScheduleConditions = { config: {}, dragging: null, init: function(options) { console.log('[ScheduleConditions] Initializing...'); this.config = $.extend({ id: 'schedule-conditions', namePrefix: 'schedule_', trans: {} }, options); // Add fullwidth class to all condition-trait parent form-groups (fallback for browsers without :has()) console.log('[ScheduleConditions] DEBUG: Found condition-trait elements:', $('.condition-trait').length); $('.condition-trait').each(function() { var $formGroup = $(this).closest('.form-group'); console.log('[ScheduleConditions] DEBUG: Adding fullwidth to form-group', $formGroup.length, $formGroup.attr('class')); $formGroup.addClass('condition-trait-fullwidth'); // Also remove the offset class that causes margin-left: 25% $formGroup.find('.col-lg-offset-3').removeClass('col-lg-offset-3'); console.log('[ScheduleConditions] DEBUG: After addClass:', $formGroup.attr('class')); }); this.bindEvents(); this.initTimelines(); this.initCollapsibleSections(); // Debug: Check if toggle button exists var $toggleBtn = $('.schedule-conditions .btn-toggle-groups'); console.log('[ScheduleConditions] Toggle button found:', $toggleBtn.length); if ($toggleBtn.length) { console.log('[ScheduleConditions] Toggle button data-state:', $toggleBtn.attr('data-state')); } }, bindEvents: function() { var self = this; // Toggle enabled/disabled (Always = 0/on, Scheduled = 1/off) $(document).on('change', '.schedule-enabled-toggle', function() { var $wrapper = $(this).closest('.schedule-conditions'); var $body = $wrapper.find('.condition-trait-body'); // value="1" means schedule is enabled (show body) var isScheduled = $(this).val() === '1' && $(this).is(':checked'); if (isScheduled) { $body.slideDown(200); $wrapper.removeClass('collapsed'); } else { $body.slideUp(200); $wrapper.addClass('collapsed'); } }); // Header click to toggle collapse (except when clicking switch) // Handles Schedule (.schedule-conditions) and Context (.context-conditions-trait) // Note: TargetConditions (.target-conditions-trait) has its own handler in target-conditions.js $(document).on('click', '.condition-trait .condition-trait-header', function(e) { // Don't toggle if clicking the switch or other interactive elements if ($(e.target).closest('.prestashop-switch, .trait-header-actions').length) { return; } var $wrapper = $(this).closest('.condition-trait'); // Skip if this is TargetConditions - it has its own handler in target-conditions.js if ($wrapper.hasClass('target-conditions-trait')) { return; } var $body = $wrapper.find('.condition-trait-body'); // Use visibility check and stop any pending animations $body.stop(true, true); if ($body.is(':visible')) { $body.slideUp(200); $wrapper.addClass('collapsed'); } else { $body.slideDown(200); $wrapper.removeClass('collapsed'); } }); // Holiday exclusion toggle (radio button: value="1" = enabled) $(document).on('change', '.holiday-exclude-toggle', function() { var $wrapper = $(this).closest('.schedule-holidays'); var $countriesWrapper = $wrapper.find('.holiday-countries-wrapper'); // Radio button: value="1" and checked means enabled var isEnabled = $(this).val() === '1' && $(this).is(':checked'); if (isEnabled) { $countriesWrapper.slideDown(200); } else { $countriesWrapper.slideUp(200); } }); // Collapsible section header click $(document).on('click', '.collapsible-section .section-header', function(e) { // Don't toggle if clicking the switch or holiday toggle if ($(e.target).closest('.prestashop-switch, .holiday-enable-toggle').length) { return; } var $section = $(this).closest('.collapsible-section'); var $content = $section.find('.section-content'); // Use visibility check instead of class - more reliable if ($content.is(':visible')) { $content.stop(true, true).slideUp(200); $section.addClass('collapsed'); } else { $content.stop(true, true).slideDown(200); $section.removeClass('collapsed'); } // Update expand/collapse all button state self.updateToggleSectionsButton($section.closest('.condition-trait-body')); }); // Expand/collapse all sections button $(document).on('click', '.schedule-conditions .btn-toggle-groups', function(e) { e.preventDefault(); e.stopPropagation(); var $btn = $(this); var $wrapper = $btn.closest('.schedule-conditions'); var $body = $wrapper.find('.condition-trait-body'); var $sections = $body.find('.collapsible-section'); var currentState = $btn.attr('data-state') || 'collapsed'; console.log('[ScheduleConditions] btn-toggle-groups clicked, state:', currentState, 'sections:', $sections.length); if (currentState === 'expanded') { // Collapse all $sections.each(function() { var $section = $(this); var $content = $section.find('.section-content'); $content.stop(true, true).slideUp(200); $section.addClass('collapsed'); }); $btn.attr('data-state', 'collapsed'); $btn.attr('title', 'Expand all sections'); $btn.find('i').removeClass('icon-compress').addClass('icon-expand'); } else { // Expand all $sections.each(function() { var $section = $(this); var $content = $section.find('.section-content'); $content.stop(true, true).slideDown(200); $section.removeClass('collapsed'); }); $btn.attr('data-state', 'expanded'); $btn.attr('title', 'Collapse all sections'); $btn.find('i').removeClass('icon-expand').addClass('icon-compress'); } }); // Holiday country picker - initialize data self.initHolidayCountryPickers(); // Holiday country search input focus $(document).on('focus', '.holiday-country-search-input', function() { var $picker = $(this).closest('.holiday-country-picker'); self.showHolidayCountryDropdown($picker, $(this).val()); }); // Holiday country search input typing $(document).on('input', '.holiday-country-search-input', function() { var $picker = $(this).closest('.holiday-country-picker'); self.showHolidayCountryDropdown($picker, $(this).val()); }); // Holiday country dropdown item click $(document).on('click', '.holiday-country-dropdown .dropdown-item', function(e) { e.preventDefault(); e.stopPropagation(); var $item = $(this); var $picker = $item.closest('.holiday-country-picker'); var id = parseInt($item.data('id'), 10); var isSelected = $item.hasClass('selected'); if (isSelected) { self.removeHolidayCountry($picker, id); } else { self.addHolidayCountry($picker, id); } $item.toggleClass('selected'); }); // Holiday country chip remove $(document).on('click', '.holiday-country-picker .chip-remove', function(e) { e.preventDefault(); e.stopPropagation(); var $chip = $(this).closest('.input-chip'); var $picker = $(this).closest('.holiday-country-picker'); var id = parseInt($chip.data('id'), 10); self.removeHolidayCountry($picker, id); // Update dropdown if visible var $dropdown = $picker.find('.holiday-country-dropdown'); if ($dropdown.hasClass('show')) { $dropdown.find('.dropdown-item[data-id="' + id + '"]').removeClass('selected'); } }); // Holiday dropdown filter tabs $(document).on('click', '.holiday-country-dropdown .tab-btn', function(e) { e.preventDefault(); var $btn = $(this); var $picker = $btn.closest('.holiday-country-picker'); var filter = $btn.data('filter'); $btn.addClass('active').siblings().removeClass('active'); $picker.data('filter', filter); var query = $picker.find('.holiday-country-search-input').val(); self.showHolidayCountryDropdown($picker, query); }); // Close holiday dropdown on outside click $(document).on('click', function(e) { if (!$(e.target).closest('.holiday-country-picker').length) { $('.holiday-country-dropdown.show').removeClass('show'); } }); // Holiday dropdown - Select All button $(document).on('click', '.holiday-country-dropdown .btn-select-all', function(e) { e.preventDefault(); e.stopPropagation(); var $picker = $(this).closest('.holiday-country-picker'); self.selectAllHolidayCountries($picker); }); // Holiday dropdown - Clear selection button $(document).on('click', '.holiday-country-dropdown .btn-clear-selection', function(e) { e.preventDefault(); e.stopPropagation(); var $picker = $(this).closest('.holiday-country-picker'); self.clearHolidayCountries($picker); }); // Holiday dropdown - Sort field change $(document).on('change', '.holiday-country-dropdown .sort-field-select', function(e) { e.stopPropagation(); var $picker = $(this).closest('.holiday-country-picker'); $picker.data('sortField', $(this).val()); var query = $picker.find('.holiday-country-search-input').val(); self.showHolidayCountryDropdown($picker, query); }); // Holiday dropdown - Sort direction toggle $(document).on('click', '.holiday-country-dropdown .btn-sort-dir', function(e) { e.preventDefault(); e.stopPropagation(); var $btn = $(this); var $picker = $btn.closest('.holiday-country-picker'); var currentDir = $picker.data('sortDir') || 'ASC'; var newDir = currentDir === 'ASC' ? 'DESC' : 'ASC'; $picker.data('sortDir', newDir); $btn.data('dir', newDir); // Update icon var $icon = $btn.find('i'); if (newDir === 'ASC') { $icon.removeClass('icon-sort-alpha-desc').addClass('icon-sort-alpha-asc'); } else { $icon.removeClass('icon-sort-alpha-asc').addClass('icon-sort-alpha-desc'); } var query = $picker.find('.holiday-country-search-input').val(); self.showHolidayCountryDropdown($picker, query); }); // Holiday dropdown - View mode change $(document).on('change', '.holiday-country-dropdown .view-mode-select', function(e) { e.stopPropagation(); var $picker = $(this).closest('.holiday-country-picker'); $picker.data('viewMode', $(this).val()); var query = $picker.find('.holiday-country-search-input').val(); self.showHolidayCountryDropdown($picker, query); }); // Holiday dropdown - Refine input $(document).on('input', '.holiday-country-dropdown .refine-input', function(e) { e.stopPropagation(); var $input = $(this); var $picker = $input.closest('.holiday-country-picker'); var $clearBtn = $picker.find('.btn-clear-refine'); var value = $input.val().toLowerCase().trim(); $picker.data('refineQuery', value); $clearBtn.toggle(value.length > 0); var query = $picker.find('.holiday-country-search-input').val(); self.showHolidayCountryDropdown($picker, query); }); // Holiday dropdown - Refine negate toggle $(document).on('click', '.holiday-country-dropdown .btn-refine-negate', function(e) { e.preventDefault(); e.stopPropagation(); var $btn = $(this); var $picker = $btn.closest('.holiday-country-picker'); var isNegate = !$picker.data('refineNegate'); $picker.data('refineNegate', isNegate); $btn.toggleClass('active', isNegate); var query = $picker.find('.holiday-country-search-input').val(); self.showHolidayCountryDropdown($picker, query); }); // Holiday dropdown - Clear refine $(document).on('click', '.holiday-country-dropdown .btn-clear-refine', function(e) { e.preventDefault(); e.stopPropagation(); var $picker = $(this).closest('.holiday-country-picker'); var $input = $picker.find('.refine-input'); $input.val(''); $picker.data('refineQuery', ''); $(this).hide(); var query = $picker.find('.holiday-country-search-input').val(); self.showHolidayCountryDropdown($picker, query); }); // Holiday dropdown - Cancel button (close without changes) $(document).on('click', '.holiday-country-dropdown .btn-cancel-dropdown', function(e) { e.preventDefault(); e.stopPropagation(); var $dropdown = $(this).closest('.holiday-country-dropdown'); $dropdown.removeClass('show'); }); // Holiday dropdown - Done button (confirm and close) $(document).on('click', '.holiday-country-dropdown .btn-confirm-dropdown', function(e) { e.preventDefault(); e.stopPropagation(); var $dropdown = $(this).closest('.holiday-country-dropdown'); $dropdown.removeClass('show'); }); // Holiday dropdown - Keyboard shortcuts $(document).on('keydown', '.holiday-country-picker', function(e) { var $picker = $(this); var $dropdown = $picker.find('.holiday-country-dropdown'); if (!$dropdown.hasClass('show')) { return; } // Escape - close dropdown if (e.keyCode === 27) { e.preventDefault(); $dropdown.removeClass('show'); return; } // Enter - confirm and close if (e.keyCode === 13) { e.preventDefault(); $dropdown.removeClass('show'); return; } // Ctrl+A - select all if (e.ctrlKey && (e.keyCode === 65 || e.keyCode === 97)) { e.preventDefault(); self.selectAllHolidayCountries($picker); return; } // Ctrl+D - clear selection if (e.ctrlKey && (e.keyCode === 68 || e.keyCode === 100)) { e.preventDefault(); self.clearHolidayCountries($picker); return; } }); // Datetime validation $(document).on('change', '.schedule-datetime-range input[type="datetime-local"]', function() { var $container = $(this).closest('.schedule-datetime-range'); var $startInput = $container.find('input[name$="datetime_start"]'); var $endInput = $container.find('input[name$="datetime_end"]'); var startDatetime = $startInput.val(); var endDatetime = $endInput.val(); if (startDatetime && endDatetime && endDatetime < startDatetime) { if ($(this).attr('name').indexOf('datetime_start') !== -1) { $endInput.val(startDatetime); } else { $startInput.val(endDatetime); } } }); // Day enabled checkbox $(document).on('change', '.day-enabled', function() { var $timeline = $(this).closest('.day-timeline'); var $track = $timeline.find('.timeline-track'); var $inputs = $timeline.find('.time-input'); var isEnabled = $(this).is(':checked'); $track.toggleClass('disabled', !isEnabled); $inputs.prop('disabled', !isEnabled); self.updateWeeklyScheduleData($timeline.closest('.schedule-weekly')); }); // Time input change $(document).on('change blur', '.time-input', function() { var $input = $(this); var $timeline = $input.closest('.day-timeline'); var value = $input.val().trim(); // Parse time value var minutes = self.parseTimeInput(value); if (minutes === null) { // Invalid - reset to previous value var isStart = $input.hasClass('time-input-start'); var currentStart = self.getHandlePosition($timeline.find('.handle-start')); var currentEnd = self.getHandlePosition($timeline.find('.handle-end')); $input.val(self.formatMinutes(isStart ? currentStart : currentEnd)); return; } var isStart = $input.hasClass('time-input-start'); var startMinutes = self.getHandlePosition($timeline.find('.handle-start')); var endMinutes = self.getHandlePosition($timeline.find('.handle-end')); if (isStart) { minutes = Math.min(minutes, endMinutes - 15); self.setTimelineRange($timeline, minutes, endMinutes); } else { minutes = Math.max(minutes, startMinutes + 15); self.setTimelineRange($timeline, startMinutes, minutes); } self.updateWeeklyScheduleData($timeline.closest('.schedule-weekly')); }); // Copy Monday to all days $(document).on('click', '.btn-copy-first-day', function(e) { e.preventDefault(); var $section = $(this).closest('.schedule-weekly'); var $mondayTimeline = $section.find('.day-timeline[data-day="1"]'); if (!$mondayTimeline.length) return; var mondayEnabled = $mondayTimeline.find('.day-enabled').is(':checked'); var mondayStart = self.getHandlePosition($mondayTimeline.find('.handle-start')); var mondayEnd = self.getHandlePosition($mondayTimeline.find('.handle-end')); $section.find('.day-timeline').each(function() { var $timeline = $(this); if ($timeline.data('day') === 1) return; $timeline.find('.day-enabled').prop('checked', mondayEnabled).trigger('change'); self.setTimelineRange($timeline, mondayStart, mondayEnd); }); self.updateWeeklyScheduleData($section); }); // Reset all days $(document).on('click', '.btn-reset-schedule', function(e) { e.preventDefault(); var $section = $(this).closest('.schedule-weekly'); $section.find('.day-timeline').each(function() { var $timeline = $(this); $timeline.find('.day-enabled').prop('checked', true); $timeline.find('.timeline-track').removeClass('disabled'); self.setTimelineRange($timeline, 0, 1440); }); self.updateWeeklyScheduleData($section); }); // Timeline handle drag $(document).on('mousedown touchstart', '.timeline-handle', function(e) { e.preventDefault(); var $handle = $(this); var $track = $handle.closest('.timeline-track'); if ($track.hasClass('disabled')) return; self.dragging = { handle: $handle, timeline: $handle.closest('.day-timeline'), track: $track, isStart: $handle.hasClass('handle-start'), startX: e.type === 'touchstart' ? e.originalEvent.touches[0].clientX : e.clientX }; $(document).on('mousemove.timeline touchmove.timeline', function(e) { self.handleDrag(e); }); $(document).on('mouseup.timeline touchend.timeline', function() { self.handleDragEnd(); }); }); // Click on track to set position $(document).on('click', '.timeline-track', function(e) { var $track = $(this); if ($track.hasClass('disabled')) return; if ($(e.target).hasClass('timeline-handle')) return; var $timeline = $track.closest('.day-timeline'); var trackRect = $track[0].getBoundingClientRect(); var clickX = e.clientX - trackRect.left; var percent = Math.max(0, Math.min(1, clickX / trackRect.width)); var minutes = Math.round(percent * 1440); var startMinutes = self.getHandlePosition($timeline.find('.handle-start')); var endMinutes = self.getHandlePosition($timeline.find('.handle-end')); var midPoint = (startMinutes + endMinutes) / 2; if (minutes < midPoint) { self.setTimelineRange($timeline, minutes, endMinutes); } else { self.setTimelineRange($timeline, startMinutes, minutes); } self.updateWeeklyScheduleData($timeline.closest('.schedule-weekly')); }); }, initTimelines: function() { var self = this; $('.schedule-weekly').each(function() { var $section = $(this); var $input = $section.find('.weekly-schedule-data'); var data = {}; try { data = JSON.parse($input.val() || '{}'); } catch (e) { data = {}; } $section.find('.day-timeline').each(function() { var $timeline = $(this); var dayNum = parseInt($timeline.data('day'), 10); var dayData = data[dayNum] || {}; var enabled = dayData.enabled !== false; var start = typeof dayData.start === 'number' ? dayData.start : 0; var end = typeof dayData.end === 'number' ? dayData.end : 1440; $timeline.find('.day-enabled').prop('checked', enabled); $timeline.find('.timeline-track').toggleClass('disabled', !enabled); self.setTimelineRange($timeline, start, end); }); }); }, handleDrag: function(e) { if (!this.dragging) return; var clientX = e.type === 'touchmove' ? e.originalEvent.touches[0].clientX : e.clientX; var trackRect = this.dragging.track[0].getBoundingClientRect(); var offsetX = clientX - trackRect.left; var percent = Math.max(0, Math.min(1, offsetX / trackRect.width)); var minutes = Math.round(percent * 1440); // Snap to 15-minute intervals minutes = Math.round(minutes / 15) * 15; var $timeline = this.dragging.timeline; var startMinutes = this.getHandlePosition($timeline.find('.handle-start')); var endMinutes = this.getHandlePosition($timeline.find('.handle-end')); if (this.dragging.isStart) { minutes = Math.min(minutes, endMinutes - 15); this.setTimelineRange($timeline, minutes, endMinutes); } else { minutes = Math.max(minutes, startMinutes + 15); this.setTimelineRange($timeline, startMinutes, minutes); } }, handleDragEnd: function() { if (this.dragging) { this.updateWeeklyScheduleData(this.dragging.timeline.closest('.schedule-weekly')); } this.dragging = null; $(document).off('.timeline'); }, getHandlePosition: function($handle) { var leftPercent = parseFloat($handle.css('left')) / $handle.parent().width(); if (isNaN(leftPercent)) { leftPercent = parseFloat($handle[0].style.left) / 100; } return Math.round(leftPercent * 1440); }, setTimelineRange: function($timeline, startMinutes, endMinutes) { startMinutes = Math.max(0, Math.min(1440, startMinutes)); endMinutes = Math.max(0, Math.min(1440, endMinutes)); if (startMinutes > endMinutes) { var tmp = startMinutes; startMinutes = endMinutes; endMinutes = tmp; } var startPercent = (startMinutes / 1440) * 100; var endPercent = (endMinutes / 1440) * 100; var widthPercent = endPercent - startPercent; $timeline.find('.handle-start').css('left', startPercent + '%'); $timeline.find('.handle-end').css('left', endPercent + '%'); $timeline.find('.timeline-range').css({ left: startPercent + '%', width: widthPercent + '%' }); // Update both legacy text display and new input fields $timeline.find('.time-start').text(this.formatMinutes(startMinutes)); $timeline.find('.time-end').text(this.formatMinutes(endMinutes)); $timeline.find('.time-input-start').val(this.formatMinutes(startMinutes)); $timeline.find('.time-input-end').val(this.formatMinutes(endMinutes)); }, formatMinutes: function(minutes) { var hours = Math.floor(minutes / 60) % 24; var mins = minutes % 60; return (hours < 10 ? '0' : '') + hours + ':' + (mins < 10 ? '0' : '') + mins; }, parseTimeInput: function(value) { // Accept formats: HH:MM, H:MM, HHMM, HMM var match = value.match(/^(\d{1,2}):?(\d{2})$/); if (!match) return null; var hours = parseInt(match[1], 10); var mins = parseInt(match[2], 10); if (hours < 0 || hours > 24 || mins < 0 || mins > 59) return null; if (hours === 24 && mins > 0) return null; return (hours * 60) + mins; }, updateWeeklyScheduleData: function($section) { var self = this; var data = {}; $section.find('.day-timeline').each(function() { var $timeline = $(this); var dayNum = parseInt($timeline.data('day'), 10); data[dayNum] = { enabled: $timeline.find('.day-enabled').is(':checked'), start: self.getHandlePosition($timeline.find('.handle-start')), end: self.getHandlePosition($timeline.find('.handle-end')) }; }); $section.find('.weekly-schedule-data').val(JSON.stringify(data)); }, getData: function($wrapper) { if (!$wrapper) { $wrapper = $('.schedule-conditions'); } var prefix = this.config.namePrefix; var data = { // value="1" means "Scheduled" (enabled), value="0" means "Always" (disabled) enabled: $wrapper.find('.schedule-enabled-toggle[value="1"]').is(':checked'), datetime_start: $wrapper.find('input[name="' + prefix + 'datetime_start"]').val() || null, datetime_end: $wrapper.find('input[name="' + prefix + 'datetime_end"]').val() || null, weekly_schedule: {} }; var weeklyJson = $wrapper.find('.weekly-schedule-data').val(); if (weeklyJson) { try { data.weekly_schedule = JSON.parse(weeklyJson); } catch (e) { data.weekly_schedule = {}; } } return data; }, setData: function($wrapper, data) { if (!data) return; var self = this; var prefix = this.config.namePrefix; if (data.enabled) { $wrapper.find('.schedule-enabled-toggle[value="1"]').prop('checked', true).trigger('change'); } else { $wrapper.find('.schedule-enabled-toggle[value="0"]').prop('checked', true).trigger('change'); } if (data.datetime_start) { $wrapper.find('input[name="' + prefix + 'datetime_start"]').val(data.datetime_start); } if (data.datetime_end) { $wrapper.find('input[name="' + prefix + 'datetime_end"]').val(data.datetime_end); } if (data.weekly_schedule) { var $section = $wrapper.find('.schedule-weekly'); $section.find('.weekly-schedule-data').val(JSON.stringify(data.weekly_schedule)); $section.find('.day-timeline').each(function() { var $timeline = $(this); var dayNum = parseInt($timeline.data('day'), 10); var dayData = data.weekly_schedule[dayNum] || {}; var enabled = dayData.enabled !== false; var start = typeof dayData.start === 'number' ? dayData.start : 0; var end = typeof dayData.end === 'number' ? dayData.end : 1440; $timeline.find('.day-enabled').prop('checked', enabled); $timeline.find('.timeline-track').toggleClass('disabled', !enabled); self.setTimelineRange($timeline, start, end); }); } }, // ===================================================== // Holiday Country Picker Methods // ===================================================== initHolidayCountryPickers: function() { var self = this; $('.holiday-country-picker').each(function() { var $picker = $(this); // Parse countries data from data attribute var countriesJson = $picker.attr('data-countries'); if (countriesJson) { try { var countriesData = JSON.parse(countriesJson); $picker.data('countriesData', countriesData); // Build country map for quick lookup var countryMap = {}; countriesData.forEach(function(c) { countryMap[c.id] = c; }); $picker.data('countryMap', countryMap); } catch (e) { console.warn('ScheduleConditions: Failed to parse countries data', e); } } // Initialize selected IDs from existing chips var selectedIds = []; $picker.find('.input-chip').each(function() { selectedIds.push(parseInt($(this).data('id'), 10)); }); $picker.data('selectedIds', selectedIds); // Initialize state $picker.data('filter', 'with-holidays'); $picker.data('sortField', 'name'); $picker.data('sortDir', 'ASC'); $picker.data('viewMode', 'list'); $picker.data('refineQuery', ''); $picker.data('refineNegate', false); }); }, showHolidayCountryDropdown: function($picker, query) { var self = this; var $dropdown = $picker.find('.holiday-country-dropdown'); var countriesData = $picker.data('countriesData') || []; var selectedIds = $picker.data('selectedIds') || []; var filter = $picker.data('filter') || 'with-holidays'; var sortField = $picker.data('sortField') || 'name'; var sortDir = $picker.data('sortDir') || 'ASC'; var viewMode = $picker.data('viewMode') || 'list'; var refineQuery = $picker.data('refineQuery') || ''; var refineNegate = $picker.data('refineNegate') || false; query = (query || '').toLowerCase().trim(); // Filter countries var filtered = countriesData.filter(function(c) { // Filter by tab if (filter === 'with-holidays' && c.holidayCount === 0) { return false; } // Filter by search query if (query) { var name = (c.name || '').toLowerCase(); var iso = (c.iso || '').toLowerCase(); var zone = (c.zone || '').toLowerCase(); if (!(name.indexOf(query) !== -1 || iso.indexOf(query) !== -1 || zone.indexOf(query) !== -1)) { return false; } } // Apply refine filter if (refineQuery) { var name = (c.name || '').toLowerCase(); var iso = (c.iso || '').toLowerCase(); var zone = (c.zone || '').toLowerCase(); var matches = name.indexOf(refineQuery) !== -1 || iso.indexOf(refineQuery) !== -1 || zone.indexOf(refineQuery) !== -1; if (refineNegate) { if (matches) return false; } else { if (!matches) return false; } } return true; }); // Sort countries filtered.sort(function(a, b) { var aVal, bVal; switch (sortField) { case 'holidays': aVal = a.holidayCount || 0; bVal = b.holidayCount || 0; break; case 'zone': aVal = a.zone || ''; bVal = b.zone || ''; break; case 'selected': aVal = selectedIds.indexOf(a.id) !== -1 ? 0 : 1; bVal = selectedIds.indexOf(b.id) !== -1 ? 0 : 1; break; default: // name aVal = a.name || ''; bVal = b.name || ''; } var result; if (typeof aVal === 'number' && typeof bVal === 'number') { result = aVal - bVal; } else { result = String(aVal).localeCompare(String(bVal)); } return sortDir === 'DESC' ? -result : result; }); // Store filtered for select all $picker.data('filteredCountries', filtered); // Build dropdown items var html = ''; var colsClass = ''; if (viewMode.indexOf('cols-') === 0) { var cols = parseInt(viewMode.replace('cols-', ''), 10); colsClass = ' view-' + viewMode; } filtered.forEach(function(c) { var isSelected = selectedIds.indexOf(c.id) !== -1; var hasHolidays = c.holidayCount > 0; var itemClass = 'dropdown-item' + (hasHolidays ? '' : ' no-holidays') + (isSelected ? ' selected' : ''); html += '