repeated_auto_complete 0.1.0
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/.gitignore +21 -0
- data/README +102 -0
- data/Rakefile +52 -0
- data/VERSION +1 -0
- data/init.rb +3 -0
- data/lib/auto_complete.rb +49 -0
- data/lib/auto_complete_form_builder_helper.rb +38 -0
- data/lib/auto_complete_macros_helper.rb +152 -0
- data/lib/repeated_auto_complete.rb +4 -0
- data/lib/view_mapper/README +4 -0
- data/lib/view_mapper/has_many_auto_complete_view.rb +88 -0
- data/lib/view_mapper/templates/controller.rb +90 -0
- data/lib/view_mapper/templates/layout.html.erb +19 -0
- data/lib/view_mapper/templates/style.css +82 -0
- data/lib/view_mapper/templates/view_child_form.html.erb +16 -0
- data/lib/view_mapper/templates/view_form.html.erb +24 -0
- data/rails/init.rb +3 -0
- data/repeated_auto_complete.gemspec +78 -0
- data/test/auto_complete_form_builder_helper_test.rb +123 -0
- data/test/auto_complete_nested_attributes_test.rb +143 -0
- data/test/auto_complete_test.rb +136 -0
- data/test/helper.rb +14 -0
- data/test/view_mapper/expected_templates/_form.html.erb +26 -0
- data/test/view_mapper/expected_templates/_person.html.erb +22 -0
- data/test/view_mapper/expected_templates/create_parents.rb +16 -0
- data/test/view_mapper/expected_templates/edit.html.erb +11 -0
- data/test/view_mapper/expected_templates/index.html.erb +20 -0
- data/test/view_mapper/expected_templates/new.html.erb +10 -0
- data/test/view_mapper/expected_templates/parent.rb +15 -0
- data/test/view_mapper/expected_templates/show.html.erb +37 -0
- data/test/view_mapper/expected_templates/testies_controller.rb +92 -0
- data/test/view_mapper/has_many_auto_complete_view_test.rb +587 -0
- metadata +93 -0
data/.gitignore
ADDED
data/README
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
Fork of the standard auto_complete plugin to support:
|
2
|
+
|
3
|
+
1. Creating auto complete text fields that can be repeated more than once a single form.
|
4
|
+
|
5
|
+
2. Using auto_complete_for with named scopes to display a customized list
|
6
|
+
of autocomplete options.
|
7
|
+
|
8
|
+
See: http://patshaughnessy.net/repeated_auto_complete for details.
|
9
|
+
|
10
|
+
|
11
|
+
Repeated autocomplete text fields:
|
12
|
+
==================================
|
13
|
+
|
14
|
+
A "text_field_with_auto_complete" method is made available to the form builder
|
15
|
+
yielded by form_for and fields_for that:
|
16
|
+
- Insures unique id's for <input> and <div> tags by inserting unique integers into their
|
17
|
+
id attributes
|
18
|
+
- Uses the object name from the surrounding call to form_for or fields_for so attribute
|
19
|
+
mass assignment will work as usual
|
20
|
+
- Works with the same server side controller method, auto_complete_for, as usual
|
21
|
+
- Supports nested attributes in Rails 2.3
|
22
|
+
|
23
|
+
form.text_field_with_auto_complete works the same as the original text_field_with_auto_complete macro,
|
24
|
+
except it does not take the object as a parameter.
|
25
|
+
|
26
|
+
Example with nested attributes using Rails 2.3 or later:
|
27
|
+
|
28
|
+
class Project < ActiveRecord::Base
|
29
|
+
has_many :tasks
|
30
|
+
accepts_nested_attributes_for :tasks, :allow_destroy => true
|
31
|
+
end
|
32
|
+
|
33
|
+
<% form_for @project do |project_form| %>
|
34
|
+
<p>
|
35
|
+
<%= project_form.label :name, "Project:" %>
|
36
|
+
<%= project_form.text_field_with_auto_complete :name, {}, {:method => :get } %>
|
37
|
+
</p>
|
38
|
+
<% project_form.fields_for :tasks do |task_form| %>
|
39
|
+
<p>
|
40
|
+
<%= task_form.label :name, "Task:" %>
|
41
|
+
<%= task_form.text_field_with_auto_complete :name, {}, { :method => :get, :skip_style => true } %>
|
42
|
+
</p>
|
43
|
+
<% end %>
|
44
|
+
<% end %>
|
45
|
+
|
46
|
+
|
47
|
+
Rails 2.2 and earlier example:
|
48
|
+
|
49
|
+
<% for person in @group.people %>
|
50
|
+
<% fields_for "group[person_attributes][]", person do |person_form| %>
|
51
|
+
<p>
|
52
|
+
Person <%= person_form.label :name %><br/>
|
53
|
+
<%= person_form.text_field_with_auto_complete :name, {}, {:method => :get } %>
|
54
|
+
</p>
|
55
|
+
<% end %>
|
56
|
+
<% end %>
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
Named scopes with auto_complete_for:
|
61
|
+
====================================
|
62
|
+
|
63
|
+
auto_complete_for now optionally accepts a block that is called with the item list and HTTP parameters
|
64
|
+
when the auto complete AJAX request is received. This block can be used to specify that a named scope
|
65
|
+
be used to generate a customized list of autocomplete options.
|
66
|
+
|
67
|
+
Example using anonymous scope:
|
68
|
+
|
69
|
+
auto_complete_for :some_model, :some_other_field do |items, params|
|
70
|
+
items.scoped( { :conditions => [ "a_third_field = ?", params['some_model']['a_third_field'] ] })
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
Example using named scope:
|
76
|
+
|
77
|
+
class Task < ActiveRecord::Base
|
78
|
+
belongs_to :project
|
79
|
+
named_scope :by_project,
|
80
|
+
lambda { |project_name| {
|
81
|
+
:include => :project,
|
82
|
+
:conditions => [ "projects.name = ?", project_name ]
|
83
|
+
} }
|
84
|
+
end
|
85
|
+
|
86
|
+
auto_complete_for :task, :name do | items, params |
|
87
|
+
items.by_project(params['project'])
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
Autocomplete Scaffolding:
|
93
|
+
=========================
|
94
|
+
|
95
|
+
The "View Mapper" gem will generate scaffolding code that illustrates how to use
|
96
|
+
the standard Rails auto_complete plugin in a simple form, or the repeated_auto_complete
|
97
|
+
plugin/gem in a complex form.
|
98
|
+
|
99
|
+
See: http://pats
|
100
|
+
|
101
|
+
|
102
|
+
Copyright (c) 2009 [Pat Shaughnessy], released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "repeated_auto_complete"
|
8
|
+
gem.summary = %Q{auto_complete plugin refactored to handle complex forms and named scopes}
|
9
|
+
gem.description = %Q{auto_complete plugin refactored to handle complex forms and named scopes}
|
10
|
+
gem.email = "pat@patshaughnessy.net"
|
11
|
+
gem.homepage = "http://patshaughnessy.net/repeated_auto_complete"
|
12
|
+
gem.authors = ["Pat Shaughnessy"]
|
13
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
14
|
+
end
|
15
|
+
Jeweler::GemcutterTasks.new
|
16
|
+
rescue LoadError
|
17
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
18
|
+
end
|
19
|
+
|
20
|
+
require 'rake/testtask'
|
21
|
+
Rake::TestTask.new(:test) do |test|
|
22
|
+
test.libs << 'lib' << 'test'
|
23
|
+
test.pattern = 'test/**/*_test.rb'
|
24
|
+
test.verbose = true
|
25
|
+
end
|
26
|
+
|
27
|
+
begin
|
28
|
+
require 'rcov/rcovtask'
|
29
|
+
Rcov::RcovTask.new do |test|
|
30
|
+
test.libs << 'test'
|
31
|
+
test.pattern = 'test/**/*_test.rb'
|
32
|
+
test.verbose = true
|
33
|
+
end
|
34
|
+
rescue LoadError
|
35
|
+
task :rcov do
|
36
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
task :test => :check_dependencies
|
41
|
+
|
42
|
+
task :default => :test
|
43
|
+
|
44
|
+
require 'rake/rdoctask'
|
45
|
+
Rake::RDocTask.new do |rdoc|
|
46
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
47
|
+
|
48
|
+
rdoc.rdoc_dir = 'rdoc'
|
49
|
+
rdoc.title = "repeated_auto_complete #{version}"
|
50
|
+
rdoc.rdoc_files.include('README*')
|
51
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
52
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/init.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
module AutoComplete
|
2
|
+
|
3
|
+
def self.included(base)
|
4
|
+
base.extend(ClassMethods)
|
5
|
+
end
|
6
|
+
|
7
|
+
#
|
8
|
+
# Example:
|
9
|
+
#
|
10
|
+
# # Controller
|
11
|
+
# class BlogController < ApplicationController
|
12
|
+
# auto_complete_for :post, :title
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# # View
|
16
|
+
# <%= text_field_with_auto_complete :post, title %>
|
17
|
+
#
|
18
|
+
# By default, auto_complete_for limits the results to 10 entries,
|
19
|
+
# and sorts by the given field.
|
20
|
+
#
|
21
|
+
# auto_complete_for takes a third parameter, an options hash to
|
22
|
+
# the find method used to search for the records:
|
23
|
+
#
|
24
|
+
# auto_complete_for :post, :title, :limit => 15, :order => 'created_at DESC'
|
25
|
+
#
|
26
|
+
# For help on defining text input fields with autocompletion,
|
27
|
+
# see ActionView::Helpers::JavaScriptHelper.
|
28
|
+
#
|
29
|
+
# For more examples, see script.aculo.us:
|
30
|
+
# * http://script.aculo.us/demos/ajax/autocompleter
|
31
|
+
# * http://script.aculo.us/demos/ajax/autocompleter_customized
|
32
|
+
module ClassMethods
|
33
|
+
def auto_complete_for(object, method, options = {})
|
34
|
+
define_method("auto_complete_for_#{object}_#{method}") do
|
35
|
+
model = object.to_s.camelize.constantize
|
36
|
+
find_options = {
|
37
|
+
:conditions => [ "LOWER(#{model.quoted_table_name}.#{method}) LIKE ?", '%' + params[object][method].downcase + '%' ],
|
38
|
+
:order => "#{model.quoted_table_name}.#{method} ASC",
|
39
|
+
:limit => 10 }.merge!(options)
|
40
|
+
|
41
|
+
@items = model.scoped(find_options)
|
42
|
+
@items = yield(@items, params) if block_given?
|
43
|
+
|
44
|
+
render :inline => "<%= auto_complete_result @items, '#{method}' %>"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module AutoCompleteFormBuilderHelper
|
2
|
+
|
3
|
+
def class_name
|
4
|
+
"#{@object.class.to_s.underscore}"
|
5
|
+
end
|
6
|
+
|
7
|
+
def sanitized_object_name
|
8
|
+
@object_name.gsub(/\]\[|[^-a-zA-Z0-9:.]/, "_").sub(/_$/, "")
|
9
|
+
end
|
10
|
+
|
11
|
+
def is_used_as_nested_attribute?
|
12
|
+
/\[#{class_name.pluralize}_attributes\]\[[0-9]+\]/.match @object_name
|
13
|
+
end
|
14
|
+
|
15
|
+
def text_field_with_auto_complete(method, tag_options = {}, completion_options = {})
|
16
|
+
if completion_options[:child_index]
|
17
|
+
unique_object_name = "#{class_name}_#{completion_options[:child_index]}"
|
18
|
+
elsif @options[:child_index]
|
19
|
+
unique_object_name = "#{class_name}_#{@options[:child_index]}"
|
20
|
+
elsif is_used_as_nested_attribute?
|
21
|
+
unique_object_name = sanitized_object_name
|
22
|
+
else
|
23
|
+
unique_object_name = "#{class_name}_#{Object.new.object_id.abs}"
|
24
|
+
end
|
25
|
+
completion_options_for_class_name = {
|
26
|
+
:url => { :action => "auto_complete_for_#{class_name}_#{method}" },
|
27
|
+
:param_name => "#{class_name}[#{method}]"
|
28
|
+
}.update(completion_options)
|
29
|
+
@template.auto_complete_field_with_style_and_script(unique_object_name,
|
30
|
+
method,
|
31
|
+
tag_options,
|
32
|
+
completion_options_for_class_name
|
33
|
+
) do
|
34
|
+
text_field(method, { :id => "#{unique_object_name}_#{method}" }.update(tag_options))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
module AutoCompleteMacrosHelper
|
2
|
+
# Adds AJAX autocomplete functionality to the text input field with the
|
3
|
+
# DOM ID specified by +field_id+.
|
4
|
+
#
|
5
|
+
# This function expects that the called action returns an HTML <ul> list,
|
6
|
+
# or nothing if no entries should be displayed for autocompletion.
|
7
|
+
#
|
8
|
+
# You'll probably want to turn the browser's built-in autocompletion off,
|
9
|
+
# so be sure to include an <tt>autocomplete="off"</tt> attribute with your text
|
10
|
+
# input field.
|
11
|
+
#
|
12
|
+
# The autocompleter object is assigned to a Javascript variable named <tt>field_id</tt>_auto_completer.
|
13
|
+
# This object is useful if you for example want to trigger the auto-complete suggestions through
|
14
|
+
# other means than user input (for that specific case, call the <tt>activate</tt> method on that object).
|
15
|
+
#
|
16
|
+
# Required +options+ are:
|
17
|
+
# <tt>:url</tt>:: URL to call for autocompletion results
|
18
|
+
# in url_for format.
|
19
|
+
#
|
20
|
+
# Addtional +options+ are:
|
21
|
+
# <tt>:update</tt>:: Specifies the DOM ID of the element whose
|
22
|
+
# innerHTML should be updated with the autocomplete
|
23
|
+
# entries returned by the AJAX request.
|
24
|
+
# Defaults to <tt>field_id</tt> + '_auto_complete'
|
25
|
+
# <tt>:with</tt>:: A JavaScript expression specifying the
|
26
|
+
# parameters for the XMLHttpRequest. This defaults
|
27
|
+
# to 'fieldname=value'.
|
28
|
+
# <tt>:frequency</tt>:: Determines the time to wait after the last keystroke
|
29
|
+
# for the AJAX request to be initiated.
|
30
|
+
# <tt>:indicator</tt>:: Specifies the DOM ID of an element which will be
|
31
|
+
# displayed while autocomplete is running.
|
32
|
+
# <tt>:tokens</tt>:: A string or an array of strings containing
|
33
|
+
# separator tokens for tokenized incremental
|
34
|
+
# autocompletion. Example: <tt>:tokens => ','</tt> would
|
35
|
+
# allow multiple autocompletion entries, separated
|
36
|
+
# by commas.
|
37
|
+
# <tt>:min_chars</tt>:: The minimum number of characters that should be
|
38
|
+
# in the input field before an Ajax call is made
|
39
|
+
# to the server.
|
40
|
+
# <tt>:on_hide</tt>:: A Javascript expression that is called when the
|
41
|
+
# autocompletion div is hidden. The expression
|
42
|
+
# should take two variables: element and update.
|
43
|
+
# Element is a DOM element for the field, update
|
44
|
+
# is a DOM element for the div from which the
|
45
|
+
# innerHTML is replaced.
|
46
|
+
# <tt>:on_show</tt>:: Like on_hide, only now the expression is called
|
47
|
+
# then the div is shown.
|
48
|
+
# <tt>:after_update_element</tt>:: A Javascript expression that is called when the
|
49
|
+
# user has selected one of the proposed values.
|
50
|
+
# The expression should take two variables: element and value.
|
51
|
+
# Element is a DOM element for the field, value
|
52
|
+
# is the value selected by the user.
|
53
|
+
# <tt>:parameters</tt>:: To send additional parameters to the server,
|
54
|
+
# add them here in the format: 'field=value&another=value'.
|
55
|
+
# <tt>:select</tt>:: Pick the class of the element from which the value for
|
56
|
+
# insertion should be extracted. If this is not specified,
|
57
|
+
# the entire element is used.
|
58
|
+
# <tt>:method</tt>:: Specifies the HTTP verb to use when the autocompletion
|
59
|
+
# request is made. Defaults to POST.
|
60
|
+
def auto_complete_field(field_id, options = {})
|
61
|
+
function = "var #{field_id}_auto_completer = new Ajax.Autocompleter("
|
62
|
+
function << "'#{field_id}', "
|
63
|
+
function << "'" + (options[:update] || "#{field_id}_auto_complete") + "', "
|
64
|
+
function << "'#{url_for(options[:url])}'"
|
65
|
+
|
66
|
+
js_options = {}
|
67
|
+
js_options[:tokens] = array_or_string_for_javascript(options[:tokens]) if options[:tokens]
|
68
|
+
js_options[:callback] = "function(element, value) { return #{options[:with]} }" if options[:with]
|
69
|
+
js_options[:indicator] = "'#{options[:indicator]}'" if options[:indicator]
|
70
|
+
js_options[:select] = "'#{options[:select]}'" if options[:select]
|
71
|
+
js_options[:paramName] = "'#{options[:param_name]}'" if options[:param_name]
|
72
|
+
js_options[:frequency] = "#{options[:frequency]}" if options[:frequency]
|
73
|
+
js_options[:method] = "'#{options[:method].to_s}'" if options[:method]
|
74
|
+
js_options[:parameters] = "'#{options[:parameters]}'" if options[:parameters]
|
75
|
+
|
76
|
+
{ :after_update_element => :afterUpdateElement,
|
77
|
+
:on_show => :onShow, :on_hide => :onHide, :min_chars => :minChars }.each do |k,v|
|
78
|
+
js_options[v] = options[k] if options[k]
|
79
|
+
end
|
80
|
+
|
81
|
+
function << (', ' + options_for_javascript(js_options) + ')')
|
82
|
+
|
83
|
+
javascript_tag(function)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Use this method in your view to generate a return for the AJAX autocomplete requests.
|
87
|
+
#
|
88
|
+
# Example action:
|
89
|
+
#
|
90
|
+
# def auto_complete_for_item_title
|
91
|
+
# @items = Item.find(:all,
|
92
|
+
# :conditions => [ 'LOWER(description) LIKE ?',
|
93
|
+
# '%' + request.raw_post.downcase + '%' ])
|
94
|
+
# render :inline => "<%= auto_complete_result(@items, 'description') %>"
|
95
|
+
# end
|
96
|
+
#
|
97
|
+
# The auto_complete_result can of course also be called from a view belonging to the
|
98
|
+
# auto_complete action if you need to decorate it further.
|
99
|
+
def auto_complete_result(entries, field, phrase = nil)
|
100
|
+
return unless entries
|
101
|
+
items = entries.map { |entry| content_tag("li", phrase ? highlight(entry[field], phrase) : h(entry[field])) }
|
102
|
+
content_tag("ul", items.uniq)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Wrapper for text_field with added AJAX autocompletion functionality.
|
106
|
+
#
|
107
|
+
# In your controller, you'll need to define an action called
|
108
|
+
# auto_complete_for to respond the AJAX calls,
|
109
|
+
#
|
110
|
+
def text_field_with_auto_complete(object, method, tag_options = {}, completion_options = {})
|
111
|
+
auto_complete_field_with_style_and_script(object, method, tag_options, completion_options) do
|
112
|
+
text_field(object, method, tag_options)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def auto_complete_field_with_style_and_script(object, method, tag_options = {}, completion_options = {})
|
117
|
+
(completion_options[:skip_style] ? "" : auto_complete_stylesheet) +
|
118
|
+
yield +
|
119
|
+
content_tag("div", "", :id => "#{object}_#{method}_auto_complete", :class => "auto_complete") +
|
120
|
+
auto_complete_field("#{object}_#{method}", { :url => { :action => "auto_complete_for_#{object}_#{method}" } }.update(completion_options))
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
def auto_complete_stylesheet
|
125
|
+
content_tag('style', <<-EOT, :type => Mime::CSS)
|
126
|
+
div.auto_complete {
|
127
|
+
width: 350px;
|
128
|
+
background: #fff;
|
129
|
+
}
|
130
|
+
div.auto_complete ul {
|
131
|
+
border:1px solid #888;
|
132
|
+
margin:0;
|
133
|
+
padding:0;
|
134
|
+
width:100%;
|
135
|
+
list-style-type:none;
|
136
|
+
}
|
137
|
+
div.auto_complete ul li {
|
138
|
+
margin:0;
|
139
|
+
padding:3px;
|
140
|
+
}
|
141
|
+
div.auto_complete ul li.selected {
|
142
|
+
background-color: #ffb;
|
143
|
+
}
|
144
|
+
div.auto_complete ul strong.highlight {
|
145
|
+
color: #800;
|
146
|
+
margin:0;
|
147
|
+
padding:0;
|
148
|
+
}
|
149
|
+
EOT
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module ViewMapper
|
2
|
+
module HasManyAutoCompleteView
|
3
|
+
|
4
|
+
def self.extended(base)
|
5
|
+
base.extend(ViewMapper::HasManyChildModels)
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.source_root
|
9
|
+
File.expand_path(File.dirname(__FILE__) + "/templates")
|
10
|
+
end
|
11
|
+
|
12
|
+
def source_roots_for_view
|
13
|
+
[
|
14
|
+
HasManyAutoCompleteView.source_root,
|
15
|
+
HasManyView.source_root,
|
16
|
+
File.expand_path(source_root),
|
17
|
+
File.expand_path(File.join(self.class.lookup('model').path, 'templates'))
|
18
|
+
]
|
19
|
+
end
|
20
|
+
|
21
|
+
def manifest
|
22
|
+
m = super.edit do |action|
|
23
|
+
action unless is_child_model_action?(action)
|
24
|
+
end
|
25
|
+
add_child_models_manifest(m)
|
26
|
+
add_auto_complete_manifest(m)
|
27
|
+
m
|
28
|
+
end
|
29
|
+
|
30
|
+
def add_auto_complete_manifest(m)
|
31
|
+
if valid
|
32
|
+
auto_complete_attributes.each do |attrib|
|
33
|
+
add_auto_complete_route(m, attrib[:model_name], attrib[:text_field])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def add_auto_complete_route(manifest, model_name, text_field)
|
39
|
+
manifest.route :name => 'connect',
|
40
|
+
:path => auto_complete_for_method(model_name, text_field),
|
41
|
+
:controller => controller_file_name,
|
42
|
+
:action => auto_complete_for_method(model_name, text_field)
|
43
|
+
end
|
44
|
+
|
45
|
+
def auto_complete_for_method(model_name, text_field)
|
46
|
+
"auto_complete_for_#{model_name}_#{text_field}"
|
47
|
+
end
|
48
|
+
|
49
|
+
def auto_complete_attributes
|
50
|
+
@auto_complete_attributes = find_auto_complete_attributes
|
51
|
+
end
|
52
|
+
|
53
|
+
def find_auto_complete_attributes
|
54
|
+
attribs = []
|
55
|
+
if view_only?
|
56
|
+
attribs << auto_complete_attributes_for_model(model)
|
57
|
+
else
|
58
|
+
attribs << auto_complete_attributes_from_command_line
|
59
|
+
end
|
60
|
+
attribs << child_models.collect { |child| auto_complete_attributes_for_model(child) }
|
61
|
+
attribs.flatten
|
62
|
+
end
|
63
|
+
|
64
|
+
def auto_complete_attributes_for_model(model_info)
|
65
|
+
model_info.text_fields.collect do |text_field|
|
66
|
+
{ :model_name => model_info.name.downcase, :text_field => text_field }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def auto_complete_attributes_from_command_line
|
71
|
+
attributes.reject do |cmd_line_attrib|
|
72
|
+
!ViewMapper::ModelInfo.is_text_field_attrib_type? cmd_line_attrib.type
|
73
|
+
end.collect do |cmd_line_attrib|
|
74
|
+
{ :model_name => singular_name, :text_field => cmd_line_attrib.name }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def is_auto_complete_attribute?(model_name, text_field)
|
79
|
+
!auto_complete_attributes.detect { |attrib| attrib[:model_name] == model_name && attrib[:text_field] == text_field }.nil?
|
80
|
+
end
|
81
|
+
|
82
|
+
def validate
|
83
|
+
super
|
84
|
+
@valid &&= validate_child_models
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|