autocomplete_addresspicker.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /*
  2. * jQuery UI addresspicker @VERSION
  3. *
  4. * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
  5. * Dual licensed under the MIT or GPL Version 2 licenses.
  6. * http://jquery.org/license
  7. *
  8. * Depends:
  9. * jquery.ui.core.js
  10. * jquery.ui.widget.js
  11. * jquery.ui.autocomplete.js
  12. */
  13. (function( $, undefined ) {
  14. $.widget( "ui.addresspicker", {
  15. options: {
  16. appendAddressString: "",
  17. draggableMarker: true,
  18. regionBias: null,
  19. bounds: '',
  20. componentsFilter:'',
  21. updateCallback: null,
  22. reverseGeocode: false,
  23. autocomplete: 'default',
  24. language: '',
  25. mapOptions: {
  26. zoom: 5,
  27. center: new google.maps.LatLng(46, 2),
  28. scrollwheel: false,
  29. mapTypeId: google.maps.MapTypeId.ROADMAP
  30. },
  31. elements: {
  32. map: false,
  33. lat: false,
  34. lng: false,
  35. street_number: false,
  36. route: false,
  37. locality: false,
  38. sublocality: false,
  39. administrative_area_level_3: false,
  40. administrative_area_level_2: false,
  41. administrative_area_level_1: false,
  42. country: false,
  43. postal_code: false,
  44. type: false
  45. },
  46. autocomplete: '' // could be autocomplete: "bootstrap" to use bootstrap typeahead autocomplete instead of jQueryUI
  47. },
  48. marker: function() {
  49. return this.gmarker;
  50. },
  51. map: function() {
  52. return this.gmap;
  53. },
  54. updatePosition: function() {
  55. this._updatePosition(this.gmarker.getPosition());
  56. },
  57. reloadPosition: function() {
  58. this.gmarker.setVisible(true);
  59. this.gmarker.setPosition(new google.maps.LatLng(this.lat.val, this.lng.val));
  60. this.gmap.setCenter(this.gmarker.getPosition());
  61. },
  62. resize: function() {
  63. google.maps.event.trigger(this.gmap, 'resize')
  64. },
  65. selected: function() {
  66. return this.selectedResult;
  67. },
  68. _mapped: {},
  69. _create: function() {
  70. var self = this;
  71. this.geocoder = {
  72. geocode: function(options, callback)
  73. {
  74. jQuery.ajax({
  75. url: "https://maps.googleapis.com/maps/api/geocode/json?" + jQuery.param(options) + '&sensor=false',
  76. type: "GET",
  77. success: function(data) {
  78. callback(data.results, data.status);
  79. }
  80. });
  81. }
  82. //new google.maps.Geocoder();
  83. };
  84. if (this.options.autocomplete === 'bootstrap') {
  85. this.element.typeahead({
  86. source: function(query, process) {
  87. self._mapped = {};
  88. var response = function(results) {
  89. var labels = [];
  90. for (var i = 0; i < results.length; i++) {
  91. self._mapped[results[i].label] = results[i];
  92. labels.push(results[i].label);
  93. }
  94. process(labels);
  95. };
  96. var request = {term: query};
  97. self._geocode(request, response);
  98. },
  99. updater: function(item) {
  100. var ui = {item: self._mapped[item]}
  101. self._focusAddress(null, ui);
  102. self._selectAddress(null, ui);
  103. return item;
  104. }
  105. });
  106. } else {
  107. this.element.autocomplete($.extend({
  108. source: $.proxy(this._geocode, this),
  109. focus: $.proxy(this._focusAddress, this),
  110. select: $.proxy(this._selectAddress, this)
  111. }), this.options.autocomplete);
  112. }
  113. this.lat = $(this.options.elements.lat);
  114. this.lng = $(this.options.elements.lng);
  115. this.street_number = $(this.options.elements.street_number);
  116. this.route = $(this.options.elements.route);
  117. this.locality = $(this.options.elements.locality);
  118. this.sublocality = $(this.options.elements.sublocality);
  119. this.administrative_area_level_3 = $(this.options.elements.administrative_area_level_3);
  120. this.administrative_area_level_2 = $(this.options.elements.administrative_area_level_2);
  121. this.administrative_area_level_1 = $(this.options.elements.administrative_area_level_1);
  122. this.country = $(this.options.elements.country);
  123. this.postal_code = $(this.options.elements.postal_code);
  124. this.type = $(this.options.elements.type);
  125. if (this.options.elements.map) {
  126. this.mapElement = $(this.options.elements.map);
  127. this._initMap();
  128. }
  129. },
  130. _initMap: function() {
  131. if (this.lat && this.lat.val()) {
  132. this.options.mapOptions.center = new google.maps.LatLng(this.lat.val(), this.lng.val());
  133. }
  134. this.gmap = new google.maps.Map(this.mapElement[0], this.options.mapOptions);
  135. this.gmarker = new google.maps.Marker({
  136. position: this.options.mapOptions.center,
  137. map:this.gmap,
  138. draggable: this.options.draggableMarker});
  139. google.maps.event.addListener(this.gmarker, 'dragend', $.proxy(this._markerMoved, this));
  140. this.gmarker.setVisible(false);
  141. },
  142. _updatePosition: function(location) {
  143. if (this.lat) {
  144. this.lat.val(location.lat());
  145. }
  146. if (this.lng) {
  147. this.lng.val(location.lng());
  148. }
  149. },
  150. _addressParts: {street_number: null, route: null, locality: null, sublocality: null,
  151. administrative_area_level_3: null, administrative_area_level_2: null,
  152. administrative_area_level_1: null, country: null, postal_code:null, type: null},
  153. _updateAddressParts: function(geocodeResult){
  154. parsedResult = this._parseGeocodeResult(geocodeResult);
  155. for (addressPart in this._addressParts){
  156. if (this[addressPart]){
  157. if (parsedResult[addressPart] !== false){
  158. this[addressPart].val(parsedResult[addressPart]);
  159. } else {
  160. this[addressPart].val('');
  161. }
  162. }
  163. }
  164. },
  165. _updateAddressPartsViaReverseGeocode: function(location){
  166. this.geocoder.geocode({'latlng': location.lat() + "," + location.lng()}, $.proxy(function(results, status){
  167. if (status == google.maps.GeocoderStatus.OK){
  168. this._updateAddressParts(results[0]);
  169. this.element.val(results[0].formatted_address);
  170. this.selectedResult = results[0];
  171. if (this.options.updateCallback) {
  172. this.options.updateCallback(this.selectedResult, this._parseGeocodeResult(this.selectedResult));
  173. }
  174. }
  175. }, this));
  176. },
  177. _parseGeocodeResult: function(geocodeResult){
  178. var parsed = this._parseLatAndLng(geocodeResult.geometry.location);
  179. for (var addressPart in this._addressParts){
  180. parsed[addressPart] = this._findInfo(geocodeResult, addressPart);
  181. }
  182. parsed.type = geocodeResult.types[0];
  183. return parsed;
  184. },
  185. _parseLatAndLng: function(location){
  186. var longitude, latitude;
  187. if(typeof(location.lat) === 'function'){
  188. latitude = location.lat();
  189. longitude = location.lng();
  190. } else {
  191. latitude = location.lat;
  192. longitude = location.lng;
  193. }
  194. return { lat: latitude, lng: longitude };
  195. },
  196. _markerMoved: function() {
  197. this._updatePosition(this.gmarker.getPosition());
  198. if (this.options.reverseGeocode){
  199. this._updateAddressPartsViaReverseGeocode(this.gmarker.getPosition());
  200. }
  201. },
  202. // Autocomplete source method: fill its suggests with google geocoder results
  203. _geocode: function(request, response) {
  204. var address = request.term, self = this;
  205. this.geocoder.geocode({
  206. 'language': this.options.language,
  207. 'address': address + this.options.appendAddressString,
  208. 'region': this.options.regionBias,
  209. 'bounds': this.options.bounds,
  210. 'components': this.options.componentsFilter
  211. }, function(results, status) {
  212. if (status == google.maps.GeocoderStatus.OK && results) {
  213. for (var i = 0; i < results.length; i++) {
  214. result = results[i]
  215. g = result.geometry
  216. g.location = new google.maps.LatLng(g.location.lat, g.location.lng);
  217. g.viewport = new google.maps.LatLngBounds(
  218. new google.maps.LatLng(g.viewport.southwest.lat, g.viewport.southwest.lng),
  219. new google.maps.LatLng(g.viewport.northeast.lat, g.viewport.northeast.lng)
  220. )
  221. result.label = results[i].formatted_address;
  222. }
  223. }
  224. response(results);
  225. })
  226. },
  227. _findInfo: function(result, type) {
  228. for (var i = 0; i < result.address_components.length; i++) {
  229. var component = result.address_components[i];
  230. if (component.types.indexOf(type) !=-1) {
  231. return component.long_name;
  232. }
  233. }
  234. return false;
  235. },
  236. _focusAddress: function(event, ui) {
  237. var address = ui.item;
  238. if (!address) {
  239. return;
  240. }
  241. if (this.gmarker) {
  242. this.gmarker.setPosition(address.geometry.location);
  243. this.gmarker.setVisible(true);
  244. this.gmap.fitBounds(address.geometry.viewport);
  245. }
  246. this._updatePosition(address.geometry.location);
  247. this._updateAddressParts(address);
  248. },
  249. _selectAddress: function(event, ui) {
  250. this.selectedResult = ui.item;
  251. if (this.options.updateCallback) {
  252. this.options.updateCallback(this.selectedResult, this._parseGeocodeResult(this.selectedResult));
  253. }
  254. }
  255. });
  256. $.extend( $.ui.addresspicker, {
  257. version: "@VERSION"
  258. });
  259. // make IE think it doesn't suck
  260. if(!Array.indexOf){
  261. Array.prototype.indexOf = function(obj){
  262. for(var i=0; i<this.length; i++){
  263. if(this[i]==obj){
  264. return i;
  265. }
  266. }
  267. return -1;
  268. }
  269. }
  270. })( jQuery );