backlog 0.35.5 → 0.36.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. data/Gemfile +19 -0
  2. data/Gemfile~ +4 -0
  3. data/History.txt +25 -0
  4. data/Rakefile +3 -3
  5. data/app/controllers/{application.rb → application_controller.rb} +1 -2
  6. data/app/controllers/backlogs_controller.rb +0 -16
  7. data/app/controllers/search_controller.rb +0 -2
  8. data/app/controllers/user_controller.rb +7 -7
  9. data/app/controllers/work_locks_controller.rb +2 -2
  10. data/app/controllers/works_controller.rb +23 -23
  11. data/app/helpers/application_helper.rb +9 -6
  12. data/app/helpers/backlogs_helper.rb +1 -1
  13. data/app/helpers/periods_helper.rb +1 -1
  14. data/app/models/backlog.rb +13 -10
  15. data/app/models/period.rb +0 -5
  16. data/app/models/sidebar.rb +1 -0
  17. data/app/models/task.rb +4 -10
  18. data/app/models/user.rb +5 -6
  19. data/app/models/user_notify.rb +0 -1
  20. data/app/models/work.rb +20 -25
  21. data/app/models/works_report_filter.rb +4 -4
  22. data/app/views/backlogs/_buttons.rhtml +1 -1
  23. data/app/views/backlogs/_form.rhtml +5 -9
  24. data/app/views/layouts/_left_top.rhtml +0 -1
  25. data/app/views/periods/_form.rhtml +1 -1
  26. data/app/views/search/results.rhtml +1 -12
  27. data/app/views/task_notify/{invite_en.rhtml → invite.en.html.erb} +0 -0
  28. data/app/views/task_notify/{invite_no.rhtml → invite.no.html.erb} +0 -0
  29. data/app/views/tasks/_task.rhtml +49 -50
  30. data/app/views/tasks/edit.rhtml +4 -4
  31. data/app/views/tasks/start_work.rjs +1 -1
  32. data/app/views/user/_edit.rhtml +1 -1
  33. data/app/views/user/change_password.rhtml +1 -1
  34. data/app/views/user/edit.rhtml +4 -4
  35. data/app/views/user/signup.rhtml +2 -2
  36. data/app/views/user_notify/{change_password_en.rhtml → change_password.en.html.erb} +0 -0
  37. data/app/views/user_notify/{change_password_no.rhtml → change_password.no.html.erb} +0 -0
  38. data/app/views/user_notify/{forgot_password_en.rhtml → forgot_password.en.html.erb} +0 -0
  39. data/app/views/user_notify/{forgot_password_no.rhtml → forgot_password.no.html.erb} +0 -0
  40. data/app/views/user_notify/{monitoring_en.rhtml → monitoring.en.html.erb} +0 -0
  41. data/app/views/user_notify/{monitoring_no.rhtml → monitoring.no.html.erb} +0 -0
  42. data/app/views/user_notify/{monitoring_invitation_en.rhtml → monitoring_invitation.en.html.erb} +0 -0
  43. data/app/views/user_notify/{monitoring_invitation_no.rhtml → monitoring_invitation.no.html.erb} +0 -0
  44. data/app/views/user_notify/{signup_en.rhtml → signup.en.html.erb} +0 -0
  45. data/app/views/user_notify/{signup_no.rhtml → signup.no.html.erb} +0 -0
  46. data/app/views/work_lock_notify/{lock_en.rhtml → lock.en.html.erb} +0 -0
  47. data/app/views/work_lock_notify/{lock_no.rhtml → lock.no.html.erb} +0 -0
  48. data/app/views/work_lock_notify/{nag_en.rhtml → nag.en.html.erb} +0 -0
  49. data/app/views/work_lock_notify/{nag_no.rhtml → nag.no.html.erb} +0 -0
  50. data/app/views/works/_form.rhtml +6 -6
  51. data/app/views/works/_new_row.rhtml +6 -6
  52. data/app/views/works/_row.rhtml +2 -2
  53. data/app/views/works/daily_work_sheet.rhtml +1 -1
  54. data/app/views/works/list.rhtml +6 -6
  55. data/app/views/works/list_excel.rhtml +8 -4
  56. data/app/views/works/timeliste.rhtml +14 -14
  57. data/app/views/works/update_row.rjs +1 -1
  58. data/app/views/works/weekly_work_sheet.rhtml +5 -5
  59. data/app/views/works/weekly_work_sheet_details.rhtml +5 -5
  60. data/config/boot.rb +108 -27
  61. data/config/database.yml +3 -26
  62. data/config/environment.rb +4 -12
  63. data/config/environments/development.rb +0 -1
  64. data/config/initializers/jdbc.rb +7 -0
  65. data/config/initializers/mongrel.rb +83 -0
  66. data/config/locales/en.yml +189 -0
  67. data/config/locales/no.yml +192 -0
  68. data/config/preinitializer.rb +20 -0
  69. data/cruise_build.sh +10 -0
  70. data/cruise_config.rb +1 -1
  71. data/db/migrate/20100720124707_merge_work_account_into_backlog.rb +74 -0
  72. data/db/schema.rb +93 -127
  73. data/lib/class_table_inheritance.rb +53 -11
  74. data/lib/tasks/jdbc.rake +8 -0
  75. data/lib/user_system.rb +5 -1
  76. data/public/javascripts/controls.js +76 -79
  77. data/public/javascripts/dragdrop.js +166 -167
  78. data/public/javascripts/effects.js +174 -168
  79. data/public/javascripts/prototype.js +470 -334
  80. data/public/stylesheets/mwrt002.css +6 -6
  81. data/script/dbconsole +3 -0
  82. data/test/fixtures/backlogs.yml +2 -2
  83. data/test/fixtures/work_lock_subscriptions.yml +2 -2
  84. data/test/fixtures/works.yml +6 -6
  85. data/test/functional/absences_controller_test.rb +1 -1
  86. data/test/functional/backlogs_controller_test.rb +4 -4
  87. data/test/functional/customers_controller_test.rb +1 -1
  88. data/test/functional/dashboard_controller_test.rb +1 -1
  89. data/test/functional/estimates_controller_test.rb +1 -1
  90. data/test/functional/groups_controller_test.rb +1 -1
  91. data/test/functional/parties_controller_test.rb +1 -1
  92. data/test/functional/periods_controller_test.rb +1 -1
  93. data/test/functional/public_holidays_controller_test.rb +1 -1
  94. data/test/functional/search_controller_test.rb +1 -1
  95. data/test/functional/task_files_controller_test.rb +1 -1
  96. data/test/functional/tasks_controller_test.rb +6 -6
  97. data/test/functional/user_controller_test.rb +3 -2
  98. data/test/functional/welcome_controller_test.rb +1 -1
  99. data/test/functional/work_locks_controller_test.rb +1 -1
  100. data/test/functional/works_controller_test.rb +11 -11
  101. data/test/test_helper.rb +2 -2
  102. data/test/unit/absence_test.rb +1 -1
  103. data/test/unit/configuration_test.rb +1 -1
  104. data/test/unit/customer_test.rb +1 -1
  105. data/test/unit/estimate_test.rb +1 -1
  106. data/test/unit/group_test.rb +1 -1
  107. data/test/unit/party_test.rb +1 -1
  108. data/test/unit/period_test.rb +1 -1
  109. data/test/unit/public_holiday_test.rb +1 -1
  110. data/test/unit/task_file_test.rb +1 -1
  111. data/test/unit/task_test.rb +1 -1
  112. data/test/unit/user_test.rb +1 -1
  113. data/test/unit/work_lock_subscription_test.rb +1 -1
  114. data/test/unit/work_lock_test.rb +1 -1
  115. data/test/unit/work_test.rb +8 -8
  116. data/vendor/plugins/acts_as_list/lib/active_record/acts/list.rb +3 -3
  117. data/vendor/plugins/assert_cookie/lib/assert_cookie.rb +2 -2
  118. data/vendor/plugins/auto_complete/README +23 -0
  119. data/vendor/plugins/auto_complete/Rakefile +22 -0
  120. data/vendor/plugins/auto_complete/init.rb +2 -0
  121. data/vendor/plugins/auto_complete/lib/auto_complete.rb +47 -0
  122. data/vendor/plugins/auto_complete/lib/auto_complete_macros_helper.rb +143 -0
  123. data/vendor/plugins/auto_complete/test/auto_complete_test.rb +67 -0
  124. data/vendor/plugins/backlog_jira/init.rb +4 -0
  125. data/vendor/plugins/backlog_jira/{tasks → lib/tasks}/backlog_jira_tasks.rake +0 -0
  126. data/vendor/plugins/has_history/{tasks → lib/tasks}/has_history_tasks.rake +0 -0
  127. metadata +745 -817
  128. data/#SearchRequest.xml# +0 -3443
  129. data/app/controllers/application.rb~ +0 -207
  130. data/app/controllers/work_accounts_controller.rb +0 -58
  131. data/app/helpers/work_accounts_helper.rb +0 -2
  132. data/app/models/work_account.rb +0 -18
  133. data/app/models/work_lock_subscription.rb +0 -3
  134. data/app/views/work_accounts/_form.rhtml +0 -16
  135. data/app/views/work_accounts/_name_list.rhtml +0 -5
  136. data/app/views/work_accounts/_title.rhtml +0 -5
  137. data/app/views/work_accounts/edit.rhtml +0 -12
  138. data/app/views/work_accounts/list.rhtml +0 -31
  139. data/app/views/work_accounts/new.rhtml +0 -10
  140. data/app/views/work_accounts/show.rhtml +0 -50
  141. data/config/environments/localization_environment.rb +0 -10
  142. data/jira.log +0 -98246
  143. data/lang/en.yaml +0 -147
  144. data/lang/localizations.yaml +0 -2
  145. data/lang/no.yaml +0 -146
  146. data/lib/localization.rb +0 -88
  147. data/test/fixtures/work_accounts.yml +0 -7
  148. data/test/functional/work_accounts_controller_test.rb +0 -94
  149. data/test/unit/localization_test.rb +0 -47
  150. data/test/unit/work_account_test.rb +0 -10
