Files
prestashop-entity-selector/assets/js/admin/schedule-conditions.js
myprestarocks a285018e0d Initial commit: prestashop-entity-selector
Forked from prestashop-target-conditions
Renamed all references from target-conditions to entity-selector
2026-01-26 14:02:54 +00:00

1101 lines
46 KiB
JavaScript
Executable File

/**
* 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 += '<div class="' + itemClass + '" data-id="' + c.id + '">';
html += '<span class="item-checkbox"><i class="icon-' + (isSelected ? 'check-square' : 'square-o') + '"></i></span>';
html += '<span class="item-flag"><img src="' + self.escapeHtml(c.flag) + '" alt="' + self.escapeHtml(c.iso) + '" onerror="this.style.display=\'none\'"></span>';
html += '<span class="item-name">' + self.escapeHtml(c.name) + '</span>';
if (c.zone) {
html += '<span class="item-zone">' + self.escapeHtml(c.zone) + '</span>';
}
if (hasHolidays) {
html += '<span class="item-badge">' + c.holidayCount + '</span>';
}
html += '</div>';
});
if (filtered.length === 0) {
html = '<div class="dropdown-empty">No countries found</div>';
}
// Update dropdown
var $items = $dropdown.find('.dropdown-items');
$items.html(html);
$items.removeClass('view-cols-2 view-cols-3 view-cols-4').addClass(colsClass);
// Update results count
var selectedCount = selectedIds.length;
var countText = filtered.length + ' countries';
if (selectedCount > 0) {
countText += ' (' + selectedCount + ' selected)';
}
$dropdown.find('.results-count').text(countText);
$dropdown.addClass('show');
},
addHolidayCountry: function($picker, id) {
var self = this;
var countryMap = $picker.data('countryMap') || {};
var selectedIds = $picker.data('selectedIds') || [];
var country = countryMap[id];
if (!country || selectedIds.indexOf(id) !== -1) {
return;
}
selectedIds.push(id);
$picker.data('selectedIds', selectedIds);
// Add chip
var $chips = $picker.find('.entity-input-chips');
var hasHolidays = country.holidayCount > 0;
var chipClass = 'input-chip' + (hasHolidays ? ' has-holidays' : '');
var chipHtml = '<span class="' + chipClass + '" data-id="' + id + '">';
chipHtml += '<span class="chip-flag"><img src="' + self.escapeHtml(country.flag) + '" alt="' + self.escapeHtml(country.iso) + '" onerror="this.style.display=\'none\'"></span>';
chipHtml += '<span class="chip-name">' + self.escapeHtml(country.name) + '</span>';
if (hasHolidays) {
chipHtml += '<span class="chip-badge">' + country.holidayCount + '</span>';
}
chipHtml += '<button type="button" class="chip-remove" title="Remove"><i class="icon-times"></i></button>';
chipHtml += '</span>';
$chips.append(chipHtml);
// Add hidden input
var prefix = this.config.namePrefix || 'schedule_';
$picker.prepend('<input type="hidden" name="' + prefix + 'holiday_countries[]" value="' + id + '" class="holiday-country-input">');
},
removeHolidayCountry: function($picker, id) {
var selectedIds = $picker.data('selectedIds') || [];
var index = selectedIds.indexOf(id);
if (index === -1) {
return;
}
selectedIds.splice(index, 1);
$picker.data('selectedIds', selectedIds);
// Remove chip
$picker.find('.input-chip[data-id="' + id + '"]').remove();
// Remove hidden input
$picker.find('.holiday-country-input[value="' + id + '"]').remove();
},
selectAllHolidayCountries: function($picker) {
var self = this;
var filtered = $picker.data('filteredCountries') || [];
var selectedIds = $picker.data('selectedIds') || [];
filtered.forEach(function(c) {
if (selectedIds.indexOf(c.id) === -1) {
self.addHolidayCountry($picker, c.id);
}
});
// Refresh dropdown
var query = $picker.find('.holiday-country-search-input').val();
this.showHolidayCountryDropdown($picker, query);
},
clearHolidayCountries: function($picker) {
var self = this;
var selectedIds = ($picker.data('selectedIds') || []).slice();
selectedIds.forEach(function(id) {
self.removeHolidayCountry($picker, id);
});
// Refresh dropdown
var query = $picker.find('.holiday-country-search-input').val();
this.showHolidayCountryDropdown($picker, query);
},
escapeHtml: function(str) {
if (!str) return '';
var div = document.createElement('div');
div.textContent = str;
return div.innerHTML;
},
// =====================================================
// Collapsible Sections Helper
// =====================================================
initCollapsibleSections: function() {
var self = this;
// Initialize toggle button state based on current collapsed sections
$('.condition-trait-body').each(function() {
self.updateToggleSectionsButton($(this));
});
},
updateToggleSectionsButton: function($body) {
// Button is now in header, find it via wrapper
var $wrapper = $body.closest('.schedule-conditions');
var $btn = $wrapper.find('.btn-toggle-groups');
if (!$btn.length) return;
var $sections = $body.find('.collapsible-section');
var totalSections = $sections.length;
var collapsedCount = $sections.filter('.collapsed').length;
// Update button state based on majority
if (collapsedCount === totalSections) {
// All collapsed - show expand icon
$btn.attr('data-state', 'collapsed');
$btn.attr('title', 'Expand all sections');
$btn.find('i').removeClass('icon-compress').addClass('icon-expand');
} else if (collapsedCount === 0) {
// All expanded - show collapse icon
$btn.attr('data-state', 'expanded');
$btn.attr('title', 'Collapse all sections');
$btn.find('i').removeClass('icon-expand').addClass('icon-compress');
}
// Mixed state - keep current icon (user can toggle to collapse or expand all)
},
// =====================================================
// Clear Method
// =====================================================
clear: function($wrapper) {
if (!$wrapper) {
$wrapper = $('.schedule-conditions');
}
var self = this;
var prefix = this.config.namePrefix;
// Set to "Always" (value=0, which is the "on" position)
$wrapper.find('.schedule-enabled-toggle[value="0"]').prop('checked', true).trigger('change');
$wrapper.find('input[name="' + prefix + 'datetime_start"]').val('');
$wrapper.find('input[name="' + prefix + 'datetime_end"]').val('');
$wrapper.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);
});
$wrapper.find('.weekly-schedule-data').val('{}');
// Clear holiday countries
$wrapper.find('.holiday-country-picker').each(function() {
var $picker = $(this);
$picker.data('selectedIds', []);
$picker.find('.entity-input-chips').empty();
$picker.find('.holiday-country-input').remove();
});
// Set holiday toggle to "No" (value="0")
$wrapper.find('.holiday-exclude-toggle[value="0"]').prop('checked', true).trigger('change');
}
};
// Export
window.ScheduleConditions = ScheduleConditions;
// Auto-init if config is available
$(document).ready(function() {
if (typeof scheduleConditionsConfig !== 'undefined' && scheduleConditionsConfig) {
ScheduleConditions.init(scheduleConditionsConfig);
} else {
ScheduleConditions.init({});
}
});
})(jQuery);