PageSourceSearch

https://mof.gov.ae/wp-content/themes/mof-theme/assets/js/ajax-search-a.js?ver=1.2.1

js mof.gov.ae collected 2026-10-02 07:45:58 UTC 8,551 bytes, 287 lines download raw bytes

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.