@@ -1,6 +1,6 @@
1
1
  require File.dirname(__FILE__) + '/../test_helper'
2
2
 
3
- class EstimateTest < Test::Unit::TestCase
3
+ class EstimateTest < ActiveSupport::TestCase
4
4
  main_scenario
5
5
 
6
6
  # Replace this with your real tests.
@@ -1,6 +1,6 @@
1
1
  require File.dirname(__FILE__) + '/../test_helper'
2
2
 
3
- class GroupTest < Test::Unit::TestCase
3
+ class GroupTest < ActiveSupport::TestCase
4
4
  main_scenario
5
5
 
6
6
  # Replace this with your real tests.
@@ -1,6 +1,6 @@
1
1
  require File.dirname(__FILE__) + '/../test_helper'
2
2
 
3
- class PartyTest < Test::Unit::TestCase
3
+ class PartyTest < ActiveSupport::TestCase
4
4
  main_scenario
5
5
 
6
6
  # Replace this with your real tests.
@@ -1,6 +1,6 @@
1
1
  require File.dirname(__FILE__) + '/../test_helper'
2
2
 
3
- class PeriodTest < Test::Unit::TestCase
3
+ class PeriodTest < ActiveSupport::TestCase
4
4
  main_scenario
5
5
 
6
6
  def test_burn_down_graph
