/** * HVAC Searchable Selectors * * Handles dynamic multi-select organizers, categories, and single-select venue * with autocomplete search, "Add New" modal integration, and role-based permissions. */ (function($) { 'use strict'; class HVACSearchableSelector { constructor(element) { this.$element = $(element); this.type = this.$element.data('type'); this.maxSelections = this.$element.data('max-selections') || 1; this.selectedItems = []; this.init(); } init() { this.bindEvents(); this.loadInitialData(); } bindEvents() { const $input = this.$element.find('.selector-search-input'); const $dropdown = this.$element.find('.selector-dropdown'); // Input focus/blur events $input.on('focus', () => this.showDropdown()); $input.on('blur', (e) => { // Delay hiding to allow clicking on dropdown items setTimeout(() => { if (!this.$element.find(':hover').length) { this.hideDropdown(); } }, 150); }); // Search input $input.on('input', (e) => this.handleSearch(e.target.value)); // Arrow click this.$element.find('.selector-arrow').on('click', () => { if ($dropdown.is(':visible')) { this.hideDropdown(); } else { $input.focus(); } }); // Create new button this.$element.find('.create-new-btn').on('click', (e) => { e.preventDefault(); this.showCreateModal(); }); // Document click to close dropdown $(document).on('click', (e) => { if (!this.$element.has(e.target).length) { this.hideDropdown(); } }); } async loadInitialData() { try { this.showLoading(); const data = await this.fetchData(); this.renderDropdownItems(data); } catch (error) { console.error(`Error loading ${this.type} data:`, error); this.showError('Failed to load data'); } finally { this.hideLoading(); } } async handleSearch(query) { if (query.length < 2) { await this.loadInitialData(); return; } try { this.showLoading(); const data = await this.fetchData(query); this.renderDropdownItems(data); } catch (error) { console.error(`Error searching ${this.type}:`, error); this.showError('Search failed'); } finally { this.hideLoading(); } } async fetchData(search = '') { const params = new URLSearchParams({ action: `hvac_search_${this.type}s`, nonce: hvacSelectors.nonce, search: search }); const response = await fetch(hvacSelectors.ajaxUrl, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: params }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const result = await response.json(); if (!result.success) { throw new Error(result.data || 'Request failed'); } return result.data; } renderDropdownItems(items) { const $container = this.$element.find('.dropdown-items'); $container.empty(); if (!items || items.length === 0) { this.showNoResults(); return; } this.hideNoResults(); items.forEach(item => { const isSelected = this.selectedItems.some(selected => selected.id === item.id); const $item = $(` `); $item.on('click', () => this.selectItem(item)); $container.append($item); }); } selectItem(item) { // Check if already selected if (this.selectedItems.some(selected => selected.id === item.id)) { return; } // Check selection limit if (this.selectedItems.length >= this.maxSelections) { alert(`You can only select up to ${this.maxSelections} ${this.type}(s).`); return; } // Add to selected items this.selectedItems.push(item); this.renderSelectedItems(); this.updateHiddenInputs(); this.hideDropdown(); this.clearSearch(); // Mark item as selected in dropdown this.$element.find(`.dropdown-item[data-id="${item.id}"]`).addClass('selected').append(''); } removeItem(itemId) { this.selectedItems = this.selectedItems.filter(item => item.id !== itemId); this.renderSelectedItems(); this.updateHiddenInputs(); // Unmark item in dropdown this.$element.find(`.dropdown-item[data-id="${itemId}"]`).removeClass('selected').find('.item-selected').remove(); } renderSelectedItems() { const $container = this.$element.find('.selected-items'); $container.empty(); this.selectedItems.forEach(item => { const $selectedItem = $(`
${this.escapeHtml(item.title)}
`); $selectedItem.find('.remove-item').on('click', () => this.removeItem(item.id)); $container.append($selectedItem); }); } updateHiddenInputs() { const $container = this.$element.find('.hidden-inputs'); $container.empty(); this.selectedItems.forEach((item, index) => { const $input = $(``); $container.append($input); }); } showDropdown() { this.$element.find('.selector-dropdown').show(); this.$element.addClass('dropdown-open'); } hideDropdown() { this.$element.find('.selector-dropdown').hide(); this.$element.removeClass('dropdown-open'); } clearSearch() { this.$element.find('.selector-search-input').val(''); } showLoading() { this.$element.find('.loading-spinner').show(); this.$element.find('.dropdown-items, .no-results').hide(); } hideLoading() { this.$element.find('.loading-spinner').hide(); this.$element.find('.dropdown-items').show(); } showNoResults() { this.$element.find('.no-results').show(); this.$element.find('.dropdown-items').hide(); } hideNoResults() { this.$element.find('.no-results').hide(); } showError(message) { this.$element.find('.no-results').text(message).show(); } showCreateModal() { // Check permissions if (!this.$element.find('.create-new-btn').length) { return; } // Trigger create modal event $(document).trigger('hvac:create-new-modal', { type: this.type, callback: (newItem) => { if (newItem) { this.selectItem(newItem); this.loadInitialData(); // Refresh the list } } }); } escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } } // Advanced Options Toggle Function window.hvacToggleAdvancedOptions = function() { const $toggle = $('.toggle-advanced-options'); const $icon = $toggle.find('.toggle-icon'); const $text = $toggle.find('.toggle-text'); const $advancedFields = $('.advanced-field'); if ($advancedFields.is(':visible')) { // Hide advanced fields $advancedFields.slideUp(300); $icon.removeClass('dashicons-arrow-up-alt2').addClass('dashicons-arrow-down-alt2'); $text.text('Show Advanced Options'); } else { // Show advanced fields $advancedFields.slideDown(300); $icon.removeClass('dashicons-arrow-down-alt2').addClass('dashicons-arrow-up-alt2'); $text.text('Hide Advanced Options'); } }; // Initialize searchable selectors when document is ready $(document).ready(function() { $('.hvac-searchable-selector').each(function() { new HVACSearchableSelector(this); }); // Hide advanced fields by default $('.advanced-field').hide(); }); })(jQuery);