PageSourceSearch

https://100blackmen.org/wp-content/plugins/sfwd-lms/themes/ld30/assets/js/learndash.js?ver=4.23.2.1

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

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.