1(function ( $ ) { 2 3 /** 4 * Holds google map object and related utility entities. 5 * @constructor 6 */ 7 function GMapContext(domElement, options) { 8 var _map = new google.maps.Map(domElement, options); 9 var _marker = new google.maps.Marker({ 10 position: new google.maps.LatLng(54.19335, -3.92695), 11 map: _map, 12 title: "Drag Me", 13 visible: options.markerVisible, 14 draggable: options.markerDraggable, 15 icon: (options.markerIcon !== undefined) ? options.markerIcon : undefined 16 }); 17 return { 18 map: _map, 19 marker: _marker, 20 circle: null, 21 location: _marker.position, 22 radius: options.radius, 23 locationName: options.locationName, 24 addressComponents: { 25 formatted_address: null, 26 addressLine1: null, 27 addressLine2: null, 28 streetName: null, 29 streetNumber: null, 30 city: null, 31 district: null, 32 state: null, 33 stateOrProvince: null 34 }, 35 settings: options.settings, 36 domContainer: domElement, 37 geodecoder: new google.maps.Geocoder() 38 } 39 } 40 41 // Utility functions for Google Map Manipulations 42 var GmUtility = { 43 /** 44 * Draw a circle over the the map. Returns circle object. 45 * Also writes new circle object in gmapContext. 46 * 47 * @param center - LatLng of the center of the circle 48 * @param radius - radius in meters 49 * @param gmapContext - context 50 * @param options 51 */ 52 drawCircle: function(gmapContext, center, radius, options) { 53 if (gmapContext.circle != null) { 54 gmapContext.circle.setMap(null); 55 } 56 if (radius > 0) { 57 radius *= 1; 58 options = $.extend({ 59 strokeColor: "#0000FF", 60 strokeOpacity: 0.35, 61 strokeWeight: 2, 62 fillColor: "#0000FF", 63 fillOpacity: 0.20 64 }, options); 65 options.map = gmapContext.map; 66 options.radius = radius; 67 options.center = center; 68 gmapContext.circle = new google.maps.Circle(options); 69 return gmapContext.circle; 70 } 71 return null; 72 }, 73 /** 74 * 75 * @param gMapContext 76 * @param location 77 * @param callback 78 */ 79 setPosition: function(gMapContext, location, callback) { 80 gMapContext.location = location; 81 gMapContext.marker.setPosition(location); 82 gMapContext.map.panTo(location); 83 this.drawCircle(gMapContext, location, gMapContext.radius, {}); 84 if (gMapContext.settings.enableReverseGeocode) { 85 this.updateLocationName(gMapContext, callback); 86 } else { 87 if (callback) { 88 callback.call(this, gMapContext); 89 } 90 } 91 92 }, 93 locationFromLatLng: function(lnlg) { 94 return {latitude: lnlg.lat(), longitude: lnlg.lng()} 95 }, 96 addressByFormat: function (addresses, format) { 97 var result = null; 98 for(var i = addresses.length - 1; i >= 0; i--){ 99 if(addresses[i].types.indexOf(format) >= 0){ 100 result = addresses[i]; 101 } 102 } 103 return result || addresses[0]; 104 }, 105 updateLocationName: function(gmapContext, callback) { 106 gmapContext.geodecoder.geocode({ 107 latLng: gmapContext.marker.position 108 }, function(results, status) { 109 if (status == google.maps.GeocoderStatus.OK && results.length > 0) { 110 var address = GmUtility.addressByFormat(results, gmapContext.settings.addressFormat); 111 gmapContext.locationName = address.formatted_address; 112 gmapContext.addressComponents = GmUtility.address_component_from_google_geocode(address.address_components); 113 }else if (status == google.maps.GeocoderStatus.OVER_QUERY_LIMIT) { 114 return setTimeout(function () { 115 GmUtility.updateLocationName(gmapContext, callback); 116 }, 1000); 117 } 118 if (callback) { 119 callback.call(this, gmapContext); 120 } 121 }); 122 }, 123 address_component_from_google_geocode: function(address_components) { 124 var result = {}; 125 for (var i = address_components.length-1; i>=0; i--) { 126 var component = address_components[i]; 127 // Postal code 128 if (component.types.indexOf('postal_code') >= 0) { 129 result.postalCode = component.short_name; 130 } 131 // Street number 132 else if (component.types.indexOf('street_number') >= 0) { 133 result.streetNumber = component.short_name; 134 } 135 // Street name 136 else if (component.types.indexOf('route') >= 0) { 137 result.streetName = component.short_name; 138 } 139 // City 140 else if (component.types.indexOf('locality') >= 0) { 141 result.city = component.short_name; 142 } 143 // District 144 else if (component.types.indexOf('sublocality') >= 0) { 145 result.district = component.short_name; 146 } 147 // State \ Province 148 else if (component.types.indexOf('administrative_area_level_1') >= 0) { 149 result.stateOrProvince = component.short_name; 150 } 151 // State \ Province 152 else if (component.types.indexOf('country') >= 0) { 153 result.country = component.short_name; 154 } 155 } 156 result.addressLine1 = [result.streetNumber, result.streetName].join(' ').trim(); 157 result.addressLine2 = ''; 158 return result; 159 } 160 }; 161 162 function isPluginApplied(domObj) { 163 return getContextForElement(domObj) != undefined; 164 } 165 166 function getContextForElement(domObj) { 167 return $(domObj).data("locationpicker"); 168 } 169 170 function updateInputValues(inputBinding, gmapContext){ 171 if (!inputBinding) return; 172 var currentLocation = GmUtility.locationFromLatLng(gmapContext.marker.position); 173 if (inputBinding.latitudeInput) { 174 inputBinding.latitudeInput.val(currentLocation.latitude).change(); 175 } 176 if (inputBinding.longitudeInput) { 177 inputBinding.longitudeInput.val(currentLocation.longitude).change(); 178 } 179 if (inputBinding.radiusInput) { 180 inputBinding.radiusInput.val(gmapContext.radius).change(); 181 } 182 if (inputBinding.locationNameInput) { 183 // inputBinding.locationNameInput.val(gmapContext.locationName).change(); 184 } 185 } 186 187 function setupInputListenersInput(inputBinding, gmapContext) { 188 if (inputBinding) { 189 if (inputBinding.radiusInput){ 190 inputBinding.radiusInput.on("change", function(e) { 191 var radiusInputValue = $(this).val(); 192 if (!e.originalEvent || isNaN(radiusInputValue)) { return }
193 gmapContext.radius = radiusInputValue; 194 GmUtility.setPosition(gmapContext, gmapContext.location, function(context){ 195 context.settings.onchanged.apply(gmapContext.domContainer, 196 [GmUtility.locationFromLatLng(context.location), context.radius, false]); 197 }); 198 }); 199 } 200 if (inputBinding.locationNameInput && gmapContext.settings.enableAutocomplete) { 201 var blur = false; 202 gmapContext.autocomplete = new google.maps.places.Autocomplete(inputBinding.locationNameInput.get(0), gmapContext.settings.autocompleteOptions); 203 google.maps.event.addListener(gmapContext.autocomplete, 'place_changed', function() { 204 blur = false; 205 var place = gmapContext.autocomplete.getPlace(); 206 if (!place.geometry) { 207 gmapContext.settings.onlocationnotfound(place.name); 208 return; 209 } 210 GmUtility.setPosition(gmapContext, place.geometry.location, function(context) { 211 updateInputValues(inputBinding, context); 212 context.settings.onchanged.apply(gmapContext.domContainer, 213 [GmUtility.locationFromLatLng(context.location), context.radius, false]); 214 }); 215 }); 216 if(gmapContext.settings.enableAutocompleteBlur) { 217 inputBinding.locationNameInput.on("change", function(e) { 218 if (!e.originalEvent) { return } 219 blur = true; 220 }); 221 inputBinding.locationNameInput.on("blur", function(e) { 222 if (!e.originalEvent) { return } 223 setTimeout(function() { 224 var address = $(inputBinding.locationNameInput).val(); 225 if (address.length > 5 && blur) { 226 blur = false; 227 gmapContext.geodecoder.geocode({'address': address}, function(results, status) { 228 if(status == google.maps.GeocoderStatus.OK && results && results.length) { 229 GmUtility.setPosition(gmapContext, results[0].geometry.location, function(context) { 230 updateInputValues(inputBinding, context); 231 context.settings.onchanged.apply(gmapContext.domContainer, 232 [GmUtility.locationFromLatLng(context.location), context.radius, false]); 233 }); 234 } 235 }); 236 } 237 }, 1000); 238 }); 239 } 240 } 241 if (inputBinding.latitudeInput) { 242 inputBinding.latitudeInput.on("change", function(e) { 243 var latitudeInputValue = $(this).val(); 244 if (!e.originalEvent || isNaN(latitudeInputValue) ) { return } 245 GmUtility.setPosition(gmapContext, new google.maps.LatLng(latitudeInputValue, gmapContext.location.lng()), function(context){ context.settings.onchanged.apply(gmapContext.domContainer, 246 [GmUtility.locationFromLatLng(context.location), context.radius, false]); 247 updateInputValues(gmapContext.settings.inputBinding, gmapContext); 248 }); 249 }); 250 } 251 if (inputBinding.longitudeInput) { 252 inputBinding.longitudeInput.on("change", function(e) { 253 var longitudeInputValue = $(this).val(); 254 if (!e.originalEvent || isNaN(longitudeInputValue) ) { return } 255 GmUtility.setPosition(gmapContext, new google.maps.LatLng(gmapContext.location.lat(), longitudeInputValue), function(context){ 256 context.settings.onchanged.apply(gmapContext.domContainer, 257 [GmUtility.locationFromLatLng(context.location), context.radius, false]); 258 updateInputValues(gmapContext.settings.inputBinding, gmapContext); 259 }); 260 }); 261 } 262 } 263 } 264 265 function autosize(gmapContext) { 266 google.maps.event.trigger(gmapContext.map, 'resize'); 267 setTimeout(function() { 268 gmapContext.map.setCenter(gmapContext.marker.position); 269 }, 300); 270 } 271 272 function updateMap(gmapContext, $target, options) { 273 var settings = $.extend({}, $.fn.locationpicker.defaults, options ), 274 latNew = settings.location.latitude, 275 lngNew = settings.location.longitude, 276 radiusNew = settings.radius, 277 latOld = gmapContext.settings.location.latitude, 278 lngOld = gmapContext.settings.location.longitude, 279 radiusOld = gmapContext.settings.radius; 280 281 if (latNew == latOld && lngNew == lngOld && radiusNew == radiusOld) 282 return; 283 284 gmapContext.settings.location.latitude = latNew; 285 gmapContext.settings.location.longitude = lngNew;
286 gmapContext.radius = radiusNew; 287 288 GmUtility.setPosition(gmapContext, new google.maps.LatLng(gmapContext.settings.location.latitude, gmapContext.settings.location.longitude), function(context){ 289 setupInputListenersInput(gmapContext.settings.inputBinding, gmapContext); 290 context.settings.oninitialized($target); 291 }); 292 } 293 /** 294 * Initializeialization: 295 * $("#myMap").locationpicker(options); 296 * @param options 297 * @param params 298 * @returns {*} 299 */ 300 $.fn.locationpicker = function( options, params ) { 301 if (typeof options == 'string') { // Command provided 302 var _targetDomElement = this.get(0); 303 // Plug-in is not applied - nothing to do. 304 if (!isPluginApplied(_targetDomElement)) return; 305 var gmapContext = getContextForElement(_targetDomElement); 306 switch (options) { 307 case "location": 308 if (params == undefined) { // Getter 309 var location = GmUtility.locationFromLatLng(gmapContext.location); 310 location.radius = gmapContext.radius; 311 location.name = gmapContext.locationName; 312 return location; 313 } else { // Setter 314 if (params.radius) { 315 gmapContext.radius = params.radius; 316 } 317 GmUtility.setPosition(gmapContext, new google.maps.LatLng(params.latitude, params.longitude), function(gmapContext) { 318 updateInputValues(gmapContext.settings.inputBinding, gmapContext); 319 }); 320 } 321 break; 322 case "subscribe": 323 /** 324 * Provides interface for subscribing for GoogleMap events. 325 * See Google API documentation for details. 326 * Parameters: 327 * - event: string, name of the event 328 * - callback: function, callback function to be invoked 329 */ 330 if (params == undefined) { // Getter is not available 331 return null; 332 } else { 333 var event = params.event; 334 var callback = params.callback; 335 if (!event || ! callback) { 336 console.error("LocationPicker: Invalid arguments for method \"subscribe\"") 337 return null; 338 } 339 google.maps.event.addListener(gmapContext.map, event, callback); 340 } 341 break; 342 case "map": 343 /** 344 * Returns object which allows access actual google widget and marker paced on it. 345 * Structure: { 346 * map: Instance of the google map widget 347 * marker: marker placed on map 348 * } 349 */ 350 if (params == undefined) { // Getter 351 var locationObj = GmUtility.locationFromLatLng(gmapContext.location); 352 locationObj.formattedAddress = gmapContext.locationName; 353 locationObj.addressComponents = gmapContext.addressComponents; 354 return { 355 map: gmapContext.map, 356 marker: gmapContext.marker, 357 location: locationObj 358 } 359 } else { // Setter is not available 360 return null; 361 } 362 case "autosize": 363 autosize(gmapContext); 364 return this; 365 } 366 return null; 367 } 368 return this.each(function() { 369 var $target = $(this); 370 // If plug-in hasn't been applied before - initialize, otherwise - skip 371 if (isPluginApplied(this)){ 372 updateMap(getContextForElement(this), $(this), options); 373 return; 374 } 375 // Plug-in initialization is required 376 // Defaults 377 var settings = $.extend({}, $.fn.locationpicker.defaults, options ); 378 // Initialize 379 var gmapContext = new GMapContext(this, $.extend({}, { 380 zoom: settings.zoom, 381 center: new google.maps.LatLng(settings.location.latitude, settings.location.longitude), 382 mapTypeId: settings.mapTypeId, 383 mapTypeControl: false, 384 styles: settings.styles, 385 disableDoubleClickZoom: false, 386 scrollwheel: settings.scrollwheel, 387 streetViewControl: false, 388 radius: settings.radius, 389 locationName: settings.locationName, 390 settings: settings, 391 autocompleteOptions : settings.autocompleteOptions, 392 addressFormat: settings.addressFormat, 393 draggable: settings.draggable, 394 markerIcon: settings.markerIcon, 395 markerDraggable: settings.markerDraggable, 396 markerVisible: settings.markerVisible 397 }, settings.mapOptions)); 398 $target.data("locationpicker", gmapContext); 399 // Subscribe GMap events 400 function displayMarkerWithSelectedArea() { 401 GmUtility.setPosition(gmapContext, gmapContext.marker.position, function (context) { 402 var currentLocation = GmUtility.locationFromLatLng(gmapContext.location); 403 updateInputValues(gmapContext.settings.inputBinding, gmapContext); 404 context.settings.onchanged.apply(gmapContext.domContainer, [currentLocation, context.radius, true]); 405 }); 406 } 407 if (settings.markerInCenter) { 408 gmapContext.map.addListener("bounds_changed", function () { 409 if (!gmapContext.marker.dragging) { 410 gmapContext.marker.setPosition(gmapContext.map.center); 411 updateInputValues(gmapContext.settings.inputBinding, gmapContext); 412 } 413 }); 414 gmapContext.map.addListener("idle", function () { 415 if (!gmapContext.marker.dragging) { 416 displayMarkerWithSelectedArea(); 417 } 418 }); 419 } 420 google.maps.event.addListener(gmapContext.marker, "drag", function(event) { 421 updateInputValues(gmapContext.settings.inputBinding, gmapContext); 422 }); 423 google.maps.event.addListener(gmapContext.marker, "dragend", function(event) { 424 displayMarkerWithSelectedArea(); 425 }); 426 GmUtility.setPosition(gmapContext, new google.maps.LatLng(settings.location.latitude, settings.location.longitude), function(context){ 427 updateInputValues(settings.inputBinding, gmapContext); 428 // Set input bindings if needed 429 setupInputListenersInput(settings.inputBinding, gmapContext); 430 context.settings.oninitialized($target); 431 }); 432 }); 433 }; 434 $.fn.locationpicker.defaults = { 435 location: {latitude: 40.7324319, longitude: -73.82480777777776}, 436 locationName: "", 437 radius: 500, 438 zoom: 15, 439 mapTypeId: google.maps.MapTypeId.ROADMAP, 440 styles: [], 441 mapOptions: {}, 442 scrollwheel: true, 443 inputBinding: { 444 latitudeInput: null, 445 longitudeInput: null, 446 radiusInput: null, 447 locationNameInput: null 448 }, 449 enableAutocomplete: false, 450 enableAutocompleteBlur: false, 451 autocompleteOptions: null, 452 addressFormat: 'postal_code', 453 enableReverseGeocode: true, 454 draggable: true, 455 onchanged: function(currentLocation, radius, isMarkerDropped) {}, 456 onlocationnotfound: function(locationName) {}, 457 oninitialized: function (component) {}, 458 // must be undefined to use the default gMaps marker 459 markerIcon: undefined, 460 markerDraggable: true, 461 markerVisible : true 462 } 463}( 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.