PluginProbe
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder / 51.1.49
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder v51.1.49
51.1.83 51.1.82 51.1.81 51.1.79 51.1.78 51.1.77 51.1.76 51.1.74 51.1.75 51.1.65 51.1.64 51.1.63 trunk 51.1.14 51.1.2 51.1.35 51.1.36 51.1.37 51.1.38 51.1.39 51.1.44 51.1.45 51.1.46 51.1.47 51.1.49 All 37 releases
king-addons / includes / widgets / Login_Register_Form / script.js

script.js in King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder 51.1.49, at includes/widgets/Login_Register_Form/script.js

921 lines 36.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function($) {
2 'use strict';
3
4 // Initialize when Elementor frontend is ready
5 $(window).on('elementor/frontend/init', function() {
6 elementorFrontend.hooks.addAction('frontend/element_ready/king-addons-login-register-form.default', function($scope) {
7 initLoginRegisterForm($scope);
8 });
9 });
10
11 // Initialize for non-Elementor pages
12 $(document).ready(function() {
13 if (typeof elementorFrontend === 'undefined') {
14 $('.king-addons-login-register-form-wrapper').each(function() {
15 initLoginRegisterForm($(this));
16 });
17 }
18 });
19
20 function initLoginRegisterForm($scope) {
21 const $wrapper = $scope.find('.king-addons-login-register-form-wrapper');
22 if (!$wrapper.length) return;
23
24 const $loginForm = $wrapper.find('.king-addons-login-form');
25 const $registerForm = $wrapper.find('.king-addons-register-form');
26 const widgetId = $wrapper.data('widget-id');
27 const isAjaxEnabled = $wrapper.data('ajax') === true;
28
29 // Get widget settings from data attributes
30 const widgetSettings = {
31 recaptcha_secret_key: $wrapper.data('recaptcha-secret-key') || '',
32 recaptcha_score_threshold: $wrapper.data('recaptcha-threshold') || '0.5',
33 redirect_after_login: $wrapper.data('redirect-login') || '',
34 redirect_after_register: $wrapper.data('redirect-register') || '',
35 terms_required: $wrapper.data('terms-required') || 'no',
36 enable_user_email: $wrapper.data('enable-user-email') || 'yes',
37 user_email_subject: $wrapper.data('user-email-subject') || '',
38 user_email_content: $wrapper.data('user-email-content') || '',
39 enable_admin_email: $wrapper.data('enable-admin-email') || 'no',
40 admin_email_address: $wrapper.data('admin-email-address') || '',
41 admin_email_subject: $wrapper.data('admin-email-subject') || '',
42 admin_email_content: $wrapper.data('admin-email-content') || '',
43 enable_mailchimp_integration: $wrapper.data('enable-mailchimp') || 'no',
44 mailchimp_api_key: $wrapper.data('mailchimp-api-key') || '',
45 mailchimp_list_id: $wrapper.data('mailchimp-list-id') || '',
46 mailchimp_double_optin: $wrapper.data('mailchimp-double-optin') || 'no',
47 auto_login_after_register: $wrapper.data('auto-login') || 'yes'
48 };
49
50 // Form toggle functionality
51 initFormToggle($wrapper, $loginForm, $registerForm);
52
53 // AJAX form submission
54 if (isAjaxEnabled) {
55 const $lostPasswordForm = $wrapper.find('.king-addons-lost-password-form');
56 initAjaxForms($wrapper, $loginForm, $registerForm, $lostPasswordForm, widgetId, widgetSettings);
57 }
58
59 // Form validation
60 initFormValidation($loginForm, $registerForm);
61
62 // Password visibility toggle
63 initPasswordToggle($wrapper);
64
65 // Social login
66 initSocialLogin($wrapper);
67
68 // reCAPTCHA initialization
69 initRecaptcha($wrapper);
70 }
71
72 function initFormToggle($wrapper, $loginForm, $registerForm) {
73 $wrapper.on('click', '.king-addons-form-toggle', function(e) {
74 e.preventDefault();
75
76 const toggleType = $(this).data('toggle');
77 const $lostPasswordForm = $wrapper.find('.king-addons-lost-password-form');
78
79 let $targetForm;
80 if (toggleType === 'login') {
81 $targetForm = $loginForm;
82 } else if (toggleType === 'register') {
83 $targetForm = $registerForm;
84 } else if (toggleType === 'lostpassword') {
85 $targetForm = $lostPasswordForm;
86 }
87
88 if (!$targetForm) return;
89
90 // Clear any existing messages
91 clearMessages($wrapper);
92
93 // Hide all forms
94 $loginForm.hide();
95 $registerForm.hide();
96 $lostPasswordForm.hide();
97
98 // Show target form
99 $targetForm.show();
100 });
101 }
102
103 function initAjaxForms($wrapper, $loginForm, $registerForm, $lostPasswordForm, widgetId, widgetSettings) {
104 // Login form submission
105 $loginForm.find('form').on('submit', function(e) {
106 e.preventDefault();
107 handleLoginSubmission($(this), $wrapper, widgetId, widgetSettings);
108 });
109
110 // Register form submission
111 $registerForm.find('form').on('submit', function(e) {
112 e.preventDefault();
113 handleRegisterSubmission($(this), $wrapper, widgetId, widgetSettings);
114 });
115
116 // Lost password form submission
117 if ($lostPasswordForm.length) {
118 $lostPasswordForm.find('form').on('submit', function(e) {
119 e.preventDefault();
120 handleLostPasswordSubmission($(this), $wrapper, widgetId);
121 });
122 }
123 }
124
125 function handleLoginSubmission($form, $wrapper, widgetId, widgetSettings) {
126 const $messageContainer = $form.closest('.king-addons-login-register-form').find('.king-addons-form-message');
127 const $submitButton = $form.find('.king-addons-login-button');
128
129 // Clear previous messages
130 clearMessages($wrapper);
131
132 // Check if variables are defined
133 if (typeof king_addons_login_register_vars === 'undefined') {
134 console.error('King Addons Login Register: AJAX variables not loaded');
135 showMessage($messageContainer, 'Configuration error. Please refresh the page.', 'error');
136 return;
137 }
138
139 // Get form data
140 const formData = {
141 action: 'king_addons_user_login',
142 nonce: king_addons_login_register_vars.login_nonce,
143 username: $form.find('[name="username"]').val(),
144 password: $form.find('[name="password"]').val(),
145 remember: $form.find('[name="remember"]').is(':checked') ? 1 : 0,
146 widget_id: widgetId,
147 recaptcha_secret_key: widgetSettings.recaptcha_secret_key,
148 recaptcha_score_threshold: widgetSettings.recaptcha_score_threshold,
149 redirect_after_login: widgetSettings.redirect_after_login
150 };
151
152 // Add reCAPTCHA response if present
153 const recaptchaResponse = $form.find('[name="g-recaptcha-response"]').val();
154 if (recaptchaResponse) {
155 formData['g-recaptcha-response'] = recaptchaResponse;
156 }
157
158 console.log('Submitting login form with data:', formData);
159
160 // Validate required fields
161 if (!formData.username || !formData.password) {
162 showMessage($messageContainer, 'Please fill in all required fields.', 'error');
163 return;
164 }
165
166 // Show loading state
167 setLoadingState($form, true);
168 $submitButton.prop('disabled', true);
169
170 // Submit via AJAX
171 $.ajax({
172 url: king_addons_login_register_vars.ajax_url,
173 type: 'POST',
174 data: formData,
175 success: function(response) {
176 if (response.success) {
177 showMessage($messageContainer, response.data.message, 'success');
178
179 // Redirect if URL provided
180 if (response.data.redirect) {
181 setTimeout(function() {
182 window.location.href = response.data.redirect;
183 }, 1500);
184 } else {
185 // Reload page
186 setTimeout(function() {
187 location.reload();
188 }, 1500);
189 }
190 } else {
191 showMessage($messageContainer, response.data.message || 'An error occurred. Please try again.', 'error');
192 }
193 },
194 error: function(xhr, status, error) {
195 console.error('Login AJAX Error:', error);
196 console.error('Login XHR response:', xhr.responseText);
197 console.error('Login XHR status code:', xhr.status);
198
199 let errorMessage = 'Network error. Please check your connection and try again.';
200
201 // Try to parse error response
202 try {
203 const response = JSON.parse(xhr.responseText);
204 if (response.data && response.data.message) {
205 errorMessage = response.data.message;
206 }
207 } catch (e) {
208 // Use default error message
209 }
210
211 showMessage($messageContainer, errorMessage, 'error');
212 },
213 complete: function() {
214 setLoadingState($form, false);
215 $submitButton.prop('disabled', false);
216 }
217 });
218 }
219
220 function handleRegisterSubmission($form, $wrapper, widgetId, widgetSettings) {
221 const $messageContainer = $form.closest('.king-addons-login-register-form').find('.king-addons-form-message');
222 const $submitButton = $form.find('.king-addons-register-button');
223
224 // Clear previous messages
225 clearMessages($wrapper);
226
227 // Check if variables are defined
228 if (typeof king_addons_login_register_vars === 'undefined') {
229 console.error('King Addons Login Register: AJAX variables not loaded');
230 showMessage($messageContainer, 'Configuration error. Please refresh the page.', 'error');
231 return;
232 }
233
234 // Get form data
235 const formData = {
236 action: 'king_addons_user_register',
237 nonce: king_addons_login_register_vars.register_nonce,
238 email: $form.find('[name="email"]').val(),
239 username: $form.find('[name="username"]').val(),
240 password: $form.find('[name="password"]').val(),
241 confirm_password: $form.find('[name="confirm_password"]').val(),
242 widget_id: widgetId,
243 recaptcha_secret_key: widgetSettings.recaptcha_secret_key,
244 recaptcha_score_threshold: widgetSettings.recaptcha_score_threshold,
245 redirect_after_register: widgetSettings.redirect_after_register,
246 terms_required: widgetSettings.terms_required,
247 enable_user_email: widgetSettings.enable_user_email,
248 user_email_subject: widgetSettings.user_email_subject,
249 user_email_content: widgetSettings.user_email_content,
250 enable_admin_email: widgetSettings.enable_admin_email,
251 admin_email_address: widgetSettings.admin_email_address,
252 admin_email_subject: widgetSettings.admin_email_subject,
253 admin_email_content: widgetSettings.admin_email_content,
254 enable_mailchimp_integration: widgetSettings.enable_mailchimp_integration,
255 mailchimp_api_key: widgetSettings.mailchimp_api_key,
256 mailchimp_list_id: widgetSettings.mailchimp_list_id,
257 mailchimp_double_optin: widgetSettings.mailchimp_double_optin,
258 auto_login_after_register: widgetSettings.auto_login_after_register
259 };
260
261 // Add additional fields if they exist
262 const firstName = $form.find('[name="first_name"]').val();
263 const lastName = $form.find('[name="last_name"]').val();
264 const website = $form.find('[name="website"]').val();
265 const phone = $form.find('[name="phone"]').val();
266 const userRole = $form.find('[name="user_role"]').val();
267 const termsConditions = $form.find('[name="terms_conditions"]').is(':checked');
268
269 if (firstName) formData.first_name = firstName;
270 if (lastName) formData.last_name = lastName;
271 if (website) formData.website = website;
272 if (phone) formData.phone = phone;
273 if (userRole) formData.user_role = userRole;
274 if (termsConditions) formData.terms_conditions = 1;
275
276 // Collect custom fields from repeater
277 const customFields = {};
278 const customFieldLabels = {};
279
280 $form.find('[name^="custom_field_"]').each(function() {
281 const fieldName = $(this).attr('name');
282 const fieldType = $(this).attr('type');
283 const fieldLabel = $(this).closest('.king-addons-form-field').data('field-label') || fieldName.replace('custom_field_', 'Field ');
284 let fieldValue;
285
286 if (fieldType === 'checkbox') {
287 // For checkboxes, collect all checked values
288 const checkedBoxes = $form.find('[name="' + fieldName + '"]:checked');
289 if (checkedBoxes.length > 0) {
290 const values = [];
291 checkedBoxes.each(function() {
292 values.push($(this).val());
293 });
294 fieldValue = values.length === 1 ? values[0] : values;
295 }
296 } else if (fieldType === 'radio') {
297 // For radio buttons, get the checked value
298 fieldValue = $form.find('[name="' + fieldName + '"]:checked').val();
299 } else {
300 // For other input types (text, email, etc.)
301 fieldValue = $(this).val();
302 }
303
304 if (fieldValue && fieldValue !== '') {
305 customFields[fieldName] = fieldValue;
306 customFieldLabels[fieldName] = fieldLabel;
307 }
308 });
309
310 // Also handle textarea and select fields
311 $form.find('textarea[name^="custom_field_"], select[name^="custom_field_"]').each(function() {
312 const fieldName = $(this).attr('name');
313 const fieldValue = $(this).val();
314 const fieldLabel = $(this).closest('.king-addons-form-field').data('field-label') || fieldName.replace('custom_field_', 'Field ');
315
316 if (fieldValue && fieldValue !== '') {
317 customFields[fieldName] = fieldValue;
318 customFieldLabels[fieldName] = fieldLabel;
319 }
320 });
321
322 // Add custom fields to form data if any exist
323 if (Object.keys(customFields).length > 0) {
324 formData.custom_fields = customFields;
325 formData.custom_field_labels = customFieldLabels;
326 console.log('Found custom fields:', customFields);
327 console.log('Field labels:', customFieldLabels);
328 } else {
329 console.log('No custom fields found');
330 }
331
332 // Add reCAPTCHA response if present
333 const recaptchaResponse = $form.find('[name="g-recaptcha-response"]').val();
334 if (recaptchaResponse) {
335 formData['g-recaptcha-response'] = recaptchaResponse;
336 }
337
338 console.log('Submitting registration form with data:', formData);
339
340 // Client-side validation
341 const validationResult = validateRegistrationForm(formData);
342 if (!validationResult.valid) {
343 showMessage($messageContainer, validationResult.message, 'error');
344 return;
345 }
346
347 // Show loading state
348 setLoadingState($form, true);
349 $submitButton.prop('disabled', true);
350
351 // Prepare FormData for file uploads
352 let ajaxData = formData;
353 let ajaxOptions = {
354 url: king_addons_login_register_vars.ajax_url,
355 type: 'POST',
356 data: ajaxData,
357 };
358
359 // Check if there are file inputs
360 const $fileInputs = $form.find('input[type="file"]');
361 if ($fileInputs.length > 0) {
362 // Use FormData for file uploads
363 const formDataObj = new FormData();
364
365 // Add all form data
366 for (const key in formData) {
367 if (formData.hasOwnProperty(key)) {
368 if (typeof formData[key] === 'object' && formData[key] !== null) {
369 formDataObj.append(key, JSON.stringify(formData[key]));
370 } else {
371 formDataObj.append(key, formData[key]);
372 }
373 }
374 }
375
376 // Add files
377 $fileInputs.each(function() {
378 const $input = $(this);
379 const files = $input[0].files;
380 if (files.length > 0) {
381 for (let i = 0; i < files.length; i++) {
382 formDataObj.append($input.attr('name'), files[i]);
383 }
384 }
385 });
386
387 ajaxOptions.data = formDataObj;
388 ajaxOptions.processData = false;
389 ajaxOptions.contentType = false;
390 }
391
392 // Submit via AJAX
393 $.ajax(ajaxOptions).done(function(response) {
394 if (response.success) {
395 showMessage($messageContainer, response.data.message, 'success');
396
397 // Redirect if URL provided
398 if (response.data.redirect) {
399 setTimeout(function() {
400 window.location.href = response.data.redirect;
401 }, 1500);
402 } else {
403 // Reload page or switch to login form
404 setTimeout(function() {
405 location.reload();
406 }, 1500);
407 }
408 } else {
409 showMessage($messageContainer, response.data.message || 'Registration failed. Please try again.', 'error');
410 }
411 }).fail(function(xhr, status, error) {
412 console.error('Registration AJAX Error:', error);
413 console.error('Registration XHR response:', xhr.responseText);
414 console.error('Registration XHR status code:', xhr.status);
415
416 let errorMessage = 'Network error. Please check your connection and try again.';
417
418 // Try to parse error response
419 try {
420 const response = JSON.parse(xhr.responseText);
421 if (response.data && response.data.message) {
422 errorMessage = response.data.message;
423 }
424 } catch (e) {
425 // Use default error message
426 }
427
428 showMessage($messageContainer, errorMessage, 'error');
429 }).always(function() {
430 setLoadingState($form, false);
431 $submitButton.prop('disabled', false);
432 });
433 }
434
435 function handleLostPasswordSubmission($form, $wrapper, widgetId) {
436 const $messageContainer = $form.closest('.king-addons-lost-password-form').find('.king-addons-form-message');
437 const $submitButton = $form.find('.king-addons-lostpassword-button');
438
439 // Clear previous messages
440 clearMessages($wrapper);
441
442 // Check if variables are defined
443 if (typeof king_addons_login_register_vars === 'undefined') {
444 console.error('King Addons Login Register: AJAX variables not loaded');
445 showMessage($messageContainer, 'Configuration error. Please refresh the page.', 'error');
446 return;
447 }
448
449 // Get form data
450 const formData = {
451 action: 'king_addons_user_lostpassword',
452 nonce: king_addons_login_register_vars.lostpassword_nonce,
453 user_login: $form.find('[name="user_login"]').val(),
454 widget_id: widgetId
455 };
456
457 // Validate required fields
458 if (!formData.user_login) {
459 showMessage($messageContainer, 'Please enter your email address.', 'error');
460 return;
461 }
462
463 // Show loading state
464 setLoadingState($form, true);
465 $submitButton.prop('disabled', true);
466
467 // Submit via AJAX
468 $.ajax({
469 url: king_addons_login_register_vars.ajax_url,
470 type: 'POST',
471 data: formData,
472 timeout: 30000,
473 success: function(response) {
474 if (response.success) {
475 showMessage($messageContainer, response.data.message, 'success');
476 $form[0].reset(); // Clear the form
477 } else {
478 showMessage($messageContainer, response.data.message || 'Lost password request failed. Please try again.', 'error');
479 }
480 },
481 error: function(xhr, status, error) {
482 console.error('Lost Password AJAX Error:', error);
483 console.error('Lost Password XHR response:', xhr.responseText);
484 console.error('Lost Password XHR status code:', xhr.status);
485
486 let errorMessage = 'Network error. Please check your connection and try again.';
487
488 // Try to parse error response
489 try {
490 const response = JSON.parse(xhr.responseText);
491 if (response.data && response.data.message) {
492 errorMessage = response.data.message;
493 }
494 } catch (e) {
495 // Use default error message
496 }
497
498 showMessage($messageContainer, errorMessage, 'error');
499 },
500 complete: function() {
501 setLoadingState($form, false);
502 $submitButton.prop('disabled', false);
503 }
504 });
505 }
506
507 function validateRegistrationForm(data) {
508 // Check required fields
509 if (!data.email || !data.username || !data.password || !data.confirm_password) {
510 return {
511 valid: false,
512 message: 'Please fill in all required fields.'
513 };
514 }
515
516 // Validate email format
517 const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
518 if (!emailRegex.test(data.email)) {
519 return {
520 valid: false,
521 message: 'Please enter a valid email address.'
522 };
523 }
524
525 // Validate username (basic validation)
526 if (data.username.length < 3) {
527 return {
528 valid: false,
529 message: 'Username must be at least 3 characters long.'
530 };
531 }
532
533 // Check username characters
534 const usernameRegex = /^[a-zA-Z0-9._-]+$/;
535 if (!usernameRegex.test(data.username)) {
536 return {
537 valid: false,
538 message: 'Username can only contain letters, numbers, periods, hyphens, and underscores.'
539 };
540 }
541
542 // Validate password length
543 if (data.password.length < 6) {
544 return {
545 valid: false,
546 message: 'Password must be at least 6 characters long.'
547 };
548 }
549
550 // Enhanced password strength validation (updated for security)
551 if (data.password.length < 8) {
552 return {
553 valid: false,
554 message: 'Password must be at least 8 characters long.'
555 };
556 }
557
558 // Check for basic password strength
559 const hasLower = /[a-z]/.test(data.password);
560 const hasUpper = /[A-Z]/.test(data.password);
561 const hasNumbers = /\d/.test(data.password);
562 const hasSpecial = /[!@#$%^&*(),.?":{}|<>]/.test(data.password);
563
564 let strengthScore = 0;
565 if (hasLower) strengthScore++;
566 if (hasUpper) strengthScore++;
567 if (hasNumbers) strengthScore++;
568 if (hasSpecial) strengthScore++;
569
570 if (strengthScore < 3) {
571 return {
572 valid: false,
573 message: 'Password must contain uppercase, lowercase, numbers, and special characters for security.'
574 };
575 }
576
577 // Check against common passwords
578 const commonPasswords = ['password', '123456', '123456789', 'qwerty', 'abc123', 'password123'];
579 if (commonPasswords.includes(data.password.toLowerCase())) {
580 return {
581 valid: false,
582 message: 'Please choose a more unique password. This password is too common.'
583 };
584 }
585
586 // Check password confirmation
587 if (data.password !== data.confirm_password) {
588 return {
589 valid: false,
590 message: 'Passwords do not match.'
591 };
592 }
593
594 // Check terms and conditions if required
595 const $termsCheckbox = $('.king-addons-register-form [name="terms_conditions"]');
596 if ($termsCheckbox.length && $termsCheckbox.prop('required') && !$termsCheckbox.is(':checked')) {
597 return {
598 valid: false,
599 message: 'Please accept the Terms & Conditions.'
600 };
601 }
602
603 return { valid: true };
604 }
605
606 function initFormValidation($loginForm, $registerForm) {
607 // Real-time validation for registration form
608 $registerForm.find('[name="confirm_password"]').on('blur keyup', function() {
609 const password = $registerForm.find('[name="password"]').val();
610 const confirmPassword = $(this).val();
611 const $field = $(this).closest('.king-addons-form-field');
612
613 // Remove existing validation classes
614 $field.removeClass('field-error field-success');
615
616 if (confirmPassword && password && password !== confirmPassword) {
617 $field.addClass('field-error');
618 showFieldError($field, 'Passwords do not match.');
619 } else if (confirmPassword && password && password === confirmPassword) {
620 $field.addClass('field-success');
621 hideFieldError($field);
622 } else {
623 hideFieldError($field);
624 }
625 });
626
627 // Email validation
628 $registerForm.find('[name="email"]').on('blur', function() {
629 const email = $(this).val();
630 const $field = $(this).closest('.king-addons-form-field');
631 const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
632
633 $field.removeClass('field-error field-success');
634
635 if (email && !emailRegex.test(email)) {
636 $field.addClass('field-error');
637 showFieldError($field, 'Please enter a valid email address.');
638 } else if (email) {
639 $field.addClass('field-success');
640 hideFieldError($field);
641 } else {
642 hideFieldError($field);
643 }
644 });
645
646 // Username validation
647 $registerForm.find('[name="username"]').on('blur', function() {
648 const username = $(this).val();
649 const $field = $(this).closest('.king-addons-form-field');
650 const usernameRegex = /^[a-zA-Z0-9._-]+$/;
651
652 $field.removeClass('field-error field-success');
653
654 if (username && (username.length < 3 || !usernameRegex.test(username))) {
655 $field.addClass('field-error');
656 const message = username.length < 3
657 ? 'Username must be at least 3 characters long.'
658 : 'Username can only contain letters, numbers, periods, hyphens, and underscores.';
659 showFieldError($field, message);
660 } else if (username) {
661 $field.addClass('field-success');
662 hideFieldError($field);
663 } else {
664 hideFieldError($field);
665 }
666 });
667 }
668
669 function showFieldError($field, message) {
670 hideFieldError($field);
671 $field.append('<span class="field-error-message" style="color: #f44336; font-size: 12px; margin-top: 5px; display: block;">' + message + '</span>');
672 }
673
674 function hideFieldError($field) {
675 $field.find('.field-error-message').remove();
676 }
677
678 function initPasswordToggle($wrapper) {
679 $wrapper.on('click', '.king-addons-password-toggle', function(e) {
680 e.preventDefault();
681
682 const $button = $(this);
683 const $input = $button.siblings('input[type="password"], input[type="text"]');
684 const $icon = $button.find('.king-addons-password-toggle-icon');
685
686 if ($input.attr('type') === 'password') {
687 $input.attr('type', 'text');
688 $icon.text('🙈');
689 $button.attr('aria-label', 'Hide password');
690 } else {
691 $input.attr('type', 'password');
692 $icon.text('👁');
693 $button.attr('aria-label', 'Show password');
694 }
695 });
696 }
697
698 function showMessage($container, message, type) {
699 $container.removeClass('success error').addClass(type + ' show').text(message);
700
701 // Auto-hide success messages after 5 seconds
702 if (type === 'success') {
703 setTimeout(function() {
704 $container.removeClass('show');
705 }, 5000);
706 }
707 }
708
709 function clearMessages($wrapper) {
710 $wrapper.find('.king-addons-form-message').removeClass('success error show').text('');
711 }
712
713 function setLoadingState($form, loading) {
714 if (loading) {
715 $form.addClass('king-addons-form-loading');
716 } else {
717 $form.removeClass('king-addons-form-loading');
718 }
719 }
720
721 function initSocialLogin($wrapper) {
722 // Google login
723 $wrapper.find('.king-addons-google-login').on('click', function(e) {
724 e.preventDefault();
725 const $button = $(this);
726 const clientId = $button.data('client-id');
727
728 if (!clientId) {
729 showSocialLoginError('Google Client ID not configured. Please check widget settings.');
730 return;
731 }
732
733 // Check if Google API is loaded
734 if (typeof google === 'undefined' || !google.accounts) {
735 showSocialLoginError('Google API not loaded. Please check your internet connection.');
736 return;
737 }
738
739 // Initialize Google One Tap
740 google.accounts.id.initialize({
741 client_id: clientId,
742 callback: handleGoogleResponse,
743 auto_select: false,
744 cancel_on_tap_outside: true
745 });
746
747 // Show Google login prompt
748 google.accounts.id.prompt();
749 });
750
751 // Facebook login
752 $wrapper.find('.king-addons-facebook-login').on('click', function(e) {
753 e.preventDefault();
754 const $button = $(this);
755 const appId = $button.data('app-id');
756
757 if (!appId) {
758 showSocialLoginError('Facebook App ID not configured. Please check widget settings.');
759 return;
760 }
761
762 // Check if Facebook SDK is loaded
763 if (typeof FB === 'undefined') {
764 showSocialLoginError('Facebook SDK not loaded. Please check your internet connection.');
765 return;
766 }
767
768 // Facebook login
769 FB.login(function(response) {
770 if (response.authResponse) {
771 handleFacebookResponse(response.authResponse);
772 } else {
773 showSocialLoginError('Facebook login was cancelled or failed.');
774 }
775 }, {scope: 'email,public_profile'});
776 });
777
778 function handleGoogleResponse(response) {
779 const $wrapper = $('.king-addons-login-register-form-wrapper');
780 const widgetId = $wrapper.data('widget-id');
781 const $messageContainer = $wrapper.find('.king-addons-form-message');
782
783 // Show loading
784 showMessage($messageContainer, 'Authenticating with Google...', 'info');
785
786 $.ajax({
787 url: king_addons_login_register_vars.ajax_url,
788 type: 'POST',
789 data: {
790 action: 'king_addons_google_login',
791 nonce: king_addons_login_register_vars.social_login_nonce,
792 google_token: response.credential,
793 widget_id: widgetId,
794 google_client_id: $wrapper.data('google-client-id')
795 },
796 success: function(ajaxResponse) {
797 if (ajaxResponse.success) {
798 showMessage($messageContainer, ajaxResponse.data.message, 'success');
799 if (ajaxResponse.data.redirect) {
800 setTimeout(() => {
801 window.location.href = ajaxResponse.data.redirect;
802 }, 1500);
803 } else {
804 setTimeout(() => {
805 location.reload();
806 }, 1500);
807 }
808 } else {
809 showMessage($messageContainer, ajaxResponse.data.message, 'error');
810 }
811 },
812 error: function() {
813 showMessage($messageContainer, 'Google login failed. Please try again.', 'error');
814 }
815 });
816 }
817
818 function handleFacebookResponse(authResponse) {
819 const $wrapper = $('.king-addons-login-register-form-wrapper');
820 const widgetId = $wrapper.data('widget-id');
821 const $messageContainer = $wrapper.find('.king-addons-form-message');
822
823 // Show loading
824 showMessage($messageContainer, 'Authenticating with Facebook...', 'info');
825
826 $.ajax({
827 url: king_addons_login_register_vars.ajax_url,
828 type: 'POST',
829 data: {
830 action: 'king_addons_facebook_login',
831 nonce: king_addons_login_register_vars.social_login_nonce,
832 facebook_token: authResponse.accessToken,
833 widget_id: widgetId,
834 facebook_app_id: $wrapper.data('facebook-app-id'),
835 facebook_app_secret: $wrapper.data('facebook-app-secret')
836 },
837 success: function(ajaxResponse) {
838 if (ajaxResponse.success) {
839 showMessage($messageContainer, ajaxResponse.data.message, 'success');
840 if (ajaxResponse.data.redirect) {
841 setTimeout(() => {
842 window.location.href = ajaxResponse.data.redirect;
843 }, 1500);
844 } else {
845 setTimeout(() => {
846 location.reload();
847 }, 1500);
848 }
849 } else {
850 showMessage($messageContainer, ajaxResponse.data.message, 'error');
851 }
852 },
853 error: function() {
854 showMessage($messageContainer, 'Facebook login failed. Please try again.', 'error');
855 }
856 });
857 }
858
859 function showSocialLoginError(message) {
860 const $wrapper = $('.king-addons-login-register-form-wrapper');
861 const $messageContainer = $wrapper.find('.king-addons-form-message');
862 showMessage($messageContainer, message, 'error');
863 }
864 }
865
866 function initRecaptcha($wrapper) {
867 // Initialize reCAPTCHA v2
868 $wrapper.find('.king-addons-recaptcha-v2').each(function() {
869 const $recaptcha = $(this);
870 const sitekey = $recaptcha.data('sitekey');
871 const theme = $recaptcha.data('theme') || 'light';
872 const size = $recaptcha.data('size') || 'normal';
873
874 if (typeof grecaptcha !== 'undefined' && sitekey) {
875 grecaptcha.ready(function() {
876 grecaptcha.render($recaptcha[0], {
877 'sitekey': sitekey,
878 'theme': theme,
879 'size': size
880 });
881 });
882 }
883 });
884
885 // For reCAPTCHA v3, we'll handle it in form submission
886 $wrapper.find('.king-addons-recaptcha-v3').each(function() {
887 const $recaptcha = $(this);
888 const sitekey = $recaptcha.data('sitekey');
889 const action = $recaptcha.data('action');
890
891 if (typeof grecaptcha !== 'undefined' && sitekey) {
892 // v3 tokens are generated on form submission
893 $recaptcha.closest('form').on('submit', function(e) {
894 const $form = $(this);
895
896 if ($recaptcha.val()) {
897 // Token already exists, proceed
898 return;
899 }
900
901 e.preventDefault();
902
903 grecaptcha.ready(function() {
904 grecaptcha.execute(sitekey, {action: action}).then(function(token) {
905 $recaptcha.val(token);
906 $form.trigger('submit');
907 });
908 });
909 });
910 }
911 });
912 }
913
914 // Expose functions globally for potential external use
915 window.KingAddonsLoginRegister = {
916 initForm: initLoginRegisterForm,
917 showMessage: showMessage,
918 clearMessages: clearMessages
919 };
920
921 })(jQuery);