1/** 2 * InmoPortal â Leaflet glue (depends on inmo-leaflet, inmo-markercluster, inmo-public). 3 * 4 * window.InmoMap = { 5 * create(el, opts) â L.map with the tiles/attribution from InmoCfg.map 6 * icon() â L.icon built from the pin SVG 7 * cluster(map) â L.markerClusterGroup added to the map (or null) 8 * priceMarker(point) â L.marker with a price-label divIcon 9 * addPoints(map, points, opts) â layer with every point (clustered), fitBounds 10 * } 11 * 12 * Points are the arrays produced by Inmo_Index::map_points(): 13 * { id, lat, lng, price, op, type, zone, title, url, thumb, m2, rooms, baths, featured }. 14 */ 15( function () { 16 'use strict'; 17 18 if ( typeof window.L === 'undefined' ) { 19 return; 20 } 21 22 function cfg() { 23 return ( window.InmoCfg && window.InmoCfg.map ) || {}; 24 } 25 26 function esc( s ) { 27 if ( window.Inmo && window.Inmo.esc ) { 28 return window.Inmo.esc( s ); 29 } 30 return String( s == null ? '' : s ).replace( /[&<>"']/g, function ( c ) { 31 return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[ c ]; 32 } ); 33 } 34 35 /** 36 * Create a map on an element with our tiles and defaults. 37 * opts: center [lat,lng], zoom, scrollWheelZoom (default false). 38 */ 39 function create( el, opts ) { 40 opts = opts || {}; 41 var c = cfg(); 42 var center = opts.center || [ ( c.center && c.center.lat ) || 0, ( c.center && c.center.lng ) || 0 ]; 43 var map = L.map( el, { 44 center: center, 45 zoom: opts.zoom || c.zoom || 13, 46 scrollWheelZoom: typeof opts.scrollWheelZoom !== 'undefined' ? opts.scrollWheelZoom : false, 47 attributionControl: true 48 } ); 49 L.tileLayer( c.tiles, { 50 attribution: c.attribution || '', 51 maxZoom: c.max_zoom || 19 52 } ).addTo( map ); 53 return map; 54 } 55 56 /** 57 * The default pin icon (SVG with the brand color). 58 */ 59 function icon() { 60 var c = cfg(); 61 var size = c.marker_size || [ 32, 42 ]; 62 return L.icon( { 63 iconUrl: c.marker_icon, 64 iconSize: size, 65 iconAnchor: [ size[ 0 ] / 2, size[ 1 ] ], 66 popupAnchor: [ 0, -size[ 1 ] + 4 ] 67 } ); 68 } 69 70 /** 71 * A cluster group added to the map, or null when the plugin is missing. 72 */ 73 function cluster( map ) { 74 if ( typeof L.markerClusterGroup !== 'function' ) { 75 return null; 76 } 77 var g = L.markerClusterGroup( { 78 showCoverageOnHover: false, 79 maxClusterRadius: 48, 80 spiderfyOnMaxZoom: true 81 } ); 82 map.addLayer( g ); 83 return g; 84 } 85 86 /** 87 * "245.000 â¬" â "245k", "1.250.000 â¬" â "1,3M", rent "850 â¬/mes" â "850â¬". 88 */ 89 function shortPrice( point ) { 90 var n = parseInt( String( point.price || '' ).replace( /[^\d]/g, '' ), 10 ); 91 if ( ! n ) { 92 return String( point.price || '' ); 93 } 94 if ( point.op === 'rent' ) { 95 return n >= 10000 ? Math.round( n / 1000 ) + 'kâ¬' : n.toLocaleString( 'es-ES' ) + 'â¬'; 96 } 97 if ( n >= 1000000 ) { 98 var m = Math.round( n / 100000 ) / 10; 99 return String( m % 1 === 0 ? m.toFixed( 0 ) : m.toFixed( 1 ) ).replace( '.', ',' ) + 'M'; 100 } 101 if ( n >= 1000 ) { 102 return Math.round( n / 1000 ) + 'k'; 103 } 104 return String( n ); 105 } 106 107 /** 108 * Marker with the price as a pill label (divIcon). 109 */ 110 function priceMarker( point ) { 111 var html = '<span class="inmo-price-marker' + ( point.featured ? ' is-featured' : '' ) + '">' + esc( shortPrice( point ) ) + '</span>'; 112 return L.marker( [ point.lat, point.lng ], { 113 icon: L.divIcon( { className: 'inmo-pmark', html: html, iconSize: [ 0, 0 ], iconAnchor: [ 0, 0 ] } ), 114 riseOnHover: true, 115 title: point.title || '' 116 } ); 117 } 118 119 /** 120 * Popup mini-card for a point. 121 */ 122 function popupHtml( point ) { 123 var meta = []; 124 if ( point.m2 ) { 125 meta.push( point.m2 + ' m²' ); 126 } 127 if ( point.rooms ) { 128 meta.push( point.rooms + ' hab.' ); 129 } 130 if ( point.baths ) { 131 meta.push( point.baths + ' baños' ); 132 } 133 return '<a class="inmo-map-pop" href="' + esc( point.url ) + '">' + 134 '<span class="inmo-map-pop__img"><img src="' + esc( point.thumb ) + '" alt="" loading="lazy" /></span>' + 135 '<span class="inmo-map-pop__body">' + 136 '<strong class="inmo-map-pop__price">' + esc( point.price ) + '</strong>' + 137 '<span class="inmo-map-pop__title">' + esc( point.title ) + '</span>' + 138 ( meta.length ? '<span class="inmo-map-pop__meta">' + esc( meta.join( ' · ' ) ) + '</span>' : '' ) +
139 '</span></a>'; 140 } 141 142 /** 143 * Add a set of points (clustered when available) and fit the view. 144 * opts: popup (default true), prices (price labels, default true), cluster (default cfg), fit (default true). 145 * Returns the layer so callers can remove it later. 146 */ 147 function addPoints( map, points, opts ) { 148 opts = opts || {}; 149 var c = cfg(); 150 var useCluster = typeof opts.cluster !== 'undefined' ? opts.cluster : ( c.cluster !== false ); 151 var group = useCluster ? cluster( map ) : null; 152 if ( ! group ) { 153 group = L.layerGroup().addTo( map ); 154 } 155 var bounds = []; 156 ( points || [] ).forEach( function ( pt ) { 157 if ( typeof pt.lat === 'undefined' || typeof pt.lng === 'undefined' ) { 158 return; 159 } 160 var m = opts.prices === false 161 ? L.marker( [ pt.lat, pt.lng ], { icon: icon(), riseOnHover: true, title: pt.title || '' } ) 162 : priceMarker( pt ); 163 if ( opts.popup !== false ) { 164 m.bindPopup( popupHtml( pt ), { maxWidth: 280, minWidth: 220 } ); 165 } 166 group.addLayer( m ); 167 bounds.push( [ pt.lat, pt.lng ] ); 168 } ); 169 if ( opts.fit !== false && bounds.length ) { 170 map.fitBounds( bounds, { padding: [ 40, 40 ], maxZoom: 16 } ); 171 } 172 return group; 173 } 174 175 window.InmoMap = { 176 create: create, 177 icon: icon, 178 cluster: cluster, 179 priceMarker: priceMarker, 180 addPoints: addPoints 181 }; 182} )();
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.