osm.js (7563B)
1 ( function( $, L, rwmb, i18n ) { 2 'use strict'; 3 4 // Use function construction to store map & DOM elements separately for each instance 5 var OsmField = function ( $container ) { 6 this.$container = $container; 7 }; 8 9 // Use prototype for better performance 10 OsmField.prototype = { 11 // Initialize everything 12 init: function () { 13 this.initDomElements(); 14 this.initMapElements(); 15 16 this.initMarkerPosition(); 17 this.addListeners(); 18 this.autocomplete(); 19 20 // Make sure the map is displayed fully. 21 var map = this.map; 22 setTimeout( function() { 23 map.invalidateSize(); 24 }, 0 ); 25 }, 26 27 // Initialize DOM elements 28 initDomElements: function () { 29 this.$canvas = this.$container.find( '.rwmb-osm-canvas' ); 30 this.canvas = this.$canvas[0]; 31 this.$coordinate = this.$container.find( '.rwmb-osm' ); 32 this.addressField = this.$container.data( 'address-field' ); 33 }, 34 35 // Initialize map elements 36 initMapElements: function () { 37 var defaultLoc = this.$canvas.data( 'default-loc' ), 38 latLng; 39 40 defaultLoc = defaultLoc ? defaultLoc.split( ',' ) : [53.346881, -6.258860]; 41 latLng = L.latLng( defaultLoc[0], defaultLoc[1] ); // Initial position for map. 42 43 this.map = L.map( this.canvas, { 44 center: latLng, 45 zoom: 14 46 } ); 47 48 L.tileLayer( 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { 49 attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' 50 } ).addTo( this.map ); 51 this.marker = L.marker( latLng, { 52 draggable: true 53 } ).addTo( this.map ); 54 }, 55 56 // Initialize marker position 57 initMarkerPosition: function () { 58 var coordinate = this.$coordinate.val(), 59 location, 60 zoom; 61 62 if ( coordinate ) { 63 location = coordinate.split( ',' ); 64 var latLng = L.latLng( location[0], location[1] ); 65 this.marker.setLatLng( latLng ); 66 67 zoom = location.length > 2 ? parseInt( location[2], 10 ) : 14; 68 69 this.map.panTo( latLng ); 70 this.map.setZoom( zoom ); 71 } else if ( this.addressField ) { 72 this.geocodeAddress( false ); 73 } 74 }, 75 76 // Add event listeners for 'click' & 'drag' 77 addListeners: function () { 78 var that = this; 79 80 /* 81 * Auto change the map when there's change in address fields. 82 * Works only for multiple address fields as single address field has autocomplete functionality. 83 */ 84 if ( this.addressField.split( ',' ).length > 1 ) { 85 var geocodeAddress = that.geocodeAddress.bind( that ); 86 var addressFields = this.addressField.split( ',' ).forEach( function( part ) { 87 var $field = that.findAddressField( part ); 88 if ( null !== $field ) { 89 $field.on( 'change', geocodeAddress ); 90 } 91 } ); 92 } 93 94 this.map.on( 'click', function ( event ) { 95 that.marker.setLatLng( event.latlng ); 96 that.updateCoordinate( event.latlng ); 97 } ); 98 99 this.map.on( 'zoom', function () { 100 that.updateCoordinate( that.marker.getLatLng() ); 101 } ); 102 103 this.marker.on( 'drag', function () { 104 that.updateCoordinate( that.marker.getLatLng() ); 105 } ); 106 107 // Custom event to refresh maps when in hidden divs. 108 var refresh = that.refresh.bind( this ); 109 $( window ).on( 'rwmb_map_refresh', refresh ); 110 111 // Refresh on meta box hide and show 112 rwmb.$document.on( 'postbox-toggled', refresh ); 113 // Refresh on sorting meta boxes 114 $( '.meta-box-sortables' ).on( 'sortstop', refresh ); 115 }, 116 117 refresh: function () { 118 if ( ! this.map ) { 119 return; 120 } 121 this.map.invalidateSize(); 122 this.map.panTo( this.map.getCenter() ); 123 }, 124 125 // Autocomplete address 126 autocomplete: function () { 127 var that = this, 128 $address = this.getAddressField(); 129 130 if ( null === $address ) { 131 return; 132 } 133 134 $address.autocomplete( { 135 source: function ( request, response ) { 136 $.get( 'https://nominatim.openstreetmap.org/search', { 137 format: 'json', 138 q: request.term, 139 countrycodes: that.$canvas.data( 'region' ), 140 "accept-language": that.$canvas.data( 'language' ), 141 addressdetails: 1 142 }, function( results ) { 143 if ( ! results.length ) { 144 response( [ { 145 value: '', 146 label: i18n.no_results_string 147 } ] ); 148 return; 149 } 150 response( results.map( function ( item ) { 151 return { 152 address: item.address, 153 label: item.display_name, 154 value: item.display_name, 155 latitude: item.lat, 156 longitude: item.lon 157 }; 158 } ) ); 159 }, 'json' ); 160 }, 161 select: function ( event, ui ) { 162 var latLng = L.latLng( ui.item.latitude, ui.item.longitude ); 163 164 that.map.panTo( latLng ); 165 that.marker.setLatLng( latLng ); 166 that.updateCoordinate( latLng ); 167 168 $address.trigger( 'selected_address', [ui.item] ); 169 } 170 } ); 171 }, 172 173 // Update coordinate to input field 174 updateCoordinate: function ( latLng ) { 175 var zoom = this.map.getZoom(); 176 this.$coordinate.val( latLng.lat + ',' + latLng.lng + ',' + zoom ).trigger( 'change' ); 177 }, 178 179 // Find coordinates by address 180 geocodeAddress: function ( notify ) { 181 var address = this.getAddress(), 182 that = this; 183 if ( ! address ) { 184 return; 185 } 186 187 if ( false !== notify ) { 188 notify = true; 189 } 190 $.get( 'https://nominatim.openstreetmap.org/search', { 191 format: 'json', 192 q: address, 193 limit: 1, 194 countrycodes: that.$canvas.data( 'region' ), 195 "accept-language": that.$canvas.data( 'language' ) 196 }, function( result ) { 197 if ( result.length !== 1 ) { 198 if ( notify ) { 199 alert( i18n.no_results_string ); 200 } 201 return; 202 } 203 var latLng = L.latLng( result[0].lat, result[0].lon ); 204 that.map.panTo( latLng ); 205 that.marker.setLatLng( latLng ); 206 that.updateCoordinate( latLng ); 207 }, 'json' ); 208 }, 209 210 // Get the address field. 211 getAddressField: function() { 212 // No address field or more than 1 address fields, ignore 213 if ( ! this.addressField || this.addressField.split( ',' ).length > 1 ) { 214 return null; 215 } 216 return this.findAddressField( this.addressField ); 217 }, 218 219 // Get the address value for geocoding. 220 getAddress: function() { 221 var that = this; 222 223 return this.addressField.split( ',' ) 224 .map( function( part ) { 225 part = that.findAddressField( part ); 226 return null === part ? '' : part.val(); 227 } ) 228 .join( ',' ).replace( /\n/g, ',' ).replace( /,,/g, ',' ); 229 }, 230 231 // Find address field based on its name attribute. Auto search inside groups when needed. 232 findAddressField: function( fieldName ) { 233 // Not in a group. 234 var $address = $( 'input[name="' + fieldName + '"]'); 235 if ( $address.length ) { 236 return $address; 237 } 238 239 // If map and address is inside a cloneable group. 240 $address = this.$container.closest( '.rwmb-group-clone' ).find( 'input[name*="[' + fieldName + ']"]' ); 241 if ( $address.length ) { 242 return $address; 243 } 244 245 // If map and address is inside a non-cloneable group. 246 $address = this.$container.closest( '.rwmb-group-wrapper' ).find( 'input[name*="[' + fieldName + ']"]' ); 247 if ( $address.length ) { 248 return $address; 249 } 250 251 return null; 252 } 253 }; 254 255 function createController() { 256 var $this = $( this ), 257 controller = $this.data( 'osmController' ); 258 if ( controller ) { 259 return; 260 } 261 262 controller = new OsmField( $this ); 263 controller.init(); 264 $this.data( 'osmController', controller ); 265 } 266 267 function init( e ) { 268 $( e.target ).find( '.rwmb-osm-field' ).each( createController ); 269 } 270 271 function restart() { 272 $( '.rwmb-osm-field' ).each( createController ); 273 } 274 275 rwmb.$document 276 .on( 'mb_ready', init ) 277 .on( 'clone', '.rwmb-input', restart ); 278 } )( jQuery, L, rwmb, RWMB_Osm );