actionpack 1.12.5 → 1.13.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

Files changed (179) hide show
  1. data/CHANGELOG +517 -15
  2. data/MIT-LICENSE +1 -1
  3. data/README +18 -20
  4. data/Rakefile +7 -4
  5. data/examples/address_book_controller.rb +3 -3
  6. data/examples/blog_controller.cgi +3 -3
  7. data/examples/debate_controller.cgi +5 -5
  8. data/lib/action_controller.rb +2 -2
  9. data/lib/action_controller/assertions.rb +73 -311
  10. data/lib/action_controller/{deprecated_assertions.rb → assertions/deprecated_assertions.rb} +32 -8
  11. data/lib/action_controller/assertions/dom_assertions.rb +25 -0
  12. data/lib/action_controller/assertions/model_assertions.rb +12 -0
  13. data/lib/action_controller/assertions/response_assertions.rb +140 -0
  14. data/lib/action_controller/assertions/routing_assertions.rb +82 -0
  15. data/lib/action_controller/assertions/selector_assertions.rb +571 -0
  16. data/lib/action_controller/assertions/tag_assertions.rb +117 -0
  17. data/lib/action_controller/base.rb +334 -163
  18. data/lib/action_controller/benchmarking.rb +3 -6
  19. data/lib/action_controller/caching.rb +83 -22
  20. data/lib/action_controller/cgi_ext/cgi_ext.rb +0 -7
  21. data/lib/action_controller/cgi_ext/cgi_methods.rb +167 -173
  22. data/lib/action_controller/cgi_ext/raw_post_data_fix.rb +43 -22
  23. data/lib/action_controller/cgi_process.rb +50 -27
  24. data/lib/action_controller/components.rb +21 -25
  25. data/lib/action_controller/cookies.rb +10 -9
  26. data/lib/action_controller/{dependencies.rb → deprecated_dependencies.rb} +9 -27
  27. data/lib/action_controller/filters.rb +448 -225
  28. data/lib/action_controller/flash.rb +24 -20
  29. data/lib/action_controller/helpers.rb +2 -5
  30. data/lib/action_controller/integration.rb +40 -16
  31. data/lib/action_controller/layout.rb +11 -8
  32. data/lib/action_controller/macros/auto_complete.rb +3 -2
  33. data/lib/action_controller/macros/in_place_editing.rb +3 -2
  34. data/lib/action_controller/mime_responds.rb +41 -29
  35. data/lib/action_controller/mime_type.rb +68 -10
  36. data/lib/action_controller/pagination.rb +4 -3
  37. data/lib/action_controller/request.rb +22 -14
  38. data/lib/action_controller/rescue.rb +25 -22
  39. data/lib/action_controller/resources.rb +302 -0
  40. data/lib/action_controller/response.rb +20 -2
  41. data/lib/action_controller/response.rb.rej +17 -0
  42. data/lib/action_controller/routing.rb +1165 -567
  43. data/lib/action_controller/scaffolding.rb +30 -31
  44. data/lib/action_controller/session/active_record_store.rb +2 -0
  45. data/lib/action_controller/session/drb_store.rb +4 -0
  46. data/lib/action_controller/session/mem_cache_store.rb +4 -0
  47. data/lib/action_controller/session_management.rb +6 -9
  48. data/lib/action_controller/status_codes.rb +89 -0
  49. data/lib/action_controller/streaming.rb +6 -15
  50. data/lib/action_controller/templates/rescues/_request_and_response.rhtml +5 -5
  51. data/lib/action_controller/templates/rescues/diagnostics.rhtml +2 -2
  52. data/lib/action_controller/templates/rescues/routing_error.rhtml +4 -4
  53. data/lib/action_controller/templates/rescues/template_error.rhtml +1 -1
  54. data/lib/action_controller/templates/scaffolds/list.rhtml +1 -1
  55. data/lib/action_controller/test_process.rb +52 -30
  56. data/lib/action_controller/url_rewriter.rb +63 -29
  57. data/lib/action_controller/vendor/html-scanner/html/document.rb +1 -0
  58. data/lib/action_controller/vendor/html-scanner/html/node.rb +3 -4
  59. data/lib/action_controller/vendor/html-scanner/html/selector.rb +822 -0
  60. data/lib/action_controller/verification.rb +22 -11
  61. data/lib/action_pack.rb +1 -1
  62. data/lib/action_pack/version.rb +2 -2
  63. data/lib/action_view.rb +1 -1
  64. data/lib/action_view/base.rb +46 -43
  65. data/lib/action_view/compiled_templates.rb +1 -1
  66. data/lib/action_view/helpers/active_record_helper.rb +54 -17
  67. data/lib/action_view/helpers/asset_tag_helper.rb +97 -46
  68. data/lib/action_view/helpers/capture_helper.rb +1 -1
  69. data/lib/action_view/helpers/date_helper.rb +258 -136
  70. data/lib/action_view/helpers/debug_helper.rb +1 -1
  71. data/lib/action_view/helpers/deprecated_helper.rb +34 -0
  72. data/lib/action_view/helpers/form_helper.rb +75 -35
  73. data/lib/action_view/helpers/form_options_helper.rb +7 -5
  74. data/lib/action_view/helpers/form_tag_helper.rb +44 -6
  75. data/lib/action_view/helpers/java_script_macros_helper.rb +59 -46
  76. data/lib/action_view/helpers/javascript_helper.rb +71 -10
  77. data/lib/action_view/helpers/javascripts/controls.js +41 -23
  78. data/lib/action_view/helpers/javascripts/dragdrop.js +105 -76
  79. data/lib/action_view/helpers/javascripts/effects.js +293 -163
  80. data/lib/action_view/helpers/javascripts/prototype.js +897 -389
  81. data/lib/action_view/helpers/javascripts/prototype.js.rej +561 -0
  82. data/lib/action_view/helpers/number_helper.rb +111 -65
  83. data/lib/action_view/helpers/prototype_helper.rb +84 -109
  84. data/lib/action_view/helpers/scriptaculous_helper.rb +5 -0
  85. data/lib/action_view/helpers/tag_helper.rb +69 -16
  86. data/lib/action_view/helpers/text_helper.rb +149 -112
  87. data/lib/action_view/helpers/url_helper.rb +200 -107
  88. data/lib/action_view/template_error.rb +66 -42
  89. data/test/abstract_unit.rb +4 -2
  90. data/test/active_record_unit.rb +84 -56
  91. data/test/activerecord/active_record_assertions_test.rb +26 -18
  92. data/test/activerecord/active_record_store_test.rb +4 -36
  93. data/test/activerecord/pagination_test.rb +1 -6
  94. data/test/controller/action_pack_assertions_test.rb +230 -113
  95. data/test/controller/addresses_render_test.rb +2 -6
  96. data/test/controller/assert_select_test.rb +576 -0
  97. data/test/controller/base_test.rb +73 -3
  98. data/test/controller/caching_test.rb +228 -0
  99. data/test/controller/capture_test.rb +12 -10
  100. data/test/controller/cgi_test.rb +89 -12
  101. data/test/controller/components_test.rb +24 -2
  102. data/test/controller/content_type_test.rb +139 -0
  103. data/test/controller/controller_fixtures/app/controllers/admin/user_controller.rb +0 -0
  104. data/test/controller/controller_fixtures/app/controllers/user_controller.rb +0 -0
  105. data/test/controller/controller_fixtures/vendor/plugins/bad_plugin/lib/plugin_controller.rb +0 -0
  106. data/test/controller/cookie_test.rb +33 -25
  107. data/test/controller/deprecated_instance_variables_test.rb +48 -0
  108. data/test/controller/deprecation/deprecated_base_methods_test.rb +60 -0
  109. data/test/controller/fake_controllers.rb +0 -1
  110. data/test/controller/filters_test.rb +301 -16
  111. data/test/controller/flash_test.rb +19 -2
  112. data/test/controller/helper_test.rb +2 -2
  113. data/test/controller/integration_test.rb +154 -0
  114. data/test/controller/layout_test.rb +115 -1
  115. data/test/controller/mime_responds_test.rb +94 -0
  116. data/test/controller/mime_type_test.rb +9 -0
  117. data/test/controller/new_render_test.rb +161 -11
  118. data/test/controller/raw_post_test.rb +52 -15
  119. data/test/controller/redirect_test.rb +27 -14
  120. data/test/controller/render_test.rb +76 -29
  121. data/test/controller/request_test.rb +55 -4
  122. data/test/controller/resources_test.rb +274 -0
  123. data/test/controller/routing_test.rb +1533 -824
  124. data/test/controller/selector_test.rb +628 -0
  125. data/test/controller/send_file_test.rb +9 -1
  126. data/test/controller/session_management_test.rb +51 -0
  127. data/test/controller/test_test.rb +113 -29
  128. data/test/controller/url_rewriter_test.rb +86 -17
  129. data/test/controller/verification_test.rb +19 -17
  130. data/test/controller/webservice_test.rb +0 -7
  131. data/test/fixtures/content_type/render_default_content_types_for_respond_to.rhtml +1 -0
  132. data/test/fixtures/content_type/render_default_for_rhtml.rhtml +1 -0
  133. data/test/fixtures/content_type/render_default_for_rjs.rjs +1 -0
  134. data/test/fixtures/content_type/render_default_for_rxml.rxml +1 -0
  135. data/test/fixtures/deprecated_instance_variables/_cookies_ivar.rhtml +1 -0
  136. data/test/fixtures/deprecated_instance_variables/_cookies_method.rhtml +1 -0
  137. data/test/fixtures/deprecated_instance_variables/_flash_ivar.rhtml +1 -0
  138. data/test/fixtures/deprecated_instance_variables/_flash_method.rhtml +1 -0
  139. data/test/fixtures/deprecated_instance_variables/_headers_ivar.rhtml +1 -0
  140. data/test/fixtures/deprecated_instance_variables/_headers_method.rhtml +1 -0
  141. data/test/fixtures/deprecated_instance_variables/_params_ivar.rhtml +1 -0
  142. data/test/fixtures/deprecated_instance_variables/_params_method.rhtml +1 -0
  143. data/test/fixtures/deprecated_instance_variables/_request_ivar.rhtml +1 -0
  144. data/test/fixtures/deprecated_instance_variables/_request_method.rhtml +1 -0
  145. data/test/fixtures/deprecated_instance_variables/_response_ivar.rhtml +1 -0
  146. data/test/fixtures/deprecated_instance_variables/_response_method.rhtml +1 -0
  147. data/test/fixtures/deprecated_instance_variables/_session_ivar.rhtml +1 -0
  148. data/test/fixtures/deprecated_instance_variables/_session_method.rhtml +1 -0
  149. data/test/fixtures/multipart/binary_file +0 -0
  150. data/test/fixtures/public/javascripts/application.js +1 -0
  151. data/test/fixtures/test/_hello.rxml +1 -0
  152. data/test/fixtures/test/hello_world_container.rxml +3 -0
  153. data/test/fixtures/topic.rb +2 -2
  154. data/test/template/active_record_helper_test.rb +83 -12
  155. data/test/template/asset_tag_helper_test.rb +75 -95
  156. data/test/template/compiled_templates_test.rb +1 -0
  157. data/test/template/date_helper_test.rb +873 -181
  158. data/test/template/deprecated_helper_test.rb +36 -0
  159. data/test/template/deprecated_instance_variables_test.rb +43 -0
  160. data/test/template/form_helper_test.rb +77 -1
  161. data/test/template/form_options_helper_test.rb +4 -0
  162. data/test/template/form_tag_helper_test.rb +66 -2
  163. data/test/template/java_script_macros_helper_test.rb +4 -1
  164. data/test/template/javascript_helper_test.rb +29 -0
  165. data/test/template/number_helper_test.rb +63 -27
  166. data/test/template/prototype_helper_test.rb +77 -34
  167. data/test/template/tag_helper_test.rb +34 -6
  168. data/test/template/text_helper_test.rb +69 -34
  169. data/test/template/url_helper_test.rb +168 -16
  170. data/test/testing_sandbox.rb +7 -22
  171. metadata +66 -20
  172. data/filler.txt +0 -50
  173. data/lib/action_controller/code_generation.rb +0 -235
  174. data/lib/action_controller/vendor/xml_simple.rb +0 -1019
  175. data/test/controller/caching_filestore.rb +0 -74
  176. data/test/fixtures/application_root/app/controllers/a_class_that_contains_a_controller/poorly_placed_controller.rb +0 -7
  177. data/test/fixtures/application_root/app/controllers/module_that_holds_controllers/nested_controller.rb +0 -3
  178. data/test/fixtures/application_root/app/models/a_class_that_contains_a_controller.rb +0 -7
  179. data/test/fixtures/dont_load.rb +0 -3
