wf-rails3-jquery-autocomplete 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG.md ADDED
@@ -0,0 +1,27 @@
1
+ # Changelog
2
+
3
+ * 1.0.3 Fixed Formtastic 2.0 + Ruby 1.8.7 compat issue
4
+ * 1.0.2 Fixed issue #93, #94
5
+ * 1.0.1 Formtastic 2.0 compatibility fix
6
+ * 1.0.0 Rails 3.1 asset pipeline support
7
+ * 0.9.1 Fixes issues #96 and #32
8
+ * 0.9.0 Massive rewrite
9
+ * 0.8.0 Compressed JS file
10
+ * 0.7.5 Pull request #46
11
+ * 0.7.4 Allows Rails 3.1
12
+ * 0.7.3 MongoMapper
13
+ * 0.7.2 Steak helper
14
+ * 0.7.1 Fixed joined scopes (Issue #43)
15
+ * 0.7.0 Scopes
16
+ * 0.6.6 ILIKE for postgres
17
+ * 0.6.5 JS select event
18
+ * 0.6.4 Use YAJL instead of JSON
19
+ * 0.6.3 SimpleForm plugin
20
+ * 0.6.2 Fix Issue #8
21
+ * 0.6.1 Allow specifying fully qualified class name for model object as an option to autocomplete
22
+ * 0.6.0 JS Code cleanup
23
+ * 0.5.1 Add STI support
24
+ * 0.5.0 Formtastic support
25
+ * 0.4.0 MongoID support
26
+ * 0.3.6 Using .live() to put autocomplete on dynamic fields
27
+
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 David Padilla
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,345 @@
1
+ # rails3-jquery-autocomplete
2
+
3
+ An easy way to use jQuery's autocomplete with Rails 3.
4
+
5
+ Supports both ActiveRecord, [mongoid](http://github.com/mongoid/mongoid), and [MongoMapper](https://github.com/jnunemaker/mongomapper).
6
+
7
+ Works with [Formtastic](http://github.com/justinfrench/formtastic)
8
+ and [SimpleForm](https://github.com/plataformatec/simple_form)
9
+
10
+ ## ActiveRecord
11
+
12
+ You can find a [detailed example](http://github.com/crowdint/rails3-jquery-autocomplete-app)
13
+ on how to use this gem with ActiveRecord [here](http://github.com/crowdint/rails3-jquery-autocomplete-app).
14
+
15
+ ## MongoID
16
+
17
+ You can find a [detailed example](http://github.com/crowdint/rails3-jquery-autocomplete-app/tree/mongoid)
18
+ on how to use this gem with MongoID [here](http://github.com/crowdint/rails3-jquery-autocomplete-app/tree/mongoid). (Same thing, different branch)
19
+
20
+ ## Before you start
21
+
22
+ Make sure your project is using jQuery-UI and the autocomplete widget
23
+ before you continue.
24
+
25
+ You can find more info about that here:
26
+
27
+ * http://jquery.com/
28
+ * http://jqueryui.com/demos/autocomplete/
29
+ * http://github.com/rails/jquery-ujs
30
+
31
+ I'd encourage you to understand how to use those 3 amazing tools before attempting to use this gem.
32
+
33
+ ## Installing
34
+
35
+ Include the gem on your Gemfile
36
+
37
+ gem 'rails3-jquery-autocomplete'
38
+
39
+ Install it
40
+
41
+ bundle install
42
+
43
+ ### Rails 3.0.x
44
+
45
+ Run the generator
46
+
47
+ rails generate autocomplete:install
48
+
49
+ And include autocomplete-rails.js on your layouts
50
+
51
+ javascript_include_tag "autocomplete-rails.js"
52
+
53
+ ### Rails 3.1.x
54
+
55
+ Just add it to your app/assets/javascripts/application.js file
56
+
57
+ //= require jquery
58
+ //= require jquery_ujs
59
+ //= require autocomplete-rails
60
+
61
+ ## Upgrading from older versions
62
+
63
+ If you are upgrading from a previous version, run the generator after installing to replace the javascript file.
64
+
65
+ rails generate autocomplete:install
66
+
67
+ I'd recommend you do this every time you update to make sure you have the latest JS file.
68
+
69
+ ## Uncompressed Javascript file
70
+
71
+ If you want to make changes to the JS file, you can install the
72
+ uncompressed version by running:
73
+
74
+ rails generate autocomplete:uncompressed
75
+
76
+ ## Usage
77
+
78
+ ### Model Example
79
+
80
+ Assuming you have a Brand model:
81
+
82
+ class Brand < ActiveRecord::Base
83
+ end
84
+
85
+ create_table :brand do |t|
86
+ t.column :name, :string
87
+ end
88
+
89
+ ### Controller
90
+
91
+ To set up the required action on your controller, all you have to do is call it with the class name and the method
92
+ as in the following example:
93
+
94
+ class ProductsController < Admin::BaseController
95
+ autocomplete :brand, :name
96
+ end
97
+
98
+ This will create an action _autocomplete_brand_name_ on your controller, don't forget to add it on your routes file
99
+
100
+ resources :products do
101
+ get :autocomplete_brand_name, :on => :collection
102
+ end
103
+
104
+ ### Options
105
+
106
+ #### :full => true
107
+
108
+ By default, the search starts from the beginning of the string you're searching for. If you want to do a full search, set the _full_ parameter to true.
109
+
110
+ class ProductsController < Admin::BaseController
111
+ autocomplete :brand, :name, :full => true
112
+ end
113
+
114
+ The following terms would match the query 'un':
115
+
116
+ * Luna
117
+ * Unacceptable
118
+ * Rerun
119
+
120
+ #### :full => false (default behavior)
121
+
122
+ Only the following terms mould match the query 'un':
123
+
124
+ * Unacceptable
125
+
126
+ #### :extra_data
127
+
128
+ By default, your search will only return the required columns from the database needed to populate your form, namely id and the column you are searching (name, in the above example).
129
+
130
+ Passing an array of attributes/column names to this option will fetch and return the specified data.
131
+
132
+ class ProductsController < Admin::BaseController
133
+ autocomplete :brand, :name, :extra_data => [:slogan]
134
+ end
135
+
136
+ #### :display_value
137
+
138
+ If you want to display a different version of what you're looking for, you can use the :display_value option.
139
+
140
+ This options receives a method name as the parameter, and that method will be called on the instance when displaying the results.
141
+
142
+ class Brand < ActiveRecord::Base
143
+ def funky_method
144
+ "#{self.name}.camelize"
145
+ end
146
+ end
147
+
148
+
149
+ class ProductsController < Admin::BaseController
150
+ autocomplete :brand, :name, :display_value => :funky_method
151
+ end
152
+
153
+ In the example above, you will search by _name_, but the autocomplete list will display the result of _funky_method_
154
+
155
+ This wouldn't really make much sense unless you use it with the "id_element" attribute. (See below)
156
+
157
+ Only the object's id and the column you are searching on will be returned in JSON, so if your display_value method requires another parameter, make sure to fetch it with the :extra_data option
158
+
159
+
160
+ #### :scopes
161
+ Added option to use scopes. Pass scopes in an array.
162
+ e.g `:scopes => [:scope1, :scope2]`
163
+
164
+ #### :column_name
165
+ By default autocomplete uses method name as column name. Now it can be specified using column_name options
166
+ `:column_name => 'name'`
167
+
168
+ #### json encoder
169
+ Autocomplete uses Yajl as JSON encoder/decoder, but you can specify your own
170
+
171
+ class ProductsController < Admin::BaseController
172
+ autocomplete :brand, :name do |items|
173
+ CustomJSON::Encoder.encode(items)
174
+ end
175
+ end
176
+
177
+ ### View
178
+
179
+ On your view, all you have to do is include the attribute autocomplete on the text field
180
+ using the url to the autocomplete action as the value.
181
+
182
+ form_for @product do |f|
183
+ f.autocomplete_field :brand_name, autocomplete_brand_name_products_path
184
+ end
185
+
186
+ This will generate an HTML tag that looks like:
187
+
188
+ <input type="text" data-autocomplete="products/autocomplete_brand_name">
189
+
190
+ If you are not using a FormBuilder (form_for) or you just want to include an autocomplete field without the form, you can use the
191
+ *autocomplete_field_tag* helper.
192
+
193
+ form_tag 'some/path'
194
+ autocomplete_field_tag 'address', '', address_autocomplete_path, :size => 75
195
+ end
196
+
197
+ Now your autocomplete code is unobtrusive, Rails 3 style.
198
+
199
+ ### Getting the object id
200
+
201
+ If you need to use the id of the selected object, you can use the *id_element* attribute too:
202
+
203
+ f.autocomplete_field :brand_name, autocomplete_brand_name_products_path, :id_element => '#some_element'
204
+
205
+ This will update the field with id *#some_element with the id of the selected object. The value for this option can be any jQuery selector.
206
+
207
+ ### Getting extra object data
208
+
209
+ If you need to extra data about the selected object, you can use the *:update_elements* HTML attribute.
210
+
211
+ The :update_elements attribute accepts a hash where the keys represent the object attribute/column data to use to update and the values are jQuery selectors to retrieve the HTML element to update:
212
+
213
+ f.autocomplete_field :brand_name, autocomplete_brand_name_products_path, :update_elements => {:id => '#id_element', :slogan => '#some_other_element'}
214
+
215
+ class ProductsController < Admin::BaseController
216
+ autocomplete :brand, :name, :extra_data => [:slogan]
217
+ end
218
+
219
+ The previous example would fetch the extra attribute slogan and update jQuery('#some_other_element') with the slogan value.
220
+
221
+ ### Running custom code on selection
222
+
223
+ A javascript event named *railsAutocomplete.select* is fired on the input field when a value is selected from the autocomplete drop down. If you need to do something more complex than update fields with data, you can hook into this event, like so:
224
+
225
+ $('#my_autocomplete_field').bind('railsAutocomplete.select', function(event, data){
226
+ /* Do something here */
227
+ alert(data.item.id);
228
+ });
229
+
230
+ ## Formtastic
231
+
232
+ If you are using [Formtastic](http://github.com/justinfrench/formtastic), you automatically get the *autocompleted_input* helper on *semantic_form_for*:
233
+
234
+ semantic_form_for @product do |f|
235
+ f.input :brand_name, :as => :autocomplete, :url => autocomplete_brand_name_products_path
236
+ end
237
+
238
+ The only difference with the original helper is that you must specify the autocomplete url using the *:url* option.
239
+
240
+ ## SimpleForm
241
+
242
+ If you want to use it with simple_form, all you have to do is use the
243
+ :as option on the input and set the autocomplete path with the :url
244
+ option.
245
+
246
+
247
+ simple_form_for @product do |form|
248
+ form.input :name
249
+ form.input :brand_name, :url => autocomplete_brand_name_products_path, :as => :autocomplete
250
+
251
+ # Cucumber
252
+
253
+ I have created a step to test your autocomplete with Cucumber and Capybara, all you have to do is add the following lines to your *env.rb* file:
254
+
255
+ require 'cucumber/autocomplete'
256
+
257
+ Then you'll have access to the following step:
258
+
259
+ I choose "([^"]*)" in the autocomplete list
260
+
261
+ An example on how to use it:
262
+
263
+ @javascript
264
+ Scenario: Autocomplete
265
+ Given the following brands exists:
266
+ | name |
267
+ | Alpha |
268
+ | Beta |
269
+ | Gamma |
270
+ And I go to the home page
271
+ And I fill in "Brand name" with "al"
272
+ And I choose "Alpha" in the autocomplete list
273
+ Then the "Brand name" field should contain "Alpha"
274
+
275
+ I have only tested this using Capybara, no idea if it works with something else, to see it in action, check the [example app](http://github.com/crowdint/rails3-jquery-autocomplete-app).
276
+
277
+ # Steak
278
+
279
+ I have created a helper to test your autocomplete with Steak and Capybara, all you have to do is add the following lines to your *acceptance_helper.rb* file:
280
+
281
+ require 'steak/autocomplete'
282
+
283
+ Then you'll have access to the following helper:
284
+
285
+ choose_autocomplete_result
286
+
287
+ An example on how to use it:
288
+
289
+ scenario "Autocomplete" do
290
+ lambda do
291
+ Brand.create! [
292
+ {:name => "Alpha"},
293
+ {:name => "Beta"},
294
+ {:name => "Gamma"}
295
+ ]
296
+ end.should change(Brand, :count).by(3)
297
+
298
+ visit home_page
299
+ fill_in "Brand name", :with => "al"
300
+ choose_autocomplete_result "Alpha"
301
+ find_field("Brand name").value.should include("Alpha")
302
+ end
303
+
304
+ I have only tested this using Capybara, no idea if it works with something else.
305
+
306
+ # Development
307
+
308
+ If you want to make changes to the gem, first install bundler 1.0.0:
309
+
310
+ gem install bundler
311
+
312
+ And then, install all your dependencies:
313
+
314
+ bundle install
315
+
316
+ ## Running the test suite
317
+
318
+ You need to have an instance of MongoDB running on your computer or all the mongo tests will fail miserably.
319
+
320
+ rake test
321
+
322
+ ## Integration tests
323
+
324
+ If you make changes or add features to the jQuery part, please make sure
325
+ you write a cucumber test for it.
326
+
327
+ You can find an example Rails app on the *integration* folder.
328
+
329
+ You can run the integration tests with the cucumber command while on the
330
+ integration folder:
331
+
332
+ cd integration
333
+ rake db:migrate
334
+ cucumber
335
+
336
+ # Thanks to
337
+
338
+ Everyone on [this list](https://github.com/crowdint/rails3-jquery-autocomplete/contributors)
339
+
340
+ # About the Author
341
+
342
+ [Crowd Interactive](http://www.crowdint.com) is an American web design and development company that happens to work in Colima, Mexico.
343
+ We specialize in building and growing online retail stores. We don’t work with everyone – just companies we believe in. Call us today to see if there’s a fit.
344
+ Find more info [here](http://www.crowdint.com)!
345
+
data/Rakefile ADDED
@@ -0,0 +1,28 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rake/testtask'
5
+ require 'rcov/rcovtask'
6
+
7
+ task :default => [:uglify, :test]
8
+
9
+ Rake::TestTask.new(:test) do |test|
10
+ test.libs << 'lib' << 'test'
11
+ test.pattern = 'test/**/*_test.rb'
12
+ test.verbose = true
13
+ end
14
+
15
+ task :uglify do
16
+ require 'uglifier'
17
+ file_folder = "lib/assets/javascripts"
18
+ File.open("#{file_folder}/autocomplete-rails.js", "w") do |f|
19
+ f << Uglifier.compile(File.read("#{file_folder}/autocomplete-rails-uncompressed.js"))
20
+ end
21
+ end
22
+
23
+ Rcov::RcovTask.new do |t|
24
+ t.libs << "test"
25
+ t.test_files = FileList['test/**/*_test.rb']
26
+ t.rcov_opts = %w{--exclude \/gems\/}
27
+ t.verbose = true
28
+ end
@@ -0,0 +1,113 @@
1
+ /*
2
+ * Unobtrusive autocomplete
3
+ *
4
+ * To use it, you just have to include the HTML attribute autocomplete
5
+ * with the autocomplete URL as the value
6
+ *
7
+ * Example:
8
+ * <input type="text" data-autocomplete="/url/to/autocomplete">
9
+ *
10
+ * Optionally, you can use a jQuery selector to specify a field that can
11
+ * be updated with the element id whenever you find a matching value
12
+ *
13
+ * Example:
14
+ * <input type="text" data-autocomplete="/url/to/autocomplete" data-id-element="#id_field">
15
+ */
16
+
17
+ $(document).ready(function(){
18
+ $('input[data-autocomplete]').railsAutocomplete();
19
+ });
20
+
21
+ (function(jQuery)
22
+ {
23
+ var self = null;
24
+ jQuery.fn.railsAutocomplete = function() {
25
+ return this.live('focus',function() {
26
+ if (!this.railsAutoCompleter) {
27
+ this.railsAutoCompleter = new jQuery.railsAutocomplete(this);
28
+ }
29
+ });
30
+ };
31
+
32
+ jQuery.railsAutocomplete = function (e) {
33
+ _e = e;
34
+ this.init(_e);
35
+ };
36
+
37
+ jQuery.railsAutocomplete.fn = jQuery.railsAutocomplete.prototype = {
38
+ railsAutocomplete: '0.0.1'
39
+ };
40
+
41
+ jQuery.railsAutocomplete.fn.extend = jQuery.railsAutocomplete.extend = jQuery.extend;
42
+ jQuery.railsAutocomplete.fn.extend({
43
+ init: function(e) {
44
+ e.delimiter = $(e).attr('data-delimiter') || null;
45
+ function split( val ) {
46
+ return val.split( e.delimiter );
47
+ }
48
+ function extractLast( term ) {
49
+ return split( term ).pop().replace(/^\s+/,"");
50
+ }
51
+
52
+ $(e).autocomplete({
53
+ source: function( request, response ) {
54
+ $.getJSON( $(e).attr('data-autocomplete'), {
55
+ term: extractLast( request.term )
56
+ }, function() {
57
+ $(arguments[0]).each(function(i, el) {
58
+ var obj = {};
59
+ obj[el.id] = el;
60
+ $(e).data(obj);
61
+ });
62
+ response.apply(null, arguments);
63
+ });
64
+ },
65
+ search: function() {
66
+ // custom minLength
67
+ var term = extractLast( this.value );
68
+ if ( term.length < 2 ) {
69
+ return false;
70
+ }
71
+ },
72
+ focus: function() {
73
+ // prevent value inserted on focus
74
+ return false;
75
+ },
76
+ select: function( event, ui ) {
77
+ var terms = split( this.value );
78
+ // remove the current input
79
+ terms.pop();
80
+ // add the selected item
81
+ terms.push( ui.item.value );
82
+ // add placeholder to get the comma-and-space at the end
83
+ if (e.delimiter != null) {
84
+ terms.push( "" );
85
+ this.value = terms.join( e.delimiter );
86
+ } else {
87
+ this.value = terms.join("");
88
+ if ($(this).attr('data-id-element')) {
89
+ $($(this).attr('data-id-element')).val(ui.item.id);
90
+ }
91
+ if ($(this).attr('data-update-elements')) {
92
+ var data = $(this).data(ui.item.id.toString());
93
+ var update_elements = $.parseJSON($(this).attr("data-update-elements"));
94
+ for (var key in update_elements) {
95
+ $(update_elements[key]).val(data[key]);
96
+ }
97
+ }
98
+ }
99
+ var remember_string = this.value;
100
+ $(this).bind('keyup.clearId', function(){
101
+ if($(this).val().trim() != remember_string.trim()){
102
+ $($(this).attr('data-id-element')).val("");
103
+ $(this).unbind('keyup.clearId');
104
+ }
105
+ });
106
+ $(this).trigger('railsAutocomplete.select', ui);
107
+
108
+ return false;
109
+ }
110
+ });
111
+ }
112
+ });
113
+ })(jQuery);
@@ -0,0 +1,16 @@
1
+ /*
2
+ * Unobtrusive autocomplete
3
+ *
4
+ * To use it, you just have to include the HTML attribute autocomplete
5
+ * with the autocomplete URL as the value
6
+ *
7
+ * Example:
8
+ * <input type="text" data-autocomplete="/url/to/autocomplete">
9
+ *
10
+ * Optionally, you can use a jQuery selector to specify a field that can
11
+ * be updated with the element id whenever you find a matching value
12
+ *
13
+ * Example:
14
+ * <input type="text" data-autocomplete="/url/to/autocomplete" data-id-element="#id_field">
15
+ */
16
+ $(document).ready(function(){$("input[data-autocomplete]").railsAutocomplete()}),function(a){var b=null;a.fn.railsAutocomplete=function(){return this.live("focus",function(){this.railsAutoCompleter||(this.railsAutoCompleter=new a.railsAutocomplete(this))})},a.railsAutocomplete=function(a){_e=a,this.init(_e)},a.railsAutocomplete.fn=a.railsAutocomplete.prototype={railsAutocomplete:"0.0.1"},a.railsAutocomplete.fn.extend=a.railsAutocomplete.extend=a.extend,a.railsAutocomplete.fn.extend({init:function(a){function b(b){return b.split(a.delimiter)}function c(a){return b(a).pop().replace(/^\s+/,"")}a.delimiter=$(a).attr("data-delimiter")||null,$(a).autocomplete({source:function(b,d){$.getJSON($(a).attr("data-autocomplete"),{term:c(b.term)},function(){$(arguments[0]).each(function(b,c){var d={};d[c.id]=c,$(a).data(d)}),d.apply(null,arguments)})},search:function(){var a=c(this.value);if(a.length<2)return!1},focus:function(){return!1},select:function(c,d){var f=b(this.value);f.pop(),f.push(d.item.value);if(a.delimiter!=null)f.push(""),this.value=f.join(a.delimiter);else{this.value=f.join(""),$(this).attr("data-id-element")&&$($(this).attr("data-id-element")).val(d.item.id);if($(this).attr("data-update-elements")){var g=$(this).data(d.item.id.toString()),h=$.parseJSON($(this).attr("data-update-elements"));for(var i in h)$(h[i]).val(g[i])}}var j=this.value;return $(this).bind("keyup.clearId",function(){$(this).val().trim()!=j.trim()&&($($(this).attr("data-id-element")).val(""),$(this).unbind("keyup.clearId"))}),$(this).trigger("railsAutocomplete.select",d),!1}})}})}(jQuery)
@@ -0,0 +1,6 @@
1
+ Given /^I choose "([^"]*)" in the autocomplete list$/ do |text|
2
+ page.execute_script %Q{ $('input[data-autocomplete]').trigger("focus") }
3
+ page.execute_script %Q{ $('input[data-autocomplete]').trigger("keydown") }
4
+ sleep 1
5
+ page.execute_script %Q{ $('.ui-menu-item a:contains("#{text}")').trigger("mouseenter").trigger("click"); }
6
+ end
@@ -0,0 +1,14 @@
1
+ require 'rails/generators'
2
+
3
+ module Autocomplete
4
+ class InstallGenerator < Rails::Generators::Base
5
+ def install
6
+ # Copy the unobtrusive JS file
7
+ copy_file('autocomplete-rails.js', 'public/javascripts/autocomplete-rails.js')
8
+ end
9
+
10
+ def self.source_root
11
+ File.join(File.dirname(__FILE__), '..', '..', 'assets', 'javascripts')
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ require 'rails/generators'
2
+
3
+ module Autocomplete
4
+ class UncompressedGenerator < Rails::Generators::Base
5
+ def install
6
+ # Copy the unobtrusive JS file
7
+ copy_file('autocomplete-rails-uncompressed.js', 'public/javascripts/autocomplete-rails.js')
8
+ end
9
+
10
+ def self.source_root
11
+ File.join(File.dirname(__FILE__), '..', '..', 'assets', 'javascripts')
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,23 @@
1
+ require 'rails3-jquery-autocomplete/form_helper'
2
+ require 'rails3-jquery-autocomplete/autocomplete'
3
+
4
+ module Rails3JQueryAutocomplete
5
+ autoload :Orm , 'rails3-jquery-autocomplete/orm'
6
+ autoload :FormtasticPlugin , 'rails3-jquery-autocomplete/formtastic_plugin'
7
+
8
+ unless ::Rails.version < "3.1"
9
+ require 'rails3-jquery-autocomplete/rails/engine'
10
+ end
11
+ end
12
+
13
+ class ActionController::Base
14
+ include Rails3JQueryAutocomplete::Autocomplete
15
+ end
16
+
17
+ require 'rails3-jquery-autocomplete/formtastic'
18
+
19
+ begin
20
+ require 'simple_form'
21
+ require 'rails3-jquery-autocomplete/simple_form_plugin'
22
+ rescue LoadError
23
+ end
@@ -0,0 +1,110 @@
1
+ module Rails3JQueryAutocomplete
2
+ module Autocomplete
3
+ def self.included(target)
4
+ target.extend Rails3JQueryAutocomplete::Autocomplete::ClassMethods
5
+
6
+ target.send :include, Rails3JQueryAutocomplete::Orm::Mongoid if defined?(Mongoid::Document)
7
+ target.send :include, Rails3JQueryAutocomplete::Orm::MongoMapper if defined?(MongoMapper::Document)
8
+ target.send :include, Rails3JQueryAutocomplete::Orm::ActiveRecord
9
+ end
10
+
11
+ #
12
+ # Usage:
13
+ #
14
+ # class ProductsController < Admin::BaseController
15
+ # autocomplete :brand, :name
16
+ # end
17
+ #
18
+ # This will magically generate an action autocomplete_brand_name, so,
19
+ # don't forget to add it on your routes file
20
+ #
21
+ # resources :products do
22
+ # get :autocomplete_brand_name, :on => :collection
23
+ # end
24
+ #
25
+ # Now, on your view, all you have to do is have a text field like:
26
+ #
27
+ # f.text_field :brand_name, :autocomplete => autocomplete_brand_name_products_path
28
+ #
29
+ #
30
+ # Yajl is used by default to encode results, if you want to use a different encoder
31
+ # you can specify your custom encoder via block
32
+ #
33
+ # class ProductsController < Admin::BaseController
34
+ # autocomplete :brand, :name do |items|
35
+ # CustomJSONEncoder.encode(items)
36
+ # end
37
+ # end
38
+ #
39
+ module ClassMethods
40
+ def autocomplete(object, method, options = {})
41
+ define_method("get_prefix") do |model|
42
+ if model.superclass == ActiveRecord::Base
43
+ 'active_record'
44
+ elsif model.superclass == Object && model.include?(Mongoid::Document)
45
+ 'mongoid'
46
+ elsif model.superclass == Object && model.include?(MongoMapper::Document)
47
+ 'mongo_mapper'
48
+ end
49
+ end
50
+
51
+ define_method("get_autocomplete_order") do |method, options, model=nil|
52
+ method("#{get_prefix(get_object(options[:class_name] || object))}_get_autocomplete_order").call(method, options, model)
53
+ end
54
+
55
+ define_method("get_autocomplete_items") do |parameters|
56
+ method("#{get_prefix(get_object(options[:class_name] || object))}_get_autocomplete_items").call(parameters)
57
+ end
58
+
59
+ define_method("autocomplete_#{object}_#{method}") do
60
+
61
+ method = options[:column_name] if options.has_key?(:column_name)
62
+
63
+ term = params[:term]
64
+
65
+ if term && !term.blank?
66
+ #allow specifying fully qualified class name for model object
67
+ class_name = options[:class_name] || object
68
+ items = get_autocomplete_items(:model => get_object(class_name), \
69
+ :options => options, :term => term, :method => method)
70
+ else
71
+ items = {}
72
+ end
73
+
74
+ render :json => json_for_autocomplete(items, options[:display_value] ||= method, options[:extra_data])
75
+ end
76
+ end
77
+ end
78
+
79
+ # Returns a limit that will be used on the query
80
+ def get_autocomplete_limit(options)
81
+ options[:limit] ||= 10
82
+ end
83
+
84
+ # Returns parameter model_sym as a constant
85
+ #
86
+ # get_object(:actor)
87
+ # # returns a Actor constant supposing it is already defined
88
+ #
89
+ def get_object(model_sym)
90
+ object = model_sym.to_s.camelize.constantize
91
+ end
92
+
93
+ #
94
+ # Returns a hash with three keys actually used by the Autocomplete jQuery-ui
95
+ # Can be overriden to show whatever you like
96
+ # Hash also includes a key/value pair for each method in extra_data
97
+ #
98
+ def json_for_autocomplete(items, method, extra_data=[])
99
+ items.collect do |item|
100
+ hash = {"id" => item.id.to_s, "label" => item.send(method), "value" => item.send(method)}
101
+ extra_data.each do |datum|
102
+ hash[datum] = item.send(datum)
103
+ end if extra_data
104
+ # TODO: Come back to remove this if clause when test suite is better
105
+ hash
106
+ end
107
+ end
108
+ end
109
+ end
110
+
@@ -0,0 +1,47 @@
1
+ module ActionView
2
+ module Helpers
3
+ module FormHelper
4
+ # Returns an input tag of the "text" type tailored for accessing a specified attribute (identified by +method+) and
5
+ # that is populated with jQuery's autocomplete plugin.
6
+ #
7
+ # ==== Examples
8
+ # autocomplete_field(:post, :title, author_autocomplete_path, :size => 20)
9
+ # # => <input type="text" id="post_title" name="post[title]" size="20" value="#{@post.title}" data-autocomplete="author/autocomplete"/>
10
+ #
11
+ def autocomplete_field(object_name, method, source, options ={})
12
+ options["data-autocomplete"] = source
13
+ text_field(object_name, method, rewrite_autocomplete_option(options))
14
+ end
15
+ end
16
+
17
+ module FormTagHelper
18
+ # Creates a standard text field that can be populated with jQuery's autocomplete plugin
19
+ #
20
+ # ==== Examples
21
+ # autocomplete_field_tag 'address', '', address_autocomplete_path, :size => 75
22
+ # # => <input id="address" name="address" size="75" type="text" value="" data-autocomplete="address/autocomplete"/>
23
+ #
24
+ def autocomplete_field_tag(name, value, source, options ={})
25
+ options["data-autocomplete"] = source
26
+ text_field_tag(name, value, rewrite_autocomplete_option(options))
27
+ end
28
+ end
29
+
30
+ #
31
+ # Method used to rename the autocomplete key to a more standard
32
+ # data-autocomplete key
33
+ #
34
+ private
35
+ def rewrite_autocomplete_option(options)
36
+ options["data-update-elements"] = JSON.generate(options.delete :update_elements) if options[:update_elements]
37
+ options["data-id-element"] = options.delete :id_element if options[:id_element]
38
+ options
39
+ end
40
+ end
41
+ end
42
+
43
+ class ActionView::Helpers::FormBuilder #:nodoc:
44
+ def autocomplete_field(method, source, options = {})
45
+ @template.autocomplete_field(@object_name, method, source, objectify_options(options))
46
+ end
47
+ end
@@ -0,0 +1,41 @@
1
+ #
2
+ # Load the formtastic plugin if using Formtastic
3
+ #
4
+ begin
5
+ require 'formtastic'
6
+ begin
7
+ require "formtastic/version"
8
+ rescue LoadError
9
+ end
10
+
11
+ if defined?(Formtastic::VERSION)
12
+ #
13
+ # Formtastic 2.x
14
+ #
15
+
16
+ module Formtastic
17
+ module Inputs
18
+ class AutocompleteInput
19
+ include Base
20
+ include Base::Stringish
21
+
22
+ def to_html
23
+ input_wrapping do
24
+ label_html <<
25
+ builder.autocomplete_field(method, options.delete(:url), input_html_options)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ else
32
+
33
+ #
34
+ # Formtastic 1.x
35
+ #
36
+ class Formtastic::SemanticFormBuilder < ActionView::Helpers::FormBuilder
37
+ include Rails3JQueryAutocomplete::FormtasticPlugin
38
+ end
39
+ end
40
+ rescue LoadError
41
+ end
@@ -0,0 +1,44 @@
1
+ module Rails3JQueryAutocomplete
2
+ module FormtasticPlugin
3
+ def autocomplete_input(method, options = {})
4
+ if options.key?(:selected) || options.key?(:checked) || options.key?(:default)
5
+ ::ActiveSupport::Deprecation.warn(
6
+ "The :selected, :checked (and :default) options are deprecated in Formtastic and will be removed from 1.0. " <<
7
+ "Please set default values in your models (using an after_initialize callback) or in your controller set-up. " <<
8
+ "See http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html for more information.", caller)
9
+ end
10
+
11
+ options[:required] = method_required?(method) unless options.key?(:required)
12
+ options[:as] ||= "autocompleted_string"
13
+
14
+ html_class = [ options[:as], (options[:required] ? :required : :optional) ]
15
+ html_class << 'error' if @object && @object.respond_to?(:errors) && !@object.errors[method.to_sym].blank?
16
+
17
+ wrapper_html = options.delete(:wrapper_html) || {}
18
+ wrapper_html[:id] ||= generate_html_id(method)
19
+ wrapper_html[:class] = (html_class << wrapper_html[:class]).flatten.compact.join(' ')
20
+
21
+ if options[:input_html] && options[:input_html][:id]
22
+ options[:label_html] ||= {}
23
+ options[:label_html][:for] ||= options[:input_html][:id]
24
+ end
25
+
26
+ input_parts = self.class.inline_order.dup
27
+ input_parts = input_parts - [:errors, :hints] if options[:as] == :hidden
28
+
29
+ list_item_content = input_parts.map do |type|
30
+ send(:"inline_#{type}_for", method, options)
31
+ end.compact.join("\n")
32
+
33
+ return template.content_tag(:li, Formtastic::Util.html_safe(list_item_content), wrapper_html)
34
+ end
35
+
36
+ alias_method :autocompleted_input, :autocomplete_input
37
+
38
+
39
+ protected
40
+ def autocompleted_string_input(method, options)
41
+ self.label(method, options_for_label(options)) << autocomplete_field(method, options.delete(:url), options)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,8 @@
1
+ module Rails3JQueryAutocomplete
2
+ module Orm
3
+ autoload :ActiveRecord , 'rails3-jquery-autocomplete/orm/active_record'
4
+ autoload :Mongoid , 'rails3-jquery-autocomplete/orm/mongoid'
5
+ autoload :MongoMapper , 'rails3-jquery-autocomplete/orm/mongo_mapper'
6
+ end
7
+ end
8
+
@@ -0,0 +1,47 @@
1
+ module Rails3JQueryAutocomplete
2
+ module Orm
3
+ module ActiveRecord
4
+ def active_record_get_autocomplete_order(method, options, model=nil)
5
+ order = options[:order]
6
+
7
+ table_prefix = model ? "#{model.table_name}." : ""
8
+ order || "#{table_prefix}#{method} ASC"
9
+ end
10
+
11
+ def active_record_get_autocomplete_items(parameters)
12
+ model = parameters[:model]
13
+ term = parameters[:term]
14
+ method = parameters[:method]
15
+ options = parameters[:options]
16
+ scopes = Array(options[:scopes])
17
+ limit = get_autocomplete_limit(options)
18
+ order = active_record_get_autocomplete_order(method, options, model)
19
+
20
+
21
+ items = model.scoped
22
+
23
+ scopes.each { |scope| items = items.send(scope) } unless scopes.empty?
24
+
25
+ items = items.select(get_autocomplete_select_clause(model, method, options)) unless options[:full_model]
26
+ items = items.where(get_autocomplete_where_clause(model, term, method, options)).
27
+ limit(limit).order(order)
28
+ end
29
+
30
+ def get_autocomplete_select_clause(model, method, options)
31
+ table_name = model.table_name
32
+ (["#{table_name}.#{model.primary_key}", "#{table_name}.#{method}"] + (options[:extra_data].blank? ? [] : options[:extra_data]))
33
+ end
34
+
35
+ def get_autocomplete_where_clause(model, term, method, options)
36
+ table_name = model.table_name
37
+ is_full_search = options[:full]
38
+ like_clause = (postgres? ? 'ILIKE' : 'LIKE')
39
+ ["LOWER(#{table_name}.#{method}) #{like_clause} ?", "#{(is_full_search ? '%' : '')}#{term.downcase}%"]
40
+ end
41
+
42
+ def postgres?
43
+ defined?(PGconn)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,30 @@
1
+ module Rails3JQueryAutocomplete
2
+ module Orm
3
+ module MongoMapper
4
+ def mongo_mapper_get_autocomplete_order(method, options, model=nil)
5
+ order = options[:order]
6
+ if order
7
+ order.split(',').collect do |fields|
8
+ sfields = fields.split
9
+ [sfields[0].downcase.to_sym, sfields[1].downcase.to_sym]
10
+ end
11
+ else
12
+ [[method.to_sym, :asc]]
13
+ end
14
+ end
15
+
16
+ def mongo_mapper_get_autocomplete_items(parameters)
17
+ model = parameters[:model]
18
+ method = parameters[:method]
19
+ options = parameters[:options]
20
+ is_full_search = options[:full]
21
+ term = parameters[:term]
22
+ limit = get_autocomplete_limit(options)
23
+ order = mongo_mapper_get_autocomplete_order(method, options)
24
+
25
+ search = (is_full_search ? '.*' : '^') + term + '.*'
26
+ items = model.where(method.to_sym => /#{search}/i).limit(limit).sort(order)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,34 @@
1
+ module Rails3JQueryAutocomplete
2
+ module Orm
3
+ module Mongoid
4
+ def mongoid_get_autocomplete_order(method, options, model=nil)
5
+ order = options[:order]
6
+ if order
7
+ order.split(',').collect do |fields|
8
+ sfields = fields.split
9
+ [sfields[0].downcase.to_sym, sfields[1].downcase.to_sym]
10
+ end
11
+ else
12
+ [[method.to_sym, :asc]]
13
+ end
14
+ end
15
+
16
+ def mongoid_get_autocomplete_items(parameters)
17
+ model = parameters[:model]
18
+ method = parameters[:method]
19
+ options = parameters[:options]
20
+ is_full_search = options[:full]
21
+ term = parameters[:term]
22
+ limit = get_autocomplete_limit(options)
23
+ order = mongoid_get_autocomplete_order(method, options)
24
+
25
+ if is_full_search
26
+ search = '.*' + term + '.*'
27
+ else
28
+ search = '^' + term
29
+ end
30
+ items = model.where(method.to_sym => /#{search}/i).limit(limit).order_by(order)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,5 @@
1
+ module Rails3JQueryAutocomplete
2
+ module Rails
3
+ class Engine < ::Rails::Engine ; end
4
+ end
5
+ end
@@ -0,0 +1,25 @@
1
+ module SimpleForm
2
+ module Inputs
3
+ class AutocompleteInput < Base
4
+ def input
5
+ @builder.autocomplete_field(attribute_name, options[:url], input_html_options)
6
+ end
7
+
8
+ protected
9
+
10
+ def limit
11
+ column && column.limit
12
+ end
13
+
14
+ def has_placeholder?
15
+ placeholder_present?
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ module SimpleForm
22
+ class FormBuilder
23
+ map_type :autocomplete, :to => SimpleForm::Inputs::AutocompleteInput
24
+ end
25
+ end
@@ -0,0 +1,3 @@
1
+ module Rails3JQueryAutocomplete
2
+ VERSION = '1.0.4'
3
+ end
@@ -0,0 +1,12 @@
1
+ module Steak
2
+ module Autocomplete
3
+ def choose_autocomplete_result(text, input_id="input[data-autocomplete]")
4
+ page.execute_script %Q{ $('#{input_id}').trigger("focus") }
5
+ page.execute_script %Q{ $('#{input_id}').trigger("keydown") }
6
+ sleep 1
7
+ page.execute_script %Q{ $('.ui-menu-item a:contains("#{text}")').trigger("mouseenter").trigger("click"); }
8
+ end
9
+ end
10
+ end
11
+
12
+ RSpec.configuration.include Steak::Autocomplete, :type => :acceptance
metadata ADDED
@@ -0,0 +1,210 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wf-rails3-jquery-autocomplete
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.4
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - David Padilla
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-09-18 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '3.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '3.0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: sqlite3-ruby
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: mongoid
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: 2.0.0
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: 2.0.0
62
+ - !ruby/object:Gem::Dependency
63
+ name: mongo_mapper
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0.9'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0.9'
78
+ - !ruby/object:Gem::Dependency
79
+ name: bson_ext
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: 1.3.0
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: 1.3.0
94
+ - !ruby/object:Gem::Dependency
95
+ name: shoulda
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ~>
100
+ - !ruby/object:Gem::Version
101
+ version: 2.11.1
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ version: 2.11.1
110
+ - !ruby/object:Gem::Dependency
111
+ name: uglifier
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: rr
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ - !ruby/object:Gem::Dependency
143
+ name: rcov
144
+ requirement: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ! '>='
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ type: :development
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ description: Use jQuery's autocomplete plugin with Rails 3.
159
+ email: david.padilla@crowdint.com
160
+ executables: []
161
+ extensions: []
162
+ extra_rdoc_files: []
163
+ files:
164
+ - lib/assets/javascripts/autocomplete-rails-uncompressed.js
165
+ - lib/assets/javascripts/autocomplete-rails.js
166
+ - lib/cucumber/autocomplete.rb
167
+ - lib/generators/autocomplete/install_generator.rb
168
+ - lib/generators/autocomplete/uncompressed_generator.rb
169
+ - lib/rails3-jquery-autocomplete/autocomplete.rb
170
+ - lib/rails3-jquery-autocomplete/formtastic.rb
171
+ - lib/rails3-jquery-autocomplete/formtastic_plugin.rb
172
+ - lib/rails3-jquery-autocomplete/form_helper.rb
173
+ - lib/rails3-jquery-autocomplete/orm/active_record.rb
174
+ - lib/rails3-jquery-autocomplete/orm/mongoid.rb
175
+ - lib/rails3-jquery-autocomplete/orm/mongo_mapper.rb
176
+ - lib/rails3-jquery-autocomplete/orm.rb
177
+ - lib/rails3-jquery-autocomplete/rails/engine.rb
178
+ - lib/rails3-jquery-autocomplete/simple_form_plugin.rb
179
+ - lib/rails3-jquery-autocomplete/version.rb
180
+ - lib/rails3-jquery-autocomplete.rb
181
+ - lib/steak/autocomplete.rb
182
+ - CHANGELOG.md
183
+ - LICENSE
184
+ - README.md
185
+ - Rakefile
186
+ homepage: http://github.com/crowdint/rails3-jquery-autocomplete
187
+ licenses: []
188
+ post_install_message:
189
+ rdoc_options: []
190
+ require_paths:
191
+ - lib
192
+ required_ruby_version: !ruby/object:Gem::Requirement
193
+ none: false
194
+ requirements:
195
+ - - ! '>='
196
+ - !ruby/object:Gem::Version
197
+ version: '0'
198
+ required_rubygems_version: !ruby/object:Gem::Requirement
199
+ none: false
200
+ requirements:
201
+ - - ! '>='
202
+ - !ruby/object:Gem::Version
203
+ version: '0'
204
+ requirements: []
205
+ rubyforge_project:
206
+ rubygems_version: 1.8.24
207
+ signing_key:
208
+ specification_version: 3
209
+ summary: Use jQuery's autocomplete plugin with Rails 3.
210
+ test_files: []