PluginProbe
Mailchimp List Subscribe Form / trunk
Mailchimp List Subscribe Form vtrunk
1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.5 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 All 55 releases
mailchimp / assets / js / admin.js

admin.js in Mailchimp List Subscribe Form trunk, at assets/js/admin.js

705 lines 20.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /* eslint-disable prefer-template, no-console */
2 (function ($) {
3 const params = window.mailchimp_sf_admin_params || {};
4 const spinner = '#mailchimp_sf_oauth_connect .mailchimp-sf-loading';
5 const errorSelector = '.mailchimp-sf-oauth-error';
6
7 /**
8 * Set connect button loading state.
9 */
10 function setConnectButtonLoading() {
11 $(spinner).removeClass('hidden');
12 $('#mailchimp_sf_oauth_connect').attr('disabled', true);
13 }
14
15 /**
16 * Set connect button normal state.
17 */
18 function setConnectButtonNormal() {
19 $(spinner).addClass('hidden');
20 $('#mailchimp_sf_oauth_connect').attr('disabled', false);
21 }
22
23 /**
24 * Open Mailchimp OAuth popup.
25 *
26 * @param {string} token - Token from the Oauth service.
27 */
28 function openMailchimpOauthPopup(token) {
29 const startUrl = params.oauth_url + '/auth/start/' + token;
30 const width = 800;
31 const height = 600;
32 const screenSizes = window.screen || { width: 1024, height: 768 };
33 const left = (screenSizes.width - width) / 2;
34 const top = (screenSizes.height - height) / 4;
35 const windowOptions =
36 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no, width=' +
37 width +
38 ', height=' +
39 height +
40 ', top=' +
41 top +
42 ', left=' +
43 left +
44 ', domain=' +
45 params.oauth_url.replace('https://', '');
46
47 // Open Mailchimp OAuth popup.
48 const popup = window.open(startUrl, params.oauth_window_name, windowOptions);
49
50 if (popup == null) {
51 // Show modal if popup is blocked.
52 $('#mailchimp-sf-popup-blocked-modal').dialog({
53 modal: true,
54 title: params.modal_title,
55 width: 480,
56 buttons: [
57 {
58 text: params.modal_button_cancel,
59 class: 'button mailchimp-sf-button button-secondary',
60 click() {
61 $(this).dialog('close');
62 },
63 },
64 {
65 text: params.modal_button_try_again,
66 class: 'button mailchimp-sf-button button-primary',
67 click() {
68 $(this).dialog('close');
69 setConnectButtonLoading();
70 openMailchimpOauthPopup(token);
71 },
72 style: 'margin-left: 10px;',
73 },
74 ],
75 classes: {
76 'ui-dialog': 'mailchimp-sf-ui-dialog',
77 'ui-dialog-titlebar': 'mailchimp-sf-ui-dialog-titlebar',
78 },
79 });
80 setConnectButtonNormal();
81 } else {
82 // Handle popup opened.
83 const oauthInterval = window.setInterval(function () {
84 if (popup.closed) {
85 // Clear interval.
86 window.clearInterval(oauthInterval);
87
88 // Check status of OAuth connection.
89 const statusUrl = params.oauth_url + '/api/status/' + token;
90 $.post(statusUrl, function (statusData) {
91 if (statusData && statusData.status === 'accepted') {
92 const finishData = {
93 action: 'mailchimp_sf_oauth_finish',
94 nonce: params.oauth_finish_nonce,
95 token,
96 };
97
98 // Finish OAuth connection and save token.
99 $.post(params.ajax_url, finishData, function (finishResponse) {
100 if (finishResponse.success) {
101 // Token is saved in the database, redirect to the settings page to reflect the changes.
102 window.location.href = params.admin_settings_url;
103 } else {
104 console.log(
105 'Error calling OAuth finish endpoint. Data:',
106 finishResponse,
107 );
108 if (finishResponse.data && finishResponse.data.message) {
109 $(errorSelector).html(finishResponse.data.message);
110 } else {
111 $(errorSelector).html(params.generic_error);
112 }
113 $(errorSelector).show();
114 }
115 setConnectButtonNormal();
116 }).fail(function () {
117 console.error('Error calling OAuth finish endpoint.');
118 $(errorSelector).html(params.generic_error);
119 $(errorSelector).show();
120 setConnectButtonNormal();
121 });
122 } else {
123 console.log(
124 'Error calling OAuth status endpoint. No credentials provided at login popup? Data:',
125 statusData,
126 );
127 setConnectButtonNormal();
128 }
129 }).fail(function () {
130 $(errorSelector).html(params.generic_error);
131 $(errorSelector).show();
132 console.error('Error calling OAuth status endpoint.');
133 setConnectButtonNormal();
134 });
135 }
136 }, 250);
137 }
138 }
139
140 $(window).on('load', function () {
141 // Mailchimp OAuth connection.
142 $('#mailchimp_sf_oauth_connect').click(function () {
143 $(errorSelector).hide();
144 $(errorSelector).html('');
145 setConnectButtonLoading();
146
147 $.post(
148 params.ajax_url,
149 {
150 action: 'mailchimp_sf_oauth_start',
151 nonce: params.oauth_start_nonce,
152 },
153 function (response) {
154 if (response.success && response.data && response.data.token) {
155 // Open Mailchimp OAuth popup.
156 openMailchimpOauthPopup(response.data.token);
157 } else {
158 if (response.data && response.data.message) {
159 $(errorSelector).html(response.data.message);
160 } else {
161 $(errorSelector).html(params.generic_error);
162 }
163 $(errorSelector).show();
164 setConnectButtonNormal();
165 }
166 },
167 ).fail(function () {
168 $(errorSelector).html(params.generic_error);
169 $(errorSelector).show();
170 setConnectButtonNormal();
171 });
172 });
173 });
174
175 /**
176 * Create Mailchimp account Handler.
177 */
178 // Waiting for login.
179 const waitingForMailchimpAccountLogin = () => {
180 const intervalId = window.setInterval(function () {
181 $.post(
182 params.ajax_url,
183 {
184 action: 'mailchimp_sf_check_login_session',
185 nonce: params.check_login_session_nonce,
186 },
187 function (response) {
188 if (response.success && response.data && response.data.logged_in) {
189 window.clearInterval(intervalId);
190 window.location.href = response.data.redirect;
191 } else {
192 console.log(response);
193 }
194 },
195 );
196 }, 10000);
197 };
198
199 $(window).on('load', function () {
200 const isCreateAccountPage = $('.mailchimp-sf-create-account').length > 0;
201 if (!isCreateAccountPage) {
202 return;
203 }
204
205 // Check if signup initiated.
206 if ($('.mailchimp-sf-create-account input[name=signup_initiated]').val() === '1') {
207 waitingForMailchimpAccountLogin();
208 }
209
210 // Validate inputs.
211 const validateFormInput = (input) => {
212 let inputLabel = '';
213 if (
214 $('label[for="' + input.id + '"] span').length > 0 &&
215 $('label[for="' + input.id + '"] span').text()
216 ) {
217 inputLabel = $('label[for="' + input.id + '"] span')
218 .text()
219 .trim();
220 inputLabel = inputLabel.split('/')[0];
221 inputLabel = inputLabel.split('(')[0];
222 }
223 const requiredError = (params.required_error || '').replace('%s', inputLabel);
224 const requiredInputs = [
225 'first_name',
226 'last_name',
227 'business_name',
228 'email',
229 'address',
230 'country',
231 'city',
232 'state',
233 'zip',
234 ];
235 if (requiredInputs.includes(input.name) && input.value === '') {
236 return requiredError;
237 }
238
239 if (input.name === 'email') {
240 if (!input.value.includes('@') || !input.value.includes('.'))
241 return params.invalid_email_error;
242 if (input.value !== $('#mailchimp-sf-profile-details input#confirm_email').val())
243 return params.confirm_email_match;
244 }
245 if (input.name === 'confirm_email') {
246 if (input.value !== $('#mailchimp-sf-profile-details input#email').val())
247 return params.confirm_email_match2;
248 }
249
250 return null;
251 };
252
253 // Display errors and disable button in case of errors
254 const validateAccountForm = (errors, wrapperId, displayErrors = false) => {
255 const inputIds = Object.keys(errors);
256
257 inputIds.forEach((key) => {
258 const inputElementId = `${wrapperId} #${key}`;
259 const errorElementId = `${wrapperId} #mailchimp-sf-${key}-error`;
260
261 if (errors[key] !== null) {
262 if (displayErrors) {
263 $(inputElementId).closest('.box').addClass('form-error');
264 $(errorElementId).text(errors[key]);
265 }
266 } else {
267 $(inputElementId).closest('.box').removeClass('form-error');
268 $(errorElementId).text('');
269 }
270 });
271 return Object.values(errors).filter((error) => error !== null).length === 0;
272 };
273
274 // Get form Errors.
275 const getFormErrors = (inputs) => {
276 const errors = {};
277 inputs.each((index, input) => {
278 errors[input.name] = validateFormInput(input);
279 });
280
281 return errors;
282 };
283
284 // Validate profile details
285 let profileDetailsInputs = $('#mailchimp-sf-profile-details input');
286 profileDetailsInputs.on('input', (e) => {
287 const input = e.target;
288
289 $(input).closest('.box').removeClass('form-error');
290 $(input).closest('.box').find('.error-field').text('');
291
292 if (input.name === 'email' || input.name === 'confirm_email') {
293 $('input#confirm_email, input#email').closest('.box').removeClass('form-error');
294 $('input#confirm_email, input#email').closest('.box').find('.error-field').text('');
295 }
296 });
297
298 // validate business address
299 let businessAddressInputs = $(
300 '#mailchimp-sf-business-address input, #mailchimp-sf-business-address select',
301 );
302 businessAddressInputs.on('input', (e) => {
303 const input = e.target;
304
305 $(input).closest('.box').removeClass('form-error');
306 $(input).closest('.box').find('.error-field').text('');
307 });
308
309 // Handle create account button click.
310 $('#mailchimp-sf-create-activate-account').click((e) => {
311 e.preventDefault();
312
313 profileDetailsInputs = $('#mailchimp-sf-profile-details input');
314 const profileErrors = getFormErrors(profileDetailsInputs);
315 const profileDetailsValid = validateAccountForm(
316 profileErrors,
317 '#mailchimp-sf-profile-details',
318 true,
319 );
320
321 businessAddressInputs = $(
322 '#mailchimp-sf-business-address input, #mailchimp-sf-business-address select',
323 );
324 const businessAddressErrors = getFormErrors(businessAddressInputs);
325 const businessAddressValid = validateAccountForm(
326 businessAddressErrors,
327 '#mailchimp-sf-business-address',
328 true,
329 );
330
331 if (profileDetailsValid && businessAddressValid) {
332 $('.mailchimp-sf-activate-account').submit();
333 }
334 });
335
336 $('.mailchimp-sf-activate-account').submit((e) => {
337 e.preventDefault();
338 $('#mailchimp-sf-create-activate-account').attr('disabled', true);
339 $('#mailchimp-sf-create-activate-account .mailchimp-sf-loading').removeClass('hidden');
340
341 const errorSelector = '.mailchimp-sf-create-account .general-error p';
342 $(errorSelector).html('');
343 const formData = $(e.target).serializeArray();
344 const formDataObject = {};
345 formData.forEach((obj) => {
346 formDataObject[obj.name] = obj.value;
347 });
348
349 const postData = {
350 email: formDataObject.email,
351 username: formDataObject.email,
352 business_name: formDataObject.business_name,
353 first_name: formDataObject.first_name,
354 last_name: formDataObject.last_name,
355 org: formDataObject.org,
356 phone_number: formDataObject.phone_number,
357 timezone: formDataObject.timezone,
358 address: {
359 address1: formDataObject.address,
360 city: formDataObject.city,
361 state: formDataObject.state,
362 zip: formDataObject.zip,
363 country: formDataObject.country,
364 },
365 };
366
367 // Add address2 if available.
368 if (formDataObject.address2 !== '') {
369 postData.address.address2 = formDataObject.address2;
370 }
371
372 $.post(
373 params.ajax_url,
374 {
375 action: 'mailchimp_sf_create_account',
376 data: postData,
377 nonce: params.create_account_nonce,
378 },
379 function (response) {
380 $('.mailchimp-sf-email').text(formDataObject.email);
381 $('#mailchimp-sf-create-activate-account').attr('disabled', false);
382 $('#mailchimp-sf-create-activate-account .mailchimp-sf-loading').addClass(
383 'hidden',
384 );
385
386 if (response.success && response.data) {
387 $('.mailchimp-sf-create-account__body-inner').addClass('hidden');
388 $('.mailchimp-sf-confirm-email-wrapper').removeClass('hidden');
389
390 // Update wizard steps.
391 $('.wizard-steps .step-1').removeClass('current');
392 $('.wizard-steps .step-2').removeClass('deselected');
393 $('.wizard-steps .step-2').addClass('current');
394
395 // Waiting for login.
396 waitingForMailchimpAccountLogin();
397 } else if (response.data && response.data.suggest_login) {
398 $('.mailchimp-sf-create-account__body-inner').addClass('hidden');
399 $('.mailchimp-sf-suggest-to-login').removeClass('hidden');
400 } else if (response.data && response.data.message) {
401 $(errorSelector).html(response.data.message);
402 window.scrollTo({ top: 0, behavior: 'smooth' });
403 } else {
404 $(errorSelector).html(params.generic_error);
405 window.scrollTo({ top: 0, behavior: 'smooth' });
406 }
407 },
408 ).fail(function () {
409 $(errorSelector).html(params.generic_error);
410 window.scrollTo({ top: 0, behavior: 'smooth' });
411 $('#mailchimp-sf-create-activate-account').attr('disabled', false);
412 $('#mailchimp-sf-create-activate-account .mailchimp-sf-loading').addClass('hidden');
413 });
414 });
415 });
416 })(jQuery); // eslint-disable-line no-undef
417
418 // User Sync Settings.
419 (function ($) {
420 const userSyncSettingsPage = $('.mailchimp-sf-user-sync-page');
421 if (userSyncSettingsPage.length > 0) {
422 const syncExistingContactsOnly = $(
423 'input[type="checkbox"][name="mailchimp_sf_user_sync_settings[existing_contacts_only]"]',
424 );
425 if (syncExistingContactsOnly) {
426 syncExistingContactsOnly.change(function () {
427 if (this.checked) {
428 $('div.mailchimp-user-sync-subscriber-status').hide();
429 } else {
430 $('div.mailchimp-user-sync-subscriber-status').show();
431 }
432 });
433
434 // Trigger change event to hide/show subscriber status.
435 syncExistingContactsOnly.trigger('change');
436 }
437 }
438 })(jQuery); // eslint-disable-line no-undef
439
440 // Update the user sync status.
441 (function ($) {
442 const statusWrapper = $('.mailchimp-sf-user-sync-status');
443 const processRunning = statusWrapper.length;
444 if (!processRunning) {
445 return;
446 }
447
448 const params = window.mailchimp_sf_admin_params || {};
449 const ajaxUrl = params.ajax_url;
450 const ajaxNonce = params.user_sync_status_nonce;
451
452 const intervalId = setInterval(function () {
453 $.ajax({
454 url: ajaxUrl,
455 type: 'POST',
456 data: {
457 action: 'mailchimp_sf_get_user_sync_status',
458 nonce: ajaxNonce,
459 },
460 success(response) {
461 if (response.success && response.data) {
462 if (response.data.is_running && response.data.status) {
463 // Update the sync status on the page
464 statusWrapper.html(response.data.status);
465 } else {
466 // Clear interval and reload the page.
467 clearInterval(intervalId);
468 window.location.reload();
469 }
470 }
471 },
472 error(jqXHR, textStatus, errorThrown) {
473 // eslint-disable-next-line no-console
474 console.error('Error: ', textStatus, ', Details: ', errorThrown);
475 },
476 });
477 }, 30000); // 30000 milliseconds = 30 seconds
478 })(jQuery); // eslint-disable-line no-undef
479
480 // User Sync Error logs.
481 (function ($) {
482 const userSyncErrors = $('.mailchimp-sf-user-sync-errors');
483 if (!userSyncErrors) {
484 return;
485 }
486
487 const params = window.mailchimp_sf_admin_params || {};
488 const tableSelector = 'table.mailchimp-sf-user-sync-errors-table';
489 const noErrorsFoundRow =
490 '<tr><td colspan="4"><em>' + params.no_errors_found + '</em></td></tr>';
491 $('#mailchimp-sf-clear-user-sync-errors').on('click', function (e) {
492 e.preventDefault();
493 $(this).prop('disabled', true);
494 $('.mailchimp-sf-user-sync-errors-footer-actions .spinner').addClass('is-active');
495
496 $.ajax({
497 url: params.ajax_url,
498 type: 'POST',
499 data: {
500 action: 'mailchimp_sf_delete_user_sync_error',
501 id: 'all',
502 nonce: params.delete_user_sync_error_nonce,
503 },
504 success(response) {
505 if (response && response.success) {
506 $(tableSelector + ' tbody').html(noErrorsFoundRow);
507 $('.mailchimp-sf-user-sync-errors-footer-actions .spinner').removeClass(
508 'is-active',
509 );
510 } else {
511 window.location.reload();
512 }
513 },
514 error(jqXHR, textStatus, errorThrown) {
515 // eslint-disable-next-line no-console
516 console.error('Error: ', textStatus, ', Details: ', errorThrown);
517 window.location.reload();
518 },
519 });
520 });
521
522 $(tableSelector).on('click', '.mailchimp-sf-user-sync-error-delete', function (e) {
523 e.preventDefault();
524
525 const errorId = $(this).data('id');
526 const rowId = '#row-' + errorId;
527 $(rowId).find('.mailchimp-sf-user-sync-error-action .spinner').addClass('is-active');
528 $(this).prop('disabled', true);
529 $.ajax({
530 url: params.ajax_url,
531 type: 'POST',
532 data: {
533 action: 'mailchimp_sf_delete_user_sync_error',
534 nonce: params.delete_user_sync_error_nonce,
535 id: errorId,
536 },
537 success(response) {
538 if (response && response.success) {
539 $(rowId).remove();
540
541 if (!$(tableSelector + ' tbody tr').length) {
542 $(tableSelector + ' tbody').html(noErrorsFoundRow);
543 $('#mailchimp-sf-clear-user-sync-errors').prop('disabled', true);
544 }
545 } else {
546 window.location.reload();
547 }
548 },
549 error(jqXHR, textStatus, errorThrown) {
550 // eslint-disable-next-line no-console
551 console.error('Error: ', textStatus, ', Details: ', errorThrown);
552 window.location.reload();
553 },
554 });
555 });
556 })(jQuery); // eslint-disable-line no-undef
557
558 // Form settings.
559 (function ($) {
560 /**
561 * Initialize form settings functionality
562 */
563 function initFormSettings() {
564 const $form = $('#mailchimp-sf-settings-form');
565 const $userSyncForm = $('.mailchimp-sf-user-sync-form');
566 const $submitButtons = $('input[type="submit"].mailchimp-sf-button-submit');
567 const params = window.mailchimp_sf_admin_params || {};
568 const ajaxUrl = params.ajax_url || '';
569 const ajaxNonce = params.preview_form_nonce || '';
570
571 // Initially hide all submit buttons
572 $submitButtons.hide();
573
574 /**
575 * Toggle submit buttons visibility based on form state
576 *
577 * @param {jQuery} $changedInput - The input that was changed
578 */
579 function toggleSubmitButtons($changedInput) {
580 $changedInput
581 .closest('.mailchimp-sf-section')
582 .find('.mailchimp-sf-button-submit')
583 .show();
584 $changedInput
585 .closest('.mailchimp-sf-section')
586 .find('.mailchimp-sf-section-footer')
587 .slideDown({ duration: 200 });
588 }
589
590 function blockElement(elementSelector) {
591 const $el = $(elementSelector);
592 $el.append(
593 '<div class="block-overlay" style="position:absolute;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.35);z-index:100;display:flex;justify-content:center;align-items:center;">' +
594 '<div style="background:#fff;border-radius: 50%;"><span class="spinner is-active" style="margin: 0px;"></span></div>' +
595 '</div>',
596 );
597 }
598
599 function unblockElement(elementSelector) {
600 $(elementSelector + ' .block-overlay').remove();
601 }
602
603 /**
604 * Debounce function
605 *
606 * @param {Function} func - The function to debounce
607 * @param {number} delay - The delay in milliseconds
608 * @returns {Function} The debounced function
609 */
610 function debounce(func, delay) {
611 let timeout;
612 return function (...args) {
613 clearTimeout(timeout);
614 timeout = setTimeout(() => {
615 func.apply(this, args);
616 }, delay);
617 };
618 }
619
620 /**
621 * Preview the form.
622 */
623 function previewForm() {
624 const $previewer = $('.mailchimp-sf-form-preview');
625 if ($previewer.length === 0) {
626 return;
627 }
628
629 // Loading overlay.
630 blockElement('.mailchimp-sf-form-preview-content');
631
632 const fields = {};
633 const groups = {};
634 $form.find('input[name^="mc_mv_"]').each(function () {
635 const $input = $(this);
636 fields[$input.data('tag')] = $input.is(':checked');
637 });
638 $form.find('input[name^="mc_show_interest_groups_"]').each(function () {
639 const $input = $(this);
640 groups[$input.data('group-id')] = $input.is(':checked');
641 });
642
643 const previewData = {
644 header: $('#mc_header_content').val(),
645 sub_heading: $('#mc_subheader_content').val(),
646 submit_text: $('#mc_submit_text').val(),
647 fields,
648 groups,
649 display_unsub_link: $('#mc_use_unsub_link').is(':checked'),
650 };
651
652 $.ajax({
653 url: ajaxUrl,
654 type: 'POST',
655 data: {
656 action: 'mailchimp_sf_preview_form',
657 nonce: ajaxNonce,
658 preview_data: previewData,
659 },
660 success(response) {
661 if (response.success && response.data) {
662 unblockElement('.mailchimp-sf-form-preview-content');
663 $previewer.html(response.data);
664 } else {
665 unblockElement('.mailchimp-sf-form-preview-content');
666 $previewer.html(
667 '<div class="mailchimp-sf-form-preview-error">' +
668 params.generic_error +
669 '</div>',
670 );
671 }
672 },
673 error(jqXHR, textStatus, errorThrown) {
674 // eslint-disable-next-line no-console
675 console.error('Error: ', textStatus, ', Details: ', errorThrown);
676 unblockElement('.mailchimp-sf-form-preview-content');
677 $previewer.html(
678 '<div class="mailchimp-sf-form-preview-error">' +
679 params.generic_error +
680 '</div>',
681 );
682 },
683 });
684 }
685
686 const debouncedPreviewForm = debounce(previewForm, 300);
687
688 // Watch for changes on all form elements
689 $form.on('input change', 'input, textarea, select', function () {
690 const $changedInput = $(this);
691 toggleSubmitButtons($changedInput);
692 debouncedPreviewForm();
693 });
694
695 // Watch for changes on user sync form elements
696 $userSyncForm.on('input change', 'input, textarea, select', function () {
697 const $changedInput = $(this);
698 toggleSubmitButtons($changedInput);
699 });
700 }
701
702 // Initialize when document is ready
703 $(document).ready(initFormSettings);
704 })(jQuery); // eslint-disable-line no-undef
705