Permalink
Browse files

much more flexible design

  • Loading branch information...
1 parent c7b9e62 commit 559c4c365c06a2ba27652b7983afb781100e2314 @kristianmandrup committed Sep 7, 2012
Showing with 242 additions and 132 deletions.
  1. +86 −15 README.md
  2. +1 −1 VERSION
  3. +2 −2 spec/init.js
  4. +153 −114 vendor/assets/javascripts/gmaps-autocomplete.js
View
101 README.md
@@ -23,37 +23,108 @@ Packed and ready for the Asset pipeline :)
```javascript
$(document).ready(function() {
- GmapsAutoComplete.gmaps_init();
- GmapsAutoComplete.autocomplete_init();
+ GmapsAutoComplete.init();
+ GmapsAutoComplete.autoCompleteInit();
});
```
## Configuration options
-`gmaps_init()` take an option hash, using the following defaults:
+`init()` take an option hash, using the following defaults:
```javascript
- defaultOptions = {
- mapElem: "#gmaps-canvas",
- zoomLevel: 2,
- mapType: google.maps.MapTypeId.ROADMAP,
- pos: [51.751724, -1.255284],
- inputField: '#gmaps-input-address',
- errorField: '#gmaps-error',
- positionOutputter: this.defaultPositionOutputter
- };
+defaultOptions = {
+ mapElem: "#gmaps-canvas",
+ zoomLevel: 2,
+ mapType: google.maps.MapTypeId.ROADMAP,
+ pos: [51.751724, -1.255284],
+ inputField: '#gmaps-input-address',
+ errorField: '#gmaps-error',
+ positionOutputter: this.defaultPositionOutputter,
+ updateUI : this.defaultUpdateUI,
+ updateMap : this.defaultUpdateMap
+};
```
-`autocomplete_init` also takes an option hash, but currently only [region](https://developers.google.com/maps/documentation/geocoding/#RegionCodes) is used.
+`autoCompleteInit` also takes an option hash, but currently only [region](https://developers.google.com/maps/documentation/geocoding/#RegionCodes) is used.
```javascript
-autocomplete_init({region: 'ES'});
+autoCompleteInit({region: 'USA'});
+```
+
+# Examples
+
+See `spec/index.html` for an example page using this "plugin". Note that if you set `mapElem`to null or leave out that element on the page, the autocomplete will function without attempting to update the map :)
+
+## Customization
+
+Some of the prime candidate functions for customization are:
+
+* updateUi
+* updateMap
+
+Here the default simple `updateUI` implementation:
+
+```javascript
+updateUi: function( address, latLng ) {
+ $(this.inputField).autocomplete("close");
+ $(this.inputField).val(address);
+
+ this.positionOutputter(latLng);
+}
+```
+
+Let's enrich the autocomplete fields with a jobs count for "the area" for each address.
+
+```javascript
+updateUi: function( address, latLng ) {
+ $(this.inputField).autocomplete("close");
+
+ var jobsCount = $.ajax(url: 'jobs/search?address=' + address + '&type=count');
+
+ $(this.inputField).val(address + ' (' + jobsCount + ' jobs)');
+}
+```
+
+## Customize messages
+
+For now, directly define your own implementation (override) the following functions directly on GmapsAutoComplete
+
+* geocodeErrorMsg: function()
+* invalidAddressMsg: function(value)
+* noAddressFoundMsg: function()
+
+Example:
+
+```javascript
+
+GmapsAutoComplete.geocodeErrorMsg = function() {
+ "Geocode error!"
+}
+```
+
+## Formtastic example
+
+For [formtastic](https://github.com/justinfrench/formtastic) something like:
+
+```ruby
+= semantic_form_for @search do |f|
+ = f.input :address, placeholder: 'find address'
+ %span#address_error
+
+```javascript
+$(document).ready(function() {
+ GmapsAutoComplete.init({inputField: 'form#search #address', errorField: 'form#search #address_error'});
+ GmapsAutoComplete.autoCompleteInit({region: 'DK'});
+});
```
## TODO
* better Javascript encapsulation
-* translation to Coffeescript and use Coffee classes :)
+* translation to Coffeescript using Coffee classes :)
+
+Please help out with suggestions and improvements etc!
## Contributing to gmaps-autocomplete-rails
View
2 VERSION
@@ -1 +1 @@
-0.1.0
+0.1.1
View
4 spec/init.js
@@ -1,4 +1,4 @@
$(document).ready(function() {
- GmapsAutoComplete.gmaps_init();
- GmapsAutoComplete.autocomplete_init();
+ GmapsAutoComplete.init();
+ GmapsAutoComplete.autoCompleteInit();
});
View
267 vendor/assets/javascripts/gmaps-autocomplete.js
@@ -5,6 +5,9 @@ var GmapsAutoComplete = {
inputField: null,
errorField: null,
positionOutputter: null,
+ updateUI: null,
+ updateMap: null,
+ region: null,
// initialise the google maps objects, and add listeners
mapElem: document.getElementById("gmaps-canvas"),
@@ -15,7 +18,7 @@ var GmapsAutoComplete = {
errorField: '#gmaps-error',
positionOutputter: this.defaultPositionOutputter,
- gmaps_init: function(opts){
+ init: function(opts){
opts = opts || {};
defaultOptions = {
@@ -25,7 +28,9 @@ var GmapsAutoComplete = {
pos: [51.751724, -1.255284],
inputField: '#gmaps-input-address',
errorField: '#gmaps-error',
- positionOutputter: this.defaultPositionOutputter
+ positionOutputter: this.defaultPositionOutputter,
+ updateUI : this.defaultUpdateUI,
+ updateMap : this.defaultUpdateMap
};
$.extend(opts, defaultOptions);
@@ -47,6 +52,8 @@ var GmapsAutoComplete = {
this.errorField = opts['#gmaps-error'];
this.positionOutputter = opts['positionOutputter'];
+ this.updateUI = opts['updateUI'];
+ this.updateMap = opts['updateMap'];
// center of the universe
var latlng = new google.maps.LatLng(lat, lng);
@@ -66,46 +73,52 @@ var GmapsAutoComplete = {
self.showError("Map element " + opts['mapElem'] + " could not be resolved!");
}
- if (mapElem) {
- // create our map object
- this.map = new google.maps.Map(mapElem, options);
-
- if (this.map) {
- // the marker shows us the position of the latest address
- this.marker = new google.maps.Marker({
- map: this.map,
- draggable: true
- });
-
- marker = this.marker;
-
- // event triggered when marker is dragged and dropped
- google.maps.event.addListener(this.marker, 'dragend', function() {
- self.geocode_lookup( 'latLng', marker.getPosition() );
- });
-
- // event triggered when map is clicked
- google.maps.event.addListener(this.map, 'click', function(event) {
- marker.setPosition(event.latLng)
- self.geocode_lookup( 'latLng', event.latLng );
- });
- }
- }
+ if (!mapElem) { return }
+
+ // create our map object
+ this.map = new google.maps.Map(mapElem, options);
+
+ if (!this.map) { return }
+
+ // the marker shows us the position of the latest address
+ this.marker = new google.maps.Marker({
+ map: this.map,
+ draggable: true
+ });
+
+ self.addMapListeners(this.marker, this.map);
+ },
+
+ addMapListeners: function(marker, map) {
+ self = this;
+ // event triggered when marker is dragged and dropped
+ google.maps.event.addListener(marker, 'dragend', function() {
+ self.geocodeLookup( 'latLng', marker.getPosition() );
+ });
+
+ // event triggered when map is clicked
+ google.maps.event.addListener(map, 'click', function(event) {
+ marker.setPosition(event.latLng)
+ self.geocodeLookup( 'latLng', event.latLng );
+ });
},
// move the marker to a new position, and center the map on it
- update_map: function( geometry ) {
- if (this.map) {
- this.map.fitBounds( geometry.viewport )
+ defaultUpdateMap: function( geometry ) {
+ var map = this.map;
+ var marker = this.marker;
+
+ if (map) {
+ map.fitBounds( geometry.viewport )
}
- if (this.marker) {
- this.marker.setPosition( geometry.location )
+ if (marker) {
+ marker.setPosition( geometry.location )
}
},
// fill in the UI elements with new position data
- update_ui: function( address, latLng ) {
+ defaultUpdateUI: function( address, latLng ) {
$(this.inputField).autocomplete("close");
$(this.inputField).val(address);
@@ -125,109 +138,135 @@ var GmapsAutoComplete = {
// value: search query
//
// update: should we update the map (center map and position marker)?
- geocode_lookup: function( type, value, update ) {
+ geocodeLookup: function( type, value, update ) {
// default value: update = false
update = typeof update !== 'undefined' ? update : false;
request = {};
request[type] = value;
var self = this;
- geocoder.geocode({address: request.term, region: 'DK'}, function(results, status) {
- $(self.errorField).html('');
- if (status == google.maps.GeocoderStatus.OK) {
- // Google geocoding has succeeded!
- if (results[0]) {
- // Always update the UI elements with new location data
- self.update_ui( results[0].formatted_address,
- results[0].geometry.location )
-
- // Only update the map (position marker and center map) if requested
- if( update ) { update_map( results[0].geometry ) }
- } else {
- // Geocoder status ok but no results!?
- self.showError("Sorry, something went wrong. Try again!");
- }
- } else {
- // Google Geocoding has failed. Two common reasons:
- // * Address not recognised (e.g. search for 'zxxzcxczxcx')
- // * Location doesn't map to address (e.g. click in middle of Atlantic)
-
- if( type == 'address' ) {
- // User has typed in an address which we can't geocode to a location
- self.showError("Sorry! We couldn't find " + value + ". Try a different search term, or click the map." );
- } else {
- // User has clicked or dragged marker to somewhere that Google can't do a reverse lookup for
- // In this case we display a warning, clear the address box, but fill in LatLng
- self.showError("Woah... that's pretty remote! You're going to have to manually enter a place name." );
- self.update_ui('', value)
- }
- };
- });
+ geocoder.geocode(request, performGeocode);
+ },
+
+ performGeocode: function(results, status) {
+ $(self.errorField).html('');
+ if (status == google.maps.GeocoderStatus.OK) {
+ self.geocodeSuccess(results);
+ } else {
+ self.geocodeFailure(type, value);
+ };
+ },
+
+ geocodeSuccess: function(results) {
+ // Google geocoding has succeeded!
+ if (results[0]) {
+ // Always update the UI elements with new location data
+ this.updateUI( results[0].formatted_address,
+ results[0].geometry.location )
+
+ // Only update the map (position marker and center map) if requested
+ if( update ) { this.updateMap( results[0].geometry ) }
+ } else {
+ // Geocoder status ok but no results!?
+ this.showError( this.geocodeErrorMsg() );
+ }
+ },
+
+ geocodeFailure: function(type, value) {
+ // Google Geocoding has failed. Two common reasons:
+ // * Address not recognised (e.g. search for 'zxxzcxczxcx')
+ // * Location doesn't map to address (e.g. click in middle of Atlantic)
+ if( type == 'address' ) {
+ // User has typed in an address which we can't geocode to a location
+ this.showError( this.invalidAddressMsg(value) );
+ } else {
+ // User has clicked or dragged marker to somewhere that Google can't do a reverse lookup for
+ // In this case we display a warning, clear the address box, but fill in LatLng
+ this.showError( this.noAddressFoundMsg() );
+ this.updateUI('', value)
+ }
+ },
+
+ geocodeErrorMsg: function() {
+ "Sorry, something went wrong. Try again!"
+ },
+
+ invalidAddressMsg: function(value) {
+ "Sorry! We couldn't find " + value + ". Try a different search term, or click the map."
+ },
+
+ noAddressFoundMsg: function() {
+ "Woah... that's pretty remote! You're going to have to manually enter a place name."
},
showError: function(msg) {
- $(self.errorField).html(msg);
- $(self.errorField).show();
+ $(this.errorField).html(msg);
+ $(this.errorField).show();
setTimeout(function(){
- $(self.errorField).hide();
+ $(this.errorField).hide();
}, 1000);
},
// initialise the jqueryUI autocomplete element
- autocomplete_init: function (opts) {
- var self = this;
+ autoCompleteInit: function (opts) {
opts = opts || {};
- var region = opts['region'] || 'DK';
-
- $(self.inputField).autocomplete({
+ this.region = opts['region'] || 'DK';
+ $(this.inputField).autocomplete({
// source is the list of input options shown in the autocomplete dropdown.
// see documentation: http://jqueryui.com/demos/autocomplete/
- source: function(request,response) {
-
- // https://developers.google.com/maps/documentation/geocoding/#RegionCodes
- console.log('region', region);
- var region_postfix = ''
- if (region) {
- region_postfix = ', ' + region
- }
-
- geocode_opts = {'address': request.term + region_postfix }
-
- // the geocode method takes an address or LatLng to search for
- // and a callback function which should process the results into
- // a format accepted by jqueryUI autocomplete
- geocoder.geocode(geocode_opts, function(results, status) {
- response($.map(results, function(item) {
- return {
- label: item.formatted_address, // appears in dropdown box
- value: item.formatted_address, // inserted into input element when selected
- geocode: item // all geocode data: used in select callback event
- }
- }));
- })
- },
-
+ source: this.autoCompleteSource,
// event triggered when drop-down option selected
- select: function(event,ui){
- self.update_ui( ui.item.value, ui.item.geocode.geometry.location )
- self.update_map( ui.item.geocode.geometry )
- }
+ select: this.autoCompleteSelect
});
// triggered when user presses a key in the address box
- $(self.inputField).bind('keydown', function(event) {
- if(event.keyCode == 13) {
- geocode_lookup( 'address', $(self.inputField).val(), true );
-
- // ensures dropdown disappears when enter is pressed
- $(self.inputField).autocomplete("disable")
- } else {
- // re-enable if previously disabled above
- $(self.inputField).autocomplete("enable")
- }
- });
- } // autocomplete_init
+ $(self.inputField).bind('keydown', this.keyDownHandler);
+ }, // autocomplete_init
+
+ keyDownHandler: function(event) {
+ if(event.keyCode == 13) {
+ this.geocodeLookup( 'address', $(self.inputField).val(), true );
+
+ // ensures dropdown disappears when enter is pressed
+ $(this.inputField).autocomplete("disable")
+ } else {
+ // re-enable if previously disabled above
+ $(this.inputField).autocomplete("enable")
+ }
+ },
+
+ // self grants access to caller scope
+ autoCompleteSelect: function(event,ui){
+ self.updateUI( ui.item.value, ui.item.geocode.geometry.location )
+ self.updateMap( ui.item.geocode.geometry )
+ },
+
+ // self grants access to caller scope
+ autoCompleteSource: function(request,response) {
+ // https://developers.google.com/maps/documentation/geocoding/#RegionCodes
+ var region_postfix = ''
+ var region = self.region;
+
+ if (region) {
+ region_postfix = ', ' + region
+ }
+
+ geocode_opts = {'address': request.term + region_postfix }
+
+ // the geocode method takes an address or LatLng to search for
+ // and a callback function which should process the results into
+ // a format accepted by jqueryUI autocomplete
+ geocoder.geocode(geocode_opts, function(results, status) {
+ response($.map(results, function(item) {
+ return {
+ label: item.formatted_address, // appears in dropdown box
+ value: item.formatted_address, // inserted into input element when selected
+ geocode: item // all geocode data: used in select callback event
+ }
+ }));
+ })
+ }
}

0 comments on commit 559c4c3

Please sign in to comment.