PluginProbe
MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings / 7.2.1
MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings v7.2.1
7.2.2 7.2.1 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 All 37 releases
mlsimport / admin / js / mlsimport-onboarding.js

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

355 lines 13.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * MLSImport Onboarding Wizard JavaScript
3 *
4 * Handles all the frontend functionality for the onboarding wizard including
5 * navigation, form validation, and AJAX requests.
6 *
7 * Depends on the localized `mlsimportOnboarding` object (ajaxurl, nonce,
8 * current_step, steps, strings) printed by the PHP that enqueues this file.
9 */
10
11 (function($) {
12 'use strict';
13
14 // Store wizard state
15 var MLSImportWizard = {
16 currentStep: '', // Slug of the step currently being shown
17 steps: {}, // Map of step slug -> step config (order defines navigation)
18 /**
19 * Bootstrap the wizard: pull state from localized data and wire it up.
20 */
21 init: function() {
22 // Set initial state from localized data
23 this.currentStep = mlsimportOnboarding.current_step;
24 this.steps = mlsimportOnboarding.steps;
25
26 // Initialize event listeners
27 this.initEvents();
28
29 },
30
31 /**
32 * Attach the wizard's global event handlers.
33 */
34 initEvents: function() {
35 // Form submission
36 $('#mlsimport-wizard-form').on('submit', this.handleFormSubmit);
37
38 // Save data when navigating away
39 $(window).on('beforeunload', this.saveCurrentData);
40
41 // Step navigation
42 $('.mlsimport-wizard-step').on('click', this.handleStepClick);
43 },
44 /**
45 * Handle a click on a step indicator: save, gate skipping, then navigate.
46 *
47 * @param {Event} e - The click event.
48 */
49 handleStepClick: function(e) {
50 e.preventDefault();
51
52 // Save current data
53 MLSImportWizard.saveCurrentData();
54
55 // Get clicked step index
56 var $step = $(this);
57 var stepIndex = $step.index();
58 var stepKeys = Object.keys(MLSImportWizard.steps);
59 var targetStep = stepKeys[stepIndex];
60
61 // Don't allow skipping ahead - only go to completed steps or next step
62 var currentIndex = stepKeys.indexOf(MLSImportWizard.currentStep);
63 if (stepIndex > currentIndex + 1) {
64 // Block the jump and prompt the user to finish the current step
65 alert(mlsimportOnboarding.strings.complete_current_step || 'Please complete the current step first.');
66 return;
67 }
68
69 // Navigate to the step
70 window.location.href = 'admin.php?page=mlsimport-onboarding&step=' + targetStep;
71 },
72
73
74 /**
75 * On form submit, persist the data then let the native submit proceed.
76 *
77 * @param {Event} e - The submit event.
78 * @return {boolean} Always true (do not cancel the submit).
79 */
80 handleFormSubmit: function(e) {
81 // Save current form data
82 MLSImportWizard.saveCurrentData();
83
84 // Let the form submit normally - PHP will handle the processing
85 return true;
86 },
87
88 /**
89 * Serialize the wizard form and save it via a synchronous AJAX call
90 * (synchronous so it completes before the page unloads).
91 */
92 saveCurrentData: function() {
93 // Collect form data
94 var formData = $('#mlsimport-wizard-form').serializeArray();
95 var data = {};
96
97 // Convert to object
98 $.each(formData, function(i, field) {
99 // Multi-value (`name[]`) fields collapse into an array under the base name
100 if (field.name.indexOf('[]') !== -1) {
101 // Handle array values
102 var name = field.name.replace('[]', '');
103 if (!data[name]) {
104 data[name] = [];
105 }
106 data[name].push(field.value);
107 } else {
108 // Scalar field: store directly
109 data[field.name] = field.value;
110 }
111 });
112
113 // Save via AJAX
114 $.ajax({
115 url: mlsimportOnboarding.ajaxurl,
116 method: 'POST',
117 data: {
118 action: 'mlsimport_save_step_data',
119 step: MLSImportWizard.currentStep,
120 data: data,
121 nonce: mlsimportOnboarding.nonce
122 },
123 async: false // Make sure data is saved before page unloads
124 });
125 },
126
127 // Utility function to show error message
128 /**
129 * Display an inline error notice above the form and scroll to it.
130 *
131 * @param {string} message - Error text to display.
132 */
133 showError: function(message) {
134 // Create the notice element once if it isn't already present
135 if (!$('.mlsimport-error-notice').length) {
136 $('<div class="mlsimport-error-notice"></div>').insertBefore('#mlsimport-wizard-form');
137 }
138
139 // Populate and reveal the notice
140 $('.mlsimport-error-notice').html('<p>' + message + '</p>').show();
141
142 // Scroll to error
143 $('html, body').animate({
144 scrollTop: $('.mlsimport-error-notice').offset().top - 50
145 }, 200);
146 },
147
148 // Utility function to hide error message
149 /**
150 * Hide the inline error notice.
151 */
152 hideError: function() {
153 $('.mlsimport-error-notice').hide();
154 }
155 };
156
157 // Initialize the wizard on document ready
158 $(document).ready(function() {
159 MLSImportWizard.init();
160 });
161
162 // Add utility functions for step templates that run inline JS
163 window.MLSImportWizard = MLSImportWizard;
164
165 })(jQuery);
166
167
168
169
170
171
172
173
174
175
176
177 // Second ready block: account / MLS-credential save handlers for the wizard.
178 jQuery(document).ready(function (jQuery) {
179
180
181
182
183 /**
184 * Show transient status text on a button, optionally reverting after 2s.
185 *
186 * @param {jQuery} button - The button element.
187 * @param {string} statusText - Text to display.
188 * @param {boolean} reset - When true, restore the original label after 2s.
189 */
190 function showButtonStatus(button, statusText, reset = true) {
191 // Remember the original label (once) so we can restore it
192 const originalText = button.data('original-text') || button.text();
193 if (!button.data('original-text')) {
194 button.data('original-text', originalText);
195 }
196 // Apply the status text; optionally schedule a revert
197 button.text(statusText);
198 if (reset) {
199 setTimeout(() => button.text(originalText), 2000);
200 }
201 }
202
203 // Save the MLSImport account username/password via AJAX
204 jQuery('.mlsimport-save-account').on('click', function (e) {
205 e.preventDefault();
206 const button = jQuery(this);
207 // A new attempt replaces any field error from the preceding attempt.
208 window.MLSImportWizard.hideError();
209 // Show a persistent "saving" label while the request is in flight
210 showButtonStatus(button, mlsimportOnboarding.strings.saving, false);
211
212 // Read the entered credentials
213 const username = jQuery('#mlsimport_admin_options-mlsimport_username').val();
214 const password = jQuery('#mlsimport_admin_options-mlsimport_password').val();
215
216 // POST the credentials to the account-save endpoint
217 jQuery.post(mlsimportOnboarding.ajaxurl, {
218 action: 'mlsimport_save_account',
219 security: mlsimportOnboarding.nonce,
220 mlsimport_username: username,
221 mlsimport_password: password
222 }, function (response) {
223 if (response.success) {
224 // Success: flash the success label
225 showButtonStatus(button, mlsimportOnboarding.strings.success);
226
227 // Replace the status feedback message
228 jQuery('.mlsimport_warning').remove();
229 jQuery('#mlsimport_admin_options-mlsimport_username')
230 .closest('fieldset')
231 .before(response.data.html);
232 } else {
233 // Validation failures carry the missing field labels. Surface
234 // that message beside the form instead of reducing it to the
235 // button's generic "Error" state (#306).
236 showButtonStatus(button, mlsimportOnboarding.strings.error);
237 const message = response.data && response.data.message
238 ? response.data.message
239 : mlsimportOnboarding.strings.error;
240 window.MLSImportWizard.showError(message);
241 }
242 }).fail(function () {
243 // A transport failure has no server message, but it still needs
244 // visible feedback beyond the transient button label.
245 showButtonStatus(button, mlsimportOnboarding.strings.error);
246 window.MLSImportWizard.showError(mlsimportOnboarding.strings.error);
247 });
248 });
249
250 // Save the MLS-specific settings (everything except the account credentials)
251 jQuery('.mlsimport-save-mls-data').on('click', function (e) {
252 e.preventDefault();
253
254 // Disable the button and show the "saving" label
255 const button = jQuery(this);
256 const originalText = button.text();
257 button.text(mlsimportOnboarding.strings.saving).prop('disabled', true);
258
259 // Base payload
260 const data = {
261 action: 'mlsimport_save_mls_data',
262 security: mlsimportOnboarding.nonce
263 };
264
265 // Collect every mlsimport_admin_options[...] field except the credentials
266 jQuery('[name^="mlsimport_admin_options"]').each(function () {
267 const name = jQuery(this).attr('name').replace('mlsimport_admin_options[', '').replace(']', '');
268 if (name !== 'mlsimport_username' && name !== 'mlsimport_password') {
269 data[name] = jQuery(this).val();
270 }
271 });
272
273 // POST the collected MLS settings
274 jQuery.post(mlsimportOnboarding.ajaxurl, data, function (response) {
275 // Restore the button regardless of outcome
276 button.text(originalText).prop('disabled', false);
277
278 if (response.success) {
279 // Remove all .mlsimport_warning except the validated one (account message)
280 jQuery('.mlsimport_warning').not('.mlsimport_validated').remove();
281
282 // Insert new MLS connection message before MLS input
283 jQuery('#mlsimport_mls_name_front')
284 .closest('fieldset')
285 .before(response.data.html);
286
287 // MLS connection confirmed: gather the metadata + save the
288 // import-field configuration in the background right away, so
289 // the Field Mapping step is ready when the user reaches it.
290 // Fire-and-forget on purpose: the shared reloading helper
291 // would yank the wizard step from under the user on success.
292 if (response.data.connected) {
293 jQuery.post(mlsimportOnboarding.ajaxurl, {
294 action: 'mlsimport_saas_get_metadata_function',
295 security: jQuery('#mlsimport_saas_get_metadata').val()
296 });
297 }
298 } else {
299 // Server reported failure
300 button.text(mlsimportOnboarding.strings.error);
301 }
302 }).fail(function () {
303 // Transport failure: show error and re-enable
304 button.text(mlsimportOnboarding.strings.error).prop('disabled', false);
305 });
306 });
307
308
309
310 // code for the acocunt page
311
312 // Only run this block on the account step
313 if (jQuery('.mlsimport-wizard-content-account').length) {
314 // Set the Continue button's initial enabled/disabled state
315 updateContinueButton();
316
317 // Add continue button navigation
318 jQuery('.mlsimport-wizard-content-account .mlsimport-wizard-next').on('click', function(e) {
319 e.preventDefault();
320 // Only navigate onward when the button isn't disabled
321 if (!jQuery(this).prop('disabled')) {
322 // Derive the admin.php URL from ajaxurl and go to the field-mapping step
323 window.location.href = ajaxurl.replace('admin-ajax.php', 'admin.php') + '?page=mlsimport-onboarding&step=field-mapping';
324 }
325 });
326
327 // Update after AJAX calls
328 jQuery(document).ajaxComplete(function() {
329 // Re-evaluate the Continue button shortly after any AJAX completes
330 setTimeout(updateContinueButton, 500);
331 });
332 }
333
334 });
335
336
337
338
339 /**
340 * Enable the account-step Continue button only once both credentials
341 * (account + MLS) have been validated.
342 */
343 function updateContinueButton() {
344 // Count how many validated confirmation messages are present
345 const validatedCount = jQuery('.mlsimport_warning.mlsimport_validated').length;
346 const continueButton = jQuery('.mlsimport-wizard-content-account .mlsimport-wizard-next');
347
348 // Both checks passed (>=2): enable; otherwise disable
349 if (validatedCount >= 2) {
350 continueButton.prop('disabled', false).removeClass('disabled');
351 } else {
352 continueButton.prop('disabled', true).addClass('disabled');
353 }
354 }
355