@@ -1,4 +1,5 @@
1
1
  require File.dirname(__FILE__) + '/tag_helper'
2
+ require File.dirname(__FILE__) + '/prototype_helper'
2
3
 
3
4
  module ActionView
4
5
  module Helpers
@@ -40,15 +41,50 @@ module ActionView
40
41
  unless const_defined? :JAVASCRIPT_PATH
41
42
  JAVASCRIPT_PATH = File.join(File.dirname(__FILE__), 'javascripts')
42
43
  end
44
+
45
+ include PrototypeHelper
43
46
 
44
- # Returns a link that'll trigger a JavaScript +function+ using the
47
+ # Returns a link that will trigger a JavaScript +function+ using the
45
48
  # onclick handler and return false after the fact.
46
49
  #
50
+ # The +function+ argument can be omitted in favor of an +update_page+
51
+ # block, which evaluates to a string when the template is rendered
52
+ # (instead of making an Ajax request first).
53
+ #
47
54
  # Examples:
48
55
  # link_to_function "Greeting", "alert('Hello world!')"
49
- # link_to_function(image_tag("delete"), "if confirm('Really?'){ do_delete(); }")
50
- def link_to_function(name, function, html_options = {})
56
+ # Produces:
57
+ # <a onclick="alert('Hello world!'); return false;" href="#">Greeting</a>
58
+ #
59
+ # link_to_function(image_tag("delete"), "if (confirm('Really?')) do_delete()")
60
+ # Produces:
61
+ # <a onclick="if (confirm('Really?')) do_delete(); return false;" href="#">
62
+ # <img src="/images/delete.png?" alt="Delete"/>
63
+ # </a>
64
+ #
65
+ # link_to_function("Show me more", nil, :id => "more_link") do |page|
66
+ # page[:details].visual_effect :toggle_blind
67
+ # page[:more_link].replace_html "Show me less"
68
+ # end
69
+ # Produces:
70
+ # <a href="#" id="more_link" onclick="try {
71
+ # $(&quot;details&quot;).visualEffect(&quot;toggle_blind&quot;);
72
+ # $(&quot;more_link&quot;).update(&quot;Show me less&quot;);
73
+ # }
74
+ # catch (e) {
75
+ # alert('RJS error:\n\n' + e.toString());
76
+ # alert('$(\&quot;details\&quot;).visualEffect(\&quot;toggle_blind\&quot;);
77
+ # \n$(\&quot;more_link\&quot;).update(\&quot;Show me less\&quot;);');
78
+ # throw e
79
+ # };
80
+ # return false;">Show me more</a>
81
+ #
82
+ def link_to_function(name, *args, &block)
83
+ html_options = args.last.is_a?(Hash) ? args.pop : {}
84
+ function = args[0] || ''
85
+
51
86
  html_options.symbolize_keys!