@@ -1,6 +1,6 @@
1
1
  require File.dirname(__FILE__) + '/../test_helper'
2
2
 
3
- class PublicHolidayTest < Test::Unit::TestCase
3
+ class PublicHolidayTest < ActiveSupport::TestCase
4
4
  fixtures :public_holidays
5
5
 
6
6
  # Replace this with your real tests.
@@ -1,6 +1,6 @@
1
1
  require File.dirname(__FILE__) + '/../test_helper'
2
2
 
3
- class TaskFileTest < Test::Unit::TestCase
3
+ class TaskFileTest < ActiveSupport::TestCase
4
4
  fixtures :tasks, :task_files, :estimates, :works
5
5
 
6
6
  # Replace this with your real tests.
@@ -1,6 +1,6 @@
1
1
  require File.dirname(__FILE__) + '/../test_helper'
2
2
 
3
- class TaskTest < Test::Unit::TestCase
3
+ class TaskTest < ActiveSupport::TestCase
4
4
  include UserSystem
5
5
 
6
6
  main_scenario
@@ -1,6 +1,6 @@
1
1
  require File.dirname(__FILE__) + '/../test_helper'
2
2
 
3
- class UserTest < Test::Unit::TestCase
3
+ class UserTest < ActiveSupport::TestCase
4
4
  main_scenario
