1jQuery(function ($) { 2 // console.log("AJAX Search script loaded"); 3 4 const isAr = $('html').attr('lang')?.toLowerCase() === 'ar'; 5 var $loader = $('#mof-search-loader'), 6 $results = $('#search-results'), 7 $form = $('#search-form'); 8 9 if (!$results.length) { 10 return; 11 } 12 13 function pushMtmEvent(data) { 14 window._mtm = window._mtm || []; 15 window._mtm.push(data); 16 } 17 18 function filterLabel(element) { 19 const $element = $(element); 20 21 if (element.type === 'checkbox') { 22 return $(`label[for="${element.id}"]`).first().text().trim(); 23 } 24 25 if (element.tagName === 'SELECT') { 26 return $element.find('option:selected').text().trim(); 27 } 28 29 return ( 30 $element.attr('aria-label') || 31 $element.closest('.aegov-form-control').find('label').first().text().trim() 32 ); 33 } 34 35 function trackFilter(element) { 36 const label = filterLabel(element); 37 if (!label) return; 38 39 pushMtmEvent({ 40 event: 'filterUse', 41 filter: label, 42 }); 43 } 44 45 // Initialize Flatpickr date pickers 46 function initDatePickers() { 47 var commonOpts = { 48 dateFormat: 'd/m/Y', 49 allowInput: true, 50 static: false, 51 position: 'auto', 52 }; 53 if (isAr) commonOpts.locale = 'ar'; 54 55 if (window.fpFrom) window.fpFrom.destroy(); 56 if (window.fpTo) window.fpTo.destroy(); 57 58 window.fpFrom = flatpickr('#from_date', { 59 ...commonOpts, 60 onReady: (instance) => (instance.calendarContainer.style.zIndex = '9999'), 61 onOpen: (instance) => { 62 setTimeout(() => { 63 const rect = instance.input.getBoundingClientRect(); 64 Object.assign(instance.calendarContainer.style, { 65 position: 'absolute', 66 top: rect.bottom + window.scrollY + 5 + 'px', 67 left: rect.left + window.scrollX + 'px', 68 zIndex: '9999', 69 }); 70 }, 10); 71 }, 72 }); 73 74 window.fpTo = flatpickr('#to_date', { 75 ...commonOpts, 76 onReady: (instance) => (instance.calendarContainer.style.zIndex = '9999'), 77 onOpen: (instance) => { 78 setTimeout(() => { 79 const rect = instance.input.getBoundingClientRect(); 80 Object.assign(instance.calendarContainer.style, { 81 position: 'absolute', 82 top: rect.bottom + window.scrollY + 5 + 'px', 83 left: rect.left + window.scrollX + 'px', 84 zIndex: '9999', 85 }); 86 }, 10); 87 }, 88 }); 89 90 // Set up calendar button click handlers AFTER initialization 91 setupCalendarButtons(); 92 } 93 94 // Setup calendar button handlers 95 function setupCalendarButtons() { 96 // Remove any existing handlers to prevent duplicates 97 $('.search-y-btn1, .search-y-btn2').off('click.calendar'); 98 99 // Calendar buttons 100 $('.search-y-btn1').on('click.calendar', (e) => { 101 e.preventDefault(); 102 // console.log("From button clicked", window.fpFrom); 103 if (window.fpFrom && typeof window.fpFrom.open === 'function') { 104 window.fpFrom.open(); 105 } else { 106 // console.error("fpFrom not properly initialized"); 107 // Fallback: trigger click on the input 108 $('#from_date').trigger('click').focus(); 109 } 110 }); 111 112 $('.search-y-btn2').on('click.calendar', (e) => { 113 e.preventDefault(); 114 // console.log("To button clicked", window.fpTo); 115 if (window.fpTo && typeof window.fpTo.open === 'function') { 116 window.fpTo.open(); 117 } else { 118 // console.error("fpTo not properly initialized"); 119 // Fallback: trigger click on the input 120 $('#to_date').trigger('click').focus(); 121 } 122 }); 123 } 124 125 // Initialize on DOM ready and window load 126 $(document).ready(() => { 127 // Try to initialize immediately 128 if (typeof flatpickr !== 'undefined') { 129 initDatePickers(); 130 } 131 }); 132 133 window.addEventListener('load', () => { 134 // Initialize again on window load to ensure everything is ready 135 if (typeof flatpickr !== 'undefined') { 136 initDatePickers(); 137 } 138 }); 139 140 // console.log("From element:", document.querySelector("#from_date")); 141 // console.log("To element:", document.querySelector("#to_date")); 142 143 // Post-type checkbox validation (simplified - no max limit) 144 function validatePostTypes() { 145 const $checked = $('.post-type-checkbox:checked'); 146 147 if (!$checked.length) { 148 // Show error message if no post types selected
149 console.warn(isAr ? 'ÙØ¬Ø¨ Ø§Ø®ØªÙØ§Ø± ÙÙØ¹ ÙØ§ØØ¯ عÙÙ Ø§ÙØ£ÙÙ' : 'Please select at least one post type'); 150 return false; 151 } 152 153 return true; 154 } 155 156 // Update checkbox visual states 157 $('.post-type-checkbox').on('change', function (event) { 158 // Update visual state based on aegov-check-item structure 159 const $checkItem = $(this).closest('.aegov-check-item'); 160 $checkItem.toggleClass('checked', this.checked); 161 if (event.originalEvent) trackFilter(this); 162 }); 163 164 // Update "You searched forâ¦" text 165 function updateSearchTermDisplay(term) { 166 if (!term) return; 167 168 const txt = isAr 169 ? `ÙÙØ¯ Ø¨ØØ«Øª ع٠"<span class="font-extrabold">${$('<div>').text(term).html()}</span>"` 170 : `You searched for "<span class="font-extrabold">${$('<div>').text(term).html()}</span>"`; 171 $('.search-text').html(txt); 172 } 173 174 // Core AJAX fetcher 175 function fetchResults(page = 1) { 176 if (!validatePostTypes()) { 177 // If validation fails, select default post types 178 $('#page, #post, #services').prop('checked', true).trigger('change'); 179 } 180 181 var data = $form.serializeArray(); 182 data.push( 183 { name: 'action', value: 'filter_search' }, 184 { name: 'nonce', value: ajax_search_params.nonce }, 185 { name: 'lang', value: isAr ? 'ar' : 'en' }, 186 { name: 'paged', value: page }, 187 ); 188 189 const term = $form.find('input[name="s"]').val(); 190 if (term) updateSearchTermDisplay(term); 191 192 if (!term || term.trim() === '') { 193 return; // stop execution if empty 194 } 195 196 $.ajax({ 197 url: ajax_search_params.ajax_url, 198 method: 'POST', 199 data: data, 200 beforeSend() { 201 $loader.addClass('shown'); 202 $results.addClass('opacity-50'); 203 }, 204 success(response) { 205 if (response.success) { 206 $results.html(response.data); 207 // Smooth-scroll into view 208 if ($results[0] && typeof $results[0].scrollIntoView === 'function') { 209 $results[0].scrollIntoView({ behavior: 'smooth' }); 210 } 211 } else { 212 const errorMsg = 213 response.data || (isAr ? 'ÙÙ ÙØªÙ Ø§ÙØ¹Ø«Ùر عÙÙ ÙØªØ§Ø¦Ø¬.' : 'No results found.'); 214 $results.html(`<p class="text-h3 font-extrabold">${errorMsg}</p>`); 215 } 216 }, 217 error(xhr, status, error) { 218 // console.error("AJAX error:", status, error); 219 $results.html(`<p class="text-red-500"> 220 ${isAr ? 'خطأ Ù٠تØÙ Ù٠اÙÙØªØ§Ø¦Ø¬.' : 'Error loading results.'} 221 </p>`); 222 }, 223 complete() { 224 $loader.removeClass('shown'); 225 $results.removeClass('opacity-50'); 226 }, 227 }); 228 } 229 230 // On initial page load 231 fetchResults(); 232 233 // Form submit 234 $form.on('submit', function (e) { 235 e.preventDefault(); 236 const query = $form.find('input[name="s"]').val().trim(); 237 if (query) { 238 pushMtmEvent({ 239 event: 'internalSearch', 240 searchQuery: query, 241 }); 242 } 243 fetchResults(1); 244 }); 245 246 // Pagination clicks (delegated) 247 $results.on('click', '[data-page]', function (e) { 248 e.preventDefault(); 249 const page = parseInt($(this).data('page')) || 1; 250 fetchResults(page); 251 }); 252 253 // Sort dropdown change 254 $('#sort').on('change', function () { 255 trackFilter(this); 256 fetchResults(1); 257 }); 258 259 $('#from_date, #to_date').on('change', function () { 260 if ($(this).val().trim()) trackFilter(this); 261 }); 262 263 // Search input real-time validation 264 $('input[name="s"]').on('input', function () { 265 const val = $(this).val().trim(); 266 if (val.length > 0) { 267 // Optional: Add visual feedback for valid input 268 $(this).removeClass('error'); 269 } 270 }); 271 272 // Clear form functionality (optional enhancement) 273 function clearForm() { 274 $form[0].reset(); 275 $('.post-type-checkbox').prop('checked', false).trigger('change'); 276 $('#page, #post, #services ').prop('checked', true).trigger('change'); // Set defaults 277 if (window.fpFrom) window.fpFrom.clear(); 278 if (window.fpTo) window.fpTo.clear(); 279 } 280 281 // Optional: Add clear button functionality if needed 282 $('.clear-form-btn').on('click', function (e) { 283 e.preventDefault(); 284 clearForm(); 285 fetchResults(1); 286 }); 287});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.