rails4-autocomplete 1.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +31 -0
  3. data/README.md +374 -0
  4. data/Rakefile +21 -0
  5. data/lib/assets/javascripts/autocomplete-rails-uncompressed.js +136 -0
  6. data/lib/assets/javascripts/autocomplete-rails.js +16 -0
  7. data/lib/cucumber/autocomplete.rb +6 -0
  8. data/lib/generators/autocomplete/install_generator.rb +14 -0
  9. data/lib/generators/autocomplete/uncompressed_generator.rb +14 -0
  10. data/lib/rails4-autocomplete.rb +23 -0
  11. data/lib/rails4-autocomplete/autocomplete.rb +96 -0
  12. data/lib/rails4-autocomplete/form_helper.rb +47 -0
  13. data/lib/rails4-autocomplete/formtastic.rb +41 -0
  14. data/lib/rails4-autocomplete/formtastic_plugin.rb +44 -0
  15. data/lib/rails4-autocomplete/orm.rb +8 -0
  16. data/lib/rails4-autocomplete/orm/active_record.rb +52 -0
  17. data/lib/rails4-autocomplete/orm/mongo_mapper.rb +30 -0
  18. data/lib/rails4-autocomplete/orm/mongoid.rb +34 -0
  19. data/lib/rails4-autocomplete/rails/engine.rb +5 -0
  20. data/lib/rails4-autocomplete/simple_form_plugin.rb +84 -0
  21. data/lib/rails4-autocomplete/version.rb +3 -0
  22. data/lib/steak/autocomplete.rb +12 -0
  23. data/test/form_helper_test.rb +25 -0
  24. data/test/generators/autocomplete/install_generator_test.rb +25 -0
  25. data/test/generators/autocomplete/uncompressed_generator_test.rb +25 -0
  26. data/test/lib/rails3-jquery-autocomplete/autocomplete_test.rb +59 -0
  27. data/test/lib/rails3-jquery-autocomplete/orm/active_record_test.rb +145 -0
  28. data/test/lib/rails3-jquery-autocomplete/orm/mongo_mapper_test.rb +60 -0
  29. data/test/lib/rails3-jquery-autocomplete/orm/mongoid_test.rb +60 -0
  30. data/test/lib/rails3-jquery-autocomplete/simple_form_plugin_test.rb +33 -0
  31. data/test/lib/rails3-jquery-autocomplete_test.rb +38 -0
  32. data/test/test_helper.rb +36 -0
  33. data/test/view_test_helper.rb +108 -0
  34. metadata +268 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bbd2893b5dac4681f3d01468635ce4b6b096dbf0
