+(function ( $, window) {
var pluginName = "placepicker";
var defaults = {
map: "",
mapOptions: {
zoom: 15
},
places: {
icons: false
},
autoCompleteOptions: {
},
// callbacks
placeChanged: null,
location: null,
preventSubmit: true
};
function PlacePicker(element, options) {
var instance = this;
var geocoder = null;
var mapElement, map, marker;
var service = null;
var autocomplete;
// stores the current place
var _place = null;
var _latLng = null;
/**
* Generates a piece of HTML that is used to replace the input element
* with one that also contains a globe button.
*/
function template() {
var templateString =
"
" +
"" +
"" +
"" +
"
";
return templateString;
}
/**
* Modifies the DOM to add a globe button that hides and shows a map
* element.
*/
function initDomElements() {
if (!options.mapContainerId) {
return;
}
// Find the index of our element under its parent
var $element = $(element);
var $parent = $element.parent();
var index = $parent.children().index(element);
// Replace the element with our template code
$element.replaceWith(template());
// Then inject back in the existing element. This retains all
// attributes on the element.
$parent.children().eq(index).append(element);
}
function codePlace(query) {
if (!query) {
return;
}
var request = {
query: query
};
if (service) {
service.textSearch(request, function (results, status) {
if (status === google.maps.places.PlacesServiceStatus.OK) {
for (var i = 0; i < results.length; i++) {
setPlace(results[i]);
return;
}
}
});
}
}
function codeLatLng(latlng) {
geocoder.geocode({"latLng": latlng}, function(results, status) {
if (status === google.maps.GeocoderStatus.OK) {
if (results[0]) {
var place = results[0];
setPlace(place, false);
} else {
// alert("No results found");
}
} else {
// alert("Geocoder failed due to: " + status);
}
});
}
/**
* Find and store the DOM element that holds the Google Map.
* @return a boolean indicating whether an element was successfully
* set.
*/
function setMapElement() {
mapElement = $(options.map).get(0);
if (!mapElement) {
if (options.mapContainerId) {
mapElement = $("#" + options.mapContainerId + " .placepicker-map").get(0);
}
}
return mapElement ? true : false;
}
function initMap() {
if (!setMapElement()) {
return;
}
map = new google.maps.Map(mapElement, options.mapOptions);
autocomplete.bindTo("bounds", map);
google.maps.event.addListener(map, "click", function(e) {
var pos = e.latLng;
marker.setPosition(pos);
map.panTo(pos);
element.blur();
codeLatLng(pos);
});
marker = new google.maps.Marker({
map: map
});
service = new google.maps.places.PlacesService(map);
// When the map is made visible, if we have no location set then
// attempt geolocation. The css() calls ensure that the map is
// refreshed.
$(mapElement).parent().on("show.bs.collapse", function(e) {
$(e.target)
.css("display", "block")
// Fix map icons
.find('img[src*="gstatic.com/"], img[src*="googleapis.com/"]').css('max-width', 'none');
if (!element.value) {
instance.geoLocation();
} else {
instance.resize();
}
$(e.target).css("display", "");
});
}
function initAutoComplete() {
autocomplete = new google.maps.places.Autocomplete(element, options.autoCompleteOptions);
google.maps.event.addListener(autocomplete, "place_changed", function() {
var place = autocomplete.getPlace();
if (place.geometry) {
setPlace(place);
}
});
}
function resizeHandler() {
instance.resize.call(instance);
}
function init() {
geocoder = new google.maps.Geocoder();
initDomElements();
initAutoComplete();
initMap();
if (!element.value) {
var lat = options.latitude || $(options.latitudeInput).prop("value");
var lng = options.longitude || $(options.longitudeInput).prop("value");
if (lat && lng) {
instance.setLocation(lat, lng);
}
} else {
codePlace(element.value);
}
$(window).on("resize", resizeHandler);
$(element).on("keypress", function(e) {
if (options.preventSubmit && e.keyCode === 13) {
e.preventDefault();
e.stopImmediatePropagation();
}
});
}
function setPlace(place, updateMap) {
updateMap = typeof updateMap === "undefined" ? true : false;
_place = place;
instance.resize();
var pos = place.geometry.location;
if (updateMap) {
updatePosition(pos);
}
$(options.latitudeInput).prop("value", pos.lat());
$(options.longitudeInput).prop("value", pos.lng());
// update inputs
if (!updateMap) {
element.value = place.formatted_address;
}
if (typeof options.placeChanged === "function") {
options.placeChanged.call(instance, place);
}
}
function updatePosition(pos) {
if (!map) {
return;
}
map.setCenter(pos);
var icon = options.icon || options.placesIcon && place.icon ? place.icon : null;
if (icon) {
var iconOptions = {
url: icon,
size: new google.maps.Size(71, 71),
origin: new google.maps.Point(0, 0),
anchor: new google.maps.Point(17, 34),
scaledSize: new google.maps.Size(35, 35)
};
marker.setIcon(iconOptions);
}
marker.setPosition(pos);
marker.setVisible(true);
}
this.setValue = function(value) {
element.value = value;
codePlace(value);
};
this.getValue = function() {
return element.value;
};
this.setLocation = function(latitude, longitude) {
var latLng = new google.maps.LatLng(latitude, longitude);
this.setLatLng(latLng);
};
this.getLocation = function() {
var latLng = this.getLatLng();
return {
latitude: latLng && latLng.lat() || options.latitude,
longitude: latLng && latLng.lng() || options.longitude
};
};
this.setLatLng = function(latLng) {
_latLng = latLng;
codeLatLng(_latLng);
};
this.getLatLng = function() {
if (_place && _place.geometry) {
return _place.geometry.location;
}
return _latLng;
};
this.getMap = function() {
return map;
};
this.reload = function() {
if (map) {
codePlace(element.value);
}
};
this.resize = function() {
if (map) {
var center = map.getCenter();
google.maps.event.trigger(map, "resize");
map.setCenter(center);
}
};
this.geoLocation = function(callback) {
// Try HTML5 geolocation
if(navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
var pos = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
updatePosition(pos);
codeLatLng(pos);
if (callback) {
callback(pos);
}
}, function() {
// error
if (callback) {
callback(null);
}
});
} else {
// Browser doesn't support Geolocation
if (callback) {
callback(null);
}
}
};
init.call(this);
}
var pluginClass = PlacePicker;
// register plugin
$.fn[pluginName] = function(options) {
return this.each(function() {
if (!$(this).data(pluginName)) {
$(this).data(pluginName, new pluginClass(this, $.extend({}, defaults, options, $(this).data())));
}
return $(this);
});
};
})( jQuery, window );