PageSourceSearch

https://www.federvini.it/media/plg_jspeed/cache/js/9306239a4e19de141ee31953457ec700_0_14.js

js federvini.it collected 2026-09-24 22:13:28 UTC 20,896 bytes, 747 lines download raw bytes

1try {
2/**
3 * @package Helix Ultimate Framework
4 * @author JoomShaper https://www.joomshaper.com
5 * @copyright Copyright (c) 2010 - 2023 JoomShaper
6 * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPLv2 or Later
7 */
8
9// Preloader
10jQuery(window).on('load', function () {
11	if (jQuery('.sp-loader-with-logo').length > 0) {
12
13		move();
14	}
15	jQuery('.sp-pre-loader').fadeOut(500, function () {
16		jQuery(this).remove();
17	});
18});
19
20/**
21 * Move the progress bar
22 */
23function move() {
24	var elem = document.getElementById('line-load');
25	var width = 1;
26	var id = setInterval(frame, 10);
27	function frame() {
28		if (width >= 100) {
29			clearInterval(id);
30		} else {
31			width++;
32			elem.style.width = width + '%';
33		}
34	}
35
36}
37
38jQuery(function ($) {
39
40	/**
41	 * Helix settings data
42	 *
43	 */
44	var settings = Joomla.getOptions('data') || {};
45
46	/**
47	 * sticky header
48	 *
49	 * @param {string} className the header className
50	 */
51	var handleStickiness = function (className, offsetTop) {
52		if ($('body:not(.layout-edit-iframe)').hasClass(className)) {
53			var $header = $('#sp-header');
54			var headerHeight = $header.outerHeight();
55			var $stickyHeaderPlaceholder = $('.sticky-header-placeholder');
56			let $stickyOffset = '100';
57
58			if (settings.header !== undefined && settings.header.stickyOffset !== undefined) {
59				$stickyOffset = settings.header.stickyOffset || '100';
60			}
61
62			var stickyHeader = function () {
63				var scrollTop = $(window).scrollTop();
64				if (scrollTop >= offsetTop + Number($stickyOffset)) {
65					$header.addClass('header-sticky');
66					$stickyHeaderPlaceholder.height(headerHeight);
67				} else {
68					if ($header.hasClass('header-sticky')) {
69						$header.removeClass('header-sticky');
70						$stickyHeaderPlaceholder.height('inherit');
71					}
72				}
73			};
74
75			stickyHeader();
76			$(window).scroll(function () {
77				stickyHeader();
78			});
79
80			if ($('body').hasClass('layout-boxed')) {
81				var windowWidth = $header.parent().outerWidth();
82				$header.css({ 'max-width': windowWidth, left: 'auto' });
83			}
84		} else {
85			var $header = $('#sp-header');
86			if ($header.hasClass('header-sticky')) {
87				$header.removeClass('header-sticky');
88			}
89			$(window).off('scroll');
90		}
91	};
92
93	/**
94	 * Calculate the header offset based on the
95	 * backend preview iframe site and real site.
96	 *
97	 * @return  integer The offset value
98	 */
99	function getHeaderOffset() {
100		/**
101		 * Real site header offset top
102		 *
103		 */
104		let $header = $('#sp-header');
105		let stickyHeaderTop = $header.offset().top;
106
107		/**
108		 * Backend edit preview iframe header offset top
109		 *
110		 */
111		let $backHeader = $('body.back-panel').find('#sp-header');
112		let backPanelStickyHeaderTop = null;
113
114		/**
115		 * If the class .back-panel exists,
116		 * that means this is from backend preview frame,
117		 * then get the offset top, as it varies with the original one.
118		 *
119		 */
120		if ($backHeader.length > 0) {
121			backPanelStickyHeaderTop = $backHeader.offset().top;
122		}
123
124		// By Default the header offset is the original header top
125		let headerOffset = stickyHeaderTop;
126
127		/**
128		 * If back panel sticky header top has value rather than null
129		 * that means the device type is changes from desktop to table or mobile or vice-versa.
130		 * If value found then subtract the settings topbar height from the offset top.
131		 *
132		 */
133		if (backPanelStickyHeaderTop !== null) {
134			headerOffset = backPanelStickyHeaderTop - settings.topbarHeight;
135			headerOffset = headerOffset < 0 ? stickyHeaderTop : headerOffset;
136		}
137
138		return headerOffset;
139	}
140
141	const headerExist = $('#sp-header');
142	if (headerExist.length > 0) {
143		handleStickiness('sticky-header', getHeaderOffset());
144	}
145
146	// go to top
147	$(window).scroll(function () {
148		if ($(this).scrollTop() > 100) {
149			$('.sp-scroll-up').fadeIn();
150		} else {
151			$('.sp-scroll-up').fadeOut(400);
152		}
153	});
154
155	$('.sp-scroll-up').click(function () {
156		$('html, body').animate(
157			{
158				scrollTop: -60,
159			},
160			600
161		);
162		return false;
163	});
164
165	//mega menu
166	$('.sp-megamenu-wrapper').parent().parent().css('position', 'static').parent().css('position', 'relative');
167	$('.sp-menu-full').each(function () {
168		$(this).parent().addClass('menu-justify');
169	});
170
171
172
173	$('#offcanvas-toggler, .offcanvas-toggler-secondary, .offcanvas-toggler-full').on('click', function (event) {
174		event.preventDefault();
175		openOffcanvas();
176	});
177
178	// Close handlers
179	$('.close-offcanvas, .offcanvas-overlay').on('click', function (event) {
180		event.preventDefault();
181		closeOffcanvas();
182	});
183
184	// Open function
185	function openOffcanvas() {
186		$('.offcanvas-init').addClass('offcanvas-active full-offcanvas');
187		$(document.body).css('overflow', 'hidden');
188
189		// Make offcanvas interactive
190		$('.offcanvas-menu')
191			.removeAttr('inert')
192			.attr('tabindex', '0');
193
194		// Set focus to close button (better for accessibility)
195		setTimeout(() => {
196			$('.close-offcanvas').focus();
197		}, 100);
198
199		// Add keyboard trap
200		$(document).on('keydown.offcanvas', handleOffcanvasKeyboard);
201	}
202
203	// Close function
204	function closeOffcanvas() {
205		$('.offcanvas-init').removeClass('offcanvas-active full-offcanvas');
206		$(document.body).css('overflow', '');
207
208		// Make offcanvas non-interactive
209		$('.offcanvas-menu')
210			.attr('inert', '')
211			.attr('tabindex', '-1');
212
213		// Return focus to the trigger
214		$('#offcanvas-toggler').focus();
215
216		// Remove keyboard trap
217		$(document).off('keydown.offcanvas');
218	}
219
220	// Keyboard trap handler on offcanvas
221	function handleOffcanvasKeyboard(e) {
222		if (!$('.offcanvas-init').hasClass('offcanvas-active')) return;
223
224		const $offcanvas = $('.offcanvas-menu');
225		const focusable = 'a[href], button, input, textarea, select, [tabindex="0"]';
226		const $focusable = $offcanvas.find(focusable).filter(':visible');
227
228		// Escape key closes
229		if (e.key === 'Escape') {
230			e.preventDefault();
231			closeOffcanvas();
232			return;
233		}
234
235		// Tab key containment
236		if (e.key === 'Tab') {
237			const $first = $focusable.first();
238			const $last = $focusable.last();
239
240			if (!$offcanvas[0].contains(document.activeElement)) {
241				e.preventDefault();
242				$first.focus();
243				return;
244			}
245
246			if (e.shiftKey && document.activeElement === $first[0]) {
247				e.preventDefault();
248				$last.focus();
249			} else if (!e.shiftKey && document.activeElement === $last[0]) {
250				e.preventDefault();
251				$first.focus();
252			}
253		}
254	}
255
256	// Prevent focus on inert elements
257	$(document).on('focusin', function (e) {
258		if ($(e.target).closest('[inert]').length) {
259			e.preventDefault();
260			$('#offcanvas-toggler').focus();
261		}
262	});
263
264	// Modal Menu
265	if ($('#modal-menu').length > 0) {
266		let $modalToggler = $('#modal-menu-toggler');
267		let $modalMenu = $('#modal-menu');
268		let $body = $('body');
269
270		$modalToggler.on('click', function (e) {
271			e.preventDefault();
272			$modalMenu.toggleClass('active');
273			$body.toggleClass('modal-menu-active');
274			$(this).toggleClass('active');
275		});
276
277		// modal menu close with escape
278		$(document).keyup(function (e) {
279			if (e.key == 'Escape') {
280				$modalMenu.removeClass('active');
281				$modalToggler.removeClass('active');
282				$body.removeClass('modal-menu-active');
283			}
284		});
285	}
286
287	// Tooltip
288	const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"], .hasTooltip'));
289	tooltipTriggerList.map(function (tooltipTriggerEl) {
290		return new bootstrap.Tooltip(tooltipTriggerEl, {
291			html: true
292		});
293	});
294
295	// Popover
296	const popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"], .hasPopover'));
297	popoverTriggerList.map(function (popoverTriggerEl) {
298		return new bootstrap.Popover(popoverTriggerEl);
299	});
300
301	// Article Ajax voting
302	$('.article-ratings .rating-star').on('click', function (event) {
303		event.preventDefault();
304		var $parent = $(this).closest('.article-ratings');
305
306		var request = {
307			option: 'com_ajax',
308			template: template,
309			action: 'rating',
310			rating: $(this).data('number'),
311			article_id: $parent.data('id'),
312			format: 'json',
313		};
314
315		$.ajax({
316			type: 'POST',
317			data: request,
318			beforeSend: function () {
319				$parent.find('.fa-spinner').show();
320			},
321			success: function (response) {
322				var data = $.parseJSON(response);
323				$parent.find('.ratings-count').text(data.message);
324				$parent.find('.fa-spinner').hide();
325
326				if (data.status) {
327					$parent.find('.rating-symbol').html(data.ratings);
328				}
329
330				setTimeout(function () {
331					$parent.find('.ratings-count').text('(' + data.rating_count + ')');
332				}, 3000);
333			},
334		});
335	});
336
337	//  Cookie consent
338	$('.sp-cookie-allow').on('click', function (event) {
339		event.preventDefault();
340
341		var date = new Date();
342		date.setTime(date.getTime() + 30 * 24 * 60 * 60 * 1000);
343		var expires = '; expires=' + date.toGMTString();
344		document.cookie = 'spcookie_status=ok' + expires + '; path=/';
345
346		$(this).closest('.sp-cookie-consent').fadeOut();
347	});
348
349	$('.btn-group label:not(.active)').click(function () {
350		var label = $(this);
351		var input = $('#' + label.attr('for'));
352
353		if (!input.prop('checked')) {
354			label.closest('.btn-group').find('label').removeClass('active btn-success btn-danger btn-primary');
355			if (input.val() === '') {
356				label.addClass('active btn-primary');
357			} else if (input.val() == 0) {
358				label.addClass('active btn-danger');
359			} else {
360				label.addClass('active btn-success');
361			}
362			input.prop('checked', true);
363			input.trigger('change');
364		}
365		var parent = $(this).parents('#attrib-helix_ultimate_blog_options');
366		if (parent) {
367			showCategoryItems(parent, input.val());
368		}
369	});
370	$('.btn-group input[checked=checked]').each(function () {
371		if ($(this).val() == '') {
372			$('label[for=' + $(this).attr('id') + ']').addClass('active btn btn-primary');
373		} else if ($(this).val() == 0) {
374			$('label[for=' + $(this).attr('id') + ']').addClass('active btn btn-danger');
375		} else {
376			$('label[for=' + $(this).attr('id') + ']').addClass('active btn btn-success');
377		}
378		var parent = $(this).parents('#attrib-helix_ultimate_blog_options');
379		if (parent) {
380			parent.find('*[data-showon]').each(function () {
381				$(this).hide();
382			});
383		}
384	});
385
386	function showCategoryItems(parent, value) {
387		var controlGroup = parent.find('*[data-showon]');
388
389		controlGroup.each(function () {
390			var data = $(this).attr('data-showon');
391			data = typeof data !== 'undefined' ? JSON.parse(data) : [];
392			if (data.length > 0) {
393				if (typeof data[0].values !== 'undefined' && data[0].values.includes(value)) {
394					$(this).slideDown();
395				} else {
396					$(this).hide();
397				}
398			}
399		});
400	}
401
402	$(window).on('scroll', function () {
403		var scrollBar = $('.sp-reading-progress-bar');
404		if (scrollBar.length > 0) {
405			var s = $(window).scrollTop(),
406				d = $(document).height(),
407				c = $(window).height();
408			var scrollPercent = (s / (d - c)) * 100;
409			const position = scrollBar.data('position');
410			if (position === 'top') {
411				// var sticky = $('.header-sticky');
412				// if( sticky.length > 0 ){
413				//     sticky.css({ top: scrollBar.height() })
414				// }else{
415				//     sticky.css({ top: 0 })
416				// }
417			}
418			scrollBar.css({ width: `${scrollPercent}%` });
419		}
420	});
421
422	// Error Alert close issue fix for Joomla 3
423	var observer = new MutationObserver(function (mutations) {
424		$('#system-message-container .alert .close').attr('data-bs-dismiss', 'alert');
425	});
426	var target = document.querySelector('#system-message-container');
427	observer.observe(target, {
428		attributes: true
429	});
430
431
432});
433
434
435// Handle accessibility on off-canvas dropdown menus
436jQuery(function ($) {
437	const menuSelector = '.menu-deeper.menu-parent';
438	const togglerSelector = '.menu-toggler';
439	const childSelector = '.menu-child';
440
441	// Toggle submenu open/close
442	function toggleSubmenu($item, open = null) {
443		const $submenu = $item.children(childSelector);
444		const isOpen = $item.hasClass('menu-parent-open');
445
446		if (open === null) open = !isOpen;
447
448		if (open) {
449			$item.addClass('menu-parent-open').attr('aria-expanded', 'true');
450			$submenu.slideDown(150);
451		} else {
452			$item.removeClass('menu-parent-open').attr('aria-expanded', 'false');
453			$submenu.slideUp(150);
454		}
455	}
456
457	// Prevent event bubbling from toggler to link
458	$(document).on('click', togglerSelector, function (event) {
459		event.preventDefault();
460		event.stopPropagation();
461		const $item = $(this).closest(menuSelector);
462		const isOpen = $item.hasClass('menu-parent-open');
463		toggleSubmenu($item, !isOpen);
464	});
465
466	// Handle menu link click or Enter/Space key
467	$(document).on('click keydown', `${menuSelector} > a`, function (event) {
468		const isToggleKey = event.type === 'click' || event.key === 'Enter' || event.key === ' ';
469		const isKeyboard = event.key === 'Enter' || event.key === ' ';
470
471		if (isToggleKey) {
472			const $item = $(this).closest(menuSelector);
473			const $submenu = $item.children(childSelector);
474
475			// If submenu exists
476			if ($submenu.length) {
477				// If it's Space key (prevent scrolling), toggle submenu only
478				if (event.key === ' ') {
479					event.preventDefault();
480					toggleSubmenu($item);
481				}
482				// If it's Enter or click — follow link (do not preventDefault)
483				// but also toggle submenu if desired
484				else if (event.key === 'Enter') {
485					toggleSubmenu($item, true);
486
487				} else if (event.type === 'click') {
488					toggleSubmenu($item, true);
489				}
490			}
491		}
492	});
493
494	// Handle arrow key navigation
495	$(document).on('keydown', `${menuSelector} > a`, function (event) {
496		const $currentItem = $(this).closest('li');
497		const $siblings = $currentItem.parent().children('li:visible');
498		const index = $siblings.index($currentItem);
499
500		if (event.key === 'ArrowDown') {
501			event.preventDefault();
502			// If submenu is open, focus first child link
503			const $submenu = $currentItem.children(childSelector);
504			if ($submenu.length && $currentItem.hasClass('menu-parent-open')) {
505				const $firstChildLink = $submenu.children('li:visible').find('a').first();
506				if ($firstChildLink.length) {
507					$firstChildLink.focus();
508					return;
509				}
510			}
511			// Otherwise, move to next sibling
512			$siblings.eq((index + 1) % $siblings.length).find('a').first().focus();
513		} else if (event.key === 'ArrowUp') {
514			event.preventDefault();
515			// Move to previous sibling
516			$siblings.eq((index - 1 + $siblings.length) % $siblings.length).find('a').first().focus();
517		} else if (event.key === 'ArrowRight') {
518			// Open nested submenu if present
519			const $submenu = $currentItem.children(childSelector);
520			if ($submenu.length) {
521				event.preventDefault();
522				toggleSubmenu($currentItem, true);
523				const $firstChildLink = $submenu.children('li:visible').find('a').first();
524				if ($firstChildLink.length) {
525					$firstChildLink.focus();
526				}
527			}
528		} else if (event.key === 'ArrowLeft' || event.key === 'Escape') {
529			event.preventDefault();
530			// Close only the current open dropdown
531			toggleSubmenu($currentItem, false);
532			$currentItem.children('a').first().focus();
533		}
534	});
535
536	// Handle arrow key navigation inside submenu
537	$(document).on('keydown', `${childSelector} > li > a`, function (event) {
538		const $currentItem = $(this).closest('li');
539		const $siblings = $currentItem.parent().children('li:visible');
540		const index = $siblings.index($currentItem);
541
542		if (event.key === 'ArrowDown') {
543			event.preventDefault();
544			$siblings.eq((index + 1) % $siblings.length).find('a').first().focus();
545		} else if (event.key === 'ArrowUp') {
546			event.preventDefault();
547			$siblings.eq((index - 1 + $siblings.length) % $siblings.length).find('a').first().focus();
548		} else if (event.key === 'ArrowRight') {
549			// Open nested submenu if present
550			const $submenu = $currentItem.children(childSelector);
551			if ($submenu.length) {
552				event.preventDefault();
553				toggleSubmenu($currentItem, true);
554				const $firstChildLink = $submenu.children('li:visible').find('a').first();
555				if ($firstChildLink.length) {
556					$firstChildLink.focus();
557				}
558			}
559		} else if (event.key === 'ArrowLeft' || event.key === 'Escape') {
560			event.preventDefault();
561			// Close submenu and focus parent
562			const $parentMenu = $currentItem.parents(menuSelector).first();
563			toggleSubmenu($parentMenu, false);
564			$parentMenu.children('a').first().focus();
565		}
566	});
567
568	// Close all menus when clicking outside
569	$(document).on('click', function (event) {
570		if (!$(event.target).closest('.menu-deeper').length) {
571			$(menuSelector).removeClass('menu-parent-open').attr('aria-expanded', 'false');
572			$(childSelector).slideUp(150);
573		}
574	});
575
576	//mark all menu-parents as aria-haspopup
577	$(menuSelector).attr('aria-haspopup', 'true').attr('aria-expanded', 'false');
578});
579
580// Handle accessibility on megamenu and profile dropdowns
581jQuery(function ($) {
582	const menuSelectors = '.sp-megamenu-parent > li, .sp-profile-wrapper';
583
584	$(menuSelectors).each(function () {
585		const $menuItem = $(this);
586		const $trigger = $menuItem.children('a, button');
587		const $dropdown = $menuItem.children('.sp-dropdown, .sp-profile-dropdown');
588
589		if ($dropdown.length) {
590			setupDropdownEvents($menuItem, $trigger, $dropdown);
591		}
592	});
593
594	bindNestedDropdowns('body');
595
596	function setupDropdownEvents($menuItem, $trigger, $dropdown) {
597		// Show on focus or mouseenter
598		$trigger.on('focus mouseenter', function () {
599			openMenu($menuItem, $dropdown);
600		});
601
602		$menuItem.on('mouseenter', function () {
603			openMenu($menuItem, $dropdown);
604		});
605
606		// Hide on focusout or mouseleave
607		$menuItem.on('mouseleave focusout', function () {
608			setTimeout(function () {
609				if (!$menuItem.find(':focus').length && !$menuItem.is(':hover')) {
610					closeMenu($menuItem, $dropdown);
611				}
612			}, 100);
613		});
614
615		// Keyboard trigger
616		$trigger.on('keydown', function (event) {
617			switch (event.key) {
618				case ' ':
619					event.preventDefault();
620					openMenu($menuItem, $dropdown);
621					break;
622				case 'ArrowDown':
623					event.preventDefault();
624					openMenu($menuItem, $dropdown);
625					focusFirstItem($dropdown);
626					break;
627				case 'Escape':
628					event.preventDefault();
629					closeMenu($menuItem, $dropdown);
630					$trigger.focus();
631					break;
632			}
633		});
634
635		// Prevent click from toggling menu
636		$trigger.on('click', function (event) {
637			if ($dropdown.length) {
638				openMenu($menuItem, $dropdown);
639			}
640		});
641
642	}
643
644	function bindNestedDropdowns(containerSelector) {
645		$(containerSelector).find(' .sp-has-child').each(function () {
646			const $subItem = $(this);
647			const $trigger = $subItem.children('a, button');
648			const $subDropdown = $subItem.children('.sp-dropdown');
649
650			if ($subDropdown.length) {
651				setupDropdownEvents($subItem, $trigger, $subDropdown);
652				bindNestedDropdowns($subDropdown);
653			}
654		});
655	}
656
657	function openMenu($item, $dropdown) {
658		$dropdown.show();
659		// Only force display for .sp-profile-dropdown
660		if ($dropdown.hasClass('sp-profile-dropdown')) {
661			$dropdown.attr('style', 'display: block !important');
662		}
663		bindKeyboardNavigation($dropdown);
664	}
665
666	function closeMenu($item, $dropdown) {
667		$dropdown.hide();
668		// Reset style for .sp-profile-dropdown
669		if ($dropdown.hasClass('sp-profile-dropdown')) {
670			$dropdown.removeAttr('style');
671		}
672	}
673
674	function focusFirstItem($dropdown) {
675		const $focusable = $dropdown.find('a, button').filter(':visible');
676		if ($focusable.length) {
677			$focusable.first().focus();
678		}
679	}
680
681	function bindKeyboardNavigation($dropdown) {
682		const $items = $dropdown.find('a, button').filter(':visible');
683
684		$items.off('keydown').on('keydown', function (event) {
685			const currentIndex = $items.index(this);
686			let newIndex = -1;
687
688			if (event.key === 'ArrowDown') {
689				event.preventDefault();
690				newIndex = (currentIndex + 1) % $items.length;
691			} else if (event.key === 'ArrowUp') {
692				event.preventDefault();
693				newIndex = (currentIndex - 1 + $items.length) % $items.length;
694			} else if (event.key === 'Escape') {
695				event.preventDefault();
696
697				// Reset style for .sp-profile-dropdown
698				if ($dropdown.hasClass('sp-profile-dropdown')) {
699					$dropdown.removeAttr('style');
700				}
701
702				const $currentDropdown = $(this).closest('.sp-dropdown');
703				const $parentItem = $currentDropdown.parent(' .sp-has-child, .sp-megamenu-parent > li');
704
705				// Check if this is the root-level dropdown
706				const isRoot = $parentItem.parent().is('.sp-megamenu-parent, .sp-megamenu-parent > ul, nav');
707
708				if (isRoot) {
709					// Close all menus
710					$(menuSelectors).each(function () {
711						const $item = $(this);
712						closeMenu($item, $item.children('.sp-dropdown'));
713					});
714				} else {
715					// Close only current submenu and focus its trigger
716					const $trigger = $parentItem.children('a, button');
717					closeMenu($parentItem, $currentDropdown);
718					if ($trigger.length) {
719						$trigger.focus();
720					}
721				}
722				return;
723			}
724
725			if (newIndex > -1) {
726				$items.eq(newIndex).focus();
727			}
728		});
729	}
730
731	// Close all menus on outside click
732	$(document).on('click', function (event) {
733		if (!$(event.target).closest(menuSelectors).length) {
734			$(menuSelectors).each(function () {
735				const $item = $(this);
736				closeMenu($item, $item.children('.sp-dropdown'));
737			});
738		}
739	});
740
741});
742
743
744
745} catch (e) {
746console.error('Error in file:/templates/shaper_helixultimate/js/main.js; Error:' + e.message);
747};

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.