geocomplete_rails 1.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in geocomplete_rails.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Guy Israeli
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,37 @@
1
+ # GeocompleteRails
2
+
3
+ jQuery Geocoding and Places Autocomplete Plugin
4
+
5
+ for Rails 3.1+ and Rails 4
6
+
7
+ see demo - http://ubilabs.github.io/geocomplete/
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'geocomplete_rails'
14
+
15
+ Add this to application.js
16
+
17
+ //= require geocomplete
18
+
19
+ And then execute:
20
+
21
+ $ bundle
22
+
23
+ Or install it yourself as:
24
+
25
+ $ gem install geocomplete_rails
26
+
27
+ ## Usage
28
+
29
+ see demo - http://ubilabs.github.io/geocomplete/
30
+
31
+ ## Contributing
32
+
33
+ 1. Fork it
34
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
35
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
36
+ 4. Push to the branch (`git push origin my-new-feature`)
37
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,451 @@
1
+ /*!
2
+ * jQuery Geocoding and Places Autocomplete Plugin - V 1.4.1
3
+ *
4
+ * @author Martin Kleppe <kleppe@ubilabs.net>, 2012
5
+ * @author Ubilabs http://ubilabs.net, 2012
6
+ * @license MIT License <http://www.opensource.org/licenses/mit-license.php>
7
+ */
8
+
9
+
10
+ ;(function($, window, document, undefined){
11
+
12
+ // ## Options
13
+ // The default options for this plugin.
14
+ //
15
+ // * `map` - Might be a selector, an jQuery object or a DOM element. Default is `false` which shows no map.
16
+ // * `details` - The container that should be populated with data. Defaults to `false` which ignores the setting.
17
+ // * `location` - Location to initialize the map on. Might be an address `string` or an `array` with [latitude, longitude] or a `google.maps.LatLng`object. Default is `false` which shows a blank map.
18
+ // * `bounds` - Whether to snap geocode search to map bounds. Default: `true` if false search globally. Alternatively pass a custom `LatLngBounds object.
19
+ // * `detailsAttribute` - The attribute's name to use as an indicator. Default: `"name"`
20
+ // * `mapOptions` - Options to pass to the `google.maps.Map` constructor. See the full list [here](http://code.google.com/apis/maps/documentation/javascript/reference.html#MapOptions).
21
+ // * `mapOptions.zoom` - The inital zoom level. Default: `14`
22
+ // * `mapOptions.scrollwheel` - Whether to enable the scrollwheel to zoom the map. Default: `false`
23
+ // * `mapOptions.mapTypeId` - The map type. Default: `"roadmap"`
24
+ // * `markerOptions` - The options to pass to the `google.maps.Marker` constructor. See the full list [here](http://code.google.com/apis/maps/documentation/javascript/reference.html#MarkerOptions).
25
+ // * `markerOptions.draggable` - If the marker is draggable. Default: `false`. Set to true to enable dragging.
26
+ // * `markerOptions.disabled` - Do not show marker. Default: `false`. Set to true to disable marker.
27
+ // * `maxZoom` - The maximum zoom level too zoom in after a geocoding response. Default: `16`
28
+ // * `types` - An array containing one or more of the supported types for the places request. Default: `['geocode']` See the full list [here](http://code.google.com/apis/maps/documentation/javascript/places.html#place_search_requests).
29
+
30
+ var defaults = {
31
+ bounds: true,
32
+ country: null,
33
+ map: false,
34
+ details: false,
35
+ detailsAttribute: "name",
36
+ location: false,
37
+
38
+ mapOptions: {
39
+ zoom: 14,
40
+ scrollwheel: false,
41
+ mapTypeId: "roadmap"
42
+ },
43
+
44
+ markerOptions: {
45
+ draggable: false
46
+ },
47
+
48
+ maxZoom: 16,
49
+ types: ['geocode'],
50
+ blur: false
51
+ };
52
+
53
+ // See: [Geocoding Types](https://developers.google.com/maps/documentation/geocoding/#Types)
54
+ // on Google Developers.
55
+ var componentTypes = ("street_address route intersection political " +
56
+ "country administrative_area_level_1 administrative_area_level_2 " +
57
+ "administrative_area_level_3 colloquial_area locality sublocality " +
58
+ "neighborhood premise subpremise postal_code natural_feature airport " +
59
+ "park point_of_interest post_box street_number floor room " +
60
+ "lat lng viewport location " +
61
+ "formatted_address location_type bounds").split(" ");
62
+
63
+ // See: [Places Details Responses](https://developers.google.com/maps/documentation/javascript/places#place_details_responses)
64
+ // on Google Developers.
65
+ var placesDetails = ("id url website vicinity reference name rating " +
66
+ "international_phone_number icon formatted_phone_number").split(" ");
67
+
68
+ // The actual plugin constructor.
69
+ function GeoComplete(input, options) {
70
+
71
+ this.options = $.extend(true, {}, defaults, options);
72
+
73
+ this.input = input;
74
+ this.$input = $(input);
75
+
76
+ this._defaults = defaults;
77
+ this._name = 'geocomplete';
78
+
79
+ this.init();
80
+ }
81
+
82
+ // Initialize all parts of the plugin.
83
+ $.extend(GeoComplete.prototype, {
84
+ init: function(){
85
+ this.initMap();
86
+ this.initMarker();
87
+ this.initGeocoder();
88
+ this.initDetails();
89
+ this.initLocation();
90
+ },
91
+
92
+ // Initialize the map but only if the option `map` was set.
93
+ // This will create a `map` within the given container
94
+ // using the provided `mapOptions` or link to the existing map instance.
95
+ initMap: function(){
96
+ if (!this.options.map){ return; }
97
+
98
+ if (typeof this.options.map.setCenter == "function"){
99
+ this.map = this.options.map;
100
+ return;
101
+ }
102
+
103
+ this.map = new google.maps.Map(
104
+ $(this.options.map)[0],
105
+ this.options.mapOptions
106
+ );
107
+
108
+ // add click event listener on the map
109
+ google.maps.event.addListener(
110
+ this.map,
111
+ 'click',
112
+ $.proxy(this.mapClicked, this)
113
+ );
114
+ },
115
+
116
+ // Add a marker with the provided `markerOptions` but only
117
+ // if the option was set. Additionally it listens for the `dragend` event
118
+ // to notify the plugin about changes.
119
+ initMarker: function(){
120
+ if (!this.map){ return; }
121
+ var options = $.extend(this.options.markerOptions, { map: this.map });
122
+
123
+ if (options.disabled){ return; }
124
+
125
+ this.marker = new google.maps.Marker(options);
126
+
127
+ google.maps.event.addListener(
128
+ this.marker,
129
+ 'dragend',
130
+ $.proxy(this.markerDragged, this)
131
+ );
132
+ },
133
+
134
+ // Associate the input with the autocompleter and create a geocoder
135
+ // to fall back when the autocompleter does not return a value.
136
+ initGeocoder: function(){
137
+
138
+ var options = {
139
+ types: this.options.types,
140
+ bounds: this.options.bounds === true ? null : this.options.bounds,
141
+ componentRestrictions: this.options.componentRestrictions
142
+ };
143
+
144
+ if (this.options.country){
145
+ options.componentRestrictions = {country: this.options.country}
146
+ }
147
+
148
+ this.autocomplete = new google.maps.places.Autocomplete(
149
+ this.input, options
150
+ );
151
+
152
+ this.geocoder = new google.maps.Geocoder();
153
+
154
+ // Bind autocomplete to map bounds but only if there is a map
155
+ // and `options.bindToMap` is set to true.
156
+ if (this.map && this.options.bounds === true){
157
+ this.autocomplete.bindTo('bounds', this.map);
158
+ }
159
+
160
+ // Watch `place_changed` events on the autocomplete input field.
161
+ google.maps.event.addListener(
162
+ this.autocomplete,
163
+ 'place_changed',
164
+ $.proxy(this.placeChanged, this)
165
+ );
166
+
167
+ // Prevent parent form from being submitted if user hit enter.
168
+ this.$input.keypress(function(event){
169
+ if (event.keyCode === 13){ return false; }
170
+ });
171
+
172
+ // Listen for "geocode" events and trigger find action.
173
+ this.$input.bind("geocode", $.proxy(function(){
174
+ this.find();
175
+ }, this));
176
+
177
+ // Trigger find action when input element is blured out.
178
+ // (Usefull for typing partial location and tabing to the next field
179
+ // or clicking somewhere else.)
180
+ if (this.options.blur === true){
181
+ this.$input.blur($.proxy(function(){
182
+ this.find();
183
+ }, this));
184
+ }
185
+ },
186
+
187
+ // Prepare a given DOM structure to be populated when we got some data.
188
+ // This will cycle through the list of component types and map the
189
+ // corresponding elements.
190
+ initDetails: function(){
191
+ if (!this.options.details){ return; }
192
+
193
+ var $details = $(this.options.details),
194
+ attribute = this.options.detailsAttribute,
195
+ details = {};
196
+
197
+ function setDetail(value){
198
+ details[value] = $details.find("[" + attribute + "=" + value + "]");
199
+ }
200
+
201
+ $.each(componentTypes, function(index, key){
202
+ setDetail(key);
203
+ setDetail(key + "_short");
204
+ });
205
+
206
+ $.each(placesDetails, function(index, key){
207
+ setDetail(key);
208
+ });
209
+
210
+ this.$details = $details;
211
+ this.details = details;
212
+ },
213
+
214
+ // Set the initial location of the plugin if the `location` options was set.
215
+ // This method will care about converting the value into the right format.
216
+ initLocation: function() {
217
+
218
+ var location = this.options.location, latLng;
219
+
220
+ if (!location) { return; }
221
+
222
+ if (typeof location == 'string') {
223
+ this.find(location);
224
+ return;
225
+ }
226
+
227
+ if (location instanceof Array) {
228
+ latLng = new google.maps.LatLng(location[0], location[1]);
229
+ }
230
+
231
+ if (location instanceof google.maps.LatLng){
232
+ latLng = location;
233
+ }
234
+
235
+ if (latLng){
236
+ if (this.map){ this.map.setCenter(latLng); }
237
+ if (this.marker){ this.marker.setPosition(latLng); }
238
+ }
239
+ },
240
+
241
+ // Look up a given address. If no `address` was specified it uses
242
+ // the current value of the input.
243
+ find: function(address){
244
+ this.geocode({
245
+ address: address || this.$input.val()
246
+ });
247
+ },
248
+
249
+ // Requests details about a given location.
250
+ // Additionally it will bias the requests to the provided bounds.
251
+ geocode: function(request){
252
+ if (this.options.bounds && !request.bounds){
253
+ if (this.options.bounds === true){
254
+ request.bounds = this.map && this.map.getBounds();
255
+ } else {
256
+ request.bounds = this.options.bounds;
257
+ }
258
+ }
259
+
260
+ if (this.options.country){
261
+ request.region = this.options.country;
262
+ }
263
+
264
+ this.geocoder.geocode(request, $.proxy(this.handleGeocode, this));
265
+ },
266
+
267
+ // Handles the geocode response. If more than one results was found
268
+ // it triggers the "geocode:multiple" events. If there was an error
269
+ // the "geocode:error" event is fired.
270
+ handleGeocode: function(results, status){
271
+ if (status === google.maps.GeocoderStatus.OK) {
272
+ var result = results[0];
273
+ this.$input.val(result.formatted_address);
274
+ this.update(result);
275
+
276
+ if (results.length > 1){
277
+ this.trigger("geocode:multiple", results);
278
+ }
279
+
280
+ } else {
281
+ this.trigger("geocode:error", status);
282
+ }
283
+ },
284
+
285
+ // Triggers a given `event` with optional `arguments` on the input.
286
+ trigger: function(event, argument){
287
+ this.$input.trigger(event, [argument]);
288
+ },
289
+
290
+ // Set the map to a new center by passing a `geometry`.
291
+ // If the geometry has a viewport, the map zooms out to fit the bounds.
292
+ // Additionally it updates the marker position.
293
+ center: function(geometry){
294
+
295
+ if (geometry.viewport){
296
+ this.map.fitBounds(geometry.viewport);
297
+ if (this.map.getZoom() > this.options.maxZoom){
298
+ this.map.setZoom(this.options.maxZoom);
299
+ }
300
+ } else {
301
+ this.map.setZoom(this.options.maxZoom);
302
+ this.map.setCenter(geometry.location);
303
+ }
304
+
305
+ if (this.marker){
306
+ this.marker.setPosition(geometry.location);
307
+ this.marker.setAnimation(this.options.markerOptions.animation);
308
+ }
309
+ },
310
+
311
+ // Update the elements based on a single places or geoocoding response
312
+ // and trigger the "geocode:result" event on the input.
313
+ update: function(result){
314
+
315
+ if (this.map){
316
+ this.center(result.geometry);
317
+ }
318
+
319
+ if (this.$details){
320
+ this.fillDetails(result);
321
+ }
322
+
323
+ this.trigger("geocode:result", result);
324
+ },
325
+
326
+ // Populate the provided elements with new `result` data.
327
+ // This will lookup all elements that has an attribute with the given
328
+ // component type.
329
+ fillDetails: function(result){
330
+
331
+ var data = {},
332
+ geometry = result.geometry,
333
+ viewport = geometry.viewport,
334
+ bounds = geometry.bounds;
335
+
336
+ // Create a simplified version of the address components.
337
+ $.each(result.address_components, function(index, object){
338
+ var name = object.types[0];
339
+ data[name] = object.long_name;
340
+ data[name + "_short"] = object.short_name;
341
+ });
342
+
343
+ // Add properties of the places details.
344
+ $.each(placesDetails, function(index, key){
345
+ data[key] = result[key];
346
+ });
347
+
348
+ // Add infos about the address and geometry.
349
+ $.extend(data, {
350
+ formatted_address: result.formatted_address,
351
+ location_type: geometry.location_type || "PLACES",
352
+ viewport: viewport,
353
+ bounds: bounds,
354
+ location: geometry.location,
355
+ lat: geometry.location.lat(),
356
+ lng: geometry.location.lng()
357
+ });
358
+
359
+ // Set the values for all details.
360
+ $.each(this.details, $.proxy(function(key, $detail){
361
+ var value = data[key];
362
+ this.setDetail($detail, value);
363
+ }, this));
364
+
365
+ this.data = data;
366
+ },
367
+
368
+ // Assign a given `value` to a single `$element`.
369
+ // If the element is an input, the value is set, otherwise it updates
370
+ // the text content.
371
+ setDetail: function($element, value){
372
+
373
+ if (value === undefined){
374
+ value = "";
375
+ } else if (typeof value.toUrlValue == "function"){
376
+ value = value.toUrlValue();
377
+ }
378
+
379
+ if ($element.is(":input")){
380
+ $element.val(value);
381
+ } else {
382
+ $element.text(value);
383
+ }
384
+ },
385
+
386
+ // Fire the "geocode:dragged" event and pass the new position.
387
+ markerDragged: function(event){
388
+ this.trigger("geocode:dragged", event.latLng);
389
+ },
390
+
391
+ mapClicked: function(event) {
392
+ this.trigger("geocode:click", event.latLng);
393
+ },
394
+
395
+ // Restore the old position of the marker to the last now location.
396
+ resetMarker: function(){
397
+ this.marker.setPosition(this.data.location);
398
+ this.setDetail(this.details.lat, this.data.location.lat());
399
+ this.setDetail(this.details.lng, this.data.location.lng());
400
+ },
401
+
402
+ // Update the plugin after the user has selected an autocomplete entry.
403
+ // If the place has no geometry it passes it to the geocoder.
404
+ placeChanged: function(){
405
+ var place = this.autocomplete.getPlace();
406
+
407
+ if (!place.geometry){
408
+ this.find(place.name);
409
+ } else {
410
+ this.update(place);
411
+ }
412
+ }
413
+ });
414
+
415
+ // A plugin wrapper around the constructor.
416
+ // Pass `options` with all settings that are different from the default.
417
+ // The attribute is used to prevent multiple instantiations of the plugin.
418
+ $.fn.geocomplete = function(options) {
419
+
420
+ var attribute = 'plugin_geocomplete';
421
+
422
+ // If you call `.geocomplete()` with a string as the first parameter
423
+ // it returns the corresponding property or calls the method with the
424
+ // following arguments.
425
+ if (typeof options == "string"){
426
+
427
+ var instance = $(this).data(attribute) || $(this).geocomplete().data(attribute),
428
+ prop = instance[options];
429
+
430
+ if (typeof prop == "function"){
431
+ prop.apply(instance, Array.prototype.slice.call(arguments, 1));
432
+ return $(this);
433
+ } else {
434
+ if (arguments.length == 2){
435
+ prop = arguments[1];
436
+ }
437
+ return prop;
438
+ }
439
+ } else {
440
+ return this.each(function() {
441
+ // Prevent against multiple instantiations.
442
+ var instance = $.data(this, attribute);
443
+ if (!instance) {
444
+ instance = new GeoComplete( this, options )
445
+ $.data(this, attribute, instance);
446
+ }
447
+ });
448
+ }
449
+ };
450
+
451
+ })( jQuery, window, document );
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'geocomplete_rails/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "geocomplete_rails"
8
+ spec.version = GeocompleteRails::VERSION
9
+ spec.authors = ["Guy Israeli"]
10
+ spec.description = %q{Wrapper for geocomplete.js - a jQuery Geocoding and Places Autocomplete Plugin}
11
+ spec.summary = %q{jQuery Geocoding and Places Autocomplete Plugin}
12
+ spec.homepage = "https://github.com/guyisra/geocomplete_rails"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.3"
21
+ spec.add_development_dependency "rake"
22
+ spec.add_dependency "railties", ">=3.1"
23
+
24
+ end
@@ -0,0 +1,8 @@
1
+ require "geocomplete_rails/version"
2
+
3
+ module GeocompleteRails
4
+ module Rails
5
+ class Engine < ::Rails::Engine
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ module GeocompleteRails
2
+ VERSION = "1.4.1"
3
+ end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: geocomplete_rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.4.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Guy Israeli
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-09-10 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.3'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.3'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: railties
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '3.1'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '3.1'
62
+ description: Wrapper for geocomplete.js - a jQuery Geocoding and Places Autocomplete
63
+ Plugin
64
+ email:
65
+ executables: []
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - .gitignore
70
+ - Gemfile
71
+ - LICENSE.txt
72
+ - README.md
73
+ - Rakefile
74
+ - app/assets/javascripts/geocomplete.js
75
+ - geocomplete_rails.gemspec
76
+ - lib/geocomplete_rails.rb
77
+ - lib/geocomplete_rails/version.rb
78
+ homepage: https://github.com/guyisra/geocomplete_rails
79
+ licenses:
80
+ - MIT
81
+ post_install_message:
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ none: false
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ requirements: []
98
+ rubyforge_project:
99
+ rubygems_version: 1.8.24
100
+ signing_key:
101
+ specification_version: 3
102
+ summary: jQuery Geocoding and Places Autocomplete Plugin
103
+ test_files: []