PageSourceSearch

https://laserum.com/wp-content/themes/laserum/assets/js/buscar-centros.js?ver=1770905800

js laserum.com collected 2026-10-05 23:31:51 UTC 17,947 bytes, 464 lines download raw bytes

1/**
2 * Buscador de Centros con Google Maps
3 * Inicializa el mapa y gestiona el filtrado del listado
4 */
5
6(function() {
7    'use strict';
8
9    // Variables globales
10    let map;
11    let markers = [];
12    let infoWindow;
13
14    /**
15     * Inicializa el mapa de Google Maps
16     */
17    window.initBuscarCentrosMapa = function() {
18        const mapElement = document.getElementById('mapa-buscar-centros');
19        
20        if (!mapElement || !window.centrosData) {
21            console.warn('No se encontró el elemento del mapa o los datos de centros');
22            return;
23        }
24
25        // Detectar si es móvil
26        const isMobile = window.innerWidth <= 768;
27        const zoomLevel = isMobile ? 5 : 6;
28
29        // Configuración del mapa centrado en España
30        map = new google.maps.Map(mapElement, {
31            zoom: zoomLevel,
32            center: { lat: 40.4637, lng: -3.7492 }, // Madrid (centro de España)
33            disableDefaultUI: true,
34            zoomControl: true,
35            streetViewControl: false,
36            fullscreenControl: false,
37            mapTypeControl: false,
38            clickableIcons: false,
39            gestureHandling: 'cooperative'
40        });
41
42        // Crear infoWindow única
43        infoWindow = new google.maps.InfoWindow();
44
45        // Geocodificar y agregar marcadores para cada centro
46        const geocoder = new google.maps.Geocoder();
47        
48        window.centrosData.forEach(function(centro, index) {
49            if (!centro.direccion) return;
50
51            // Agregar delay para evitar límite de peticiones
52            setTimeout(function() {
53                geocodificarYCrearMarcador(geocoder, centro);
54            }, index * 100);
55        });
56    };
57
58    /**
59     * Geocodifica una dirección y crea un marcador
60     */
61    function geocodificarYCrearMarcador(geocoder, centro) {
62        geocoder.geocode({ address: centro.direccion }, function(results, status) {
63            if (status === 'OK' && results[0]) {
64                const marker = new google.maps.Marker({
65                    position: results[0].geometry.location,
66                    map: map,
67                    title: centro.titulo,
68                    icon: {
69                        url: window.iconUrl,
70                        scaledSize: new google.maps.Size(40, 40)
71                    },
72                    animation: google.maps.Animation.DROP
73                });
74
75                // Guardar referencia al centro en el marcador
76                marker.centroData = centro;
77                markers.push(marker);
78
79                // Evento click en el marcador
80                marker.addListener('click', function() {
81                    const content = `
82                        <div style="padding: 5px 10px 10px 10px; max-width: 280px; min-width: 260px;">
83                            <h3 style="margin: 0 0 4px; color: #1C3E8F; font-family: Sztos; font-size: 16px; font-weight: 500; line-height: 19px; letter-spacing: -0.14px;">Láserum - ${centro.ciudad}</h3>
84                            <p style="margin: 0 0 12px; font-size: 14px; color: #6B7280;">Especialistas en depilación láser</p>
85                            <p style="margin: 0 0 4px; font-size: 12px; color: #9CA3AF; font-weight: 700;">Centro estético</p>
86                            <p style="margin: 0 0 12px; font-size: 13px; color: #9CA3AF;">${centro.direccion}</p>
87                            ${centro.telefono ? `<p style="margin: 0 0 12px; font-size: 13px; font-weight: 500; color: #1C3E8F;">Tel: ${centro.telefono}</p>` : ''}
88                            <a href="${centro.url}" style="display: inline-flex; align-items: center; gap: 6px; font-size: 14px; font-weight: 400; color: #1C3E8F; text-decoration: none;">Ver página de centro</a>
89                        </div>
90                    `;
91                    
92                    infoWindow.setContent(content);
93                    infoWindow.open(map, marker);
94                    
95                    // Ajustar el margen del contenedor del InfoWindow
96                    google.maps.event.addListenerOnce(infoWindow, 'domready', function() {
97                        const iwOuter = document.querySelector('.gm-style-iw-d');
98                        if (iwOuter) {
99                            iwOuter.style.marginTop = '-30px';
100                        }
101                    });
102                });
103            }
104        });
105    }
106
107    /**
108     * Filtra los centros según el texto de búsqueda
109     */
110    function filtrarCentros(searchText) {
111        const items = document.querySelectorAll('.centro-item');
112        const listado = document.getElementById('listado-centros');
113        let visibleCount = 0;
114
115        // Normalizar texto de búsqueda
116        const searchNormalized = searchText.toLowerCase().trim();
117
118        items.forEach(function(item) {
119            const titulo = item.dataset.titulo.toLowerCase();
120            const provincia = item.dataset.provincia.toLowerCase();
121            const codigoPostal = item.dataset.codigoPostal;
122
123            // Verificar si coincide con la búsqueda
124            const coincide = searchNormalized === '' ||
125                           titulo.includes(searchNormalized) ||
126                           provincia.includes(searchNormalized) ||
127                           (codigoPostal && codigoPostal.includes(searchNormalized));
128
129            if (coincide) {
130                item.classList.remove('hidden');
131                visibleCount++;
132            } else {
133                item.classList.add('hidden');
134            }
135        });
136
137        // Mostrar mensaje si no hay resultados
138        let noResultadosMsg = listado.querySelector('.no-resultados');
139        
140        if (visibleCount === 0 && searchNormalized !== '') {
141            if (!noResultadosMsg) {
142                noResultadosMsg = document.createElement('div');
143                noResultadosMsg.className = 'no-resultados';
144                noResultadosMsg.textContent = 'No se encontraron centros para tu búsqueda';
145                listado.appendChild(noResultadosMsg);
146            }
147        } else if (noResultadosMsg) {
148            noResultadosMsg.remove();
149        }
150
151        // Filtrar marcadores en el mapa
152        filtrarMarcadores(searchNormalized);
153    }
154
155    /**
156     * Filtra los marcadores del mapa según la búsqueda
157     */
158    function filtrarMarcadores(searchText) {
159        markers.forEach(function(marker) {
160            const centro = marker.centroData;
161            
162            if (!centro) {
163                marker.setMap(map);
164                return;
165            }
166
167            const titulo = centro.ciudad.toLowerCase();
168            const provincia = centro.provincia.toLowerCase();
169            const codigoPostal = centro.codigo_postal;
170
171            const coincide = searchText === '' ||
172                           titulo.includes(searchText) ||
173                           provincia.includes(searchText) ||
174                           (codigoPostal && codigoPostal.includes(searchText));
175
176            // Mostrar u ocultar marcador
177            marker.setMap(coincide ? map : null);
178        });
179
180        // Ajustar zoom si hay filtros activos
181        if (searchText !== '' && markers.length > 0) {
182            const bounds = new google.maps.LatLngBounds();
183            let hasVisibleMarkers = false;
184
185            markers.forEach(function(marker) {
186                if (marker.getMap()) {
187                    bounds.extend(marker.getPosition());
188                    hasVisibleMarkers = true;
189                }
190            });
191
192            if (hasVisibleMarkers) {
193                map.fitBounds(bounds);
194                
195                // Limitar el zoom máximo
196                google.maps.event.addListenerOnce(map, 'bounds_changed', function() {
197                    if (map.getZoom() > 15) {
198                        map.setZoom(15);
199                    }
200                });
201            }
202        }
203    }
204
205    /**
206     * Inicializa los event listeners
207     */
208    function inicializarEventListeners() {
209        const input = document.getElementById('buscar-centros-input');
210        const button = document.querySelector('.buscar-centros-btn');
211
212        if (!input) return;
213
214        // Filtrar mientras se escribe (con debounce)
215        let timeoutId;
216        input.addEventListener('input', function() {
217            clearTimeout(timeoutId);
218            timeoutId = setTimeout(function() {
219                filtrarCentros(input.value);
220            }, 300);
221        });
222
223        // Filtrar al hacer click en el botón
224        if (button) {
225            button.addEventListener('click', function() {
226                filtrarCentros(input.value);
227            });
228        }
229
230        // Filtrar al presionar Enter
231        input.addEventListener('keypress', function(e) {
232            if (e.key === 'Enter') {
233                e.preventDefault();
234                filtrarCentros(input.value);
235            }
236        });
237    }
238
239    /**
240     * Cargar el script de Google Maps
241     */
242    function cargarGoogleMaps() {
243        // Verificar si ya existe el script
244        if (window.google && window.google.maps) {
245            initBuscarCentrosMapa();
246            return;
247        }
248
249        // Verificar si ya se está cargando
250        if (document.querySelector('script[src*="maps.googleapis.com"]')) {
251            return;
252        }
253
254        // Crear y cargar el script
255        const script = document.createElement('script');
256        script.src = 'https://maps.googleapis.com/maps/api/js?key=AIzaSyCjSxKoaBzfLYt9bQGb8-F0eI6zfJGHTzk&callback=initBuscarCentrosMapa';
257        script.async = true;
258        script.defer = true;
259        document.head.appendChild(script);
260    }
261
262    /**
263     * Inicializa el slider mobile con barra de scroll personalizada
264     */
265    function inicializarSliderMobile() {
266        const listadoScroll = document.querySelector('.listado-centros-scroll');
267        const panel = document.querySelector('.panel-buscar-centros');
268        
269        /*console.log('Inicializando slider mobile', {
270            listadoScroll: !!listadoScroll,
271            panel: !!panel,
272            width: window.innerWidth
273        });*/
274        
275        if (!listadoScroll || !panel) {
276            /*console.log('No se encontraron elementos necesarios');*/
277            return;
278        }
279        
280        if (window.innerWidth > 480) {
281            /*console.log('Ancho mayor a 480px, no se inicializa');*/
282            return;
283        }
284
285        // Eliminar TODOS los elementos de indicadores que puedan existir
286        const allIndicators = panel.querySelectorAll('.slider-indicators, .slider-indicator');
287        allIndicators.forEach(el => {
288            el.remove();
289            /*console.log('Elemento eliminado:', el.className);*/
290        });
291
292        // Buscar y eliminar cualquier div que contenga puntos pequeños
293        const allDivs = panel.querySelectorAll('div');
294        allDivs.forEach(div => {
295            if (div.style.width === '6px' || div.style.height === '6px' || 
296                div.classList.contains('indicator') || div.classList.contains('dot')) {
297                div.remove();
298                /*console.log('Div sospechoso eliminado');*/
299            }
300        });
301
302        // Crear barra de scroll personalizada si no existe
303        let customScrollbar = panel.querySelector('.custom-scrollbar');
304        if (!customScrollbar) {
305            customScrollbar = document.createElement('div');
306            customScrollbar.className = 'custom-scrollbar';
307            
308            const thumb = document.createElement('div');
309            thumb.className = 'custom-scrollbar-thumb';
310            customScrollbar.appendChild(thumb);
311            
312            panel.appendChild(customScrollbar);
313            /*console.log('Barra de scroll creada');*/
314        }
315
316        const thumb = customScrollbar.querySelector('.custom-scrollbar-thumb');
317
318        // Función para actualizar la barra de scroll
319        function actualizarScrollbar() {
320            const scrollWidth = listadoScroll.scrollWidth;
321            const clientWidth = listadoScroll.clientWidth;
322            const scrollLeft = listadoScroll.scrollLeft;
323            
324            // Contar centros visibles
325            const centrosVisibles = listadoScroll.querySelectorAll('.centro-item:not([style*="display: none"])').length;
326
327            /*console.log('Actualizando scrollbar', {
328                scrollWidth,
329                clientWidth,
330                scrollLeft,
331                centrosVisibles
332            });*/
333
334            // Ocultar si solo hay un centro o si no hay scroll
335            if (scrollWidth <= clientWidth || centrosVisibles <= 1) {
336                customScrollbar.style.display = 'none';
337                /*console.log('Contenido no desborda o solo hay un centro, ocultando scrollbar');*/
338                return;
339            }
340
341            customScrollbar.style.display = 'block';
342            
343            // Obtener el ancho real del contenedor de la scrollbar (que es fijo)
344            const scrollbarWidth = customScrollbar.getBoundingClientRect().width;
345
346            // Calcular ancho del thumb en píxeles basado en la proporción de contenido visible
347            const thumbWidthPx = (clientWidth / scrollWidth) * scrollbarWidth;
348            // Calcular posición del thumb en píxeles basada en el scroll real
349            const maxScroll = Math.max(scrollWidth - clientWidth, 1);
350            const scrollPercentage = scrollLeft / maxScroll;
351            const availableSpace = scrollbarWidth - thumbWidthPx;
352            const thumbLeftPx = Math.min(scrollPercentage * availableSpace, availableSpace);
353
354            thumb.style.width = thumbWidthPx + 'px';
355            thumb.style.left = thumbLeftPx + 'px';
356            
357            /*console.log('Scrollbar actualizada', {
358                scrollbarWidth: scrollbarWidth + 'px',
359                thumbWidth: thumbWidthPx + 'px',
360                thumbLeft: thumbLeftPx + 'px',
361                scrollPercentage: scrollPercentage
362            });*/
363        }
364
365        // Actualizar al hacer scroll
366        listadoScroll.addEventListener('scroll', actualizarScrollbar);
367
368        // Drag en la barra de scroll personalizada
369        let isDragging = false;
370        let startX = 0;
371        let startScrollLeft = 0;
372
373        thumb.addEventListener('mousedown', startDrag);
374        thumb.addEventListener('touchstart', startDrag);
375
376        function startDrag(e) {
377            isDragging = true;
378            startX = e.type === 'mousedown' ? e.clientX : e.touches[0].clientX;
379            startScrollLeft = listadoScroll.scrollLeft;
380            e.preventDefault();
381        }
382
383        document.addEventListener('mousemove', drag);
384        document.addEventListener('touchmove', drag);
385
386        function drag(e) {
387            if (!isDragging) return;
388            
389            const currentX = e.type === 'mousemove' ? e.clientX : e.touches[0].clientX;
390            const diff = currentX - startX;
391            const scrollbarWidth = customScrollbar.offsetWidth;
392            const scrollWidth = listadoScroll.scrollWidth;
393            
394            const scrollDiff = (diff / scrollbarWidth) * scrollWidth;
395            listadoScroll.scrollLeft = startScrollLeft + scrollDiff;
396        }
397
398        document.addEventListener('mouseup', stopDrag);
399        document.addEventListener('touchend', stopDrag);
400
401        function stopDrag() {
402            isDragging = false;
403        }
404
405        // Click en track para saltar
406        customScrollbar.addEventListener('click', function(e) {
407            if (e.target === customScrollbar) {
408                const rect = customScrollbar.getBoundingClientRect();
409                const clickX = e.clientX - rect.left;
410                const percentage = clickX / rect.width;
411                listadoScroll.scrollLeft = percentage * listadoScroll.scrollWidth;
412            }
413        });
414
415        // Actualizar al cambiar contenido
416        const observer = new MutationObserver(actualizarScrollbar);
417        const listado = listadoScroll.querySelector('.listado-centros');
418        if (listado) {
419            observer.observe(listado, {
420                childList: true,
421                subtree: true,
422                attributes: true,
423                attributeFilter: ['class', 'style']
424            });
425        }
426
427        // Actualizar inicialmente
428        actualizarScrollbar();
429
430        // Actualizar al cambiar tamaño
431        window.addEventListener('resize', actualizarScrollbar);
432    }
433
434    /**
435     * Inicialización cuando el DOM está listo
436     */
437    if (document.readyState === 'loading') {
438        document.addEventListener('DOMContentLoaded', function() {
439            if (document.querySelector('.mapa-buscar-centros')) {
440                inicializarEventListeners();
441                cargarGoogleMaps();
442                // Delay para asegurar que el contenido esté renderizado
443                setTimeout(inicializarSliderMobile, 500);
444            }
445        });
446    } else {
447        if (document.querySelector('.mapa-buscar-centros')) {
448            inicializarEventListeners();
449            cargarGoogleMaps();
450            // Delay para asegurar que el contenido esté renderizado
451            setTimeout(inicializarSliderMobile, 500);
452        }
453    }
454
455    // Reinicializar slider al cambiar tamaño de ventana
456    let resizeTimeout;
457    window.addEventListener('resize', function() {
458        clearTimeout(resizeTimeout);
459        resizeTimeout = setTimeout(function() {
460            inicializarSliderMobile();
461        }, 250);
462    });
463
464})();

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.