PageSourceSearch

https://ine.es/menus/_b/js/component/components.js?L=0&crrsl=1&ilp=1&pnls=1&smap=1&emap=1&sv=1&sshow=1

js ine.es collected 2026-10-01 07:31:41 UTC 74,046 bytes, 1,975 lines download raw bytes

1document.addEventListener('DOMContentLoaded', function (){
2	ine.carrousel();
3});
4
5ine.carrousel = function(){
6	ine.carrousel.remove();
7
8	//Creación y asignación de clases de las capas necesarias para el componente
9	let carrouselComponent = document.querySelector('.carrouselComponent');
10	let Citem = document.querySelector('.carrouselComponent > *');
11	let Citems = document.querySelectorAll('.carrouselComponent > *');
12	let carrouselGalery = document.createElement('div');
13	let carrouselButtons = document.createElement('div');
14
15	if (carrouselComponent){
16		carrouselGalery.classList.add("loading");
17		carrouselComponent.appendChild(carrouselGalery);
18		carrouselComponent.appendChild(carrouselButtons);
19
20		let lang = {
21	"prev": "Anterior",
22	"next": "Posterior"
23};
24
25		let btnL = document.createElement('button');
26		btnL.setAttribute("aria-label", lang.prev);
27		btnL.appendChild(document.createElement('i'))
28		carrouselButtons.appendChild(btnL);
29		let btnR = document.createElement('button');
30		btnR.setAttribute("aria-label", lang.next);
31		btnR.appendChild(document.createElement('i'))
32		carrouselButtons.appendChild(btnR);
33
34		Citems.forEach(function (item, idx){ carrouselGalery.appendChild(item); item.dataset.index = idx; })
35
36		carrouselButtons.classList.add("carrouselButtons");
37		carrouselGalery.classList.add("carrouselGallery");
38
39		//Funcionamiento del componente
40		let variable = true;
41		let specialScroll = false;
42		let deleteButtons = false;
43		let nItemsCarrousel = Number(getComputedStyle(carrouselGalery.parentElement).getPropertyValue('--carrousel-NumElementos'));
44
45		if (Citems.length == nItemsCarrousel + 1) specialScroll = true;
46		if (Citems.length <= nItemsCarrousel)     deleteButtons = true;
47
48		// Definición y funcionalidad botones 
49		btnL.onclick = function (){
50			ine.carrousel.lock(this);
51
52			let noInf = this.closest(".no-infinite");
53			let first = ine.carrousel.getFirst(carrouselGalery);
54
55			if(first.dataset.index == 0 && noInf){
56				return;
57			}
58
59			if (variable && specialScroll){
60				carrouselGalery.scrollLeft = 0;
61				variable = false;
62			} else {
63				carrouselGalery.insertBefore(Citems[Citems.length - 1], Citems[0]);
64				Citems = document.querySelectorAll('.carrouselGallery > *');
65				if (specialScroll){
66					carrouselGalery.scrollLeft = 0;
67				} else {
68					carrouselGalery.scrollLeft = Citem.scrollWidth;
69				}
70			}
71
72			if(noInf){
73				this.style.display = "";
74				this.nextElementSibling.style.display = "";
75				if(parseInt(first.dataset.index) <= 1){
76					this.style.display = "none"
77				}
78			}
79		}
80		
81		if(btnL.closest(".no-infinite")) btnL.style.display = "none";
82
83		btnR.onclick = function (){
84			ine.carrousel.lock(this);
85
86			let noInf = this.closest(".no-infinite");
87			let last  = ine.carrousel.getLast(carrouselGalery);
88		
89			if(ine.isVisible(ine.carrousel.getLast(carrouselGalery)) && noInf){
90				return;
91			}
92
93			if (!variable && specialScroll){
94				carrouselGalery.scrollLeft = Citem.scrollWidth;
95				variable = true;
96			} else {
97				carrouselGalery.appendChild(Citems[0]);
98				Citems = document.querySelectorAll('.carrouselGallery > *');
99				carrouselGalery.scrollLeft = Citem.scrollWidth;
100			}
101
102			if(noInf){
103				this.style.display = "";
104				this.previousElementSibling.style.display = "";
105				if(last.dataset.index == Citems[nItemsCarrousel].dataset.index){
106					this.style.display = "none"
107				}
108			}
109		}
110
111		//inicialización de la presentación
112		carrouselGalery.insertBefore(Citems[Citems.length - 1], Citems[0]);
113		Citems = document.querySelectorAll('.carrouselGallery > *');
114		carrouselGalery.scrollLeft = Citem.scrollWidth;
115
116		//En caso de que se necesiten eliminar los botones (mismos elementos totales que elementos a mostrar)
117		if (deleteButtons){
118			carrouselGalery.appendChild(Citems[0]);
119			carrouselButtons.remove();
120		}
121		carrouselGalery.classList.remove("loading");
122	}
123}
124
125ine.carrousel.remove = function(){
126	document.querySelectorAll('.carrouselComponent').forEach(function(item){
127		let carrouselGalery = item.querySelector(".carrouselGallery");
128	
129		if(carrouselGalery){
130			Array.from(carrouselGalery.children).forEach(function(item2){
131				carrouselGalery.parentElement.append(item2);
132			});
133			Array.from(carrouselGalery.children).forEach(function(item2){
134				item2.remove();
135			});
136			carrouselGalery.parentElement.querySelector(".carrouselButtons").remove();
137			carrouselGalery.parentElement.querySelector(".carrouselGallery").remove();
138
139			let sorted = Array.from(item.querySelectorAll(":scope > *")).sort(sorter);
140
141			function sorter(a,b) {
142				return a.dataset.index.localeCompare(b.dataset.index); // sorts based on alphabetical order
143			}
144			sorted.forEach(e => item.appendChild(e));
145		}
146	});
147}
148
149ine.carrousel.getFirst = function(el){
150	var aux = 100000, f;
151	Array.from(el.children).forEach(function(item){
152		if(ine.isVisible(item) && aux >= item.offsetLeft){
153			aux = item.offsetLeft;
154			f = item
155		}
156	});
157
158	return f;
159}
160
161ine.carrousel.getLast = function(el){
162	var aux = -1, f;
163	Array.from(el.children).forEach(function(item){
164		if(aux < parseInt(item.dataset.index)){
165			aux = parseInt(item.dataset.index);
166			f = item
167		}
168	});
169
170	return f
171}
172
173ine.carrousel.lock = function(el){
174	setTimeout(function(){
175		this.parentElement.querySelectorAll("button").forEach(function(item){
176			item.disabled = true;
177		});	
178	}.bind(el), 0);
179
180	setTimeout(function(){
181		this.parentElement.querySelectorAll("button").forEach(function(item){
182			item.disabled = false;
183		});	
184	}.bind(el), 350);
185}
186
187var ulSectionTypeByDefault = "menu";
188var seccionesSelectorNotTitle = ">*:not(.title, a.desplegar.title, .tooltip)";
189
190if(typeof ine == "undefined"){ ine = {}}
191
192ine.secciones = function(t, f){
193	let items;
194	if(f == undefined){
195		if(typeof t == "string"){
196			items = document.querySelectorAll(t) || t;
197		} else {
198			if(t.length == undefined) items = [t]; else items = t;
199		}
200	} else if(typeof f == "object"){
201		items = f.querySelectorAll(t);
202	} else {
203		items = document.querySelector(f).querySelectorAll(t);
204	}
205
206	if(items.length == 0 && !ine.loading){
207		console.log("No se encontraron elementos con el selector:", t, f ? f : '');
208	}
209
210	ine.secciones.assign(items);
211
212	return items;
213}
214ine.secciones.version = 1;
215ine.secciones.speed = 30;
216
217ine.secciones.assign = function(el){
218	return Object.assign(el, ine.secciones);
219
220}
221
222ine.each = function(){
223	if(!(arguments[0] instanceof Array || arguments[0] instanceof NodeList)){
224		arguments[0] = [arguments[0]];
225	}
226	
227    var trgs = arguments[0];
228    for(var i = 0; i < trgs.length; i++){
229        var item = trgs[i];
230
231        for(var j = 0; j < arguments.length; j++){
232            var arg = arguments[j], targ = typeof arg;
233            if(targ == 'object'){
234                for(var key in arg){
235                    item[key] = arg[key];
236                }
237            } else if(targ == 'function'){
238                var res = arg.call(item, i)
239                if(res != undefined) return res;
240            }
241        }
242    }
243
244    return trgs;
245}
246
247ine.secciones.forEach = function(fn){
248	Array.prototype.forEach.call (this, function(el){
249      fn.bind(ine.secciones.assign(el))(el)
250	  
251    });
252}
253
254ine.secciones.isSecciones = function(el){
255	if(!el) return false;
256	
257    let p, ptrnSearch = 'ul', ptrnInclude = ".secciones, .subSecc";
258
259    // Añadimos a array si el elemento es un UL
260    if(el.matches(ptrnSearch) && !el.matches(ptrnInclude)){ return false; }
261
262    // Añadimos a array si alguno de sus padres es un UL
263    for(p = el && el.parentElement; p && !p.matches('.secciones'); p = p.parentElement){
264        if(p.matches(ptrnSearch) && !p.matches(ptrnInclude)){
265            return false
266        }
267    }
268
269    return true;
270}
271
272ine.secciones.set = function(){
273	//Evaluamos componente secciones
274	this.forEach(function (){
275		var ulSecc=this;
276
277		if(ulSecc.id == "") ulSecc.id = Math.random().toString(36).substring(2, 12);
278
279		// Si el secciones tiene un aria-labelledby no válido, recuperamos
280		// el primer ID del contenido principal
281		if(ulSecc.getAttribute("aria-labelledby") == "c_"){
282			console.log(ulSecc.getAttribute("aria-labelledby") == "c_")
283			ulSecc.setAttribute("aria-labelledby", document.querySelector("main [id]").id)
284		}
285		
286		// Para todos los elementos que no contengan sublistas
287		//RRC Correccion, añadimos ">" para que solo sean los inmediatos al li
288		ine.secciones.updateLISecciones('>li', ulSecc);
289		
290		// Para todos los elementos con sublistas
291		// Esto sobreescribe los A y LI manipulados en el FOREACH anterior, si procede
292		arr =ulSecc.querySelectorAll("li>.title, li>a.desplegar.title");
293		
294		for (var i=0; i < arr.length; i++){
295			elemTitle=arr[i];
296
297			if(elemTitle.closest("ul").id == "") elemTitle.closest("ul").id = Math.random().toString(36).substring(2, 12);
298
299			if(!elemTitle.getAttribute("role")) elemTitle.setAttribute("role", 'button');
300
301			// Asignamos los atributos ARIA necearios
302			var offset = Math.random().toString(36).substring(2, 12), 
303				ulID = elemTitle.id ? elemTitle.id : ("ULmenu" + offset),
304				btnID = elemTitle.id ? elemTitle.id : ("ULmenu" + offset + "Button");
305
306			elemTitle.setAttribute('aria-haspopup', "false");
307			elemTitle.id =  btnID;
308
309			var ul = elemTitle.nextElementSibling;
310
311			// Calculamos el aria-labelledby si procede
312			// Futuro --> Eliminar: || ul.tagName == "OL"
313			if(ul && (ul.tagName == "UL" || ul.tagName == "OL") && !ul.getAttribute("aria-labelledby")){
314				ul.id = ul.id ? ul.id : ulID+"_list";//ul.id = ulID+"_list";
315				let offsetUL = "";
316				Array.from(ul.parentElement.getParents('ul')).forEach(function(el){
317					if(el){
318						let aux = (el.id );
319						if(offsetUL.indexOf(aux) == -1){
320							offsetUL += el.id + "|";
321						}
322					}
323				});
324
325				ul.setAttribute('aria-labelledby', offsetUL.replace(/\|/g, " ").trim());
326			}
327
328			// Si los UL hijos no tienen ARIA-LABELLEDBY o ARIA-LABEL intentamos asignárselo
329			if(!ulSecc.getAttribute("aria-labelledby") && (!ulSecc.getAttribute("aria-label") || ulSecc.getAttribute("aria-label") == "")){
330				var pElemTitle = ulSecc.parentElement, xCount = 0;
331
332				while(pElemTitle && xCount < 100){
333					var ULAriaLabelledBy = null;
334
335					ULAriaLabelledBy = pElemTitle.querySelector('h2, h3, h4, h5, h6');
336
337					if(!ULAriaLabelledBy && pElemTitle.getAttribute("aria-labelledby")){
338						ULAriaLabelledBy = document.getElementById(pElemTitle.getAttribute("aria-labelledby"));
339						
340					} else if(!ULAriaLabelledBy && pElemTitle.id != ""){
341						ULAriaLabelledBy = document.querySelector('[href="#' + pElemTitle.id + '"]');
342
343					}
344
345					if(ULAriaLabelledBy) break;
346
347					pElemTitle = pElemTitle.parentElement;
348					xCount++
349				}
350				if(ULAriaLabelledBy && (ulSecc.classList.contains("secciones") || ulSecc.classList.contains("secSimple"))){
351					elemTitle.parentElement.parentElement.setAttribute('aria-label', ULAriaLabelledBy.innerText)
352				} else {
353					elemTitle.parentElement.parentElement.setAttribute('aria-label', 'Lista estadística general')
354				}
355			}
356
357			// Si el LI donde se encuentra el SPAN con clase TITLE sólo tiene un UL, 
358			// damos por sentado que ese UL contiene los elementos hoja y, por tanto,
359			// le asignamos a sus LI el ROLE "none" y a sus enlaces el ROLE "...item"
360			var ulLast = (elemTitle.nextElementSibling && elemTitle.nextElementSibling.tagName != "UL" && elemTitle.nextElementSibling.tagName != "OL")
361							? elemTitle.nextElementSibling.querySelector("ul")
362							: (elemTitle.nextElementSibling && (elemTitle.nextElementSibling.tagName == "UL" || elemTitle.nextElementSibling.tagName == "OL") ? elemTitle.nextElementSibling : null);
363			
364			if(ulLast){
365				ine.secciones.updateLISecciones('>li', ulLast);
366			}
367
368			if (ulSecc){
369				var elemTitleUL = elemTitle.parentElement.parentElement;
370
371				if(elemTitle.classList.contains("title")) elemTitle.setAttribute("tabindex", "0");
372
373				elemTitle.onclick = function(event){
374					event.preventDefault();
375
376					liclicked = this.parentElement
377					ulSeccParent = this.closest(".secciones, .secSimple")
378
379					if ((ulSeccParent) && (ulSeccParent.classList.contains("unico") || ulSeccParent.classList.contains("unique"))){
380						var currentLI = this.closest("li");
381						var LIs = this.closest("ul").children;
382						
383						Array.prototype.forEach.call(LIs, function (li) {
384							if(li != currentLI){
385								var title = li.querySelector(".title");
386								if (title){
387									if (title.tagName != "A"){
388										$(seccionesSelectorNotTitle,title.parentElement).hide("blind", { direction: "up" }, ine.secciones.speed)
389									}
390									title.classList.remove("titleOpen");
391									title.classList.add("titleClose");
392								}
393							}
394						});
395
396						if(this.classList.contains("titleClose")) $(seccionesSelectorNotTitle, currentLI).hide("blind", { direction: "up" }, ine.secciones.speed)
397					}
398					
399					elem = this.parentElement.querySelector(":scope " + seccionesSelectorNotTitle);
400
401					setTimeout(function(){
402						ine.secciones.updateLISecciones('>li', this.parentElement.querySelector('ul'));
403					}.bind(this), ine.secciones.speed);
404
405					if (this.classList.contains("titleOpen") || (elem && ine.isVisible(elem))){
406						this.classList.remove("titleOpen");
407						this.classList.add("titleClose");
408						this.setAttribute("aria-expanded", "false");
409						
410						if (this.tagName != "A") $(elem).hide("blind", { direction: "up" }, ine.secciones.speed);
411						
412						if(isTitleByDefault(this)) this.setAttribute("title",Txt_Desplegar);
413
414					} else {
415						this.classList.remove("titleClose");
416						this.classList.add("titleOpen");
417						this.setAttribute("aria-expanded", "true");
418
419						if (this.tagName != "A") $(elem).show("blind", { direction: "up" }, ine.secciones.speed);
420						
421						if(isTitleByDefault(this)) this.setAttribute("title",Txt_Plegar);
422					}
423				};
424
425				elemTitle.setAttribute("aria-expanded", elemTitle.classList.contains('titleOpen') ? "true" : "false")
426				elemTitle.parentElement.removeAttribute("tabindex");
427				elemTitle.parentElement.setAttribute("role", ulSecc.getAttribute("data-type") + "item")
428				elemTitle.parentElement.parentElement.setAttribute("role", (elemTitleUL.classList.contains("secciones") || elemTitleUL.classList.contains("secSimple")) ? ulSecc.getAttribute("data-type") : "group");
429
430				if(elemTitle.nextElementSibling && elemTitle.nextElementSibling.tagName == "DIV"){
431					if(elemTitle.classList.contains("titleOpen")){
432						elemTitle.nextElementSibling.style.display = "";
433					} else {
434						elemTitle.nextElementSibling.style.display = "none";
435					}
436				}
437				
438				// Si la versión estamos dentro de un secciones y su versión es anterior a la última (v2.0).
439				
440                if (!elemTitle.classList.contains("titleClose") && !elemTitle.classList.contains("titleOpen")){
441                    elemTitle.classList.add("titleClose");
442
443                    elemTitle.parentElement.querySelector(":scope " + seccionesSelectorNotTitle).hide(ine.secciones.speed);
444                
445                    if(isTitleByDefault(elemTitle)) elemTitle.setAttribute("title",Txt_Desplegar);
446                    
447                } else {
448                    if (elemTitle.classList.contains("titleClose")){
449                        var aux = elemTitle.parentElement.querySelector(":scope " + seccionesSelectorNotTitle);
450                        if(aux) aux.style.display = "none";
451
452                        if(isTitleByDefault(elemTitle)) elemTitle.setAttribute("title",Txt_Desplegar);
453
454                    } else {
455                        var aux = elemTitle.parentElement.querySelector(":scope " + seccionesSelectorNotTitle);
456                        if(aux) aux.style.display = "";
457
458                        if(isTitleByDefault(elemTitle)) elemTitle.setAttribute("title",Txt_Plegar);
459                    }
460                }
461			}
462		}
463
464		let capsel = new URLSearchParams(location.search).get('capsel');
465		if(capsel){
466			var uls = document.getElementById("c_" + capsel).getParents('ul');
467
468			Array.prototype.forEach.call(uls, function (el){
469				el.style.display = '';
470			});
471
472			var uls = document.getElementById("c_" + capsel).getParents('li')
473			Array.prototype.forEach.call(uls, function (el){
474				el.setAttribute("role", ulSecc.getAttribute("role") + "item")
475			});
476		}
477
478		ulSecc.style.display = "";
479	});
480}
481
482/** 
483 * Fución que establece los roles y estilos de los elementos de un selector.
484 * Generalmente se coressponderá con un LI y sus elementos A o FORM.
485 * **/
486ine.secciones.updateLISecciones = function(selector, ulSecc){
487	if(!ulSecc) return;
488
489	if(typeof jQuery != "undefined"){
490		if(ulSecc instanceof jQuery) ulSecc = ulSecc[0];
491	}
492
493	ine.each(ulSecc.querySelectorAll(":scope " + selector), function(){
494	
495		if(ulSecc.dataset.type == undefined) ulSecc.dataset.type = ulSectionTypeByDefault;
496		
497		// Eliminamos los elementos P vacíos y los BR
498		var ps = this.querySelectorAll("p, br");
499		if(ps.length != 0){
500			for(var i = 0; i < ps.length; i++){
501				var psi = ps[i];
502				if(psi.tagName == "BR" && psi.nextSibling.nodeType != 1) continue;
503				if(psi.innerText.trim() == "" && psi.querySelectorAll("iframe").length == 0) {
504					psi.remove();
505				}
506			}
507		}
508
509		// Si el elemento this (que es un LI) sólo contiene un hijo y es un UL
510		// Se añade automáticamente la clase secciones y se elimina la clase subSecc
511		if(this.children.length == 1 && this.hasChildren("UL")){
512			console.log("Se reformatea el elemento UL contenido dentro de: ", this)
513
514			let items = this.children;
515			if(this.id == "") this.id = Math.random().toString(36).substring(2, 12);
516		}
517
518		// Si está vacío, lo eliminamos
519		if(this.innerHTML.trim() == ""){
520			this.remove();
521
522		// Si no tiene hijos
523		} else if(this.dataset.hasChildren == "false"){
524			this.setAttribute("role", "none")
525			this.classList.add("title-incomplete");
526
527		// Si los tiene y hay un ancla o un span con una lista a continuación
528		} else if(this.querySelectorAll("a").length != 0 || (this.querySelectorAll("span:not(.ocultar)").length == 1 && this.querySelectorAll("ul").length == 0)){
529			if(this.closest("li").querySelectorAll("ul").length == 0){
530				this.setAttribute("role", "none");
531
532			} else {
533				this.setAttribute("role", ulSecc.dataset.type + "item");
534				ine.each(this.querySelectorAll("ul"), function(){
535					this.setAttribute("role", "group");
536				});
537			}
538
539			// Si el elemento A está dentro de un P no lo tomamos como opción de menú/arbol
540			ine.each(this.querySelectorAll("a"), function(){
541				if(this.parentElement.tagName != "P"){
542					this.setAttribute("role", ulSecc.dataset.type + "item");
543				}
544			});
545
546			ine.each(this.querySelectorAll('span:not(.ocultar):not(.indice)'), function(){
547				if(this.closest("li").querySelectorAll("ul").length != 0){
548					if(this.classList.contains("title")){
549						this.setAttribute("role", 'button');
550					} else {
551						this.setAttribute("role", ulSecc.dataset.type + "item");
552					}
553				}
554
555				if(this.parentElement.tagName == "A") this.parentElement.setAttribute("role", "button");
556			});
557
558			if(this.querySelectorAll("ul, a, dl, span:not(.ocultar):not(.indice)").length == 0 && this.getAttribute("role") == "none") this.classList.add("title-incomplete");
559
560		// En cualquier otro caso
561		} else {
562			// Si el LI no contiene un A, pero sí un FORM
563			ine.each(this.querySelectorAll("form"), function(){
564				this.style.padding = "0";
565				this.style.minHeight = "0";
566			});
567
568			if(this.querySelectorAll('ul').length != 0){
569				this.setAttribute("role", ulSecc.dataset.type + "item");
570			} else {
571				this.setAttribute("role", "comment");
572
573				if([].indexOf.call(this.parentElement.children, this) == 0){
574					var item = this.querySelector('strong, b');
575					if(item){
576						this.dataset.comment = item.innerText.replace(/[^0-9a-zA-Z\s\-\.\,]/g, '').trim();
577						if(item.closest(".secciones").querySelector("form")) item.remove();
578					}
579				}
580			}
581		}
582	});
583}
584
585function isTitleByDefault(el){
586	return !el.getAttribute("title") || (el.getAttribute("title") && el.getAttribute("title").trim() == '') || el.getAttribute("title") == Txt_Desplegar || el.getAttribute("title") == Txt_Plegar;
587}
588
589if(typeof ine.isReady == "function"){
590	ine.isReady(function(){
591		ine.secciones(".secciones, .secSimple").set();
592	})
593} else {
594	onLoadAsync(function(){
595		ine.secciones(".secciones, .secSimple").set();
596	},2);
597}
598
599ine.secciones.txtlang = {
600	"unfold": "Desplegar",
601	"fold": "Plegar"
602};
603var Txt_Desplegar = ine.secciones.txtlang.unfold;
604var Txt_Plegar = ine.secciones.txtlang.fold;
605
606/*
607 ************************************************************************************************************************************************************************************
608 * Componente para añadir un botón de búsqueda en los mapas del INE
609 * Este botón aparece con una "lupita" que se suele añadir a los botones de "Zoom", justo debajo. 
610 * Cuándo lo pulsas, se expande mostrando un input búsqueda que lleva asociado un autocomplete que, cuándo se selecciona uno de sus elementos se devuelve a una función de callback
611   pasada por parámetro.
612 
613 * @param config - Es un JSON con los parámetros "callback", "placeholder" y "data". 
614          - La propiedad "callback" indica la función a la que se le devolverá el valor (el JSON completo asociado a ese elemento) seleccionado en la búsqueda.
615          - La propiedad "placeholder" indica el texto que aparecerá en el input tras pulsar en la "lupita".
616          - La propiedad "data" indica el JSON con todos los datos que se desean tratar. 
617          - ES IMPORTANTE DESTACAR QUE EL CAMPO POR EL QUE SE BUSCA DENTRO DE ESTE COMPONENTE ES LA PROPIEDAD "nm"
618   "breadcrumb" y false.
619 * @return - Devuelve el objeto ine para poder seguir trabajando con él si hace falta.
620 * **********************************************************************************************************************************************************************************
621 * EJEMPLO DE USO:
622   ---------------
623    // Definimos el Array con los datos
624    // El array puede llevar todos los campos que se deseen, pero uno de ellos debe denominarse "nm" para poder realizar la búsqueda.
625    var mapaValues = [{"id":"04","nm":"Almería"},{"id":"52","nm":"Melilla"}, ...]
626
627    // Llamamos a la funcionalidad con los parámetros necesarios
628    ine('.zoomSVG').searchMap({callback: cc, placeholder: 'Buscar', data: mapaValues })
629
630    // Función de retorno cuándo seleccionamos una opción de la lista del autocomplete
631    function cc(data){
632        console.log(data)
633    }
634 * **********************************************************************************************************************************************************************************
635*/
636
637ine.searchMap = function(config){
638    if(this.targets.length == 0) return;
639
640    // Añadimos los estilos del botón
641    this.targets[0].insertAdjacentHTML('afterbegin',`<style>
642    .searchMap                  { font-family: 'INEIcons'; font-weight: normal; display: table; }
643    .searchMap::before          { content: "\\e91d"; font-size: 1.4rem; padding: 0; width: 0; }
644    .searchMap.showing::before  { content: "\\e902"; position: relative; top: 0; font-size: 1.2rem; }
645    .searchMap.showing          { width: auto; padding: 0 12px 0 5px; }
646    .searchMap input            { display: none; }
647    .searchMap.showing input    { display: inline-block;
647 height: 26px; font-size: 0.9rem; font-family: arial; font-weight: normal; padding: 0 4px; width: 200px; position: relative; top: -2px; left: 10px; border-radius: 4px; border: 1px solid transparent; }
648    .searchMap.showing.autocomplete-active input{ border-radius: 4px 4px 0 0; }
649    </style>`);
650
651    // Creamods ID
652    config.id = Math.random().toString(16).slice(2);
653
654    // Creamos el botón 
655    var el = document.createElement("div");
656    el.id = config.id + "Layer";
657    el.classList.add("searchMap");
658    el.setAttribute("title", HM_idioma == "en" ? "Search inside map" : "Buscar dentro del mapa");
659    el.setAttribute("tabindex", "0");
660    el.setAttribute("role", "button");
661
662    this.targets[0].append(el);
663
664    // Habilitamos el autocomplete
665    el.onclick = function(e){
666        e.target.classList.toggle("showing");
667        if(e.target.querySelectorAll("input").length == 0){
668            e.target.insertAdjacentHTML('afterbegin', `<style>
669                .autocomplete-items     { position: absolute; border: 2px solid #666; border-top: none; background: #fff; z-index: 99; top: calc(100% - 8px); left: 31px; right: 0; bottom: 0; width: 204px; font-size: 1rem; color: #000; text-align: left; font-family: arial; font-weight: normal; height: 100%; height: min-content; min-height: 34px; max-height: 100px; overflow-y: auto; }
670                .autocomplete-items div { font-size: 0.9rem; padding: 3px 8px; cursor: pointer; background-color: #fff; border-bottom: 1px solid #eee; }
671                .autocomplete-items div:hover,
672                .autocomplete-active    { background-color: #457e76 !important; color: #ffffff; }
673                </style>`);
674            e.target.insertAdjacentHTML('afterbegin', `<input id="${config.id}" type="search" placeholder="${config.placeholder}">`);
675            e.target.querySelector("input").focus();
676            ine.searchMap.autocomplete(document.getElementById(config.id), config);
677        } else  {
678            //
679        }
680    }
681    el.addEventListener('keypress',keyPressToClick, false);
682}
683
684ine.searchMap.version = '1.0';
685ine.searchMap.autocomplete = function(inp, config) {
686    var currentFocus, arr = config.data;
687
688    // Cuándo se produce una entrada de datos
689    inp.oninput = function(e){
690        var a, b, i, val = this.value;
691        closeAllLists();
692
693        if (!val) { return false;}
694
695        currentFocus = -1;
696        a = document.createElement("DIV");
697        a.setAttribute("id", this.id + "autocomplete-list");
698        a.setAttribute("class", "autocomplete-items");
699        a.setAttribute("role", "listbox");
700        this.parentNode.appendChild(a);
701
702        a.closest(".searchMap").classList.add("autocomplete-active");
703
704        var posinset = 0;
705        for (i = 0; i < arr.length; i++) {
706            var posiSV = arr[i].nm.toUpperCase().indexOf(val.toUpperCase());
707            if (posiSV != -1) {
708                posinset++;
709
710                b = document.createElement("DIV");
711                b.setAttribute("role", "option");
712                b.setAttribute("aria-posinset", posinset);
713                
714                var subval = arr[i].nm.substr(posiSV, val.length);
715                b.innerHTML = arr[i].nm.replace(new RegExp(subval, "gi"), "<strong>" + subval + "</strong>");
716                b.return = arr[i];
717                b.callback = config.callback;
718
719                b.onclick = function() {
720                    inp.value = this.innerText;
721                    this.callback(this.return);
722                    closeAllLists();
723                };
724                a.appendChild(b);
725            }
726        }
727    };
728
729    // Cuándo pulsamos los cursores o el Enter
730    inp.onkeydown = function(e) {
731        var x = document.getElementById(this.id + "autocomplete-list");
732        if (x) x = x.getElementsByTagName("div");
733        
734        if (e.keyCode == 40) {
735            e.preventDefault();
736            currentFocus++;
737            addActive(x);
738        } else if (e.keyCode == 38) { //up
739            e.preventDefault();
740            currentFocus--;
741            addActive(x);
742        } else if (e.keyCode == 13) {
743            e.preventDefault();
744            if (currentFocus > -1) {
745                if (x) x[currentFocus].click();
746            }
747        }
748    }
749
750    inp.onfocus = function(){
751        this.dispatchEvent(new Event('input',{ bubbles: true, cancelable: true }));
752    }
753
754    // Si pulsamos en otra zona, cerramos los autocompletes
755    document.addEventListener("click", function (e){
756        closeAllLists(e.target);
757    });
758
759    function addActive(x) {
760        if (!x) return false;
761        removeActive(x);
762        if (currentFocus >= x.length) currentFocus = 0;
763        if (currentFocus < 0) currentFocus = (x.length - 1);
764        x[currentFocus].classList.add("autocomplete-active");
765        x[currentFocus].closest('.autocomplete-items').scrollTop = x[currentFocus].offsetTop;
766    }
767
768    function removeActive(x) {
769        for (var i = 0; i < x.length; i++) {
770            x[i].classList.remove("autocomplete-active");
771        }
772    }
773
774    function closeAllLists(elmnt) {
775        var x = document.getElementsByClassName("autocomplete-items");
776
777        for (var i = 0; i < x.length; i++) {
778            if (elmnt != x[i] && elmnt != inp) {
779                x[i].closest(".searchMap").classList.remove("autocomplete-active");
780                x[i].parentNode.removeChild(x[i]);
781            }
782        }
783    }
784};
785// download function
786ine.map = function(){return "Export map enable"}
787
788ine.map.getCSV = function(id){
789    if(!id){
790        document.querySelectorAll(".zoomSVG").forEach(function(it){
791            if(ine.isVisible(it)) id = it.parentElement.id;
792        });
793    } 
794    
795    var lines = VisualINEJS[id].csv.split("\n"), arrAux = []
796    lines.forEach(function(line){var tmp = [];
797        var tmp = [];
798        line.split(";").forEach(function(item){
799            var breakLine = item.indexOf("\n") != -1 ? "\n" : "";
800            item = item.trim();
801            return tmp.push(isNaN(item) ? item : (ine.map.toFormatMoney(item) + breakLine));
802        });
803        arrAux.push(tmp.join(";"))
804    });
805    
806    return arrAux.join("\n");
807}
808
809ine.map.download2CSV = function(config) {
810    let csv_data = ine.map.getCSV(config.divDestino);
811
812    CSVFile = new Blob(['\uFEFF' + csv_data], {
813        type: "text/csv;charset=utf-8"
814    });
815
816    let temp_link = document.createElement('a');
817
818    temp_link.download = "export.csv";
819    let url = window.URL.createObjectURL(CSVFile);
820    temp_link.href = url;
821
822    temp_link.style.display = "none";
823    document.body.appendChild(temp_link);
824
825    temp_link.click();
826    document.body.removeChild(temp_link);
827
828    document.querySelector(".zoomSVG .export").classList.remove("active");
829}
830
831ine.map.download2Imgage = function(config) {
832    function export2Img(name){
833        guardarMapa(name)
834    }
835    if(!document.querySelector("script[src*='savetoimg.js']")){
836        var s = document.createElement("script");
837        s.onload = function(){
838            export2Img(config.divDestino)
839        }
840        s.src = "/menus/js/mapasINE/savetoimg.js";
841        document.head.append(s)
842    } else {
843        export2Img(config.divDestino)
844    }
845}
846
847// Show data table function
848ine.map.showData = function(config) {
849    let csv_data = ine.map.getCSV();
850
851    var auxTable = document.createElement("table");
852    auxTable.style.width = "100%";
853    var array = [];
854    csv_data.split("\n").forEach(function(it, idx){
855        array.push(it.split(";"));
856    });
857
858    array.sort(function(a, b){ return b[1].localeCompare(a[1]) });
859
860    array.reverse().map((row,rowId)=>{
861        if(row[0].replace(/[0-9\.\,]/g, '') == ""){
862            var newRow = auxTable.insertRow(auxTable.length );
863            row.map((cellVal,cellId)=> {
864                var cell = newRow.insertCell(cellId);
865                cell.innerHTML = cellVal;
866                if(cellId == 1) cell.style.textAlign = "left";
867                cell.style.lineHeight = "32px";
868            })
869        }
870    });
871
872    if(!config.dataMap.titulo && config.dataMap.nombre) config.dataMap.titulo = (clicked == 1 ? "Nombre: " : "Apellido: " ) + config.dataMap.nombre
873
874    auxTable.insertAdjacentHTML("afterbegin", "<thead><tr><th style='line-height: 32px'>" + zoomLang[7] +"</th><th style=' style='line-height: 32px'; text-align: left'>" + zoomLang[8] + "</th><th style='line-height: 32px'>" + zoomLang[9] + "</th></tr></thead>");
875    if(config.dataMap.titulo) auxTable.insertAdjacentHTML("afterbegin", "<caption style='line-height: 32px; text-align: center; font-weight: bold; color: var(--color1-100); margin: -5px 5px 5px; border-bottom: 1px solid var(--color1-125);'>" + config.dataMap.titulo + "</caption>");
876    document.dialog("Tabla de datos", auxTable.outerHTML, { left
876: '0', top: '0', width: "auto", "max-height": "90%", "min-width" : "50%"});
877
878    document.querySelector(".zoomSVG .export").classList.remove("active");
879}
880
881ine.map.toFormatMoney = function(val, d = general_charDecimal, m = general_chatMiles){
882    return isNaN(val) ? val : val.formatMoney(null, d, m);
883}
884
885/* COMIENZO SLIDESHOW */
886if(typeof ine == "undefined"){ ine = {}; }
887var AddCSSRule = function(cfg, selector, styles, index) {
888	var s, r, itS = document.getElementById("isiToolsStyles");
889	var sheet = cfg;
890
891	// Get style sheet
892	if (sheet == null || sheet == "") {
893		if (itS == null) {
894			var style = document.createElement("style");
895			style.setAttribute("id", "isiToolsStyles");
896			style.setAttribute("media", "screen");
897
898			// Add style tag to head
899			document.head.insertBefore(style, document.head.firstChild);
900			s = style.sheet;
901		} else {
902			s = itS.sheet;
903		}
904	} else {
905		if (typeof sheet == "number")
906			s = document.styleSheets[sheet];
907		else if (typeof sheet == "object")
908			s = sheet;
909		else
910			console.log("sheet not avilable!")
911	}
912
913	// Get rules
914	var rText = s.cssRules || s.rules;
915	index = typeof index == "undefined" ? rText.length : index;
916
917	for (var i = 0; i < index; i++) {
918		r = rText[i];
919
920		if (typeof r.selectorText != "undefined" && r.selectorText.trim() == selector.trim()) {
921			s.deleteRule(i);
922			index--;
923			break;
924		}
925	}
926
927	// Insert rule
928	if (styles == undefined) {
929		try {
930			s.insertRule(selector);
931		} catch (e) {}
932
933	} else {
934		try {
935			s.insertRule(selector + "{ " + styles + " } ", index);
936		} catch (e) {}
937	}
938}
939
940/**
941 * @description Componente Slide Show.
942 * @param {Object} cfg Es el selector o elemento HTML a recuperar.
943 * @param {String} f Es el elemento padre desde dónde empezar a buscar. Si no se establece se toma por defecto el objeto 'document'.
944 * @example 
945 *     ine(.secciones)
946 * @returns {NodeList} Con todos los elementos coincidentes y todos los métodos y propiedades del componente secciones.
947 * @notes
948 * La estructura del slideShow debe ser como la siguiente
949 <div class="slideshow">
950	<div class="slide">
951		<img src="https://cdn.pixabay.com/photo/2021/02/24/09/51/magical-6046020_960_720.jpg">
952		<div class="title">SLOGAN 1</div>
953		<div class="text">Texto adicional 1</div>
954	</div>
955	<div class="slide">
956		<img src="https://cdn.pixabay.com/photo/2019/12/29/13/59/trees-4727156_960_720.jpg">
957		<div class="title">SLOGAN 2</div>
958		<div class="text">Texto adicional 2</div>
959	</div>
960	<div class="slide">
961		<img src="https://cdn.pixabay.com/photo/2017/06/17/10/55/hot-air-balloon-2411851_960_720.jpg">
962		<div class="title">SLOGAN 3</div>
963		<div class="text">Otro texto adicional</div>
964	</div>
965</div>
966 */
967ine.slideShow = function (cfg) {
968	if(typeof cfg == "undefined") cfg = {};
969	
970	// If method was called by HTMLSelectElement
971	this.targets = this.tagName != undefined ? [this] : (this.entries == undefined ? this.targets : this);
972
973	var opt;
974	Array.prototype.slice.call(this.targets).forEach(function(target){
975		var id = target.id, i;
976
977		if(target.tagName == "IT-SLIDESHOW"){
978			target = ine.slideShow.build(target, opt);
979		}
980
981		if(cfg.preRender && typeof cfg.preRender == "function") cfg.preRender();
982
983		// Recuperamos la configuración actual
984		if(!ine.slideShow._init[target.id]){
985			opt = ine.slideShow.config[id] || cfg;
986			opt.autoplay = cfg.hasOwnProperty("autoplay") ? cfg.autoplay : false;
987			opt.currentSlide = cfg.hasOwnProperty("currentSlide") ? cfg.currentSlide : (typeof cfg == "number" ? cfg : 1);
988			opt.dots = target.querySelectorAll(".dot");
989			opt.effect = cfg.hasOwnProperty("effect") ? cfg.effect : 'fade';
990			opt.fullscreen = cfg.hasOwnProperty("fullscreen") ? cfg.fullscreen : false;
991			opt.interval = cfg.hasOwnProperty("interval") ? cfg.interval : 5;
992			opt.player = cfg.hasOwnProperty("player") ? cfg.player : false;
993			opt.preRender = cfg.hasOwnProperty("preRender") ? cfg.preRender : null;
994			opt.showNumbers = cfg.hasOwnProperty("showNumbers") ? cfg.showNumbers : false;
995			opt.slides = target.querySelectorAll(".slide");
996			opt.stylesheet = cfg.hasOwnProperty("stylesheet") ? cfg.stylesheet : false;
997			opt.title = cfg.hasOwnProperty("title") ? cfg.title : (target.dataset.title != "" ? target.dataset.title : ine.slideShow.language.title);
998			opt.width = cfg.hasOwnProperty("width") ? cfg.width : '100%';
999			opt.height = cfg.hasOwnProperty("height") ? cfg.height : '';
1000			opt.style = cfg.hasOwnProperty("style") ? cfg.style : '';
1001			opt.lastSlide = !opt.lastSlide ? 1 : opt.lastSlide
1002
1003			// Si slides es vacío tomamos los hijos del "target"
1004			if(opt.slides.length == 0){
1005				let tagName = "";
1006				Array.from(target.children).forEach(function(slide){
1007					if(tagName == "") tagName = slide.tagName;
1008					if(slide.tagName == tagName){
1009						slide.classList.add("slide")
1010					}
1011				});
1012				opt.slides = target.querySelectorAll(".slide");
1013			}
1014
1015			// Controlamos el nº de slides
1016			// Si sólo hay uno, terminamos la ejecución y no hacemos nada
1017			if(opt.slides.length == 1) return;
1018			
1019			// Limpiamos de clases CSS los slides, 
1020			// Asignamos eventos y estilos
1021			Array.from(opt.slides).forEach(function(slide){
1022				slide.setAttribute("class", "slide");
1023				
1024
1025				if(slide.querySelector("a")){
1026					slide.onclick = function(e){
1027						e.target.closest(".slide").querySelector("a").click();
1028					}
1029					slide.style.cursor = "pointer";
1030				}
1031			});
1032
1033			if(cfg.style){
1034				target.style = opt.style;
1035			}
1036
1037			let prevPosition, prevHeight, prevDisplay, minHeight = (!opt.height || opt.height.trim() == "") ? 0 : parseInt(opt.height);
1038			Array.from(opt.slides).forEach(function(slide){
1039				if(slide.querySelector("[href*='youtube.com'")){
1040					slide.classList.add("video");
1041					slide.parentElement.classList.add("video-list")
1042				}
1043
1044				if(slide.offsetHeight > minHeight && slide.classList.contains("video")){
1045					opt.height = opt.height ? opt.height : "250";
1046				}
1047
1048				slide.style = '--bh: ' + (parseInt(opt.height)/2) + "px; --bw: " + (slide.querySelector(":scope > div").offsetWidth - 55) + "px";
1049
1050				prevPosition = slide.style.position;
1051				prevHeight = slide.style.height;
1052				prevDisplay = slide.style.display;
1053
1054				slide.style.position = "relative";
1055				slide.style.height   = "auto";
1056				slide.style.display  ="inline-block";
1057				
1058				if(slide.offsetHeight > minHeight && !slide.classList.contains("video")){
1059					slide.querySelector(":scope > div").style.display = "none"
1060					minHeight = slide.offsetHeight + parseInt(getComputedStyle(slide).paddingTop) + parseInt(getComputedStyle(slide).paddingBottom)
1061					slide.querySelector(":scope > div").style.display = ""
1062				}
1063
1064				slide.style.position = prevPosition;
1065				slide.style.height = prevHeight;
1066				slide.style.display = prevDisplay;
1067			});
1068
1069			if(!opt.height || opt.height.trim() == "") opt.height = minHeight + "px";
1070
1071			target.style.minHeight = (parseInt(opt.height) + parseInt(getComputedStyle(target).borderTopWidth) + parseInt(getComputedStyle(target).borderBottomWidth)) + "px";
1072			target.style.minWidth = opt.width;
1073
1074			target.classList.add("loading");
1075
1076			// Si el target no tiene ID, se lo asignamos
1077			if(!id){
1078				if(!id) id = 'it-slider-' + Math.random().toString(36).substr(2, 9);
1079				target.id = id;
1080			}
1081
1082			// Si se solicitó a pantalla completa establecemos los valores calculados
1083			if(opt.fullscreen){
1084				opt.height = '100vh';
1085				opt.width = '100%';
1086				target.classList.add("fullscreen");
1087			}
1088
1089			// Si se solicitó el botón de reproducción
1090			if(opt.player){
1091				var aux = document.createElement("button");
1092				aux.classList.add("player");
1093				aux.setAttribute("role", "button")
1094				target.appendChild(aux);
1095
1096				ine.slideShow.pause(target);
1097			}
1098		} else {
1099			opt = ine.slideShow.config[id];
1100			opt.currentSlide = (typeof cfg == "number" || typeof cfg == "string") ? cfg : 1;
1101		}
1102		
1103		// Establecemos valores por defecto si el número de slide está fuera de los límites
1104		if (opt.currentSlide > opt.slides.length) {opt.currentSlide = 1}
1105		if (opt.currentSlide < 1) {opt.currentSlide = opt.slides.length}
1106
1107		// Reestablecemos todos los slides y dots activos
1108		if(opt.dots.length != 0){
1109			for (i = 0; i < opt.dots.length; i++) { opt.dots[i].classList.remove("active"); }
1110		}
1111
1112		// Asignamos el slide actual
1113		for (i = 0; i < opt.slides.length; i++) { opt.slides[i].classList.remove("show", 'move'); opt.slides[i].classList.add("hide"); }
1114		
1115		if(opt.effect == "fade"){
1116			opt.slides[opt.lastSlide - 1].classList.add("hide");
1117			opt.slides[opt.lastSlide - 1].classList.remove("show");
1118		} 
1119		opt.slides[opt.currentSlide - 1].classList.add("show");
1120		opt.slides[opt.currentSlide - 1].classList.remove("hide");
1121
1122		if(opt.effect == "move"){
1123			// En esta circunstancia cfg es el número de slide solicitado sin correccción
1124			let dir = opt.lastSlide < cfg ? "next" : "prev";
1125
1126			for (i = 0; i < opt.slides.length; i++) {
1127				if(i != opt.currentSlide - 1 && i != opt.lastSlide - 1){
1128					opt.slides[i].style.left = dir == "prev" ? "-100vw" : "100vw";
1129				} 
1130			}
1131			opt.slides[opt.currentSlide - 1].style.left = dir == "prev" ? "-100vw" : "100vw";
1132			opt.slides[opt.lastSlide - 1].style.left = "0";
1133
1134			setTimeout(function(){
1135				for (i = 0; i < this.slides.length; i++) { this.slides[i].classList.add("move"); }
1136				this.slides[this.currentSlide - 1].style.left = "0";
1137				if(this.lastSlide != this.currentSlide){
1138					if(dir == "prev"){
1139						this.slides[this.lastSlide - 1].style.left = "100vw";
1140					} else{
1141						this.slides[this.lastSlide - 1].style.left = "-100vw";
1142					}
1143
1144					this.slides[this.lastSlide - 1].classList.add("hide");
1145					this.slides[this.lastSlide - 1].classList.remove("show");
1146				}
1147
1148				opt.lastSlide = opt.currentSlide;
1149			}.bind(opt), 50)
1150		}
1151	
1152
1153		// Asignamos el dot actual
1154		if(opt.dots.length != 0){
1155			opt.dots[opt.currentSlide-1].classList.add("active");
1156		}
1157
1158		// Asignamos tamaño si el target no lo tiene todavía
1159		if(!ine.slideShow._init[target.id]){
1160			// Asignamos la clase CSS
1161			target.classList.add("it-slideshow");
1162
1163			// Asignamos los atributos de accesibilidad 
1164			target.setAttribute("aria-roledescription", "carousel");
1165			target.setAttribute("aria-label", opt.title);
1166
1167			// Creamos el contenedor de dots
1168			var dots = document.createElement("div");
1169				dots.classList.add("dots");
1170
1171			// Recorremos los slides
1172			for(var i = 0; i < opt.slides.length; i++){
1173				if(i != opt.currentSlide - 1){
1174					opt.slides[i].classList.add("hide");
1175				}
1176
1177				// Asignamos los atributos de accesibilidad a cada slide,
1178				opt.slides[i].setAttribute("aria-roledescription", "slide");
1179				opt.slides[i].setAttribute("aria-label", (i + 1) + ine.slideShow.language.slideOf +  opt.slides.length);
1180				if(cfg.width) opt.slides[i].style.minWidth = opt.width;
1181				if(cfg.height) opt.slides[i].style.minHeight = opt.height;
1182
1183				// Añadimos los enlaces/dots para cada slide con sus
1184				// respectivos atributos de accesibilidad
1185				if(opt.dots.length == 0){
1186					var dot = document.createElement("a");
1187						dot.classList.add("dot")
1188						dot.setAttribute("onclick", "ine.slideShow.toSlide(this, " + (i + 1) + ")");
1189						dot.setAttribute("role", "button");
1190						dot.setAttribute("aria-controls", target.id);
1191						dot.setAttribute("title", ine.slideShow.language.goto + (i + 1));
1192						dot.setAttribute("tabindex", "0");
1193
1194					// Asingamos el dot activo
1195					if(i == opt.currentSlide-1) dot.classList.add("active");
1196
1197					dots.appendChild(dot);
1198				}
1199
1200				// Añadimos el número de diapositiva, si procede
1201				if(opt.showNumbers){
1202					var sn = document.createElement("span");
1203						sn.classList.add("slide-id")
1204						sn.innerHTML = (i + 1) + " / " + opt.slides.length;
1205
1206					opt.slides[i].insertAdjacentElement("afterbegin", sn);
1207				}
1208
1209				// Asignamos a cada slide el efecto de transición solicitado,
1210				// Por defecto se establece a 'fade'
1211				opt.slides[i].classList.add(opt.effect);
1212			}
1213
1214			// Añadimos el elemento contenedor de dots
1215			target.appendChild(dots);
1216
1217			opt.dots = dots.querySelectorAll(".dot");
1218
1219			// Añadimos los botones y dots a cada target
1220			var prev = document.createElement("a");
1221				prev.classList.add("prev")
1222				prev.setAttribute("onclick", "ine.slideShow.toggle(this, -1)");
1223				prev.setAttribute("role", "button");
1224				prev.setAttribute("aria-controls", target.id);
1225				prev.setAttribute("title", ine.slideShow.language.prev);
1226				prev.setAttribute("tabindex", "0");
1227				prev.innerHTML = "&#10094;"
1228
1229				target.appendChild(prev);
1230
1231			var next = document.createElement("a");
1232				next.classList.add("next")
1233				next.setAttribute("onclick", "ine.slideShow.toggle(this, 1)");
1234				next.setAttribute("role", "button");
1235				next.setAttribute("aria-controls", target.id);
1236				next.setAttribute("title", ine.slideShow.language.next);
1237				next.setAttribute("tabindex", "0");
1238				next.innerHTML = "&#10095;"
1239
1240				target.appendChild(next);
1241
1242			// Guardamos la actual configuración
1243			ine.slideShow.config[id] = opt;
1244
1245			// Si se solicitó la reprocucción automática, la activamos
1246			if(opt.autoplay){
1247				ine.slideShow.play(target);
1248			}
1249
1250			target.addEventListener('touchstart', handleTouchStart, {passive: true});        
1251			target.addEventListener('touchmove', handleTouchMove, {passive: true});
1252			var xDown = null, yDown = null;
1253			
1254			function getTouches(evt) { return evt.touches || evt.originalEvent.touches; }                                                     
1255
1256			function handleTouchStart(evt) { const firstTouch = getTouches(evt)[0]; xDown = firstTouch.clientX; yDown = firstTouch.clientY; };                                                
1257			function handleTouchMove(evt)  { 
1258				if ( ! xDown || ! yDown ) { return; }
1259
1260				var xUp = evt.touches[0].clientX, yUp = evt.touches[0].clientY;
1261				var xDiff = xDown - xUp, yDiff = yDown - yUp;
1262
1263				if ( Math.abs( xDiff ) > Math.abs( yDiff ) ) {
1264					if ( xDiff > 0 ) {
1265						target.querySelector(".next").click();
1266					} else {
1267						target.querySelector(".prev").click();
1268					}
1269				} 
1270				xDown = yDown = null;
1271			};
1272
1273			ine.slideShow._init[target.id] = target.id
1274		}
1275
1276		ine.slideShow.config[id].currentSlide = opt.currentSlide;
1277
1278		setTimeout(function(){this.classList.remove("loading");}.bind(target), 0);
1279	});
1280
1281	if(opt && !opt.stylesheet && !ine.slideShow._stylesAdded){
1282		AddCSSRule('', '.it-slideshow', 'max-width: none; position: relative; margin: 0 !important; padding: 0 !important; display: block !important;');
1283		AddCSSRule('', '.it-slideshow .prev, .it-slideshow .next', 'cursor: pointer; position: absolute; left: 0; right: auto; top: 50%; width: 40px; margin-top: -22px; padding: 16px 0; text-align: center; color: white; font-weight: bold; font-size: 18px; transition: 0.1s ease; background: var(--bg-color); color: var(--text-color); border: 1px solid var(--text-color); border-radius: 0 3px 3px 0; user-select: none; z-index: 9;');
1284		AddCSSRule('', '.it-slideshow .next', 'right: 0; left: auto; border-radius: 3px 0 0 3px; border-right-color: transparent;');
1285		AddCSSRule('', '.it-slideshow .prev', 'border-left-color: transparent;');
1286		AddCSSRule('', '.it-slideshow .prev:hover, .it-slideshow .next:hover, .it-slideshow .prev:focus, .it-slideshow .next:focus, .it-slideshow .player:hover, .it-slideshow .player:focus', '    box-shadow: 0 0 0 2px var(--bg-color) inset; border: 1px solid var(--text-color); background: var(--text-color); color: var(--bg-color);');
1287		//AddCSSRule('', '.it-slideshow .slide:hover ~ .prev, .it-slideshow .slide:hover ~ .next', 'background: var(--text-color); box-shadow: 0 0 0 2px var(--bg-color) inset; border: 1px solid var(--text-color);');
1288		AddCSSRule('', '.it-slideshow .title', 'color: var(--bg-color); font-size: 2rem; padding: 8px 12px; position: absolute; bottom: 50%; width: 100%; text-align: center;');
1289		AddCSSRule('', '.it-slideshow .text', 'background: rgba(0,0,0,0.5); color: #f2f2f2; font-size: 1rem; padding: 8px 12px 22px; position: absolute; bottom: 0; width: 100%; text-align: center;');
1290		AddCSSRule('', '.it-slideshow .slide-id', 'background-color: rgba(0,0,0,0.8); color: #f2f2f2; font-size: 0.8rem; padding: 5px 10px; position: absolute; top: 0;');
1291		AddCSSRule('', '.it-slideshow .dots', 'text-align: center; position: absolute; width: 100%; bottom: 0; left: 0;');
1292		AddCSSRule('', '.it-slideshow .dot ', 'cursor: pointer; height: 25px; width: 25px; margin: 0 2px; background-color: #bbb; border-radius: 50%; display: inline-block; transition: background-color 0.6s ease;');
1293		AddCSSRule('', '.it-slideshow .slide', 'display: block !important; position: absolute; top: 0; left: 0; transition: opacity 0s ease-in-out; height: 100%; width: 100% !important; margin: 0; padding: 0;');
1294		AddCSSRule('', '.it-slideshow:not(.loading) .slide.fade', 'transition: opacity 1.2s ease-in-out;');
1295		AddCSSRule('', '.it-slideshow:not(.loading) .slide.move', 'transition: left 1.2s ease-in-out;');
1296		AddCSSRule('', '.it-slideshow:not(.loading) .slide.nomove', 'transition: none !important;');		
1297		AddCSSRule('', '.it-slideshow .slide img, .it-slideshow .slide svg', 'max-width: 100%; display: block; object-fit: cover; height: 100%; width: 100%; display: block;');
1298		AddCSSRule('', '.it-slideshow .active, .it-slideshow .dot:hover, .it-slideshow .dot:focus', 'background-color: var(--text-color);');
1299		AddCSSRule('', '.it-slideshow .slide.fade', 'opacity: 0; display: flex; flex-flow: row nowrap;');
1300		AddCSSRule('', '.it-slideshow .slide.fade.hide', 'opacity: 0; overflow: hidden; min-height: 0 !important; pointer-events: none;');
1301		AddCSSRule('', '.it-slideshow .slide.fade.show', 'opacity: 1;');
1302		AddCSSRule('', '.it-slideshow .slide h3', 'font-size: 1.4rem;');
1303		
1304		AddCSSRule('', '.it-slideshow.fullscreen', 'height: 100vh; width: 100%;');
1305
1306		AddCSSRule('', '.it-slideshow .player', 'cursor: pointer; position: absolute; top: 5px; right: 5px; font-size: 21px; background: var(--bg-color); color: var(--text-color); border: 1px solid var(--text-color); width: 32px; height: 32px; line-height: 32px; text-align: center; padding: 0; margin: 0;');
1307		AddCSSRule('', '.it-slideshow.playing .player::before', 'content: "\\2590\\a0\\258c"; ');
1308		AddCSSRule('', '.it-slideshow.playing .player', 'font-size: 12px;');
1309		AddCSSRule('', '.it-slideshow.paused .player::before', 'content: "\\25b6"; ');
1310		AddCSSRule('', '.it-slideshow.paused .player', 'font-size: 19px;');
1311		
1312		AddCSSRule('', '.it-slideshow progress', 'position: absolute; top: -2px; left: 0; height: 4px; width: 100%; -webkit-appearance: none; -moz-appearance: none; appearance: none; border: none; background-color: var(--color1-100); color: rgba(var(--bg-color), 1); z-index: 2;');
1313		AddCSSRule('', '.it-slideshow progress::-webkit-progress-bar', 'background-color: var(--color1-100); border-radius: 20px;');
1314		AddCSSRule('', '.it-slideshow progress::-webkit-progress-value', 'background-color: var(--color1-125);  transition: 0.2s width ;');
1315		AddCSSRule('', '.it-slideshow progress::-moz-progress-bar', 'background-color: var(--color1-125);');
1316		AddCSSRule('', '.it-slideshow progress::-ms-fill', 'background-color: var(--color1-125);');
1317
1318		ine.slideShow._stylesAdded = true;
1319	}
1320
1321	window.addEventListener("resize", function(){
1322		this.document.querySelectorAll(".slide.video").forEach(function(item){
1323			item.style["--bw"] = (item.offsetWidth - 55) + 'px';
1324		});
1325	});
1326}
1327
1328ine.slideShow.tries = 0;
1329ine.slideShow.MaxTries = 100
1330
1331ine.slideShow.build = function(trg, cfg){
1332	var cont, slide, img, tlt, txt;
1333
1334	// Creamos el DIV contenedor
1335	cont = document.createElement("div");
1336	cont.classList.add("slideshow");
1337
1338	// Creamos los elementos de diapositiva
1339	for(var i = 0; i < trg.children.length; i++){
1340		var item = trg.children[i];
1341
1342		slide = document.createElement("div");
1343		slide.classList.add("slide");
1344		if(i > 0){ 
1345			slide.classList.add("hide");
1346		}
1347
1348		img = document.createElement("img");
1349		img.src = item.getAttribute("img");
1350		img.setAttribute("width", "100%");
1351		img.setAttribute("height", "100%");
1352
1353		tlt = document.createElement("div");
1354		tlt.classList.add("title");
1355		tlt.innerHTML = item.getAttribute("title");
1356
1357		txt = document.createElement("div");
1358		txt.classList.add("text");
1359		txt.innerHTML = item.getAttribute("text");
1360
1361		slide.append(img);
1362		slide.append(tlt);
1363		slide.append(txt);
1364
1365		cont.append(slide);
1366	}
1367	
1368	trg.insertAdjacentElement("beforebegin", cont);
1369	trg.remove();
1370
1371	return cont;
1372}
1373
1374ine.slideShow.config = {}
1375ine.slideShow.language = {
1376	"prev": "Mostrar diapositiva anterior",
1377	"next": "Mostrar diapositiva siguiente",
1378	"goto": "Mostrar diapositiva ",
1379	"start": "Iniciar presentación automática de diapositivas",
1380	"stop": "Detener presentación automática de diapositivas",
1381	"title": "Presentación de diapositivas de imágenes",
1382	"slideOf": " de "
1383};
1384
1385ine.slideShow.play = function(el){
1386	var cfg = ine.slideShow.config[el.id] || {};
1387
1388	// Añadimos la barra de progreso
1389	var trg = cfg.slides[0].parentElement, prg;
1390	if(!trg.querySelector("progress")){
1391		prg = document.createElement("progress");
1392			prg.max = "101";
1393			prg.value = "0";
1394		trg.insertAdjacentElement("afterbegin", prg);
1395	} else {
1396		prg = trg.querySelector("progress");
1397	}
1398
1399	cfg.progress = setInterval(function(interval, el){
1400		if(prg.value > 100){
1401			prg.value = 0;
1402			ine.slideShow.toggle(el, 1);
1403		}
1404		prg.value += prg.max / interval / 10;
1405
1406	}.bind(prg, cfg.interval, el.querySelector(".next")), 100);
1407
1408	// Cambiamos el evento click
1409	el.querySelector(".player").onclick = function(e){
1410		ine.slideShow.pause(e.target.parentElement)
1411	}
1412
1413	el.querySelector(".player").setAttribute("title", ine.slideShow.language.stop)
1414
1415	el.classList.add("playing");
1416	el.classList.remove("paused");
1417}
1418
1419ine.slideShow.pause = function(el){
1420	var cfg = ine.slideShow.config[el.id] || {};
1421
1422	// Paramos el intervalo y barra de progreso
1423	clearInterval(cfg.progress);
1424
1425	// Cambiamos el evento click
1426	el.querySelector(".player").onclick = function(e){
1427		ine.slideShow.play(e.target.parentElement)
1428	}
1429
1430	el.querySelector(".player").setAttribute("title", ine.slideShow.language.start)
1431
1432	el.classList.remove("playing");
1433	el.classList.add("paused");
1434}
1435
1436ine.slideShow.toggle = function(el, n){
1437	el = el.parentElement;
1438	ine(el).slideShow(parseInt(el.querySelector(".dot.active").getAttribute("onclick").replace(/[^0-9]/g, '')) + n);
1439}
1440
1441ine.slideShow.toSlide = function(el, n){
1442	el = el.parentElement.parentElement;
1443	ine(el).slideShow(n);
1444}
1445
1446ine.slideShow._stylesAdded = false;
1447ine.slideShow._init = [];
1448
1449if(typeof ine.isReady == "function"){
1450	ine.isReady(function(){
1451		ine(".it-slideshow, .slideshow").slideShow({
1452			interval: 10,
1453			player: true,
1454			title: 'Contenedor para presentaci�n de diapositivas'
1455		});
1456	});
1457}
1458/* FIN SLIDESHOW */
1459/**
1460    @description Funcionalidad para añadir tooltips buscando la clase .tooltip-content, si no existe utilizando el atributo "title" y si vuelve a no existir utilizar "textContent"
1461    @example document.querySelectorAll(".miga a, .miga h1").tooltip(opt);
1462    opt={
1463        eventsIN : ["focus", "over"],
1464        eventsOUT : ["focusout ", "out"],
1465        funcallback : function(){...}
1466    }
1467    @returns {void}
1468 **/
1469    window.getScrollbarWidth = function() {
1470        const outer = document.createElement('div');
1471        outer.style.visibility = 'hidden';
1472        outer.style.overflow = 'scroll';
1473        outer.style.msOverflowStyle = 'scrollbar';
1474        document.body.appendChild(outer);
1475    
1476        const inner = document.createElement('div');
1477        outer.appendChild(inner);
1478    
1479        const scrollbarWidth = (outer.offsetWidth - inner.offsetWidth);
1480    
1481        outer.parentNode.removeChild(outer);
1482
1483        return scrollbarWidth;
1484    }
1485
1486    window.addEventListener("DOMContentLoaded", function(e){
1487        window.scrollbarWidth = window.getScrollbarWidth();
1488    }, { passive: false});
1489
1490    resizeTooltipINE = function(){
1491        // Corrections if out of window
1492        let  tooltipContent = this.tooltipContent;
1493        posTC=tooltipContent.getBoundingClientRect();
1494        if ((posTC.left + posTC.width) > window.innerWidth - window.scrollbarWidth){
1495            tooltipContent.style.left = (window.innerWidth -  posTC.width - window.scrollbarWidth  + window.scrollX) + 'px';
1496        }
1497        
1498        if ((posTC.top + posTC.height) > window.innerHeight){
1499            tooltipContent.style.top = (window.innerHeight- posTC.height - window.scrollbarWidth + window.scrollY) + 'px';
1500        }        
1501    }
1502
1503
1504    eventoTooltipINE_IN = function(opt,e){
1505        document.querySelectorAll(".tooltipINE-content").forEach(function(currentValue){
1506            currentValue.style.display="none";
1507        });
1508        
1509        let tc= window["tc"]
1510        if (!tc)
1511            tc=0;
1512
1513        if(!this.id){
1514            tc++;
1515            this.setAttribute("id","id_tooltipINE_" + tc );
1516        }
1517
1518        window["tc"]=tc;
1519
1520        let tooltipContent =this.tooltipContent;
1521        if (!this.tooltipContent){
1522            tooltipContent=this.parentElement.querySelector(".tooltip-content,.tooltipINE-content");           
1523        }
1524
1525        this.classList.add("tooltipINE");
1526        //Eliminamos restos de antiguos tootlips
1527        this.classList.remove("tooltip");
1528        this.classList.remove("tooltip-evnt");
1529
1530        divTooltipContentAux = window["divTooltipContentAux"];
1531        if(tooltipContent && (tooltipContent != divTooltipContentAux)){
1532            
1533            tooltipContent.setAttribute("aria-label", this.getAttribute("id") );
1534            tooltipContent.classList.add("tooltipINE-content");
1535            tooltipContent.classList.remove("tooltip-content");
1536
1537        } else {
1538            
1539            divTooltipContentAux = window["divTooltipContentAux"];
1540
1541            if(!divTooltipContentAux){
1542                divTooltipContentAux = document.createElement("div");
1543                this.tooltipContent=divTooltipContentAux;
1544                window["divTooltipContentAux"]= divTooltipContentAux;
1545            }
1546
1547            divTooltipContentAux.setAttribute("aria-label", this.getAttribute("id") );
1548            divTooltipContentAux.classList.add("tooltipINE-content")
1549            //this.appendChild(divTooltipContentAux);      --Insertar dentro        
1550            document.body.appendChild(divTooltipContentAux);           
1551            //this.after(divTooltipContentAux);            //--Insertar al lado
1552            
1553            if(this.getAttribute("title")){
1554                divTooltipContentAux.innerHTML = this.getAttribute("title");
1555
1556                this.setAttribute('data-title', this.title); 
1557                this.title = ''
1558                this.onmouseout= function(){this.setAttribute('title', this.getAttribute('data-title'))};
1559            } else {
1560                
1561                divTooltipContentAux.textContent = '';
1562                divTooltipContentAux.textContent = this.textContent;
1563            }
1564            tooltipContent = divTooltipContentAux;
1565        }
1566
1567        this.tooltipContent=tooltipContent;
1568
1569        let pos = this.getBoundingClientRect(), x, y;
1570        if(e instanceof MouseEvent){
1571            x = e.clientX + 10;
1572            y = e.clientY + 10 + window.scrollY;
1573        } else{
1574            x = pos.left;
1575            y = pos.top + pos.height + window.scrollY;
1576        }
1577
1578        tooltipContent.style.top = y + "px";
1579        tooltipContent.style.left = x + "px";
1580
1581        if (opt && opt.funcallback ) opt.funcallback(this);
1582        
1583        tooltipContent.style.display="block";
1584        this.resizeTooltipINE();
1585  
1586    }
1587
1588    eventoTooltipINE_OUT= function(opt,e){
1589        if (this.tooltipContent){
1590            this.tooltipContent.style.display="none";
1591        }
1592    }
1593
1594    eventoTooltipINE_KEY = function(opt, e){
1595        if(e.type == "keydown" && e.key == "Escape"){
1596            e.preventDefault();
1597            e.stopImmediatePropagation();
1598            eventoTooltipINE_OUT.bind({tooltipContent: document.querySelector(".tooltipINE-content[style*='block']")})();
1599        }
1600    }
1601
1602    HTMLElement.prototype.tooltipINE = function (opt){
1603        this.scrollbarWidth = window.scrollbarWidth;
1604
1605        
1606        let eventosIN = ["mouseover","focus"];
1607        let eventosOUT = ["mouseout","focusout"];
1608
1609        this.resizeTooltipINE=resizeTooltipINE;
1610
1611        if (opt && opt.eventsIN){
1612            opt.eventsIN.forEach(function(currentValue){
1613                if (eventosIN.indexOf(currentValue)<0)
1614                eventosIN.push(currentValue);
1615            })
1616        }
1617
1618        if (opt && opt.eventsOUT){
1619            opt.eventsOUT.forEach(function(currentValue){
1620                if (eventosOUT.indexOf(currentValue)<0)
1621                eventosOUT.push(currentValue);
1622            })
1623        }
1624
1625        eventosIN.forEach(function(ev){ 
1626            this.removeEventListener(ev, eventoTooltipINE_IN.bind(this,opt), {passive: true});
1627            this.addEventListener(ev, eventoTooltipINE_IN.bind(this,opt), {passive: true});
1628        }.bind(this));
1629
1630        eventosOUT.forEach(function(ev){ 
1631            this.removeEventListener(ev, eventoTooltipINE_OUT.bind(this,opt), {passive: true});
1632            this.addEventListener(ev, eventoTooltipINE_OUT.bind(this,opt), {passive: true});
1633        }.bind(this));
1634
1635        document.body.removeEventListener("keydown", eventoTooltipINE_KEY.bind(this,opt), false);
1636        document.body.addEventListener("keydown", eventoTooltipINE_KEY.bind(this,opt), false);
1637    } 
1638    
1639    NodeList.prototype.tooltipINE = function (opt){
1640        this.forEach(function(el){     
1641                el.tooltipINE(opt);
1642        });
1643    }
1644
1645    HTMLElement.prototype.tooltip = HTMLElement.prototype.tooltipINE;
1646    NodeList.prototype.tooltip = NodeList.prototype.tooltipINE;
1647
1648    ine.isReady(function(){
1649        //forzamos reescribir tooltip para evitar los problemas con jqueryUI y bootstrap
1650        HTMLElement.prototype.tooltip = HTMLElement.prototype.tooltipINE;
1651        NodeList.prototype.tooltip = NodeList.prototype.tooltipINE;
1652        document.querySelectorAll(".tooltip,.tooltipINE").tooltip();
1653        //carga de textos de tooltip antigua por retrocompatibilidad
1654        if (typeof TextoCargado == 'undefined' && typeof loadUrlScript == "function"){
1655            loadUrlScript(HM_DirJs+ "/" + HM_idioma + "/textoTooltip.js", null,null);
1656        }
1657    });
1658HTMLElement.prototype.dialog = function (...args) {
1659	// Función para comprobar si lo que se recibe es un json
1660	function jsonTest(text){
1661		if(typeof text == "undefined") return false;
1662
1663		if (typeof text != "string"){
1664			try {
1665				text = JSON.stringify(text)
1666			} catch(jerr){
1667				return false;
1668			}
1669		}
1670
1671		if (/^[\],:{}\s]*$/.test(text.replace(/\\["\\\/bfnrtu]/g, '@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
1672			return true;
1673
1674		} 
1675		
1676		return false;
1677	}
1678
1679	// Si ya hay un diálogo, lo eliminamos
1680	try { document.body.querySelector("body > .modal").remove(); } catch (e) { }
1681
1682	// Establecemos los parámetros por defecto
1683	let title = !args[0] ? this.dialog.lang.warning : args[0], body = args[1], options = args[2];
1684
1685	// Si no se recibe el cuerpo del mensaje 
1686	// tomamos el propio elemento como contenido del diálogo
1687	if(typeof body == "undefined"){ body = this.outerHTML }
1688
1689	// Si el segundo argumento es un JSON establecemos
1690	// como cuerpo del mensaje el elemento del que se llama y
1691	// como opciones de configuración el JSON enviado
1692	if(jsonTest(args[1])){
1693		body = this.outerHTML;
1694		options = args[1];
1695	} else if(args[1] instanceof HTMLElement) {
1696		body = args[1].outerHTML;
1697	}
1698
1699	// Si, después de todo, no hay opciones establecidas
1700	// definimos el JSON de configuración por defecto
1701	if(typeof options == "undefined" || options == "" || !options){
1702		options = {
1703			'ok': {
1704				text: this.dialog.lang.close,
1705				action: this.dialog.close
1706			},
1707			'draggable': true,
1708			'callback': null
1709		};
1710	}
1711
1712	// Si no tiene el atributo de arrastrable establecido, lo asignamo a true por defecto
1713	if(!options.hasOwnProperty("draggable")) options.draggable = true;
1714
1715	// Definimos la plantilla
1716	let cont = body.toLowerCase().substring(1, 4) == "div" ? body : ("<div>" + body + "</div>");
1717	let type = this.tagName == "IFRAME" ? " iframe" : "";
1718	let clss = (options.hasOwnProperty("class") && options.class.trim() != "") ? (" " + options.class) : '';
1719	let dlid = "dlg-" + Math.random().toString(16).slice(2);
1720	let dlOp = cont.indexOf("thickBoxINE") != -1 ? " style='visibility: hidden; opacity: 0'" : "";
1721	let base = `
1722    <div id="${dlid}" class="modal${type}${clss}" role="dialog" aria-labelledby="modalTitle" aria-modal="true">
1723        <article class="modal-content"${dlOp}>
1724            <header class="modal-header">
1725			    <button class="close" onclick="this.closest('.modal').remove()" aria-label="${this.dialog.lang.close}"><i class="ii ii-times"></i></button>
1726				<span id="modalTitle">${title}</span>
1727			</header>
1728            <div class="modal-body">${cont}</div>
1729			<footer class="modal-footer"></footer>
1730        </article>
1731    </div>`;
1732
1733	document.body.insertAdjacentHTML("beforeend", base);
1734
1735	if(this.tagName == "IFRAME"){
1736		let elem=document.querySelector("#" + dlid + " .modal-body");
1737		elem.innerHTML = elem.querySelector(":scope iframe").outerHTML;
1738	} 
1739
1740	//if (typeof body == "object") body.remove();
1741
1742	// Calculamos altura y anchura del diálogo
1743	let modalHeader = document.querySelector("#" + dlid + " .modal-header"),
1744		modalBody = document.querySelector("#" + dlid + " .modal-body"),
1745	    modalCont = document.querySelector("#" + dlid + " .modal-content"),
1746		modalFooter = document.querySelector("#" + dlid + " .modal-footer");
1747
1748	if(modalBody.querySelector("iframe")){
1749		modalCont.style.height = (parseInt(getComputedStyle(modalBody).height) + 40) + "px";
1750		modalCont.style.width = (modalBody.querySelector("iframe").offsetWidth + 40) + "px";
1751
1752		if(cont.indexOf("thickBoxINE") == -1){
1753			modalCont.querySelector("iframe").addEventListener("load", function(){
1754				modalCont.style.opacity = 1;
1755				modalCont.style.visibility = "";
1756			}, false);
1757		}
1758	}
1759
1760	// Si entre las opciones se solicita un alto determinado
1761	if(options.hasOwnProperty("height") && options.height != null){ 
1762		modalCont.style.height = parseFloat(options.height) == options.height ? (options.height + 'px') : options.height;
1763	}
1764
1765	// Si entre las opciones se solicita un ancho determinado
1766	if(options.hasOwnProperty("width") && options.width != null){ 
1767		modalCont.style.width = parseFloat(options.width) == options.width ? (options.width + 'px') : options.width;
1768		if(modalBody.querySelector("iframe")){
1769			modalCont.style.left = 0;
1770			//modalCont.style.transform = "translate(0%, -50%)";
1771
1772		} 
1773	}
1774
1775	// Si se solicitan otras opciones
1776	for(var key in options){
1777		if(Array.from(getComputedStyle(document.body)).indexOf(key) != -1){
1778			if(key == "width" || key == "height") continue;
1779
1780			modalCont.style[key] = options[key];
1781		}
1782	}
1783	
1784	// Definimos el pie del diálogo
1785	if((options.hasOwnProperty("ok") || options.hasOwnProperty("nok")) && !options.onlyClose){
1786		if(options.ok){
1787			let okbtn = document.createElement("button")
1788			okbtn.innerHTML = options.ok.text;
1789
1790			modalFooter.append(okbtn);
1791			okbtn.onclick = function(e){
1792				e.preventDefault()
1793				if(typeof options.ok.action == "function") options.ok.action(e);
1794				this.dialog.close(e);
1795			}
1796		}
1797
1798		if(options.nok){
1799			let cancelbtn = document.createElement("button")
1800			cancelbtn.innerHTML = options.nok.text;
1801
1802			modalFooter.append(cancelbtn);
1803			cancelbtn.onclick = function(e){
1804				e.preventDefault()
1805				if(typeof options.nok.action == "function") options.nok.action(e);
1806				this.dialog.close(e);
1807			}
1808		}
1809
1810	} else {
1811		// Si options es un JSON vacío o no está definido
1812		// lo eliminamos
1813		modalFooter.remove();
1814	}
1815
1816	// Habilitamos el evento de click fuera del propio diálogo
1817	// para conseguir que se cierre automáticamente
1818	window.addEventListener("click", function (event) {
1819		if (event.target.classList.contains("modal")) {
1820			event.target.remove();
1821		}
1822	}, { passive: true });
1823
1824	// Habilitamos el evento de keypress fuera del propio diálogo
1825	// para conseguir que se cierre automáticamente
1826	window.addEventListener("keydown", function (event) {
1827		if (event.key === "Escape" && document.body.querySelector(".modal")) {
1828			document.body.querySelector(".modal").remove();
1829		}
1830	}, { passive: true });
1831
1832	// Si entre las opciones se solicita que sea arrastrable
1833	if(options.draggable){
1834		modalHeader.addEventListener('mousedown', this.dialog.onMouseDown, { passive: true });
1835		document.addEventListener('mousemove', this.dialog.onMouseMove, { passive: true });
1836		document.addEventListener('mouseup', this.dialog.onMouseUp, { passive: true });
1837
1838		modalCont.parentElement.classList.add("draggable");
1839		this.dialog.state = { isDragging: false, xDiff: 0, yDiff: 0, x: 0, y: 0, target: modalCont };
1840	}
1841
1842	if(options.callback){
1843		options.callback()
1844	}
1845
1846	// Ponemos el foco en el primer elemento enfocable del diálogo
1847	try{
1848		document.querySelector("#" + dlid + " .modal-body *:is(input, button, select, textarea, a), #" + dlid + " .modal-footer button").focus();
1849	} catch(dlgerr){}
1850
1851	return this;
1852}
1853
1854HTMLElement.prototype.dialog.close = function (e) {
1855	let dlg = e.target.closest(".modal");
1856	if(dlg) dlg.remove();
1857}
1858
1859// Hacemos la llamada global
1860document.dialog = HTMLElement.prototype.dialog;
1861
1862// Hacer el include virtual en vez de esto
1863HTMLElement.prototype.dialog.lang = {
1864	"close": "Cerrar",
1865	"warning": "Aviso",
1866	"accept": "Aceptar",
1867	"cancel": "Cancelar"
1868};
1869
1870HTMLElement.prototype.dialog.state = {
1871    isDragging: false,
1872    xDiff: 0,
1873    yDiff: 0,
1874    x: 0,
1875    y: 0,
1876	target: null
1877};
1878
1879HTMLElement.prototype.dialog.renderWindow = function() {
1880    this.state.target.style.left = this.state.x + 'px';
1881	this.state.target.style.top = this.state.y + 'px';
1882}
1883
1884HTMLElement.prototype.dialog.clampX = function(n) {
1885    return Math.min(Math.max(n, 0), document.body.offsetWidth - this.state.target.offsetWidth/2);
1886}
1887
1888HTMLElement.prototype.dialog.clampY = function(n) {
1889    return Math.min(Math.max(n, 0), document.body.offsetHeight);
1890}
1891
1892HTMLElement.prototype.dialog.onMouseMove = function(e) {
1893    if (e.target.dialog && e.target.dialog.state.isDragging) {
1894        e.target.dialog.state.x = this.dialog.clampX(e.pageX - e.target.dialog.state.xDiff);
1895        e.target.dialog.state.y = this.dialog.clampY(e.pageY - e.target.dialog.state.yDiff);
1896
1897		// Update window position
1898		this.dialog.renderWindow();
1899    }
1900}
1901
1902HTMLElement.prototype.dialog.onMouseDown = function(e) {
1903    e.target.dialog.state.isDragging = true;
1904	e.target.dialog.state.x = parseInt(getComputedStyle(this.dialog.state.target).left);
1905	e.target.dialog.state.y = parseInt(getComputedStyle(this.dialog.state.target).top);
1906    e.target.dialog.state.xDiff = e.pageX - e.target.dialog.state.x;
1907    e.target.dialog.state.yDiff = e.pageY - e.target.dialog.state.y;
1908}
1909
1910HTMLElement.prototype.dialog.onMouseUp = function(e) {
1911    if (e.target.dialog) e.target.dialog.state.isDragging = false;
1912}
1913
1914function alerta(msg, title){
1915    document.body.dialog(title, msg, {
1916        'ok': {
1917			text: document.body.dialog.lang.close,
1918			action: function () {
1919				document.querySelector("body > .modal").remove();
1920			}
1921		}
1922    });
1923}
1924
1925function dialogByURL(title, url, props, callback) {
1926	if(typeof props == "undefined") props = {};
1927	
1928	let opt = {
1929        'ok': {
1930            text: "OK",
1931            action: function (e) {
1932				e.preventDefault();
1933				
1934				if(callback && typeof callback == "function") callback(e)
1935				document.querySelector("body > .modal").remove();
1936            }
1937        }
1938    };
1939
1940	if(!props.hasOwnProperty("onlyClose") || !Boolean(props.onlyClose)){
1941		opt.ok.action = function (e) {
1942			e.preventDefault();
1943			
1944			if(callback && typeof callback == "function") callback(e)
1945			document.querySelector("body > .modal").remove();
1946		}
1947
1948		opt.nok = {
1949            text: "Cancelar",
1950            action: function () {
1951                document.querySelector("body > .modal").remove();
1952            }
1953        }
1954		
1955	opt.nok.action = function () {
1956        document.querySelector("body > .modal").remove();
1957		}
1958    }
1959
1960    var ifrm = document.createElement("iframe");
1961
1962	ifrm.src = url;
1963
1964	for (let key in props) {
1965        if(key == "width" || key == "height"){
1966            ifrm.style[key] = props[key] == parseInt(props[key]) ? (props[key] + "px") : props[key];
1967        } else if(key != "onlyClose") {
1968            ifrm.style[key] = props[key];
1969        }
1970		opt[key] = props[key];
1971    }
1972
1973	
1974	ifrm.dialog(title, opt)
1975}

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.