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.
- data/CHANGELOG +517 -15
- data/MIT-LICENSE +1 -1
- data/README +18 -20
- data/Rakefile +7 -4
- data/examples/address_book_controller.rb +3 -3
- data/examples/blog_controller.cgi +3 -3
- data/examples/debate_controller.cgi +5 -5
- data/lib/action_controller.rb +2 -2
- data/lib/action_controller/assertions.rb +73 -311
- data/lib/action_controller/{deprecated_assertions.rb → assertions/deprecated_assertions.rb} +32 -8
- data/lib/action_controller/assertions/dom_assertions.rb +25 -0
- data/lib/action_controller/assertions/model_assertions.rb +12 -0
- data/lib/action_controller/assertions/response_assertions.rb +140 -0
- data/lib/action_controller/assertions/routing_assertions.rb +82 -0
- data/lib/action_controller/assertions/selector_assertions.rb +571 -0
- data/lib/action_controller/assertions/tag_assertions.rb +117 -0
- data/lib/action_controller/base.rb +334 -163
- data/lib/action_controller/benchmarking.rb +3 -6
- data/lib/action_controller/caching.rb +83 -22
- data/lib/action_controller/cgi_ext/cgi_ext.rb +0 -7
- data/lib/action_controller/cgi_ext/cgi_methods.rb +167 -173
- data/lib/action_controller/cgi_ext/raw_post_data_fix.rb +43 -22
- data/lib/action_controller/cgi_process.rb +50 -27
- data/lib/action_controller/components.rb +21 -25
- data/lib/action_controller/cookies.rb +10 -9
- data/lib/action_controller/{dependencies.rb → deprecated_dependencies.rb} +9 -27
- data/lib/action_controller/filters.rb +448 -225
- data/lib/action_controller/flash.rb +24 -20
- data/lib/action_controller/helpers.rb +2 -5
- data/lib/action_controller/integration.rb +40 -16
- data/lib/action_controller/layout.rb +11 -8
- data/lib/action_controller/macros/auto_complete.rb +3 -2
- data/lib/action_controller/macros/in_place_editing.rb +3 -2
- data/lib/action_controller/mime_responds.rb +41 -29
- data/lib/action_controller/mime_type.rb +68 -10
- data/lib/action_controller/pagination.rb +4 -3
- data/lib/action_controller/request.rb +22 -14
- data/lib/action_controller/rescue.rb +25 -22
- data/lib/action_controller/resources.rb +302 -0
- data/lib/action_controller/response.rb +20 -2
- data/lib/action_controller/response.rb.rej +17 -0
- data/lib/action_controller/routing.rb +1165 -567
- data/lib/action_controller/scaffolding.rb +30 -31
- data/lib/action_controller/session/active_record_store.rb +2 -0
- data/lib/action_controller/session/drb_store.rb +4 -0
- data/lib/action_controller/session/mem_cache_store.rb +4 -0
- data/lib/action_controller/session_management.rb +6 -9
- data/lib/action_controller/status_codes.rb +89 -0
- data/lib/action_controller/streaming.rb +6 -15
- data/lib/action_controller/templates/rescues/_request_and_response.rhtml +5 -5
- data/lib/action_controller/templates/rescues/diagnostics.rhtml +2 -2
- data/lib/action_controller/templates/rescues/routing_error.rhtml +4 -4
- data/lib/action_controller/templates/rescues/template_error.rhtml +1 -1
- data/lib/action_controller/templates/scaffolds/list.rhtml +1 -1
- data/lib/action_controller/test_process.rb +52 -30
- data/lib/action_controller/url_rewriter.rb +63 -29
- data/lib/action_controller/vendor/html-scanner/html/document.rb +1 -0
- data/lib/action_controller/vendor/html-scanner/html/node.rb +3 -4
- data/lib/action_controller/vendor/html-scanner/html/selector.rb +822 -0
- data/lib/action_controller/verification.rb +22 -11
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/version.rb +2 -2
- data/lib/action_view.rb +1 -1
- data/lib/action_view/base.rb +46 -43
- data/lib/action_view/compiled_templates.rb +1 -1
- data/lib/action_view/helpers/active_record_helper.rb +54 -17
- data/lib/action_view/helpers/asset_tag_helper.rb +97 -46
- data/lib/action_view/helpers/capture_helper.rb +1 -1
- data/lib/action_view/helpers/date_helper.rb +258 -136
- data/lib/action_view/helpers/debug_helper.rb +1 -1
- data/lib/action_view/helpers/deprecated_helper.rb +34 -0
- data/lib/action_view/helpers/form_helper.rb +75 -35
- data/lib/action_view/helpers/form_options_helper.rb +7 -5
- data/lib/action_view/helpers/form_tag_helper.rb +44 -6
- data/lib/action_view/helpers/java_script_macros_helper.rb +59 -46
- data/lib/action_view/helpers/javascript_helper.rb +71 -10
- data/lib/action_view/helpers/javascripts/controls.js +41 -23
- data/lib/action_view/helpers/javascripts/dragdrop.js +105 -76
- data/lib/action_view/helpers/javascripts/effects.js +293 -163
- data/lib/action_view/helpers/javascripts/prototype.js +897 -389
- data/lib/action_view/helpers/javascripts/prototype.js.rej +561 -0
- data/lib/action_view/helpers/number_helper.rb +111 -65
- data/lib/action_view/helpers/prototype_helper.rb +84 -109
- data/lib/action_view/helpers/scriptaculous_helper.rb +5 -0
- data/lib/action_view/helpers/tag_helper.rb +69 -16
- data/lib/action_view/helpers/text_helper.rb +149 -112
- data/lib/action_view/helpers/url_helper.rb +200 -107
- data/lib/action_view/template_error.rb +66 -42
- data/test/abstract_unit.rb +4 -2
- data/test/active_record_unit.rb +84 -56
- data/test/activerecord/active_record_assertions_test.rb +26 -18
- data/test/activerecord/active_record_store_test.rb +4 -36
- data/test/activerecord/pagination_test.rb +1 -6
- data/test/controller/action_pack_assertions_test.rb +230 -113
- data/test/controller/addresses_render_test.rb +2 -6
- data/test/controller/assert_select_test.rb +576 -0
- data/test/controller/base_test.rb +73 -3
- data/test/controller/caching_test.rb +228 -0
- data/test/controller/capture_test.rb +12 -10
- data/test/controller/cgi_test.rb +89 -12
- data/test/controller/components_test.rb +24 -2
- data/test/controller/content_type_test.rb +139 -0
- data/test/controller/controller_fixtures/app/controllers/admin/user_controller.rb +0 -0
- data/test/controller/controller_fixtures/app/controllers/user_controller.rb +0 -0
- data/test/controller/controller_fixtures/vendor/plugins/bad_plugin/lib/plugin_controller.rb +0 -0
- data/test/controller/cookie_test.rb +33 -25
- data/test/controller/deprecated_instance_variables_test.rb +48 -0
- data/test/controller/deprecation/deprecated_base_methods_test.rb +60 -0
- data/test/controller/fake_controllers.rb +0 -1
- data/test/controller/filters_test.rb +301 -16
- data/test/controller/flash_test.rb +19 -2
- data/test/controller/helper_test.rb +2 -2
- data/test/controller/integration_test.rb +154 -0
- data/test/controller/layout_test.rb +115 -1
- data/test/controller/mime_responds_test.rb +94 -0
- data/test/controller/mime_type_test.rb +9 -0
- data/test/controller/new_render_test.rb +161 -11
- data/test/controller/raw_post_test.rb +52 -15
- data/test/controller/redirect_test.rb +27 -14
- data/test/controller/render_test.rb +76 -29
- data/test/controller/request_test.rb +55 -4
- data/test/controller/resources_test.rb +274 -0
- data/test/controller/routing_test.rb +1533 -824
- data/test/controller/selector_test.rb +628 -0
- data/test/controller/send_file_test.rb +9 -1
- data/test/controller/session_management_test.rb +51 -0
- data/test/controller/test_test.rb +113 -29
- data/test/controller/url_rewriter_test.rb +86 -17
- data/test/controller/verification_test.rb +19 -17
- data/test/controller/webservice_test.rb +0 -7
- data/test/fixtures/content_type/render_default_content_types_for_respond_to.rhtml +1 -0
- data/test/fixtures/content_type/render_default_for_rhtml.rhtml +1 -0
- data/test/fixtures/content_type/render_default_for_rjs.rjs +1 -0
- data/test/fixtures/content_type/render_default_for_rxml.rxml +1 -0
- data/test/fixtures/deprecated_instance_variables/_cookies_ivar.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_cookies_method.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_flash_ivar.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_flash_method.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_headers_ivar.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_headers_method.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_params_ivar.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_params_method.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_request_ivar.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_request_method.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_response_ivar.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_response_method.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_session_ivar.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_session_method.rhtml +1 -0
- data/test/fixtures/multipart/binary_file +0 -0
- data/test/fixtures/public/javascripts/application.js +1 -0
- data/test/fixtures/test/_hello.rxml +1 -0
- data/test/fixtures/test/hello_world_container.rxml +3 -0
- data/test/fixtures/topic.rb +2 -2
- data/test/template/active_record_helper_test.rb +83 -12
- data/test/template/asset_tag_helper_test.rb +75 -95
- data/test/template/compiled_templates_test.rb +1 -0
- data/test/template/date_helper_test.rb +873 -181
- data/test/template/deprecated_helper_test.rb +36 -0
- data/test/template/deprecated_instance_variables_test.rb +43 -0
- data/test/template/form_helper_test.rb +77 -1
- data/test/template/form_options_helper_test.rb +4 -0
- data/test/template/form_tag_helper_test.rb +66 -2
- data/test/template/java_script_macros_helper_test.rb +4 -1
- data/test/template/javascript_helper_test.rb +29 -0
- data/test/template/number_helper_test.rb +63 -27
- data/test/template/prototype_helper_test.rb +77 -34
- data/test/template/tag_helper_test.rb +34 -6
- data/test/template/text_helper_test.rb +69 -34
- data/test/template/url_helper_test.rb +168 -16
- data/test/testing_sandbox.rb +7 -22
- metadata +66 -20
- data/filler.txt +0 -50
- data/lib/action_controller/code_generation.rb +0 -235
- data/lib/action_controller/vendor/xml_simple.rb +0 -1019
- data/test/controller/caching_filestore.rb +0 -74
- data/test/fixtures/application_root/app/controllers/a_class_that_contains_a_controller/poorly_placed_controller.rb +0 -7
- data/test/fixtures/application_root/app/controllers/module_that_holds_controllers/nested_controller.rb +0 -3
- data/test/fixtures/application_root/app/models/a_class_that_contains_a_controller.rb +0 -7
- data/test/fixtures/dont_load.rb +0 -3
@@ -7,7 +7,7 @@ module ActionView
|
|
7
7
|
begin
|
8
8
|
Marshal::dump(object)
|
9
9
|
"<pre class='debug_dump'>#{h(object.to_yaml).gsub(" ", " ")}</pre>"
|
10
|
-
rescue
|
10
|
+
rescue Exception => e # errors from Marshal or YAML
|
11
11
|
# Object couldn't be dumped, perhaps because of singleton methods -- this is the fallback
|
12
12
|
"<code class='debug_dump'>#{h(object.inspect)}</code>"
|
13
13
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module ActionView
|
2
|
+
module Helpers
|
3
|
+
module PrototypeHelper
|
4
|
+
|
5
|
+
def update_element_function(element_id, options = {}, &block)
|
6
|
+
content = escape_javascript(options[:content] || '')
|
7
|
+
content = escape_javascript(capture(&block)) if block
|
8
|
+
|
9
|
+
javascript_function = case (options[:action] || :update)
|
10
|
+
when :update
|
11
|
+
if options[:position]
|
12
|
+
"new Insertion.#{options[:position].to_s.camelize}('#{element_id}','#{content}')"
|
13
|
+
else
|
14
|
+
"$('#{element_id}').innerHTML = '#{content}'"
|
15
|
+
end
|
16
|
+
|
17
|
+
when :empty
|
18
|
+
"$('#{element_id}').innerHTML = ''"
|
19
|
+
|
20
|
+
when :remove
|
21
|
+
"Element.remove('#{element_id}')"
|
22
|
+
|
23
|
+
else
|
24
|
+
raise ArgumentError, "Invalid action, choose one of :update, :remove, :empty"
|
25
|
+
end
|
26
|
+
|
27
|
+
javascript_function << ";\n"
|
28
|
+
options[:binding] ? concat(javascript_function, options[:binding]) : javascript_function
|
29
|
+
end
|
30
|
+
deprecate :update_element_function => "use RJS instead"
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -142,11 +142,13 @@ module ActionView
|
|
142
142
|
#
|
143
143
|
# Note: This also works for the methods in FormOptionHelper and DateHelper that are designed to work with an object as base.
|
144
144
|
# Like collection_select and datetime_select.
|
145
|
-
def fields_for(object_name, *args, &
|
145
|
+
def fields_for(object_name, *args, &block)
|
146
146
|
raise ArgumentError, "Missing block" unless block_given?
|
147
147
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
148
148
|
object = args.first
|
149
|
-
|
149
|
+
|
150
|
+
builder = options[:builder] || ActionView::Base.default_form_builder
|
151
|
+
yield builder.new(object_name, object, self, options, block)
|
150
152
|
end
|
151
153
|
|
152
154
|
# Returns an input tag of the "text" type tailored for accessing a specified attribute (identified by +method+) on an object
|
@@ -238,7 +240,11 @@ module ActionView
|
|
238
240
|
@template_object, @local_binding = template_object, local_binding
|
239
241
|
@object = object
|
240
242
|
if @object_name.sub!(/\[\]$/,"")
|
241
|
-
|
243
|
+
if object ||= @template_object.instance_variable_get("@#{Regexp.last_match.pre_match}") and object.respond_to?(:id_before_type_cast)
|
244
|
+
@auto_index = object.id_before_type_cast
|
245
|
+
else
|
246
|
+
raise ArgumentError, "object[] naming but object param and @object var don't exist or don't respond to id_before_type_cast: #{object.inspect}"
|
247
|
+
end
|
242
248
|
end
|
243
249
|
end
|
244
250
|
|
@@ -250,7 +256,7 @@ module ActionView
|
|
250
256
|
options.delete("size")
|
251
257
|
end
|
252
258
|
options["type"] = field_type
|
253
|
-
options["value"] ||= value_before_type_cast unless field_type == "file"
|
259
|
+
options["value"] ||= value_before_type_cast(object) unless field_type == "file"
|
254
260
|
add_default_name_and_id(options)
|
255
261
|
tag("input", options)
|
256
262
|
end
|
@@ -259,9 +265,15 @@ module ActionView
|
|
259
265
|
options = DEFAULT_RADIO_OPTIONS.merge(options.stringify_keys)
|
260
266
|
options["type"] = "radio"
|
261
267
|
options["value"] = tag_value
|
262
|
-
options
|
268
|
+
if options.has_key?("checked")
|
269
|
+
cv = options.delete "checked"
|
270
|
+
checked = cv == true || cv == "checked"
|
271
|
+
else
|
272
|
+
checked = self.class.radio_button_checked?(value(object), tag_value)
|
273
|
+
end
|
274
|
+
options["checked"] = "checked" if checked
|
263
275
|
pretty_tag_value = tag_value.to_s.gsub(/\s/, "_").gsub(/\W/, "").downcase
|
264
|
-
options["id"]
|
276
|
+
options["id"] ||= defined?(@auto_index) ?
|
265
277
|
"#{@object_name}_#{@auto_index}_#{@method_name}_#{pretty_tag_value}" :
|
266
278
|
"#{@object_name}_#{@method_name}_#{pretty_tag_value}"
|
267
279
|
add_default_name_and_id(options)
|
@@ -271,37 +283,32 @@ module ActionView
|
|
271
283
|
def to_text_area_tag(options = {})
|
272
284
|
options = DEFAULT_TEXT_AREA_OPTIONS.merge(options.stringify_keys)
|
273
285
|
add_default_name_and_id(options)
|
274
|
-
|
286
|
+
|
287
|
+
if size = options.delete("size")
|
288
|
+
options["cols"], options["rows"] = size.split("x")
|
289
|
+
end
|
290
|
+
|
291
|
+
content_tag("textarea", html_escape(options.delete('value') || value_before_type_cast(object)), options)
|
275
292
|
end
|
276
293
|
|
277
294
|
def to_check_box_tag(options = {}, checked_value = "1", unchecked_value = "0")
|
278
295
|
options = options.stringify_keys
|
279
296
|
options["type"] = "checkbox"
|
280
297
|
options["value"] = checked_value
|
281
|
-
checked
|
282
|
-
|
283
|
-
|
284
|
-
when NilClass
|
285
|
-
false
|
286
|
-
when Integer
|
287
|
-
value != 0
|
288
|
-
when String
|
289
|
-
value == checked_value
|
290
|
-
else
|
291
|
-
value.to_i != 0
|
292
|
-
end
|
293
|
-
if checked || options["checked"] == "checked"
|
294
|
-
options["checked"] = "checked"
|
298
|
+
if options.has_key?("checked")
|
299
|
+
cv = options.delete "checked"
|
300
|
+
checked = cv == true || cv == "checked"
|
295
301
|
else
|
296
|
-
|
302
|
+
checked = self.class.check_box_checked?(value(object), checked_value)
|
297
303
|
end
|
304
|
+
options["checked"] = "checked" if checked
|
298
305
|
add_default_name_and_id(options)
|
299
306
|
tag("input", options) << tag("input", "name" => options["name"], "type" => "hidden", "value" => unchecked_value)
|
300
307
|
end
|
301
308
|
|
302
309
|
def to_date_tag()
|
303
310
|
defaults = DEFAULT_DATE_OPTIONS.dup
|
304
|
-
date = value || Date.today
|
311
|
+
date = value(object) || Date.today
|
305
312
|
options = Proc.new { |position| defaults.merge(:prefix => "#{@object_name}[#{@method_name}(#{position}i)]") }
|
306
313
|
html_day_select(date, options.call(3)) +
|
307
314
|
html_month_select(date, options.call(2)) +
|
@@ -311,6 +318,7 @@ module ActionView
|
|
311
318
|
def to_boolean_select_tag(options = {})
|
312
319
|
options = options.stringify_keys
|
313
320
|
add_default_name_and_id(options)
|
321
|
+
value = value(object)
|
314
322
|
tag_text = "<select"
|
315
323
|
tag_text << tag_options(options)
|
316
324
|
tag_text << "><option value=\"false\""
|
@@ -321,24 +329,51 @@ module ActionView
|
|
321
329
|
end
|
322
330
|
|
323
331
|
def to_content_tag(tag_name, options = {})
|
324
|
-
content_tag(tag_name, value, options)
|
332
|
+
content_tag(tag_name, value(object), options)
|
325
333
|
end
|
326
334
|
|
327
335
|
def object
|
328
336
|
@object || @template_object.instance_variable_get("@#{@object_name}")
|
329
337
|
end
|
330
338
|
|
331
|
-
def value
|
332
|
-
|
333
|
-
object.send(@method_name)
|
334
|
-
end
|
339
|
+
def value(object)
|
340
|
+
self.class.value(object, @method_name)
|
335
341
|
end
|
336
342
|
|
337
|
-
def value_before_type_cast
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
343
|
+
def value_before_type_cast(object)
|
344
|
+
self.class.value_before_type_cast(object, @method_name)
|
345
|
+
end
|
346
|
+
|
347
|
+
class << self
|
348
|
+
def value(object, method_name)
|
349
|
+
object.send method_name unless object.nil?
|
350
|
+
end
|
351
|
+
|
352
|
+
def value_before_type_cast(object, method_name)
|
353
|
+
unless object.nil?
|
354
|
+
object.respond_to?(method_name + "_before_type_cast") ?
|
355
|
+
object.send(method_name + "_before_type_cast") :
|
356
|
+
object.send(method_name)
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
def check_box_checked?(value, checked_value)
|
361
|
+
case value
|
362
|
+
when TrueClass, FalseClass
|
363
|
+
value
|
364
|
+
when NilClass
|
365
|
+
false
|
366
|
+
when Integer
|
367
|
+
value != 0
|
368
|
+
when String
|
369
|
+
value == checked_value
|
370
|
+
else
|
371
|
+
value.to_i != 0
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
def radio_button_checked?(value, checked_value)
|
376
|
+
value.to_s == checked_value.to_s
|
342
377
|
end
|
343
378
|
end
|
344
379
|
|
@@ -348,7 +383,7 @@ module ActionView
|
|
348
383
|
options["name"] ||= tag_name_with_index(options["index"])
|
349
384
|
options["id"] ||= tag_id_with_index(options["index"])
|
350
385
|
options.delete("index")
|
351
|
-
elsif @auto_index
|
386
|
+
elsif defined?(@auto_index)
|
352
387
|
options["name"] ||= tag_name_with_index(@auto_index)
|
353
388
|
options["id"] ||= tag_id_with_index(@auto_index)
|
354
389
|
else
|
@@ -379,7 +414,7 @@ module ActionView
|
|
379
414
|
class_inheritable_accessor :field_helpers
|
380
415
|
self.field_helpers = (FormHelper.instance_methods - ['form_for'])
|
381
416
|
|
382
|
-
attr_accessor :object_name, :object
|
417
|
+
attr_accessor :object_name, :object, :options
|
383
418
|
|
384
419
|
def initialize(object_name, object, template, options, proc)
|
385
420
|
@object_name, @object, @template, @options, @proc = object_name, object, template, options, proc
|
@@ -403,4 +438,9 @@ module ActionView
|
|
403
438
|
end
|
404
439
|
end
|
405
440
|
end
|
441
|
+
|
442
|
+
class Base
|
443
|
+
cattr_accessor :default_form_builder
|
444
|
+
self.default_form_builder = ::ActionView::Helpers::FormBuilder
|
445
|
+
end
|
406
446
|
end
|
@@ -26,7 +26,7 @@ module ActionView
|
|
26
26
|
#
|
27
27
|
# Another common case is a select tag for an <tt>belongs_to</tt>-associated object. For example,
|
28
28
|
#
|
29
|
-
# select("post", "person_id", Person.
|
29
|
+
# select("post", "person_id", Person.find(:all).collect {|p| [ p.name, p.id ] })
|
30
30
|
#
|
31
31
|
# could become:
|
32
32
|
#
|
@@ -43,7 +43,7 @@ module ActionView
|
|
43
43
|
# See options_for_select for the required format of the choices parameter.
|
44
44
|
#
|
45
45
|
# Example with @post.person_id => 1:
|
46
|
-
# select("post", "person_id", Person.
|
46
|
+
# select("post", "person_id", Person.find(:all).collect {|p| [ p.name, p.id ] }, { :include_blank => true })
|
47
47
|
#
|
48
48
|
# could become:
|
49
49
|
#
|
@@ -113,7 +113,6 @@ module ActionView
|
|
113
113
|
|
114
114
|
options_for_select = container.inject([]) do |options, element|
|
115
115
|
if !element.is_a?(String) and element.respond_to?(:first) and element.respond_to?(:last)
|
116
|
-
is_selected = ( (selected.respond_to?(:include?) ? selected.include?(element.last) : element.last == selected) )
|
117
116
|
is_selected = ( (selected.respond_to?(:include?) && !selected.is_a?(String) ? selected.include?(element.last) : element.last == selected) )
|
118
117
|
if is_selected
|
119
118
|
options << "<option value=\"#{html_escape(element.last.to_s)}\" selected=\"selected\">#{html_escape(element.first.to_s)}</option>"
|
@@ -121,7 +120,6 @@ module ActionView
|
|
121
120
|
options << "<option value=\"#{html_escape(element.last.to_s)}\">#{html_escape(element.first.to_s)}</option>"
|
122
121
|
end
|
123
122
|
else
|
124
|
-
is_selected = ( (selected.respond_to?(:include?) ? selected.include?(element) : element == selected) )
|
125
123
|
is_selected = ( (selected.respond_to?(:include?) && !selected.is_a?(String) ? selected.include?(element) : element == selected) )
|
126
124
|
options << ((is_selected) ? "<option value=\"#{html_escape(element.to_s)}\" selected=\"selected\">#{html_escape(element.to_s)}</option>" : "<option value=\"#{html_escape(element.to_s)}\">#{html_escape(element.to_s)}</option>")
|
127
125
|
end
|
@@ -299,13 +297,15 @@ module ActionView
|
|
299
297
|
def to_select_tag(choices, options, html_options)
|
300
298
|
html_options = html_options.stringify_keys
|
301
299
|
add_default_name_and_id(html_options)
|
300
|
+
value = value(object)
|
302
301
|
selected_value = options.has_key?(:selected) ? options[:selected] : value
|
303
|
-
content_tag("select", add_options(options_for_select(choices, selected_value), options,
|
302
|
+
content_tag("select", add_options(options_for_select(choices, selected_value), options, selected_value), html_options)
|
304
303
|
end
|
305
304
|
|
306
305
|
def to_collection_select_tag(collection, value_method, text_method, options, html_options)
|
307
306
|
html_options = html_options.stringify_keys
|
308
307
|
add_default_name_and_id(html_options)
|
308
|
+
value = value(object)
|
309
309
|
content_tag(
|
310
310
|
"select", add_options(options_from_collection_for_select(collection, value_method, text_method, value), options, value), html_options
|
311
311
|
)
|
@@ -314,12 +314,14 @@ module ActionView
|
|
314
314
|
def to_country_select_tag(priority_countries, options, html_options)
|
315
315
|
html_options = html_options.stringify_keys
|
316
316
|
add_default_name_and_id(html_options)
|
317
|
+
value = value(object)
|
317
318
|
content_tag("select", add_options(country_options_for_select(value, priority_countries), options, value), html_options)
|
318
319
|
end
|
319
320
|
|
320
321
|
def to_time_zone_select_tag(priority_zones, options, html_options)
|
321
322
|
html_options = html_options.stringify_keys
|
322
323
|
add_default_name_and_id(html_options)
|
324
|
+
value = value(object)
|
323
325
|
content_tag("select",
|
324
326
|
add_options(
|
325
327
|
time_zone_options_for_select(value, priority_zones, options[:model] || TimeZone),
|
@@ -12,14 +12,49 @@ module ActionView
|
|
12
12
|
# Starts a form tag that points the action to an url configured with <tt>url_for_options</tt> just like
|
13
13
|
# ActionController::Base#url_for. The method for the form defaults to POST.
|
14
14
|
#
|
15
|
+
# Examples:
|
16
|
+
# * <tt>form_tag('/posts') => <form action="/posts" method="post"></tt>
|
17
|
+
# * <tt>form_tag('/posts/1', :method => :put) => <form action="/posts/1" method="put"></tt>
|
18
|
+
# * <tt>form_tag('/upload', :multipart => true) => <form action="/upload" method="post" enctype="multipart/form-data"></tt>
|
19
|
+
#
|
20
|
+
# ERb example:
|
21
|
+
# <% form_tag '/posts' do -%>
|
22
|
+
# <div><%= submit_tag 'Save' %></div>
|
23
|
+
# <% end -%>
|
24
|
+
#
|
25
|
+
# Will output:
|
26
|
+
# <form action="/posts" method="post"><div><input type="submit" name="submit" value="Save" /></div></form>
|
27
|
+
#
|
15
28
|
# Options:
|
16
29
|
# * <tt>:multipart</tt> - If set to true, the enctype is set to "multipart/form-data".
|
17
|
-
# * <tt>:method</tt>
|
18
|
-
|
19
|
-
|
30
|
+
# * <tt>:method</tt> - The method to use when submitting the form, usually either "get" or "post".
|
31
|
+
# If "put", "delete", or another verb is used, a hidden input with name _method
|
32
|
+
# is added to simulate the verb over post.
|
33
|
+
def form_tag(url_for_options = {}, options = {}, *parameters_for_url, &block)
|
34
|
+
html_options = options.stringify_keys
|
20
35
|
html_options["enctype"] = "multipart/form-data" if html_options.delete("multipart")
|
21
|
-
html_options["action"]
|
22
|
-
|
36
|
+
html_options["action"] = url_for(url_for_options, *parameters_for_url)
|
37
|
+
|
38
|
+
method_tag = ""
|
39
|
+
|
40
|
+
case method = html_options.delete("method").to_s
|
41
|
+
when /^get$/i # must be case-insentive, but can't use downcase as might be nil
|
42
|
+
html_options["method"] = "get"
|
43
|
+
when /^post$/i, "", nil
|
44
|
+
html_options["method"] = "post"
|
45
|
+
else
|
46
|
+
html_options["method"] = "post"
|
47
|
+
method_tag = content_tag(:div, tag(:input, :type => "hidden", :name => "_method", :value => method), :style => 'margin:0;padding:0')
|
48
|
+
end
|
49
|
+
|
50
|
+
if block_given?
|
51
|
+
content = capture(&block)
|
52
|
+
concat(tag(:form, html_options, true) + method_tag, block.binding)
|
53
|
+
concat(content, block.binding)
|
54
|
+
concat("</form>", block.binding)
|
55
|
+
else
|
56
|
+
tag(:form, html_options, true) + method_tag
|
57
|
+
end
|
23
58
|
end
|
24
59
|
|
25
60
|
alias_method :start_form_tag, :form_tag
|
@@ -28,6 +63,8 @@ module ActionView
|
|
28
63
|
def end_form_tag
|
29
64
|
"</form>"
|
30
65
|
end
|
66
|
+
|
67
|
+
deprecate :end_form_tag, :start_form_tag => :form_tag
|
31
68
|
|
32
69
|
# Creates a dropdown selection box, or if the <tt>:multiple</tt> option is set to true, a multiple
|
33
70
|
# choice selection box.
|
@@ -110,7 +147,8 @@ module ActionView
|
|
110
147
|
|
111
148
|
# Creates a radio button.
|
112
149
|
def radio_button_tag(name, value, checked = false, options = {})
|
113
|
-
|
150
|
+
pretty_tag_value = value.to_s.gsub(/\s/, "_").gsub(/(?!-)\W/, "").downcase
|
151
|
+
html_options = { "type" => "radio", "name" => name, "id" => "#{name}_#{pretty_tag_value}", "value" => value }.update(options.stringify_keys)
|
114
152
|
html_options["checked"] = "checked" if checked
|
115
153
|
tag :input, html_options
|
116
154
|
end
|
@@ -7,6 +7,8 @@ module ActionView
|
|
7
7
|
# editing relies on ActionController::Base.in_place_edit_for and the autocompletion relies on
|
8
8
|
# ActionController::Base.auto_complete_for.
|
9
9
|
module JavaScriptMacrosHelper
|
10
|
+
# DEPRECATION WARNING: This method will become a separate plugin when Rails 2.0 ships.
|
11
|
+
#
|
10
12
|
# Makes an HTML element specified by the DOM ID +field_id+ become an in-place
|
11
13
|
# editor of a property.
|
12
14
|
#
|
@@ -27,20 +29,21 @@ module ActionView
|
|
27
29
|
# <tt>:url</tt>:: Specifies the url where the updated value should
|
28
30
|
# be sent after the user presses "ok".
|
29
31
|
#
|
30
|
-
#
|
31
32
|
# Addtional +options+ are:
|
32
33
|
# <tt>:rows</tt>:: Number of rows (more than 1 will use a TEXTAREA)
|
33
34
|
# <tt>:cols</tt>:: Number of characters the text input should span (works for both INPUT and TEXTAREA)
|
34
35
|
# <tt>:size</tt>:: Synonym for :cols when using a single line text input.
|
35
36
|
# <tt>:cancel_text</tt>:: The text on the cancel link. (default: "cancel")
|
36
37
|
# <tt>:save_text</tt>:: The text on the save link. (default: "ok")
|
37
|
-
# <tt>:loading_text</tt>:: The text to display
|
38
|
+
# <tt>:loading_text</tt>:: The text to display while the data is being loaded from the server (default: "Loading...")
|
39
|
+
# <tt>:saving_text</tt>:: The text to display when submitting to the server (default: "Saving...")
|
38
40
|
# <tt>:external_control</tt>:: The id of an external control used to enter edit mode.
|
39
41
|
# <tt>:load_text_url</tt>:: URL where initial value of editor (content) is retrieved.
|
40
42
|
# <tt>:options</tt>:: Pass through options to the AJAX call (see prototype's Ajax.Updater)
|
41
43
|
# <tt>:with</tt>:: JavaScript snippet that should return what is to be sent
|
42
44
|
# in the AJAX call, +form+ is an implicit parameter
|
43
45
|
# <tt>:script</tt>:: Instructs the in-place editor to evaluate the remote JavaScript response (default: false)
|
46
|
+
# <tt>:click_to_edit_text</tt>::The text shown during mouseover the editable text (default: "Click to edit")
|
44
47
|
def in_place_editor(field_id, options = {})
|
45
48
|
function = "new Ajax.InPlaceEditor("
|
46
49
|
function << "'#{field_id}', "
|
@@ -50,6 +53,7 @@ module ActionView
|
|
50
53
|
js_options['cancelText'] = %('#{options[:cancel_text]}') if options[:cancel_text]
|
51
54
|
js_options['okText'] = %('#{options[:save_text]}') if options[:save_text]
|
52
55
|
js_options['loadingText'] = %('#{options[:loading_text]}') if options[:loading_text]
|
56
|
+
js_options['savingText'] = %('#{options[:saving_text]}') if options[:saving_text]
|
53
57
|
js_options['rows'] = options[:rows] if options[:rows]
|
54
58
|
js_options['cols'] = options[:cols] if options[:cols]
|
55
59
|
js_options['size'] = options[:size] if options[:size]
|
@@ -58,6 +62,7 @@ module ActionView
|
|
58
62
|
js_options['ajaxOptions'] = options[:options] if options[:options]
|
59
63
|
js_options['evalScripts'] = options[:script] if options[:script]
|
60
64
|
js_options['callback'] = "function(form) { return #{options[:with]} }" if options[:with]
|
65
|
+
js_options['clickToEditText'] = %('#{options[:click_to_edit_text]}') if options[:click_to_edit_text]
|
61
66
|
function << (', ' + options_for_javascript(js_options)) unless js_options.empty?
|
62
67
|
|
63
68
|
function << ')'
|
@@ -65,6 +70,8 @@ module ActionView
|
|
65
70
|
javascript_tag(function)
|
66
71
|
end
|
67
72
|
|
73
|
+
# DEPRECATION WARNING: This method will become a separate plugin when Rails 2.0 ships.
|
74
|
+
#
|
68
75
|
# Renders the value of the specified object and method with in-place editing capabilities.
|
69
76
|
#
|
70
77
|
# See the RDoc on ActionController::InPlaceEditing to learn more about this.
|
@@ -76,14 +83,16 @@ module ActionView
|
|
76
83
|
in_place_editor(tag_options[:id], in_place_editor_options)
|
77
84
|
end
|
78
85
|
|
86
|
+
# DEPRECATION WARNING: This method will become a separate plugin when Rails 2.0 ships.
|
87
|
+
#
|
79
88
|
# Adds AJAX autocomplete functionality to the text input field with the
|
80
89
|
# DOM ID specified by +field_id+.
|
81
90
|
#
|
82
|
-
# This function expects that the called action returns
|
91
|
+
# This function expects that the called action returns an HTML <ul> list,
|
83
92
|
# or nothing if no entries should be displayed for autocompletion.
|
84
93
|
#
|
85
94
|
# You'll probably want to turn the browser's built-in autocompletion off,
|
86
|
-
# so be sure to include
|
95
|
+
# so be sure to include an <tt>autocomplete="off"</tt> attribute with your text
|
87
96
|
# input field.
|
88
97
|
#
|
89
98
|
# The autocompleter object is assigned to a Javascript variable named <tt>field_id</tt>_auto_completer.
|
@@ -91,45 +100,45 @@ module ActionView
|
|
91
100
|
# other means than user input (for that specific case, call the <tt>activate</tt> method on that object).
|
92
101
|
#
|
93
102
|
# Required +options+ are:
|
94
|
-
# <tt>:url</tt>::
|
95
|
-
#
|
103
|
+
# <tt>:url</tt>:: URL to call for autocompletion results
|
104
|
+
# in url_for format.
|
96
105
|
#
|
97
106
|
# Addtional +options+ are:
|
98
|
-
# <tt>:update</tt>::
|
99
|
-
#
|
100
|
-
#
|
101
|
-
#
|
102
|
-
# <tt>:with</tt>::
|
103
|
-
#
|
104
|
-
#
|
105
|
-
# <tt>:frequency</tt>::
|
106
|
-
#
|
107
|
-
# <tt>:indicator</tt>::
|
108
|
-
#
|
109
|
-
# <tt>:tokens</tt>::
|
110
|
-
#
|
111
|
-
#
|
112
|
-
#
|
113
|
-
#
|
114
|
-
# <tt>:min_chars</tt>::
|
115
|
-
#
|
116
|
-
#
|
117
|
-
# <tt>:on_hide</tt>::
|
118
|
-
#
|
119
|
-
#
|
120
|
-
#
|
121
|
-
#
|
122
|
-
#
|
123
|
-
# <tt>:on_show</tt>::
|
124
|
-
#
|
125
|
-
# <tt>:after_update_element</tt>::
|
126
|
-
#
|
127
|
-
#
|
128
|
-
#
|
129
|
-
#
|
130
|
-
# <tt>:select</tt>::
|
131
|
-
#
|
132
|
-
#
|
107
|
+
# <tt>:update</tt>:: Specifies the DOM ID of the element whose
|
108
|
+
# innerHTML should be updated with the autocomplete
|
109
|
+
# entries returned by the AJAX request.
|
110
|
+
# Defaults to <tt>field_id</tt> + '_auto_complete'
|
111
|
+
# <tt>:with</tt>:: A JavaScript expression specifying the
|
112
|
+
# parameters for the XMLHttpRequest. This defaults
|
113
|
+
# to 'fieldname=value'.
|
114
|
+
# <tt>:frequency</tt>:: Determines the time to wait after the last keystroke
|
115
|
+
# for the AJAX request to be initiated.
|
116
|
+
# <tt>:indicator</tt>:: Specifies the DOM ID of an element which will be
|
117
|
+
# displayed while autocomplete is running.
|
118
|
+
# <tt>:tokens</tt>:: A string or an array of strings containing
|
119
|
+
# separator tokens for tokenized incremental
|
120
|
+
# autocompletion. Example: <tt>:tokens => ','</tt> would
|
121
|
+
# allow multiple autocompletion entries, separated
|
122
|
+
# by commas.
|
123
|
+
# <tt>:min_chars</tt>:: The minimum number of characters that should be
|
124
|
+
# in the input field before an Ajax call is made
|
125
|
+
# to the server.
|
126
|
+
# <tt>:on_hide</tt>:: A Javascript expression that is called when the
|
127
|
+
# autocompletion div is hidden. The expression
|
128
|
+
# should take two variables: element and update.
|
129
|
+
# Element is a DOM element for the field, update
|
130
|
+
# is a DOM element for the div from which the
|
131
|
+
# innerHTML is replaced.
|
132
|
+
# <tt>:on_show</tt>:: Like on_hide, only now the expression is called
|
133
|
+
# then the div is shown.
|
134
|
+
# <tt>:after_update_element</tt>:: A Javascript expression that is called when the
|
135
|
+
# user has selected one of the proposed values.
|
136
|
+
# The expression should take two variables: element and value.
|
137
|
+
# Element is a DOM element for the field, value
|
138
|
+
# is the value selected by the user.
|
139
|
+
# <tt>:select</tt>:: Pick the class of the element from which the value for
|
140
|
+
# insertion should be extracted. If this is not specified,
|
141
|
+
# the entire element is used.
|
133
142
|
def auto_complete_field(field_id, options = {})
|
134
143
|
function = "var #{field_id}_auto_completer = new Ajax.Autocompleter("
|
135
144
|
function << "'#{field_id}', "
|
@@ -141,6 +150,7 @@ module ActionView
|
|
141
150
|
js_options[:callback] = "function(element, value) { return #{options[:with]} }" if options[:with]
|
142
151
|
js_options[:indicator] = "'#{options[:indicator]}'" if options[:indicator]
|
143
152
|
js_options[:select] = "'#{options[:select]}'" if options[:select]
|
153
|
+
js_options[:paramName] = "'#{options[:param_name]}'" if options[:param_name]
|
144
154
|
js_options[:frequency] = "#{options[:frequency]}" if options[:frequency]
|
145
155
|
|
146
156
|
{ :after_update_element => :afterUpdateElement,
|
@@ -153,6 +163,8 @@ module ActionView
|
|
153
163
|
javascript_tag(function)
|
154
164
|
end
|
155
165
|
|
166
|
+
# DEPRECATION WARNING: This method will become a separate plugin when Rails 2.0 ships.
|
167
|
+
#
|
156
168
|
# Use this method in your view to generate a return for the AJAX autocomplete requests.
|
157
169
|
#
|
158
170
|
# Example action:
|
@@ -161,7 +173,7 @@ module ActionView
|
|
161
173
|
# @items = Item.find(:all,
|
162
174
|
# :conditions => [ 'LOWER(description) LIKE ?',
|
163
175
|
# '%' + request.raw_post.downcase + '%' ])
|
164
|
-
# render :inline =>
|
176
|
+
# render :inline => "<%= auto_complete_result(@items, 'description') %>"
|
165
177
|
# end
|
166
178
|
#
|
167
179
|
# The auto_complete_result can of course also be called from a view belonging to the
|
@@ -172,12 +184,14 @@ module ActionView
|
|
172
184
|
content_tag("ul", items.uniq)
|
173
185
|
end
|
174
186
|
|
187
|
+
# DEPRECATION WARNING: This method will become a separate plugin when Rails 2.0 ships.
|
188
|
+
#
|
175
189
|
# Wrapper for text_field with added AJAX autocompletion functionality.
|
176
190
|
#
|
177
191
|
# In your controller, you'll need to define an action called
|
178
|
-
#
|
192
|
+
# auto_complete_for to respond the AJAX calls,
|
179
193
|
#
|
180
|
-
# See the RDoc on ActionController::AutoComplete to learn more about this.
|
194
|
+
# See the RDoc on ActionController::Macros::AutoComplete to learn more about this.
|
181
195
|
def text_field_with_auto_complete(object, method, tag_options = {}, completion_options = {})
|
182
196
|
(completion_options[:skip_style] ? "" : auto_complete_stylesheet) +
|
183
197
|
text_field(object, method, tag_options) +
|
@@ -187,7 +201,7 @@ module ActionView
|
|
187
201
|
|
188
202
|
private
|
189
203
|
def auto_complete_stylesheet
|
190
|
-
content_tag(
|
204
|
+
content_tag('style', <<-EOT, :type => 'text/css')
|
191
205
|
div.auto_complete {
|
192
206
|
width: 350px;
|
193
207
|
background: #fff;
|
@@ -212,7 +226,6 @@ module ActionView
|
|
212
226
|
padding:0;
|
213
227
|
}
|
214
228
|
EOT
|
215
|
-
)
|
216
229
|
end
|
217
230
|
|
218
231
|
end
|