87
+ function = update_page(&block) if block_given?
52
88
  content_tag(
53
89
  "a", name,
54
90
  html_options.merge({
@@ -58,14 +94,28 @@ module ActionView
58
94
  )
59
95
  end
60
96
 
61
- # Returns a link that'll trigger a JavaScript +function+ using the
97
+ # Returns a button that'll trigger a JavaScript +function+ using the
62
98
  # onclick handler.
63
99
  #
100
+ # The +function+ argument can be omitted in favor of an +update_page+
101
+ # block, which evaluates to a string when the template is rendered
102
+ # (instead of making an Ajax request first).
103
+ #
64
104
  # Examples:
65
105
  # button_to_function "Greeting", "alert('Hello world!')"
66
- # button_to_function "Delete", "if confirm('Really?'){ do_delete(); }")
67
- def button_to_function(name, function, html_options = {})
106
+ # button_to_function "Delete", "if (confirm('Really?')) do_delete()"
107
+ # button_to_function "Details" do |page|
108
+ # page[:details].visual_effect :toggle_slide
109
+ # end
110
+ # button_to_function "Details", :class => "details_button" do |page|
111
+ # page[:details].visual_effect :toggle_slide
112
+ # end
113
+ def button_to_function(name, *args, &block)
114
+ html_options = args.last.is_a?(Hash) ? args.pop : {}
115
+ function = args[0] || ''
116
+
68
117
  html_options.symbolize_keys!
118
+ function = update_page(&block) if block_given?
69
119
  tag(:input, html_options.merge({
70
120
  :type => "button", :value => name,
71
121
  :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};"
@@ -99,13 +149,24 @@ module ActionView
99
149
 
100
150
  # Escape carrier returns and single and double quotes for JavaScript segments.
101
151
  def escape_javascript(javascript)
102
- (javascript || '').gsub(/\r\n|\n|\r/, "\\n").gsub(/["']/) { |m| "\\#{m}" }
152
+ (javascript || '').gsub('\\','\0\0').gsub(/\r\n|\n|\r/, "\\n").gsub(/["']/) { |m| "\\#{m}" }
103
153
  end
104
154
 
105
155
  # Returns a JavaScript tag with the +content+ inside. Example:
106
- # javascript_tag "alert('All is good')" # => <script type="text/javascript">alert('All is good')</script>
107
- def javascript_tag(content)
108
- content_tag("script", javascript_cdata_section(content), :type => "text/javascript")
156
+ # javascript_tag "alert('All is good')"
157
+ #
158
+ # Returns:
159
+ #
160
+ # <script type="text/javascript">
161
+ # //<![CDATA[
162
+ # alert('All is good')
163
+ # //]]>
164
+ # </script>
165
+ #
166
+ # +html_options+ may be a hash of attributes for the <script> tag. Example:
167
+ # javascript_tag "alert('All is good')", :defer => 'true' # => <script defer="true" type="text/javascript">alert('All is good')</script>
168
+ def javascript_tag(content, html_options = {})
169
+ content_tag("script", javascript_cdata_section(content), html_options.merge(:type => "text/javascript"))
109
170
  end
110
171
 
111
172
  def javascript_cdata_section(content) #:nodoc:
@@ -1,12 +1,13 @@
1
- // Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
2
- // (c) 2005 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
3
- // (c) 2005 Jon Tirsen (http://www.tirsen.com)
1
+ // Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
2
+ // (c) 2005, 2006 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
3
+ // (c) 2005, 2006 Jon Tirsen (http://www.tirsen.com)
4
4
  // Contributors:
5
5
  // Richard Livsey
6
6
  // Rahul Bhargava
7
7
  // Rob Wills
8
8
  //
9
- // See scriptaculous.js for full license.
9
+ // script.aculo.us is freely distributable under the terms of an MIT-style license.
10
+ // For details, see the script.aculo.us web site: http://script.aculo.us/
10
11
 
11
12
  // Autocompleter.Base handles all the autocompletion functionality
12
13
  // that's independent of the data source for autocompletion. This
@@ -33,6 +34,9 @@
33
34
  // useful when one of the tokens is \n (a newline), as it
34
35
  // allows smart autocompletion after linebreaks.
35
36
 
37
+ if(typeof Effect == 'undefined')
38
+ throw("controls.js requires including script.aculo.us' effects.js library");
39
+
36
40
  var Autocompleter = {}
37
41
  Autocompleter.Base = function() {};
38
42
  Autocompleter.Base.prototype = {
@@ -45,7 +49,7 @@ Autocompleter.Base.prototype = {
45
49
  this.index = 0;
46
50
  this.entryCount = 0;
47
51
 
48
- if (this.setOptions)
52
+ if(this.setOptions)
49
53
  this.setOptions(options);
50
54
  else
51
55
  this.options = options || {};
@@ -55,17 +59,20 @@ Autocompleter.Base.prototype = {
55
59
  this.options.frequency = this.options.frequency || 0.4;
56
60
  this.options.minChars = this.options.minChars || 1;
57
61
  this.options.onShow = this.options.onShow ||
58
- function(element, update){
59
- if(!update.style.position || update.style.position=='absolute') {
60
- update.style.position = 'absolute';
61
- Position.clone(element, update, {setHeight: false, offsetTop: element.offsetHeight});
62
- }
63
- Effect.Appear(update,{duration:0.15});
64
- };
62
+ function(element, update){
63
+ if(!update.style.position || update.style.position=='absolute') {
64
+ update.style.position = 'absolute';
65
+ Position.clone(element, update, {
66
+ setHeight: false,
67
+ offsetTop: element.offsetHeight
68
+ });
69
+ }
70
+ Effect.Appear(update,{duration:0.15});
71
+ };
65
72
  this.options.onHide = this.options.onHide ||
66
- function(element, update){ new Effect.Fade(update,{duration:0.15}) };
73
+ function(element, update){ new Effect.Fade(update,{duration:0.15}) };
67
74
 
68
- if (typeof(this.options.tokens) == 'string')
75
+ if(typeof(this.options.tokens) == 'string')
69
76
  this.options.tokens = new Array(this.options.tokens);
70
77
 
71
78
  this.observer = null;
@@ -94,7 +101,7 @@ Autocompleter.Base.prototype = {
94
101
  },
95
102
 
96
103
  fixIEOverlapping: function() {
97
- Position.clone(this.update, this.iefix);
104
+ Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
98
105
  this.iefix.style.zIndex = 1;
99
106
  this.update.style.zIndex = 2;
100
107
  Element.show(this.iefix);
@@ -202,11 +209,13 @@ Autocompleter.Base.prototype = {
202
209
  markPrevious: function() {
203
210
  if(this.index > 0) this.index--
204
211
  else this.index = this.entryCount-1;
212
+ this.getEntry(this.index).scrollIntoView(true);
205
213
  },
206
214
 
207
215
  markNext: function() {
208
216
  if(this.index < this.entryCount-1) this.index++
209
217
  else this.index = 0;
218
+ this.getEntry(this.index).scrollIntoView(false);
210
219
  },
211
220
 
212
221
  getEntry: function(index) {
@@ -254,11 +263,11 @@ Autocompleter.Base.prototype = {
254
263
  if(!this.changed && this.hasFocus) {
255
264
  this.update.innerHTML = choices;
256
265
  Element.cleanWhitespace(this.update);
257
- Element.cleanWhitespace(this.update.firstChild);
266
+ Element.cleanWhitespace(this.update.down());
258
267
 
259
- if(this.update.firstChild && this.update.firstChild.childNodes) {
268
+ if(this.update.firstChild && this.update.down().childNodes) {
260
269
  this.entryCount =
261
- this.update.firstChild.childNodes.length;
270
+ this.update.down().childNodes.length;
262
271
  for (var i = 0; i < this.entryCount; i++) {
263
272
  var entry = this.getEntry(i);
264
273
  entry.autocompleteIndex = i;
@@ -269,9 +278,14 @@ Autocompleter.Base.prototype = {
269
278
  }
270
279
 
271
280
  this.stopIndicator();
272
-
273
281
  this.index = 0;
274
- this.render();
282
+
283
+ if(this.entryCount==1 && this.options.autoSelect) {
284
+ this.selectEntry();
285
+ this.hide();
286
+ } else {
287
+ this.render();
288
+ }
275
289
  }
276
290
  },
277
291
 
@@ -459,6 +473,7 @@ Ajax.InPlaceEditor.prototype = {
459
473
  this.element = $(element);
460
474
 
461
475
  this.options = Object.extend({
476
+ paramName: "value",
462
477
  okButton: true,
463
478
  okText: "ok",
464
479
  cancelLink: true,
@@ -531,7 +546,7 @@ Ajax.InPlaceEditor.prototype = {
531
546
  Element.hide(this.element);
532
547
  this.createForm();
533
548
  this.element.parentNode.insertBefore(this.form, this.element);
534
- Field.scrollFreeActivate(this.editField);
549
+ if (!this.options.loadTextURL) Field.scrollFreeActivate(this.editField);
535
550
  // stop the event to avoid a page refresh in Safari
536
551
  if (evt) {
537
552
  Event.stop(evt);
@@ -590,7 +605,7 @@ Ajax.InPlaceEditor.prototype = {
590
605
  var textField = document.createElement("input");
591
606
  textField.obj = this;
592
607
  textField.type = "text";
593
- textField.name = "value";
608
+ textField.name = this.options.paramName;
594
609
  textField.value = text;
595
610
  textField.style.backgroundColor = this.options.highlightcolor;
596
611
  textField.className = 'editor_field';
@@ -603,7 +618,7 @@ Ajax.InPlaceEditor.prototype = {
603
618
  this.options.textarea = true;
604
619
  var textArea = document.createElement("textarea");
605
620
  textArea.obj = this;
606
- textArea.name = "value";
621
+ textArea.name = this.options.paramName;
607
622
  textArea.value = this.convertHTMLLineBreaks(text);
608
623
  textArea.rows = this.options.rows;
609
624
  textArea.cols = this.options.cols || 40;
@@ -636,6 +651,7 @@ Ajax.InPlaceEditor.prototype = {
636
651
  Element.removeClassName(this.form, this.options.loadingClassName);
637
652
  this.editField.disabled = false;
638
653
  this.editField.value = transport.responseText.stripTags();
654
+ Field.scrollFreeActivate(this.editField);
639
655
  },
640
656
  onclickCancel: function() {
641
657
  this.onComplete();
@@ -772,6 +788,8 @@ Object.extend(Ajax.InPlaceCollectionEditor.prototype, {
772
788
  collection.each(function(e,i) {
773
789
  optionTag = document.createElement("option");
774
790
  optionTag.value = (e instanceof Array) ? e[0] : e;
791
+ if((typeof this.options.value == 'undefined') &&
792
+ ((e instanceof Array) ? this.element.innerHTML == e[1] : e == optionTag.value)) optionTag.selected = true;
775
793
  if(this.options.value==optionTag.value) optionTag.selected = true;
776
794
  optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e));
777
795
  selectTag.appendChild(optionTag);
@@ -1,9 +1,11 @@
1
- // Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
2
- // (c) 2005 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
1
+ // Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
2
+ // (c) 2005, 2006 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
3
3
  //
4
- // See scriptaculous.js for full license.
4
+ // script.aculo.us is freely distributable under the terms of an MIT-style license.
5
+ // For details, see the script.aculo.us web site: http://script.aculo.us/
5
6
 
6
- /*--------------------------------------------------------------------------*/
7
+ if(typeof Effect == 'undefined')
8
+ throw("dragdrop.js requires including script.aculo.us' effects.js library");
7
9
 
8
10
  var Droppables = {
9
11
  drops: [],
@@ -145,8 +147,16 @@ var Draggables = {
145
147
  },
146
148
 
147
149
  activate: function(draggable) {
148
- window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
149
- this.activeDraggable = draggable;
150
+ if(draggable.options.delay) {
151
+ this._timeout = setTimeout(function() {
152
+ Draggables._timeout = null;
153
+ window.focus();
154
+ Draggables.activeDraggable = draggable;
155
+ }.bind(this), draggable.options.delay);
156
+ } else {
157
+ window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
158
+ this.activeDraggable = draggable;
159
+ }
150
160
  },
151
161
 
152
162
  deactivate: function() {
@@ -160,10 +170,15 @@ var Draggables = {
160
170
  // the same coordinates, prevent needless redrawing (moz bug?)
161
171
  if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
162
172
  this._lastPointer = pointer;
173
+
163
174
  this.activeDraggable.updateDrag(event, pointer);
164
175
  },
165
176
 
166
177
  endDrag: function(event) {
178
+ if(this._timeout) {
179
+ clearTimeout(this._timeout);
180
+ this._timeout = null;
181
+ }
167
182
  if(!this.activeDraggable) return;
168
183
  this._lastPointer = null;
169
184
  this.activeDraggable.endDrag(event);
@@ -190,6 +205,7 @@ var Draggables = {
190
205
  this.observers.each( function(o) {
191
206
  if(o[eventName]) o[eventName](eventName, draggable, event);
192
207
  });
208
+ if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
193
209
  },
194
210
 
195
211
  _cacheObserverCallbacks: function() {
@@ -204,39 +220,59 @@ var Draggables = {
204
220
  /*--------------------------------------------------------------------------*/
205
221
 
206
222
  var Draggable = Class.create();
223
+ Draggable._dragging = {};
224
+
207
225
  Draggable.prototype = {
208
226
  initialize: function(element) {
209
- var options = Object.extend({
227
+ var defaults = {
210
228
  handle: false,
211
- starteffect: function(element) {
212
- new Effect.Opacity(element, {duration:0.2, from:1.0, to:0.7});
213
- },
214
229
  reverteffect: function(element, top_offset, left_offset) {
215
230
  var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
216
- element._revert = new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur});
231
+ new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur,
232
+ queue: {scope:'_draggable', position:'end'}
233
+ });
217
234
  },
218
- endeffect: function(element) {
219
- new Effect.Opacity(element, {duration:0.2, from:0.7, to:1.0});
235
+ endeffect: function(element) {
236
+ var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0;
237
+ new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,
238
+ queue: {scope:'_draggable', position:'end'},
239
+ afterFinish: function(){
240
+ Draggable._dragging[element] = false
241
+ }
242
+ });
220
243
  },
221
244
  zindex: 1000,
222
245
  revert: false,
223
246
  scroll: false,
224
247
  scrollSensitivity: 20,
225
248
  scrollSpeed: 15,
226
- snap: false // false, or xy or [x,y] or function(x,y){ return [x,y] }
227
- }, arguments[1] || {});
249
+ snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] }
250
+ delay: 0
251
+ };
252
+
253
+ if(!arguments[1] || typeof arguments[1].endeffect == 'undefined')
254
+ Object.extend(defaults, {
255
+ starteffect: function(element) {
256
+ element._opacity = Element.getOpacity(element);
257
+ Draggable._dragging[element] = true;
258
+ new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});
259
+ }
260
+ });
261
+
262
+ var options = Object.extend(defaults, arguments[1] || {});
228
263
 
229
264
  this.element = $(element);
230
265
 
231
- if(options.handle && (typeof options.handle == 'string')) {
232
- var h = Element.childrenWithClassName(this.element, options.handle, true);
233
- if(h.length>0) this.handle = h[0];
234
- }
266
+ if(options.handle && (typeof options.handle == 'string'))
267
+ this.handle = this.element.down('.'+options.handle, 0);
268
+
235
269
  if(!this.handle) this.handle = $(options.handle);
236
270
  if(!this.handle) this.handle = this.element;
237
271
 
238
- if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML)
272
+ if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
239
273
  options.scroll = $(options.scroll);
274
+ this._isScrollChild = Element.childOf(this.element, options.scroll);
275
+ }
240
276
 
241
277
  Element.makePositioned(this.element); // fix IE
242
278
 
@@ -262,6 +298,8 @@ Draggable.prototype = {
262
298
  },
263
299
 
264
300
  initDrag: function(event) {
301
+ if(typeof Draggable._dragging[this.element] != 'undefined' &&
302
+ Draggable._dragging[this.element]) return;
265
303
  if(Event.isLeftClick(event)) {
266
304
  // abort on form elements, fixes a Firefox issue
267
305
  var src = Event.element(event);
@@ -272,11 +310,6 @@ Draggable.prototype = {
272
310
  src.tagName=='BUTTON' ||
273
311
  src.tagName=='TEXTAREA')) return;
274
312
 
275
- if(this.element._revert) {
276
- this.element._revert.cancel();
277
- this.element._revert = null;
278
- }
279
-
280
313
  var pointer = [Event.pointerX(event), Event.pointerY(event)];
281
314
  var pos = Position.cumulativeOffset(this.element);
282
315
  this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
@@ -312,6 +345,7 @@ Draggable.prototype = {
312
345
  }
313
346
 
314
347
  Draggables.notify('onStart', this, event);
348
+
315
349
  if(this.options.starteffect) this.options.starteffect(this.element);
316
350
  },
317
351
 
@@ -320,6 +354,7 @@ Draggable.prototype = {
320
354
  Position.prepare();
321
355
  Droppables.show(pointer, this.element);
322
356
  Draggables.notify('onDrag', this, event);
357
+
323
358
  this.draw(pointer);
324
359
  if(this.options.change) this.options.change(this);
325
360
 
@@ -331,8 +366,8 @@ Draggable.prototype = {
331
366
  with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
332
367
  } else {
333
368
  p = Position.page(this.options.scroll);
334
- p[0] += this.options.scroll.scrollLeft;
335
- p[1] += this.options.scroll.scrollTop;
369
+ p[0] += this.options.scroll.scrollLeft + Position.deltaX;
370
+ p[1] += this.options.scroll.scrollTop + Position.deltaY;
336
371
  p.push(p[0]+this.options.scroll.offsetWidth);
337
372
  p.push(p[1]+this.options.scroll.offsetHeight);
338
373
  }
@@ -378,7 +413,7 @@ Draggable.prototype = {
378
413
 
379
414
  if(this.options.endeffect)
380
415
  this.options.endeffect(this.element);
381
-
416
+
382
417
  Draggables.deactivate(this);
383
418
  Droppables.reset();
384
419
  },
@@ -398,10 +433,15 @@ Draggable.prototype = {
398
433
 
399
434
  draw: function(point) {
400
435
  var pos = Position.cumulativeOffset(this.element);
436
+ if(this.options.ghosting) {
437
+ var r = Position.realOffset(this.element);
438
+ pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
439
+ }
440
+
401
441
  var d = this.currentDelta();
402
442
  pos[0] -= d[0]; pos[1] -= d[1];
403
443
 
404
- if(this.options.scroll && (this.options.scroll != window)) {
444
+ if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
405
445
  pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
406
446
  pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
407
447
  }
@@ -412,7 +452,7 @@ Draggable.prototype = {
412
452
 
413
453
  if(this.options.snap) {
414
454
  if(typeof this.options.snap == 'function') {
415
- p = this.options.snap(p[0],p[1]);
455
+ p = this.options.snap(p[0],p[1],this);
416
456
  } else {
417
457
  if(this.options.snap instanceof Array) {
418
458
  p = p.map( function(v, i) {
@@ -428,6 +468,7 @@ Draggable.prototype = {
428
468
  style.left = p[0] + "px";
429
469
  if((!this.options.constraint) || (this.options.constraint=='vertical'))
430
470
  style.top = p[1] + "px";
471
+
431
472
  if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
432
473
  },
433
474
 
@@ -440,6 +481,7 @@ Draggable.prototype = {
440
481
  },
441
482
 
442
483
  startScrolling: function(speed) {
484
+ if(!(speed[0] || speed[1])) return;
443
485
  this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
444
486
  this.lastScrolled = new Date();
445
487
  this.scrollInterval = setInterval(this.scroll.bind(this), 10);
@@ -464,14 +506,16 @@ Draggable.prototype = {
464
506
  Position.prepare();
465
507
  Droppables.show(Draggables._lastPointer, this.element);
466
508
  Draggables.notify('onDrag', this);
467
- Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
468
- Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
469
- Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
470
- if (Draggables._lastScrollPointer[0] < 0)
471
- Draggables._lastScrollPointer[0] = 0;
472
- if (Draggables._lastScrollPointer[1] < 0)
473
- Draggables._lastScrollPointer[1] = 0;
474
- this.draw(Draggables._lastScrollPointer);
509
+ if (this._isScrollChild) {
510
+ Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
511
+ Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
512
+ Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
513
+ if (Draggables._lastScrollPointer[0] < 0)
514
+ Draggables._lastScrollPointer[0] = 0;
515
+ if (Draggables._lastScrollPointer[1] < 0)
516
+ Draggables._lastScrollPointer[1] = 0;
517
+ this.draw(Draggables._lastScrollPointer);
518
+ }
475
519
 
476
520
  if(this.options.change) this.options.change(this);
477
521
  },
@@ -523,6 +567,8 @@ SortableObserver.prototype = {
523
567
  }
524
568
 
525
569
  var Sortable = {
570
+ SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
571
+
526
572
  sortables: {},
527
573
 
528
574
  _findRootElement: function(element) {
@@ -563,12 +609,13 @@ var Sortable = {
563
609
  containment: element, // also takes array of elements (or id's); or false
564
610
  handle: false, // or a CSS class
565
611
  only: false,
612
+ delay: 0,
566
613
  hoverclass: null,
567
614
  ghosting: false,
568
615
  scroll: false,
569
616
  scrollSensitivity: 20,
570
617
  scrollSpeed: 15,
571
- format: /^[^_]*_(.*)$/,
618
+ format: this.SERIALIZE_RULE,
572
619
  onChange: Prototype.emptyFunction,
573
620
  onUpdate: Prototype.emptyFunction
574
621
  }, arguments[1] || {});
@@ -582,6 +629,7 @@ var Sortable = {
582
629
  scroll: options.scroll,
583
630
  scrollSpeed: options.scrollSpeed,
584
631
  scrollSensitivity: options.scrollSensitivity,
632
+ delay: options.delay,
585
633
  ghosting: options.ghosting,
586
634
  constraint: options.constraint,
587
635
  handle: options.handle };
@@ -610,7 +658,6 @@ var Sortable = {
610
658
  tree: options.tree,
611
659
  hoverclass: options.hoverclass,
612
660
  onHover: Sortable.onHover
613
- //greedy: !options.dropOnEmpty
614
661
  }
615
662
 
616
663
  var options_for_tree = {
@@ -635,7 +682,7 @@ var Sortable = {
635
682
  (this.findElements(element, options) || []).each( function(e) {
636
683
  // handles are per-draggable
637
684
  var handle = options.handle ?
638
- Element.childrenWithClassName(e, options.handle)[0] : e;
685
+ $(e).down('.'+options.handle,0) : e;
639
686
  options.draggables.push(
640
687
  new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
641
688
  Droppables.add(e, options_for_droppable);
@@ -706,7 +753,7 @@ var Sortable = {
706
753
  if(!Element.isParent(dropon, element)) {
707
754
  var index;
708
755
 
709
- var children = Sortable.findElements(dropon, {tag: droponOptions.tag});
756
+ var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only});
710
757
  var child = null;
711
758
 
712
759
  if(children) {
@@ -733,7 +780,7 @@ var Sortable = {
733
780
  },
734
781
 
735
782
  unmark: function() {
736
- if(Sortable._marker) Element.hide(Sortable._marker);
783
+ if(Sortable._marker) Sortable._marker.hide();
737
784
  },
738
785
 
739
786
  mark: function(dropon, position) {
@@ -742,23 +789,21 @@ var Sortable = {
742
789
  if(sortable && !sortable.ghosting) return;
743
790
 
744
791
  if(!Sortable._marker) {
745
- Sortable._marker = $('dropmarker') || document.createElement('DIV');
746
- Element.hide(Sortable._marker);
747
- Element.addClassName(Sortable._marker, 'dropmarker');
748
- Sortable._marker.style.position = 'absolute';
792
+ Sortable._marker =
793
+ ($('dropmarker') || Element.extend(document.createElement('DIV'))).
794
+ hide().addClassName('dropmarker').setStyle({position:'absolute'});
749
795
  document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
750
796
  }
751
797
  var offsets = Position.cumulativeOffset(dropon);
752
- Sortable._marker.style.left = offsets[0] + 'px';
753
- Sortable._marker.style.top = offsets[1] + 'px';
798
+ Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'});
754
799
 
755
800
  if(position=='after')
756
801
  if(sortable.overlap == 'horizontal')
757
- Sortable._marker.style.left = (offsets[0]+dropon.clientWidth) + 'px';
802
+ Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'});
758
803
  else
759
- Sortable._marker.style.top = (offsets[1]+dropon.clientHeight) + 'px';
804
+ Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'});
760
805
 
761
- Element.show(Sortable._marker);
806
+ Sortable._marker.show();
762
807
  },
763
808
 
764
809
  _tree: function(element, options, parent) {
@@ -773,9 +818,9 @@ var Sortable = {
773
818
  id: encodeURIComponent(match ? match[1] : null),
774
819
  element: element,
775
820
  parent: parent,
776
- children: new Array,
821
+ children: [],
777
822
  position: parent.children.length,
778
- container: Sortable._findChildrenElement(children[i], options.treeTag.toUpperCase())
823
+ container: $(children[i]).down(options.treeTag)
779
824
  }
780
825
 
781
826
  /* Get the element containing the children and recurse over it */
@@ -788,17 +833,6 @@ var Sortable = {
788
833
  return parent;
789
834
  },
790
835
 
791
- /* Finds the first element of the given tag type within a parent element.
792
- Used for finding the first LI[ST] within a L[IST]I[TEM].*/
793
- _findChildrenElement: function (element, containerTag) {
794
- if (element && element.hasChildNodes)
795
- for (var i = 0; i < element.childNodes.length; ++i)
796
- if (element.childNodes[i].tagName == containerTag)
797
- return element.childNodes[i];
798
-
799
- return null;
800
- },
801
-
802
836
  tree: function(element) {
803
837
  element = $(element);
804
838
  var sortableOptions = this.options(element);
@@ -813,12 +847,12 @@ var Sortable = {
813
847
  var root = {
814
848
  id: null,
815
849
  parent: null,
816
- children: new Array,
850
+ children: [],
817
851
  container: element,
818
852
  position: 0
819
853
  }
820
854
 
821
- return Sortable._tree (element, options, root);
855
+ return Sortable._tree(element, options, root);
822
856
  },
823
857
 
824
858
  /* Construct a [i] index for a particular node */
@@ -867,7 +901,7 @@ var Sortable = {
867
901
 
868
902
  if (options.tree) {
869
903
  return Sortable.tree(element, arguments[1]).children.map( function (item) {
870
- return [name + Sortable._constructIndex(item) + "=" +
904
+ return [name + Sortable._constructIndex(item) + "[id]=" +
871
905
  encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
872
906
  }).flatten().join('&');
873
907
  } else {
@@ -878,12 +912,10 @@ var Sortable = {
878
912
  }
879
913
  }
880
914
 
881
- /* Returns true if child is contained within element */
915
+ // Returns true if child is contained within element
882
916
  Element.isParent = function(child, element) {
883
917
  if (!child.parentNode || child == element) return false;
884
-
885
918
  if (child.parentNode == element) return true;
886
-
887
919
  return Element.isParent(child.parentNode, element);
888
920
  }
889
921
 
@@ -906,8 +938,5 @@ Element.findChildren = function(element, only, recursive, tagName) {
906
938
  }
907
939
 
908
940
  Element.offsetSize = function (element, type) {
909
- if (type == 'vertical' || type == 'height')
910
- return element.offsetHeight;
911
- else
912
- return element.offsetWidth;
913
- }
941
+ return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')];
942
+ }