PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.2.7
Yatra – Travel Booking & Tour Operator Software v3.0.2.7
3.0.16 3.0.15 3.0.14 3.0.14.1 3.0.14.2 3.0.12 3.0.13 3.0.11 3.0.10 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.5.1 3.0.4 3.0.3 3.0.2.9 3.0.2.7 3.0.2.8 3.0.2.6 trunk 1.0.0 2.0.0 2.0.1 All 84 releases
yatra / assets / js / login-shortcode.js

login-shortcode.js in Yatra – Travel Booking & Tour Operator Software 3.0.2.7, at assets/js/login-shortcode.js

415 lines 13.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Login Shortcode JavaScript
3 *
4 * Production-optimized login form interactions and functionality
5 *
6 * @package Yatra
7 * @version 1.0.0
8 */
9
10 (function($) {
11 'use strict';
12
13 // Performance: Cache DOM elements
14 let $document = $(document);
15 let $window = $(window);
16
17 // Performance: Debounce function for performance
18 function debounce(func, wait) {
19 let timeout;
20 return function executedFunction(...args) {
21 const later = () => {
22 clearTimeout(timeout);
23 func(...args);
24 };
25 clearTimeout(timeout);
26 timeout = setTimeout(later, wait);
27 };
28 }
29
30 // Performance: Throttle function for scroll events
31 function throttle(func, limit) {
32 let inThrottle;
33 return function() {
34 const args = arguments;
35 const context = this;
36 if (!inThrottle) {
37 func.apply(context, args);
38 inThrottle = true;
39 setTimeout(() => inThrottle = false, limit);
40 }
41 };
42 }
43
44 // Initialize when DOM is ready
45 $document.ready(function() {
46 // Performance: Check if login form exists before initializing
47 if ($('.yatra-login-form').length === 0) {
48 return;
49 }
50
51 // Initialize components
52 initPasswordToggles();
53 initAjaxLogin();
54 initAccessibility();
55 initPerformanceOptimizations();
56 });
57
58 /**
59 * Initialize password toggle functionality with performance optimizations
60 */
61 function initPasswordToggles() {
62 const passwordToggles = $('.yatra-password-toggle');
63
64 // Performance: Use event delegation for better performance
65 $document.on('click', '.yatra-password-toggle', function(e) {
66 e.preventDefault();
67
68 const $toggle = $(this);
69 const targetId = $toggle.data('target');
70 const $input = targetId ? $('#' + targetId) : $toggle.siblings('.yatra-form-input');
71
72 if (!$input.length) {
73 console.warn('Password input not found for toggle');
74 return;
75 }
76
77 const $eyeIcon = $toggle.find('.yatra-eye-icon');
78 const $eyeOffIcon = $toggle.find('.yatra-eye-off-icon');
79
80 try {
81 const isPassword = $input.attr('type') === 'password';
82
83 if (isPassword) {
84 $input.attr('type', 'text');
85 $eyeIcon.hide();
86 $eyeOffIcon.show();
87 $toggle.attr('aria-label', 'Hide password');
88 } else {
89 $input.attr('type', 'password');
90 $eyeIcon.show();
91 $eyeOffIcon.hide();
92 $toggle.attr('aria-label', 'Show password');
93 }
94 } catch (error) {
95 console.error('Error toggling password visibility:', error);
96 }
97 });
98 }
99
100 /**
101 * Enhanced form validation function
102 */
103 function validateLoginForm($username, $password) {
104 const username = $username.val().trim();
105 const password = $password.val().trim();
106
107 if (!username) {
108 return {
109 valid: false,
110 message: yatra_ajax?.strings?.validation_error || 'Please enter your email or username.'
111 };
112 }
113
114 if (!password) {
115 return {
116 valid: false,
117 message: yatra_ajax?.strings?.validation_error || 'Please enter your password.'
118 };
119 }
120
121 if (username.length > 60) {
122 return {
123 valid: false,
124 message: 'Username is too long.'
125 };
126 }
127
128 if (password.length > 72) {
129 return {
130 valid: false,
131 message: 'Password is too long.'
132 };
133 }
134
135 return { valid: true };
136 }
137
138 /**
139 * Initialize accessibility features
140 */
141 function initAccessibility() {
142 // Add ARIA labels and improve keyboard navigation
143 $document.on('keydown', '.yatra-form-input', function(e) {
144 if (e.key === 'Enter') {
145 const $form = $(this).closest('form');
146 if ($form.length) {
147 $form.trigger('submit');
148 }
149 }
150 });
151
152 // Focus management for error messages
153 $document.on('click', '.yatra-form-error', function() {
154 $(this).fadeOut(200, function() {
155 $(this).remove();
156 });
157 });
158 }
159
160 /**
161 * Initialize performance optimizations
162 */
163 function initPerformanceOptimizations() {
164 // Lazy load error styles
165 if (!$('#yatra-login-error-styles').length) {
166 $('<style id="yatra-login-error-styles">')
167 .text('.yatra-form-error { transition: opacity 0.2s ease; }')
168 .appendTo('head');
169 }
170
171 // Preload critical resources
172 if (window.performance && window.performance.getEntriesByType) {
173 // Monitor performance in development
174 if (yatra_ajax?.debug) {
175 setTimeout(() => {
176 const entries = performance.getEntriesByType('navigation');
177 if (entries.length > 0) {
178 console.log('Login form load time:', entries[0].loadEventEnd - entries[0].loadEventStart, 'ms');
179 }
180 }, 1000);
181 }
182 }
183 }
184
185 /**
186 * Initialize AJAX login with production optimizations
187 */
188 function initAjaxLogin() {
189 const $loginForm = $('.yatra-login-form');
190
191 // Only use AJAX if the form has data-ajax="true" attribute
192 if ($loginForm.data('ajax') === true) {
193 // Performance: Use event delegation for better performance
194 $document.on('submit', '.yatra-login-form[data-ajax="true"]', function(e) {
195 e.preventDefault();
196 e.stopPropagation();
197
198 const $form = $(this);
199 const $submitBtn = $form.find('button[type="submit"], input[type="submit"]');
200 const $username = $form.find('[name="log"], [name="username"], [name="email"]');
201 const $password = $form.find('[name="pwd"], [name="password"]');
202
203 // Prevent multiple submissions
204 if ($submitBtn.prop('disabled')) {
205 return false;
206 }
207
208 // Enhanced form validation
209 const validation = validateLoginForm($username, $password);
210 if (!validation.valid) {
211 showFormError($form, validation.message);
212 return false;
213 }
214
215 // Reset previous errors
216 $('.yatra-form-error').remove();
217
218 // Validate username
219 if (!$username.val().trim()) {
220 showFieldError($username, 'Please enter your email or username.');
221 isValid = false;
222 }
223
224 // Validate password
225 if (!$password.val().trim()) {
226 showFieldError($password, 'Please enter your password.');
227 isValid = false;
228 }
229
230 if (!isValid) {
231 return false;
232 }
233
234 // Show loading state immediately to prevent flicker
235 $submitBtn.prop('disabled', true);
236 const originalText = $submitBtn.text();
237 $submitBtn.html('<span class="yatra-spinner"></span> ' + (yatra_ajax?.strings?.loading || 'Loading...'));
238
239 // Prepare AJAX request data
240 const formData = {
241 action: 'yatra_ajax_login',
242 username: $username.val().trim(),
243 password: $password.val().trim(),
244 remember: $form.find('[name="rememberme"]').is(':checked') ? 'forever' : '',
245 security: $form.find('[name="yatra-login-nonce"]').val(),
246 ajax: true
247 };
248
249 // Perform AJAX request with timeout
250 const ajaxRequest = $.ajax({
251 url: yatra_ajax?.ajax_url || '/wp-admin/admin-ajax.php',
252 type: 'POST',
253 data: formData,
254 timeout: 15000, // 15 second timeout
255 dataType: 'json'
256 });
257
258 // Handle success
259 ajaxRequest.done(function(response) {
260 if (response.success) {
261 // Success: Redirect or show success message
262 if (response.data.redirect) {
263 window.location.href = response.data.redirect;
264 } else {
265 showFormSuccess($form, response.data.message || 'Login successful!');
266 setTimeout(() => {
267 window.location.reload();
268 }, 1500);
269 }
270 } else {
271 // Error: Show error message
272 showFormError($form, response.data.message || 'Login failed. Please try again.');
273 }
274 });
275
276 // Handle error
277 ajaxRequest.fail(function(xhr, status, error) {
278 let errorMessage = 'Network error. Please check your connection and try again.';
279
280 if (status === 'timeout') {
281 errorMessage = 'Request timed out. Please try again.';
282 } else if (xhr.responseJSON && xhr.responseJSON.data) {
283 errorMessage = xhr.responseJSON.data.message || errorMessage;
284 }
285
286 showFormError($form, errorMessage);
287 });
288
289 // Always restore button state
290 ajaxRequest.always(function() {
291 $submitBtn.prop('disabled', false);
292 $submitBtn.text(originalText);
293 });
294
295 return false;
296 });
297 }
298 }
299
300 /**
301 * Show field-specific error message
302 */
303 function showFieldError($field, message) {
304 // Remove existing field error
305 $field.siblings('.yatra-form-error').fadeOut(200, function() {
306 $(this).remove();
307 });
308
309 // Create and insert error message with fade-in to prevent flicker
310 const $error = $('<div class="yatra-form-error" style="display: none;">' + message + '</div>');
311 $error.css({
312 color: '#dc2626',
313 fontSize: '0.875rem',
314 marginTop: '4px',
315 fontWeight: '500',
316 opacity: 0,
317 transition: 'opacity 0.2s ease'
318 });
319
320 $field.after($error);
321
322 // Fade in error message
323 setTimeout(function() {
324 $error.css({
325 display: 'block',
326 opacity: 1
327 });
328 }, 10);
329
330 // Remove error on focus
331 $field.on('focus', function() {
332 $(this).removeClass('error');
333 $(this).siblings('.yatra-form-error').fadeOut(200, function() {
334 $(this).remove();
335 });
336 });
337 }
338
339 /**
340 * Show form error message
341 */
342 function showFormError($form, message) {
343 // Remove existing error with fade out
344 $form.find('.yatra-form-error').fadeOut(200, function() {
345 $(this).remove();
346 });
347
348 // Create and insert error message at the top of the form with fade-in
349 const $error = $('<div class="yatra-form-error" style="display: none;">' + message + '</div>');
350 $error.css({
351 color: '#dc2626',
352 backgroundColor: '#fef2f2',
353 border: '1px solid #fecaca',
354 borderRadius: '8px',
355 padding: '12px 16px',
356 marginBottom: '20px',
357 fontWeight: '500',
358 opacity: 0,
359 transition: 'opacity 0.2s ease'
360 });
361
362 $form.prepend($error);
363
364 // Fade in error message
365 setTimeout(function() {
366 $error.css({
367 display: 'block',
368 opacity: 1
369 });
370 }, 10);
371
372 // Scroll to error smoothly
373 setTimeout(function() {
374 $('html, body').animate({
375 scrollTop: $form.offset().top - 100
376 }, 300);
377 }, 50);
378 }
379
380 /**
381 * Show form success message
382 */
383 function showFormSuccess($form, message) {
384 // Remove existing messages
385 $form.find('.yatra-form-error, .yatra-form-success').fadeOut(200, function() {
386 $(this).remove();
387 });
388
389 // Create and insert success message
390 const $success = $('<div class="yatra-form-success" style="display: none;">' + message + '</div>');
391 $success.css({
392 color: '#059669',
393 backgroundColor: '#f0fdf4',
394 border: '1px solid #bbf7d0',
395 borderRadius: '8px',
396 padding: '12px 16px',
397 marginBottom: '20px',
398 fontWeight: '500',
399 opacity: 0,
400 transition: 'opacity 0.2s ease'
401 });
402
403 $form.prepend($success);
404
405 // Fade in success message
406 setTimeout(function() {
407 $success.css({
408 display: 'block',
409 opacity: 1
410 });
411 }, 10);
412 }
413
414 })(jQuery);
415