/** * 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 = $(`