admin_assistant 1.0.4 → 2.0.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -1,10 +1,29 @@
1
1
  require 'grancher/task'
2
2
  require 'rake'
3
3
  require 'rake/testtask'
4
+ require 'rake/rdoctask'
5
+ require 'spec/rake/spectask'
4
6
 
5
7
  desc 'Default: run all specs across all supported Rails gem versions.'
6
8
  task :default => :spec
7
9
 
10
+ # run with rake publish
11
+ Grancher::Task.new do |g|
12
+ g.branch = 'gh-pages'
13
+ g.push_to = 'origin' # automatically push too
14
+
15
+ g.directory 'website'
16
+ end
17
+
18
+ desc 'Generate documentation for the admin_assistant plugin.'
19
+ Rake::RDocTask.new(:rdoc) do |rdoc|
20
+ rdoc.rdoc_dir = 'rdoc'
21
+ rdoc.title = 'AdminAssistant'
22
+ rdoc.options << '--line-numbers' << '--inline-source'
23
+ rdoc.rdoc_files.include('README')
24
+ rdoc.rdoc_files.include('lib/**/*.rb')
25
+ end
26
+
8
27
  desc 'Run all specs across all supported Rails gem versions.'
9
28
  task :spec do
10
29
  supported_versions = %w(2.1.0 2.1.2 2.2.2 2.3.2 2.3.3 2.3.4)
@@ -16,7 +35,7 @@ task :spec do
16
35
  if !missing.empty?
17
36
  puts "Missing Rails versions #{missing.join(',')}; please install and then re-run tests"
18
37
  else
