PageSourceSearch

https://saludcastillayleon.es/sanidad/javaScript/init.js?nc=1787781600000

js saludcastillayleon.es collected 2026-09-24 08:54:02 UTC 118,006 bytes, 2,909 lines download raw bytes

1/** @namespace Init */
2/*!
3 * Este archivo lleva las acciones que se han de ejecutar
4 * cuando esta cargado el dom y cuando está cargada la página.
5 *
6 * Copyright(c) Divisa Informática y Telecomunicaciones S.A.
7 */
8
9if(typeof(_rootWeb) != 'string' && window.top && typeof(window.top._rootWeb) == 'string') {
10    var _rootWeb = window.top._rootWeb;
11}
12if(typeof(_userLocale) != 'string' && window.top && typeof(window.top._userLocale) == 'string') {
13    var _userLocale = window.top._userLocale;
14}
15if(typeof(_userLocaleLang) != 'string' && window.top && typeof(window.top._userLocaleLang) == 'string') {
16    var _userLocaleLang = window.top._userLocaleLang;
17}
18if(typeof(_userLocaleCountry) != 'string' && window.top && typeof(window.top._userLocaleCountry) == 'string') {
19    var _userLocaleCountry = window.top._userLocaleCountry;
20}
21
22/**
23 * Devuelve la versión actual de Proxia
24 * @returns {string} Proxia versión
25 * @memberOf Init
26 */
27function getProxiaVersion() {
28    var metaGenerator = $("meta[name=generator]");
29    if(metaGenerator.length > 0)
30        return metaGenerator.attr("content");
31    else
32        return "Proxia© Content Manager";
33}
34
35/**
36 * Configuración por defecto de las tooltip para todo el portal
37 * @type {{position: {corner: {target: string, tooltip: string}}, style: {name: string}, show: {effect: {type: qTipDefaults.show.effect.type}}, hide: {fixed: boolean, effect: {type: qTipDefaults.hide.effect.type}}}}
38 * @memberOf Init
39 */
40qTipDefaults = {
41    position: {
42        corner: {
43            target: 'center',
44            tooltip: 'topLeft'
45        }
46    },
47    style: {
48        name: 'light'
49    },
50    // sobrescribimos los efectos al mostrar y ocultar, para evitar que en ie
51    // nos aparezca el bug con el cleartype de las fuentes al aplicar filtros
52    show: {
53        effect: {
54            type: function(){ (!$.browser.msie) ? $(this).fadeIn() : $(this).show(); }
55        }
56    },
57    hide: {
58        fixed: true,
59        effect: {
60            type: function(){ (!$.browser.msie) ? $(this).fadeOut() : $(this).hide(); }
61        }
62    }
63}
64
65/**
66 * Función que devuelve el dominio completo de una url
67 * @param {string} str - Url a comprobar
68 * @returns {string} - Dominio
69 * @memberOf Init
70 */
71function getDomain(str) {
72    if(str && str != "") {
73        _domain = str.match(/:\/\/(.[^/]+)/);
74        if(_domain != null && _domain.length > 0) {
75            return _domain[1];
76        }
77    }
78    return "";
79}
80
81/**
82 * Función que devuelve la parte de dominio de una url
83 * @param {string} url Url a comprobar
84 * @returns {string} Dominio
85 * @memberOf Init
86 */
87function getDomainName(url) {
88    var url_parts = url.split('/');
89    var domain_name_parts = url_parts[2].split(':');
90    var domain_name = domain_name_parts[0];
91    var domain_parts = domain_name.split('.');
92    // Si existen subdominios sólo cogemos la parte del dominio
93    if(domain_parts.length >= 2){
94        domain_name = domain_parts[domain_parts.length-2];
95        domain_name += "."+domain_parts[domain_parts.length-1];
96    }
97    return domain_name;
98}
99
100/**
101 * Función que devuelve la clave del flowPlayer en función del dominio
102 * @returns {string} Clave del flowPlayer
103 * @memberOf Init
104 */
105function getFlpKey() {
106    var domain_name = getDomainName(window.location.href);
107    for(var i= 0; i < flpKeys.length; i++) {
108        if(flpDomains[i].toLowerCase() == domain_name.toLowerCase()) {
109            return flpKeys[i];
110        }
111    }
112    // Devolvemos una key por defecto si no hemos encontrado una
113    return flpKeys[0];
114}
115
116/**
117 * Array para flowPlayer con los respectivos dominios y keys
118 * @type {Array}
119 * @memberOf Init
120 */
121var flpDomains = "{flowplayer.domains}".split(",");
122
123/**
124 * Array para flowPlayer con los respectivos dominios y keys
125 * @type {Array}
126 * @memberOf Init
127 */
128var flpKeys = "#daef8215901bf76af63".split(",");
129
130var flpSettings = '';
131
132/**
133 * Función que carga los settings para el Flowplayer
134 * @memberOf Init
135 */
136function loadflpSettings(){
137    // Settings que utilizamos para embeber el Flowplayer dentro del prettyPhoto
138    if(flpSettings!='') return;
139
140    // Si el idioma no está soportado cargamos en inglés
141    var supportedLanguages = ['en','es','fr','pt','nl','de'];
142    var scriptToLoad = _rootWeb+'/javaScript/flowplayer/lang/flowplayer-en.js';
143    if($.inArray(_userLocaleLang, supportedLanguages) != -1) {
144        scriptToLoad = _rootWeb+'/javaScript/flowplayer/lang/flowplayer-'+_userLocaleLang+'.js';
145    }
146
147    loadScript({ url: scriptToLoad, success: function(){
148            flpSettings =	'"key": "'+getFlpKey()+'",'+
149                '"logo": {'+
150                '    "url": "'+_rootWeb+'/imagenes/video/logo.png",'+
151                '    "bottom": 22,'+
152                '    "right": 22,'+
153                '    "width": 40,'+
154                '    "height": 40,'+
155                '    "opacity": 0.8,'+
156                '    "fullscreenOnly": false,'+
157                '    "displayTime": 10,'+
158                '    "fadeSpeed": 300'+
159                '},'+
160                '"plugins":  {'+
161                '    "controls": {'+
162                '        "autoHide": "always",'+
163                '        "stop": true,'+
164                '        "tooltips": {'+
165                '            "buttons": true, '+
166                '            "play" : "'+ FlowPlayer.TT['PLAY'] +'", '+
167                '            "pause" : "'+FlowPlayer.TT['PAUSE']+'", '+
168                '            "mute" : "'+FlowPlayer.TT['MUTE']+'", '+
169                '            "unmute" : "'+FlowPlayer.TT['UNMUTE']+'", '+
170                '            "stop" : "'+ FlowPlayer.TT['STOP']+'", '+
171                '            "fullscreen" : "'+FlowPlayer.TT['FULLSCREEN']+'", '+
172                '            "fullscreenExit" : "'+FlowPlayer.TT['FULLSCREEN_EXIT']+'", '+
173                '            "next" : "'+FlowPlayer.TT['NEXT']+'", '+
174                '            "previous" : "'+FlowPlayer.TT['PREVIOUS']+'"'+
175                '        }'+
176                '    }'+
177                '}, '+
178                '"clip": {'+
179                '    "url": "{path}",'+
180                '    "scaling": "orig",'+
181                '    "accelerated": false,'+
182                '    "linkWindow": "_blank"'+
183                '},'+
184                '"contextMenu": ['+
185                '    "'+getProxiaVersion()+'",'+
186                '    "Powered by Flowplayer"'+
187                ']';
188        }});
189}
190
191/**
192 * Función que carga el prettyPhoto
193 * @memberOf Init
194 */
195function loadPrettyPhoto() {
196    $("a[rel^='prettyPhoto']:not(.cmPhotoSwipe),a[data-rel^='prettyPhoto']:not(.cmPhotoSwipe)").prettyPhoto({
197        flowplayerSettings: flpSettings
198    });
199}
200
201/**
202 * Función que carga el FlowPlayer
203 * @memberOf Init
204 */
205function loadFlowPlayer() {
206    var $videos = $('a.cmAutoVideo,a.cmAutoVideoNoAlt');
207    if($videos.length > 0) {
208
209        // Activamos el flowplayer, en primer lugar nos aseguramos de que el funcionamiento
210        // es el correcto limpiando y eliminado aquellos elementos que no funcionan, el
211        // A debe estar vacío para que empiece el auto-play del video y el href no puede
212        // tener caracteres &, puesto que esto afecta al parseado JSON del flowplayer.
213        $('em.cmAutoVideoNoAlt,a.cmAutoVideoNoAlt').show(); // Aquellos videos que no tienen imagen de splash
214
215        // Cogemos el nombre del recurso y lo añadimos antes del enlace
216        $videos.each(function() {
217            $(this).wrap("<em class=\"cmEmbeddedResource\"/>");
218            var _em = $(this).parent();
219            _em.prepend($("span", $(this)));
220
221            // Añadimos al EM las clases css del enlace
222            var classes = ($(this).attr("class")).split(' ');
223            for(var i = 0; i < classes.length; i++) {
224                var currentClass = $.trim(classes[i]);
225                if(currentClass.indexOf('cmEmbedImage') != -1) $(this).removeClass(currentClass);
226                _em.addClass(currentClass);
227            }
228
229            // Eliminamos el contenido del enlace antes de insertar el object del flowplayer
230            $(this).empty();
231        });
232
233        // Vamos a modificar la URL del href..., si tehemos un atributo
234        // path quiere decir que tenemos que utilizar este en lugar
235        // de extractar el idMmedia que es la opción que estamos aplicando
236        // hasta ahora.
237        $('a.cmAutoVideo').attr('href',function() {
238            // Recuperamos el índice base.
239            var currentUrl = this.href
240            var _baseIndex = currentUrl.indexOf('tkShowResource');
241            // Comportamiento antiguo.
242            if(_baseIndex != -1) {
243                var hasPath = currentUrl.indexOf('path');
244                if(hasPath!=-1) {
245                    // Ahora tenemos que encontrar el siguiente & o en su defecto el fin
246                    var _nextAmp = currentUrl.indexOf('&',hasPath);
247                    var url = false;
248                    if(_nextAmp!=-1) {
249                        url = currentUrl.substring(hasPath+5,_nextAmp);
250                    } else {
251                        url = currentUrl.substring(hasPath+5);
252                    }
253                    return url;
254                } else {
255                    // Ahora, tenemos que obtener los datos
256                    var _idMmediaIndx = currentUrl.indexOf('idMmedia=');
257                    // Ahora tenemos que encontrar el siguiente & o en su defecto el fin
258                    var _nextAmp = currentUrl.indexOf('&',_idMmediaIndx);
259
260                    var _url = currentUrl.substring(0,_baseIndex)+'images?idMmedia=';
261                    if(_nextAmp != -1) {
262                        _url+=currentUrl.substring(_idMmediaIndx+9,_nextAmp);
263                    } else {
264                        _url+=currentUrl.substring(_idMmediaIndx+9);
265                    }
266                    return _url;
267                }
268            } else {
269                // En el comportamiento nuevo el nombre del recurso sera
270                // del tipo path_base/s,id-fichero, tenemos que eliminar
271                // el caracter s,
272                var tmpImage = currentUrl;
273                var baseImage = '';
274                if(tmpImage.indexOf('/')!=-1) {
275                    baseImage = tmpImage.substring(0,tmpImage.lastIndexOf('/')+1);
276                    tmpImage = tmpImage.substring(tmpImage.lastIndexOf('/')+1);
277                }
278                if(tmpImage.indexOf('g,') == 0 || tmpImage.indexOf('s,') == 0 ||
279                    tmpImage.indexOf('f,') == 0) {
280                    tmpImage = tmpImage.substring(2);
281                }
282                return baseImage+tmpImage;
283            }
284        });
285
286        // Instanciamos los flowplayer.
287        flowplayer("a.cmAutoVideo", _rootWeb+"/javaScript/flowplayer/flowplayer.unlimited-3.1.5.swf",{
288            key: getFlpKey(),
289            logo: {
290                url: _rootWeb+'/imagenes/video/logo.png',
291                bottom: 22,
292                right: 22,
293                width: 40,
294                height: 40,
295                opacity: 0.8,
296                fullscreenOnly: false,
297                displayTime: 10,
298                fadeSpeed: 300
299            },
300            plugins: {
301                controls: {
302                    tooltipColor: '#70c6a9',
303                    tooltipTextColor: '#000000',
304                    sliderColor: '#70c6a9',
305                    volumeSliderColor: '#70c6a9',
306                    autoHide: 'always',
307                    stop: true,
308                    tooltips: {
309                        buttons: true,
310                        play: FlowPlayer.TT['PLAY'],
311                        pause: FlowPlayer.TT['PAUSE'],
312                        mute: FlowPlayer.TT['MUTE'],
313                        unmute: FlowPlayer.TT['UNMUTE'],
314                        stop: FlowPlayer.TT['STOP'],
315                        fullscreen: FlowPlayer.TT['FULLSCREEN'],
316                        fullscreenExit: FlowPlayer.TT['FULLSCREEN_EXIT'],
317                        next: FlowPlayer.TT['NEXT'],
318                        previous: FlowPlayer.TT['PREVIOUS']
319                    }
320                }
321            },
322            clip: {
323                scaling: 'orig',
324                accelerated: false,
325                linkWindow: '_blank'
326            },
327            contextMenu: [
328                // Indicamos que es un video Powered by Proxia
329                getProxiaVersion(),
330                "Powered by Flowplayer"
331            ]
332        });
333
334        // En el caso de que el video no tenga imagen de inicio, decimos
335        // que la reproducción no se inicie de forma automática...
336        $('a.cmAutoVideoNoAlt').flowplayer().each(function() {
337            this.onLoad(function() {
338                this.getClip(0).update({autoPlay:false});
339            });
340        });
341
342        // Añadimos al EM las mismas dimensiones que las de su enlace hijo
343        $('em.cmAutoVideoNoAlt').each(function() {
344            $(this).css('width',$("a", $(this)).css('width'));
345            $(this).css('height',$("a", $(this)).css('height'));
346        });
347    };
348
349    // Plugin para el modelo videoteca
350    if($("#videoteca,#videotecaPlayer").length > 0) {
351
352        // Número de videos a mostrar en el scrolling,
353        // si no hemos especificado uno previamente...
354        if(typeof(videotecaSize) != 'number') videotecaSize = 4;
355
356        // Proporcionamos scrolling a la barra horizontal de videos
357        $("#videoteca").scrollable({items:'div.entries', size:videotecaSize, clickable:false});
358
359        // Configuración del flowplayer
360        flowplayer("videotecaPlayer", _rootWeb+"/javaScript/flowplayer/flowplayer.unlimited-3.1.5.swf", {
361            key: getFlpKey(),
362            logo: {
363                url: _rootWeb+'/imagenes/video/logo.png',
364                bottom: 22,
365                right: 22,
366                width: 40,
367                height: 40,
368                opacity: 0.8,
369                fullscreenOnly: false,
370                displayTime: 10,
371                fadeSpeed: 300
372            },
373            plugins: {
374                controls: {
375                    autoHide: 'always',
376                    stop: true,
377                    tooltips: {
378                        buttons: true,
379                        play: FlowPlayer.TT['PLAY'],
380                        pause: FlowPlayer.TT['PAUSE'],
381                        mute: FlowPlayer.TT['MUTE'],
382                        unmute: FlowPlayer.TT['UNMUTE'],
383                        stop: FlowPlayer.TT['STOP'],
384                        fullscreen: FlowPlayer.TT['FULLSCREEN'],
385                        fullscreenExit: FlowPlayer.TT['FULLSCREEN_EXIT'],
386                        next: FlowPlayer.TT['NEXT'],
387                        previous: FlowPlayer.TT['PREVIOUS']
388                    }
389                }
390            },
391            clip: {
392                scaling: 'orig',
393                accelerated: false,
394                linkWindow: '_blank',
395                baseUrl: _rootWeb + '/cm/'
396            },
397            contextMenu: [
398                // Indicamos que es un video Powered by Proxia
399                getProxiaVersion(),
400                "Powered by Flowplayer"
401            ]
402        }).playlist("div.entries");
403    }
404}
405
406/*!
407 * Este archivo implementa ciertas funcionalidades de carga de scripts y CSS
408 *
409 * Copyright(c) Divisa Informática y Telecomunicaciones S.A.
410 */
411
412// Array donde guardamos los ficheros (css/js) ya cargados
413var loadedFiles = [];
414
415/**
416 * Función que carga un css de forma dinámica
417 * @param {string} cssFile - Ruta al fichero a enlazar
418 * @memberOf Init
419 */
420function loadCSS(cssFile){
421
422    // Añadimos el parámetro nc a la URL
423    var _url = appendNoCache(cssFile);
424
425    var _src = prepareLoadedFile(_url);
426
427    // Si ya lo hemos cargado no lo volvemos a cargar
428    if(loadedFiles[_src]) return;
429
430    var cssLink=document.createElement("link");
431    cssLink.setAttribute("rel", "stylesheet");
432    cssLink.setAttribute("type", "text/css");
433    cssLink.setAttribute("href", _url);
434    document.getElementsByTagName("head")[0].appendChild(cssLink);
435
436    // Almacenamos en un array el fichero que acabamos de cargar
437    loadedFiles[_src] = true;
438    loadedFiles[_src+'.success'] = true;
439}
440
441/**
442 * Carga un conjunto de ficheros de forma asíncrona en el sistema, sin esperar a que se
443 * cargue uno para cargar el siguiente.
444 *
445 * @param	scriptArray	El array de scripts a cargar
446 */
447function loadSetOfScripts(scriptArray) {
448    for(var i=0;i<scriptArray.length;i++) {
449        loadScript({url:scriptArray[i]});
450    }
451}
452
453/**
454 * Función de callback asociado a la carga de un fichero para permitir recursividad
455 * @param {array} urlArray - Array con todas las urls que tenemos que cargar
456 * @param {number} index - La posición del índice en la que estamos evaluando
457 * @param successFunction - Callback cuando todo ha ido bien.
458 * @memberOf Init
459 */
460function loadScriptFile(urlArray, index,
461                        successFunction) {
462    var i = index+1;
463    if(urlArray.length > i) {
464        loadScript({url: urlArray[i], success: function() {
465                // Nos llamamos de forma recursiva.
466                loadScriptFile(urlArray,i,successFunction);
467            }});
468
469    } else {
470        if(typeof successFunction == 'function') {
471            successFunction();
472        }
473    }
474}
475
476/**
477 * Carga un javaScript de forma dinámica
478 * @param {Object} opts - Las opciones
479 * @param {string} opts.url - Url del JS
480 * @param {boolean} opts.success - El estado
481 * @param {boolean} opts.error - Si hay error
482 * @memberOf Init
483 */
484function loadScript(opts){
485    if(opts.url == false || opts.url == 'undefined' || opts.url == null) {
486        opts.success();
487    }
488
489    // Permitimos un paso de un array de scripts que deben cargarse de forma
490    // secuencial y cuando terminen cargamos el que tenemos asociado.
491    if(opts.url instanceof Array) {
492        var i = 0;
493        loadScript({url: opts.url[0], success:function() {
494                loadScriptFile(opts.url,0,opts.success);
495            }});
496        return;
497    }
498
499    // Añadimos el parámetro nc a la URL
500    var _url = appendNoCache(opts.url);
501
502    // Si ya lo hemos cargado no lo volvemos a cargar
503    var _src = prepareLoadedFile(_url);
504
505    if(loadedFiles[_src]) {
506        // En cualquier caso ejecutamos la función callback si existe
507        if(opts.success) {
508            if(loadedFiles[_src+'.success']) {
509                opts.success();
510            } else {
511                // Si otro proceso inició la carga pero aún no ha acabado,
512                // tendremos que esperar para ejecutar el callback
513                var scriptInterval = setInterval(function() {
514                    if(loadedFiles[_src+'.success']) {
515                        clearInterval(scriptInterval);
516                        opts.success();
517                    }
518                    if(loadedFiles[_src+'.error']) {
519                        clearInterval(scriptInterval);
520                    }
521                }, 100);
522            }
523        }
524        return;
525    }
526
527    var script = document.createElement('script');
528    script.setAttribute('type', 'text/javascript');
529    script.setAttribute('src', _url);
530    if(opts.error) script.onerror = opts.error;
531    document.getElementsByTagName("head")[0].appendChild(script);
532
533    // Almacenamos en un array el fichero para que no se vuelva a cargar otra vez
534    var _src = prepareLoadedFile(_url);
535    loadedFiles[_src] = true;
536
537    script.onload = script.onreadystatechange = function(){
538        if ( !this.readyState || this.readyState == "loaded" || this.readyState == "complete" ) {
539            if(opts.success) opts.success();
540
541            // Registramos la finalización con éxito de la carga del fichero
542            loadedFiles[_src+'.success'] = true;
543
544            // Handle memory leak in IE
545            script.onload = script.onreadystatechange = null;
546        } else {
547            // Registramos la finalización con error de la carga del fichero
548            loadedFiles[_src+'.error'] = true;
549        }
550    };
551};
552
553/**
554 * Función que añade a una url el parametro noCache
555 * @param {string} _url - Url
556 * @returns {string} La url a devolver
557 * @memberOf Init
558 */
559function appendNoCache(_url) {
560    if(typeof(_noCache) == 'string' && _url.indexOf('nc=') == -1) {
561        if(_url.indexOf('?') != -1) {
562            _url += '&';
563        } else {
564            _url += '?';
565        }
566        _url += _noCache;
567    }
568    return _url;
569}
570
571/**
572 * Función que prepara el archivo para cargarlo
573 * @param {string} _src - Source
574 * @returns {string} Source
575 * @memberOf Init
576 */
577function prepareLoadedFile(_src) {
578    if(_src.indexOf("//") != -1) _src = _src.substr(_src.indexOf("//") + 2);
579    if(_src.indexOf("?") != -1) _src = _src.substr(0, _src.indexOf("?"));
580    if(_src.indexOf("/") != -1) _src = _src.substr(_src.indexOf("/"));
581
582    return _src;
583}
584
585/**
586 * Función que inicializa el plugin prettyPhoto para imágenes, videos,...
587 * @param fnOnLoad
588 * @memberOf Init
589 */
590function initPrettyPhoto(fnOnLoad) {
591    // Si el idioma no está soportado cargamos en inglés
592    var supportedLanguages = ['en','es','fr','pt','nl','de'];
593    var scriptToLoad = _rootWeb+'/javaScript/prettyPhoto/js/lang/prettyPhoto-en.js';
594    if($.inArray(_userLocaleLang, supportedLanguages) != -1) {
595        scriptToLoad = _rootWeb+'/javaScript/prettyPhoto/js/lang/prettyPhoto-'+_userLocaleLang+'.js';
596    }
597    loadCSS(_rootWeb+'/javaScript/prettyPhoto/css/prettyPhoto.css');
598    loadflpSettings();
599    if(typeof ($.fn.prettyPhoto) == "undefined") {
600        loadScript({ url: scriptToLoad, success: function(){
601                loadScript({ url: _rootWeb+'/javaScript/prettyPhoto/js/jquery.prettyPhoto.js', success: function(){
602                        loadPrettyPhoto();
603                        if(typeof fnOnLoad == 'function') fnOnLoad();
604                    }});
605            }});
606    }else{
607        loadPrettyPhoto();
608        if(typeof fnOnLoad == 'function') fnOnLoad();
609    }
610}
611
612/**
613 * Función que inicializa el plugin flowPlayer para videos...
614 * @memberOf Init
615 */
616function initFlowPlayer() {
617    loadflpSettings();
618    if(typeof ($.fn.flowplayer) == "undefined") {
619        loadScript({ url: _rootWeb+'/javaScript/flowplayer/flowplayer-3.1.4.min.js', success: function(){
620                loadScript({ url: _rootWeb+'/javaScript/flowplayer/flowplayer.playlist-3.0.7.min.js', success: function(){
621                        loadFlowPlayer();
622                    }});
623            }});
624    }else{
625        loadFlowPlayer();
626    }
627}
628
629/**
630 * Función que carga el plugin photoSwipe para recursos multimedia
631 * @param {string} $container - El lugar en el que se va a cargar el plugin
632 * @param {string} callback - El callback
633 * @memberOf Init
634 */
635function initPhotoSwipe($container, callback) {
636
637    loadflpSettings();
638    if(typeof(PhotoSwipe) != 'function') {
639        loadCSS(_rootWeb+'/javaScript/photoswipe/photoswipe.css');
640        loadCSS(_rootWeb+'/javaScript/photoswipe/default-skin/default-skin.css');
641        loadScript({ url: _rootWeb+'/javaScript/photoswipe/photoswipe.min.js', success: function(){
642                loadScript({ url: _rootWeb+'/javaScript/photoswipe/photoswipe-ui-default.min.js', success: function(){
643                        loadPhotoSwipe($container);
644                        if(typeof(callback) == 'function') callback($container);
645                    }});
646            }});
647    } else {
648        loadPhotoSwipe($container);
649        if(typeof(callback) == 'function') callback($container);
650    }
651
652}
653
654/**
655 * Función que inicializa el plugin photoSwipe para recursos multimedia
656 * @param {string} $container=body - El lugar en el que se va a inicializar el plugin
657 * @memberOf Init
658 */
659function loadPhotoSwipe($container) {
660
661    if(!$container) $container = $("body");
662
663    var markupPhotoSwipe = ' \
664		<div class="pswp" tabindex="0" role="dialog" aria-hidden="true"> \
665			<div class="pswp__bg"></div> \
666			<div class="pswp__scroll-wrap"> \
667				<div class="pswp__container"> \
668					<div class="pswp__item"></div> \
669					<div class="pswp__item"></div> \
670					<div class="pswp__item"></div> \
671				</div> \
672				<div class="pswp__ui pswp__ui--hidden"> \
673					<div class="pswp__top-bar"> \
674						<div class="pswp__counter"></div> \
675						<div class="pswp__buttons"> \
676							<button class="pswp__button pswp__button--zoom" title="'+photoSwipeText.zoomInOut+'"></button> \
677							<button class="pswp__button pswp__button--fs" title="'+photoSwipeText.toggleFullscreen+'"></button> \
678							<button class="pswp__button pswp__button--share" title="'+photoSwipeText.sharePhoto+'"></button> \
679							<button class="pswp__button pswp__button--close" title="'+photoSwipeText.closePhoto+'"></button> \
680						</div> \
681						<div class="pswp__preloader"> \
682							<div class="pswp__preloader__icn"> \
683								<div class="pswp__preloader__cut"> \
684									<div class="pswp__preloader__donut"></div> \
685								</div> \
686							</div> \
687						</div> \
688					</div> \
689					<div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap"> \
690						<div class="pswp__share-tooltip"></div> \
691					</div> \
692					<button class="pswp__button pswp__button--arrow--left" title="'+photoSwipeText.prevPhoto+'"> </button> \
693					<button class="pswp__button pswp__button--arrow--right" title="'+photoSwipeText.nextPhoto+'"> </button> \
694					<div class="pswp__caption" tabindex="0"> \
695						<div class="pswp__caption__center"> \
696							<div class="pswp__caption__title"></div> \
697							<div class="pswp__caption__description"></div> \
698							<div class="pswp__caption__author"></div> \
699						</div> \
700					</div> \
701				</div> \
702			</div> \
703		</div> \
704	';
705
706    if($("body >
706 div.pswp").length == 0) {
707        var $markupPhotoSwipe = $(markupPhotoSwipe);
708        $("body").append($markupPhotoSwipe);
709
710        // para que el foco pueda ser circular dentro del modal
711        $('div.pswp__caption', $markupPhotoSwipe).off("focusin").on("focusin", function(e) {
712            e.preventDefault();
713            $markupPhotoSwipe.focus();
714        });
715    }
716
717    var photoSwipeOptions = {
718        history: false,
719        errorMsg: '<div class="pswp__error-msg">' + photoSwipeText.loadErrMsg + '</div>',
720        selector: 'a.cmPhotoSwipe,area.cmPhotoSwipe',
721        showAnimationDuration : 333,
722        hideAnimationDuration : 333,
723        closeOnScroll: false,
724        shareButtons: [
725            {id:'facebook', label:photoSwipeText.shareOnFacebook, url:'https://www.facebook.com/sharer/sharer.php?u={{image_url}}'},
726            {id:'twitter', label:photoSwipeText.shareOnTwitter, url:'https://twitter.com/intent/tweet?text={{text}}&url={{image_url}}'},
727            {id:'pinterest', label:photoSwipeText.shareOnPinterest, url:'https://www.pinterest.com/pin/create/button/?url={{url}}&media={{image_url}}&description={{text}}'},
728            {id:'download', label:photoSwipeText.downloadMedia, url:'{{raw_image_url}}', download:true}
729        ]
730    };
731
732    // Galerías de imágenes
733    var $photoSwipeGalleries = $("div.cmImageGallery, ul.cm-img-gallery-list", $container);
734    if($photoSwipeGalleries.length > 0) {
735        $photoSwipeGalleries.each(function() {
736            if($("a.cmPhotoSwipe", $(this)).first().data("init")) return true;
737            photoSwipe(photoSwipeOptions, this);
738            $("a.cmPhotoSwipe", $(this)).data("init", true);
739        });
740    }
741
742    // Imágenes individuales
743    var $photoSwipeImages = $container.hasClass("cmPhotoSwipe") ? $container : $("a.cmPhotoSwipe", $container);
744    $photoSwipeImages.each(function() {
745        if($(this).first().data("init")) return true;
746        photoSwipe(photoSwipeOptions, this);
747        $(this).data("init", true);
748    });
749}
750
751/**
752 * Función que abre un enlace de tipo imagen con photoSwipe
753 * @param {object} obj - Objeto en el que se abre el enlace
754 * @param {string} type=image - El tipo
755 * @returns {boolean}
756 * @memberOf Init
757 */
758function openPhotoSwipe(obj, type) {
759    if(!type) type = 'image';
760    var $obj = $(obj);
761
762    if($obj.hasClass("cmPhotoSwipe")) return false;
763
764    $obj.addClass("cmPhotoSwipe");
765    $obj.attr("data-type", type);
766    $obj.attr("data-title", $obj.attr("title") || $obj.attr("alt") || $obj.attr("data-original-title"));
767    $obj.removeAttr("onclick").off("click");
768
769    var href = $obj.attr("href");
770    href = href.replace('/g,','/').replace('/s,','/').replace('/f,','/');
771
772    $obj.attr("data-href", href);
773
774    if(type == 'image') {
775        $("<img/>").load(function(){
776            var w = $(this).width();
777            var h = $(this).height();
778            $(this).remove();
779            if(w && h) $obj.attr("data-size", w.toString()+"x"+h.toString());
780
781            initPhotoSwipe($obj, function($this) {
782                $this.trigger("click");
783            });
784
785        }).attr("src", href).hide().appendTo("body");
786    } else {
787        initPhotoSwipe($obj, function($this) {
788            $this.trigger("click");
789        });
790    }
791
792    return false;
793}
794
795/**
796 * Función que monta una galería
797 * @param {object} options - Opciones de configuracion
798 * @param selector
799 * @memberOf Init
800 */
801function photoSwipe(options, selector){
802    var galleries = [],
803        _options = options;
804
805    var markups = {
806        flash: ' \
807			<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"> \
808				<param name="wmode" value="transparent" /> \
809				<param name="allowfullscreen" value="true" /> \
810				<param name="allowscriptaccess" value="always" /> \
811				<param name="movie" value="{href}" /> \
812				<embed src="{href}" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" wmode="transparent"></embed> \
813			</object> \
814		',
815        audio: ' \
816			<i class="fa fa-file-audio-o"></i> \
817			<audio controls="controls" preload="auto" autoplay="autoplay" src="{href}"> \
818				Your browser does not support the audio element. \
819			</audio> \
820		',
821        video: ' \
822			<video controls="controls" preload="auto" autoplay="autoplay" src="{href}"> \
823				Your browser does not support the video element. \
824			</video> \
825		',
826        flv: ' \
827			<object id="fp_pphoto" type="application/x-shockwave-flash" data="'+_rootWeb+'/javaScript/flowplayer/flowplayer.unlimited-3.1.5.swf"> \
828				<param name="movie" value="'+_rootWeb+'/javaScript/flowplayer/flowplayer.unlimited-3.1.5.swf"/> \
829				<param name="wmode" value="transparent" /><param name="allowfullscreen" value="true"/> \
830				<param name="flashvars" value=\'config={{flpSettings}}\'/> \
831			</object> \
832		',
833        ebook: ' \
834			<object id="ebook" type="application/x-shockwave-flash" data="'+_rootWeb+'/javaScript/pageflip/pageflip_loader.swf"> \
835				<param name="movie" value="'+_rootWeb+'/javaScript/pageflip/pageflip_loader.swf"/> \
836				<param name="wmode" value="transparent" /> \
837				<param name="allowfullscreen" value="true"/> \
838				<param name="allowscriptaccess" value="samedomain"/> \
839				<param name="menu" value="true"/> \
840				<param name="bgcolor" value="#4B4B4B"/> \
841				<param name="flashvars" value="XMLfn={href}"/> \
842				<param name="base" value="'+_rootWeb+'/javaScript/pageflip/"/> \
843			</object> \
844		',
845        jpageflip: ' \
846			<div id="jpfBody"> \
847				<div class="jpfLoader"></div> \
848				<div class="jpfContainer"> \
849					<div class="jpfTopContainer"> \
850						<div class="jpfHead"></div> \
851						<div class="jpfNav"> \
852							<a class="jpfFirst jpfNavButton" href="javascript:;" rel="toolTip"><img src="'+_rootWeb+'/javaScript/jpageflip/images/first.png" alt=""/></a> \
853							<a class="jpfPrev jpfNavButton" href="javascript:;" rel="toolTip"><img src="'+_rootWeb+'/javaScript/jpageflip/images/prev.png" alt=""/></a> \
854							<div class="jpfNavFormPagesDiv"> \
855								<form class="jpfNavFormPages" name="jpfNavFormPages" action=""> \
856									<input class="jpfNavFormPagesInput" name="jpfNavFormPagesInput" type="text" value=""/> \
857								</form> \
858							</div> \
859							<a class="jpfNext jpfNavButton" href="javascript:;" rel="toolTip"><img src="'+_rootWeb+'/javaScript/jpageflip/images/next.png" alt=""/></a> \
860							<a class="jpfLast jpfNavButton" href="javascript:;" rel="toolTip"><img src="'+_rootWeb+'/javaScript/jpageflip/images/last.png" alt=""/></a> \
861						</div> \
862					</div> \
863					<div class="jpfLeftContainer"> \
864						<a class="jpfPrevBig" href="javascript:;"><img class="arrowNav" src="'+_rootWeb+'/javaScript/jpageflip/images/prevBig.png" width="40" alt="" /></a> \
865					</div> \
866					<div class="jpfRightContainer"> \
867						<a class="jpfNextBig" href="javascript:;"><img class="arrowNav" src="'+_rootWeb+'/javaScript/jpageflip/images/nextBig.png" width="40" alt="" /></a> \
868					</div> \
869					<div class="jpfContainerInner"> \
870						<div class="jpfTopContainerInner"></div> \
871						<div class="jpfDivForMoveContainer"> \
872							<div class="jpfDivForMove"></div> \
873						</div> \
874						<div class="jpfInner" data-jpageflip="jPageFlip[path=&quot;{href}&quot;][width=&quot;{width}&quot;][height=&quot;{height}&quot;]"> \
875							<img src="'+_rootWeb+'/javaScript/jpageflip/images/clearpixel.gif" 
875class="jPageFlip jPageFlipZero" alt="" /> \
876						</div> \
877						<div class="jpfBottomContainerInner"></div> \
878					</div> \
879					<div class="jpfBottomContainer"> \
880						<div class="jpfBottom"> \
881							<div class="jpfNavFormGoToDiv"> \
882								<form class="jpfNavFormGoTo" name="jpfNavFormGoTo" action=""> \
883									<label><span class="jpfNavFormGoToLabel"></span><input class="jpfNavFormGoToInput" name="jpfNavFormGoToInput" type="text" value=""/></label> \
884									<button type="submit" name="jpfNavFormGoToButton" class="jpfNavFormGoToButton"><img src="'+_rootWeb+'/javaScript/jpageflip/images/navButton.png" alt="" /><span class="jpfNavFormGoToButtonText"></span></button> \
885								</form> \
886							</div> \
887							<div class="jpfControlButtons"> \
888								<a class="jpfFullscreen jpfNavButton" href="tkJPageFlip" rel="toolTip"><img src="'+_rootWeb+'/javaScript/jpageflip/images/fullscreen.png" alt="" /></a> \
889								<a class="jpfThumbnails jpfNavButton" href="javascript:;" rel="toolTip"><img src="'+_rootWeb+'/javaScript/jpageflip/images/thumbnails.png" alt="" /></a> \
890								<span class="jpfZoomEscale">100%</span> \
891								<span class="jpfSliderZoom"> \
892									<span class="jpfSliderZoomTitle">ZOOM</span> \
893									<a class="jpfZoomMinus" rel="toolTip"></a> \
894									<span class="jpfDraggerZoom" style="left:19px;top:13px;"></span> \
895									<a class="jpfZoomMas" rel="toolTip"></a> \
896								</span> \
897								<a class="jpfPrintleft jpfNavButton" href="javascript:;" rel="toolTip"><img src="'+_rootWeb+'/javaScript/jpageflip/images/printleft.png" alt="" /></a> \
898								<a class="jpfPrintright jpfNavButton" href="javascript:;" rel="toolTip"><img src="'+_rootWeb+'/javaScript/jpageflip/images/printright.png" alt="" /></a> \
899								<a class="jpfDownloadPdf jpfNavButton" href="javascript:;" rel="toolTip"><img src="'+_rootWeb+'/javaScript/jpageflip/images/downloadPdf.png" alt="" /></a> \
900								<span class="jpfSliderAutoFlip"><span class="jpfDraggerAutoFlip" style="left:6px;top:17px;"></span></span> \
901								<span class="jpfAutoFlip"> \
902									<a class="jpfPlay jpfNavButton" href="javascript:;" rel="toolTip"><img src="'+_rootWeb+'/javaScript/jpageflip/images/play.png" alt="" /></a> \
903									<a class="jpfPause jpfNavButton" href="javascript:;" rel="toolTip"><img src="'+_rootWeb+'/javaScript/jpageflip/images/pause.png" alt="" /></a> \
904								</span> \
905							</div> \
906						</div> \
907						<div class="jpfFoot">Powered by <a href="http://www.proxiasuite.com" target="_blank">Proxia</a> &copy;</div> \
908					</div> \
909					<div class="jpfIframeHolder"></div> \
910				</div> \
911			</div> \
912		',
913        iframe: ' \
914			<iframe src="{href}"></iframe> \
915		'
916    };
917
918    var init = function($this){
919        galleries = [];
920
921        var initPhotoSwipeOnResource = function(size, link, galleryId, photoId ){
922            link.data('gallery-id',galleryId);
923            link.data('photo-id', photoId);
924
925            var item = {};
926            item.type = link.data('type');
927            item.title = link.data('title');
928            item.description = link.data('description') && item.title != link.data('description') ? link.data('description') : '';
929            item.author = link.data('author') ? '<strong>' + photoSwipeText.psAuthor + '</strong> ' + link.data('author') : '';
930
931            var href = link.attr("data-href") || link.attr("href");
932            href = href.replace('/g,','/').replace('/s,','/').replace('/f,','/');
933
934            if(href.indexOf('/tkImageGalleryComponent?') != -1) {
935                href = href.replace('/tkImageGalleryComponent?', '/images?');
936            }
937
938            if(!item.type) return true;
939
940            item.type = item.type.toLowerCase();
941
942            var flashSupport = typeof swfobject !== 'undefined' && swfobject.getFlashPlayerVersion().major !== 0;
943
944            var jPageFlipLoaded = false;
945            if(item.type == 'ebook' && !flashSupport) {
946                item.type = 'jpageflip';
947                if(!jPageFlipLoaded) {
948                    loadCSS(_rootWeb+'/javaScript/jpageflip/css/jPageFlip.css');
949                    loadScript({ url: _rootWeb+'/javaScript/jpageflip/js/jquery.jpageflip.js', success: function(){
950                            loadScript({ url: _rootWeb+'/javaScript/jquery.tipsy.js', success: function(){
951                                    jPageFlipLoaded = true;
952                                }});
953                        }});
954                }
955            }
956
957            // slide with HTML
958            if(item.type == 'image') {
959                item.src = href;
960                item.msrc = link.children[0] ? link.children[0].getAttribute('src') : item.src;
961                item.w = parseInt(size[0],10);
962                item.h = parseInt(size[1],10);
963                item.el = link;
964            } else {
965                item.html = '<div class="pswp__content '+item.type+'" data-type="'+item.type+'" data-src="'+href+'"></div>';
966                item.msrc = href;
967            }
968
969            galleries[galleryId - 1].items.push(item);
970        }
971
972        $this.each(function(i, gallery){
973            galleries.push({
974                id: i,
975                items: []
976            });
977
978            var $resources = $(selector).hasClass("cmPhotoSwipe") ? $(selector) : $(_options.selector, $(gallery));
979            if($resources.length == 0) return;
980
981            $resources.each(function(k, link) {
982                var $link = $(link);
983                var isImage = $link.data('type')=='image';
984
985                var size = $link.data('size') ? $link.data('size').split('x') : [];
986
987                if(size.length > 0 || !isImage) {
988                    initPhotoSwipeOnResource(size,$link,i+1,k);
989                } else{
990                    var imagenUrl = $link.attr("href");
991                    var img = new Image();
992                    img.src = imagenUrl;
993                    $(img).on('load',function() {
994                        var w = img.width || 1920;
995                        var h = img.height || 1080;
996                        initPhotoSwipeOnResource([w,h],$link,i+1,k);
997                    });
998                }
999            });
1000
1001            $resources.off('click').on('click', function(e){
1002                e.preventDefault();
1003                var gid = $(this).data('gallery-id'),
1004                    pid = $(this).data('photo-id');
1005                openGallery(gid,pid);
1006            });
1007        });
1008    }
1009
1010    var parseHash = function() {
1011        var hash = window.location.hash.substring(1),
1012            params = {};
1013
1014        if(hash.length < 5) {
1015            return params;
1016        }
1017
1018        var vars = hash.split('&');
1019        for (var i = 0; i < vars.length; i++) {
1020            if(!vars[i]) {
1021                continue;
1022            }
1023            var pair = vars[i].split('=');
1024            if(pair.length < 2) {
1025                continue;
1026            }
1027            params[pair[0]] = pair[1];
1028        }
1029
1030        if(params.gid) {
1031            params.gid = parseInt(params.gid, 10);
1032        }
1033
1034        if(!params.hasOwnProperty('pid')) {
1035            return params;
1036        }
1037        params.pid = parseInt(params.pid, 10);
1038        return params;
1039    };
1040
1041    var openGallery = function(gid,pid){
1042        var pswpElement = document.querySelectorAll('.pswp')[0],
1043            items = galleries[gid-1].items,
1044            options = {
1045                index: pid,
1046                galleryUID: gid,
1047                getThumbBoundsFn: function(index) {
1048                    var item = items[index];
1049                    if(!item || !item.el || !item.el.children[0]) return;
1050                    var thumbnail = item.el.children[0],
1051                        pageYScroll = window.pageYOffset || document.documentElement.scrollTop,
1052                        rect = thumbnail.getBoundingClientRect();
1053
1054                    return {x:rect.left, y:rect.top + pageYScroll, w:rect.width};
1055                },
1056                addCaptionHTMLFn: function(item, captionEl) {
1057                    var $caption = $(captionEl);
1058                    var $title = $("div.pswp__caption__title", $caption);
1059                    var $description = $("div.pswp__caption__description", $caption);
1060                    var $author = $("div.pswp__caption__author", $caption);
1061                    var hasCaption = false;
1062                    if(item.title) {
1063                        $title.html(item.title);
1064                        hasCaption = true;
1065                    } else {
1066                        $title.empty();
1067                    }
1068                    if(item.description) {
1069                        $description.html(item.description);
1070                        hasCaption = true;
1071                    } else {
1072                        $description.empty();
1073                    }
1074                    if(item.author) {
1075                        $author.html(item.author);
1076                        hasCaption = true;
1077                    } else {
1078                        $author.empty();
1079                    }
1080                    // Añadimos un class al contenedor con el tipo de recurso que estamos mostrando
1081                    if(item.type) {
1082                        $caption.closest("div.pswp").addClass("pswp__type_"+item.type);
1083                    }
1084                    return hasCaption;
1085                }
1086            };
1087        $.extend(options,_options);
1088        var gallery = new PhotoSwipe( pswpElement, PhotoSwipeUI_Default, items, options);
1089        gallery.listen('afterChange', function() {
1090            var  $container = $(this.container);
1091            var $current = $(this.currItem.container);
1092            if($current.length == 0) return;
1093
1094            onLightboxShown($("body > div.pswp"));
1095
1096            var $content = $("div.pswp__content", $current);
1097            $content.empty();
1098
1099            var type = $content.data("type");
1100            if(!type) return;
1101
1102            var markup = markups[type];
1103            if(!markup) return;
1104
1105            var href = this.currItem.msrc || this.currItem.src;
1106
1107            markup = markup.replace(/{flpSettings}/g, flpSettings);
1108            markup = markup.replace(/{path}/g, '{href}');
1109            markup = markup.replace(/{href}/g, href);
1110            markup = markup.replace(/{width}/g, $(window).outerWidth());
1111            markup = markup.replace(/{height}/g, $(window).outerHeight());
1112
1113            $content.html(markup);
1114
1115            if(type == 'jpageflip') {
1116                $.ajax({
1117                    type: 'post',
1118                    url: href,
1119                    success: function(xml) {
1120                        var xmlResp = $("PageflipDataSet", xml);
1121                        if($("PageData", xmlResp).attr('PageImage')){
1122                            $('div.jpfInner', $content).jPageFlip({
1123                                startPage : 1,
1124                                defaultValueTipsy: {title: 'title', gravity: 's', html: true, cssClass: 'jpftipsy'}
1125                            });
1126                            $('div.jpfContainer a[rel=toolTip]', $content).tipsy({title: 'title', gravity: 's', html: true, cssClass: 'jpftipsy'});
1127                        }
1128                    }
1129                });
1130            }
1131        });
1132        gallery.listen('close', function() {
1133            var  $container = $(this.container);
1134            var $current = $(this.currItem.container);
1135            var $content = $("div.pswp__content", $current);
1136            $content.empty();
1137            onLightboxHidden($("body >
1137 div.pswp"), $(this.currItem.el));
1138        });
1139
1140        gallery.init();
1141    }
1142
1143    // initialize
1144    init($(selector));
1145
1146    // Parse URL and open gallery if it contains #&pid=3&gid=1
1147    var hashData = parseHash();
1148    if(hashData.pid > 0 && hashData.gid > 0) {
1149        openGallery(hashData.gid,hashData.pid);
1150    }
1151}
1152
1153/**
1154 * Función que inicializa los calendarios
1155 * @memberOf Init
1156 */
1157function initCalendarios()  {
1158    // contenidos en modo calendario con tooltip
1159    var calendariosConTooltip = $("div.calendarWithTooltip");
1160    if(calendariosConTooltip.length > 0){
1161        calendariosConTooltip.each(function(){
1162            var itemActual = $(this);
1163            $(this).addClass('activatedTooltip');
1164            // hay que quitar el title de los enlaces ya que el hover se hace sobre los td
1165            $('.cmCalendarTable .calendarDayWithEvents .cmEventInCalendar .cmContentLink span', itemActual).removeAttr('title');
1166
1167            // el tooltip de cada celda con eventos
1168            $('.cmCalendarTable .calendarDayWithEvents', itemActual).each(function(){
1169                $(this).qtip({
1170                    // cogemos el contenido del tooltip
1171                    content: { text: $($(this).find('.dayNumber a').attr('href')).html() },
1172                    position: qTipDefaults.position,
1173                    style: qTipDefaults.style,
1174                    show: qTipDefaults.show,
1175                    hide: qTipDefaults.hide
1176                });
1177            });
1178        });
1179    }
1180
1181    // contenidos en modo calendario con click que muestra / oculta el dia
1182    var calendariosConClick = $("div.calendarWithClick");
1183    if(calendariosConClick.length > 0){
1184        calendariosConClick.each(function(){
1185            var itemActual = $(this);
1186
1187            // el evento click de cada celda con eventos
1188            $('.cmCalendarTable .calendarDayWithEvents', itemActual).click(function(){
1189                // buscamos el id al que dirige el dia con evento
1190                var target = $(this).find('.dayNumber a').attr('href');
1191
1192                // escondemos los posibles mensajes cuando no existen eventos en el día actual o el mes actual
1193                $('.cmCalendarNoEvents', itemActual).hide();
1194
1195                // primeramente escondemos el item visible
1196                $('div.cmMonthEventsContainer li.cmCalendarDay:visible', itemActual).hide();
1197                $('div.cmMonthEventsContainer div.cmMonthContents').hide();
1198
1199                // mostramos los eventos del dia clickado
1200                $(target).show();
1201
1202                //buscamos si ha seleccionado un dia previamente
1203                var selectedDay = $('.selected-day', itemActual);
1204                if(selectedDay.length > 0){
1205                    //si ya habia un dia seleccionado le quitamos la clase
1206                    selectedDay.removeClass('selected-day');
1207                }
1208
1209                //añadimos class al dia seleccionado
1210                $(this).addClass('selected-day');
1211
1212                return false;
1213            });
1214
1215            // Si en la URL me viene informacion sobre un evento lo analizo
1216            var locationHref = location.href;
1217            var dateParamExist = false;
1218            if(locationHref.lastIndexOf('#') != -1) {
1219                var dayFromUrl = locationHref.substring(locationHref.lastIndexOf('#'));
1220                if(dayFromUrl.indexOf("_") != -1) {
1221                    var urlDay = dayFromUrl.substring(dayFromUrl.indexOf("_"));
1222                    var dayWithEvent = $(".cmCalendarTable .calendarDayWithEvents a[href$='"+urlDay+"']", itemActual);
1223                    if(dayWithEvent.length > 0){
1224                        $('.cmCalendarNoEvents', itemActual).hide();
1225                        $(dayWithEvent.attr('href')).show();
1226                        dateParamExist = true;
1227                    }
1228                }
1229            }
1230
1231        });
1232    }
1233}
1234
1235/**
1236 * Función usada para cargar el calendario por ajax.
1237 * en el tag <cm:getChildrenList_2> se añade <dv2ee:setPluginProperty key="ajaxFunction" value="calendarAjax"/>
1238 * @param {string} url - La url a cargar
1239 * @param param - Los parametros
1240 * @param link - EL sitio en el que enlazar el calendario
1241 * @memberOf Init
1242 */
1243function calendarAjax(url,param,link){
1244    var linkContainer=$(link).closest("td.portalLayoutCell,div.portalLayoutCell,div.proxia-column").find("div:first");
1245
1246    var calendarLoader=linkContainer.find('.calendarLoader');
1247    if(calendarLoader.length > 0){
1248        calendarLoader.css({'display':'block'});
1249    }else{
1250        linkContainer.prepend('<div class="calendarLoader"></div>');
1251    }
1252
1253    linkContainer.find('.cmCalendarViewContainer').css({'opacity':'0.6'});
1254
1255    if(url.indexOf('Ajax')==-1) url += 'Ajax';
1256    $.ajax({
1257        url: url,
1258        type: "POST",
1259        data: param,
1260        success: function(msg){
1261            linkContainer.html(msg);
1262            initCalendarios();
1263        }
1264    });
1265}
1266
1267/**
1268 * This function decodes the data stored in data in the way ([key="value"])+, it converts this information to an array indexed by key
1269 * @param data - Data to decode
1270 * @returns {Array} Array decoded
1271 * @memberOf Init
1272 */
1273function decodeMap(data) {
1274    // The regular expresion we are going to eval
1275    var regexExpr = /\[([^=]+)=\"([^\"]+)\"\]/g;
1276    var results = regexExpr.exec(data);
1277    // The array - in which we are going to store data (indexed as a map of arrays)
1278    var resultsArray = new Array();
1279    while(results!=null) {
1280        // If the key exists in the map we add a new entry to it.
1281        if(resultsArray[results[1]]) {
1282            resultsArray[results[1]][resultsArray[results[1]].length] = results[2];
1283        } else {
1284            resultsArray[results[1]] = new Array();
1285            resultsArray[results[1]][0] = results[2];
1286        }
1287        // We check for new data...
1288        results = regexExpr.exec(data);
1289    }
1290    // Finally, we have eval the array, so we can return it.
1291    return resultsArray;
1292}
1293
1294/**
1295 * Función que inicializa la librería que convierte tablas de datos a gráficas...
1296 * @memberOf Init
1297 */
1298function initVisualizeCharts() {
1299    loadCSS(_rootWeb+'/javaScript/visualizeCharts/css/visualize.css');
1300    if(typeof ($.fn.visualize) == "undefined") {
1301        if($.browser.msie) {
1302            loadScript({ url: _rootWeb+'/javaScript/visualizeCharts/js/excanvas.js', success: function(){
1303                    loadScript({ url: _rootWeb+'/javaScript/visualizeCharts/js/jquery.visualize.js', success: function(){
1304                            loadVisualizeCharts();
1305                        }});
1306                }});
1307        }else{
1308            loadScript({ url: _rootWeb+'/javaScript/visualizeCharts/js/jquery.visualize.js', success: function(){
1309                    loadVisualizeCharts();
1310                }});
1311        }
1312    }
1313    else {
1314        loadVisualizeCharts();
1315    }
1316}
1317
1318/**
1319 * Función que convierte las posibles tablas de datos que pudiera tener la página a gráficas...
1320 * @memberOf Init
1321 */
1322function loadVisualizeCharts() {
1323
1324    // Examinamos cuantas gráficas tenemos que generar
1325    var cmCharts = $("a[rel^='cmChart'],a[data-rel^='cmChart']");
1326    if(cmCharts.length > 0) {
1327        cmCharts.each(function() {
1328            var table = $(this).next('table');
1329            if(table.length > 0) {
1330                var theRel = $(this).attr("rel");
1331                if(!theRel) theRel = $(this).attr("data-rel");
1332                theRel = theRel.replace(/\&quot;/g,'"'); // Necesario para IE
1333                var theRelAttribs = decodeMap(theRel);
1334                var _chartType = null, _chartTheme = null, _showDataTable = false, _title = null, _chartParseDirection = null;
1335                var _width = table.width(), _height = table.height();
1336
1337                // Recogemos los parámetros del rel
1338                if(theRelAttribs["type"] != undefined)
1339                    _chartType = theRelAttribs["type"][0];
1340
1341                if(theRelAttribs["theme"] != undefined)
1342                    _chartTheme = theRelAttribs["theme"][0];
1343
1344                if(theRelAttribs["parseDirection"] != undefined)
1345                    _chartParseDirection = theRelAttribs["parseDirection"][0];
1346
1347                if(theRelAttribs["width"] != undefined)
1348                    _width = parseInt(theRelAttribs["width"][0], 10);
1349
1350                if(theRelAttribs["height"] != undefined)
1351                    _height = parseInt(theRelAttribs["height"][0], 10);
1352
1353                if(theRelAttribs["showdatatable"] != undefined && theRelAttribs["showdatatable"][0] == "true")
1354                    _showDataTable = true;
1355
1356                if($("caption", table).length > 0 && $("caption", table).text() != '')
1357                    _title = $("caption", table).text();
1358                else if(table.attr("summary") + '' != '')
1359                    _title = table.attr("summary");
1360
1361                // Ocultamos la tabla de datos si hace falta
1362                if(!_showDataTable) table.hide();
1363
1364                // Generamos y adjuntamos la gráfica justo después de la tabla de datos
1365                try {
1366                    //console.log('type:'+_chartType+' theme:'+_chartTheme+' width:'+_width+' height:'+_height+' title:'+_title +' parseDirection:'+_chartParseDirection);
1367                    table.visualize({ type: _chartType, theme: _chartTheme, width: _width, height: _height, title: _title, parseDirection: _chartParseDirection });
1368                }
1369                catch (ex) {
1370                }
1371            }
1372        });
1373    }
1374}
1375
1376/**
1377 * Función que se encarga de asociar eventos a los items del cubo OLAP para marcar cuando se abren y ocultan elementos
1378 * expandibles
1379 *
1380 * @memberOf Init
1381 */
1382function manageOlapExpandables() {
1383
1384    $('.olapExpandable','.olapCalendarDates').click(function() {
1385        $(this).toggleClass('olapOpened');
1386    });
1387
1388}
1389
1390/**
1391 * Evento ready
1392 * @memberOf Init
1393 */
1394$(document).ready(function () {
1395
1396    // Registramos todos los scripts/css actualmente cargados para no volverlos a cargar de forma dinámica...
1397    $("script,link[rel='stylesheet']").each(function() {
1398        var _src = '';
1399        if(this.nodeName.toLowerCase() == 'link') {
1400            _src = $(this).attr("href");
1401        } else if(this.nodeName.toLowerCase() == 'script') {
1402            _src = $(this).attr("src");
1403        }
1404        if(_src && _src != '') {
1405            _src = prepareLoadedFile(_src);
1406            loadedFiles[_src] = true;
1407            loadedFiles[_src+'.success'] = true;
1408        }
1409    });
1410
1411    // comprobamos si necesitamos el plugin prettyPhoto para imágenes, videos...
1412    if($("a[rel^='prettyPhoto']:not(.cmPhotoSwipe),a[data-rel^='prettyPhoto']:not(.cmPhotoSwipe)").length > 0){
1413        initPrettyPhoto();
1414    }
1415
1416    // comprobamos si necesitamos el plugin photoSwipe para imágenes, videos...
1417    if($("a.cmPhotoSwipe").length > 0){
1418        initPhotoSwipe();
1419    }
1420
1421    if($('.olapCalendarDates').length>0) {
1422        manageOlapExpandables();
1423    }
1424
1425    // comprobamos si necesitamos el plugin flowPlayer para videos...
1426    if($('a.cmAutoVideo,a.cmAutoAudio,a.cmAutoVideoNoAlt').length > 0 || $("#videoteca,#videotecaPlayer").length > 0) {
1427        initFlowPlayer();
1428    };
1429
1430    // función que inicializa los calendarios...
1431    initCalendarios();
1432
1433    // comprobamos si necesitamos el plugin que convierte tablas de datos a gráficas...
1434    if($("a[rel^='cmChart'],a[data-rel^='cmChart']").length > 0) {
1435        initVisualizeCharts();
1436    }
1437
1438    // Determinamos si estamos en _preview
1439    if(typeof(_currentTemplate) == 'string' && _currentTemplate == '/preview') {
1440        $('body').css('position','relative');
1441        $('body').prepend('<div class="coverWrapper"></div>');
1442    }
1443
1444    // Inicializamos el plugin de localización si es necesario
1445    initProxiaLocation();
1446    initProxiaSearch();
1447    initCsrf();
1448
1449    // Inicializamos xforms sólo si existe algún formulario en la página, aprovechamos para inicializar el plugin de calendario
1450    var $forms = $('form.form-container');
1451    if($forms.length > 0) {
1452        // Si no existe bootstrap en la web lo cargamos de forma dinámica
1453        if(typeof($.fn.modal) === 'undefined') {
1454            if(typeof(_bootstrapPath) != 'string') {
1455                _bootstrapPath = _rootWeb+'/javaScript/bootstrap';
1456            }
1457            loadCSS(_bootstrapPath+'/css/bootstrap.min.css');
1458            loadCSS(_bootstrapPath+'/css/bootstrap-theme.min.css');
1459            loadScript({ url: _bootstrapPath+'/js/bootstrap.min.js', success: function(){
1460                    $.fn.bstooltip = $.fn.tooltip.noConflict(); // Para evitar conflictos con jquery-ui
1461                    initXForms($forms, initDateTimePickers);
1462                }});
1463        } else {
1464            initXForms($forms, initDateTimePickers);
1465        }
1466    } else {
1467        initDateTimePickers();
1468    }
1469
1470    // Nos aseguramos de que todos los tooltip y popover se cierren con ESC
1471    document.addEventListener('keydown', function(e) {
1472        if ( typeof ( $.fn.bstooltip ) === 'function' ) {
1473            $.fn.tooltip = $.fn.bstooltip;
1474        }
1475
1476        if ( typeof ( $.fn.tooltip ) !== 'function' ) return;
1477        if ('Escape' === e.key) {
1478            const $openTooltips = $('.tooltip');
1479            const $openPopovers = $('.popover');
1480
1481            if ($openPopovers.length || $openTooltips.length) {
1482                e.stopPropagation();
1483                $openTooltips.tooltip('hide');
1484                $openPopovers.popover('hide');
1485            }
1486        }
1487    }, true);
1488});
1489
1490/**
1491 * Inicializamos el token CSRF en todos los formularios y lo activamos a nivel de todas las peticiones AJAX
1492 */
1493function initCsrf() {
1494    var csrf = GetCookie('_proxia_csrf');
1495    if(csrf) {
1496        // Vamos a añadir a todos los formularios de la página que tengan un actionCode definido el valor
1497        // de la cookie de CSRF
1498        $('form').each(function(i) {
1499            var $form = $(this);
1500            if(!$form.attr('method') || $form.attr('method').toUpperCase()=== 'GET') return;
1501
1502            // Ahora vemos si tenemos un aributo de tipo actionCode
1503            if($('[name="actionCode"]',$form).length > 0) {
1504                // Tenemos que añadir el atributo de CSRF a la petición.
1505                var _csrf = $('<input type="hidden" name="__proxia_csrf" value="'+csrf+'"/>');
1506                $form.append(_csrf);
1507            }
1508        });
1509    }
1510    // Para que todas las funciones AJAX lo incluyan... tenemos que leerlo siempre antes
1511    // de envía.
1512    $( document ).ajaxSend(function( event, jqxhr, settings ) {
1513        var csrf = GetCookie('_proxia_csrf');
1514        if(csrf) {
1515            jqxhr.setRequestHeader('X-Proxia-CSRF', csrf)
1516        }
1517    });
1518}
1519
1520/**
1521 * Inicializamos el plugin de localización si es necesario
1522 * @memberOf Init
1523 */
1524function initProxiaLocation() {
1525    if(typeof(locationSettings) == "object" && $('input[data-location]').length > 0) {
1526        loadCSS(_rootWeb+'/css/jquery-ui-theme/jquery-ui-theme.min.css');
1527        loadScript({ url: _rootWeb+'/javaScript/jquery-ui.min.js', success: function(){
1528                loadScript({ url: _rootWeb+'/javaScript/jquery.ui.touch-punch.min.js', success: function(){
1529                        loadScript({ url: _rootWeb+'/javaScript/proxia.location.js', success: function(){
1530                                $(document).proxiaLocation(locationSettings);
1531                            }});
1532                    }});
1533            }});
1534    }
1535}
1536
1537/**
1538 * Inicializamos el plugin de busqueda predictiva si es necesario
1539 * @memberOf Init
1540 */
1541function initProxiaSearch() {
1542    var $inputs = $('input[data-search="true"]');
1543    if($inputs.length > 0) {
1544        loadCSS(_rootWeb+'/css/jquery-ui-theme/jquery-ui-theme.min.css');
1545        loadScript({ url: _rootWeb+'/javaScript/jquery-ui.min.js', success: function(){
1546                loadScript({ url: _rootWeb+'/javaScript/jquery.ui.touch-punch.min.js', success: function(){
1547                        proxiaSearchPredictive($inputs);
1548                    }});
1549            }});
1550    }
1551}
1552
1553/**
1554 * Inicializa los formularios pasados como parámetro y carga las librerías css/js necesarias
1555 * @param {array} $forms - Array de formularios
1556 * @param callback - El callback
1557 * @memberOf Init
1558 */
1559function initXForms($forms, callback) {
1560    var doInitForms = function() {
1561        // Independientemente de que carge o no el custom tengo que inicializar los formularios
1562        $forms.each(function() {
1563            xforms.init($(this));
1564            if(typeof(callback) == 'function') callback($forms);
1565        });
1566    }
1567
1568    loadCSS(_rootWeb+'/css/proxia.xforms.css');
1569    loadScript({ url: _rootWeb+'/javaScript/proxia.xforms.js', success: function(){
1570            loadScript({ url: _rootWeb+'/javaScript/moment/min/moment.min.js', success: function(){
1571                    loadScript({ url: _rootWeb+'/javaScript/moment/locale/'+xforms.getMomentLocale(xforms.locale)+'.js', success: function(){
1572                            loadScript({ url: _rootWeb+'/javaScript/xpath.min.js', success: function(){
1573                                    var _xformsPath = _rootWeb+'/javaScript/proxia.xforms.custom.js';
1574                                    if(typeof(xformsCustomPath)!=='undefined' && xformsCustomPath) {
1575                                        _xformsPath = xformsCustomPath;
1576                                    }
1577                                    // Puede que exista o no exista el fichero de custom (si da error lo ignoramos)
1578                                    loadScript({ url: _xformsPath, success: function(){
1579                                            doInitForms();
1580                                        }, error: function(){
1581                                            doInitForms();
1582                                        }});
1583
1584                                }});
1585                        }});
1586                }});
1587        }});
1588}
1589
1590
1591
1592// Cargamos de forma dinámica unos estilos css relacionados con el componente de paginación con scroll infinito
1593if(typeof jQuery !== 'undefined' && $('#cmAutoPaginationStyle').length == 0) {
1594    $("head").append(' \
1595		<style type="text/css" id="cmAutoPaginationStyle"> \
1596		.cmAutoPagination .cmContentItem { visibility: hidden; } \
1597		.cmAutoPagination .cmNavigation { display: none; } \
1598		</style> \
1599	');
1600}
1601
1602/**
1603 * Inicializamos los componentes de paginación con scroll infinito
1604 * @memberOf Init
1605 */
1606function initWayPoints() {
1607    var $items = $("ul.cmAutoPagination,div[class*='animation-']");
1608    if($items.length > 0) {
1609        if(_compatibilityMode < 2) loadCSS(_rootWeb+'/css/animate.css');
1610        if(typeof(Waypoint) != 'function') {
1611            loadScript({ url: _rootWeb+'/javaScript/waypoints/jquery.waypoints.min.js', success: function(){
1612                    loadScript({ url: _rootWeb+'/javaScript/waypoints/shortcuts/inview.min.js', success: function(){
1613                            afterInitWayPoints($items);
1614                        }});
1615                }});
1616        } else {
1617            afterInitWayPoints($items);
1618        }
1619    }
1620}
1621
1622function afterInitWayPoints($items) {
1623    initAnimationEffects($items);
1624    initAutoPagination($items);
1625}
1626
1627/**
1628 * Inicializa las animaciones css3 para cada uno de los componentes
1629 * @param {array} $items - Array de items a procesar
1630 * @memberOf Init
1631 */
1632function initAnimationEffects($items) {
1633    $items.filter("[class*='animation-']").each(function() {
1634        var $this = $(this);
1635        var className = $this.attr("class");
1636        var results = className.match(/animation-([_a-zA-Z0-9-]+)/gm);
1637        if(results != null && results.length > 0) {
1638            $this.data("animationClasses", results);
1639            var myWaypoint = new Waypoint.Inview({
1640                element: $this.get(0),
1641                enter: function(direction) {
1642                    var animationClasses = $(this.element).data("animationClasses");
1643                    if(animationClasses != null && animationClasses.length > 0) {
1644                        $(this.element).addClass('animated');
1645                        for(var i = 0; i < animationClasses.length; i++) {
1646                            var classEffect = animationClasses[i];
1647                            var animationEnd = 'webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend';
1648                            $(this.element).queue(function (next) {
1649                                $(this).addClass(classEffect.replace('animation-', '')).removeClass(classEffect);
1650                                $(this).one(animationEnd, function() {
1651                                    $(this).removeClass(classEffect.replace('animation-', ''));
1652                                    if(i == animationClasses.length - 1) {
1653                                        $(this).removeClass('animated');
1654                                        myWaypoint.destroy();
1655                                    }
1656                                    next();
1657                                });
1658                            });
1659                        }
1660                    }
1661                }
1662            });
1663        }
1664    });
1665}
1666
1667/**
1668 * Inicializa el soporte de paginacion con scroll infinito en modo moderno
1669 * @memberOf Init
1670 */
1671function initEndlessNavigation() {
1672    // Tenemos que localizar los eventos que tienen asociado la clase CSS .cmAutoNavigation de tipo A
1673    $('a.cmAutoNavigation').each(function() {
1674        // Cargamos la lista en la que mostramos los datos que tenemos asociados.
1675        var $link = $(this);
1676        var $ul = $link.closest('.cmNavigation').siblings('ul.cmContentList');
1677        var $container = $ul.closest("div.cmBodyAbstractContent[data-beanname],div.cmBodyContentChildrens[data-beanname],div.cmSameParentContentsBox[data-beanname],div.autoRelatedBox[data-beanname]");
1678        if($container.length == 0) return;
1679
1680
1681        var url = $container.data('url');
1682        var beanname = $container.data('beanname');
1683        var elements = $container.data("elements");
1684        var columns = $container.data("columns");
1685        var animated = $container.data("animated");
1686        var delay = $container.data("delay");
1687        var nshow = elements; // Elementos por página
1688        var totalLength;
1689        if ($("li.cmContentItem", $ul).length < nshow){
1690            totalLength= $("li.cmContentItem", $ul).length;
1691        }else{
1692            totalLength= $container.data("totalLength");
1693        }
1694
1695        // Initializamos variables de paginación
1696        $container.data("nshow", nshow);
1697        $container.data("position", 0);
1698
1699        if($ul.nextAll("div.spinner").length == 0) {
1700            $ul.after('<div class="spinner" style="display:none;"><span class="fa fa-4x fa-refresh fa-spin"></span></div>');
1701        }
1702
1703        // Cuando hagamos click sobre el elemento es cuando tenemos que pintar los daots y además
1704        $link.click(function(e) {
1705            e.preventDefault();
1706
1707            // Preincrementamos para tener los resultados que queremos mostrar.
1708            $container.data("position", $container.data("position") + $container.data("nshow"));
1709
1710
1711            // Generamos la URL de nuevo, por JavaScript, no nos hace falta otra cosa...
1712            var ajaxUrl;
1713            if ($container.data("parameters")){
1714                ajaxUrl  = url;
1715                ajaxUrl += '?' + $container.data("parameters");
1716            }else{
1717                ajaxUrl  = _rootWeb + '/cm/' + url;
1718                ajaxUrl += '?containerShown=false';
1719            }
1720            ajaxUrl += '&position.'+beanname+'='+$container.data("position");
1721            ajaxUrl += '&nshow.'+beanname+'='+$container.data("nshow");
1722
1723            // Activamos el spinner...
1724            $ul.nextAll("div.spinner").show();
1725            // Hacemos la llamada por Ajax
1726            $.ajax({
1727                type: 'GET',
1728                url: ajaxUrl,
1729                dataType: 'text',
1730                success: function(html) {
1731                    var $html = $(html);
1732
1733                    // Tenemos que recalcuar las expresiones de fecha que aplican
1734                    if(typeof resolveDateExpressions === 'function') {
1735                        resolveDateExpressions($html);
1736                    }
1737
1738
1739
1740                    var $items = $("li.cmContentItem", $html);
1741                    var timeout = 0;
1742
1743                    if($items.length > 0) {
1744                        $items.each(function(index) {
1745                            var $li = $(this);
1746                            if(animated) {
1747                                animatePaginationItem($ul, $li, animated, delay ? timeout+=delay : 0);
1748                            } else {
1749                                $li.css("visibility", "visible");
1750                            }
1751
1752                            $ul.append($li);
1753                            if(index === 0) {
1754                                $('a',$li).attr('tabindex',0);
1755                                $('a',$li).focus();
1756                            }
1757                        });
1758                    }
1759                    // Si tenemos el caso de que el nº de items es menor que el nº de elementos pedidos, es posible que estemos
1760                    // en una búsqueda y el totalLenth sea estimado. En ese caso, lo seteamos al valor total.
1761                    if ($items.length < $container.data("nshow")){
1762                        totalLength = $("li.cmContentItem", $ul).length;
1763                    }
1764
1765
1766
1767                    $ul.nextAll("div.spinner").hide();
1768
1769                    // Ejecutamos el resize de la ventana por si tiene que ejecutarse algún plugin
1770                    setTimeout(function() {
1771                        $(window).trigger("resize");
1772                    }, timeout);
1773
1774                    // Cargamos los botones del wizard, si está cargado
1775                    if(typeof(checkContentPermissions) == 'function') {
1776                        checkContentPermissions();
1777                    }
1778
1779                    var nshow = $container.data("nshow");
1780                    var position = $container.data("position");
1781
1782                    // Tenemos que actualizar los datos que tenemos en pantalla, a la posición
1783                    if(position + nshow >= totalLength) {
1784                        // Ocultamos el link.
1785                        $link.closest('.cmNavigation').hide();
1786                    }
1787
1788                    // Tenemos que calcular cambios en el tamaño de posibles elementos
1789                    // que hayan aparecido.
1790                    if(typeof adjustCSSCutTextHeights === 'function') {
1791                        adjustCSSCutTextHeights($ul[0],false); // Forzamos el recálculo.
1792                    }
1793
1794
1795                    return;
1796                }
1797            });
1798
1799        });
1800    });
1801}
1802
1803/**
1804 * Ajusta las alturas de todos los elementos de la página, lo ajustamos con un pequeño timeout,
1805 * se puede personalizar en función del lineHeight del proyecto y una función de cálculo
1806 * repetido de after para personalizr situaciones no contempladas.
1807 *
1808 * @param rootNode El nodo raiz o todo el documento si es undefined, null, cadena vacía
1809 * @param adaptative Si estamos en un cambio adaptativo
1810 */
1811function adjustCSSCutTextHeights(rootNode,adaptative) {
1812    if(rootNode === undefined || rootNode === null || rootNode === '') rootNode = document.documentElement;
1813
1814    if($('#lineHeightChecker').length == 0) {
1815        var n = document.createElement('div');
1816        n.style.lineHeight = 1;
1817        n.style.fontSize = '10px';
1818        n.setAttribute('id', 'lineHeightChecker');
1819        document.body.appendChild(n);
1820    }
1821    var elem = document.getElementById('lineHeightChecker');
1822    var oldLineHeight = elem.dataset.lineHeight;
1823    var lineHeightBase = 1.428571429; // Variable por defecto
1824    if(typeof _projectLineHeight !=='undefined' && _projectLineHeight) {
1825        lineHeightBase = _projectLineHeight;
1826    }
1827
1828    var lheight = window.getComputedStyle(document.getElementById('lineHeightChecker')).lineHeight;
1829
1830
1831    if(rootNode!=document.documentElement || adaptative || (lheight != '10px' && oldLineHeight===undefined) || (oldLineHeight!==undefined && oldLineHeight!=lheight)) {
1832        var redefinedLineHeight = parseInt(lheight)/10;
1833
1834        // Tenemos que iterar por todos los elementos para calcular la altura
1835        var whatToFind = {
1836            property: "text-overflow",
1837            values: ["ellipsis"]
1838        };
1839
1840        var walker =
1841            document.createTreeWalker(rootNode, NodeFilter.SHOW_ELEMENT,
1842                function(el) {
1843                    var style = getComputedStyle(el)[whatToFind.property];
1844                    return whatToFind.values.includes(style)
1845                        ? NodeFilter.FILTER_ACCEPT
1846                        : NodeFilter.FILTER_SKIP;
1847                });
1848
1849
1850        while (walker.nextNode()) {
1851            var n = walker.currentNode;
1852            if(adaptative || n.dataset.originalHeight === undefined || n.dataset.originalHeight === '') {
1853                if(adaptative) n.style.height = null;
1854                n.dataset.originalHeight = parseInt(getComputedStyle(n)['height']);
1855            }
1856            if(redefinedLineHeight === 1) {
1857                n.style.height = null;
1858            } else {
1859                var fontSize = parseInt(getComputedStyle(n)['fontSize']);
1860                var lines = Math.round(n.dataset.originalHeight/(fontSize*lineHeightBase));
1861                if(redefinedLineHeight > 1) {
1862                    lines++;
1863                    n.style.setProperty('-webkit-line-clamp',lines);
1864                }
1865                var newHeight = redefinedLineHeight*fontSize*lines;
1866                if(redefinedLineHeight!==1) {
1867                    if(parseInt(getComputedStyle(n)['lineHeight']) != fontSize*redefinedLineHeight) {
1868                        n.style.setProperty('line-height',fontSize*redefinedLineHeight+'px','important');
1869                    } else {
1870                        n.style.lineHeight = undefined;
1871                        n.style.setProperty('-webkit-line-clamp',undefined);
1872                    }
1873                } else {
1874                    n.style.lineHeight = null;
1875                }
1876                n.style.height = newHeight + 'px';
1877            }
1878        }
1879        elem.dataset.lineHeight = lheight;
1880
1881        // Indicamos al cuerpo que tenemos un userDefinedLineHeight
1882        if(redefinedLineHeight===1) {
1883            $('body').removeClass('userDefinedLineHeight');
1884        } else {
1885            $('body').addClass('userDefinedLineHeight');
1886        }
1887
1888        // Para que ejecute una función despues de resetear el tamaño de línea
1889        if(typeof customAfterSetHeight === 'function') {
1890            customAfterSetHeight(redefinedLineHeight);
1891        }
1892    }
1893
1894    // Ejecutamos el chequeo cada 500 ms... por si se meten a mano o se modifican los estilos
1895    // en cualqueir momento.
1896    setTimeout(function() {
1897        adjustCSSCutTextHeights();
1898    },500);
1899}
1900
1901
1902/**
1903 * Inicializa cada uno de los componentes de paginación con scroll infinito
1904 * @param {array} $autoPagination - Array de componentes de paginación
1905 * @memberOf Init
1906 */
1907function initAutoPagination($autoPagination) {
1908    $autoPagination.filter("ul.cmAutoPagination").each(function() {
1909        var $ul = $(this);
1910
1911        if ($ul.data("initialized")){
1912            return;
1913        }
1914        var $container = $ul.closest("div.cmBodyAbstractContent[data-beanname],div.cmBodyContentChildrens[data-beanname]");
1915
1916        if($container.length == 0) return;
1917
1918        var elements = $container.data("elements");
1919        var columns = $container.data("columns");
1920        var animated = $container.data("animated");
1921        var delay = $container.data("delay");
1922        var manual = $container.data("manual") || $container.hasClass("manual-scroll");
1923        var nshow = elements; // Elementos por página
1924
1925        // Si estamos en una búsqueda, es posible que el totalLength sea estimado. En este caso lo seteamos si en nº de elementos
1926        // obtenidos es menor qeu el nº de elementos pedidos
1927        var totalLength;
1928        if ($("li.cmContentItem", $ul).length < nshow){
1929            totalLength= $("li.cmContentItem", $ul).length;
1930        }else{
1931            totalLength= $container.data("totalLength");
1932        }
1933
1934        // Animamos los elementos actuales
1935        var $items = $("> li.cmContentItem", $ul);
1936        var timeout = 0;
1937        $items.each(function() {
1938            var $li = $(this);
1939            if(animated) {
1940                animatePaginationItem($ul, $li, animated, delay ? timeout+=delay : 0);
1941            } else {
1942                $li.css("visibility", "visible");
1943            }
1944        });
1945
1946        // No se pagina, ya que se muestran todos
1947        if(nshow == -1 || nshow > totalLength) {
1948            if(manual) {
1949                var $manualSelector = $container.data("manualSelector") || $(".contentViewMore", $container);
1950                if($manualSelector && $manualSelector.length > 0) {
1951                    $manualSelector.hide();
1952                }
1953            }
1954            return;
1955        }
1956
1957        setTimeout(function() {
1958
1959            // Initializamos variables de paginación
1960            $container.data("nshow", nshow);
1961            $container.data("position", 0);
1962
1963            // Avance manual
1964            if(manual) {
1965
1966                var $manualSelector = $container.data("manualSelector") || $(".contentViewMore", $container);
1967                if($manualSelector && $manualSelector.length > 0) {
1968                    $manualSelector.show();
1969                    var $link = $container.data("manualSelector") || $("> a", $manualSelector);
1970                    if($link && $link.length > 0) {
1971                        $link.click(function(e) {
1972                            e.preventDefault();
1973                            $container.data("position", $container.data("position") + $container.data("nshow"));
1974                            getAutoPaginationItems($ul, $container);
1975                        });
1976                    }
1977                }
1978
1979            } else {
1980
1981                // Initializamos la paginación con scroll infinito
1982                var waypoint = new Waypoint({
1983                    element: $ul.get(0),
1984                    handler: function(direction) {
1985                        if(direction == 'down') {
1986
1987                            // Si tenemos el layoutManager activado, desactivamos la auto-paginación
1988                            if($('body').hasClass("layoutManagerEnabled") || $('body').hasClass("cmWizardEditMode")) return;
1989
1990                            $container.data("position", $container.data("position") + $container.data("nshow"));
1991                            getAutoPaginationItems($ul, $container);
1992                        }
1993                    },
1994                    offset: 'bottom-in-view'
1995                });
1996                $container.data("waypoint", waypoint);
1997            }
1998
1999            if($ul.nextAll("div.spinner").length == 0) {
2000                $ul.after('<div class="spinner" style="display:none;"><span class="fa fa-4x fa-refresh fa-spin"></span></div>');
2001            }
2002
2003        }, timeout);
2004
2005        // Por último, lo marcamos como inicializado para que no se inicialice 2 veces
2006        $ul.data("initialized","true");
2007    });
2008}
2009
2010/**
2011 * Función que realiza una búsqueda de elementos a paginar por ajax
2012 * @param $ul - Listado
2013 * @param {object} $container - Contenedor de parametros y ajustes
2014 * @returns {boolean}
2015 * @memberOf Init
2016 */
2017function getAutoPaginationItems($ul, $container) {
2018
2019    var url = $container.data("url");
2020    var parameters = $container.data("parameters");
2021    var beanname = $container.data("beanname");
2022    var totalLength = $container.data("totalLength");
2023    var animated = $container.data("animated");
2024    var delay = $container.data("delay");
2025    var manual = $container.data("manual") || $container.hasClass("manual-scroll");
2026
2027    var ajaxUrl;
2028
2029    if (parameters){
2030        ajaxUrl  = url;
2031        ajaxUrl += '?' + parameters;
2032    }else{
2033        ajaxUrl  = _rootWeb + '/cm/' + url;
2034        ajaxUrl += '?containerShown=false';
2035    }
2036
2037    ajaxUrl += '&position.'+beanname+'='+$container.data("position");
2038    ajaxUrl += '&nshow.'+beanname+'='+$container.data("nshow");
2039
2040    $ul.nextAll("div.spinner").show();
2041
2042    $.ajax({
2043        type: 'GET',
2044        url: ajaxUrl,
2045        dataType: 'text',
2046        success: function(html) {
2047            var $html = $(html);
2048            var $items = $("li.cmContentItem", $html);
2049            var timeout = 0;
2050
2051            if($items.length > 0) {
2052                $items.each(function() {
2053                    var $li = $(this);
2054                    if(animated) {
2055                        animatePaginationItem($ul, $li, animated, delay ? timeout+=delay : 0);
2056                    } else {
2057                        $li.css("visibility", "visible");
2058                    }
2059                    $ul.append($li);
2060                });
2061            }
2062
2063            // Si tenemos el caso de que el nº de items es menor qeu el nº de elementos pedidos, es posible qeu estemos
2064            // en una búsqueda y el totalLenth sea estimado. En ese caso, lo seteamos al valor total.
2065            if ($items.length < $container.data("nshow")){
2066                totalLength = $("li.cmContentItem", $ul).length;
2067            }
2068
2069            $ul.nextAll("div.spinner").hide();
2070
2071            var fn = $container.data("manualCallback");
2072            if(typeof(fn) == 'function') {
2073                fn($ul, $container);
2074            }
2075
2076            // Ejecutamos el resize de la ventana por si tiene que ejecutarse algún plugin
2077            setTimeout(function() {
2078                $(window).trigger("resize");
2079            }, timeout);
2080
2081            // Cargamos los botones del wizard, si está cargado
2082            if(typeof(checkContentPermissions) == 'function') {
2083                checkContentPermissions();
2084            }
2085
2086            var nshow = $container.data("nshow");
2087            var position = $container.data("position");
2088
2089            if(position + nshow >= totalLength) {
2090                // Ya hemos mostrado todo
2091                if($ul.nextAll("div.no-results").length == 0) {
2092                    $ul.nextAll("div.spinner").after('<div class="no-results"></div>');
2093                }
2094                if(!manual) {
2095                    var waypoint = $container.data("waypoint");
2096                    waypoint.destroy();
2097                } else {
2098                    var $manualSelector = $container.data("manualSelector") || $(".contentViewMore", $container);
2099                    if($manualSelector && $manualSelector.length > 0) $manualSelector.hide();
2100                }
2101                return;
2102            }
2103
2104            if(!manual) {
2105                // Actualizamos las posiciones de waypoint
2106                Waypoint.refreshAll();
2107            }
2108        }
2109    });
2110
2111    return false;
2112}
2113
2114/**
2115 * Función que aplica un efecto css a un elemento de la paginación
2116 * @param $ul
2117 * @param $li - Objeto en cuestión a aplicar el efecto
2118 * @param {string} animated - Animación css clase
2119 * @param {number} timeout - Tiempo para el delay de la animación
2120 * @memberOf Init
2121 */
2122function animatePaginationItem($ul, $li, animated, timeout) {
2123    if(!animated) return;
2124    // Usamos visibility para preservar el espacio
2125    $li.css("visibility", "hidden");
2126    setTimeout(function() {
2127        $li.css("visibility", "visible");
2128        // Realizamos la animación
2129        $li.addClass("animated " + animated);
2130        // Una vez acabada quitamos los css
2131        $li.one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function() {
2132            $(this).removeClass('animated ' + animated);
2133        });
2134    }, timeout);
2135}
2136
2137/**
2138 * Función que proporciona el mecanismo necesario para desarrollar menús para páginas OnePage con el uso de anclas de tipo #![ID] en los enlaces de los menús.
2139 * @param $selector Los distintos menús con anclas de tipo #![ID]
2140 * @param [$header] - Selector de la cabecera fixed si tenemos. Este parámetro es opcional.
2141 * @memberOf Init
2142 */
2143function initScrollLink($selector, $header) {
2144
2145    var header = false;
2146    if($header && $header.length > 0) header = $header.selector;
2147
2148    var getHeaderHeight = function() {
2149        var height = 0;
2150        if(header) {
2151            height = $(header).outerHeight();
2152        }
2153        return height;
2154    }
2155
2156    var getHeaderBorder = function() {
2157        var borderWidth = 0;
2158        if(header) {
2159            borderWidth += parseInt($(header).css("border-top-width"), 10);
2160            borderWidth += parseInt($(header).css("border-bottom-width"), 10);
2161        }
2162        return borderWidth;
2163    }
2164
2165    var onScrollLink = function() {
2166        var scrollPos = $(document).scrollTop() + getHeaderHeight();
2167        $selector.each(function() {
2168            var currLink = $(this);
2169            var attrHref = currLink.attr("href").replace('!','');
2170            if(attrHref.indexOf('#') != -1) {
2171                var selector = attrHref.substring(attrHref.indexOf('#'));
2172                var $refElement = selector == '#' ? $('body') : $(selector);
2173                if($refElement.length == 0) return;
2174
2175                if((selector == '#' && $(document).scrollTop() == 0) ||
2176                    (selector != '#' && $refElement.length > 0 && $refElement.offset().top <= scrollPos &&
2177                        $refElement.offset().top + $refElement.outerHeight() > scrollPos)) {
2178
2179                    currLink.addClass("link-active");
2180                } else{
2181                    currLink.removeClass("link-active");
2182                }
2183            }
2184        });
2185    };
2186
2187    $(document).on("scroll.link", function() { onScrollLink($selector); });
2188
2189    $(window).load(function(){
2190        var locHash = window.location.hash;
2191        if(locHash.match("^#!")){
2192            urlHash = locHash.replace('!','');
2193        }
2194        var initialHeaderHeight = getHeaderHeight();
2195        if(typeof(urlHash) != 'undefined' && urlHash != '#' && urlHash.length > 0) {
2196            $('html,body').stop().animate({
2197                'scrollTop': $(urlHash).offset().top - getHeaderHeight() + getHeaderBorder()
2198            }, $(urlHash).offset().top / 3, 'swing', function() {
2199                // Si la altura de la cabecera cambia al hacer scroll, la ajustamos al final
2200                if(initialHeaderHeight != getHeaderHeight()) {
2201                    $('html,body').stop().animate({
2202                        'scrollTop': $(urlHash).offset().top - getHeaderHeight() + getHeaderBorder()
2203                    });
2204                }
2205            });
2206        }
2207
2208        $(document).trigger("scroll.link");
2209    });
2210
2211    var cleanURL = function(url) {
2212
2213        if(!url) return '';
2214
2215        var pos1 = url.lastIndexOf('#');
2216        if(pos1 != -1) url = url.substring(0, pos1);
2217
2218        var pos2 = url.lastIndexOf('?');
2219        if(pos2 != -1) url = url.substring(0, pos2);
2220
2221        if(url.substring(url.length - 1) == '/') {
2222            url = url.substring(0, url.length - 1);
2223        }
2224
2225        return url;
2226    };
2227
2228    //smoothscroll
2229    $selector.on('click.link', function (e) {
2230
2231        if(!this.hash) return;
2232
2233        // Si nos encontramos en una página distinta a la del enlace, no hacemos nada
2234        if(cleanURL(this.href) != cleanURL(location.href)) return;
2235
2236        $(document).off("scroll.link");
2237
2238        $('a').each(function () {
2239            $(this).removeClass('link-active');
2240        })
2241        $(this).addClass('link-active');
2242
2243        var hash = this.hash;
2244        var target = hash.replace('!','');
2245        if(target == '#') {
2246            $target = $('body');
2247        } else {
2248            $target = $(target);
2249        }
2250        if($target.length == 0) return;
2251
2252        e.preventDefault();
2253
2254        var initialHeaderHeight = getHeaderHeight();
2255
2256        $('html,body').stop().animate({
2257            'scrollTop': $target.offset().top - getHeaderHeight() + getHeaderBorder()
2258        }, 600, 'swing', function() {
2259            // Si la altura de la cabecera cambia al hacer scroll, la ajustamos al final
2260            if(initialHeaderHeight != getHeaderHeight()) {
2261                $('html,body').stop().animate({
2262                    'scrollTop': $target.offset().top - getHeaderHeight() + getHeaderBorder()
2263                },200);
2264            }
2265            if(hash) window.location.hash = hash;
2266            $(document).on("scroll.link", function() { onScrollLink($selector); });
2267        });
2268    });
2269}
2270
2271/**
2272 * Función utilizada para el árbol de etiquetas de los blogs
2273 * @param objSPAN
2274 * @memberOf Init
2275 */
2276function toggleTreeNode(objSPAN) {
2277    if(objSPAN && objSPAN.style) objSPAN = $(objSPAN);
2278    if(objSPAN && objSPAN.hasClass("cmCategorizerImage")) {
2279        var objUL=objSPAN.parent().find("ul:first"); // El UL que contiene las subentradas
2280        var objIMG=objSPAN.find("img"); // La imagen del triángulo
2281        if(objUL.length > 0 && objIMG.length > 0) {
2282            var imgSrc = objIMG.attr("src");
2283            if(objUL.hasClass("cmContentListRight")) {
2284                objIMG.attr("src",imgSrc.replace('Right','Down'));
2285                objIMG.attr("class","cmCategorizerImageDown");
2286                objUL.attr("class","cmContentListDown");
2287            }
2288            else {
2289                objIMG.attr("src",imgSrc.replace('Down','Right'));
2290                objIMG.attr("class","cmCategorizerImageRight");
2291                objUL.attr("class","cmContentListRight");
2292            }
2293        }
2294    }
2295}
2296
2297/**
2298 * Función utilizada para enviar un comentario dentro de una entrada de blog
2299 * @param {string} objForm - El blog al cual enviamos el comentario
2300 * @returns {boolean}
2301 * @memberOf Init
2302 */
2303function sendBlogEntryComment(objForm) {
2304    var $objForm = $(objForm);
2305    if(dv2eeFormChecker(objForm,requiredAttsForSendMail,requiredAttsValsForSendMail)) {
2306        objForm.cmClientButtonSubmit.disabled = true;
2307        showWaitDialog('Enviando...');
2308        // Recuperamos los textos multiidiomas (properties) por ajax
2309        $.ajax({
2310            url: $objForm.attr("action"),
2311            type: $objForm.attr("method"),
2312            data: $objForm.serialize(),
2313            success: function(html) {
2314                hideWaitDialog();
2315                objForm.cmClientButtonSubmit.disabled = false;
2316                $('.successComment').css('display','block');
2317                $('.boxEntryComments form')[0].reset();
2318                $('.boxEntryComments label').css('display','block');
2319                if(_role == true){
2320                    location.reload();
2321                }
2322            },
2323            error: function (xhr, ajaxOptions, thrownError) {
2324                alert(thrownError + '\nError ' + xhr.status);
2325            }
2326        });
2327    }
2328
2329    return false;
2330}
2331
2332/**
2333 * Función que inicializa los componentes de los blogs
2334 * @memberOf Init
2335 */
2336function initBlogs() {
2337    // Blogs: Cerramos todos los nodos por fecha menos el primer año y mes
2338    var $treeByDate = $("#treeByDate");
2339    if($treeByDate.length > 0 && $("span", $treeByDate).length > 2) {
2340        $("span", $treeByDate).each(function(index, val){
2341            if(index >= 2) toggleTreeNode($(this));
2342        });
2343    }
2344
2345    // Blogs: Cerramos todos los nodos por etiqueta
2346    var $treeByLabels = $("#treeByLabels");
2347    if($treeByLabels.length > 0 && $("span", $treeByLabels).length > 0) {
2348        $("span", $treeByLabels).each(function(index, val){
2349            toggleTreeNode($(this));
2350        });
2351    }
2352}
2353
2354/**
2355 * Función que retorna la locale a utilizar
2356 * @param {string} locale - Cadena que se corresponde con el idioma a usar
2357 * @returns {*}
2358 * @memberOf Init
2359 */
2360function getMomentLocale(locale) {
2361    // Incluimos la región en aquellos idiomas que estén localizados a nivel de región en el plugin bootstrap datetimepicker
2362
2363    if(locale == 'hy') return 'hy-am'; // Armenian
2364    if(locale == 'tl') return 'tl-ph'; // Tagalog/Filipino
2365    if(locale == 'zh') return 'zh-cn'; // Chinese
2366    if(locale == 'ar') return 'ar-tn'; // Tunisian Arabic
2367    // Y casos especiales
2368    // En proxia se utiliza para inglés británico el en_UK lo cual es incorrecto.
2369    // Para Java en = en_US = en_UK (aunque el en_UK sea un engendro un poco raro, yo creo que tira directamente al en y por tanto en_US)
2370    //       y la única forma de poner el inglés británico es el en_GB
2371    // En javaScript tenemos:
2372    // 		en y en-us: que es el inglés americano
2373    //		en-gb: que es el inglés británico
2374    if ( locale == 'en-UK') return 'en-us';
2375    if ( locale == 'en') return 'en-us';
2376    // Al en-gb no le tocamos
2377    // if(locale == 'en') return 'en-gb'; // English (Great Britain)
2378    return locale;
2379}
2380
2381/**
2382 * Función que inicializa el selector de fecha
2383 * @param {string} $container - Contenedor en el que se carga el selector
2384 * @param callbackOnChange
2385 * @memberOf Init
2386 */
2387function initDateTimePickers($container, callbackOnChange) {
2388
2389    var selector = "input.cmParamDateType,input.cmParamDateTimeType,input.cmParamTimeType";
2390
2391    if(!$container) $container = $(selector);
2392
2393    if($container.length > 0) {
2394        if(typeof(moment) != 'function') {
2395            loadScript({ url: _rootWeb+'/javaScript/moment/min/moment.min.js', success: function(){
2396                    loadScript({ url: _rootWeb+'/javaScript/moment/locale/'+getMomentLocale(_userLocaleLang)+'.js', success: function(){
2397                            initDateTimePickers($container, callbackOnChange);
2398                        }});
2399                }});
2400        } else {
2401            if(typeof($.fn.datetimepicker) != 'function') {
2402                loadCSS(_rootWeb+'/javaScript/bootstrap-datetimepicker/css/bootstrap-datetimepicker.css');
2403                loadScript({ url: _rootWeb+'/javaScript/bootstrap-datetimepicker/js/bootstrap-datetimepicker.js', success: function(){
2404                        initDateTimePickers($container, callbackOnChange);
2405                    }});
2406            } else {
2407                // Opciones comunes
2408                var pickerOptions = {
2409                    locale: getMomentLocale(_userLocaleLang),
2410                    allowInputToggle: true,
2411                    useCurrent: false,
2412                    keepOpen: false,
2413                    debug: ($.browser.msie && $.browser.version <= 8) ? true : false,
2414                    tooltips: {
2415                        today: dtp_goToday,
2416                        clear: dtp_clearSelection,
2417                        close: dtp_closePicker,
2418                        selectMonth: dtp_selectMonth,
2419                        prevMonth: dtp_prevMonth,
2420                        nextMonth: dtp_nextMonth,
2421                        selectYear: dtp_selectYear,
2422                        prevYear: dtp_prevYear,
2423                        nextYear: dtp_nextYear,
2424                        selectDecade: dtp_selectDecade,
2425                        prevDecade: dtp_prevDecade,
2426                        nextDecade: dtp_nextDecade,
2427                        prevCentury: dtp_prevCentury,
2428                        nextCentury: dtp_nextCentury,
2429                        pickHour: dtp_pickHour,
2430                        incrementHour: dtp_incrementHour,
2431                        decrementHour: dtp_decrementHour,
2432                        pickMinute: dtp_pickMinute,
2433                        incrementMinute: dtp_incrementMinute,
2434                        decrementMinute: dtp_decrementMinute,
2435                        pickSecond: dtp_pickSecond,
2436                        incrementSecond: dtp_incrementSecond,
2437                        decrementSecond: dtp_decrementSecond,
2438                        togglePeriod: dtp_togglePeriod,
2439                        selectTime: dtp_selectTime,
2440                        helpKey: dtp_helpKey,
2441                        helpTitle: dtp_helpTitle,
2442                        helpText: dtp_helpText
2443                    }
2444                };
2445
2446                $container.each(function() {
2447                    var $input = $(this);
2448
2449                    if($input.data("init")) return true;
2450
2451                    if(!$input.is("input")) {
2452                        initDateTimePickers($(selector, $input), callbackOnChange);
2453                        return true;
2454                    }
2455
2456                    var dateFormat = $input.data("dateFormat") ? $input.data("dateFormat") : dtp_dateFormat.replace(/-/g, '/'); // En Proxia se tratan las fechas siempre con barras
2457                    var timeFormat = $input.data("timeFormat") ? $input.data("timeFormat") : dtp_timeFormat;
2458
2459                    if($input.hasClass("cmParamDateType")) {
2460                        $input.datetimepicker($.extend(pickerOptions, { format: dateFormat }));
2461                    }
2462
2463                    if($input.hasClass("cmParamDateTimeType")) {
2464                        $input.datetimepicker($.extend(pickerOptions, { format: dateFormat + ' ' + timeFormat }));
2465                    }
2466
2467                    if($input.hasClass("cmParamTimeType")) {
2468                        $input.datetimepicker($.extend(pickerOptions, { format: timeFormat }));
2469                    }
2470
2471                    if(typeof(callbackOnChange) == 'function') {
2472                        $input.on("dp.change", callbackOnChange);
2473                    }
2474
2475                    var $button = $input.next("button,.btn").first();
2476                    if($button.length == 0) $button = $input.prev("button,.btn").first();
2477                    if($button.length == 0) $button = $("button,.btn", $input.parent()).first();
2478                    if($button.length == 0) $button = $("button,.btn", $input.parent().parent()).first();
2479                    if($button.length > 0) {
2480                        $button.removeAttr("onclick").removeAttr("onkeypress");
2481                        $button.click(function(e) {
2482                            e.preventDefault();
2483                            if(!$input.prop("disabled")) $input.focus();
2484                        });
2485                    }
2486
2487                    $input.data("init", true);
2488                });
2489
2490            }
2491
2492        }
2493    }
2494}
2495
2496/*!
2497 * Este archivo lleva las acciones que se han de ejecutar para la carga de los mapas.
2498 *
2499 * Copyright(c) Divisa Informática y Telecomunicaciones S.A.
2500 */
2501
2502var globalGmarkerImage = false;
2503var globalGmarkerShadowImage = false;
2504var globalGmarkerRouteImage = false;
2505var globalGClusterImage = false;
2506var globalGClusterShadowImage = false;
2507
2508/**
2509 * Función usada para cargar la librería de Google Maps
2510 * @param {boolean} force=false Por defecto es false
2511 * @param {boolean} routingEngine=true Si habilitamos o no el motor de routing
2512 * @param {boolean} drawingEngine=false Si habilitamos o no el motor de dibujado
2513 * @param callback Función de callback
2514 * @memberOf Init
2515 */
2516function initMaps(force, routingEngine, drawingEngine, callback) {
2517    var mapsContainer = $("div.cmMap_Container");
2518    // Si no hay mapas no lo cargamos...
2519    if(mapsContainer.length <= 0) {
2520        if(force === undefined || force === false || force === null) return;
2521    }
2522    if(routingEngine === undefined || routingEngine === null) routingEngine = true;
2523    if(drawingEngine === undefined || drawingEngine === null) drawingEngine = false;
2524
2525    // Tenemos que cargar la configuración relacionada con el tipo de mapas.
2526    $.getJSON(_rootWeb+'/cm/gmaps/maps-configuration.json',function(mapEngineConfiguration) {
2527        // En función del motor de mapas cargamos un conjunto de scripts u otros.
2528        globalGmarkerImage = mapEngineConfiguration.markers.gmarker;
2529        globalGmarkerShadowImage = mapEngineConfiguration.markers.gmarkerShadow;
2530        globalGmarkerRouteImage = mapEngineConfiguration.markers.gmarkerRoute;
2531        globalGClusterImage = mapEngineConfiguration.markers.gcluster;
2532        globalGClusterShadowImage = mapEngineConfiguration.markers.gclusterShadow;
2533
2534
2535        switch(mapEngineConfiguration.engine) {
2536            case 'leaflet':
2537                // Cargamos los motores de CSS de leaflet, routing-machine y geocoder
2538                loadCSS(_rootWeb+'/javaScript/leaflet/core-1.9.4/leaflet.css');
2539                loadCSS(_rootWeb+'/javaScript/leaflet/gesture-handling-1.4.4/leaflet-gesture-handling.min.css');
2540                if(routingEngine) {
2541                    loadCSS(_rootWeb+'/javaScript/leaflet/routing-machine-3.2.8/leaflet-routing-machine.css');
2542                    loadCSS(_rootWeb+'/javaScript/leaflet/control-geocoder-1.5.8/Control.Geocoder.css');
2543                }
2544                if(drawingEngine) {
2545                    loadCSS(_rootWeb+'/javaScript/leaflet/draw-0.4.14/leaflet.draw.css');
2546                }
2547
2548                var scripts = new Array();
2549                scripts.push(_rootWeb+'/javaScript/leaflet/core-1.9.4/leaflet.js');
2550                scripts.push(_rootWeb+'/javaScript/leaflet/gesture-handling-1.4.4/leaflet-gesture-handling.min.js');
2551                if(routingEngine) {
2552                    // Introducimos el motor de routing correspondiente.
2553                    switch(mapEngineConfiguration.leaflet.directions.provider) {
2554                        case 'mapbox':
2555                            scripts.push('https://api.mapbox.com/mapbox.js/v3.1.1/mapbox.js');
2556                            // La parte de routing especifica, por alguna razon debe ir antes.
2557                            scripts.push(_rootWeb+'/javaScript/leaflet/routing-machine-3.2.8/leaflet-routing-machine.min.js');
2558                            scripts.push(_rootWeb+'/javaScript/leaflet/control-geocoder-1.5.8/Control.Geocoder.js');
2559                            break;
2560                        case 'esri':
2561                            // La parte de routing especifica.
2562                            scripts.push(_rootWeb+'/javaScript/leaflet/routing-machine-3.2.8/leaflet-routing-machine.min.js');
2563                            scripts.push(_rootWeb+'/javaScript/leaflet/control-geocoder-1.5.8/Control.Geocoder.js');
2564                            // El motor de esri debe ir despues
2565                            scripts.push(_rootWeb+'/javaScript/leaflet/routing-machine-esri/lrm-esri.js');
2566                            break;
2567                        case 'disabled':
2568                            // Solo el geocoder.
2569                            scripts.push(_rootWeb+'/javaScript/leaflet/control-geocoder-1.5.8/Control.Geocoder.js');
2570                            break;
2571                        default:
2572                            // La parte de routing especifica.
2573                            scripts.push(_rootWeb+'/javaScript/leaflet/routing-machine-3.2.8/leaflet-routing-machine.min.js');
2574                            scripts.push(_rootWeb+'/javaScript/leaflet/control-geocoder-1.5.8/Control.Geocoder.js');
2575                            break;
2576                    }
2577
2578                }
2579                if(drawingEngine) {
2580                    // Metemos el motro de drawing.
2581                    scripts.push(_rootWeb+'/javaScript/leaflet/draw-0.4.14/leaflet.draw.js');
2582                }
2583
2584                // Ahora lo único que tenemos que hacer es cargar todos los scripts en bloque.
2585                loadScript({url: scripts,success: function() {
2586                        afterMapsLoaded(mapEngineConfiguration.leaflet,routingEngine,callback);
2587                    }});
2588                break;
2589            case 'google':
2590                // Comprobamos si hemos especificado alguna API key de Google Maps para el proyecto actual
2591                var gmapsAPIKey = mapEngineConfiguration.google.apiKey;
2592
2593                var gmapsLibrary  = "https://maps.googleapis.com/ma
2593ps/api/js";
2594                gmapsLibrary += "?language="+_userLocaleLang;
2595                gmapsLibrary += "&region="+_userLocaleCountry;
2596                gmapsLibrary += "&libraries=drawing";
2597                gmapsLibrary += "&callback=initGMapsLoaded";
2598                // Chapuza... habría que adaptarse a la última version en el mapsApi mandando el POI central.
2599                gmapsLibrary += "&v=3.22";
2600                gmapsLibrary += gmapsAPIKey != null && gmapsAPIKey != "" ? "&key="+gmapsAPIKey : "";
2601
2602                if(loadedFiles[prepareLoadedFile(gmapsLibrary)])
2603                    initGMapsLoaded();
2604                else
2605                    loadScript({ url: gmapsLibrary });
2606                break;
2607        }
2608    });
2609}
2610
2611/**
2612 * Función usada para pintar mapas de LeafLet
2613 * @param mapEngineConfiguration
2614 * @param routingEngine
2615 * @param callback
2616 * @memberOf Init
2617 */
2618function afterMapsLoaded(mapEngineConfiguration,routingEngine,callback) {
2619    var mapsContainer = $("div.cmMap_Container");
2620
2621    // La parte de atribuciones que tenemos.
2622    var attributions = new Array();
2623
2624    // La configuración especial que tenemos asociada.
2625    var config = {mapsEngine: {},
2626        geocodingEngine: false,
2627        directionsEngine: false,
2628        attributions: new Array()};
2629
2630    // El motor de tiles asociado que tenemos.
2631
2632    switch(mapEngineConfiguration.maps.provider) {
2633        case 'osm':
2634        case 'bing':
2635            config.mapsEngine.url = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
2636            config.mapsEngine.options = mapEngineConfiguration.maps.options;
2637            config.attributions.push('Tiles &copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors');
2638            break;
2639        case 'mapbox':
2640            config.mapsEngine.url = 'https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}';
2641            config.mapsEngine.options = $.extend($.extend({},{accessToken: mapEngineConfiguration.mapbox.apiKey}),mapEngineConfiguration.maps.options);
2642            config.attributions.push('Tiles &copy; <a href="https://www.mapbox.com/about/maps/">Mapbox</a>, <a href="http://osm.org/copyright">OpenStreetMap</a> contributors');
2643            break;
2644        case 'esri':
2645            config.mapsEngine.url = 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}';
2646            config.mapsEngine.options = mapEngineConfiguration.maps.options;
2647            config.attributions.push('Tiles &copy; Esri &mdash; Source: Esri, DeLorme, NAVTEQ, USGS, Intermap, iPC, NRCAN, Esri Japan, METI, Esri China (Hong Kong), Esri (Thailand), TomTom, 2012');
2648            break;
2649    }
2650
2651    if(routingEngine) {
2652        // Inicalizamos el motor de geocoding asociado...
2653        switch(mapEngineConfiguration.geocoder.provider) {
2654            case 'osm':
2655                config.geocodingEngine = new L.Control.Geocoder.Nominatim(mapEngineConfiguration.geocoder.options);
2656                config.attributions.push('Geocoding &copy; <a href="http://osm.org/copyright">OSM Nominatim</a>');
2657                break;
2658            case 'mapbox':
2659                config.geocodingEngine = new L.Control.Geocoder.Mapbox(mapEngineConfiguration.mapbox.apiKey,mapEngineConfiguration.geocoder.options);
2660                config.attributions.push('Geocoding &copy; <a href="https://www.mapbox.com/about/maps/">Mapbox</a>');
2661                break;
2662            case 'bing':
2663                config.geocodingEngine = new L.Control.Geocoder.Bing(mapEngineConfiguration.bing.apiKey);
2664                config.attributions.push('Geocoding &copy; <a href="https://www.bing.com/maps">Microsoft Bing Maps</a>');
2665                break;
2666            case 'esri':
2667                config.geocodingEngine = new L.Control.Geocoder.ArcGis('',$.extend({service_url: mapEngineConfiguration.esri.geocoderServiceUrl},mapEngineConfiguration.geocoder.options));
2668                config.attributions.push('Geocoding &copy; <a href="https://www.esri.com">ESRI</a>');
2669                break;
2670        }
2671
2672        switch(mapEngineConfiguration.directions.provider) {
2673            case 'osm':
2674            case 'bing':
2675                config.directionsEngine = new L.Routing.OSRMv1(mapEngineConfiguration.directions.options);
2676                config.attributions.push('Routing &copy; <a href="http://project-osrm.org/">Project OSRM</a>')
2677                break;
2678            case 'esri':
2679                config.directionsEngine = new L.Routing.esri($.extend($.extend({serviceUrl: mapEngineConfiguration.esri.directionsServiceUrl}
2679,{routingOptions: {liveTraffic: false, profile: 'Driving'}}),mapEngineConfiguration.directions.options));
2680                config.attributions.push('Routing &copy; <a href="https://www.esri.com">ESRI</a>')
2681                break;
2682            case 'mapbox':
2683                config.directionsEngine = new L.Routing.mapbox(mapEngineConfiguration.mapbox.apiKey,mapEngineConfiguration.directions.options);
2684                config.attributions.push('Routing &copy; <a href="https://www.mapbox.com/about/maps/">Mapbox</a>')
2685                break;
2686        }
2687    }
2688
2689    // Incializamos el motor de mapas...
2690    loadScript({ url: _rootWeb+'/javaScript/leafletMapsApi.js', success: function(){
2691            if(callback!=undefined) {
2692                cfg = {};
2693                cfg.routingEngine   = config.directionsEngine;
2694                cfg.geocodingEngine = config.geocodingEngine;
2695                cfg.tilesEngine     = config.mapsEngine
2696                cfg.attributions    = config.attributions;
2697
2698                callback(cfg);
2699            } else {
2700                mapsContainer.each(function() {
2701                    var gmapsThis = $(this);
2702                    var gmapsMap = $("div.cmMap_googleMaps", gmapsThis);
2703                    var gmapsKml = $("div.cmMap_kml", gmapsThis);
2704                    if(gmapsMap.length > 0 && gmapsMap.is(":empty")) {
2705                        var kmlObject = null;
2706                        if(gmapsKml.length > 0) {
2707                            var kmlContent = gmapsKml.html();
2708                            if(kmlContent && kmlContent != '') {
2709                                kmlContent = kmlContent.replace(/<!--/g, '').replace(/-->/g, '');
2710                                kmlObject = $.parseXML(kmlContent);
2711                            }
2712                        }
2713                        mapConfiguration = varTipoMapaUsuario;
2714                        mapConfiguration.routingEngine   = config.directionsEngine;
2715                        mapConfiguration.geocodingEngine = config.geocodingEngine;
2716                        mapConfiguration.tilesEngine     = config.mapsEngine
2717                        mapConfiguration.attributions    = config.attributions;
2718
2719                        var mapObject = new cm_LeafletMap(mapConfiguration);
2720                        mapObject.cmMap_initMap(gmapsThis, kmlObject);
2721                    }
2722                });
2723            }
2724        }});
2725}
2726
2727/**
2728 * Función usada para pintar mapas de Google Maps
2729 * @memberOf Init
2730 */
2731function initGMapsLoaded() {
2732    loadScript({ url: _rootWeb+'/javaScript/mapsApi.js', success: function(){
2733            var gmapsContainer = $("div.cmMap_Container");
2734            if(gmapsContainer.length > 0) {
2735                gmapsContainer.each(function() {
2736                    var gmapsThis = $(this);
2737                    var gmapsMap = $("div.cmMap_googleMaps", gmapsThis);
2738                    var gmapsKml = $("div.cmMap_kml", gmapsThis);
2739                    if(gmapsMap.length > 0 && gmapsMap.is(":empty")) {
2740                        var kmlObject = null;
2741                        if(gmapsKml.length > 0) {
2742                            var kmlContent = gmapsKml.html();
2743                            if(kmlContent && kmlContent != '') {
2744                                kmlContent = kmlContent.replace(/<!--/g, '').replace(/-->/g, '');
2745                                kmlObject = $.parseXML(kmlContent);
2746                            }
2747                        }
2748                        var googleMapObject = new cm_googleMap(varTipoMapaUsuario);
2749                        googleMapObject.cmMap_initMap(gmapsThis, kmlObject);
2750                    }
2751                });
2752            }
2753        }});
2754}
2755
2756//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
2757//:::                                                                         :::
2758//:::  This routine calculates the distance between two points (given the     :::
2759//:::  latitude/longitude of those points). It is being used to calculate     :::
2760//:::  the distance between two locations using GeoDataSource (TM) prodducts  :::
2761//:::                                                                         :::
2762//:::  Definitions:                                                           :::
2763//:::    South latitudes are negative, east longitudes are positive           :::
2764//:::                                                                         :::
2765//:::  Passed to function:                                                    :::
2766//:::    lat1, lon1 = Latitude and Longitude of point 1 (in decimal degrees)  :::
2767//:::    lat2, lon2 = Latitude and Longitude of point 2 (in decimal degrees)  :::
2768//:::    unit = the unit you desire for results                               :::
2769//:::           where: 'M' is statute miles (default)                         :::
2770//:::                  'K' is kilometers                                      :::
2771//:::                  'N' is nautical miles                                  :::
2772//:::                                                                         :::
2773//:::  Worldwide cities and other features databases with latitude longitude  :::
2774//:::  are available at https://www.geodatasource.com                         :::
2775//:::                                                                         :::
2776//:::  For enquiries, please contact [email protected]                  :::
2777//:::                                                                         :::
2778//:::  Official Web site: https://www.geodatasource.com                       :::
2779//:::                                                                         :::
2780//:::               GeoDataSource.com (C) All Rights Reserved 2017            :::
2781//:::                                                                         :::
2782//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
2783
2784/**
2785 *
2786 * @param lat1
2787 * @param lon1
2788 * @param lat2
2789 * @param lon2
2790 * @param unit
2791 * @returns {number}
2792 * @memberOf Init
2793 */
2794function distance(lat1, lon1, lat2, lon2, unit) {
2795    var radlat1 = Math.PI * lat1/180;
2796    var radlat2 = Math.PI * lat2/180;
2797    var theta = lon1-lon2;
2798    var radtheta = Math.PI * theta/180;
2799    var dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
2800    if (dist > 1) {
2801        dist = 1;
2802    }
2803    dist = Math.acos(dist);
2804    dist = dist * 180/Math.PI;
2805    dist = dist * 60 * 1.1515;
2806    if (unit=="K") { dist = dist * 1.609344; }
2807    if (unit=="N") { dist = dist * 0.8684; }
2808    return dist;
2809}
2810
2811/**
2812 *
2813 * @param $container
2814 * @memberOf Init
2815 */
2816function initContentListGeolocation($container) {
2817    if(!$container || $container.length == 0) return;
2818
2819    var $list = $("ul.cmContentList,ul.cmContentMultipleList", $container).first();
2820    var $items = $("li.cmContentItem", $list);
2821    if($items.length == 0) return;
2822
2823    if (navigator.geolocation) {
2824        navigator.geolocation.getCurrentPosition(function(position) {
2825
2826            // Success: obtenemos la ubicación actual del usuario
2827            var userLat = position.coords.latitude;
2828            var userLon = position.coords.longitude;
2829
2830            var items = [];
2831            $items.each(function() {
2832                var $item = $(this);
2833                var itemLat = $("div[data-latitude]", $item).data("latitude");
2834                var itemLon = $("div[data-longitude]", $item).data("longitude");
2835                if(itemLat && itemLat != '' && itemLon && itemLon != '') {
2836                    itemLat = parseFloat(itemLat.replace(',','.'), 10);
2837                    itemLon = parseFloat(itemLon.replace(',','.'), 10);
2838
2839                    // Distancia desde la ubicación del usuario a cada elemento, en metros
2840                    var dist = distance(userLat, userLon, itemLat, itemLon, 'K') * 1000;
2841
2842                    items.push([dist, $item]);
2843                } else {
2844                    // Si el contenido no tiene coordenadas lo ponemos al final (diámetro de la tierra en metros por PI)
2845                    items.push([12742 * 1000 * Math.PI, $item]);
2846                }
2847            });
2848
2849            // Ahora ordenamos el array de items por distancia, de forma descendente,
2850            // es decir, primero el elemento más cercano al usuario
2851            items.sort(function sortFunction(a, b) {
2852                if (a[0] === b[0]) return 0;
2853                else return (a[0] < b[0]) ? -1 : 1;
2854            });
2855
2856            // Repintamos la lista de elementos ordenados por cercanía
2857            $list.empty();
2858            for(var i = 0; i < items.length; i++) {
2859                $list.append(items[i][1]);
2860            }
2861
2862        }, function() {
2863            // Error: el usuario no ha aceptado compartir su ubicación
2864        });
2865    }
2866}
2867
2868/**
2869 * Esta función se ejecuta una vez cargado el contenido por ajaz, para incializar los scroll infinitos, rotativos, etc..
2870 * @memberOf Init
2871 */
2872function afterAjaxContent(){
2873    initWayPoints();
2874    initEndlessNavigation();
2875    // Si existe función custom, también se ejecuta
2876    try {
2877        if (typeof(customAfterAjaxContent) == 'function'){
2878            customAfterAjaxContent();
2879        }
2880    } catch(ex) {
2881    }
2882
2883}
2884
2885/**
2886 * Evento load
2887 * @memberOf Init
2888 */
2889$(window).load(function(){
2890
2891    // Función que inicializa los mapas (Leaflet / GoogleMaps)
2892    if(typeof(wizardMode) != 'boolean' || !wizardMode) initMaps();
2893
2894    // Función que inicializa el plugin WayPoints
2895    initWayPoints();
2896
2897    // Función que inicializa el soporte para la autopaginacion (modo nuevo vs. waypoints que no es accesible)
2898    initEndlessNavigation();
2899
2900    // Función que inicializa los mapas de imagen
2901    if(typeof(initImageMaps) == 'function') initImageMaps();
2902
2903    // Función que inicializa los componentes de los blogs
2904    initBlogs();
2905
2906    // Función que se encarga de ocultar el wait-dialog con efecto fade
2907    if(typeof(hideWaitDialog) == 'function') hideWaitDialog(true);
2908
2909});

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.