PageSourceSearch

https://www.administraciondejusticia.gob.es/o/pagaj-theme/js/parent__functions.js

js administraciondejusticia.gob.es collected 2026-09-25 14:57:37 UTC 35,134 bytes, 1,266 lines download raw bytes

1/*** VARIABLES ***/
2let	xs_bkp = getComputedStyle(document.documentElement).getPropertyValue('--xs') || 320,
3sm_bkp = getComputedStyle(document.documentElement).getPropertyValue('--sm') || 576,
4md_bkp = getComputedStyle(document.documentElement).getPropertyValue('--md') || 768,
5lg_bkp = getComputedStyle(document.documentElement).getPropertyValue('--lg') || 992,
6xl_bkp = getComputedStyle(document.documentElement).getPropertyValue('--xl') || 1200,
7
8// Get the header
9headerElem = document.querySelector('.header-basic'),
10navElem = document.querySelector('.nav-basic'),
11navWrapperElem = $(navElem).find('.nav-menu-wrapper'),
12navTitle = document.querySelector('.nav-title'),
13navAdmin = $('.control-menu-container'),
14navAdminHeight = 0,
15sticky;
16
17// Get the offset position of the navbar
18if(!!$(navElem).length){
19	if(!!$(navAdmin).length){
20		navAdminHeight = (navAdmin.outerHeight() * 2);
21	}
22	sticky = (window.innerWidth < md_bkp) ? navElem.offsetTop - navAdminHeight : 0;
23}
24
25function clickOutHideHeaderCollapse(e){
26	if(!!$(headerElem).length){
27		let targetElem = $('.header-basic .collapse.show');
28
29		if ( !($(e.target).parents('.header-basic').length && ($(e.target).parents('.collapse.show').length)))
30		{
31			targetElem.collapse("hide");
32			if(!!$(navElem).length && !!$(navWrapperElem).length) displayOverlay(e);
33		}
34	}
35}	
36
37// Add the sticky class to the header when you reach its scroll position. Remove "sticky" when you leave the scroll position
38
39function fixedHeader() {
40	if(sticky != undefined){
41		if ((window.innerWidth < Number(md_bkp)) && (window.scrollY > sticky)) {
42			$("body").css("padding-top", (sticky + navElem.offsetHeight));
43			document.body.classList.add('sticky');	
44		} else {
45			$("body").css("padding-top", "");
46			document.body.classList.remove("sticky");
47		}
48	}
49}
50
51function displayOverlay(e) {
52	if($('body').hasClass("menu-opened") ){
53		$("body").removeClass("menu-opened");
54		$('.nav-menu-wrapper').css('max-height', 'none');
55	}else{
56		let heightSignedIn = 0;
57		if($('body').hasClass("has-control-menu") ){
58			 heightSignedIn = parseInt($("#wrapper").css("marginTop").replace("px", ""));
59		}
60		let menuBarHeight = navElem.offsetHeight - document.querySelector('.nav-menu-wrapper').offsetHeight,
61		scrolling = (window.scrollY < sticky) ? navElem.offsetTop - window.scrollY : 0,
62		maxHeightMenu = window.innerHeight - (scrolling + menuBarHeight) - heightSignedIn;
63		$('.nav-menu-wrapper').css('max-height', maxHeightMenu);
64		if(e.target.classList.contains('nav-button')) $("body").addClass("menu-opened");
65	}
66}
67
68function stopAction(event) {
69	if(($(document).width() < md_bkp)){
70		event.stopPropagation();
71	}
72}
73
74
75function focusableElemsOff(){
76	$('[tabindex]').each(function(e){
77		let tabVal = $(this).attr('tabindex');
78		let dataTabindex = $(this).attr('data-tabindex');
79
80		if (typeof dataTabindex == typeof undefined){
81			$(this).attr('data-tabindex',tabVal);
82		}
83
84	});
85
86	$('a, button, input, textarea, select, details, [tabindex]:not([tabindex="-1"])').attr("tabindex", "-1");	
87}
88
89function focusableElemsOn(){
90	$('[tabindex]').each(function(e){
91		let tabVal = $(this).data('tabindex');
92		$(this).attr("tabindex", tabVal);
93	});
94}
95
96
97function headerInit(){
98	if(window.innerWidth > md_bkp) $('.header-basic .nav-item').removeClass('open');
99	if(sticky != undefined) headerElem.style.top = - sticky + 'px';
100}
101
102function languageMenuButton(){
103	$(".js-menu-button").click(function () {
104        if ($(this).attr('aria-label') == 'Mostrar\x20Menú\x20Principal')
105			$(this).attr('aria-label', 'Ocultar\x20Menú\x20Principal');
106		else
107			$(this).attr('aria-label', 'Mostrar\x20Menú\x20Principal');  
108	});
109}
110
111
112
113function accCarousel(selector) {
114    const carousels = $(selector);
115	carousels.each(function(index) {
116		$(this).on('init reInit afterChange', function(event, slick, currentSlide) {
117			$(this).find(".slick-list").appendTo($(this));
118			$(this).find(".slick-list").attr('id', 'myCarousel-items' + index );
119			$(this).find(".slick-arrow").attr('aria-controls', 'myCarousel-items' + index );
120			$(this).find('.slick-slide').attr('aria-roledescription', 'slide');
121			$(this).find('.slick-dots').attr('aria-label', 'Slides');	 				 
122			setTimeout(() => {
123				$(this).find('.slick-dots').find("button[aria-selected!='true']").attr('aria-selected', 'false');
124			}, 1000);
125		});	
126	});
127}
128
129function accLanguageSelector(orientation = 'vertical') {
130	return new accSelector({
131		container: '.select-language',
132		button: '.select-language__button',
133		list: '.select-language__list',
134		options: '.select-language__list li',
135		optionId: 'selectLanguageListItem',
136		selectedCssClass: 'active',
137		orientation
138	});
139}
140
141class accSelector {
142	selectKeys = ['Enter'];
143	closeKeys = ['Escape', 'Tab'];
144
145	optionId;
146	selectedCssClass;
147	index = -1;
148	orientation = 'vertical';
149
150	constructor(options) {
151		this.container = document.querySelector(options.container);
152		this.button = document.querySelector(options.button);
153		this.list = $(options.list);
154		this.options = document.querySelectorAll(options.options);
155		this.optionId = options.optionId;
156		this.selectedCssClass = options.selectedCssClass || 'active';
157		this.orientation = options.orientation === 'horizontal' ? 'horizontal' : 'vertical';
158
159		this.arrowKeys = this.orientation === 'horizontal'
160			? ['ArrowRight', 'ArrowLeft']
161			: ['ArrowDown', 'ArrowUp'];
162
163		if (!this.container || !this.button) {
164			return;
165		}
166
167		$(this.options).each((index, opt) => {
168			$(opt).attr('id', this.optionId + index);
169		});
170
171		$(document.body).on('click', () => {
172			this.list.hasClass('show') && this.closeList();
173		});
174
175		this.container.addEventListener('keydown', (e) => {
176			if (this.closeKeys.includes(e.key)) {
177				this.closeList();
178			}
179		});
180
181		this.button.addEventListener('keydown', this.onKeyDown.bind(this));
182	}
183
184	openList() {
185		if (!this.list.hasClass('show')) {
186			this.list.collapse('show');
187		}
188	}
189
190	closeList() {
191		this.index = -1;
192		this.list.collapse('hide');
193		this.button.setAttribute('aria-activedescendant', '');
194		$(this.options).removeClass(this.selectedCssClass);
195	}
196
197	selectItemList(key) {
198		const isForward = key === 'ArrowDown' || key === 'ArrowRight';
199		const isBackward = key === 'ArrowUp' || key === 'ArrowLeft';
200
201		if (isForward) {
202			this.index = Math.min(this.index + 1, this.options.length - 1);
203		} else if (isBackward) {
204			this.index = Math.max(this.index - 1, 0);
205		}
206
207		this.button.setAttribute('aria-activedescendant', this.optionId + this.index);
208		$(this.options).removeClass(this.selectedCssClass);
209		$(this.options[this.index]).addClass(this.selectedCssClass);
210	}
211
212	onKeyDown(e) {
213		if (!this.arrowKeys.concat(this.selectKeys).includes(e.key)) {
214			return;
215		}
216
217		e.preventDefault();
218		this.openList();
219
220		if (this.arrowKeys.includes(e.key)) {
221			this.selectItemList(e.key);
222			return;
223		}
224
225		if (this.selectKeys.includes(e.key)) {
226			if (this.index === -1) {
227				this.selectItemList(this.arrowKeys[0]);
228				return;
229			}
230			this.options[this.index].querySelector('a').click();
231			this.closeList();
232		}
233	}
234}
235
236
237class accDropdown {
238	arrowKeys = ['ArrowDown', 'ArrowUp', 'Home', 'End'];
239	selectKeys = ['Enter'];
240	closeKeys = ['Escape', 'Tab'];
241
242	optionId;
243	selectedCssClass;
244	index = -1;
245
246	constructor(options) {
247		this.container = document.querySelector(options.container);
248		this.button = document.querySelector(options.button);
249		this.listDropdown = $(options.list);
250		this.menuList = document.querySelector(options.list);
251		this.options = document.querySelectorAll(options.options);
252		this.optionId = options.optionId;
253		this.selectedCssClass = options.selectedCssClass || 'active';
254		this.menuitemNodes = [];
255		this.firstChars = [];
256		
257		let nodes = this.options;
258
259		for (let i = 0; i < nodes.length; i++) {
260			let menuitem = nodes[i];
261			this.menuitemNodes.push(menuitem);
262			menuitem.tabIndex = -1;
263			this.firstChars.push(menuitem.textContent.trim()[0].toLowerCase());
264		}
265		
266		if (!this.container || !this.button) {
267			return;
268		}
269
270		$(this.options).each((index, opt) => {
271			$(opt).attr('id', this.optionId + index);
272		});
273
274		$(document.body).on('click', (e) => {
275			this.listDropdown.hasClass('show') && this.closeList();
276		});
277		
278		$(this.options).on("mouseover", function() {
279			$(this).parent().attr("aria-activedescendant", $(this).attr('id'));
280			$(this).siblings().removeClass('active');
281			$(this).addClass('active');
282    	});
283
284		this.container.addEventListener('keydown', (e) => {
285			this.closeKeys.includes(e.key) && this.closeList();
286		});
287
288		this.button.addEventListener('keydown', this.onKeyDown.bind(this));
289		
290	}
291	
292	setFocusByFirstCharacter(char) {
293		let start, index;
294
295		if (char.length > 1) {
296			return;
297		}
298
299		char = char.toLowerCase();
300			
301		start = this.menuitemNodes.indexOf(this.options[this.index]) + 1;
302			
303		if (start >= this.menuitemNodes.length) {
304			start = 0;
305		}
306
307		index = this.firstChars.indexOf(char, start);
308			
309		if (index === -1) {
310			index = this.firstChars.indexOf(char, 0);
311		}
312
313		if (index > -1) {
314			$(this.menuList).attr("aria-activedescendant", $(this.options[index]).attr('id'));
315			$(this.options).toggleClass(this.selectedCssClass, false);
316			$(this.options[index]).toggleClass(this.selectedCssClass, true);
317			this.index = index;
318		}
319	}
320
321	#openListDropdown() {
322		if (!this.listDropdown.hasClass('show')) {
323			this.listDropdown.collapse('show');
324		}
325	}
326
327	closeList() {
328		this.index = -1;
329		this.listDropdown.collapse('hide');
330		this.menuList.setAttribute('aria-activedescendant', '');
331		$(this.options).toggleClass(this.selectedCssClass, false);
332	}
333
334	selectItemList(key) {
335		if (key === 'ArrowDown') {
336			if (this.index == this.options.length - 1){
337				this.index = 0;
338			} else {
339				this.index = Math.min(this.index + 1, this.options.length - 1);
340			}	
341		} else if(key === 'ArrowUp') {
342			if (this.index == 0){
343				this.index = this.options.length - 1;
344			} else {
345				this.index = Math.max(this.index - 1, 0);
346			}
347		}
348		if (key === 'Home') {
349		  this.index = 0;
350		}
351		if (key === 'End') {
352		  this.index = this.options.length - 1;
353		}
354			
355		this.menuList.setAttribute('aria-activedescendant', this.optionId + this.index);
356		$(this.options).toggleClass(this.selectedCssClass, false);
357		$(this.options[this.index]).toggleClass(this.selectedCssClass, true);
358	}
359
360	onKeyDown(e) {
361
362		function isPrintableCharacter(str) {
363			return str.length === 1 && str.match(/\S/);
364		}
365		
366	  	if(isPrintableCharacter(e.key)) {
367         	this.setFocusByFirstCharacter(e.key);;
368    	}
369	  
370		if (!this.arrowKeys.concat(this.selectKeys).includes(e.key)) {
371			return;
372		}
373
374		e.preventDefault();
375		this.#openListDropdown();
376
377		if (this.arrowKeys.includes(e.key)) {
378      	
379			if (this.index === -1 && e.key == 'ArrowUp'){
380			this.index = this.options.length - 1;
381			this.menuList.setAttribute('aria-activedescendant', this.optionId + this.index);
382			$(this.options).toggleClass(this.selectedCssClass, false);
383		    $(this.options[this.index]).toggleClass(this.selectedCssClass, true);
384				return;
385			}
386			
387			this.selectItemList(e.key);
388			return;
389		}
390		
391		if (!this.selectKeys.includes(e.key)) {
392			return;
393		}
394		
395		if (this.index === -1) {
396			this.selectItemList('ArrowDown');
397			return;
398		}
399		
400		this.options[this.index].querySelector('a').click();
401		this.closeList();
402	}
403}
404
405class AccAccordion {
406	constructor(accordionSelector) {
407		this.accordion = $(accordionSelector);
408		this.focusableElements = this.accordion.find('button[data-toggle="collapse"]');
409		this.firstFocusableElement = this.focusableElements.first();
410		this.lastFocusableElement = this.focusableElements.last();
411
412		this.bindEvents();
413	}
414
415	bindEvents() {
416		this.accordion.on('keydown', (e) => this.onKeyDown(e));
417	}
418	
419	onKeyDown(e) {
420		if (e.key === 'ArrowUp'){
421				if ($(document.activeElement).is(this.firstFocusableElement)) {
422					e.preventDefault();
423					this.lastFocusableElement.focus();
424				} else {
425				  e.preventDefault();
426					$(document.activeElement).closest('.card').prev().find('button[data-toggle="collapse"]').focus();
427				}
428		} else if (e.key === 'ArrowDown'){ // Solo Tab
429				if ($(document.activeElement).is(this.lastFocusableElement)) {
430					e.preventDefault();
431					this.firstFocusableElement.focus();
432				} else {
433				  e.preventDefault();
434					$(document.activeElement).closest('.card').next().find('button[data-toggle="collapse"]').focus();
435				}
436		} else if (e.key === 'Home') {
437		  e.preventDefault();
438			this.firstFocusableElement.focus();
439		} else if (e.key === 'End') {
440		  e.preventDefault();
441			this.lastFocusableElement.focus();
442		}
443	}
444}
445
446class accTablist {
447	constructor(options) {
448		this.container = document.querySelector(options.container);
449
450		this.vertical = options.vertical;
451		this.automatic = options.automatic;
452		this.selectionFn = this.automatic ? 'setSelectedTab' : 'moveFocusToTab';
453
454		this.firstTab = null;
455		this.lastTab = null;
456
457		this.tabs = Array.from(this.container.querySelectorAll('[role=tab]'));
458		this.tabpanels = new Map();
459
460		for (const tab of this.tabs) {
461			const tabpanelid = tab.getAttribute('aria-controls');
462			const tabpanel = document.getElementById(tabpanelid);
463
464			if (tabpanel) {
465				this.tabpanels.set(tabpanelid, tabpanel);
466			}
467
468			tab.tabIndex = -1;
469			tab.setAttribute('aria-selected', 'false');
470			tab.addEventListener('keydown', this.onKeydown.bind(this));
471			tab.addEventListener('click', this.onClick.bind(this));
472
473			if (!this.firstTab) {
474				this.firstTab = tab;
475			}
476			this.lastTab = tab;
477		}
478
479		this.setSelectedTab(this.firstTab, !this.automatic);
480	}
481
482	setSelectedTab(currentTab, setFocus) {
483		if (typeof setFocus !== 'boolean') {
484			setFocus = true;
485		}
486		for (const tab of this.tabs) {
487			
488			if (currentTab === tab) {
489				tab.setAttribute('aria-selected', 'true');
490				tab.removeAttribute('tabindex');
491				if (setFocus) {
492					tab.focus();
493					tab.click();
494				}
495			} else {
496				tab.setAttribute('aria-selected', 'false');
497				tab.tabIndex = -1;
498			}
499		}
500	}
501
502	setSelectedToPreviousTab(currentTab) {
503		if (currentTab === this.firstTab) {
504			this[this.selectionFn](this.lastTab);
505		} else {
506			const index = this.tabs.indexOf(currentTab);
507			this[this.selectionFn](this.tabs[index - 1]);
508		}
509	}
510
511	setSelectedToNextTab(currentTab) {
512		if (currentTab === this.lastTab) {
513			this[this.selectionFn](this.firstTab);
514		} else {
515			const index = this.tabs.indexOf(currentTab);
516			this[this.selectionFn](this.tabs[index + 1]);
517		}
518	}
519
520	moveFocusToTab(currentTab) {
521		currentTab.focus();
522	}
523
524	onClick(event) {
525		this.setSelectedTab(event.currentTarget, false);
526	}
527
528	onKeydown(event) {
529		const tgt = event.currentTarget;
530		let flag = false;
531
532		const previousKey = this.vertical ? 'ArrowUp' : 'ArrowLeft';
533		const nextKey = this.vertical ? 'ArrowDown' : 'ArrowRight';
534
535		switch (event.key) {
536			case previousKey:
537				this.setSelectedToPreviousTab(tgt);
538				flag = true;
539				break;
540
541			case nextKey:
542				this.setSelectedToNextTab(tgt);
543				flag = true;
544				break;
545
546			case 'Home':
547				this[this.selectionFn](this.firstTab);
548				flag = true;
549				break;
550
551			case 'End':
552				this[this.selectionFn](this.lastTab);
553				flag = true;
554				break;
555
556			default:
557				break;
558		}
559
560		if (flag) {
561			event.stopPropagation();
562			event.preventDefault();
563		}
564	}
565}
566
567function navigationCustomMenuDropdown(){
568	let btnToggle = $('.navbar-custom .menu-btn-toggle'),
569		navBtn = $('.navbar-custom .nav-button'),
570		childMenu = $('.navbar-custom .child-menu'),
571		myMenu = $('.navbar-custom');
572
573	btnToggle.click(function(){
574		if (myMenu.hasClass("navbar-third-level")) {
575			if($(this).parent().hasClass("item-menu-2")){
576				$(this).parent().parent().parent().siblings('.nav-item').find('.child-menu').hide();
577				$(this).parent().parent().parent().siblings('.nav-item').find('.menu-btn-toggle').removeClass('open');  
578			}
579
580				 if($(this).parent().parent().hasClass("navbar-custom")){
581						$(this).parent().siblings('.nav-item').find('.child-menu').hide();
582						$(this).parent().siblings('.nav-item').find('.menu-btn-toggle').removeClass('open');   
583				 }
584
585			   if($(this).hasClass("open")){
586						$(this).next().find('.child-menu').hide("slow"); 
587						$(this).next().find('.menu-btn-toggle').removeClass('open');   
588			   }
589
590		   $(this).next('.child-menu').slideToggle();
591		   $(this).toggleClass('open');
592		} else {
593			$(this).parents().siblings('.nav-item').children('.child-menu').hide('slow'); 
594			$(this).next('.child-menu').slideToggle();
595			$(this).toggleClass('open');
596			btnToggle.not(this).removeClass('open');
597		}
598   });
599
600	navBtn.click(function(){
601		childMenu.hide();
602		btnToggle.removeClass('open');
603	});
604}
605
606function navigationCustomMenuInit(){
607	let navItem = $('.navbar-custom .nav-item'),
608	   childMenu = $('.navbar-custom .child-menu');
609
610	if($(window).width() > 767){
611		navItem.addClass('dropdown');
612		childMenu.removeAttr('style');
613	}else{
614		navItem.removeClass('dropdown');
615	}
616}
617
618function custMenuThirdLevel() {
619	const KEY = { ESC: 27, LEFT: 37, UP: 38, RIGHT: 39, DOWN: 40 };
620	const menuBar = Array.from(document.querySelectorAll(".navbar-third-level > li"));
621	let justOpenedSubmenu = false;
622	const getDirectAnchor = (li) =>
623	  li.querySelector(':scope > a[role="menuitem"], :scope > a');
624	const getDirectSubmenu = (li) =>
625	  li.querySelector(':scope > ul.child-menu');
626	const getSubmenuItems = (li) => {
627	  const ul = getDirectSubmenu(li);
628	  return ul ? Array.from(ul.querySelectorAll(':scope > li > a[role="menuitem"], :scope > li > a')) : [];
629	};
630  
631	function openSubMenu(li) {
632	  li.classList.add("hover", "open");
633	  const ul = getDirectSubmenu(li);
634	  if (ul) {
635		ul.classList.add("open", "show");
636		ul.setAttribute("aria-expanded", "true");
637	  }
638	}
639	function closeSubMenu(li) {
640	  li.classList.remove("hover", "open");
641	  const ul = getDirectSubmenu(li);
642	  if (ul) {
643		ul.classList.remove("open", "show");
644		ul.setAttribute("aria-expanded", "false");
645	  }
646	}
647	function closeOtherSubMenus(currentLi) {
648	  menuBar.forEach((li) => {
649		if (li !== currentLi) closeSubMenu(li);
650	  });
651	}
652  
653	const focusNext = (items, i) => items[(i + 1) % items.length].focus();
654	const focusPrev = (items, i) => items[(i - 1 + items.length) % items.length].focus();
655
656	menuBar.forEach((li) => {
657	  const a = getDirectAnchor(li);
658	  if (a) a.setAttribute("tabindex", "0");
659	});
660	document.querySelectorAll(".link-menu-2, .link-menu-3").forEach((a) => {
661	  a.setAttribute("tabindex", "-1");
662	});
663  
664	menuBar.forEach((li, liIndex) => {
665	  	const anchor = getDirectAnchor(li);
666	  	if (!anchor) return;
667	  	anchor.addEventListener("keydown", (e) => {
668			if (justOpenedSubmenu) {
669				justOpenedSubmenu = false;
670				e.preventDefault();
671				e.stopPropagation();
672				return false;
673			}
674  
675			switch (e.which) {
676				case KEY.RIGHT: {
677					e.preventDefault();
678					e.stopPropagation();
679					const nextIndex = (liIndex + 1) % menuBar.length;
680					const targetLi = menuBar[nextIndex];
681					closeSubMenu(li);
682					closeOtherSubMenus(targetLi);
683					const targetA = getDirectAnchor(targetLi);
684					if (targetA) targetA.focus();
685					return false;
686				}
687	
688				case KEY.LEFT: {
689					e.preventDefault();
690					e.stopPropagation();
691					const prevIndex = (liIndex - 1 + menuBar.length) % menuBar.length;
692					const targetLi = menuBar[prevIndex];
693					closeSubMenu(li);
694					closeOtherSubMenus(targetLi);
695					const targetA = getDirectAnchor(targetLi);
696					if (targetA) targetA.focus();
697					return false;
698				}
699	
700				case KEY.DOWN: {
701					e.preventDefault();
702					e.stopPropagation();
703					const sub = getDirectSubmenu(li);
704					if (sub) {
705						closeOtherSubMenus(li);
706						openSubMenu(li);
707						const items = getSubmenuItems(li);
708						if (items.length) {
709							items[0].focus();
710							justOpenedSubmenu = true;
711						}
712					}
713					return false;
714				}
715	
716				case KEY.UP: {
717					e.preventDefault();
718					e.stopPropagation();
719					const sub = getDirectSubmenu(li);
720					if (sub) {
721						closeOtherSubMenus(li);
722						openSubMenu(li);
723						const items = getSubmenuItems(li);
724						if (items.length) {
725							items[items.length - 1].focus();
726							justOpenedSubmenu = true;
727						}
728					}
729					return false;
730				}
731	
732				default:
733				break;
734			}
735	  	});
736	});
737  
738	document.querySelectorAll(".link-menu-2, .link-menu-3").forEach((a) => {
739		a.addEventListener("keydown", (e) => {
740			const li = a.parentElement;
741			const ul = li.parentElement;
742			const siblings = Array.from(ul.querySelectorAll(':scope > li > a[role="menuitem"], :scope > li > a'));
743			const idx = siblings.indexOf(a);
744			const isLevel2 = a.classList.contains("link-menu-2");
745			const isLevel3 = a.classList.contains("link-menu-3");
746  
747			switch (e.which) {
748				case KEY.ESC: {
749					e.preventDefault();
750					e.stopPropagation();
751					const parentLi = ul.parentElement;
752					closeSubMenu(parentLi);
753					const trigger = getDirectAnchor(parentLi);
754					if (trigger) trigger.focus();
755					return false;
756				}
757	
758				case KEY.DOWN: {
759					e.preventDefault();
760					e.stopPropagation();
761					focusNext(siblings, idx);
762					return false;
763				}
764	
765				case KEY.UP: {
766					e.preventDefault();
767					e.stopPropagation();
768					focusPrev(siblings, idx);
769					return false;
770				}
771	
772				case KEY.RIGHT: {
773					e.preventDefault();
774					e.stopPropagation();
775		
776					const childMenu = li.querySelector(':scope > ul.child-menu');
777					if (childMenu) {
778						openSubMenu(li);
779						const childItems = Array.from(childMenu.querySelectorAll(':scope > li > a[role="menuitem"], :scope > li > a'));
780						if (childItems.length) childItems[0].focus();
781					} 
782					else if (isLevel2) {
783						const topLi = ul.parentElement;
784						const mainLis = Array.from(topLi.parentElement.children);
785						const topIndex = mainLis.indexOf(topLi);
786						const nextTopIndex = (topIndex + 1) % mainLis.length;
787						const targetTopLi = mainLis[nextTopIndex];
788			
789						closeSubMenu(topLi);
790						closeOtherSubMenus(targetTopLi);
791			
792						const targetTopA = getDirectAnchor(targetTopLi);
793						if (targetTopA) {
794							targetTopA.focus();
795							justOpenedSubmenu = false;
796						}
797			
798						if (getDirectSubmenu(targetTopLi)) {
799							openSubMenu(targetTopLi);
800						}
801					}
802					return false;
803				}
804	
805				case KEY.LEFT: {
806					e.preventDefault();
807					e.stopPropagation();
808		
809					if (isLevel3) {
810						const parentL2Li = ul.parentElement;
811						closeSubMenu(parentL2Li);
812						const l2Anchor = getDirectAnchor(parentL2Li);
813						if (l2Anchor) l2Anchor.focus();
814					} 
815					else {
816						const parentL1Li = ul.parentElement;
817						closeSubMenu(parentL1Li);
818						const l1Anchor = getDirectAnchor(parentL1Li);
819						if (l1Anchor) {
820							l1Anchor.focus();
821							justOpenedSubmenu = false;
822						}
823					}
824					return false;
825				}
826				default:
827				break;
828			}
829	  	});
830	});
831}
832
833function loadSpinner(){
834	let loader = document.createElement("div");
835	loader.id = 'loader';
836	loader.innerHTML = "<div class='spinner'></div>";
837	if(!$('body #loader').length){
838		$('body').append(loader);
839	}
840}
841
842function removeSpinner(){
843	$('#loader').remove();
844}
845
846class AccModal {
847	constructor(modalSelector, onSaveCallback = null) {
848		this.modal = $(modalSelector);
849		this.focusableElements = this.modal.find('button, [href], input, select, textarea, [tabindex]:not
849([tabindex="-1"])');
850		this.firstFocusableElement = this.focusableElements.first();
851		this.lastFocusableElement = this.focusableElements.last();
852		this.onSaveCallback = onSaveCallback;
853
854		this.bindEvents();
855	}
856
857	bindEvents() {
858		this.modal.on('shown.bs.modal', (e) => this.onModalShown(e));
859		this.modal.on('hidden.bs.modal', (e) => this.onModalHidden(e));
860
861		this.modal.on('keydown', (e) => this.onKeyDown(e));
862
863		this.modal.find('[data-action="confirm"]').on('click', () => this.onSave());
864	}
865
866	onModalShown(e) {
867		this.focusElement = this.modal.find('[data-focus="true"]').first();
868
869		if (this.focusElement.length && !this.focusableElements.is(this.focusElement)) {
870			this.focusElement.attr('tabindex', '-1');
871		}
872
873		let dismissElement = this.modal.find('[data-dismiss="modal"]').first();
874
875		this.toFocusFirst = this.focusElement.length ? this.focusElement : ( dismissElement.length ? dismissElement : this.firstFocusableElement );
876
877		if (this.toFocusFirst.length) {
878			this.toFocusFirst.focus();
879		}
880	}
881	
882	onModalHidden(e) { //Prevents error by focus in an aria-hidden=true element due to Bootstrap behaviour
883		this.modal.removeAttr("aria-hidden").attr("aria-modal","true");
884	}
885
886	onKeyDown(e) {
887		if (e.key === 'Tab' || e.keyCode === 9){
888			if (e.shiftKey) { // Shift + Tab
889				if ($(document.activeElement).is(this.firstFocusableElement)) {
890					e.preventDefault();
891					this.lastFocusableElement.focus();
892				}
893			} else { // Solo Tab
894				if ($(document.activeElement).is(this.lastFocusableElement)) {
895					e.preventDefault();
896					this.firstFocusableElement.focus();
897				}
898			}
899		}
900	}
901
902	onSave() {
903		if (typeof this.onSaveCallback === 'function') {
904			this.onSaveCallback();
905		}
906	}
907}
908
909class AccTooltip {
910	constructor(el = '[data-toggle="tooltip"]') {
911		this.el = $(el);
912		
913		this.el.tooltip();
914		
915		this.bindEvents();
916	}
917
918	bindEvents() {
919		this.el.on('keydown', (e) => this.onKeyDown(e));
920	}
921
922	onKeyDown(e) {
923		if (e.key === 'Escape' || e.keyCode === 27){
924			this.el.tooltip('hide');
925		}
926	}
927}
928
929const MJUCookies = (function (){
930
931	function translationsConfig() {
932		const DEFAULT = 'Es\x20necesario\x20aceptar\x20las\x20cookies\x20para\x20visualizar\x20este\x20contenido';
933		const NECESSARY = 'Es\x20necesario\x20aceptar\x20las\x20cookies\x20obligatorias\x20para\x20visualizar\x20este\x20contenido';
934		const FUNCTIONAL = 'Es\x20necesario\x20aceptar\x20las\x20cookies\x20funcionales\x20para\x20visualizar\x20este\x20contenido';
935		const PERFORMANCE = 'Es\x20necesario\x20aceptar\x20las\x20cookies\x20de\x20rendimiento\x20para\x20visualizar\x20este\x20contenido';
936		const PERSONALIZATION = 'Es\x20necesario\x20aceptar\x20las\x20cookies\x20de\x20personalización\x20para\x20visualizar\x20este\x20contenido';
937
938		return {
939			text: {
940				DEFAULT,
941				NECESSARY: NECESSARY !== 'cookies.blocked-content.text.necessary' ? NECESSARY : DEFAULT,
942				FUNCTIONAL: FUNCTIONAL !== 'cookies.blocked-content.text.functional' ? FUNCTIONAL : DEFAULT,
943				PERFORMANCE: PERFORMANCE !== 'cookies.blocked-content.text.performance' ? PERFORMANCE : DEFAULT,
944				PERSONALIZATION: PERSONALIZATION !== 'cookies.blocked-content.text.personalization' ? PERSONALIZATION : DEFAULT
945			},
946			action: 'Revisar\x20mi\x20elección',
947			accessibility: 'Revisar\x20mi\x20elección\x20de\x20configuración\x20de\x20cookies'
948		}
949	}
950
951	const COOKIE_TYPES = {
952		FUNCTIONAL: 'CONSENT_TYPE_FUNCTIONAL',
953		NECESSARY: 'CONSENT_TYPE_NECESSARY',
954		PERFORMANCE: 'CONSENT_TYPE_PERFORMANCE',
955		PERSONALIZATION: 'CONSENT_TYPE_PERSONALIZATION'
956	};
957
958	const DEFAULT_OPTS = {
959		type: null, // ['NECESSARY', 'FUNCTIONAL', 'PERFORMANCE', 'PERSONALIZATION']
960		blockedCookiesMessageHTML: { // {NECESSARY:'', FUNCTIONAL:'', PERFORMANCE:'', PERSONALIZATION:''}
961			default: `
962				<div class="mj-blocked-cookies">
963					<div class="mj-blocked-cookies-text text-center">
964						<p>%TEXT%</p>
965						<button class="btn btn-link mj-blocked-cookies-button" aria-label="%ACCESSIBILITY%">
966							%ACTION%
967						</button>
968					</div>
969				</div>
970			`
971		},
972		blockedCookiesMessageActionSelector: '.mj-blocked-cookies-button',
973		blockedCookiesMessageActionOnClickFn: function() {
974			$('[id$="CookiesBannerPortlet_configurationButton"]').click();
975		},
976		cookiesBannerSelector: '.cookies-banner',
977		lang: translationsConfig()
978	};
979
980	const COOKIE_CONSENT_COOKIE_ATTR = 'data-third-party-cookie';
981	const COOKIE_CONSENT_MESSAGE_ATTR = 'data-third-party-cookie-message';
982	const COOKIE_CONSENT_FLIPPED_ATTR = 'data-third-party-cookie-flipped';
983
984	let opts, cookieTypes, isCheckingCookies, blockedCookiesMessages, cookiesConsentLast;
985
986	function showBlockedCookiesHtml(type, element) {
987		switch (element.tagName.toUpperCase()) {
988			case 'EMBED': case 'IFRAME': case 'IMG': {
989				const blockedCookiesMessage =
990					(opts.blockedCookiesMessageHTML[type] || opts.blockedCookiesMessageHTML.default)
991						.replace(/%TEXT%/g, opts.lang.text[type] || opts.lang.text.DEFAULT)
992						.replace(/%ACTION%/g, opts.lang.action)
993						.replace(/%ACCESSIBILITY%/g, opts.lang.accessibility);
994
995				const node = $(blockedCookiesMessage);
996				blockedCookiesMessages.set(type, (blockedCookiesMessages.get(type) || []).concat(node));
997				$(element).after(node);
998				break;
999			}
1000			default:
1001		}
1002	}
1003
1004	function hideBlockedCookiesHtml(type) {
1005		for (const node of (blockedCookiesMessages.get(type) || [])) {
1006			node.remove();
1007		}
1008		blockedCookiesMessages.delete(type);
1009	}
1010
1011	function checkCookiesConsent() {
1012		let consent = new Map();
1013		Object.entries(cookieTypes).forEach((type) => {
1014			const value = Liferay.Util.Cookie.get(type[1]) === "true";
1015			consent.set(type[0], value);
1016		});
1017		return consent;
1018	}
1019
1020	function checkCookies() {
1021		const cookiesConsent = checkCookiesConsent();
1022
1023		Object.entries(cookieTypes).forEach((type) => {
1024			const cookieConsent = cookiesConsent.get(type[0]);
1025
1026			const selector = `[${COOKIE_CONSENT_COOKIE_ATTR}="${type[1]}"]`;
1027
1028			$(selector).each(function () {
1029				const hasMessage = this.hasAttribute(COOKIE_CONSENT_MESSAGE_ATTR);
1030				const hasFlipped = this.hasAttribute(COOKIE_CONSENT_FLIPPED_ATTR);
1031
1032				const show = !cookieConsent && !hasMessage && !hasFlipped;
1033				const hide = cookieConsent && hasMessage && hasFlipped;
1034
1035				if(show) {
1036					showBlockedCookiesHtml(type[0], this);
1037					this.setAttribute(COOKIE_CONSENT_MESSAGE_ATTR, '');
1038				}
1039				else if (hide) {
1040					hideBlockedCookiesHtml(type[0]);
1041					this.removeAttribute(COOKIE_CONSENT_MESSAGE_ATTR);
1042				}
1043			});
1044		});
1045
1046		cookiesConsentLast = structuredClone(cookiesConsent);
1047	}
1048
1049	function init(_opts) {
1050		opts = $.extend(true, {}, DEFAULT_OPTS, _opts);
1051
1052		if (!$(opts.cookiesBannerSelector).length || isCheckingCookies) return;
1053
1054		blockedCookiesMessages = new Map();
1055		cookiesConsentLast = new Map();
1056
1057		cookieTypes = Object.fromEntries(
1058			Object.entries(COOKIE_TYPES).filter(([k]) => !opts.type?.length || opts.type.includes(k))
1059		);
1060
1061		$(document).on('click', opts.blockedCookiesMessageActionSelector, opts.blockedCookiesMessageActionOnClickFn);
1062
1063		const observer = new MutationObserver(checkCookies);
1064
1065		observer.observe(document, {
1066			attributes: true,
1067			attributeFilter: [COOKIE_CONSENT_FLIPPED_ATTR],
1068			subtree: true
1069		});
1070
1071		const checkCookiesInterval = function (interval) {
1072			if (interval < 7000) {
1073				interval += 500;
1074			}
1075			if (isCheckingCookies) {
1076				checkCookies();
1077				setTimeout(() => checkCookiesInterval(interval), interval);
1078			}
1079		}
1080
1081		isCheckingCookies = true;
1082
1083		checkCookiesInterval(2000);
1084	}
1085
1086	return { init };
1087
1088})();
1089
1090$(document).ready(function() {
1091	// Añadiendo la clase custom-facet-collapsed al portlet, en su configuración del aspecto e interacción/Estilos avanzados, conseguiremos que la faceta aparezca collapsada al cargar la página
1092	if($('.custom-facet-collapsed').length){
1093		$('.custom-facet-collapsed').find('.panel-header-link').attr('aria-expanded', false).addClass('collapsed');
1094		$('.custom-facet-collapsed').find('.collapse').removeClass('show');
1095	}
1096});
1097
1098class accCombobox {
1099	constructor(options) {
1100		this.container = document.querySelector(options.container);
1101		this.button = this.container.querySelector(options.button);
1102		this.list = this.container.querySelector(options.list);
1103		this.options = this.container.querySelectorAll(options.options);
1104		this.optionId = options.optionId;
1105		this.selectedCssClass = options.selectedCssClass || 'active';
1106		this.index = -1;
1107		this.menuitemNodes = [];
1108		this.firstChars = [];
1109	
1110		this.init();
1111	}
1112
1113	init() {
1114		this.options.forEach((option, index) => {
1115			this.menuitemNodes.push(option);
1116			option.setAttribute("id", `${this.optionId}${index}`);
1117			option.tabIndex = -1;
1118	
1119			const text = option.textContent.trim();
1120			if (text) {
1121				this.firstChars.push(text[0].toLowerCase());
1122			}
1123		});
1124		
1125		this.addEventListeners();
1126		
1127	}
1128
1129	addEventListeners() {
1130		this.button.addEventListener("click", (event) => {
1131			this.toggleDropdown();
1132			event.stopImmediatePropagation();
1133		});
1134
1135		this.button.addEventListener("keydown", (event) => {
1136			this.onKeyDown(event);
1137			event.stopImmediatePropagation();
1138		});
1139
1140		this.options.forEach((option) => {
1141			option.addEventListener("click", (event) => {
1142				this.selectOption(option);
1143				event.stopImmediatePropagation();
1144			});
1145		});
1146
1147		document.addEventListener("click", (event) => {
1148			if (!this.container.contains(event.target)) {
1149				this.closeDropdown();
1150			}
1151		});
1152	}
1153
1154	toggleDropdown() {
1155		this.list.classList.contains("show") ? this.closeDropdown() : this.openDropdown();
1156	}
1157
1158	openDropdown() {
1159		this.list.classList.add("show");
1160		this.button.setAttribute("aria-expanded", "true");
1161	}
1162
1163	closeDropdown() {
1164		this.list.classList.remove("show");
1165		this.button.setAttribute("aria-expanded", "false");
1166		this.index = -1;
1167	}
1168
1169	updateActiveOption(index) {
1170		this.options.forEach((option, i) => {
1171			option.classList.toggle(this.selectedCssClass, i === index);
1172		});
1173		this.button.setAttribute("aria-activedescendant", this.options[index]?.id || "");
1174		this.index = index;
1175	}
1176
1177	setFocusByFirstCharacter(char) {
1178		if (char.length > 1) return;
1179	
1180		char = char.toLowerCase();
1181		let start = this.index + 1 >= this.menuitemNodes.length ? 0 : this.index + 1;
1182		let matchIndex = this.firstChars.indexOf(char, start);
1183	
1184		if (matchIndex === -1) {
1185			matchIndex = this.firstChars.indexOf(char, 0);
1186		}
1187	
1188		if (matchIndex > -1) {
1189			if (!this.list.classList.contains("show")) this.openDropdown();
1190			this.updateActiveOption(matchIndex);
1191		}
1192	}
1193
1194	jumpByPage(key) {
1195		if (!this.list.classList.contains("show")) {
1196			this.openDropdown();
1197		}
1198	
1199		let jump = 10;
1200		if (key === "PageUp") {
1201			this.index = Math.max(0, this.index - jump);
1202		} else if (key === "PageDown") {
1203			this.index = Math.min(this.options.length - 1, this.index + jump);
1204		}
1205	
1206		this.updateActiveOption(this.index);
1207	}
1208
1209	onKeyDown(event) {
1210		const keys = { ArrowDown: 1, ArrowUp: -1, Home: "first", End: "last" };
1211
1212		if (event.key.length === 1 && event.key.match(/\S/)) {
1213			this.setFocusByFirstCharacter(event.key);
1214			return;
1215		}
1216
1217		if (event.key in keys) {
1218			event.preventDefault();
1219			if (!this.list.classList.contains("show")) this.openDropdown();
1220
1221			if (keys[event.key] === "first") {
1222				this.index = 0;
1223			}
1224			else if (keys[event.key] === "last") {
1225				this.index = this.options.length - 1;
1226			}
1227			else {
1228				this.index = Math.max(0, Math.min(this.index + keys[event.key], this.options.length - 1));
1229			}
1230
1231			this.updateActiveOption(this.index);
1232		}
1233
1234		if (event.key === "Enter" || event.key === "Space" || (event.altKey && event.key === "ArrowUp") || event.key === " ") {
1235			event.preventDefault();
1236			if (!this.list.classList.contains("show")) {
1237				this.openDropdown();
1238			}
1239			if (this.index >= 0) {
1240				this.selectOption(this.options[this.index]);
1241			}
1242		}
1243
1244		if (event.key === "Tab") {
1245			if (this.index >= 0) {
1246				this.selectOption(this.options[this.index]);
1247			}
1248		}
1249
1250		if (event.key === "Escape") {
1251			this.closeDropdown();
1252		}
1253
1254		if (event.key === "PageUp" || event.key === "PageDown") {
1255			event.preventDefault();
1256			this.jumpByPage(event.key);
1257		}
1258	}
1259
1260	selectOption(option) {
1261		this.button.innerText = option.innerText;
1262		this.button.setAttribute("aria-activedescendant", option.id);
1263		this.index = Array.from(this.options).indexOf(option);
1264		this.closeDropdown();
1265	}
1266}

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.