19
- cmd = "cd test_rails_app && " + (
38
+ cmd = "cd rails_2_test && " + (
20
39
  supported_versions.map { |version|
21
40
  "echo '===== Testing #{version} =====' && RAILS_GEM_VERSION=#{version} rake"
22
41
  }.join(" && ")
@@ -36,7 +55,7 @@ begin
36
55
  gem.homepage = "http://github.com/fhwang/admin_assistant"
37
56
  gem.authors = ["Francis Hwang"]
38
57
  gem.add_dependency "will_paginate"
39
- gem.files.exclude "test_rails_app/**/*"
58
+ gem.files.exclude "rails_2_test"
40
59
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
41
60
  end
42
61
  Jeweler::GemcutterTasks.new
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.4
1
+ 2.0.0.pre1
@@ -4,14 +4,14 @@
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
- s.name = "admin_assistant"
8
- s.version = "1.0.4"
7
+ s.name = %q{admin_assistant}
8
+ s.version = "2.0.0.pre1"
9
9
 
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
10
+ s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Francis Hwang"]
12
- s.date = "2013-02-07"
13
- s.description = "admin_assistant is a Rails plugin that automates a lot of features typically needed in admin interfaces."
14
- s.email = "sera@fhwang.net"
12
+ s.date = %q{2011-05-08}
13
+ s.description = %q{admin_assistant is a Rails plugin that automates a lot of features typically needed in admin interfaces.}
14
+ s.email = %q{sera@fhwang.net}
15
15
  s.extra_rdoc_files = [
16
16
  "README"
17
17
  ]
@@ -54,11 +54,12 @@ Gem::Specification.new do |s|
54
54
  "lib/images/sort-asc.png",
55
55
  "lib/images/sort-desc.png",
56
56
  "lib/javascripts/admin_assistant.js",
57
+ "lib/javascripts/jquery.tokeninput.js",
57
58
  "lib/stylesheets/activescaffold.css",
58
59
  "lib/stylesheets/default.css",
60
+ "lib/stylesheets/token-input.css",
59
61
  "lib/views/_polymorphic_field_search.html.erb",
60
- "lib/views/_restricted_autocompleter.html.erb",
61
- "lib/views/autocomplete.html.erb",
62
+ "lib/views/_token_input.html.erb",
62
63
  "lib/views/form.html.erb",
63
64
  "lib/views/index.html.erb",
64
65
  "lib/views/multi_form.html.erb",
@@ -133,12 +134,13 @@ Gem::Specification.new do |s|
133
134
  "website/screenshots.markdown",
134
135
  "website/tutorial.markdown"
135
136
  ]
136
- s.homepage = "http://github.com/fhwang/admin_assistant"
137
+ s.homepage = %q{http://github.com/fhwang/admin_assistant}
137
138
  s.require_paths = ["lib"]
138
- s.rubygems_version = "1.8.25"
139
- s.summary = "admin_assistant is a Rails plugin that automates a lot of features typically needed in admin interfaces."
139
+ s.rubygems_version = %q{1.3.7}
140
+ s.summary = %q{admin_assistant is a Rails plugin that automates a lot of features typically needed in admin interfaces.}
140
141
 
141
142
  if s.respond_to? :specification_version then
143
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
142
144
  s.specification_version = 3
143
145
 
144
146
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
data/install.rb CHANGED
@@ -3,24 +3,19 @@ require 'pathname'
3
3
 
4
4
  outer = File.dirname(__FILE__)
5
5
 
6
- # Delete test_rails_app and various doc directories, unless you're actually
6
+ # Delete rails_2_test and various doc directories, unless you're actually
7
7
  # developing admin_assistant itself
8
- test_rails_app = Pathname.new("#{outer}/test_rails_app").realpath.to_s
8
+ test_rails_app = Pathname.new("#{outer}/rails_2_test").realpath.to_s
9
9
  unless RAILS_ROOT == test_rails_app
10
- %w(doc test_rails_app website).each do |dir|
10
+ %w(doc rails_2_test website).each do |dir|
11
11
  FileUtils.rm_rf "#{outer}/#{dir}"
12
12
  end
13
13
  end
14
14
 
15
15
  # Copy over static assets
16
- css_dir = "#{RAILS_ROOT}/public/stylesheets/admin_assistant"
17
- FileUtils.mkdir(css_dir) unless File.exist?(css_dir)
18
- FileUtils.cp_r(Dir.glob("#{outer}/lib/stylesheets/*"), css_dir)
19
- FileUtils.copy(
20
- "#{outer}/lib/javascripts/admin_assistant.js",
21
- "#{RAILS_ROOT}/public/javascripts/admin_assistant.js"
22
- )
23
- images_dir = "#{RAILS_ROOT}/public/images/admin_assistant"
24
- FileUtils.mkdir(images_dir) unless File.exist?(images_dir)
25
- FileUtils.cp_r(Dir.glob("#{outer}/lib/images/*"), images_dir)
16
+ %w(stylesheets javascripts images).each do |asset_type|
17
+ asset_dir = "#{Rails.root}/public/#{asset_type}/admin_assistant"
18
+ FileUtils.mkdir(asset_dir) unless File.exist?(asset_dir)
19
+ FileUtils.cp_r(Dir.glob("#{outer}/lib/#{asset_type}/*"), asset_dir)
20
+ end
26
21
 
@@ -1,16 +1,12 @@
1
1
  $: << File.join(File.dirname(__FILE__), '../vendor/ar_query/lib')
2
- files = %w(
3
- column virtual_column active_record_column association_target
4
- belongs_to_column builder date_time_range_end_point_selector
5
- default_search_column file_column_column form_view has_many_column helper
6
- index paperclip_column polymorphic_belongs_to_column request/base
7
- request/autocomplete request/create request/destroy request/edit
8
- request/index request/new request/show request/update search show_view
9
- )
10
- files.each do |file|
11
- require "#{File.dirname(__FILE__)}/admin_assistant/#{file}"
2
+ require 'find'
3
+ require 'admin_assistant/column'
4
+ Find.find(File.dirname(__FILE__)) do |path|
5
+ if path =~ %r|\.rb$| && path !~ %r|admin_assistant\.rb$| &&
6
+ path !~ %r|admin_assistant/column\.rb$|
7
+ require path
8
+ end
12
9
  end
13
-
14
10
  require 'will_paginate'
15
11
 
16
12
  class AdminAssistant
@@ -166,8 +166,8 @@ class AdminAssistant
166
166
  js_name = "#{form.object.class.name.underscore}_#{name}"
167
167
  name = @clear_link || "Clear"
168
168
  h << @action_view.send(
169
- :link_to_function, name,
170
- "AdminAssistant.clear_datetime_select('#{js_name}')"
169
+ :link_to, name, '#',
170
+ 'data-prefix' => js_name, :class => 'clear_datetime_select'
171
171
  )
172
172
  end
173
173
  h
@@ -270,16 +270,15 @@ class AdminAssistant
270
270
 
271
271
  def ajax_toggle_inner_html(record)
272
272
  div_id = ajax_toggle_div_id record
273
- @action_view.link_to_remote(
273
+ @action_view.link_to(
274
274
  string(record),
275
- :update => div_id,
276
- :url => {
275
+ {
277
276
  :action => 'update', :id => record.id, :from => div_id,
278
277
  record.class.name.underscore.to_sym => {
279
278
  name => (!value(record) ? '1' : '0')
280
279
  }
281
280
  },
282
- :success => "$(#{div_id}).hide(); $(#{div_id}).appear()"
281
+ {:class => 'toggle', :rel => 'nofollow', 'data-method' => 'put'}
283
282
  )
284
283
  end
285
284
 
@@ -142,7 +142,7 @@ class AdminAssistant
142
142
  def render_autocompleter(form)
143
143
  @action_view.send(
144
144
  :render,
145
- :file => AdminAssistant.template_file('_restricted_autocompleter'),
145
+ :file => AdminAssistant.template_file('_token_input'),
146
146
  :use_full_path => false,
147
147
  :locals => {
148
148
  :form => form, :column => @column,
@@ -176,7 +176,7 @@ class AdminAssistant
176
176
  def render_autocompleter(form)
177
177
  @action_view.send(
178
178
  :render,
179
- :file => AdminAssistant.template_file('_restricted_autocompleter'),
179
+ :file => AdminAssistant.template_file('_token_input'),
180
180
  :use_full_path => false,
181
181
  :locals => {
182
182
  :form => form, :column => @column,
@@ -238,8 +238,9 @@ class AdminAssistant
238
238
  input << comparator_html(form.object) << ' ' if @comparators == :all
239
239
  input << form.datetime_select(name, :include_blank => true)
240
240
  input << @action_view.send(
241
- :link_to_function, 'Clear',
242
- "AdminAssistant.clear_datetime_select('search_#{name.underscore}')"
241
+ :link_to, 'Clear', '#',
242
+ 'data-prefix' => "search_#{name.underscore}",
243
+ :class => 'clear_datetime_select'
243
244
  )
244
245
  end
245
246
  input
@@ -254,8 +255,9 @@ class AdminAssistant
254
255
  :datetime_separator => ' &mdash; ', :time_separator => ' : '
255
256
  ).select_datetime
256
257
  input << @action_view.send(
257
- :link_to_function, 'Clear',
258
- "AdminAssistant.clear_datetime_select('search_#{name.underscore}_#{comparator}')"
258
+ :link_to, 'Clear', '#',
259
+ 'data-prefix' => "search_#{name.underscore}_#{comparator}",
260
+ :class => 'clear_datetime_select'
259
261
  )
260
262
  input
261
263
  end
@@ -2,8 +2,15 @@ class AdminAssistant
2
2
  module Helper
3
3
  def admin_assistant_includes(opts = {})
4
4
  theme = opts[:theme] || 'default'
5
- stylesheet_link_tag("admin_assistant/#{theme}") +
6
- javascript_include_tag('admin_assistant')
5
+ tags = stylesheet_link_tag("admin_assistant/#{theme}")
6
+ tags << stylesheet_link_tag("admin_assistant/token-input")
7
+ js_dir = Pathname.new(Rails.root) + "public/javascripts/admin_assistant"
8
+ Dir.entries(js_dir).each do |entry|
9
+ if entry =~ /\.js$/
10
+ tags << javascript_include_tag("admin_assistant/#{entry}")
11
+ end
12
+ end
13
+ tags
7
14
  end
8
15
  end
9
16
  end
@@ -216,13 +216,13 @@ class AdminAssistant
216
216
  end
217
217
 
218
218
  def delete_link(record)
219
- @action_view.link_to_remote(
219
+ @action_view.link_to(
220
220
  'Delete',
221
- :url => {:action => 'destroy', :id => record.id},
222
- :confirm => 'Are you sure?',
223
- :success =>
224
- "Effect.Fade('#{@admin_assistant.model_class.name.underscore}_#{record.id}', {duration: 0.25})",
225
- :method => :delete
221
+ {:action => 'destroy', :id => record.id},
222
+ {
223
+ 'data-confirm' => 'Are you sure?', :rel => 'nofollow',
224
+ 'data-method' => 'delete', :class => 'destroy'
225
+ }
226
226
  )
227
227
  end
228
228
 
@@ -8,34 +8,31 @@ class AdminAssistant
8
8
  end
9
9
 
10
10
  def call
11
- render_template_file(
12
- 'autocomplete', :layout => false,
13
- :locals => {
14
- :records => records, :prefix => underscored_assoc_class_name,
15
- :associated_class => associated_class
16
- }
17
- )
11
+ results = records.map { |record|
12
+ {:id => record.id.to_s, :name => record.send(record_name_field)}
13
+ }
14
+ @controller.send(:render, :json => results.to_json)
15
+ end
16
+
17
+ def record_name_field
18
+ AssociationTarget.new(associated_class).default_name_method
18
19
  end
19
20
 
20
21
  def records
21
22
  action =~ /autocomplete_(.*)/
22
- associated_class = Module.const_get $1.camelize
23
- target = AssociationTarget.new associated_class
24
- field = target.default_name_method
25
23
  associated_class.find(
26
24
  :all,
27
25
  :conditions => [
28
- "LOWER(#{field}) like ?",
26
+ "LOWER(#{record_name_field}) like ?",
29
27
  "%#{search_string.downcase unless search_string.nil?}%"
30
28
  ],
31
- :limit => 10, :order => "length(#{field}), lower(#{field})"
29
+ :limit => 10,
30
+ :order => "length(#{record_name_field}), lower(#{record_name_field})"
32
31
  )
33
32
  end
34
33
 
35
34
  def search_string
36
- @controller.params[
37
- "#{underscored_assoc_class_name}_autocomplete_input"
38
- ]
35
+ @controller.params['q']
39
36
  end
40
37
 
41
38
  def underscored_assoc_class_name
@@ -3,251 +3,179 @@ Don't edit this file: It gets re-copied every time the server starts.
3
3
  ******************************************************************************/
4
4
 
5
5
  var AdminAssistant = {};
6
- AdminAssistant.clear_datetime_select = function(name) {
7
- $R(1,5).each(function(index) {
8
- $(name + '_' + index + 'i').value = '';
9
- });
10
- };
11
6
 
12
- AdminAssistant.show_search_form = function() {
13
- $('search_form').show();
7
+ $(document).ready(function() {
8
+ $('.clear_datetime_select').click(function(event) {
9
+ name = $(event.target).attr('data-prefix');
10
+ $.each([1,2,3,4,5], function(i, val) {
11
+ $('#' + name + '_' + val + 'i').attr('value', '');
12
+ });
13
+ return false;
14
+ });
15
+
16
+ $('.index #show_search_form').click(function() {
17
+ $('#search_form').show();
18
+ return false;
19
+ });
20
+
21
+ $('.index a.destroy').click(function(event) {
22
+ jqElt = $(event.target);
23
+ if (confirm(jqElt.attr('data-confirm'))) {
24
+ url = jqElt.attr('href');
25
+ jqTr = jqElt.closest('tr')
26
+ $.post(
27
+ url,
28
+ {"_method": jqElt.attr('data-method')},
29
+ function() {
30
+ jqTr.fadeOut();
31
+ }
32
+ );
33
+ }
34
+ return false;
35
+ });
36
+
37
+ $('.index a.toggle').live('click', function(event) {
38
+ url = $(event.target).attr('href');
39
+ container = '#' + $(event.target).parent().attr('id');
40
+ $.post(
41
+ url,
42
+ {},
43
+ function(data) {
44
+ $(container).fadeOut(50, function() {
45
+ $(container).html(data);
46
+ $(container).fadeIn()
47
+ });
48
+ }
49
+ );
50
+ return false;
51
+ });
52
+ });
53
+
54
+ AdminAssistant.PolymorphicFieldSearch = function(name) {
55
+ this.name = name;
56
+ this.initialize();
14
57
  };
15
58
 
16
- AdminAssistant.PolymorphicFieldSearch = Class.create();
17
59
  AdminAssistant.PolymorphicFieldSearch.prototype = {
18
- initialize: function(name, types) {
19
- this.name = name;
20
- this.hiddenFieldId = 'search_' + name + '_id';
21
- this.hiddenTypeFieldId = 'search_' + name + '_type';
22
- this.autocompleteTypes = types.autocompleteTypes;
23
- this.autocompleters = {};
24
- this.autocompleteTypes.each(function(autocompleteType) {
25
- autocompleter = this.newAutocompleter(autocompleteType);
26
- this.autocompleters[autocompleteType.name] = autocompleter;
27
- }, this);
28
- this.idTypes = types.idTypes;
29
- this.idTypes.each(function(idType) {
30
- Event.observe(
31
- this.name + '_' + idType.name + "_id", 'keyup',
32
- this.setHiddenFieldsFromIdField.bind(this)
33
- );
34
- }, this);
35
- this.selectTypes = types.selectTypes;
36
- this.selectTypes.each(function(selectType) {
37
- Event.observe(
38
- this.name + '_' + selectType.name + "_id", 'change',
39
- this.setHiddenFieldsFromSelectField.bind(this)
40
- );
41
- }, this);
60
+ initialize: function() {
61
+ this.initAutocompleters();
62
+ this.initSelectors();
63
+ this.initTextFields();
42
64
  },
43
65
 
44
- clearHiddenFields: function() {
45
- this.hiddenField().value = '';
46
- this.hiddenTypeField().value = '';
66
+ initAutocompleters: function() {
67
+ var fieldSearch = this;
68
+ $.each(this.autocompleterElts(), function(i, elt) {
69
+ var valueType = $(elt).attr('data-value-type')
70
+ var opts = {
71
+ 'crossDomain': false, 'tokenLimit': 1,
72
+ 'onAdd': function(item) {
73
+ fieldSearch.tokenInputOnAdd(item, valueType, elt);
74
+ },
75
+ 'onDelete': function(item) {
76
+ fieldSearch.tokenInputOnDelete(item, valueType);
77
+ }
78
+ };
79
+ var initialId = $(elt).attr('data-initial-id');
80
+ var initialName = $(elt).attr('data-initial-name');
81
+ if (initialId && initialName) {
82
+ opts['prePopulate'] = [{'id': initialId, 'name': initialName}];
83
+ }
84
+ $(elt).tokenInput($(elt).attr('data-autocomplete-url'), opts)
85
+ });
47
86
  },
48
87
 
49
- clearInputsExceptFor: function(name_to_not_clear) {
50
- this.autocompleteTypes.each(function(autocompleteType) {
51
- if (autocompleteType.name != name_to_not_clear) {
52
- var autocompleter = this.autocompleters[autocompleteType.name]
53
- autocompleter.clearTextField();
54
- autocompleter.setClearLinkVisibility();
55
- }
56
- }, this);
57
- this.idTypes.each(function(idType) {
58
- if (idType.name != name_to_not_clear) {
59
- $(this.name + '_' + idType.name + '_id').value = '';
60
- }
61
- }, this);
62
- this.selectTypes.each(function(selectType) {
63
- if (selectType.name != name_to_not_clear) {
64
- $(this.name + '_' + selectType.name + '_id').value = '';
65
- }
66
- }, this);
88
+ initSelectors: function() {
89
+ var fieldSearch = this;
90
+ $.each(this.selectorElts(), function(i, elt) {
91
+ $(elt).bind('change', function(evt) {
92
+ fieldSearch.update(
93
+ $(this).val(), $(this).attr('data-value-type'), this
94
+ );
95
+ });
96
+ });
67
97
  },
68
98
 
69
- hiddenField: function() {
70
- return $(this.hiddenFieldId);
99
+ initTextFields: function() {
100
+ var fieldSearch = this;
101
+ $.each(this.textFieldElts(), function(i, elt) {
102
+ $(elt).bind('keyup', function(evt) {
103
+ fieldSearch.update(
104
+ $(this).val(), $(this).attr('data-value-type'), this
105
+ );
106
+ });
107
+ });
71
108
  },
72
109
 
73
- hiddenTypeField: function() {
74
- return $(this.hiddenTypeFieldId);
110
+ autocompleterElts: function() {
111
+ var acElts = [];
112
+ $("#" + this.rootId() + " input").each(function(i, elt) {
113
+ if ($(elt).attr('data-behavior') == 'autocomplete') {
114
+ acElts.push(elt);
115
+ }
116
+ });
117
+ return acElts;
75
118
  },
76
119
 
77
- newAutocompleter: function(autocompleteType) {
78
- options = {
79
- clearLink: autocompleteType.clearLink,
80
- includeBlank: true,
81
- modelName: autocompleteType.name,
82
- palette: autocompleteType.palette,
83
- paletteClonesInputWidth: false,
84
- parameters: autocompleteType.parameters,
85
- paramName: autocompleteType.name + '_autocomplete_input',
86
- textField: autocompleteType.textField
87
- };
88
- options.afterAutocomplete = function(value) {
89
- this.hiddenTypeField().value = autocompleteType.type;
90
- this.clearInputsExceptFor(autocompleteType.name);
91
- }.bind(this);
92
- options.afterClearSelected = function(value) {
93
- this.hiddenTypeField().value = '';
94
- }.bind(this);
95
- return new AdminAssistant.RestrictedAutocompleter(
96
- autocompleteType.name, this.hiddenFieldId, autocompleteType.url,
97
- options
98
- );
120
+ clearAutocompleterView: function(elt) {
121
+ containerDiv =
122
+ "#polymorphic_search_" + $(elt).attr('id').replace(/_id/, '');
123
+ // 1. remove the div containing the selected token
124
+ $(containerDiv + " .token-input-token").remove();
125
+ // 2. show the autocompleter input with a blank value
126
+ $(containerDiv + " input[autocomplete=off]").show().val("");
99
127
  },
100
128
 
101
- setHiddenFieldsFromIdField: function(event) {
102
- input = event.findElement();
103
- idType = this.idTypes.detect(function(idt) {
104
- return (this.name + '_' + idt.name + '_id' == input.id);
105
- }, this);
106
- if (input.value == '') {
107
- if (this.hiddenTypeField().value == idType.type) {
108
- this.clearHiddenFields();
109
- }
110
- } else {
111
- this.hiddenField().value = input.value;
112
- this.hiddenTypeField().value = idType.type;
113
- this.clearInputsExceptFor(idType.name);
114
- }
129
+ rootId: function() {
130
+ return "polymorphic_search_" + this.name;
115
131
  },
116
132
 
117
- setHiddenFieldsFromSelectField: function(event) {
118
- select = event.findElement();
119
- selectType = this.selectTypes.detect(function(st) {
120
- return (this.name + '_' + st.name + '_id' == select.id);
121
- }, this);
122
- if (select.value == '') {
123
- if (this.hiddenTypeField().value == selectType.type) {
124
- this.clearHiddenFields();
125
- }
126
- } else {
127
- this.hiddenField().value = select.value;
128
- this.hiddenTypeField().value = selectType.type;
129
- this.clearInputsExceptFor(selectType.name);
130
- }
131
- }
132
- }
133
-
134
- /*
135
- This autocompleter restricts based on a list of names and matching IDs; the IDs
136
- are set in a hidden field. Arguments
137
- */
138
- AdminAssistant.RestrictedAutocompleter = Class.create();
139
- AdminAssistant.RestrictedAutocompleter.prototype = {
140
- initialize: function(name, hiddenField, url, options) {
141
- this.name = name;
142
- this.textField = options.textField || (this.name + '_autocomplete_input');
143
- this.palette = options.palette || (this.name + '_autocomplete_palette');
144
- this.selectedTextFieldValue = $(this.textField).value;
145
- this.hiddenField = hiddenField;
146
- this.includeBlank = options.includeBlank;
147
- this.modelName = options.modelName || this.name;
148
- this.clearLink = options.clearLink || ('clear_' + this.name + '_link');
149
- ajaxAutocompleterOptions = {
150
- afterUpdateElement: this.autocompleteAfterUpdateElement.bind(this),
151
- fullSearch: true,
152
- onHide: this.autocompleteOnHide,
153
- parameters: options.parameters,
154
- paramName: options.paramName,
155
- partialChars: 1
156
- };
157
- if (!options.paletteClonesInputWidth) {
158
- ajaxAutocompleterOptions.onShow = this.onShowWithoutCloningInputWidth;
159
- }
160
- var ac = new Ajax.Autocompleter(
161
- this.textField, this.palette, url, ajaxAutocompleterOptions
162
- );
163
- this.changeArrowBehavior(ac);
164
- this.setClearLinkVisibility();
165
- Event.observe(this.clearLink, 'click', function(event) {
166
- this.clearSelected();
167
- }.bind(this));
168
- this.afterAutocomplete = options.afterAutocomplete;
169
- this.afterClearSelected = options.afterClearSelected;
133
+ selectorElts: function() {
134
+ sElts = [];
135
+ $("#" + this.rootId() + " select").each(function(i, elt) {
136
+ if ($(elt).attr('data-behavior') == 'select') {
137
+ sElts.push(elt);
138
+ }
139
+ });
140
+ return sElts;
170
141
  },
171
142
 
172
- /*
173
- This is the callback that fires after a selection is made from the
174
- autocompleter results.
175
-
176
- In addition to setting hidden id fields, it will place the text label of the
177
- selected item in the search field. It assumes that your selectedElement is
178
- one with simple text contents or some markup structure with an element of
179
- class "title". In the latter case, it will use the text of the "title"
180
- element.
181
- */
182
- autocompleteAfterUpdateElement: function(element, selectedElement) {
183
- var id_name = element.id;
184
- var input_id = id_name.substr(id_name.length - 1)
185
- var selected_value = selectedElement.id.substr(this.modelName.length)
186
-
187
- // If they have more complex markup inside the selection, get the "title" element
188
- var title_element = selectedElement.down(".title")
189
- if (title_element) selectedElement = title_element
190
-
191
- $(this.hiddenField).value = selected_value
192
- this.selectedTextFieldValue =
193
- selectedElement.innerHTML.unescapeHTML().strip();
194
- this.setClearLinkVisibility();
195
- if (this.afterAutocomplete) { this.afterAutocomplete(selected_value); }
196
- },
197
-
198
- /*
199
- Refresh the text fill-in field to the value reflected in the underlying
200
- hidden input fields
201
- */
202
- autocompleteOnHide: function( element, update ) {
203
- if (this.selectedTextFieldValue) {
204
- element.value = this.selectedTextFieldValue;
205
- }
206
- new Effect.Fade(update,{duration:0.15});
207
- },
208
-
209
- /*
210
- Overriding totally wierd arrow-up and arrow-down scrolling behavior built
211
- into the autocompleter in scriptaculous 1.7.0
212
- */
213
- changeArrowBehavior: function(ac) {
214
- ac.markPrevious = function() {
215
- if(this.index > 0) this.index--
216
- else this.index = this.entryCount-1;
217
- };
218
- ac.markNext = function() {
219
- if(this.index < this.entryCount-1) this.index++
220
- else this.index = 0;
221
- };
143
+ textFieldElts: function() {
144
+ var tfElts = []
145
+ $("#" + this.rootId() + " input[type!=hidden]").each(function(i, elt) {
146
+ if ($(elt).attr('data-behavior') == 'id') {
147
+ tfElts.push(elt);
148
+ }
149
+ });
150
+ return tfElts;
222
151
  },
223
152
 
224
- clearSelected: function() {
225
- $(this.hiddenField).value = '';
226
- this.clearTextField();
227
- this.setClearLinkVisibility();
228
- if (this.afterClearSelected) { this.afterClearSelected(); }
153
+ tokenInputOnAdd: function(item, valueType, updatedElt) {
154
+ this.update(item.id, valueType, updatedElt);
229
155
  },
230
156
 
231
- onShowWithoutCloningInputWidth: function(element, update){
232
- if(!update.style.position || update.style.position=='absolute') {
233
- update.style.position = 'absolute';
234
- Position.clone(element, update, {
235
- setHeight: false, setWidth: false, offsetTop: element.offsetHeight
236
- });
237
- }
238
- Effect.Appear(update,{duration:0.15});
157
+ tokenInputOnDelete: function(item, valueType) {
158
+ this.update(null, null, null);
239
159
  },
240
160
 
241
- clearTextField: function() {
242
- $(this.textField).value = '';
243
- },
244
-
245
- setClearLinkVisibility: function() {
246
- if ($(this.textField).value == '') {
247
- $(this.clearLink).hide();
248
- } else {
249
- if (this.includeBlank) { $(this.clearLink).show(); }
250
- }
161
+ update: function(id, type, updatedElt) {
162
+ $('#search_' + this.name + "_id").val(id);
163
+ $('#search_' + this.name + "_type").val(type);
164
+ var fieldSearch = this;
165
+ $.each(this.autocompleterElts(), function(i, elt) {
166
+ idFromUpdatedElt = $(updatedElt).attr('id');
167
+ idFromThisAutocompleter = $(elt).attr('id');
168
+ if (idFromUpdatedElt != idFromThisAutocompleter) {
169
+ fieldSearch.clearAutocompleterView(elt);
170
+ }
171
+ });
172
+ $.each(this.selectorElts(), function(i, elt) {
173
+ if (elt != updatedElt) { $(elt).val(''); }
174
+ });
175
+ $.each(this.textFieldElts(), function(i, elt) {
176
+ if (elt != updatedElt) { $(elt).val(''); }
177
+ });
251
178
  }
252
- }
179
+ };
180
+
253
181