client_side_autocomplete 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.markdown +307 -0
- data/Rakefile +1 -0
- data/client_side_autocomplete.gemspec +26 -0
- data/lib/client_side_autocomplete.rb +29 -0
- data/lib/client_side_autocomplete/autocomplete.rb +96 -0
- data/lib/client_side_autocomplete/form_helper.rb +47 -0
- data/lib/client_side_autocomplete/formtastic_plugin.rb +41 -0
- data/lib/client_side_autocomplete/orm.rb +8 -0
- data/lib/client_side_autocomplete/orm/active_record.rb +47 -0
- data/lib/client_side_autocomplete/orm/mongo_mapper.rb +30 -0
- data/lib/client_side_autocomplete/orm/mongoid.rb +30 -0
- data/lib/client_side_autocomplete/simple_form_plugin.rb +25 -0
- data/lib/client_side_autocomplete/version.rb +3 -0
- data/vendor/assets/javascripts/rails.autocomplete.js +16 -0
- metadata +73 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
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.markdown
ADDED
@@ -0,0 +1,307 @@
|
|
1
|
+
# client_side_autocomplete
|
2
|
+
|
3
|
+
An easy way to use jQuery's autocomplete with Rails 3.1
|
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
|
+
## Before you start
|
11
|
+
|
12
|
+
Make sure your project is using jQuery-UI and the autocomplete widget
|
13
|
+
before you continue.
|
14
|
+
|
15
|
+
You can find more info about that here:
|
16
|
+
|
17
|
+
* http://jquery.com/
|
18
|
+
* http://jqueryui.com/demos/autocomplete/
|
19
|
+
* http://github.com/rails/jquery-ujs
|
20
|
+
|
21
|
+
I'd encourage you to understand how to use those 3 amazing tools before attempting to use this gem.
|
22
|
+
|
23
|
+
## Installing
|
24
|
+
|
25
|
+
Include the gem on your Gemfile
|
26
|
+
|
27
|
+
gem 'client_side_autocomplete'
|
28
|
+
|
29
|
+
Install it
|
30
|
+
|
31
|
+
bundle install
|
32
|
+
|
33
|
+
## Usage ##
|
34
|
+
|
35
|
+
### Rails 3.1 ###
|
36
|
+
The javascript file is served up in the asset pipeline. Add the
|
37
|
+
following to your `app/assets/javascripts/application.js` file.
|
38
|
+
|
39
|
+
```javascript
|
40
|
+
//= require jquery
|
41
|
+
//= require jquery_ujs
|
42
|
+
//= require jquery-ui
|
43
|
+
//= require rails.autocomplete
|
44
|
+
```
|
45
|
+
|
46
|
+
### Model Example
|
47
|
+
|
48
|
+
Assuming you have a Brand model:
|
49
|
+
|
50
|
+
class Brand < ActiveRecord::Base
|
51
|
+
end
|
52
|
+
|
53
|
+
create_table :brand do |t|
|
54
|
+
t.column :name, :string
|
55
|
+
end
|
56
|
+
|
57
|
+
### Controller
|
58
|
+
|
59
|
+
To set up the required action on your controller, all you have to do is call it with the class name and the method
|
60
|
+
as in the following example:
|
61
|
+
|
62
|
+
class ProductsController < Admin::BaseController
|
63
|
+
autocomplete :brand, :name
|
64
|
+
end
|
65
|
+
|
66
|
+
This will create an action _autocomplete_brand_name_ on your controller, don't forget to add it on your routes file
|
67
|
+
|
68
|
+
resources :products do
|
69
|
+
get :autocomplete_brand_name, :on => :collection
|
70
|
+
end
|
71
|
+
|
72
|
+
### Options
|
73
|
+
|
74
|
+
#### :full => true
|
75
|
+
|
76
|
+
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.
|
77
|
+
|
78
|
+
class ProductsController < Admin::BaseController
|
79
|
+
autocomplete :brand, :name, :full => true
|
80
|
+
end
|
81
|
+
|
82
|
+
The following terms would match the query 'un':
|
83
|
+
|
84
|
+
* Luna
|
85
|
+
* Unacceptable
|
86
|
+
* Rerun
|
87
|
+
|
88
|
+
#### :full => false (default behavior)
|
89
|
+
|
90
|
+
Only the following terms mould match the query 'un':
|
91
|
+
|
92
|
+
* Unacceptable
|
93
|
+
|
94
|
+
#### :extra_data
|
95
|
+
|
96
|
+
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).
|
97
|
+
|
98
|
+
Passing an array of attributes/column names to this option will fetch and return the specified data.
|
99
|
+
|
100
|
+
class ProductsController < Admin::BaseController
|
101
|
+
autocomplete :brand, :name, :extra_data => [:slogan]
|
102
|
+
end
|
103
|
+
|
104
|
+
#### :display_value
|
105
|
+
|
106
|
+
If you want to display a different version of what you're looking for, you can use the :display_value option.
|
107
|
+
|
108
|
+
This options receives a method name as the parameter, and that method will be called on the instance when displaying the results.
|
109
|
+
|
110
|
+
class Brand < ActiveRecord::Base
|
111
|
+
def funky_method
|
112
|
+
"#{self.name}.camelize"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
class ProductsController < Admin::BaseController
|
118
|
+
autocomplete :brand, :name, :display_value => :funky_method
|
119
|
+
end
|
120
|
+
|
121
|
+
In the example above, you will search by _name_, but the autocomplete list will display the result of _funky_method_
|
122
|
+
|
123
|
+
This wouldn't really make much sense unless you use it with the "id_element" attribute. (See below)
|
124
|
+
|
125
|
+
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
|
126
|
+
|
127
|
+
|
128
|
+
#### :scopes
|
129
|
+
Added option to use scopes. Pass scopes in an array.
|
130
|
+
e.g `:scopes => [:scope1, :scope2]`
|
131
|
+
|
132
|
+
#### :column_name
|
133
|
+
By default autocomplete uses method name as column name. Now it can be specified using column_name options
|
134
|
+
`:column_name => 'name'`
|
135
|
+
|
136
|
+
#### json encoder
|
137
|
+
Autocomplete uses Yajl as JSON encoder/decoder, but you can specify your own
|
138
|
+
|
139
|
+
class ProductsController < Admin::BaseController
|
140
|
+
autocomplete :brand, :name do |items|
|
141
|
+
CustomJSON::Encoder.encode(items)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
### View
|
146
|
+
|
147
|
+
On your view, all you have to do is include the attribute autocomplete on the text field
|
148
|
+
using the url to the autocomplete action as the value.
|
149
|
+
|
150
|
+
form_for @product do |f|
|
151
|
+
f.autocomplete_field :brand_name, autocomplete_brand_name_products_path
|
152
|
+
end
|
153
|
+
|
154
|
+
This will generate an HTML tag that looks like:
|
155
|
+
|
156
|
+
<input type="text" data-autocomplete="products/autocomplete_brand_name">
|
157
|
+
|
158
|
+
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
|
159
|
+
*autocomplete_field_tag* helper.
|
160
|
+
|
161
|
+
form_tag 'some/path'
|
162
|
+
autocomplete_field_tag 'address', '', address_autocomplete_path, :size => 75
|
163
|
+
end
|
164
|
+
|
165
|
+
Now your autocomplete code is unobtrusive, Rails 3 style.
|
166
|
+
|
167
|
+
### Getting the object id
|
168
|
+
|
169
|
+
If you need to use the id of the selected object, you can use the *id_element* attribute too:
|
170
|
+
|
171
|
+
f.autocomplete_field :brand_name, autocomplete_brand_name_products_path, :id_element => '#some_element'
|
172
|
+
|
173
|
+
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.
|
174
|
+
|
175
|
+
### Getting extra object data
|
176
|
+
|
177
|
+
If you need to extra data about the selected object, you can use the *:update_elements* HTML attribute.
|
178
|
+
|
179
|
+
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:
|
180
|
+
|
181
|
+
f.autocomplete_field :brand_name, autocomplete_brand_name_products_path, :update_elements => {:id => '#id_element', :slogan => '#some_other_element'}
|
182
|
+
|
183
|
+
class ProductsController < Admin::BaseController
|
184
|
+
autocomplete :brand, :name, :extra_data => [:slogan]
|
185
|
+
end
|
186
|
+
|
187
|
+
The previous example would fetch the extra attribute slogan and update jQuery('#some_other_element') with the slogan value.
|
188
|
+
|
189
|
+
### Running custom code on selection
|
190
|
+
|
191
|
+
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:
|
192
|
+
|
193
|
+
$('#my_autocomplete_field').bind('railsAutocomplete.select', function(event, data){
|
194
|
+
/* Do something here */
|
195
|
+
alert(data.item.id);
|
196
|
+
});
|
197
|
+
|
198
|
+
## Formtastic
|
199
|
+
|
200
|
+
If you are using [Formtastic](http://github.com/justinfrench/formtastic), you automatically get the *autocompleted_input* helper on *semantic_form_for*:
|
201
|
+
|
202
|
+
semantic_form_for @product do |f|
|
203
|
+
f.autocompleted_input :brand_name, :url => autocomplete_brand_name_products_path
|
204
|
+
end
|
205
|
+
|
206
|
+
The only difference with the original helper is that you must specify the autocomplete url using the *:url* option.
|
207
|
+
|
208
|
+
## SimpleForm
|
209
|
+
|
210
|
+
If you want to use it with simple_form, all you have to do is use the
|
211
|
+
:as option on the input and set the autocomplete path with the :url
|
212
|
+
option.
|
213
|
+
|
214
|
+
|
215
|
+
simple_form_for @product do |form|
|
216
|
+
form.input :name
|
217
|
+
form.input :brand_name, :url => autocomplete_brand_name_products_path, :as => :autocomplete
|
218
|
+
|
219
|
+
# Cucumber
|
220
|
+
|
221
|
+
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:
|
222
|
+
|
223
|
+
require 'cucumber/autocomplete'
|
224
|
+
|
225
|
+
Then you'll have access to the following step:
|
226
|
+
|
227
|
+
I choose "([^"]*)" in the autocomplete list
|
228
|
+
|
229
|
+
An example on how to use it:
|
230
|
+
|
231
|
+
@javascript
|
232
|
+
Scenario: Autocomplete
|
233
|
+
Given the following brands exists:
|
234
|
+
| name |
|
235
|
+
| Alpha |
|
236
|
+
| Beta |
|
237
|
+
| Gamma |
|
238
|
+
And I go to the home page
|
239
|
+
And I fill in "Brand name" with "al"
|
240
|
+
And I choose "Alpha" in the autocomplete list
|
241
|
+
Then the "Brand name" field should contain "Alpha"
|
242
|
+
|
243
|
+
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).
|
244
|
+
|
245
|
+
# Steak
|
246
|
+
|
247
|
+
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:
|
248
|
+
|
249
|
+
require 'steak/autocomplete'
|
250
|
+
|
251
|
+
Then you'll have access to the following helper:
|
252
|
+
|
253
|
+
choose_autocomplete_result
|
254
|
+
|
255
|
+
An example on how to use it:
|
256
|
+
|
257
|
+
scenario "Autocomplete" do
|
258
|
+
lambda do
|
259
|
+
Brand.create! [
|
260
|
+
{:name => "Alpha"},
|
261
|
+
{:name => "Beta"},
|
262
|
+
{:name => "Gamma"}
|
263
|
+
]
|
264
|
+
end.should change(Brand, :count).by(3)
|
265
|
+
|
266
|
+
visit home_page
|
267
|
+
fill_in "Brand name", :with => "al"
|
268
|
+
choose_autocomplete_result "Alpha"
|
269
|
+
find_field("Brand name").value.should include("Alpha")
|
270
|
+
end
|
271
|
+
|
272
|
+
I have only tested this using Capybara, no idea if it works with something else.
|
273
|
+
|
274
|
+
# Development
|
275
|
+
|
276
|
+
If you want to make changes to the gem, first install bundler 1.0.0:
|
277
|
+
|
278
|
+
gem install bundler
|
279
|
+
|
280
|
+
And then, install all your dependencies:
|
281
|
+
|
282
|
+
bundle install
|
283
|
+
|
284
|
+
## Running the test suite
|
285
|
+
|
286
|
+
You need to have an instance of MongoDB running on your computer or all the mongo tests will fail miserably.
|
287
|
+
|
288
|
+
rake test
|
289
|
+
|
290
|
+
## Integration tests
|
291
|
+
|
292
|
+
If you make changes or add features to the jQuery part, please make sure
|
293
|
+
you write a cucumber test for it.
|
294
|
+
|
295
|
+
You can find an example Rails app on the *integration* folder.
|
296
|
+
|
297
|
+
You can run the integration tests with the cucumber command while on the
|
298
|
+
integration folder:
|
299
|
+
|
300
|
+
cd integration
|
301
|
+
rake db:migrate
|
302
|
+
cucumber
|
303
|
+
|
304
|
+
# Thanks to
|
305
|
+
|
306
|
+
Author of rails3-jquery-autocomplete and [this list](https://github.com/crowdint/rails3-jquery-autocomplete/contributors)
|
307
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "client_side_autocomplete/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "client_side_autocomplete"
|
7
|
+
s.version = ClientSideAutocomplete::VERSION
|
8
|
+
s.authors = ["Shenouda Bertel"]
|
9
|
+
s.email = ["ShenoudaB@gmail.com"]
|
10
|
+
s.homepage = "http://mobithought.com"
|
11
|
+
s.summary = %q{Client Side AutoComplete}
|
12
|
+
s.description = %q{Client Side AutoComplete}
|
13
|
+
|
14
|
+
s.rubyforge_project = "client_side_autocomplete"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_dependency('rails', '~>3.1.0')
|
22
|
+
|
23
|
+
# specify any dependencies here; for example:
|
24
|
+
# s.add_development_dependency "rspec"
|
25
|
+
# s.add_runtime_dependency "rest-client"
|
26
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "client_side_autocomplete/version"
|
2
|
+
require 'client_side_autocomplete/form_helper'
|
3
|
+
require 'client_side_autocomplete/autocomplete'
|
4
|
+
|
5
|
+
module ClientSideAutocomplete
|
6
|
+
autoload :Orm , 'client_side_autocomplete/orm'
|
7
|
+
autoload :FormtasticPlugin , 'client_side_autocomplete/formtastic_plugin'
|
8
|
+
end
|
9
|
+
|
10
|
+
class ActionController::Base
|
11
|
+
include ClientSideAutocomplete::Autocomplete
|
12
|
+
end
|
13
|
+
|
14
|
+
#
|
15
|
+
# Load the formtastic plugin if using Formtastic
|
16
|
+
# TODO: Better way to load plugins
|
17
|
+
begin
|
18
|
+
require 'formtastic'
|
19
|
+
class Formtastic::FormBuilder < ActionView::Helpers::FormBuilder
|
20
|
+
include ClientSideAutocomplete::FormtasticPlugin
|
21
|
+
end
|
22
|
+
rescue LoadError
|
23
|
+
end
|
24
|
+
|
25
|
+
begin
|
26
|
+
require 'simple_form'
|
27
|
+
require 'client_side_autocomplete/simple_form_plugin'
|
28
|
+
rescue LoadError
|
29
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module ClientSideAutocomplete
|
2
|
+
module Autocomplete
|
3
|
+
def self.included(target)
|
4
|
+
target.extend ClientSideAutocomplete::Autocomplete::ClassMethods
|
5
|
+
|
6
|
+
if defined?(Mongoid::Document)
|
7
|
+
target.send :include, ClientSideAutocomplete::Orm::Mongoid
|
8
|
+
elsif defined?(MongoMapper::Document)
|
9
|
+
target.send :include, ClientSideAutocomplete::Orm::MongoMapper
|
10
|
+
else
|
11
|
+
target.send :include, ClientSideAutocomplete::Orm::ActiveRecord
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
#
|
16
|
+
# Usage:
|
17
|
+
#
|
18
|
+
# class ProductsController < Admin::BaseController
|
19
|
+
# autocomplete :brand, :name
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# This will magically generate an action autocomplete_brand_name, so,
|
23
|
+
# don't forget to add it on your routes file
|
24
|
+
#
|
25
|
+
# resources :products do
|
26
|
+
# get :autocomplete_brand_name, :on => :collection
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# Now, on your view, all you have to do is have a text field like:
|
30
|
+
#
|
31
|
+
# f.text_field :brand_name, :autocomplete => autocomplete_brand_name_products_path
|
32
|
+
#
|
33
|
+
#
|
34
|
+
# Yajl is used by default to encode results, if you want to use a different encoder
|
35
|
+
# you can specify your custom encoder via block
|
36
|
+
#
|
37
|
+
# class ProductsController < Admin::BaseController
|
38
|
+
# autocomplete :brand, :name do |items|
|
39
|
+
# CustomJSONEncoder.encode(items)
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
module ClassMethods
|
44
|
+
def autocomplete(object, method, options = {})
|
45
|
+
define_method("autocomplete_#{object}_#{method}") do
|
46
|
+
|
47
|
+
method = options[:column_name] if options.has_key?(:column_name)
|
48
|
+
|
49
|
+
term = params[:term]
|
50
|
+
|
51
|
+
if term && !term.blank?
|
52
|
+
#allow specifying fully qualified class name for model object
|
53
|
+
class_name = options[:class_name] || object
|
54
|
+
items = get_autocomplete_items(:model => get_object(class_name), \
|
55
|
+
:options => options, :term => term, :method => method)
|
56
|
+
else
|
57
|
+
items = {}
|
58
|
+
end
|
59
|
+
|
60
|
+
render :json => json_for_autocomplete(items, options[:display_value] ||= method, options[:extra_data])
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Returns a limit that will be used on the query
|
66
|
+
def get_autocomplete_limit(options)
|
67
|
+
options[:limit] ||= 10
|
68
|
+
end
|
69
|
+
|
70
|
+
# Returns parameter model_sym as a constant
|
71
|
+
#
|
72
|
+
# get_object(:actor)
|
73
|
+
# # returns a Actor constant supposing it is already defined
|
74
|
+
#
|
75
|
+
def get_object(model_sym)
|
76
|
+
object = model_sym.to_s.camelize.constantize
|
77
|
+
end
|
78
|
+
|
79
|
+
#
|
80
|
+
# Returns a hash with three keys actually used by the Autocomplete jQuery-ui
|
81
|
+
# Can be overriden to show whatever you like
|
82
|
+
# Hash also includes a key/value pair for each method in extra_data
|
83
|
+
#
|
84
|
+
def json_for_autocomplete(items, method, extra_data=[])
|
85
|
+
items.collect do |item|
|
86
|
+
hash = {"id" => item.id.to_s, "label" => item.send(method), "value" => item.send(method)}
|
87
|
+
extra_data.each do |datum|
|
88
|
+
hash[datum] = item.send(datum)
|
89
|
+
end if extra_data
|
90
|
+
# TODO: Come back to remove this if clause when test suite is better
|
91
|
+
hash
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
@@ -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
|
+
module ClientSideAutocomplete
|
2
|
+
module FormtasticPlugin
|
3
|
+
def autocompleted_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[:as] ||= "autocompleted_string"
|
12
|
+
|
13
|
+
html_class = [ options[:as], (options[:required] ? :required : :optional) ]
|
14
|
+
html_class << 'error' if @object && @object.respond_to?(:errors) && !@object.errors[method.to_sym].blank?
|
15
|
+
|
16
|
+
wrapper_html = options.delete(:wrapper_html) || {}
|
17
|
+
# wrapper_html[:id] ||= generate_html_id(method)
|
18
|
+
wrapper_html[:class] = (html_class << wrapper_html[:class]).flatten.compact.join(' ')
|
19
|
+
|
20
|
+
if options[:input_html] && options[:input_html][:id]
|
21
|
+
options[:label_html] ||= {}
|
22
|
+
options[:label_html][:for] ||= options[:input_html][:id]
|
23
|
+
end
|
24
|
+
|
25
|
+
# input_parts = self.class.inline_order.dup
|
26
|
+
# input_parts = input_parts - [:errors, :hints] if options[:as] == :hidden
|
27
|
+
|
28
|
+
list_item_content = input_parts.map do |type|
|
29
|
+
send(:"inline_#{type}_for", method, options)
|
30
|
+
end.compact.join("\n")
|
31
|
+
|
32
|
+
return template.content_tag(:li, Formtastic::Util.html_safe(list_item_content), wrapper_html)
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
protected
|
37
|
+
def autocompleted_string_input(method, options)
|
38
|
+
self.label(method, options_for_label(options)) << autocomplete_field(method, options.delete(:url), options)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module ClientSideAutocomplete
|
2
|
+
module Orm
|
3
|
+
module ActiveRecord
|
4
|
+
def 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 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 = 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 ClientSideAutocomplete
|
2
|
+
module Orm
|
3
|
+
module MongoMapper
|
4
|
+
def 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 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 = 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,30 @@
|
|
1
|
+
module ClientSideAutocomplete
|
2
|
+
module Orm
|
3
|
+
module Mongoid
|
4
|
+
def 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 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 = get_autocomplete_order(method, options)
|
24
|
+
|
25
|
+
search = (is_full_search ? '.*' : '^') + term + '.*'
|
26
|
+
items = model.where(method.to_sym => /#{search}/i).limit(limit).order_by(order)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
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,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 c(a){return b(a).pop().replace(/^\s+/,"")}function b(b){return b.split(a.delimiter)}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;$(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);return!1}})}})}(jQuery)
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: client_side_autocomplete
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Shenouda Bertel
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-09-01 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rails
|
16
|
+
requirement: &70263840 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 3.1.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70263840
|
25
|
+
description: Client Side AutoComplete
|
26
|
+
email:
|
27
|
+
- ShenoudaB@gmail.com
|
28
|
+
executables: []
|
29
|
+
extensions: []
|
30
|
+
extra_rdoc_files: []
|
31
|
+
files:
|
32
|
+
- .gitignore
|
33
|
+
- Gemfile
|
34
|
+
- LICENSE
|
35
|
+
- README.markdown
|
36
|
+
- Rakefile
|
37
|
+
- client_side_autocomplete.gemspec
|
38
|
+
- lib/client_side_autocomplete.rb
|
39
|
+
- lib/client_side_autocomplete/autocomplete.rb
|
40
|
+
- lib/client_side_autocomplete/form_helper.rb
|
41
|
+
- lib/client_side_autocomplete/formtastic_plugin.rb
|
42
|
+
- lib/client_side_autocomplete/orm.rb
|
43
|
+
- lib/client_side_autocomplete/orm/active_record.rb
|
44
|
+
- lib/client_side_autocomplete/orm/mongo_mapper.rb
|
45
|
+
- lib/client_side_autocomplete/orm/mongoid.rb
|
46
|
+
- lib/client_side_autocomplete/simple_form_plugin.rb
|
47
|
+
- lib/client_side_autocomplete/version.rb
|
48
|
+
- vendor/assets/javascripts/rails.autocomplete.js
|
49
|
+
homepage: http://mobithought.com
|
50
|
+
licenses: []
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options: []
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ! '>='
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
requirements: []
|
68
|
+
rubyforge_project: client_side_autocomplete
|
69
|
+
rubygems_version: 1.8.6
|
70
|
+
signing_key:
|
71
|
+
specification_version: 3
|
72
|
+
summary: Client Side AutoComplete
|
73
|
+
test_files: []
|