4
+ data.tar.gz: 19d5c6f5ad87f1a1c420fa203358533b3b93e133
5
+ SHA512:
6
+ metadata.gz: 83ccea6859af39f9d34ba067e52a33fb5589bf527617d6c0b99590247b422fa4ba67da59f902994a9e3a05280259dcc3cb14eb619b189b53abca15f36db5d973
7
+ data.tar.gz: 8e51caab6b1c3736b807d4ab4527edf125e5633af0fc38804c5c009c3f734f9903f16208f7303db03b5ad6ea43b1fac16834c4b8ded2a83f85c63ccd4ccb6b06
@@ -0,0 +1,31 @@
1
+ # Changelog
2
+
3
+ * 1.0.7
4
+ * mongoid: escape regular expression in search
5
+ * When possible, use jQuery .on() rather than .live()
6
+ * 1.0.6 Postgres or non-postgres queries are now determined at model level
7
+ * 1.0.3 Fixed Formtastic 2.0 + Ruby 1.8.7 compat issue
8
+ * 1.0.2 Fixed issue #93, #94
9
+ * 1.0.1 Formtastic 2.0 compatibility fix
10
+ * 1.0.0 Rails 3.1 asset pipeline support
11
+ * 0.9.1 Fixes issues #96 and #32
12
+ * 0.9.0 Massive rewrite
13
+ * 0.8.0 Compressed JS file
14
+ * 0.7.5 Pull request #46
15
+ * 0.7.4 Allows Rails 3.1
16
+ * 0.7.3 MongoMapper
17
+ * 0.7.2 Steak helper
18
+ * 0.7.1 Fixed joined scopes (Issue #43)
19
+ * 0.7.0 Scopes
20
+ * 0.6.6 ILIKE for postgres
21
+ * 0.6.5 JS select event
22
+ * 0.6.4 Use YAJL instead of JSON
23
+ * 0.6.3 SimpleForm plugin
24
+ * 0.6.2 Fix Issue #8
25
+ * 0.6.1 Allow specifying fully qualified class name for model object as an option to autocomplete
26
+ * 0.6.0 JS Code cleanup
27
+ * 0.5.1 Add STI support
28
+ * 0.5.0 Formtastic support
29
+ * 0.4.0 MongoID support
30
+ * 0.3.6 Using .live() to put autocomplete on dynamic fields
31
+
@@ -0,0 +1,374 @@
1
+ ## Status
2
+
3
+ Unfortunately, I don't have much time to work on this gem, I'm looking for
4
+ someone to help with its maintenance. Send me an email if you are interested in
5
+ getting push privileges to this repo.
6
+
7
+
8
+ # rails4-autocomplete
9
+
10
+ An easy way to use jQuery's autocomplete with Rails 4.
11
+
12
+ Supports both ActiveRecord, [mongoid](http://github.com/mongoid/mongoid), and [MongoMapper](https://github.com/jnunemaker/mongomapper).
13
+
14
+ Works with [Formtastic](http://github.com/justinfrench/formtastic)
15
+ and [SimpleForm](https://github.com/plataformatec/simple_form)
16
+
17
+ ## ActiveRecord
18
+
19
+ You can find a [detailed example](http://github.com/crowdint/rails3-jquery-autocomplete-app)
20
+ on how to use this gem with ActiveRecord [here](http://github.com/crowdint/rails3-jquery-autocomplete-app).
21
+
22
+ ## MongoID
23
+
24
+ You can find a [detailed example](http://github.com/crowdint/rails3-jquery-autocomplete-app/tree/mongoid)
25
+ on how to use this gem with MongoID [here](http://github.com/crowdint/rails3-jquery-autocomplete-app/tree/mongoid). (Same thing, different branch)
26
+
27
+ ## Before you start
28
+
29
+ Make sure your project is using jQuery-UI and the autocomplete widget
30
+ before you continue.
31
+
32
+ You can find more info about that here:
33
+
34
+ * http://jquery.com/
35
+ * http://jqueryui.com/demos/autocomplete/
36
+ * http://github.com/rails/jquery-ujs
37
+
38
+ I'd encourage you to understand how to use those 3 amazing tools before attempting to use this gem.
39
+
40
+ ## Installing
41
+
42
+ Include the gem on your Gemfile
43
+
44
+ gem 'rails4-autocomplete'
45
+
46
+ Install it
47
+
48
+ bundle install
49
+
50
+ ### Rails 3.0.x
51
+
52
+ Run the generator
53
+
54
+ rails generate autocomplete:install
55
+
56
+ And include autocomplete-rails.js on your layouts
57
+
58
+ javascript_include_tag "autocomplete-rails.js"
59
+
60
+ #### Upgrading from older versions
61
+
62
+ If you are upgrading from a previous version, run the generator after installing to replace the javascript file.
63
+
64
+ rails generate autocomplete:install
65
+
66
+ I'd recommend you do this every time you update to make sure you have the latest JS file.
67
+
68
+ #### Uncompressed Javascript file
69
+
70
+ If you want to make changes to the JS file, you can install the
71
+ uncompressed version by running:
72
+
73
+ rails generate autocomplete:uncompressed
74
+
75
+ ### Rails 4.x
76
+
77
+ Just add it to your app/assets/javascripts/application.js file
78
+
79
+ //= require jquery
80
+ //= require jquery_ujs
81
+ //= require jquery-ui
82
+ //= require autocomplete-rails
83
+
84
+ ## Usage
85
+
86
+ ### Model Example
87
+
88
+ Assuming you have a Brand model:
89
+
90
+ class Brand < ActiveRecord::Base
91
+ end
92
+
93
+ create_table :brand do |t|
94
+ t.column :name, :string
95
+ end
96
+
97
+ ### Controller
98
+
99
+ To set up the required action on your controller, all you have to do is call it with the class name and the method
100
+ as in the following example:
101
+
102
+ class ProductsController < Admin::BaseController
103
+ autocomplete :brand, :name
104
+ end
105
+
106
+ This will create an action _autocomplete_brand_name_ on your controller, don't forget to add it on your routes file
107
+
108
+ resources :products do
109
+ get :autocomplete_brand_name, :on => :collection
110
+ end
111
+
112
+ ### Options
113
+
114
+ #### :full => true
115
+
116
+ 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.
117
+
118
+ class ProductsController < Admin::BaseController
119
+ autocomplete :brand, :name, :full => true
120
+ end
121
+
122
+ The following terms would match the query 'un':
123
+
124
+ * Luna
125
+ * Unacceptable
126
+ * Rerun
127
+
128
+ #### :full => false (default behavior)
129
+
130
+ Only the following terms mould match the query 'un':
131
+
132
+ * Unacceptable
133
+
134
+ #### :extra_data
135
+
136
+ 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).
137
+
138
+ Passing an array of attributes/column names to this option will fetch and return the specified data.
139
+
140
+ class ProductsController < Admin::BaseController
141
+ autocomplete :brand, :name, :extra_data => [:slogan]
142
+ end
143
+
144
+ #### :display_value
145
+
146
+ If you want to display a different version of what you're looking for, you can use the :display_value option.
147
+
148
+ This options receives a method name as the parameter, and that method will be called on the instance when displaying the results.
149
+
150
+ class Brand < ActiveRecord::Base
151
+ def funky_method
152
+ "#{self.name}.camelize"
153
+ end
154
+ end
155
+
156
+
157
+ class ProductsController < Admin::BaseController
158
+ autocomplete :brand, :name, :display_value => :funky_method
159
+ end
160
+
161
+ In the example above, you will search by _name_, but the autocomplete list will display the result of _funky_method_
162
+
163
+ This wouldn't really make much sense unless you use it with the "id_element" attribute. (See below)
164
+
165
+ 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
166
+
167
+
168
+ #### :scopes
169
+ Added option to use scopes. Pass scopes in an array.
170
+ e.g `:scopes => [:scope1, :scope2]`
171
+
172
+ #### :column_name
173
+ By default autocomplete uses method name as column name. Now it can be specified using column_name options
174
+ `:column_name => 'name'`
175
+
176
+ #### json encoder
177
+ Autocomplete uses Yajl as JSON encoder/decoder, but you can specify your own
178
+
179
+ class ProductsController < Admin::BaseController
180
+ autocomplete :brand, :name do |items|
181
+ CustomJSON::Encoder.encode(items)
182
+ end
183
+ end
184
+
185
+ ### View
186
+
187
+ On your view, all you have to do is include the attribute autocomplete on the text field
188
+ using the url to the autocomplete action as the value.
189
+
190
+ form_for @product do |f|
191
+ f.autocomplete_field :brand_name, autocomplete_brand_name_products_path
192
+ end
193
+
194
+ This will generate an HTML tag that looks like:
195
+
196
+ <input type="text" data-autocomplete="products/autocomplete_brand_name">
197
+
198
+ 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
199
+ *autocomplete_field_tag* helper.
200
+
201
+ form_tag 'some/path'
202
+ autocomplete_field_tag 'address', '', address_autocomplete_path, :size => 75
203
+ end
204
+
205
+ #### Multiple Values Separated by Delimiter
206
+
207
+ To generate an autocomplete input field that accepts multiple values separated by a given delimiter, add the `'data-delimiter'` and `:multiple` options:
208
+
209
+ form_for @product do |f|
210
+ f.autocomplete_field :brand_names, autocomplete_brand_name_products_path,
211
+ 'data-delimiter' => ',', :multiple => true
212
+ end
213
+
214
+ NOTE: Setting the `:multiple` option to `true` will result in the chosen values being submitted as an array. Leaving this option off will result in the values being passed as a single string, with the values separated by your chosen delimiter.
215
+
216
+ Now your autocomplete code is unobtrusive, Rails 3 style.
217
+
218
+ ### Getting the object id
219
+
220
+ If you need to use the id of the selected object, you can use the *id_element* attribute too:
221
+
222
+ f.autocomplete_field :brand_name, autocomplete_brand_name_products_path, :id_element => '#some_element'
223
+
224
+ 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.
225
+
226
+ ### Getting extra object data
227
+
228
+ If you need to extra data about the selected object, you can use the *:update_elements* HTML attribute.
229
+
230
+ 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:
231
+
232
+ f.autocomplete_field :brand_name, autocomplete_brand_name_products_path, :update_elements => {:id => '#id_element', :slogan => '#some_other_element'}
233
+
234
+ class ProductsController < Admin::BaseController
235
+ autocomplete :brand, :name, :extra_data => [:slogan]
236
+ end
237
+
238
+ The previous example would fetch the extra attribute slogan and update jQuery('#some_other_element') with the slogan value.
239
+
240
+ ### Running custom code on selection
241
+
242
+ 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:
243
+
244
+ $('#my_autocomplete_field').bind('railsAutocomplete.select', function(event, data){
245
+ /* Do something here */
246
+ alert(data.item.id);
247
+ });
248
+
249
+ ## Formtastic
250
+
251
+ If you are using [Formtastic](http://github.com/justinfrench/formtastic), you automatically get the *autocompleted_input* helper on *semantic_form_for*:
252
+
253
+ semantic_form_for @product do |f|
254
+ f.input :brand_name, :as => :autocomplete, :url => autocomplete_brand_name_products_path
255
+ end
256
+
257
+ The only difference with the original helper is that you must specify the autocomplete url using the *:url* option.
258
+
259
+ ## SimpleForm
260
+
261
+ If you want to use it with simple_form, all you have to do is use the
262
+ :as option on the input and set the autocomplete path with the :url
263
+ option.
264
+
265
+
266
+ simple_form_for @product do |form|
267
+ form.input :name
268
+ form.input :brand_name, :url => autocomplete_brand_name_products_path, :as => :autocomplete
269
+
270
+ # Cucumber
271
+
272
+ 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:
273
+
274
+ require 'cucumber/autocomplete'
275
+
276
+ Then you'll have access to the following step:
277
+
278
+ I choose "([^"]*)" in the autocomplete list
279
+
280
+ An example on how to use it:
281
+
282
+ @javascript
283
+ Scenario: Autocomplete
284
+ Given the following brands exists:
285
+ | name |
286
+ | Alpha |
287
+ | Beta |
288
+ | Gamma |
289
+ And I go to the home page
290
+ And I fill in "Brand name" with "al"
291
+ And I choose "Alpha" in the autocomplete list
292
+ Then the "Brand name" field should contain "Alpha"
293
+
294
+ 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).
295
+
296
+ # Steak
297
+
298
+ 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:
299
+
300
+ require 'steak/autocomplete'
301
+
302
+ Then you'll have access to the following helper:
303
+
304
+ choose_autocomplete_result
305
+
306
+ An example on how to use it:
307
+
308
+ scenario "Autocomplete" do
309
+ lambda do
310
+ Brand.create! [
311
+ {:name => "Alpha"},
312
+ {:name => "Beta"},
313
+ {:name => "Gamma"}
314
+ ]
315
+ end.should change(Brand, :count).by(3)
316
+
317
+ visit home_page
318
+ fill_in "Brand name", :with => "al"
319
+ choose_autocomplete_result "Alpha"
320
+ find_field("Brand name").value.should include("Alpha")
321
+ end
322
+
323
+ I have only tested this using Capybara, no idea if it works with something else.
324
+
325
+ # Development
326
+
327
+ If you want to make changes to the gem, first install bundler 1.0.0:
328
+
329
+ gem install bundler
330
+
331
+ And then, install all your dependencies:
332
+
333
+ bundle install
334
+
335
+ ## Running the test suite
336
+
337
+ <strike>You need to have an instance of MongoDB running on your computer or all the mongo tests will fail miserably.</strike>
338
+
339
+ To run all the tests once, simply use
340
+
341
+ rake test
342
+
343
+ while you're developing, it is recommended that you run
344
+
345
+ bundle exec guard
346
+
347
+ to have the relevent test run every time you save a file.
348
+
349
+ ## Integration tests
350
+
351
+ If you make changes or add features to the jQuery part, please make sure
352
+ you write a cucumber test for it.
353
+
354
+ You can find an example Rails app on the *integration* folder.
355
+
356
+ You can run the integration tests with the cucumber command while on the
357
+ integration folder:
358
+
359
+ cd integration
360
+ rake db:migrate
361
+ cucumber
362
+
363
+ ## Where to test what
364
+
365
+ If you're making or tweaking a plugin (such as the formastic plugin or
366
+ simple\_form plugin), check out the simple\_form\_plugin\_test for an
367
+ example of how to test it as part of the main `rake test` run.
368
+ Historically, plugins like these had been tested (shoddily) as part of
369
+ the integration tests. Feel free to remove them from the integration
370
+ suite and move them into the main suite. Your tests will run much
371
+ faster, and there will be less likelihood of your feature breaking in
372
+ the future. Thanks!
373
+
374
+
@@ -0,0 +1,21 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rake/testtask'
5
+
6
+ task :default => [:uglify, :test]
7
+
8
+ Rake::TestTask.new(:test) do |test|
9
+ test.libs << 'lib' << 'test'
10
+ test.pattern = 'test/**/*_test.rb'
11
+ test.verbose = true
12
+ end
13
+
14
+ task :uglify do
15
+ require 'uglifier'
16
+ file_folder = "lib/assets/javascripts"
17
+ File.open("#{file_folder}/autocomplete-rails.js", "w") do |f|
18
+ f << Uglifier.compile(File.read("#{file_folder}/autocomplete-rails-uncompressed.js"))
19
+ end
20
+ end
21
+
@@ -0,0 +1,136 @@
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
+ (function(jQuery)
18
+ {
19
+ var self = null;
20
+ jQuery.fn.railsAutocomplete = function() {
21
+ var handler = function() {
22
+ if (!this.railsAutoCompleter) {
23
+ this.railsAutoCompleter = new jQuery.railsAutocomplete(this);
24
+ }
25
+ };
26
+ if (jQuery.fn.on !== undefined) {
27
+ return $(document).on('focus',this.selector,handler);
28
+ }
29
+ else {
30
+ return this.live('focus',handler);
31
+ }
32
+ };
33
+
34
+ jQuery.railsAutocomplete = function (e) {
35
+ _e = e;
36
+ this.init(_e);
37
+ };
38
+
39
+ jQuery.railsAutocomplete.fn = jQuery.railsAutocomplete.prototype = {
40
+ railsAutocomplete: '0.0.1'
41
+ };
42
+
43
+ jQuery.railsAutocomplete.fn.extend = jQuery.railsAutocomplete.extend = jQuery.extend;
44
+ jQuery.railsAutocomplete.fn.extend({
45
+ init: function(e) {
46
+ e.delimiter = jQuery(e).attr('data-delimiter') || null;
47
+ function split( val ) {
48
+ return val.split( e.delimiter );
49
+ }
50
+ function extractLast( term ) {
51
+ return split( term ).pop().replace(/^\s+/,"");
52
+ }
53
+
54
+ jQuery(e).autocomplete({
55
+ source: function( request, response ) {
56
+ jQuery.getJSON( jQuery(e).attr('data-autocomplete'), {
57
+ term: extractLast( request.term )
58
+ }, function() {
59
+ if(arguments[0].length == 0) {
60
+ arguments[0] = []
61
+ arguments[0][0] = { id: "", label: "no existing match" }
62
+ }
63
+ jQuery(arguments[0]).each(function(i, el) {
64
+ var obj = {};
65
+ obj[el.id] = el;
66
+ jQuery(e).data(obj);
67
+ });
68
+ response.apply(null, arguments);
69
+ });
70
+ },
71
+ change: function( event, ui ) {
72
+ if(jQuery(jQuery(this).attr('data-id-element')).val() == "") {
73
+ return;
74
+ }
75
+ jQuery(jQuery(this).attr('data-id-element')).val(ui.item ? ui.item.id : "");
76
+ var update_elements = jQuery.parseJSON(jQuery(this).attr("data-update-elements"));
77
+ var data = ui.item ? jQuery(this).data(ui.item.id.toString()) : {};
78
+ if(update_elements && jQuery(update_elements['id']).val() == "") {
79
+ return;
80
+ }
81
+ for (var key in update_elements) {
82
+ jQuery(update_elements[key]).val(ui.item ? data[key] : "");
83
+ }
84
+ },
85
+ search: function() {
86
+ // custom minLength
87
+ var term = extractLast( this.value );
88
+ if ( term.length < 2 ) {
89
+ return false;
90
+ }
91
+ },
92
+ focus: function() {
93
+ // prevent value inserted on focus
94
+ return false;
95
+ },
96
+ select: function( event, ui ) {
97
+ var terms = split( this.value );
98
+ // remove the current input
99
+ terms.pop();
100
+ // add the selected item
101
+ terms.push( ui.item.value );
102
+ // add placeholder to get the comma-and-space at the end
103
+ if (e.delimiter != null) {
104
+ terms.push( "" );
105
+ this.value = terms.join( e.delimiter );
106
+ } else {
107
+ this.value = terms.join("");
108
+ if (jQuery(this).attr('data-id-element')) {
109
+ jQuery(jQuery(this).attr('data-id-element')).val(ui.item.id);
110
+ }
111
+ if (jQuery(this).attr('data-update-elements')) {
112
+ var data = jQuery(this).data(ui.item.id.toString());
113
+ var update_elements = jQuery.parseJSON(jQuery(this).attr("data-update-elements"));
114
+ for (var key in update_elements) {
115
+ jQuery(update_elements[key]).val(data[key]);
116
+ }
117
+ }
118
+ }
119
+ var remember_string = this.value;
120
+ jQuery(this).bind('keyup.clearId', function(){
121
+ if(jQuery(this).val().trim() != remember_string.trim()){
122
+ jQuery(jQuery(this).attr('data-id-element')).val("");
123
+ jQuery(this).unbind('keyup.clearId');
124
+ }
125
+ });
126
+ jQuery(e).trigger('railsAutocomplete.select', ui);
127
+ return false;
128
+ }
129
+ });
130
+ }
131
+ });
132
+
133
+ jQuery(document).ready(function(){
134
+ jQuery('input[data-autocomplete]').railsAutocomplete();
135
+ });
136
+ })(jQuery);