5
5
  self.use_transactional_fixtures = false
6
6
 
@@ -1,6 +1,6 @@
1
1
  require File.dirname(__FILE__) + '/../test_helper'
2
2
 
3
- class WorkLockSubscriptionTest < Test::Unit::TestCase
3
+ class WorkLockSubscriptionTest < ActiveSupport::TestCase
4
4
  fixtures :work_lock_subscriptions
5
5
 
6
6
  # Replace this with your real tests.
@@ -1,6 +1,6 @@
1
1
  require File.dirname(__FILE__) + '/../test_helper'
2
2
 
3
- class WorkLockTest < Test::Unit::TestCase
3
+ class WorkLockTest < ActiveSupport::TestCase
4
4
  fixtures :work_locks
5
5
 
6
6
  # Replace this with your real tests.
@@ -1,7 +1,7 @@
1
1
  require File.dirname(__FILE__) + '/../test_helper'
2
2
  require 'user_system'
3
3
 
4
- class WorkTest < Test::Unit::TestCase
4
+ class WorkTest < ActiveSupport::TestCase
5
5
  include UserSystem
6
6
 
7
7
  main_scenario
@@ -50,20 +50,20 @@ class WorkTest < Test::Unit::TestCase
50
50
  assert_equal 1, Work.find_work_for_day(Date.parse('2007-06-12')).size
51
51
  end
52
52
 
53
- def test_works_for_week_by_work_account
53
+ def test_works_for_week_by_backlog
54
54
  Thread.current[:user] = users(:tesla)
55
- work_totals = Work.works_for_week_by_work_account(2007, 24, users(:tesla))
56
- assert_equal({work_accounts(:light_control) => [nil, BigDecimal('40'), BigDecimal('8'), nil, nil, nil, nil]}, work_totals)
55
+ work_totals = Work.works_for_week_by_backlog(2007, 24, users(:tesla))
56
+ assert_equal({backlogs(:first) => [nil, BigDecimal('40'), BigDecimal('8'), nil, nil, nil, nil]}, work_totals)
57
57
  end
58
58
 
59
- def test_works_for_week_by_work_account_anonymous
60
- work_totals = Work.works_for_week_by_work_account(2007, 24, nil)
61
- assert_equal({work_accounts(:light_control) => [nil, BigDecimal('30'), nil, nil, nil, nil, nil]}, work_totals)
59
+ def test_works_for_week_by_backlog_anonymous
60
+ work_totals = Work.works_for_week_by_backlog(2007, 24, nil)
61
+ assert_equal({backlogs(:first) => [nil, BigDecimal('30'), nil, nil, nil, nil, nil]}, work_totals)
62
62
  end
63
63
 
64
64
  def test_legal_to_register_work_if_the_same_date_is_marked_as_absent
65
65
  Thread.current[:user] = users(:tesla)
66
- Work.create!({:started_on => '2007-06-10', :user_id => 1000001, :work_account => work_accounts(:light_control)})
66
+ Work.create!({:started_on => '2007-06-10', :start_time => '17:59', :user_id => 1000001, :backlog => backlogs(:first)})
67
67
  end
68
68
 
69
69
  def test_calculate_hours
@@ -63,7 +63,7 @@ module ActiveRecord
63
63
 
64
64
  #{scope_condition_method}
65
65
 
66
- before_destroy :remove_from_list
66
+ before_destroy lambda{|r| r.remove_from_list(true)}
67
67
  before_create :add_to_list_bottom
68
68
  EOV
69
69
  end
@@ -120,10 +120,10 @@ module ActiveRecord
120
120
  end
121
121
 
122
122
  # Removes the item from the list.
123
- def remove_from_list
123
+ def remove_from_list(record_will_be_destroyed = false)
124
124
  if in_list?
125
125
  decrement_positions_on_lower_items
126
- update_attribute position_column, nil
126
+ update_attribute position_column, nil unless record_will_be_destroyed
127
127
  end
128
128
  end
129
129
 
