rails4-autocomplete 1.0.7

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.
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);