PageSourceSearch

https://bootsschuley.de/wp-content/plugins/sfwd-lms/themes/ld30/assets/js/learndash.js?ver=4.25.7

js bootsschuley.de collected 2026-10-08 23:43:42 UTC 55,164 bytes, 2,061 lines download raw bytes

1/* eslint-disable no-var */
2jQuery(function ($) {
3	var hash = window.location.hash;
4
5	learndashFocusModeSidebarAutoScroll();
6
7	initLoginModal();
8	if ('#login' == hash) {
9		openLoginModal();
10	}
11
12	if ('undefined' !== typeof ldGetUrlVars().login) {
13		var loginStatus = ldGetUrlVars().login;
14
15		if ('failed' == loginStatus) {
16			openLoginModal();
17		}
18	}
19
20	if ('undefined' !== typeof ldGetUrlVars()['ld-topic-page']) {
21		var topicPage = ldGetUrlVars()['ld-topic-page'];
22		var topicIds = topicPage.split('-');
23		var topicId = Object.values(topicIds)[0];
24
25		var lesson = $('#ld-expand-' + topicId);
26		var button = $(lesson).find('.ld-expand-button');
27
28		ldToggleExpandableElement(button, true);
29
30		$('html, body').animate(
31			{
32				scrollTop: $(lesson).offset().top,
33			},
34			500
35		);
36	}
37
38	// a[href="#login"] is for backwards compatibility with potentially outdated templates.
39	$('body').on(
40		'click',
41		'a[href="#login"], button[data-ld-login-modal-trigger]',
42		function (e) {
43			e.preventDefault();
44			openLoginModal();
45		}
46	);
47
48	// By default, the element is not interactable with keyboard. We make the keypress event for space and enter key to close the login modal for accessibility.
49	$('body').on('keypress', '.ld-modal-closer', function (e) {
50		if (13 === e.keyCode || 32 === e.keyCode) {
51			e.preventDefault();
52			closeLoginModal();
53		}
54	});
55
56	$('body').on('click', '.ld-modal-closer', function (e) {
57		e.preventDefault();
58		closeLoginModal();
59	});
60
61	$('body').on('click', '#ld-comments-post-button', function (e) {
62		$(this).addClass('ld-open');
63		$('#ld-comments-form').removeClass('ld-collapsed');
64		$('textarea#comment').focus();
65	});
66
67	// Close modal if clicking away
68	/*
69	$('body').on('click', function(e) {
70		if ($('.learndash-wrapper').hasClass('ld-modal-open')) {
71			if ( ! $(e.target).parents('.ld-modal').length && (! $(e.target).is('a'))) {
72				closeLoginModal();
73			}
74		}
75	});
76	*/
77
78	// Close modal on Esc key
79	$(document).on('keyup', function (e) {
80		if (27 === e.keyCode) {
81			closeLoginModal();
82		}
83	});
84
85	$('.learndash-wrapper').on(
86		'click',
87		'a.user_statistic',
88		learndash_ld30_show_user_statistic
89	);
90
91	focusMobileCheck();
92	focusMobileResizeCheck();
93
94	disableFocusTrap();
95
96	$('body').on('click', '.ld-focus-sidebar-trigger', function (e) {
97		if ($('.ld-focus').hasClass('ld-focus-sidebar-collapsed')) {
98			openFocusSidebar();
99		} else {
100			closeFocusSidebar();
101		}
102	});
103
104	$('body').on('click', '.ld-trigger-mobile-nav', function (e) {
105		e.preventDefault();
106		if ($('.ld-focus').hasClass('ld-focus-sidebar-collapsed')) {
107			openFocusSidebar();
108		} else {
109			closeFocusSidebar();
110		}
111	});
112
113	$('.ld-js-register-account').on('click', function (e) {
114		e.preventDefault();
115
116		$('.ld-login-modal-register .ld-modal-text').slideUp('slow');
117		$('.ld-login-modal-register .ld-alert').slideUp('slow');
118		$(this).slideUp('slow', function () {
119			$('#ld-user-register').slideDown('slow');
120		});
121	});
122
123	// If registration login link filter not defined, allow to replace the register form with login form
124	ldRegistrationLinkInit();
125	ldRegistrationLinkInitModern();
126
127	var windowWidth = $(window).width();
128
129	// Ensure that tooltips are positioned properly after screen size changes.
130	$(window).on('resize orientationchange', function () {
131		const resizeTimer = setTimeout(() => {
132			const newWidth = $(window).width();
133
134			if (newWidth === windowWidth) {
135				return;
136			}
137
138			windowWidth = newWidth;
139
140			// Wait one more animation frame after debounce to let layout settle.
141			window.requestAnimationFrame(() => {
142				initTooltips();
143				focusMobileResizeCheck();
144				clearTimeout(resizeTimer);
145			});
146		}, 150);
147	});
148
149	if ($('.ld-course-status-content').length) {
150		var tallest = 0;
151
152		$('.ld-course-status-content').each(function () {
153			if ($(this).height() > tallest) {
154				tallest = $(this).height();
155			}
156		});
157
158		$('.ld-course-status-content').height(tallest);
159	}
160
161	function focusMobileCheck() {
162		if (1024 > $(window).width()) {
163			closeFocusSidebarPageLoad();
164		}
165	}
166
167	/**
168	 * Toggles the focus sidebar based on the window width.
169	 *
170	 * @since 3.2.0
171	 * @since 4.21.5 Now also toggles aria-modal attribute.
172	 *
173	 * @return {void}
174	 */
175	function focusMobileResizeCheck() {
176		if ($(window).width() < 1024) {
177			$('#ld-focus-sidebar').attr('aria-modal', 'true');
178
179			if (!$('.ld-focus').hasClass('ld-focus-sidebar-collapsed')) {
180				closeFocusSidebar();
181			}
182		} else {
183			$('#ld-focus-sidebar').attr('aria-modal', 'false');
184
185			if ($('.ld-focus').hasClass('ld-focus-sidebar-filtered')) {
186				closeFocusSidebar();
187			} else if (
188				!$('.ld-focus').hasClass('ld-focus-sidebar-filtered') &&
189				$('.ld-focus').hasClass('ld-focus-sidebar-collapsed')
190			) {
191				openFocusSidebar();
192			}
193		}
194	}
195
196	function focusMobileHandleOrientationChange(e) {
197		if (e.matches) {
198			if (
199				1024 <= $(window).width() &&
200				!$('.ld-focus').hasClass('ld-focus-sidebar-filtered') &&
201				$('.ld-focus').hasClass('ld-focus-sidebar-collapsed')
202			) {
203				openFocusSidebar();
204			}
205		}
206	}
207	window
208		.matchMedia('(orientation: landscape)')
209		.addListener(focusMobileHandleOrientationChange);
210
211	function closeFocusSidebarPageLoad() {
212		$('.ld-focus').addClass('ld-focus-sidebar-collapsed');
213		$('.ld-focus').removeClass('ld-focus-initial-transition');
214		$('.ld-mobile-nav').removeClass('expanded');
215		$('[aria-controls="ld-focus-sidebar"]').attr('aria-expanded', 'false');
216		positionTooltips();
217
218		const sidebar = document.querySelector('.ld-focus-sidebar');
219
220		if (sidebar) {
221			sidebar.dispatchEvent(new CustomEvent('ld-focus-sidebar-closed'));
222		}
223		dispatchSidebarEvent(false);
224	}
225
226	/**
227	 * Dispatches a custom event on to notify other scripts that the focus sidebar has been opened or closed.
228	 *
229	 * @since 4.23.2
230	 *
231	 * @param {boolean} isOpen Whether the sidebar is open.
232	 *
233	 * @return {void}
234	 */
235	function dispatchSidebarEvent(isOpen) {
236		const sidebar = document.querySelector('.ld-focus-sidebar');
237
238		if (!sidebar) {
239			return;
240		}
241
242		let eventName = 'ld-focus-sidebar-closed';
243
244		if (isOpen) {
245			eventName = 'ld-focus-sidebar-opened';
246		}
247
248		sidebar.dispatchEvent(new CustomEvent(eventName));
249	}
250
251	/**
252	 * Closes the focus sidebar.
253	 *
254	 * @since 3.0.0
255	 *
256	 * @return {void}
257	 */
258	function closeFocusSidebar() {
259		// Hide the wrapper to avoid issues with focus trap.
260		$('.ld-focus-sidebar-wrapper').hide();
261
262		$('.ld-focus').addClass('ld-focus-sidebar-collapsed');
263		$('.ld-mobile-nav').removeClass('expanded');
264
265		if (
266			$('.ld-focus-sidebar-trigger .ld-icon').hasClass(
267				'ld-icon-arrow-left'
268			)
269		) {
270			$('.ld-focus-sidebar-trigger .ld-icon').removeClass(
271				'ld-icon-arrow-left'
272			);
273			$('.ld-focus-sidebar-trigger .ld-icon').addClass(
274				'ld-icon-arrow-right'
275			);
276		} else if (
277			$('.ld-focus-sidebar-trigger .ld-icon').hasClass(
278				'ld-icon-arrow-right'
279			)
280		) {
281			$('.ld-focus-sidebar-trigger .ld-icon').removeClass(
282				'ld-icon-arrow-right'
283			);
284			$('.ld-focus-sidebar-trigger .ld-icon').addClass(
285				'ld-icon-arrow-left'
286			);
287		}
288
289		$('[aria-controls="ld-focus-sidebar"]').attr('aria-expanded', 'false');
290
291		disableFocusTrap();
292
293		// If the mobile trigger is visible, move focus to it.
294		const mobileTrigger = $('.ld-trigger-mobile-nav');
295
296		if (mobileTrigger.is(':visible')) {
297			mobileTrigger.focus();
298		}
299
300		positionTooltips();
301
302		const sidebar = document.querySelector('.ld-focus-sidebar');
303
304		if (sidebar) {
305			sidebar.dispatchEvent(new CustomEvent('ld-focus-sidebar-closed'));
306		}
307		dispatchSidebarEvent(false);
308	}
309	/**
310	 * Handles tab key press in the focus sidebar to trap focus within the sidebar.
311	 * When the last focusable element is reached, focus is redirected to the first element.
312	 *
313	 * @since 4.21.3
314	 * @param {Event} e The keyboard event object.
315	 */
316	function handleTabTrap(e) {
317		if (e.key === 'Tab') {
318			e.preventDefault();
319			$('#ld-focus-sidebar-toggle').focus();
320		}
321	}
322
323	/**
324	 * Enables focus trap for the sidebar to improve accessibility.
325	 * Makes sidebar elements tabbable, focuses the sidebar toggle button,
326	 * and adds event listener to trap focus within the sidebar.
327	 *
328	 * @since 4.21.3
329	 */
330	function enableFocusTrap() {
331		// Focus sidebar for accessibility when opened, allowing keyboard navigation easier.
332		$('#ld-focus-sidebar-toggle').focus();
333
334		// Make the course heading tabbable.
335		$('#ld-focus-mode-course-heading').attr('tabindex', '0');
336
337		// Get list of focusable elements, and when last one is focused, focus on the first element to trap focus.
338		const focusableElements = $('.ld-lesson-items a');
339		const lastFocusableElement =
340			focusableElements[focusableElements.length - 1];
341
342		lastFocusableElement.addEventListener('keydown', handleTabTrap);
343	}
344
345	/**
346	 * Disables focus trap for the sidebar when it's closed.
347	 * Makes sidebar elements non-tabbable and removes the event listener.
348	 *
349	 * @since 4.21.3
350	 */
351	function disableFocusTrap() {
352		// Make the course heading non-tabbable when the sidebar is closed.
353		$('#ld-focus-mode-course-heading').attr('tabindex', '-1');
354
355		if ($('.ld-focus-sidebar-trigger').attr('aria-expanded') === 'true') {
356			return;
357		}
358
359		// Remove focus trap when sidebar is closed.
360		const focusableElements = $('.ld-lesson-items a');
361		const lastFocusableElement =
362			focusableElements[focusableElements.length - 1];
363
364		if (lastFocusableElement) {
365			lastFocusableElement.removeEventListener('keydown', handleTabTrap);
366		}
367	}
368
369	/**
370	 * Opens the focus sidebar and enables focus trap for accessibility.
371	 * Handles mobile checks, class toggling, and icon changes.
372	 *
373	 * @since 3.0.0
374	 */
375	function openFocusSidebar() {
376		focusMobileCheck();
377
378		// Show the wrapper
379		$('.ld-focus-sidebar-wrapper').show();
380
381		// Flip classes to open the focus sidebar.
382		$('.ld-focus').removeClass('ld-focus-sidebar-collapsed');
383		$('.ld-mobile-nav').addClass('expanded');
384
385		// We need to wait for the sidebar to be opened before we can enable the focus trap.
386		enableFocusTrap();
387
388		if (
389			$('.ld-focus-sidebar-trigger .ld-icon').hasClass(
390				'ld-icon-arrow-left'
391			)
392		) {
393			$('.ld-focus-sidebar-trigger .ld-icon').removeClass(
394				'ld-icon-arrow-left'
395			);
396			$('.ld-focus-sidebar-trigger .ld-icon').addClass(
397				'ld-icon-arrow-right'
398			);
399		} else if (
400			$('.ld-focus-sidebar-trigger .ld-icon').hasClass(
401				'ld-icon-arrow-right'
402			)
403		) {
404			$('.ld-focus-sidebar-trigger .ld-icon').removeClass(
405				'ld-icon-arrow-right'
406			);
407			$('.ld-focus-sidebar-trigger .ld-icon').addClass(
408				'ld-icon-arrow-left'
409			);
410		}
411
412		$('[aria-controls="ld-focus-sidebar"]').attr('aria-expanded', 'true');
413
414		const sidebar = document.querySelector('.ld-focus-sidebar');
415
416		if (sidebar) {
417			sidebar.dispatchEvent(new CustomEvent('ld-focus-sidebar-opened'));
418		}
419		dispatchSidebarEvent(true);
420
421		positionTooltips();
422	}
423
424	$('.ld-file-input').each(function () {
425		var $input = $(this),
426			$label = $input.next('label'),
427			labelVal = $label.html();
428
429		$input.on('change', function (e) {
430			var fileName = '';
431			if (this.files && 1 < this.files.length) {
432				fileName = (
433					this.getAttribute('data-multiple-caption') || ''
434				).replace('{count}', this.files.length);
435			} else if (e.target.value) {
436				fileName = e.target.value.split('\\').pop();
437			}
438			if (fileName) {
439				$label.find('span').html(fileName);
440				$label.addClass('ld-file-selected');
441				$('#uploadfile_btn').attr('disabled', false);
442			} else {
443				$label.html(labelVal);
444				$label.removeClass('ld-file-selected');
445				$('#uploadfile_btn').attr('disabled', true);
446			}
447		});
448
449		$('#uploadfile_form').on('submit', function () {
450			$label.removeClass('ld-file-selected');
451			$('#uploadfile_btn').attr('disabled', true);
452		});
453
454		// Firefox bug fix
455		$input
456			.on('focus', function () {
457				$input.addClass('has-focus');
458			})
459			.on('blur', function () {
460				$input.removeClass('has-focus');
461			});
462	});
463
464	$('body').on(
465		'click',
466		'.ld-expand-button, [data-ld-expand-button]',
467		function (e) {
468			e.preventDefault();
469
470			ldToggleExpandableElement($(this));
471
472			positionTooltips();
473		}
474	);
475
476	/**
477	 * Initialize expanded items to be expanded and collapsed elements to have [hidden="hidden"].
478	 * Expanded elements allow "Expand All" items to expand all their children by default.
479	 * Collapsed elements need [hidden="hidden"] to be set via JavaScript, so we cannot pre-load this on the server.
480	 *
481	 * @see https://designsystem.digital.gov/components/accordion/
482	 *
483	 * @since 4.21.0
484	 */
485	function initializeExpandableElements() {
486		$('.ld-expand-button, [data-ld-expand-button], .ld-search-prompt').each(
487			function (index, buttonElement) {
488				ldToggleExpandableElement(
489					$(buttonElement),
490					$(buttonElement).attr('aria-expanded') === 'true'
491				);
492			}
493		);
494	}
495
496	/**
497	 * Focuses on the first alert on the page with a role "alert".
498	 * This is required for accessibility.
499	 *
500	 * @since 4.21.3
501	 * @since 4.21.5 Switched to a focus-based approach for better compatibility with different screen readers.
502	 *
503	 * @return {void}
504	 */
505	function initializeAlerts() {
506		/**
507		 * We need to give it a tabindex of -1 to allow it to be programmatically focused so it will be
508		 * read out by screen readers. Unfortunately, we cannot remove it after focusing.
509		 * If we do, it won't be read at all.
510		 *
511		 * By using -1 rather than 0, it won't show up in the tab order when navigating by keyboard.
512		 *
513		 * We can only target the first alert because we have no way to know when the screen reader has finished
514		 * reading each alert to focus on the next one.
515		 *
516		 * The setTimeout() is used to force this to happen at the end of the event queue and improve compatibility.
517		 */
518		setTimeout(function () {
519			$('.ld-alert[role="alert"]:visible')
520				.first()
521				.attr('tabindex', '-1')
522				.focus();
523		}, 500);
524	}
525
526	$(document).on(
527		'ldAccordionPaginationComplete',
528		'.ld-accordion',
529		initializeExpandableElements
530	);
531
532	// On page load.
533	initializeExpandableElements();
534	initializeAlerts();
535
536	$('body').on('click', '.ld-search-prompt', function (e) {
537		e.preventDefault();
538
539		$('#course_name_field').focus();
540
541		ldToggleExpandableElement($(this));
542
543		const $controls = $('#' + $(this).attr('aria-controls'));
544
545		if ($controls.find('.ld-closer').length > 0) {
546			$controls
547				.find('.ld-closer')
548				.attr('aria-expanded', $(this).attr('aria-expanded'));
549		}
550	});
551
552	/**
553	 * Handles expanding and collapsing elements on button click.
554	 *
555	 * @since 4.20.2
556	 *
557	 * @param {jQuery}  $button jQuery Element for the button that was clicked.
558	 * @param {boolean} expand  Whether to expand the associated element or not. Defaults to a value based on the button's aria-expanded attribute.
559	 *
560	 * @return {void}
561	 */
562	function ldToggleExpandableElement($button, expand) {
563		if ('undefined' === typeof expand) {
564			// Checking !== true to handle undefined and false.
565			expand = $button.attr('aria-expanded') !== 'true';
566		}
567
568		const containerID = $button.attr('aria-controls');
569
570		if (
571			typeof containerID !== 'undefined' &&
572			containerID.indexOf(' ') > -1 &&
573			!$button.data('ld-expanding-all')
574		) {
575			// We're toggling multiple elements at once via an "Expand All"-type button.
576
577			containerID.split(' ').forEach(function (id) {
578				const $element = $('[aria-controls="' + id + '"]');
579
580				ldToggleExpandableElement($element, expand);
581			});
582
583			// Temporarily set the "ld-expanding-all" data to allow us to toggle the state of this specific button.
584
585			$button.data('ld-expanding-all', true);
586
587			ldToggleExpandableElement($button, expand);
588
589			$button.data('ld-expanding-all', false);
590		} else {
591			// Toggle a specific button.
592
593			// Account for edge cases where an Expand All button controls only one expandable area.
594			$button = $('[aria-controls="' + containerID + '"]');
595
596			const $container = $('#' + containerID);
597
598			if (expand && $container.length > 0) {
599				// Unhide right away.
600				$container.attr('hidden', false);
601			}
602
603			$button.each(function (index, element) {
604				/**
605				 * Pull the initial text from a cached data attribute,
606				 * that way as the button text changes we always know what it was initially.
607				 */
608				const dataInitialText =
609					$(element).data('ld-initial-text') ||
610					$(element)
611						.find('.ld-text, [data-ld-expand-button-text-element]')
612						.html();
613
614				$(element).data('ld-initial-text', dataInitialText);
615
616				const dataExpandText =
617					$(element).data('ld-expand-text') || dataInitialText;
618				const dataCollapseText =
619					$(element).data('ld-collapse-text') || dataInitialText;
620
621				$(element)
622					.attr('aria-expanded', expand)
623					.toggleClass('ld-expanded', expand);
624
625				if (expand && dataCollapseText) {
626					$(element)
627						.find('.ld-text, [data-ld-expand-button-text-element]')
628						.html(dataCollapseText);
629				} else if (!expand && dataExpandText) {
630					$(element)
631						.find('.ld-text, [data-ld-expand-button-text-element]')
632						.html(dataExpandText);
633				}
634			});
635
636			if ($container.length <= 0) {
637				/**
638				 * Expand All buttons with more than one controlled element won't have a valid Container,
639				 * so we shouldn't proceed.
640				 */
641				return;
642			}
643
644			let totalHeight = 0;
645			$container.find('> *').each(function () {
646				totalHeight += $(this).outerHeight();
647			});
648
649			// Writing to the attribute to make debugging easier.
650			$container.attr('data-height', totalHeight + 50);
651
652			$container.css({
653				'max-height': expand ? $container.data('height') : 0,
654			});
655
656			if (!expand) {
657				// If we're collapsing, we should remove this class immediately.
658				$container.toggleClass('ld-expanded', expand);
659
660				const waitForCollapsed = setInterval(function () {
661					if ($container.outerHeight() === 0) {
662						clearInterval(waitForCollapsed);
663						$container.attr('hidden', true);
664					}
665				});
666			} else {
667				// If we're expanding, we only want to add the .ld-expanded class once fully expanded.
668				const waitForExpanded = setInterval(function () {
669					if ($container.outerHeight() === totalHeight) {
670						clearInterval(waitForExpanded);
671						$container.toggleClass('ld-expanded', expand);
672					}
673				});
674			}
675		}
676
677		positionTooltips();
678	}
679
680	/**
681	 * Initialize registration link in the classic registration page.
682	 *
683	 * @since 4.16.0
684	 *
685	 * @return {void}
686	 */
687	function ldRegistrationLinkInit() {
688		const $loginLink = $('.registration-login-link');
689
690		if ($loginLink.length === 0) {
691			return;
692		}
693
694		if ('' !== $loginLink.attr('href')) {
695			return;
696		}
697
698		$loginLink.on('click', function (e) {
699			e.preventDefault();
700			$('#learndash_registerform, .registration-login').hide();
701			$(
702				'.registration-login-form, .show-register-form, .show-password-reset-link'
703			).show();
704		});
705
706		$('.show-register-form').on('click', function (e) {
707			e.preventDefault();
708			$(
709				'.registration-login-form, .show-register-form, .show-password-reset-link'
710			).hide();
711			$('#learndash_registerform, .registration-login').show();
712		});
713	}
714
715	/**
716	 * Initialize registration link in the modern registration page.
717	 *
718	 * @since 4.16.0
719	 *
720	 * @return {void}
721	 */
722	function ldRegistrationLinkInitModern() {
723		const $loginLink = $('.ld-registration__login-link');
724
725		if ($loginLink.length === 0) {
726			return;
727		}
728
729		if ('' !== $loginLink.attr('href')) {
730			return;
731		}
732
733		$(document).on('click', '.ld-registration__login-link', function (e) {
734			e.preventDefault();
735			let $wrapper = $(this).closest('.ld-registration__wrapper');
736			$wrapper.addClass('ld-registration__wrapper--login');
737			$wrapper.removeClass('ld-registration__wrapper--register');
738		});
739
740		$(document).on(
741			'click',
742			'.ld-registration__register-link',
743			function (e) {
744				e.preventDefault();
745				let $wrapper = $(this).closest('.ld-registration__wrapper');
746				$wrapper.removeClass('ld-registration__wrapper--login');
747				$wrapper.addClass('ld-registration__wrapper--register');
748			}
749		);
750	}
751
752	$('body').on('click', '.ld-closer', function (e) {
753		ldToggleExpandableElement($('.ld-search-prompt'), false);
754		$(this).attr('aria-expanded', false);
755	});
756
757	$('body').on('touch click', '.ld-tabs-navigation .ld-tab', function () {
758		const $tabContent = $('#' + $(this).attr('aria-controls'));
759		if (!$tabContent.length) {
760			return;
761		}
762
763		// Set other Tabs as inactive.
764		$('.ld-tabs-navigation .ld-tab.ld-active')
765			.removeClass('ld-active')
766			.attr('aria-selected', 'false')
767			.attr('tabindex', '-1');
768
769		// Set current Tab as active.
770		$(this)
771			.addClass('ld-active')
772			.attr('aria-selected', 'true')
773			.removeAttr('tabindex');
774
775		// Make other Tab Content panels invisible.
776		$('.ld-tabs-content .ld-tab-content.ld-visible').removeClass(
777			'ld-visible'
778		);
779
780		$tabContent.addClass('ld-visible');
781
782		positionTooltips();
783	});
784
785	$('body').on('keydown', '.ld-tabs-navigation .ld-tab', function (event) {
786		// If the key is not a Left/Right arrow key, Home, or End, do nothing.
787		if (
788			['ArrowLeft', 'ArrowRight', 'Home', 'End'].indexOf(event.key) === -1
789		) {
790			return;
791		}
792
793		const target = event.currentTarget;
794		const $firstTab = $(target)
795			.closest('[role="tablist"]')
796			.find('[role="tab"]')
797			.first();
798		const $lastTab = $(target)
799			.closest('[role="tablist"]')
800			.find('[role="tab"]')
801			.last();
802
803		event.stopPropagation();
804		event.preventDefault();
805
806		switch (event.key) {
807			case 'ArrowLeft':
808				if (target === $firstTab[0]) {
809					$lastTab.focus();
810				} else {
811					$(this).prev().focus();
812				}
813				break;
814			case 'ArrowRight':
815				if (target === $lastTab[0]) {
816					$firstTab.focus();
817				} else {
818					$(target).next().focus();
819				}
820				break;
821			case 'Home':
822				$firstTab.focus();
823				break;
824			case 'End':
825				$lastTab.focus();
826				break;
827			default:
828				break;
829		}
830	});
831
832	/**
833	 * Initialize tooltips.
834	 * - If JS isn't enabled, the tooltips will be visible at all times.
835	 * - This adds the `ld-tooltip--initialized` class to all tooltips to signify that JS is enabled.
836	 * - The `ld-tooltip--hidden` class is removed when the mouse is over a tooltip, the tooltip is focused,
837	 * or the tooltip is focused-within.
838	 * - The `ld-tooltip--hidden` class is added if a tooltip is visible and the Escape key is pressed.
839	 *
840	 * @since 4.21.3
841	 *
842	 * @return {void}
843	 */
844	function initTooltips() {
845		$('.ld-tooltip').each(function () {
846			const $tooltip = $(this).find('[role="tooltip"]');
847
848			if (!$tooltip.length || typeof $tooltip[0] === 'undefined') {
849				return;
850			}
851
852			if (!$(this).hasClass('ld-tooltip--initialized')) {
853				$(this)
854					.addClass('ld-tooltip--initialized')
855					.addClass('ld-tooltip--hidden');
856			}
857
858			/**
859			 * We need to temporarily remove the `ld-tooltip--hidden` class
860			 * as hidden tooltips are hidden off to the left edge of the screen.
861			 *
862			 * We need to know where it would normally be positioned when visible
863			 * to know if we need to move it to the right.
864			 */
865			const isHidden = $(this).hasClass('ld-tooltip--hidden');
866
867			$(this).removeClass('ld-tooltip--hidden');
868			$(this).removeClass('ld-tooltip--position-right');
869
870			const tooltipRect = $tooltip[0].getBoundingClientRect();
871
872			let containerWidth = windowWidth;
873
874			/**
875			 * If the tooltip is within the focus sidebar, use the sidebar width.
876			 *
877			 * We have to do this because when an element is vertically scrollable, a browser will simply not
878			 * allow you to have items spill out the left or right sides even when the appropriate CSS for
879			 * overflow-x is set to visible as it will be forced to auto implicitly.
880			 *
881			 * See https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-x#syntax
882			 */
883			if ($(this).closest('.ld-focus-sidebar').length) {
884				containerWidth = $(this).closest('.ld-focus-sidebar').width();
885			}
886
887			/**
888			 * If the tooltip would overflow the right edge of the window,
889			 * add the `ld-tooltip--position-right` class.
890			 */
891			$(this).toggleClass(
892				'ld-tooltip--position-right',
893				tooltipRect.right > containerWidth
894			);
895
896			// Add the .ld-tooltip--hidden class back if it was hidden.
897			$(this).toggleClass('ld-tooltip--hidden', isHidden);
898		});
899
900		$(document).on('keydown', function (event) {
901			/**
902			 * We need to check if the Escape key is pressed and if any tooltips
903			 * are currently visible before dismissing them.
904			 */
905			if (
906				event.key === 'Escape' &&
907				($('.ld-tooltip:hover').length ||
908					$('.ld-tooltip:focus').length ||
909					$('.ld-tooltip:focus-within').length)
910			) {
911				$(
912					'.ld-tooltip:hover, .ld-tooltip:focus, .ld-tooltip:focus-within'
913				).addClass('ld-tooltip--hidden');
914
915				// Remove focus to prevent automatically scrolling the page.
916				$('.ld-tooltip:focus, .ld-tooltip :focus').blur();
917			}
918		});
919
920		/**
921		 * For the next two event listeners:
922		 *
923		 * - mouseenter/mouseleave are used for hover on desktop.
924		 *
925		 * - focusin/focusout are used for keyboard focus on desktop.
926		 * 	- These are used instead of focus/blur because the focused element is likely _within_ the tooltip container.
927		 * 	- If the focused element is the tooltip container, these event names still work.
928		 *
929		 * - touchstart is used for touch devices.
930		 */
931
932		$(document).on(
933			'mouseenter focusin touchstart',
934			'.ld-tooltip--hidden',
935			function () {
936				// Show the tooltip.
937				$(this).removeClass('ld-tooltip--hidden');
938			}
939		);
940
941		$(document).on(
942			'mouseleave focusout touchstart',
943			'.ld-tooltip:not(.ld-tooltip--hidden)',
944			function () {
945				// Hide the tooltip when the mouse when the user moves away from the tooltip.
946				$(this).addClass('ld-tooltip--hidden');
947			}
948		);
949	}
950
951	/**
952	 * In order to account for container breakpoints modifying the layout,
953	 * we need to initialize tooltips twice on page load.
954	 *
955	 * TODO: Find a better way to do this.
956	 */
957	initTooltips();
958	initTooltips();
959
960	var $tooltips = $('*[data-ld-tooltip]');
961
962	initLegacyTooltips();
963
964	/**
965	 * Initialize legacy LD30 Classic tooltips.
966	 * Replaced with a new style of tooltips in 4.21.3 for accessibility reasons.
967	 * Kept for backwards compatibility.
968	 *
969	 * @since 3.0.0
970	 * @since 4.21.3 Renamed from initTooltips to initLegacyTooltips.
971	 *
972	 * @return {void}
973	 */
974	function initLegacyTooltips() {
975		// Clear out old tooltips
976
977		if ($('#learndash-tooltips').length) {
978			$('#learndash-tooltips').remove();
979			$tooltips = $('*[data-ld-tooltip]');
980		}
981
982		if ($tooltips.length) {
983			$('body').prepend('<div id="learndash-tooltips"></div>');
984			var $ctr = 1;
985			$tooltips.each(function () {
986				var anchor = $(this);
987				if (anchor.hasClass('ld-item-list-item')) {
988					anchor = anchor.find('.ld-item-title');
989				}
990
991				/**
992				 * Prevent calendar icon from being clickable.
993				 */
994				if (
995					'undefined' !== typeof anchor &&
996					$(anchor).hasClass('ld-status-waiting')
997				) {
998					$(anchor).on('click', function (e) {
999						e.preventDefault();
1000						return false;
1001					});
1002
1003					// Also prevent parent <a> from being clickable.
1004					var parent_anchor = $(anchor).parents('a');
1005					if ('undefined' !== typeof parent_anchor) {
1006						$(parent_anchor).on('click', function (e) {
1007							e.preventDefault();
1008							return false;
1009						});
1010					}
1011				}
1012
1013				var elementOffsets = {
1014					top: anchor.offset().top,
1015					left: anchor.offset().left + anchor.outerWidth() / 2,
1016				};
1017				var $content = $(this).attr('data-ld-tooltip');
1018				var $rel_id = Math.floor(Math.random() * 99999);
1019
1020				//var $tooltip = '<span id="ld-tooltip-' + $rel_id + '" class="ld-tooltip" style="top:' + elementOffsets.top + 'px; left:' + elementOffsets.left + 'px;">' + $content + '</span>';
1021				var $tooltip =
1022					'<span id="ld-tooltip-' +
1023					$rel_id +
1024					'" class="ld-tooltip">' +
1025					$content +
1026					'</span>';
1027				$(this).attr('data-ld-tooltip-id', $rel_id);
1028				$('#learndash-tooltips').append($tooltip);
1029				$ctr++;
1030				var $tooltip = $('#ld-tooltip-' + $rel_id);
1031				$(this)
1032					.on('mouseenter', function () {
1033						$tooltip.addClass('ld-visible');
1034					})
1035					.on('mouseleave', function () {
1036						$tooltip.removeClass('ld-visible');
1037					});
1038			});
1039
1040			$(window).on('resize', function () {
1041				// Reposition tooltips after resizing
1042				positionTooltips();
1043			});
1044
1045			$(window)
1046				.add('.ld-focus-sidebar-wrapper')
1047				.on('scroll', function () {
1048					// Hide tooltips so they don't persist while scrolling
1049					$('.ld-visible.ld-tooltip').removeClass('ld-visible');
1050
1051					// Reposition tooltips after scrolling
1052					positionTooltips();
1053				});
1054
1055			positionTooltips();
1056		}
1057	}
1058
1059	function initLoginModal() {
1060		var modal_wrapper = $('.learndash-wrapper-login-modal');
1061		if ('undefined' !== typeof modal_wrapper && modal_wrapper.length) {
1062			// Move the model to be first element of the body. See LEARNDASH-3503
1063			$(modal_wrapper).prependTo('body');
1064		}
1065	}
1066
1067	function openLoginModal() {
1068		var modal_wrapper = $('.learndash-wrapper-login-modal');
1069		if ('undefined' !== typeof modal_wrapper && modal_wrapper.length) {
1070			$(modal_wrapper).addClass('ld-modal-open');
1071			$(modal_wrapper).removeClass('ld-modal-closed');
1072
1073			// Removed LEARNDASH-3867 #4
1074			$('html, body').animate(
1075				{
1076					scrollTop: $('.ld-modal', modal_wrapper).offset().top,
1077				},
1078				50
1079			);
1080
1081			$('.ld-modal', modal_wrapper).focus();
1082		}
1083	}
1084
1085	function closeLoginModal() {
1086		var modal_wrapper = $('.learndash-wrapper-login-modal');
1087		if ('undefined' !== typeof modal_wrapper && modal_wrapper.length) {
1088			$(modal_wrapper).removeClass('ld-modal-open');
1089			$(modal_wrapper).addClass('ld-modal-closed');
1090
1091			// Return the focus to the login link that triggers the modal.
1092			$('[data-ld-login-modal-trigger]').focus();
1093		}
1094	}
1095
1096	/**
1097	 * Position legacy LD30 Classic tooltips.
1098	 * This is not used by the new tooltips added in 4.21.3.
1099	 * Kept for backwards compatibility.
1100	 *
1101	 * @since 3.0.0
1102	 *
1103	 * @return {void}
1104	 */
1105	function positionTooltips() {
1106		if ('undefined' !== typeof $tooltips) {
1107			setTimeout(function () {
1108				$tooltips.each(function () {
1109					var anchor = $(this);
1110					var $rel_id = anchor.attr('data-ld-tooltip-id');
1111					$tooltip = $('#ld-tooltip-' + $rel_id);
1112
1113					if (anchor.hasClass('ld-item-list-item')) {
1114						//anchor = anchor.find('.ld-item-title');
1115						anchor = anchor.find('.ld-status-icon');
1116					}
1117
1118					var parent_focus =
1119						jQuery(anchor).parents('.ld-focus-sidebar');
1120					var left_post =
1121						anchor.offset().left + (anchor.outerWidth() + 10);
1122					if (parent_focus.length) {
1123						left_post =
1124							anchor.offset().left + (anchor.outerWidth() - 18);
1125					}
1126
1127					// Get the main content height
1128					var focusModeMainContentHeight =
1129						$('.ld-focus-main').height();
1130
1131					// Current tooltip height
1132					var focusModeCurrentTooltipHeight =
1133						anchor.offset().top + -3;
1134
1135					// Position tooltip depending on focus mode or not
1136					if (!focusModeMainContentHeight) {
1137						var anchorTop = anchor.offset().top + -3;
1138						var anchorLeft = anchor.offset().left;
1139					} else {
1140						anchorTop =
1141							focusModeCurrentTooltipHeight <
1142							focusModeMainContentHeight
1143								? focusModeCurrentTooltipHeight
1144								: focusModeMainContentHeight;
1145						anchorLeft = left_post;
1146					}
1147
1148					$tooltip
1149						.css({
1150							top: anchorTop,
1151
1152							//'left' : anchor.offset().left + (anchor.outerWidth() / 2),
1153							//'left': left_post, //anchor.offset().left + (anchor.outerWidth() +10),
1154							left: anchorLeft, //anchor.offset().left + (anchor.outerWidth() +10),
1155							'margin-left': 0,
1156							'margin-right': 0,
1157						})
1158						.removeClass('ld-shifted-left ld-shifted-right');
1159					if ($tooltip.offset().left <= 0) {
1160						$tooltip
1161							.css({
1162								'margin-left': Math.abs($tooltip.offset().left),
1163							})
1164							.addClass('ld-shifted-left');
1165					}
1166					var $tooltipRight =
1167						$(window).width() -
1168						($tooltip.offset().left + $tooltip.outerWidth());
1169					if (0 >= $tooltipRight && 360 < $(window).width()) {
1170						$tooltip
1171							.css({ 'margin-right': Math.abs($tooltipRight) })
1172							.addClass('ld-shifted-right');
1173					}
1174				});
1175			}, 500);
1176		}
1177	}
1178
1179	$('body').on('click', '#ld-profile .ld-reset-button', function (e) {
1180		e.preventDefault();
1181
1182		$('#ld-profile #course_name_field').val('');
1183
1184		var searchVars = {
1185			shortcode_instance: $('#ld-profile').data('shortcode_instance'),
1186		};
1187
1188		searchVars['ld-profile-search'] = $(this)
1189			.parents('.ld-item-search-wrapper')
1190			.find('#course_name_field')
1191			.val();
1192		searchVars['ld-profile-search-nonce'] = $(this)
1193			.parents('.ld-item-search-wrapper')
1194			.find('form.ld-item-search-fields')
1195			.data('nonce');
1196
1197		$('#ld-profile #ld-main-course-list').addClass('ld-loading');
1198
1199		$.ajax({
1200			type: 'GET',
1201			url: ldVars.ajaxurl + '?action=ld30_ajax_profile_search',
1202			data: searchVars,
1203			success(response) {
1204				if ('undefined' !== typeof response.data.markup) {
1205					$('#ld-profile').html(response.data.markup);
1206					ldToggleExpandableElement(
1207						'#ld-profile .ld-search-prompt',
1208						true
1209					);
1210				}
1211			},
1212		});
1213	});
1214
1215	$('body').on('submit', '.ld-item-search-fields', function (e) {
1216		e.preventDefault();
1217
1218		var searchVars = {
1219			shortcode_instance: $('#ld-profile').data('shortcode_instance'),
1220		};
1221
1222		searchVars['ld-profile-search'] = $(this)
1223			.parents('.ld-item-search-wrapper')
1224			.find('#course_name_field')
1225			.val();
1226		searchVars['ld-profile-search-nonce'] = $(this)
1227			.parents('.ld-item-search-wrapper')
1228			.find('form.ld-item-search-fields')
1229			.data('nonce');
1230
1231		$('#ld-profile #ld-main-course-list').addClass('ld-loading');
1232
1233		$.ajax({
1234			type: 'GET',
1235			url: ldVars.ajaxurl + '?action=ld30_ajax_profile_search',
1236			data: searchVars,
1237			success(response) {
1238				if ('undefined' !== typeof response.data.markup) {
1239					$('#ld-profile').html(response.data.markup);
1240					ldToggleExpandableElement(
1241						'#ld-profile .ld-search-prompt',
1242						true
1243					);
1244				}
1245			},
1246		});
1247	});
1248
1249	$('body').on('click', '.ld-pagination a', function (e) {
1250		e.preventDefault();
1251
1252		var linkVars = {};
1253		var parentVars = {};
1254
1255		$(this)
1256			.attr('href')
1257			.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (m, key, value) {
1258				linkVars[key] = value;
1259			});
1260
1261		linkVars.pager_nonce = $(this)
1262			.parents('.ld-pagination')
1263			.data('pager-nonce');
1264
1265		linkVars.pager_results = $(this)
1266			.parents('.ld-pagination')
1267			.data('pager-results');
1268
1269		linkVars.context = $(this).data('context');
1270
1271		parentVars.currentTarget = e.currentTarget;
1272
1273		if ('profile' != linkVars.context) {
1274			linkVars.lesson_id = $(this).data('lesson_id');
1275			linkVars.course_id = $(this).data('course_id');
1276
1277			if ($('.ld-course-nav-' + linkVars.course_id).length) {
1278				linkVars.widget_instance = $(
1279					'.ld-course-nav-' + linkVars.course_id
1280				).data('widget_instance');
1281			}
1282		}
1283
1284		if ('course_topics' == linkVars.context) {
1285			$('#ld-topic-list-' + linkVars.lesson_id).addClass('ld-loading');
1286			$('#ld-nav-content-list-' + linkVars.lesson_id).addClass(
1287				'ld-loading'
1288			);
1289		}
1290
1291		if ('course_content_shortcode' == linkVars.context) {
1292			parentVars.parent_container = $(parentVars.currentTarget).closest(
1293				'.ld-course-content-' + linkVars.course_id
1294			);
1295			if (
1296				'undefined' !== typeof parentVars.parent_container &&
1297				parentVars.parent_container.length
1298			) {
1299				$(parentVars.parent_container).addClass('ld-loading');
1300				linkVars.shortcode_instance = $(
1301					parentVars.parent_container
1302				).data('shortcode_instance');
1303			} else {
1304				$('.ld-course-content-' + linkVars.course_id).addClass(
1305					'ld-loading'
1306				);
1307				linkVars.shortcode_instance = $(
1308					'.ld-course-content-' + linkVars.course_id
1309				).data('shortcode_instance');
1310			}
1311		} else if ('course_lessons' == linkVars.context) {
1312			var parent_container;
1313
1314			// Check if we are within the Course Navigation Widget.
1315			if (
1316				'undefined' === typeof parentVars.parent_container ||
1317				!parentVars.parent_container.length
1318			) {
1319				parent_container = $(parentVars.currentTarget).parents(
1320					'.ld-lesson-navigation'
1321				);
1322				if (
1323					'undefined' !== typeof parent_container &&
1324					parent_container.length
1325				) {
1326					parentVars.context_sub = 'course_navigation_widget';
1327					parentVars.parent_container = $(
1328						parentVars.currentTarget
1329					).parents('#ld-lesson-list-' + linkVars.course_id);
1330				}
1331			}
1332
1333			// Check if we are within the Focus Mode Sidebar.
1334			if (
1335				'undefined' === typeof parentVars.parent_container ||
1336				!parentVars.parent_container.length
1337			) {
1338				parent_container = $(parentVars.currentTarget).parents(
1339					'.ld-focus-sidebar-wrapper'
1340				);
1341				if (
1342					'undefined' !== typeof parent_container &&
1343					parent_container.length
1344				) {
1345					parentVars.context_sub = 'focus_mode_sidebar';
1346					parentVars.parent_container = $(
1347						parentVars.currentTarget
1348					).parents('#ld-lesson-list-' + linkVars.course_id);
1349				}
1350			}
1351
1352			if (
1353				'undefined' === typeof parentVars.parent_container ||
1354				!parentVars.parent_container.length
1355			) {
1356				parentVars.parent_container = $(
1357					parentVars.currentTarget
1358				).closest(
1359					'#ld-item-list-' + linkVars.course_id,
1360					'#ld-lesson-list-' + linkVars.course_id
1361				);
1362			}
1363			if (
1364				'undefined' !== typeof parentVars.parent_container &&
1365				parentVars.parent_container.length
1366			) {
1367				$(parentVars.parent_container).addClass('ld-loading');
1368			} else {
1369				// Fallback solution.
1370				$('#ld-item-list-' + linkVars.course_id).addClass('ld-loading');
1371				$('#ld-lesson-list-' + linkVars.course_id).addClass(
1372					'ld-loading'
1373				);
1374			}
1375		}
1376
1377		if ('profile' == linkVars.context) {
1378			$('#ld-profile #ld-main-course-list').addClass('ld-loading');
1379			linkVars.shortcode_instance =
1380				$('#ld-profile').data('shortcode_instance');
1381		}
1382
1383		if ('profile_quizzes' == linkVars.context) {
1384			$(
1385				'#ld-course-list-item-' +
1386					linkVars.pager_results.quiz_course_id +
1387					' .ld-item-contents'
1388			).addClass('ld-loading');
1389		}
1390
1391		if ('course_info_courses' == linkVars.context) {
1392			$('.ld-user-status').addClass('ld-loading');
1393			linkVars.shortcode_instance =
1394				$('.ld-user-status').data('shortcode-atts');
1395		}
1396
1397		if ('group_courses' == linkVars.context) {
1398			linkVars.group_id = $(this).data('group_id');
1399			if ('undefined' !== typeof linkVars.group_id) {
1400				parent_container = $(parentVars.currentTarget).parents(
1401					'.ld-group-courses-' + linkVars.group_id
1402				);
1403				if (
1404					'undefined' !== typeof parent_container &&
1405					parent_container.length
1406				) {
1407					$(parent_container).addClass('ld-loading');
1408					parentVars.parent_container = parent_container;
1409				}
1410			}
1411		}
1412
1413		$.ajax({
1414			type: 'GET',
1415			url: ldVars.ajaxurl + '?action=ld30_ajax_pager',
1416			data: linkVars,
1417			success(response) {
1418				// If we have a course listing, update
1419
1420				if ('course_topics' == linkVars.context) {
1421					if ($('#ld-topic-list-' + linkVars.lesson_id).length) {
1422						if ('undefined' !== typeof response.data.topics) {
1423							$('#ld-topic-list-' + linkVars.lesson_id).html(
1424								response.data.topics
1425							);
1426						}
1427
1428						if ('undefined' !== typeof response.data.pager) {
1429							$('#ld-expand-' + linkVars.lesson_id)
1430								.find('.ld-table-list-footer')
1431								.html(response.data.pager);
1432						}
1433
1434						learndashSetMaxHeight(
1435							$('.ld-lesson-item-' + linkVars.lesson_id).find(
1436								'.ld-item-list-item-expanded'
1437							)
1438						);
1439
1440						$('#ld-topic-list-' + linkVars.lesson_id).removeClass(
1441							'ld-loading'
1442						);
1443					}
1444
1445					if (
1446						$('#ld-nav-content-list-' + linkVars.lesson_id).length
1447					) {
1448						if ('undefined' !== typeof response.data.nav_topics) {
1449							$('#ld-nav-content-list-' + linkVars.lesson_id)
1450								.find('.ld-table-list-items')
1451								.html(response.data.topics);
1452						}
1453
1454						if ('undefined' !== typeof response.data.pager) {
1455							$('#ld-nav-content-list-' + linkVars.lesson_id)
1456								.find('.ld-table-list-footer')
1457								.html(response.data.pager);
1458						}
1459
1460						$(
1461							'#ld-nav-content-list-' + linkVars.lesson_id
1462						).removeClass('ld-loading');
1463					}
1464				}
1465
1466				if ('course_content_shortcode' == linkVars.context) {
1467					if ('undefined' !== typeof response.data.markup) {
1468						if (
1469							'undefined' !==
1470								typeof parentVars.parent_container &&
1471							parentVars.parent_container.length
1472						) {
1473							$(parentVars.parent_container).replaceWith(
1474								response.data.markup
1475							);
1476						} else {
1477							$(
1478								'#learndash_post_' + linkVars.course_id
1479							).replaceWith(response.data.markup);
1480						}
1481					}
1482				} else if ('course_lessons' == linkVars.context) {
1483					if (
1484						'undefined' !== typeof parentVars.parent_container &&
1485						parentVars.parent_container.length
1486					) {
1487						if (
1488							'course_navigation_widget' == parentVars.context_sub
1489						) {
1490							if (
1491								'undefined' !== typeof response.data.nav_lessons
1492							) {
1493								$(parentVars.parent_container)
1494									.html(response.data.nav_lessons)
1495									.removeClass('ld-loading');
1496							}
1497						} else if (
1498							'focus_mode_sidebar' == parentVars.context_sub
1499						) {
1500							if (
1501								'undefined' !== typeof response.data.nav_lessons
1502							) {
1503								$(parentVars.parent_container)
1504									.html(response.data.nav_lessons)
1505									.removeClass('ld-loading');
1506							}
1507						} else if (
1508							'undefined' !== typeof response.data.lessons
1509						) {
1510							$(parentVars.parent_container)
1511								.html(response.data.lessons)
1512								.removeClass('ld-loading');
1513						}
1514					} else {
1515						if ($('#ld-item-list-' + linkVars.course_id).length) {
1516							if ('undefined' !== typeof response.data.lessons) {
1517								$('#ld-item-list-' + linkVars.course_id)
1518									.html(response.data.lessons)
1519									.removeClass('ld-loading');
1520							}
1521						}
1522
1523						if ($('#ld-lesson-list-' + linkVars.course_id).length) {
1524							if (
1525								'undefined' !== typeof response.data.nav_lessons
1526							) {
1527								$('#ld-lesson-list-' + linkVars.course_id)
1528									.html(response.data.nav_lessons)
1529									.removeClass('ld-loading');
1530							}
1531						}
1532					}
1533				}
1534
1535				if ('group_courses' == linkVars.context) {
1536					if (
1537						'undefined' !== typeof parentVars.parent_container &&
1538						parentVars.parent_container.length
1539					) {
1540						if ('undefined' !== typeof response.data.markup) {
1541							$(parentVars.parent_container)
1542								.html(response.data.markup)
1543								.removeClass('ld-loading');
1544						}
1545					}
1546				}
1547
1548				if ('profile' == linkVars.context) {
1549					if ('undefined' !== typeof response.data.markup) {
1550						$('#ld-profile').html(response.data.markup);
1551					}
1552				}
1553
1554				if ('profile_quizzes' == linkVars.context) {
1555					if ('undefined' !== typeof response.data.markup) {
1556						$(
1557							'#ld-course-list-item-' +
1558								linkVars.pager_results.quiz_course_id +
1559								' .ld-item-list-item-expanded .ld-item-contents'
1560						).replaceWith(response.data.markup);
1561						$(
1562							'#ld-course-list-item-' +
1563								linkVars.pager_results.quiz_course_id
1564						)
1565							.get(0)
1566							.scrollIntoView({ behavior: 'smooth' });
1567					}
1568				}
1569
1570				if ('course_info_courses' == linkVars.context) {
1571					if ('undefined' !== typeof response.data.markup) {
1572						$('.ld-user-status').replaceWith(response.data.markup);
1573					}
1574				}
1575
1576				$('body').trigger('ld_has_paginated');
1577
1578				initTooltips();
1579			},
1580		});
1581	});
1582
1583	if ($('#learndash_timer').length) {
1584		var timer_el = jQuery('#learndash_timer');
1585		var timer_seconds = timer_el.attr('data-timer-seconds');
1586		var timer_button_el = jQuery(timer_el.attr('data-button'));
1587
1588		var cookie_key = timer_el.attr('data-cookie-key');
1589
1590		if ('undefined' !== typeof cookie_key) {
1591			var cookie_name = 'learndash_timer_cookie_' + cookie_key;
1592		} else {
1593			var cookie_name = 'learndash_timer_cookie';
1594		}
1595
1596		cookie_timer_seconds = jQuery.cookie(cookie_name);
1597
1598		if ('undefined' !== typeof cookie_timer_seconds) {
1599			timer_seconds = parseInt(cookie_timer_seconds);
1600		}
1601
1602		if (0 == timer_seconds) {
1603			$(timer_el).hide();
1604		}
1605
1606		$(timer_button_el).on('learndash-time-finished', function () {
1607			$(timer_el).hide();
1608		});
1609	}
1610
1611	$(document).on('learndash_video_disable_assets', function (event, status) {
1612		if ('undefined' === typeof learndash_video_data) {
1613			return false;
1614		}
1615
1616		if ('BEFORE' == learndash_video_data.videos_shown) {
1617			if (true == status) {
1618				$('.ld-lesson-topic-list').hide();
1619				$('.ld-lesson-navigation')
1620					.find('#ld-nav-content-list-' + ldVars.postID)
1621					.addClass('user_has_no_access');
1622				$('.ld-quiz-list').hide();
1623			} else {
1624				$('.ld-lesson-topic-list').slideDown();
1625				$('.ld-quiz-list').slideDown();
1626				$('.ld-lesson-navigation')
1627					.find('#ld-nav-content-list-' + ldVars.postID)
1628					.removeClass('user_has_no_access');
1629			}
1630		}
1631	});
1632
1633	$('.learndash-wrapper').on(
1634		'click',
1635		'.wpProQuiz_questionListItem input[type="radio"]',
1636		function (e) {
1637			$(this)
1638				.parents('.wpProQuiz_questionList')
1639				.find('label')
1640				.removeClass('is-selected');
1641			$(this).parents('label').addClass('is-selected');
1642		}
1643	);
1644
1645	$('.learndash-wrapper').on(
1646		'click',
1647		'.wpProQuiz_questionListItem input[type="checkbox"]',
1648		function (e) {
1649			if (jQuery(e.currentTarget).is(':checked')) {
1650				$(this).parents('label').addClass('is-selected');
1651			} else {
1652				$(this).parents('label').removeClass('is-selected');
1653			}
1654		}
1655	);
1656
1657	function learndash_ld30_show_user_statistic(e) {
1658		e.preventDefault();
1659
1660		var refId = jQuery(this).data('ref-id');
1661		var quizId = jQuery(this).data('quiz-id');
1662		var userId = jQuery(this).data('user-id');
1663		var statistic_nonce = jQuery(this).data('statistic-nonce');
1664		var post_data = {
1665			action: 'wp_pro_quiz_admin_ajax_statistic_load_user',
1666			func: 'statisticLoadUser',
1667			data: {
1668				quizId,
1669				userId,
1670				refId,
1671				statistic_nonce,
1672				avg: 0,
1673			},
1674		};
1675
1676		jQuery('#wpProQuiz_user_overlay, #wpProQuiz_loadUserData').show();
1677		var content = jQuery('#wpProQuiz_user_content').hide();
1678
1679		jQuery.ajax({
1680			type: 'POST',
1681			url: ldVars.ajaxurl,
1682			dataType: 'json',
1683			cache: false,
1684			data: post_data,
1685			error(jqXHR, textStatus, errorThrown) {},
1686			success(reply_data) {
1687				if ('undefined' !== typeof reply_data.html) {
1688					content.html(reply_data.html);
1689					jQuery('#wpProQuiz_user_content').show();
1690
1691					jQuery('body').trigger(
1692						'learndash-statistics-contentchanged'
1693					);
1694
1695					jQuery('#wpProQuiz_loadUserData').hide();
1696
1697					content.find('.statistic_data').on('click', function () {
1698						jQuery(this).parents('tr').next().toggle('fast');
1699
1700						return false;
1701					});
1702				}
1703			},
1704		});
1705
1706		jQuery('#wpProQuiz_overlay_close').on('click', function () {
1707			jQuery('#wpProQuiz_user_overlay').hide();
1708		});
1709	}
1710
1711	function learndashSetMaxHeight(elm) {
1712		var totalHeight = 0;
1713
1714		elm.find('> *').each(function () {
1715			totalHeight += $(this).outerHeight();
1716		});
1717
1718		elm.attr('data-height', '' + (totalHeight + 50) + '');
1719
1720		elm.css({
1721			'max-height': totalHeight + 50,
1722		});
1723	}
1724
1725	/**
1726	 * Will scroll the position of the Focus Mode sidebar
1727	 * to the active step.
1728	 */
1729	function learndashFocusModeSidebarAutoScroll() {
1730		if (jQuery('.learndash-wrapper .ld-focus').length) {
1731			var sidebar_wrapper = jQuery(
1732				'.learndash-wrapper .ld-focus .ld-focus-sidebar-wrapper'
1733			);
1734
1735			var sidebar_current_topic = jQuery(
1736				'.learndash-wrapper .ld-focus .ld-focus-sidebar-wrapper .ld-is-current-item'
1737			);
1738			if (
1739				'undefined' !== typeof sidebar_current_topic &&
1740				sidebar_current_topic.length
1741			) {
1742				var sidebar_scrollTo = sidebar_current_topic;
1743			} else {
1744				var sidebar_current_lesson = jQuery(
1745					'.learndash-wrapper .ld-focus .ld-focus-sidebar-wrapper .ld-is-current-lesson'
1746				);
1747				if (
1748					'undefined' !== typeof sidebar_current_lesson &&
1749					sidebar_current_lesson.length
1750				) {
1751					var sidebar_scrollTo = sidebar_current_lesson;
1752				}
1753			}
1754
1755			if (
1756				'undefined' !== typeof sidebar_scrollTo &&
1757				sidebar_scrollTo.length
1758			) {
1759				var offset_top = 0;
1760				if (
1761					jQuery('.learndash-wrapper .ld-focus .ld-focus-header')
1762						.length
1763				) {
1764					var logo_height = jQuery(
1765						'.learndash-wrapper .ld-focus .ld-focus-header'
1766					).height();
1767					offset_top += logo_height;
1768				}
1769				if (
1770					jQuery(
1771						'.learndash-wrapper .ld-focus .ld-focus-sidebar .ld-course-navigation-heading'
1772					).length
1773				) {
1774					var heading_height = jQuery(
1775						'.learndash-wrapper .ld-focus .ld-focus-sidebar .ld-course-navigation-heading'
1776					).height();
1777					offset_top += heading_height;
1778				}
1779				if (
1780					jQuery(
1781						'.learndash-wrapper .ld-focus .ld-focus-sidebar .ld-focus-sidebar-wrapper'
1782					).length
1783				) {
1784					var container_height = jQuery(
1785						'.learndash-wrapper .ld-focus .ld-focus-sidebar .ld-focus-sidebar-wrapper'
1786					).height();
1787					offset_top += container_height;
1788				}
1789
1790				var current_item_height = jQuery(sidebar_scrollTo).height();
1791				offset_top -= current_item_height;
1792
1793				sidebar_wrapper.animate(
1794					{
1795						scrollTop: sidebar_scrollTo.offset().top - offset_top,
1796					},
1797					1000
1798				);
1799			}
1800		}
1801	}
1802
1803	// Coupon processing.
1804
1805	function update_payment_forms(data) {
1806		$('#total-row').attr('data-total', data.total.value);
1807
1808		// Update PayPal form amount.
1809		$('form[name="buynow"] input[name="amount"]').val(data.total.value);
1810
1811		// Update Stripe form amount.
1812		$('form.learndash-stripe-checkout input[name="stripe_price"]').val(
1813			data.total.stripe_value
1814		);
1815
1816		// Remove Stripe Connect session to respect the new amount.
1817		const stripe_course_id = $(
1818			'.learndash-stripe-checkout input[name="stripe_course_id"]'
1819		).val();
1820
1821		if (stripe_course_id) {
1822			LD_Cookies.remove('ld_stripe_session_id_' + stripe_course_id); // Stripe Plugin (Checkout).
1823			LD_Cookies.remove(
1824				'ld_stripe_connect_session_id_' + stripe_course_id
1825			); // Stripe Connect in core.
1826		}
1827
1828		// Re-init Stripe Plugin (Legacy) to respect the new amount.
1829		if (typeof ld_init_stripe_legacy === 'function') {
1830			ld_init_stripe_legacy();
1831		}
1832	}
1833
1834	$('.btn-join').on('click', function (e) {
1835		if ($(this).hasClass('btn-disabled')) {
1836			e.preventDefault();
1837			return false;
1838		}
1839
1840		const supportsCoupon = $('#total-row').attr('data-supports-coupon');
1841
1842		if (!supportsCoupon) {
1843			return;
1844		}
1845
1846		const total = parseFloat($('#total-row').attr('data-total'));
1847
1848		if (0 === total) {
1849			$.ajax({
1850				type: 'POST',
1851				url: ldVars.ajaxurl,
1852				dataType: 'json',
1853				cache: false,
1854				data: {
1855					action: 'learndash_enroll_with_zero_price',
1856					nonce: $('#apply-coupon-form').data('nonce'),
1857					post_id: $('#apply-coupon-form').data('post-id'),
1858				},
1859				success(response) {
1860					if (response.success) {
1861						window.location.replace(response.data.redirect_url);
1862					} else {
1863						alert(response.data.message);
1864					}
1865				},
1866			});
1867
1868			e.preventDefault();
1869			return false;
1870		}
1871	});
1872
1873	$('#apply-coupon-form').on('submit', function (e) {
1874		e.preventDefault();
1875		const $el = $(this);
1876		const $wrapper = $el.closest('.ld-registration-order__items');
1877
1878		$.ajax({
1879			type: 'POST',
1880			url: ldVars.ajaxurl,
1881			dataType: 'json',
1882			cache: false,
1883			data: {
1884				action: 'learndash_apply_coupon',
1885				nonce: $(this).data('nonce'),
1886				coupon_code: $(this).find('#coupon-field').val(),
1887				post_id: $(this).data('post-id'),
1888			},
1889			success(response) {
1890				const isModernRegistration = $(
1891					'.ld-form__field-coupon_field'
1892				).length;
1893
1894				if (isModernRegistration) {
1895					$('#coupon-alerts .coupon-alert').hide();
1896
1897					const $alert = $('#coupon-alerts').find(
1898						response.success
1899							? '.coupon-alert-success'
1900							: '.coupon-alert-warning'
1901					);
1902
1903					if (response.success) {
1904						$wrapper
1905							.find('.ld-coupon__label-text')
1906							.html(response.data.coupon_code); // Set coupon code in totals.
1907
1908						$wrapper
1909							.find('.ld-coupon__value')
1910							.html('(' + response.data.discount + ')'); // Set discount value in totals.
1911
1912						$wrapper
1913							.find('.ld-registration-order__item-price-value')
1914							.html(response.data.total.formatted); // Update course/group price.
1915
1916						$wrapper
1917							.find('.ld-registration-order__total-price')
1918							.html(response.data.total.formatted); // Update Total.
1919
1920						$wrapper.addClass(
1921							'ld-registration-order__items--with-coupon'
1922						);
1923
1924						update_payment_forms(response.data);
1925					}
1926
1927					$alert
1928						.find('.ld-alert-messages')
1929						.html(response.data.message);
1930					$alert.fadeIn();
1931				} else {
1932					$('#coupon-alerts .coupon-alert').hide();
1933
1934					const $alert = $('#coupon-alerts').find(
1935						response.success
1936							? '.coupon-alert-success'
1937							: '.coupon-alert-warning'
1938					);
1939
1940					const $coupon_row = $('#coupon-row');
1941
1942					if (response.success) {
1943						$coupon_row
1944							.find('.purchase-label > span')
1945							.html(response.data.coupon_code); // Set coupon code in totals.
1946						$coupon_row
1947							.find('.purchase-value span')
1948							.html(response.data.discount); // Set discount value in totals.
1949						$coupon_row.css('display', 'flex').hide().fadeIn(); // Show a coupon row in totals.
1950						$('#total-row .purchase-value').html(
1951							response.data.total.formatted
1952						); // Update Total.
1953						$('#totals').show();
1954
1955						update_payment_forms(response.data);
1956					}
1957
1958					$alert
1959						.find('.ld-alert-messages')
1960						.html(response.data.message);
1961					$alert.fadeIn();
1962				}
1963			},
1964		});
1965	});
1966
1967	$('#remove-coupon-form').on('submit', function (e) {
1968		e.preventDefault();
1969		const $el = $(this);
1970		const $wrapper = $el.closest('.ld-registration-order__items');
1971
1972		$.ajax({
1973			type: 'POST',
1974			url: ldVars.ajaxurl,
1975			dataType: 'json',
1976			cache: false,
1977			data: {
1978				action: 'learndash_remove_coupon',
1979				nonce: $(this).data('nonce'),
1980				post_id: $(this).data('post-id'),
1981			},
1982			success(response) {
1983				const isModernRegistration = $(
1984					'.ld-form__field-coupon_field'
1985				).length;
1986
1987				if (isModernRegistration) {
1988					$('#coupon-alerts .coupon-alert').hide();
1989
1990					const $alert = $('#coupon-alerts').find(
1991						response.success
1992							? '.coupon-alert-success'
1993							: '.coupon-alert-warning'
1994					);
1995
1996					if (response.success) {
1997						$wrapper.removeClass(
1998							'ld-registration-order__items--with-coupon'
1999						);
2000						$wrapper.find('.ld-form__field-coupon_field').val(''); // Set coupon field empty.
2001						$wrapper
2002							.find('.ld-registration-order__item-price-value')
2003							.html(response.data.total.formatted); // Update course/group price.
2004						$wrapper
2005							.find('.ld-registration-order__total-price')
2006							.html(response.data.total.formatted); // Update Total.
2007
2008						update_payment_forms(response.data);
2009					}
2010
2011					$alert
2012						.find('.ld-alert-messages')
2013						.html(response.data.message);
2014					$alert.fadeIn();
2015				} else {
2016					$('#coupon-alerts .coupon-alert').hide();
2017
2018					const $alert = $('#coupon-alerts').find(
2019						response.success
2020							? '.coupon-alert-success'
2021							: '.coupon-alert-warning'
2022					);
2023
2024					if (response.success) {
2025						$('#coupon-row').hide(); // Hide a coupon row in totals.
2026						$('#coupon-field').val(''); // Set coupon field empty.
2027						$('#price-row .purchase-value').html(
2028							response.data.total.formatted
2029						); // Update Price.
2030						$('#subtotal-row .purchase-value').html(
2031							response.data.total.formatted
2032						); // Update Subtotal.
2033						$('#total-row .purchase-value').html(
2034							response.data.total.formatted
2035						); // Update Total.
2036						$('#totals').hide();
2037
2038						update_payment_forms(response.data);
2039					}
2040
2041					$alert
2042						.find('.ld-alert-messages')
2043						.html(response.data.message);
2044					$alert.fadeIn();
2045				}
2046			},
2047		});
2048	});
2049});
2050
2051function ldGetUrlVars() {
2052	var vars = {};
2053	var parts = window.location.href.replace(
2054		/[?&]+([^=&]+)=([^&]*)/gi,
2055		function (m, key, value) {
2056			vars[key] = value;
2057		}
2058	);
2059
2060	return vars;
2061}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.