@@ -30,12 +30,12 @@ module Test
30
30
  options[:value].each do |value|
31
31
  msg = build_message(message,
32
32
  "expected cookie value to include <?> but it was not found.", value)
33
- assert(cookie.value.include?(value), msg)
33
+ assert(cookie == value, msg)
34
34
  end
35
35
  else
36
36
  msg = build_message(message, "expected cookie value to be <?> but it was <?>.",
37
37
  options[:value], cookie.value)
38
- assert(cookie.value.include?(options[:value]), msg)
38
+ assert(cookie.first[:value].include?(options[:value]), msg)
39
39
  end if options.key?(:value)
40
40
 
41
41
  assert_call_or_value :path, options, cookie, message
@@ -0,0 +1,23 @@
1
+ Example:
2
+
3
+ # Controller
4
+ class BlogController < ApplicationController
5
+ auto_complete_for :post, :title
6
+ end
7
+
8
+ # View
9
+ <%= text_field_with_auto_complete :post, title %>
10
+
11
+ By default, auto_complete_for limits the results to 10 entries,
12
+ and sorts by the given field.
13
+
14
+ auto_complete_for takes a third parameter, an options hash to
15
+ the find method used to search for the records:
16
+
17
+ auto_complete_for :post, :title, :limit => 15, :order => 'created_at DESC'
18
+
19
+ For more examples, see script.aculo.us:
20
+ * http://script.aculo.us/demos/ajax/autocompleter
21
+ * http://script.aculo.us/demos/ajax/autocompleter_customized
22
+
23
+ Copyright (c) 2007 David Heinemeier Hansson, released under the MIT license
@@ -0,0 +1,22 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test auto_complete plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.pattern = 'test/**/*_test.rb'
12
+ t.verbose = true
13
+ end
14
+
15
+ desc 'Generate documentation for auto_complete plugin.'
16
+ Rake::RDocTask.new(:rdoc) do |rdoc|
17
+ rdoc.rdoc_dir = 'rdoc'
18
+ rdoc.title = 'Auto Complete'
19
+ rdoc.options << '--line-numbers' << '--inline-source'
20
+ rdoc.rdoc_files.include('README')
21
+ rdoc.rdoc_files.include('lib/**/*.rb')
22
+ end
@@ -0,0 +1,2 @@
1
+ ActionController::Base.send :include, AutoComplete
2
+ ActionController::Base.helper AutoCompleteMacrosHelper
@@ -0,0 +1,47 @@
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
+ find_options = {
36
+ :conditions => [ "LOWER(#{method}) LIKE ?", '%' + params[object][method].downcase + '%' ],
37
+ :order => "#{method} ASC",
38
+ :limit => 10 }.merge!(options)
39
+
40
+ @items = object.to_s.camelize.constantize.find(:all, find_options)
41
+
42
+ render :inline => "<%= auto_complete_result @items, '#{method}' %>"
43
+ end
44
+ end
45
+ end
46
+
47
+ end
@@ -0,0 +1,143 @@
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>:select</tt>:: Pick the class of the element from which the value for
54
+ # insertion should be extracted. If this is not specified,
55
+ # the entire element is used.
56
+ # <tt>:method</tt>:: Specifies the HTTP verb to use when the autocompletion
57
+ # request is made. Defaults to POST.
58
+ def auto_complete_field(field_id, options = {})
59
+ function = "var #{field_id}_auto_completer = new Ajax.Autocompleter("
60
+ function << "'#{field_id}', "
61
+ function << "'" + (options[:update] || "#{field_id}_auto_complete") + "', "
62
+ function << "'#{url_for(options[:url])}'"
63
+
64
+ js_options = {}
65
+ js_options[:tokens] = array_or_string_for_javascript(options[:tokens]) if options[:tokens]
66
+ js_options[:callback] = "function(element, value) { return #{options[:with]} }" if options[:with]
67
+ js_options[:indicator] = "'#{options[:indicator]}'" if options[:indicator]
68
+ js_options[:select] = "'#{options[:select]}'" if options[:select]
69
+ js_options[:paramName] = "'#{options[:param_name]}'" if options[:param_name]
70
+ js_options[:frequency] = "#{options[:frequency]}" if options[:frequency]
71
+ js_options[:method] = "'#{options[:method].to_s}'" if options[:method]
72
+
73
+ { :after_update_element => :afterUpdateElement,
74
+ :on_show => :onShow, :on_hide => :onHide, :min_chars => :minChars }.each do |k,v|
75
+ js_options[v] = options[k] if options[k]
76
+ end
77
+
78
+ function << (', ' + options_for_javascript(js_options) + ')')
79
+
80
+ javascript_tag(function)
81
+ end
82
+
83
+ # Use this method in your view to generate a return for the AJAX autocomplete requests.
84
+ #
85
+ # Example action:
86
+ #
87
+ # def auto_complete_for_item_title
88
+ # @items = Item.find(:all,
89
+ # :conditions => [ 'LOWER(description) LIKE ?',
90
+ # '%' + request.raw_post.downcase + '%' ])
91
+ # render :inline => "<%= auto_complete_result(@items, 'description') %>"
92
+ # end
93
+ #
94
+ # The auto_complete_result can of course also be called from a view belonging to the
95
+ # auto_complete action if you need to decorate it further.
96
+ def auto_complete_result(entries, field, phrase = nil)
97
+ return unless entries
98
+ items = entries.map { |entry| content_tag("li", phrase ? highlight(entry[field], phrase) : h(entry[field])) }
99
+ content_tag("ul", items.uniq)
100
+ end
101
+
102
+ # Wrapper for text_field with added AJAX autocompletion functionality.
103
+ #
104
+ # In your controller, you'll need to define an action called
105
+ # auto_complete_for to respond the AJAX calls,
106
+ #
107
+ def text_field_with_auto_complete(object, method, tag_options = {}, completion_options = {})
108
+ (completion_options[:skip_style] ? "" : auto_complete_stylesheet) +
109
+ text_field(object, method, tag_options) +
110
+ content_tag("div", "", :id => "#{object}_#{method}_auto_complete", :class => "auto_complete") +
111
+ auto_complete_field("#{object}_#{method}", { :url => { :action => "auto_complete_for_#{object}_#{method}" } }.update(completion_options))
112
+ end
113
+
114
+ private
115
+ def auto_complete_stylesheet
116
+ content_tag('style', <<-EOT, :type => Mime::CSS)
117
+ div.auto_complete {
118
+ width: 350px;
119
+ background: #fff;
120
+ }
121
+ div.auto_complete ul {
122
+ border:1px solid #888;
123
+ margin:0;
124
+ padding:0;
125
+ width:100%;
126
+ list-style-type:none;
127
+ }
128
+ div.auto_complete ul li {
129
+ margin:0;
130
+ padding:3px;
131
+ }
132
+ div.auto_complete ul li.selected {
133
+ background-color: #ffb;
134
+ }
135
+ div.auto_complete ul strong.highlight {
136
+ color: #800;
137
+ margin:0;
138
+ padding:0;
139
+ }
140
+ EOT
141
+ end
142
+
143
+ end
@@ -0,0 +1,67 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '../../../../test/test_helper'))
2
+
3
+ class AutoCompleteTest < Test::Unit::TestCase
4
+ include AutoComplete
5
+ include AutoCompleteMacrosHelper
6
+
7
+ include ActionView::Helpers::UrlHelper
8
+ include ActionView::Helpers::TagHelper
9
+ include ActionView::Helpers::TextHelper
10
+ include ActionView::Helpers::FormHelper
11
+ include ActionView::Helpers::CaptureHelper
12
+
13
+ def setup
14
+ @controller = Class.new do
15
+ def url_for(options)
16
+ url = "http://www.example.com/"
17
+ url << options[:action].to_s if options and options[:action]
18
+ url
19
+ end
20
+ end
21
+ @controller = @controller.new
22
+ end
23
+
24
+
25
+ def test_auto_complete_field
26
+ assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nvar some_input_auto_completer = new Ajax.Autocompleter('some_input', 'some_input_auto_complete', 'http://www.example.com/autocomplete', {})\n//]]>\n</script>),
27
+ auto_complete_field("some_input", :url => { :action => "autocomplete" });
28
+ assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nvar some_input_auto_completer = new Ajax.Autocompleter('some_input', 'some_input_auto_complete', 'http://www.example.com/autocomplete', {tokens:','})\n//]]>\n</script>),
29
+ auto_complete_field("some_input", :url => { :action => "autocomplete" }, :tokens => ',');
30
+ assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nvar some_input_auto_completer = new Ajax.Autocompleter('some_input', 'some_input_auto_complete', 'http://www.example.com/autocomplete', {tokens:[',']})\n//]]>\n</script>),
31
+ auto_complete_field("some_input", :url => { :action => "autocomplete" }, :tokens => [',']);
32
+ assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nvar some_input_auto_completer = new Ajax.Autocompleter('some_input', 'some_input_auto_complete', 'http://www.example.com/autocomplete', {minChars:3})\n//]]>\n</script>),
33
+ auto_complete_field("some_input", :url => { :action => "autocomplete" }, :min_chars => 3);
34
+ assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nvar some_input_auto_completer = new Ajax.Autocompleter('some_input', 'some_input_auto_complete', 'http://www.example.com/autocomplete', {onHide:function(element, update){alert('me');}})\n//]]>\n</script>),
35
+ auto_complete_field("some_input", :url => { :action => "autocomplete" }, :on_hide => "function(element, update){alert('me');}");
36
+ assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nvar some_input_auto_completer = new Ajax.Autocompleter('some_input', 'some_input_auto_complete', 'http://www.example.com/autocomplete', {frequency:2})\n//]]>\n</script>),
37
+ auto_complete_field("some_input", :url => { :action => "autocomplete" }, :frequency => 2);
38
+ assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nvar some_input_auto_completer = new Ajax.Autocompleter('some_input', 'some_input_auto_complete', 'http://www.example.com/autocomplete', {afterUpdateElement:function(element,value){alert('You have chosen: '+value)}})\n//]]>\n</script>),
39
+ auto_complete_field("some_input", :url => { :action => "autocomplete" },
40
+ :after_update_element => "function(element,value){alert('You have chosen: '+value)}");
41
+ assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nvar some_input_auto_completer = new Ajax.Autocompleter('some_input', 'some_input_auto_complete', 'http://www.example.com/autocomplete', {paramName:'huidriwusch'})\n//]]>\n</script>),
42
+ auto_complete_field("some_input", :url => { :action => "autocomplete" }, :param_name => 'huidriwusch');
43
+ assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nvar some_input_auto_completer = new Ajax.Autocompleter('some_input', 'some_input_auto_complete', 'http://www.example.com/autocomplete', {method:'get'})\n//]]>\n</script>),
44
+ auto_complete_field("some_input", :url => { :action => "autocomplete" }, :method => :get);
45
+ end
46
+
47
+ def test_auto_complete_result
48
+ result = [ { :title => 'test1' }, { :title => 'test2' } ]
49
+ assert_equal %(<ul><li>test1</li><li>test2</li></ul>),
50
+ auto_complete_result(result, :title)
51
+ assert_equal %(<ul><li>t<strong class=\"highlight\">est</strong>1</li><li>t<strong class=\"highlight\">est</strong>2</li></ul>),
52
+ auto_complete_result(result, :title, "est")
53
+
54
+ resultuniq = [ { :title => 'test1' }, { :title => 'test1' } ]
55
+ assert_equal %(<ul><li>t<strong class=\"highlight\">est</strong>1</li></ul>),
56
+ auto_complete_result(resultuniq, :title, "est")
57
+ end
58
+
59
+ def test_text_field_with_auto_complete
60
+ assert_match %(<style type="text/css">),
61
+ text_field_with_auto_complete(:message, :recipient)
62
+
63
+ assert_dom_equal %(<input id=\"message_recipient\" name=\"message[recipient]\" size=\"30\" type=\"text\" /><div class=\"auto_complete\" id=\"message_recipient_auto_complete\"></div><script type=\"text/javascript\">\n//<![CDATA[\nvar message_recipient_auto_completer = new Ajax.Autocompleter('message_recipient', 'message_recipient_auto_complete', 'http://www.example.com/auto_complete_for_message_recipient', {})\n//]]>\n</script>),
64
+ text_field_with_auto_complete(:message, :recipient, {}, :skip_style => true)
65
+ end
66
+
67
+ end