PluginProbe
MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings / 7.2
MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings v7.2
7.2 7.1.2 7.1.1 7.1 7.0.4 7.0.6 7.0.7 6.3.8 6.3.7 6.3.6 6.3.5 6.3.4 6.3.3 6.3.1 trunk 5.7.3 5.7.5 5.8.1 5.8.2 5.8.3 5.8.4 5.8.6 6.0.4 6.0.5 6.0.7 All 35 releases
mlsimport / admin / js / mlsimport-admin.js

mlsimport-admin.js in MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings 7.2, at admin/js/mlsimport-admin.js

803 lines 29.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * MLSImport — admin settings/import screen behaviour.
3 *
4 * Drives the plugin's admin UI: shows/hides the credential fieldsets that match
5 * the selected MLS provider, starts/stops imports (global and per-import-task),
6 * polls the server for import log/progress, clears caches, batch-deletes
7 * properties by taxonomy term, and provides the front-end MLS autocomplete.
8 * All server calls go through admin-ajax (ajaxurl / mlsimport_vars.ajax_url).
9 *
10 * PHP's Provider Family module supplies the exact credential fields for the
11 * selected MLS; this file only applies their visibility.
12 */
13 jQuery( document ).ready(
14 function ($) {
15 'use strict';
16
17 // Handles for the two polling timers (global import + per-item import).
18 var log_refresh_interval;
19 var log_refresh_interval_per_item;
20 // Poll intervals in milliseconds.
21 var timer = 2000;
22 var timer_per_item = 4000;
23
24 // If the Import tab is the active tab on load, begin polling the global import log.
25 if (jQuery( '#nav-tab-import' ).hasClass( 'nav-tab-active' )) {
26 log_refresh_interval = setInterval( mlsimport_log_interval, timer );
27 }
28
29 // Start checking logs only after an import actually begins
30 // to avoid showing a completed message on initial page load.
31
32 //mlsimport_autocomplte_mls_selection();
33 /**
34 * Show / hide extra input field - cities and counties
35 */
36
37 mslimport_show_extra_options();
38
39 /**
40 * Show / hide input tokens on load
41 */
42 mlsimport_token_on_load();
43
44 /**
45 * Show / hide input tokens on change
46 */
47
48 // When the chosen MLS changes, use the provider fields supplied by PHP.
49 jQuery( '#mlsimport_mls_name' ).on(
50 'change',
51 function () {
52 mlsimport_token_on_load();
53 }
54 );
55
56 /**
57 * Stop Import per item
58 */
59
60 // Stop a single import task: halt client-side polling, then tell the server to stop.
61 jQuery( '#mlsimport_stop_item' ).on(
62 'click',
63 function () {
64 console.log( 'mlsimport-stop' );
65 // Import task post id and the shared item-actions nonce.
66 var post_id = jQuery( this ).attr( 'data-post_id' );
67 var nonce = jQuery('#mlsimport_item_actions').val();
68 // stop refreshing logs immediately on the client side
69 if (typeof log_refresh_interval_per_item !== 'undefined') {
70 clearInterval( log_refresh_interval_per_item );
71 }
72 jQuery.ajax(
73 {
74 type: 'POST',
75 url: ajaxurl,
76 data: {
77 'action' : 'mlsimport_stop_import_per_item',
78 'post_id' : post_id,
79 'security' : nonce
80 // AJAX action + task id + nonce for the stop request.
81 },
82 success: function (data) {
83 console.log( data );
84 jQuery( '#mlsimport_item_status' ).empty().append( 'Import stopped!' );
85 },
86 error: function (errorThrown) {
87 console.log( errorThrown );
88 }
89 }
90 );// end ajax
91 }
92 );
93
94 /**
95 * Start Import per item
96 */
97
98 // Start a single import from the Import Task editor. The onboarding wizard
99 // owns its Run Test button separately because it uses a dedicated endpoint,
100 // server-side five-listing cap, and completion polling. Binding that button
101 // here as well starts two different requests from one click and makes them
102 // compete for the global import mutex.
103 jQuery( '#mlsimport-start_item' ).on(
104 'click',
105 function () {
106 console.log( 'mlsimport-start' );
107 // Gather the task's identifiers and requested batch size from the DOM.
108 var ajaxurl = mlsimport_vars.ajax_url;
109 var post_id = jQuery( this ).attr( 'data-post_id' );
110 var post_number = jQuery( this ).attr( 'data-post-number' );
111 var how_many = jQuery( '#mlsimport_item_how_many' ).val();
112 var is_onboard = 0;
113 var nonce = jQuery('#mlsimport_item_actions').val();
114 // Reset the status line to a "starting" message.
115 jQuery( '#mlsimport_item_status' ).empty();
116 jQuery( '#mlsimport_item_status' ).append( "Starting the import. Please stand by!" );
117
118
119 clearInterval( log_refresh_interval_per_item );
120 log_refresh_interval_per_item = setInterval( mlsimport_log_interval_per_item, timer_per_item );
121
122
123 jQuery.ajax(
124 {
125 type: 'POST',
126 url: ajaxurl,
127 data: {
128 'action' : 'mlsimport_move_files_per_item',
129 'post_id' : post_id,
130 'how_many' : how_many,
131 'post_number' : post_number,
132 'is_onboard' : is_onboard,
133 'security' : nonce,
134 },
135 success: function (data) {
136 console.log( data );
137 if ( data && data.success === false && data.message ) {
138 jQuery( '#mlsimport_item_status' ).empty().append( data.message );
139 jQuery( '#mlsimport-start_item' ).prop( 'disabled', true );
140 }
141
142 },
143 error: function (errorThrown) {
144 console.log( errorThrown );
145 var message = '';
146 if ( errorThrown.responseJSON && errorThrown.responseJSON.message ) {
147 message = errorThrown.responseJSON.message;
148 } else if ( errorThrown.responseText ) {
149 try {
150 var parsed = JSON.parse( errorThrown.responseText );
151 message = parsed.message || errorThrown.statusText;
152 } catch (e) {
153 message = errorThrown.statusText;
154 }
155 } else {
156 message = errorThrown.statusText;
157 }
158 jQuery( '#mlsimport_item_status' ).empty().append( message );
159 jQuery( '#mlsimport-start_item' ).prop( 'disabled', true );
160 }
161 }
162 );// end ajax
163
164 }
165 );
166
167 /**
168 * delete cache
169 */
170
171 // Clear cache tool: ask the server to delete cached MLS data.
172 jQuery( '#mlsimport-clear-cache' ).on(
173 'click',
174 function () {
175 var ajaxurl = mlsimport_vars.ajax_url;
176 var nonce = jQuery('#mlsimport_tool_actions').val();
177
178 jQuery( '#mlsimport-clear-cache' ).val( 'Deleting...' );
179
180 jQuery.ajax(
181 {
182 type: 'POST',
183 url: ajaxurl,
184 data: {
185 'action' : 'mlsimport_delete_cache',
186 'security' : nonce
187 },
188 success: function (data) {
189 console.log( data );
190 jQuery( '#mlsimport-clear-cache' ).val( 'Deleted!' );
191
192 },
193 error: function (errorThrown) {
194 console.log( errorThrown );
195 }
196 }
197 );// end ajax
198 }
199 );
200
201 // Clear fields data tool: ask the server to wipe the stored field mapping data.
202 jQuery( '#mlsimport-clear-fields-data' ).on(
203 'click',
204 function () {
205 var ajaxurl = mlsimport_vars.ajax_url;
206 var nonce = jQuery('#mlsimport_tool_actions').val();
207
208 jQuery( '#mlsimport-clear-fields-data' ).val( 'Deleting...' );
209
210 jQuery.ajax(
211 {
212 type: 'POST',
213 url: ajaxurl,
214 data: {
215 'action' : 'mlsimport_clear_fields_data',
216 'security' : nonce
217 },
218 success: function (data) {
219 console.log( data );
220 jQuery( '#mlsimport-clear-fields-data' ).val( 'Deleted!' );
221
222 },
223 error: function (errorThrown) {
224 console.log( errorThrown );
225 }
226 }
227 );// end ajax
228 }
229 );
230
231 /**
232 * delete properties
233 */
234
235 // Load taxonomy terms when taxonomy is selected
236 // Populates the dependent term dropdown via AJAX for the chosen taxonomy.
237 jQuery( '#mlsimport_delete_category' ).on( 'change', function () {
238 var taxonomy = jQuery( this ).val();
239 var $termSelect = jQuery( '#mlsimport_delete_category_term' );
240 var nonce = jQuery( '#mlsimport_tool_actions' ).val();
241
242 // Clear and disable the term select until fresh terms arrive.
243 $termSelect.empty().prop( 'disabled', true );
244
245 // No taxonomy chosen: prompt the user and stop.
246 if ( ! taxonomy ) {
247 $termSelect.append( '<option value="" disabled>Select a taxonomy first</option>' );
248 return;
249 }
250
251 $termSelect.append( '<option value="" disabled>Loading...</option>' );
252
253 jQuery.ajax( {
254 type: 'POST',
255 url: mlsimport_vars.ajax_url,
256 dataType: 'json',
257 data: {
258 action: 'mlsimport_get_taxonomy_terms',
259 taxonomy: taxonomy,
260 security: nonce
261 },
262 success: function ( response ) {
263 $termSelect.empty();
264 if ( response.success && response.data.length ) {
265 jQuery.each( response.data, function ( i, term ) {
266 $termSelect.append(
267 '<option value="' + term.slug + '">' + term.name + ' (' + term.count + ')</option>'
268 );
269 } );
270 $termSelect.prop( 'disabled', false );
271 } else {
272 $termSelect.append( '<option value="" disabled>No terms found</option>' );
273 }
274 },
275 error: function () {
276 $termSelect.empty().append( '<option value="" disabled>Error loading terms</option>' );
277 }
278 } );
279 } );
280
281 // Batched delete
282 // Global flag the Stop button flips to end the recursive batch loop.
283 window.mlsimportDeleteStopped = false;
284
285 /**
286 * Delete matching properties one server batch at a time, recursing until done.
287 *
288 * @param {string} taxonomy Selected taxonomy slug.
289 * @param {Array} terms Selected term slugs to match.
290 * @param {string} nonce Tool-actions nonce.
291 * @param {number} totalDeleted Running count carried across batches.
292 */
293 function mlsimportDeleteBatch( taxonomy, terms, nonce, totalDeleted ) {
294 // Abort the loop if the user pressed Stop.
295 if ( window.mlsimportDeleteStopped ) {
296 jQuery( '#mlsimport-delete-notification' ).text( 'Stopped. Deleted ' + totalDeleted + ' properties.' );
297 mlsimportDeleteResetUI();
298 return;
299 }
300
301 jQuery.ajax( {
302 type: 'POST',
303 url: mlsimport_vars.ajax_url,
304 dataType: 'json',
305 data: {
306 action: 'mlsimport_delete_properties',
307 mlsimport_delete_category: taxonomy,
308 'mlsimport_delete_category_term[]': terms,
309 security: nonce
310 },
311 success: function ( response ) {
312 if ( ! response.success ) {
313 jQuery( '#mlsimport-delete-notification' ).text( response.data || 'Error' );
314 mlsimportDeleteResetUI();
315 return;
316 }
317
318 // Accumulate deleted count and derive an overall percentage for the bar.
319 var data = response.data;
320 totalDeleted += data.deleted;
321 var totalProperties = totalDeleted + data.remaining;
322 var pct = totalProperties > 0 ? Math.round( ( totalDeleted / totalProperties ) * 100 ) : 100;
323
324 jQuery( '#mlsimport-delete-progress-bar' ).css( 'width', pct + '%' );
325 jQuery( '#mlsimport-delete-progress-text' ).text( totalDeleted + ' / ' + totalProperties + ' deleted' );
326 jQuery( '#mlsimport-delete-notification' ).text( 'Deleting... ' + totalDeleted + ' deleted so far.' );
327
328 // Server signals completion, otherwise recurse for the next batch.
329 if ( data.done ) {
330 jQuery( '#mlsimport-delete-notification' ).text( 'Done! Deleted ' + totalDeleted + ' properties.' );
331 jQuery( '#mlsimport-delete-progress-bar' ).css( 'width', '100%' );
332 mlsimportDeleteResetUI();
333 } else {
334 mlsimportDeleteBatch( taxonomy, terms, nonce, totalDeleted );
335 }
336 },
337 error: function ( xhr ) {
338 console.log( xhr );
339 jQuery( '#mlsimport-delete-notification' ).text( 'Error during deletion. Deleted ' + totalDeleted + ' so far.' );
340 mlsimportDeleteResetUI();
341 }
342 } );
343 }
344
345 /**
346 * Restore the delete controls to their idle state (show start, hide stop).
347 */
348 function mlsimportDeleteResetUI() {
349 jQuery( '#mlsimport-delete-prop' ).show();
350 jQuery( '#mlsimport-delete-stop' ).hide();
351 }
352
353 // Start button: validate selections, confirm, then kick off the batch loop.
354 jQuery( '#mlsimport-delete-prop' ).on( 'click', function () {
355 var taxonomy = jQuery( '#mlsimport_delete_category' ).val();
356 var terms = jQuery( '#mlsimport_delete_category_term' ).val();
357 var nonce = jQuery( '#mlsimport_tool_actions' ).val();
358
359 if ( ! taxonomy ) {
360 jQuery( '#mlsimport-delete-notification' ).text( 'Please select a taxonomy.' );
361 return;
362 }
363 if ( ! terms || ! terms.length ) {
364 jQuery( '#mlsimport-delete-notification' ).text( 'Please select at least one term.' );
365 return;
366 }
367
368 // Require explicit confirmation before an irreversible bulk delete.
369 if ( ! confirm( 'Are you sure you want to delete all properties matching the selected terms? This cannot be undone.' ) ) {
370 return;
371 }
372
373 // Reset stop flag and switch the UI into the "deleting" state.
374 window.mlsimportDeleteStopped = false;
375 jQuery( '#mlsimport-delete-prop' ).hide();
376 jQuery( '#mlsimport-delete-stop' ).show();
377 jQuery( '#mlsimport-delete-progress' ).show();
378 jQuery( '#mlsimport-delete-progress-bar' ).css( 'width', '0%' );
379 jQuery( '#mlsimport-delete-progress-text' ).text( 'Starting...' );
380 jQuery( '#mlsimport-delete-notification' ).text( 'Deleting...' );
381
382 mlsimportDeleteBatch( taxonomy, terms, nonce, 0 );
383 } );
384
385 // Stop button: set the flag so the batch loop ends after the current request.
386 jQuery( '#mlsimport-delete-stop' ).on( 'click', function () {
387 window.mlsimportDeleteStopped = true;
388 jQuery( '#mlsimport-delete-notification' ).text( 'Stopping after current batch...' );
389 } );
390
391 /**
392 * Stop import
393 */
394
395 // Stop the global (all-tasks) import: tell the server to stop moving files,
396 // re-show the start button and stop the log poll.
397 jQuery( '#mlsimport_stop' ).on(
398 'click',
399 function () {
400 var ajaxurl = mlsimport_vars.ajax_url;
401
402 console.log( 'stop files' );
403 jQuery.ajax(
404 {
405 type: 'POST',
406 url: ajaxurl,
407 data: {
408 'action' : 'mlsimport_stop_moving_files',
409 },
410 success: function (data) {
411 console.log( data );
412 jQuery( '#aws-move-start' ).show();
413 clearInterval( log_refresh_interval );
414
415 },
416 error: function (errorThrown) {
417 console.log( errorThrown );
418 }
419 }
420 );// end ajax
421 }
422 );
423
424 /**
425 * Start Import
426 */
427
428 // Start the global import: show the progress UI, trigger the server move,
429 // then (re)start polling the global log.
430 jQuery( '#mlsimport-start' ).on(
431 'click',
432 function () {
433 console.log( 'mlsimport-start' );
434 var ajaxurl = mlsimport_vars.ajax_url;
435 aws_show_progress();
436
437 jQuery.ajax(
438 {
439 type: 'POST',
440 url: ajaxurl,
441 data: {
442 'action' : 'mlsimport_move_files'
443 },
444 success: function (data) {
445 console.log( data );
446 console.log( 'starting loggers' );
447 clearInterval( log_refresh_interval );
448 log_refresh_interval = setInterval( mlsimport_log_interval, timer );
449
450 },
451 error: function (errorThrown) {
452 console.log( errorThrown );
453 }
454 }
455 );// end ajax
456
457 }
458 );
459
460 /**
461 * Log import
462 *
463 * Polled on an interval during a global import: fetches the latest log text
464 * and remaining-file count, updates the log container and progress bar, and
465 * stops the poll when the server reports the run is done.
466 */
467
468 function mlsimport_log_interval()
469 {
470
471 // Total files to process (from the progress element) is the bar's denominator.
472 var progress_total = jQuery( '#mlsimport_monster_myProgress' ).attr( 'data-total' );
473 progress_total = parseInt( progress_total );
474 var remain_images = progress_total;
475 var done_images = 0;
476 var bar_width = 0;
477 jQuery.ajax(
478 {
479 type: 'POST',
480 url: ajaxurl,
481 dataType: 'json',
482 data: {
483 'action' : 'mlsimport_move_files_to_aws_logger',
484 },
485 success: function (data) {
486
487 // Done and no more logs: mark COMPLETED and stop polling.
488 if (data.is_done === 'done' && data.logs === '' ) {
489 jQuery( '#log_container' ).prepend( 'COMPLETED' );
490 jQuery( '#log_container' ).append( 'COMPLETED' );
491 clearInterval( log_refresh_interval );
492 } else if (data.logs !== '') {
493 // Still running: replace the log text and remaining-file count.
494 jQuery( '#log_container' ).empty().prepend( data.logs );
495 jQuery( '#aws_more_files' ).empty().text( data.current_files_no );
496
497 // Derive processed count and update the progress bar width.
498 remain_images = parseInt( data.current_files_no );
499 done_images = progress_total - remain_images;
500
501 bar_width = done_images * 100 / progress_total;
502 bar_width = parseFloat( bar_width );
503
504 jQuery( '#mlsimport_myBar' ).css( 'width',bar_width + '%' );
505 }
506 },
507 error: function (errorThrown) {
508 console.log( errorThrown );
509 }
510 }
511 );// end ajax
512 }
513
514 /**
515 * Log import per item
516 *
517 * Polled on an interval during a single import task: reads progress/total,
518 * updates that task's status text and progress bar, and stops the poll when
519 * the server reports the task is done.
520 */
521
522 function mlsimport_log_interval_per_item()
523 {
524 console.log( 'mlsimport_log_interval_per_item' );
525 // Task id and item-actions nonce for the logger request.
526 var item_id = jQuery( '#mlsimport-start_item' ).attr( 'data-post_id' );
527 var nonce = jQuery('#mlsimport_item_actions').val();
528 jQuery.ajax(
529 {
530 type: 'POST',
531 url: ajaxurl,
532 dataType: 'json',
533 data: {
534 'action' : 'mlsimport_logger_per_item',
535 'post_id' : item_id,
536 'security' : nonce
537 },
538 success: function (data) {
539 console.log( data );
540 // Imported-so-far vs total, used to size the progress bar.
541 var progress = parseInt( data.mlsimport_progress_properties );
542 var total = parseInt( data.mlsimport_task_to_import );
543 // Only update the bar when both numbers are valid.
544 if ( ! isNaN( progress ) && ! isNaN( total ) && total > 0 ) {
545 var width = progress * 100 / total;
546 jQuery( '#mlsimport_item_progress .mlsimport-progress-bar-inner' ).css( 'width', width + '%' );
547 }
548 // Only the server's run state can end polling. An empty log is
549 // valid while an Action Scheduler worker is still waiting.
550 if (data.is_done === 'done') {
551 console.log( 'kill interval' );
552
553 clearInterval( log_refresh_interval_per_item );
554 var message = "Ready to import!";
555 if (data.status === 'completed') {
556 message = "Import completed!";
557 jQuery( '#mlsimport_item_progress .mlsimport-progress-bar-inner' ).css( 'width', '100%' );
558 } else if (data.status === 'stopped') {
559 message = "Import stopped!";
560 } else if (data.status === 'failed') {
561 var runError = data.result && data.result.error ? ': ' + data.result.error : '';
562 message = "Import failed" + runError;
563 }
564 jQuery( '#mlsimport_item_status' ).empty().append( message );
565
566 }else if(data.is_done==='wip'){
567 // Work-in-progress: show current property number and memory usage.
568 console.log('we do wip');
569 var runningMessage = data.status === 'waiting'
570 ? 'Waiting for the import worker to start.'
571 : 'Importing property: '+data.mlsimport_progress_properties+' of '+data.mlsimport_task_to_import+'. Memory used: '+data.memory+' MB.';
572 jQuery( '#mlsimport_item_status' ).empty().append( runningMessage );
573
574 } else if (data.logs !== '') {
575 // Otherwise surface whatever raw log text the server returned.
576 console.log('we do logs');
577 jQuery( '#mlsimport_item_status' ).empty().append( data.logs );
578
579
580 jQuery('.mlsimport-import-summary').append(
581 '<p><strong><?php _e("Status:", "mlsimport"); ?></strong> ' +
582 '<span class="mlsimport-status-success">'+data.logs+'/span></p>'
583 );
584
585 }
586 },
587 error: function (errorThrown) {
588 console.log( errorThrown );
589 }
590 }
591 );// end ajax
592 }
593
594 /**
595 * SHow progress bar -
596 *
597 * Prepares the global import progress UI: clears the log, resolves how many
598 * files remain to move, reveals the progress wrapper and hides the start button.
599 */
600
601 function aws_show_progress()
602 {
603
604 // Start with an empty log container.
605 jQuery( '#log_container' ).empty();
606
607 // Read the count of files to move from the primary counter element.
608 var files_to_move = jQuery( '#aws_move' ).text();
609 files_to_move = parseInt( files_to_move );
610
611 console.log( 'files_to_move ' + files_to_move );
612
613 // Fall back to the secondary counter if the primary one is not a number.
614 if ( isNaN( parseFloat( files_to_move ) ) ) {
615 files_to_move = jQuery( '#aws_more_files' ).text();
616 }
617 console.log( 'files_to_move2 ' + files_to_move );
618 files_to_move = parseInt( files_to_move );
619
620 jQuery( '#mlsimport_myProgress_wrapper' ).show();
621 jQuery( '.aws_to_move' ).empty().html( '<strong>We start importing. Please wait.</strong>' );
622 jQuery( '#aws-move-start' ).hide();
623 }
624
625 /**
626 * Check / unchechek fields
627 */
628
629 // Select-all / select-none buttons for the import field checkboxes. The
630 // data-import value on the clicked button decides which set to (un)check.
631 jQuery( '.mls_import_selec_all_class' ).on(
632 'click',
633 function () {
634 var trigger_type = jQuery( this ).attr( 'data-import' );
635 console.log( 'trigger type ' + trigger_type );
636
637 // Branch on the button's mode: check/uncheck the import or admin field group.
638 if (trigger_type === 'import_select') {
639
640 jQuery( '.mlsimport_select_import_all' ).prop( 'checked', true );
641 } else if (trigger_type === 'import_select_none') {
642
643 jQuery( '.mlsimport_select_import_all' ).prop( 'checked', false );
644 } else if (trigger_type === 'import_admin') {
645 jQuery( '.mlsimport_select_import_admin_all' ).prop( 'checked', true );
646 } else if (trigger_type === 'import_admin_none') {
647 jQuery( '.mlsimport_select_import_admin_all' ).prop( 'checked', false );
648 }
649 }
650 );
651
652 }
653 );
654
655
656
657 /**
658 * Wire the "show extra options" toggles (e.g. cities/counties inputs).
659 *
660 * Each hidden-field button toggles the visibility of the input wrapper inside
661 * its parent fieldset.
662 */
663 function mslimport_show_extra_options()
664 {
665 // On click, find the enclosing fieldset and toggle its input wrapper.
666 jQuery( '.mlsimport_hidden_field_button' ).on(
667 'click',
668 function () {
669 var parent = jQuery( this ).closest( '.mlsimport-fieldset' );
670 console.log( parent )
671 parent.find( '.mlsimport-input-wrapper' ).toggle();
672 }
673 );
674 }
675
676
677
678
679 /**
680 * Trigger a server-side fetch of the selected MLS's metadata from the SaaS API,
681 * then reload the page so the newly available fields show up.
682 */
683 function mlsimport_saas_get_metadata()
684 {
685
686 console.log( 'mlsimport_saas_get_metadata' );
687 // Nonce and admin-ajax endpoint for the metadata request.
688 var nonce = jQuery('#mlsimport_saas_get_metadata').val();
689 var ajaxurl = mlsimport_vars.ajax_url;
690 var request = {
691 'action' : 'mlsimport_saas_get_metadata_function',
692 'security' : nonce
693 };
694 // Scoped field tab (multi-MLS): gather for the rendered connection, not
695 // blindly for the current one. Absent input (other pages) => legacy scope.
696 var scope = jQuery('#mlsimport_field_scope').val();
697 if (scope && parseInt(scope, 10) > 0) {
698 request.mls_id = scope;
699 }
700 jQuery.ajax(
701 {
702 type: 'POST',
703 url: ajaxurl,
704 data: request,
705 success: function (data) {
706 console.log( data );
707 jQuery( '.mlsimport_populate_warning' ).remove();
708 location.reload( true );
709 },
710 error: function (errorThrown) {
711 console.log( errorThrown );
712 }
713 }
714 );// end ajax
715
716 }
717
718
719 /**
720 * Show only the selected MLS's credential fields using PHP-generated config.
721 * JavaScript contains no provider rules; it applies the final field-name list.
722 */
723 function mlsimport_token_on_load()
724 {
725 // PHP resolves the selected MLS to final credential field names. JavaScript
726 // only applies visibility and has no provider names or numeric ranges.
727 var providerConfig = window.mlsimport_vars && mlsimport_vars.provider_families
728 ? mlsimport_vars.provider_families
729 : { by_mls_id: {}, all_credential_fields: [] };
730 var selectedId = String( jQuery( '#mlsimport_mls_name' ).val() || '' );
731 var family = providerConfig.by_mls_id[ selectedId ];
732
733 providerConfig.all_credential_fields.forEach(
734 function (field) {
735 jQuery( '.fieldset_' + field ).hide();
736 }
737 );
738 if ( family && Array.isArray( family.credential_fields ) ) {
739 family.credential_fields.forEach(
740 function (field) {
741 jQuery( '.fieldset_' + field ).show();
742 }
743 );
744 }
745 }
746
747
748
749 /**
750 * Front-end MLS name autocomplete.
751 *
752 * Attaches a jQuery UI autocomplete to the visible MLS-name input. As the user
753 * types, matches come from the supplied list; picking one stores the human label
754 * in the front field and the numeric id in the hidden field, then refreshes the
755 * credential fieldsets via mlsimport_token_on_load().
756 *
757 * @param {Array} autofill Source list of { label, value } MLS entries.
758 */
759 function mlsimport_autocomplte_mls_selection(autofill){
760
761 console.log('mlsimport_autocomplte_mls_selection');
762 console.log(typeof jQuery.ui.autocomplete); // should be "function"
763 console.log(autofill);
764
765
766 jQuery( "#mlsimport_mls_name_front" ).autocomplete({
767 // Data source and minimum characters before suggestions appear.
768 source: autofill,
769 minLength: 3,
770 // Tag the dropdown widget so it can be styled by the plugin CSS.
771 open: function(event, ui) {
772 jQuery(this).autocomplete("widget").addClass("mlsimport-autocomplete-menu");
773 },
774 // On committed change, store label + id and refresh credential fields.
775 change( event, ui ){
776 console.log(ui);
777 jQuery("#mlsimport_mls_name_front").val(ui.item.label);
778 jQuery("#mlsimport_mls_name").val(ui.item.value);
779 mlsimport_token_on_load();
780 },
781 focus: function(event, ui) {
782 jQuery("#mlsimport_mls_name_front").val(ui.item.label);
783 jQuery("#mlsimport_mls_name").val(ui.item.value); mlsimport_token_on_load();
784 return false;
785 },
786 select: function(event, ui) {
787 jQuery("#mlsimport_mls_name_front").val(ui.item.label);
788 jQuery("#mlsimport_mls_name").val(ui.item.value); mlsimport_token_on_load();
789 return false;
790 },
791 // When no matches come back, inject a single "No results found" entry.
792 response: function(event, ui) {
793 if (!ui.content.length) {
794 var noResult = { value:"",label:"No results found" };
795 ui.content.push(noResult);
796 //$("#message").text("No results found");
797 } else {
798 // $("#message").empty();
799 }
800 }
801 });
802 }
803