1/** 2 * UpSolution Element: Google Maps 3 * 4 * Used for [us_gmaps] shortcode 5 * @requires jQuery 6 */ 7! function( $, undefined ) { 8 "use strict"; 9 10 // Private variables that are used only in the context of this function, it is necessary to optimize the code 11 var _document = document, 12 _window = window, 13 _null = null; 14 15 // Check for is set objects 16 _window.$us = _window.$us || {}; 17 18 /** 19 * @type {RegExp} Regular expression to check or extract coordinates. 20 */ 21 const _REGEXP_EXTRACT_COORDINATES_ = /^(-?[\d\.]+),(-?[\d\.]+)$/; 22 23 /** 24 * @var {Function} The handler is called when Maps API is ready to use 25 */ 26 _window.usGmapLoaded = function() { 27 $us.$document.trigger( 'usGmapLoaded' ); 28 }; 29 30 /** 31 * @var {{}} 32 */ 33 $us._wGmapsGeocodes = { 34 _maxAttempts: 5, // maximum number of attempts 35 _tasks: {}, // task stack 36 37 /** 38 * Add a new task 39 * 40 * @param {String} key The unique key 41 * @param {Function} callback The callback 42 * @return {Function} self.run() 43 */ 44 add: function( key, callback ) { 45 var self = this; 46 self._tasks[ '' + key ] = { 47 counter: 0, 48 running: false, 49 callback: callback, 50 }; 51 return self.run.bind( self, key ); 52 }, 53 54 /** 55 * Remove task by key 56 * 57 * @param {String} key The unique key 58 */ 59 remove: function( key ) { 60 var self = this; 61 if ( self._tasks[ key ] ) { 62 delete self._tasks[ key ]; 63 } 64 }, 65 66 /** 67 * Run a task from the stack by key 68 * 69 * @param {String} key The unique key 70 */ 71 run: function( key ) { 72 var self = this, task = self._tasks[ key ]; 73 if ( $ush.isUndefined( task ) || task.running ) { 74 return; 75 } 76 if ( task.counter >= self._maxAttempts ) { 77 self.remove( key ); 78 } 79 if ( typeof task.callback === 'function' ) { 80 task.counter++; 81 task.running = true; 82 task.callback( /* stopGeocodeTask */function() { 83 task.running = false; 84 } ); 85 } 86 } 87 }; 88 89 /** 90 * @class wGmaps 91 * @param {Node} container The node container 92 * @param {{}} options The map options 93 */ 94 $us.wGmaps = function ( container, options ) { 95 var self = this; 96 97 // Elements 98 self.$container = $( container ); 99 100 // Prevent double init 101 if ( self.$container.data( '_inited' ) ) { 102 return; 103 } 104 self.$container.data( '_inited', 1 ); 105 106 // Variables 107 self._mapInstance = _null; // An instance of the Google Maps object 108 self.cookieName = self.$container.data( 'cookie-name' ); // The cookie name to save the load consent 109 self.options = options || {}; // Main options of the element 110 self.style = {}; // Setting styles derived from the frontend 111 self.uniqid = $ush.uniqid(); // Unique element id 112 113 // Get a key to connect to the Google API 114 var attributeName = 'data-api-key'; 115 if ( self.$container.is( '[' + attributeName + ']' ) ) { 116 self._apiKey = self.$container.attr( attributeName ); 117 self.$container.removeAttr( attributeName ); 118 } 119 120 /** 121 * @var {{}} Bindable events 122 */ 123 self._events = { 124 confirm: self._confirm.bind( self ), 125 redraw: self._redraw.bind( self ), 126 init: self._init.bind( self ), 127 }; 128 129 // Events 130 $us.$document 131 // The handler is called when Maps API is ready to use 132 .on( 'usGmapLoaded', self._events.init ); 133 134 // Initialization via confirmations 135 if ( self.cookieName ) { 136 self.$container.on( 'click', '.action_confirm_load', self._events.confirm ); 137 return; 138 } 139 140 // Init the map 141 if ( ! self.cookieName || $ush.getCookie( self.cookieName ) ) { 142 self[ self.isGmapLoaded() ? '_init' : '_initAftetGmapLoaded' ](); // Init map 143 }; 144 }; 145 146 /** 147 * Export API 148 */ 149 $.extend( $us.wGmaps.prototype, { 150 151 /** 152 * Determines if gmap loaded 153 * 154 * @return {Boolean} True if Maps API loaded, False otherwise 155 */ 156 isGmapLoaded: function() { 157 return !! ( _window['google'] || {} )['maps']; 158 }, 159 160 /** 161 * Map initialization handler after confirmation 162 * 163 * @event handler 164 */ 165 _confirm: function() { 166 var self = this; 167 168 // Save permission to loading maps in cookies 169 if ( $( 'input[name^=' + self.cookieName + ']:checked', self.$container ).length ) { 170 $ush.setCookie( self.cookieName, /* value */1, /* days */365 ); 171 } 172 173 self.$container 174 // Add map html markup to element 175 .html( $ush.base64Decode( '' + $( 'script[type="text/template"]', self.$container ).text() ) ) 176 .removeAttr( 'data-cookie-name' ); 177 178 // Init the map 179 self[ self.isGmapLoaded() ? '_init' : '_initAftetGmapLoaded' ](); 180 }, 181 182 /** 183 * Init the map 184 * 185 * @event handler 186 * @link https://developers.google.com/maps/documentation/javascript/overview 187 */ 188 _init: function() { 189 var self = this; 190 191 if ( 192 // If there is an attribute, stop initialization because it is not a validated map 193 self.$container.is( '[data-cookie-name]' ) 194 // If the google.maps object is not loaded, stop the initialization 195 || ! self.isGmapLoaded() 196 ) { 197 return; 198 } 199 200 // Get map options 201 var $mapJson = $( '.w-map-json', self.$container ); 202 if ( $mapJson.is( '[onclick]' ) ) { 203 $.extend( self.options, $mapJson[0].onclick() || {} ); 204 $mapJson.remove(); 205 } 206 207 // Get style options 208 var $styleJson = $( '.w-map-style-json', self.$container ); 209 if ( $styleJson.is( '[onclick]' ) ) { 210 self.style = $styleJson[0].onclick() || []; 211 $styleJson.remove(); 212 } 213 214 /** 215 * @var {{}} Map options 216 */ 217 var mapOptions = { 218 el: '#' + self.$container.attr( 'id' ), 219 lat: 0, 220 lng: 0, 221 mapTypeId: google.maps.MapTypeId[ self.options.maptype ], 222 type: self.options.type, 223 zoom: self.options.zoom 224 }; 225 226 if ( self.options.hideControls ) { 227 mapOptions.disableDefaultUI = true; 228 } 229 if ( self.options.disableZoom ) { 230 mapOptions.scrollwheel = false; 231 } 232 if ( self.options.disableDragging && ( ! $us.$html.hasClass( 'no-touch' ) ) ) { 233 mapOptions.draggable = false; 234 } 235 236 // Create an instance of the GMaps class 237 self._mapInstance = new GMaps( mapOptions ); 238 239 // Set map style 240 if ( self.style != _null && Array.isArray( self.style ) ) { 241 self._mapInstance.map.setOptions( { styles: self.style } ); 242 } 243 244 var shouldRunGeoCode, 245 matches = $ush.removeSpaces( '' + self.options.address ) // Remove all spaces and tabs 246 .match( _REGEXP_EXTRACT_COORDINATES_ ); // Example: -0.00000,0.00000 247 248 if ( matches ) { 249 self.options.latitude = matches[/* latitude */1]; 250 self.options.longitude = matches[/* longitude */2]; 251 $ush.timeout( function() { 252 self._mapInstance.setCenter( self.options.latitude, self.options.longitude ); 253 }, 1 ); 254 } else { 255 // Get the address coordinates through the reverse call function 256 $us._wGmapsGeocodes.add( self.uniqid, function( stopGeocodeTask ) { 257 self._mapGeoCode( 258 self.uniqid, 259 self.options.address, 260 function( latitude, longitude ) { 261 self.options.latitude = latitude; 262 self.options.longitude = longitude; 263 self._mapInstance.setCenter( latitude, longitude ); 264 if ( typeof stopGeocodeTask === 'function' ) { 265 stopGeocodeTask(); 266 } 267 }, 268 self.uniqid 269 ) 270 } )/* run */(); 271 } 272 273 // Map Markers 274 $.each( self.options.markers, function( i, _ ) { 275 var markerOptions = {}; 276 if ( self.options.icon != _null || self.options.markers[ i ].marker_img != _null ) { 277 var url, width, height; 278 if ( self.options.markers[ i ].marker_img != _null ) { 279 url = self.options.markers[ i ].marker_img[0]; 280 width = self.options.markers[ i ].marker_size[/* width */0]; 281 height = self.options.markers[ i ].marker_size[/* height */1]; 282 } else { 283 url = self.options.icon.url; 284 width = self.options.icon.size[/* width */0]; 285 height = self.options.icon.size[/* height */1]; 286 } 287 var size = new google.maps.Size( 288 $ush.parseInt( width ), 289 $ush.parseInt( height ) 290 ); 291 markerOptions.icon = { 292 url: url, 293 size: size, 294 scaledSize: size, 295 }; 296 } 297 298 if ( self.options.markers[ i ] != _null ) { 299 var matches = $ush.removeSpaces( self.options.markers[ i ].address ) // Remove all spaces and tabs 300 .match( _REGEXP_EXTRACT_COORDINATES_ ); 301 if ( matches ) { 302 markerOptions.lat = matches[/* latitude */1]; 303 markerOptions.lng = matches[/* longitude */2];
304 // Do not output empty tooltips 305 if ( self.options.markers[ i ].html ) { 306 markerOptions.infoWindow = { content: self.options.markers[ i ].html }; 307 } 308 var marker = self._mapInstance.addMarker( markerOptions ); 309 if ( self.options.markers[ i ].infowindow ) { 310 marker.infoWindow.open( self._mapInstance.map, marker ); 311 } 312 } else { 313 var markerGeocodeId = self.uniqid + ':' + i; // the unique marker id 314 // Get the address coordinates through the reverse call function 315 $us._wGmapsGeocodes.add( markerGeocodeId, function( stopGeocodeTask ) { 316 self._mapGeoCode( 317 markerGeocodeId, 318 self.options.markers[i].address, 319 function( latitude, longitude ) { 320 markerOptions.lat = latitude; 321 markerOptions.lng = longitude; 322 if ( self.options.markers[ i ].html ) { 323 markerOptions.infoWindow = { content: self.options.markers[ i ].html }; 324 } 325 var marker = self._mapInstance.addMarker( markerOptions ); 326 if ( self.options.markers[ i ].infowindow ) { 327 marker.infoWindow.open( $ush.clone( self._mapInstance.map, /* default */{ shouldFocus: false } ), marker ); 328 } 329 if ( typeof stopGeocodeTask === 'function' ) { 330 stopGeocodeTask(); 331 } 332 } 333 ); 334 } )/* run */(); 335 } 336 } 337 }); 338 339 $us.$canvas.on( 'contentChange', self._events.redraw ); 340 341 // Note: In case some toggler was opened before the actual page load 342 $us.$window.on( 'load', self._events.redraw ); 343 }, 344 345 /** 346 * Get the address coordinates through the reverse call function 347 * 348 * @param {String} uniqid The unique iteration id 349 * @param {String} address The address 350 * @param {Function} callback The callback 351 * 352 * @link https://developers.google.com/maps/documentation/javascript/geocoding 353 */ 354 _mapGeoCode: function( uniqid, address, callback ) { 355 var self = this; 356 GMaps.geocode( { 357 address: address, 358 callback: function( results, status ) { 359 if ( status == 'OK' ) { 360 var location = results[0].geometry.location; 361 if ( typeof callback === 'function' ) { 362 callback.call( _null, location.lat(), location.lng(), results ); 363 } 364 $us._wGmapsGeocodes.remove( uniqid ); 365 } else if ( status == 'OVER_QUERY_LIMIT' ) { 366 $ush.timeout( $us._wGmapsGeocodes.bind( _null, uniqid ), 2000 ); 367 } 368 } 369 } ); 370 }, 371 372 /** 373 * Map redraw 374 * Note: Fixing hidden and other breaking-cases maps 375 * 376 * @event handler 377 */ 378 _redraw: function() { 379 var self = this; 380 if ( self.$container.is( ':hidden' ) ) { 381 return; 382 } 383 self.$container.css( { height: '', width: '' } ); 384 self._mapInstance.refresh(); 385 var latitude = $ush.parseFloat( self.options.latitude ), 386 longitude = $ush.parseFloat( self.options.longitude ); 387 if ( latitude && longitude ) { 388 self._mapInstance.setCenter( latitude, longitude ); 389 } 390 }, 391 392 /** 393 * Initializes the Maps API load, which calls `self._init()` 394 */ 395 _initAftetGmapLoaded: function() { 396 var $script = $( 'script#us-google-maps:first' ); 397 if ( ! $script.is( '[data-src]' ) ) { // Check if there is a data-src to the script 398 return; 399 } 400 $script 401 .attr( 'src', ( '' + $script.data( 'src' ) ).replace( '&', '&' ) ) 402 .removeAttr( 'data-src' ); 403 } 404 } ); 405 406 /** 407 * Wrapper for jQuery 408 * 409 * @param {{}} options The map options 410 * @return self 411 */ 412 $.fn.wGmaps = function( options ) { 413 options = options || {}; 414 return this.each( function() { 415 this._wGmaps = new $us.wGmaps( this, $ush.clone( options ) ); 416 } ); 417 }; 418 419 // Initializing an element after loading a document 420 $( function() { 421 $( '.w-map.provider_google' ).wGmaps(); 422 } ); 423 424}( jQuery );
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.