actionpack 1.11.2 → 1.12.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 +392 -5
- data/lib/action_controller.rb +8 -4
- data/lib/action_controller/assertions.rb +9 -10
- data/lib/action_controller/base.rb +177 -88
- data/lib/action_controller/benchmarking.rb +5 -5
- data/lib/action_controller/caching.rb +44 -36
- data/lib/action_controller/cgi_ext/cgi_methods.rb +71 -6
- data/lib/action_controller/cgi_ext/cookie_performance_fix.rb +1 -1
- data/lib/action_controller/cgi_process.rb +36 -24
- data/lib/action_controller/components.rb +152 -52
- data/lib/action_controller/dependencies.rb +1 -1
- data/lib/action_controller/deprecated_redirects.rb +2 -2
- data/lib/action_controller/deprecated_request_methods.rb +34 -0
- data/lib/action_controller/filters.rb +59 -19
- data/lib/action_controller/flash.rb +53 -47
- data/lib/action_controller/helpers.rb +2 -2
- data/lib/action_controller/integration.rb +524 -0
- data/lib/action_controller/layout.rb +58 -23
- data/lib/action_controller/mime_responds.rb +163 -0
- data/lib/action_controller/mime_type.rb +142 -0
- data/lib/action_controller/pagination.rb +13 -7
- data/lib/action_controller/request.rb +59 -56
- data/lib/action_controller/rescue.rb +1 -1
- data/lib/action_controller/routing.rb +29 -10
- data/lib/action_controller/scaffolding.rb +8 -0
- data/lib/action_controller/session/active_record_store.rb +21 -10
- data/lib/action_controller/session/mem_cache_store.rb +18 -12
- data/lib/action_controller/session_management.rb +30 -11
- data/lib/action_controller/templates/rescues/_trace.rhtml +1 -1
- data/lib/action_controller/templates/scaffolds/layout.rhtml +4 -4
- data/lib/action_controller/templates/scaffolds/list.rhtml +1 -1
- data/lib/action_controller/test_process.rb +189 -118
- data/lib/action_controller/vendor/html-scanner/html/node.rb +20 -1
- data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +3 -0
- data/lib/action_controller/vendor/html-scanner/html/version.rb +1 -1
- data/lib/action_controller/vendor/xml_node.rb +97 -0
- data/lib/action_controller/verification.rb +2 -0
- data/lib/action_pack/version.rb +3 -3
- data/lib/action_view.rb +0 -2
- data/lib/action_view/base.rb +109 -36
- data/lib/action_view/compiled_templates.rb +1 -1
- data/lib/action_view/helpers/active_record_helper.rb +4 -2
- data/lib/action_view/helpers/asset_tag_helper.rb +6 -7
- data/lib/action_view/helpers/capture_helper.rb +49 -12
- data/lib/action_view/helpers/date_helper.rb +14 -4
- data/lib/action_view/helpers/form_helper.rb +136 -20
- data/lib/action_view/helpers/form_options_helper.rb +29 -7
- data/lib/action_view/helpers/form_tag_helper.rb +22 -20
- data/lib/action_view/helpers/java_script_macros_helper.rb +29 -9
- data/lib/action_view/helpers/javascript_helper.rb +50 -446
- data/lib/action_view/helpers/javascripts/controls.js +95 -30
- data/lib/action_view/helpers/javascripts/dragdrop.js +161 -21
- data/lib/action_view/helpers/javascripts/effects.js +310 -211
- data/lib/action_view/helpers/javascripts/prototype.js +228 -28
- data/lib/action_view/helpers/number_helper.rb +9 -9
- data/lib/action_view/helpers/pagination_helper.rb +1 -1
- data/lib/action_view/helpers/prototype_helper.rb +900 -0
- data/lib/action_view/helpers/scriptaculous_helper.rb +135 -0
- data/lib/action_view/helpers/text_helper.rb +7 -6
- data/lib/action_view/helpers/url_helper.rb +23 -14
- data/lib/action_view/partials.rb +12 -4
- data/rakefile +13 -5
- data/test/abstract_unit.rb +4 -3
- data/test/active_record_unit.rb +88 -0
- data/test/{controller → activerecord}/active_record_assertions_test.rb +7 -50
- data/test/{controller → activerecord}/active_record_store_test.rb +27 -4
- data/test/activerecord/pagination_test.rb +161 -0
- data/test/controller/action_pack_assertions_test.rb +18 -15
- data/test/controller/base_test.rb +31 -42
- data/test/controller/benchmark_test.rb +8 -11
- data/test/controller/capture_test.rb +33 -1
- data/test/controller/cgi_test.rb +33 -0
- data/test/controller/custom_handler_test.rb +8 -0
- data/test/controller/fake_controllers.rb +9 -17
- data/test/controller/filters_test.rb +32 -3
- data/test/controller/flash_test.rb +26 -41
- data/test/controller/fragment_store_setting_test.rb +1 -1
- data/test/controller/layout_test.rb +73 -0
- data/test/controller/mime_responds_test.rb +257 -0
- data/test/controller/mime_type_test.rb +24 -0
- data/test/controller/new_render_test.rb +157 -1
- data/test/controller/redirect_test.rb +23 -0
- data/test/controller/render_test.rb +54 -56
- data/test/controller/request_test.rb +25 -0
- data/test/controller/routing_test.rb +74 -66
- data/test/controller/test_test.rb +66 -1
- data/test/controller/verification_test.rb +3 -1
- data/test/controller/webservice_test.rb +255 -0
- data/test/fixtures/companies.yml +24 -0
- data/test/fixtures/company.rb +9 -0
- data/test/fixtures/db_definitions/sqlite.sql +42 -0
- data/test/fixtures/developer.rb +7 -0
- data/test/fixtures/developers.yml +21 -0
- data/test/fixtures/developers_projects.yml +13 -0
- data/test/fixtures/layout_tests/layouts/controller_name_space/nested.rhtml +1 -0
- data/test/fixtures/layout_tests/layouts/item.rhtml +1 -0
- data/test/fixtures/layout_tests/layouts/layout_test.rhtml +1 -0
- data/test/fixtures/layout_tests/layouts/third_party_template_library.mab +1 -0
- data/test/fixtures/layout_tests/views/hello.rhtml +1 -0
- data/test/fixtures/multipart/mona_lisa.jpg +0 -0
- data/test/fixtures/project.rb +3 -0
- data/test/fixtures/projects.yml +7 -0
- data/test/fixtures/replies.yml +13 -0
- data/test/fixtures/reply.rb +5 -0
- data/test/fixtures/respond_to/all_types_with_layout.rhtml +1 -0
- data/test/fixtures/respond_to/all_types_with_layout.rjs +1 -0
- data/test/fixtures/respond_to/layouts/standard.rhtml +1 -0
- data/test/fixtures/respond_to/using_defaults.rhtml +1 -0
- data/test/fixtures/respond_to/using_defaults.rjs +1 -0
- data/test/fixtures/respond_to/using_defaults.rxml +1 -0
- data/test/fixtures/respond_to/using_defaults_with_type_list.rhtml +1 -0
- data/test/fixtures/respond_to/using_defaults_with_type_list.rjs +1 -0
- data/test/fixtures/respond_to/using_defaults_with_type_list.rxml +1 -0
- data/test/fixtures/test/block_content_for.rhtml +2 -0
- data/test/fixtures/test/delete_with_js.rjs +2 -0
- data/test/fixtures/test/dot.directory/render_file_with_ivar.rhtml +1 -0
- data/test/fixtures/test/enum_rjs_test.rjs +6 -0
- data/test/fixtures/test/erb_content_for.rhtml +2 -0
- data/test/fixtures/test/hello_world.rxml +3 -0
- data/test/fixtures/test/hello_world_with_layout_false.rhtml +1 -0
- data/test/fixtures/test/non_erb_block_content_for.rxml +4 -0
- data/test/fixtures/topic.rb +3 -0
- data/test/fixtures/topics.yml +22 -0
- data/test/template/active_record_helper_test.rb +4 -0
- data/test/template/asset_tag_helper_test.rb +7 -2
- data/test/template/date_helper_test.rb +39 -2
- data/test/template/form_helper_test.rb +238 -5
- data/test/template/form_options_helper_test.rb +78 -0
- data/test/template/form_tag_helper_test.rb +11 -0
- data/test/template/java_script_macros_helper_test.rb +51 -6
- data/test/template/javascript_helper_test.rb +7 -153
- data/test/template/number_helper_test.rb +14 -13
- data/test/template/prototype_helper_test.rb +423 -0
- data/test/template/scriptaculous_helper_test.rb +90 -0
- data/test/template/text_helper_test.rb +12 -9
- data/test/template/url_helper_test.rb +31 -15
- metadata +291 -246
- data/lib/action_controller/cgi_ext/multipart_progress.rb +0 -169
- data/lib/action_controller/upload_progress.rb +0 -473
- data/lib/action_controller/vendor/html-scanner/html/node.rb.rej +0 -17
- data/lib/action_view/helpers/upload_progress_helper.rb +0 -433
- data/lib/action_view/vendor/builder.rb +0 -13
- data/lib/action_view/vendor/builder/blankslate.rb +0 -53
- data/lib/action_view/vendor/builder/xmlbase.rb +0 -143
- data/lib/action_view/vendor/builder/xmlevents.rb +0 -63
- data/lib/action_view/vendor/builder/xmlmarkup.rb +0 -308
- data/test/controller/multipart_progress_testx.rb +0 -365
- data/test/controller/upload_progress_testx.rb +0 -89
- data/test/template/upload_progress_helper_testx.rb +0 -136
@@ -15,16 +15,11 @@ module ActionView
|
|
15
15
|
# Options:
|
16
16
|
# * <tt>:multipart</tt> - If set to true, the enctype is set to "multipart/form-data".
|
17
17
|
# * <tt>:method</tt> - The method to use when submitting the form, usually either "get" or "post".
|
18
|
-
def form_tag(url_for_options = {}, options = {}, *parameters_for_url)
|
18
|
+
def form_tag(url_for_options = {}, options = {}, *parameters_for_url, &proc)
|
19
19
|
html_options = { "method" => "post" }.merge(options.stringify_keys)
|
20
|
-
|
21
|
-
if html_options["multipart"]
|
22
|
-
html_options["enctype"] = "multipart/form-data"
|
23
|
-
html_options.delete("multipart")
|
24
|
-
end
|
25
|
-
|
20
|
+
html_options["enctype"] = "multipart/form-data" if html_options.delete("multipart")
|
26
21
|
html_options["action"] = url_for(url_for_options, *parameters_for_url)
|
27
|
-
tag
|
22
|
+
tag :form, html_options, true
|
28
23
|
end
|
29
24
|
|
30
25
|
alias_method :start_form_tag, :form_tag
|
@@ -47,7 +42,7 @@ module ActionView
|
|
47
42
|
# Options:
|
48
43
|
# * <tt>:multiple</tt> - If set to true the selection will allow multiple choices.
|
49
44
|
def select_tag(name, option_tags = nil, options = {})
|
50
|
-
content_tag
|
45
|
+
content_tag :select, option_tags, { "name" => name, "id" => name }.update(options.stringify_keys)
|
51
46
|
end
|
52
47
|
|
53
48
|
# Creates a standard text field.
|
@@ -59,7 +54,7 @@ module ActionView
|
|
59
54
|
#
|
60
55
|
# A hash of standard HTML options for the tag.
|
61
56
|
def text_field_tag(name, value = nil, options = {})
|
62
|
-
tag
|
57
|
+
tag :input, { "type" => "text", "name" => name, "id" => name, "value" => value }.update(options.stringify_keys)
|
63
58
|
end
|
64
59
|
|
65
60
|
# Creates a hidden field.
|
@@ -97,39 +92,46 @@ module ActionView
|
|
97
92
|
# # Outputs <textarea name="body" id="body" cols="25" rows="10"></textarea>
|
98
93
|
# <%= text_area_tag "body", nil, :size => "25x10" %>
|
99
94
|
def text_area_tag(name, content = nil, options = {})
|
100
|
-
options
|
101
|
-
|
102
|
-
|
103
|
-
options.
|
95
|
+
options.stringify_keys!
|
96
|
+
|
97
|
+
if size = options.delete("size")
|
98
|
+
options["cols"], options["rows"] = size.split("x")
|
104
99
|
end
|
105
100
|
|
106
|
-
content_tag
|
101
|
+
content_tag :textarea, content, { "name" => name, "id" => name }.update(options.stringify_keys)
|
107
102
|
end
|
108
103
|
|
109
104
|
# Creates a check box.
|
110
105
|
def check_box_tag(name, value = "1", checked = false, options = {})
|
111
106
|
html_options = { "type" => "checkbox", "name" => name, "id" => name, "value" => value }.update(options.stringify_keys)
|
112
107
|
html_options["checked"] = "checked" if checked
|
113
|
-
tag
|
108
|
+
tag :input, html_options
|
114
109
|
end
|
115
110
|
|
116
111
|
# Creates a radio button.
|
117
112
|
def radio_button_tag(name, value, checked = false, options = {})
|
118
113
|
html_options = { "type" => "radio", "name" => name, "id" => name, "value" => value }.update(options.stringify_keys)
|
119
114
|
html_options["checked"] = "checked" if checked
|
120
|
-
tag
|
115
|
+
tag :input, html_options
|
121
116
|
end
|
122
117
|
|
123
|
-
# Creates a submit button with the text <tt>value</tt> as the caption.
|
118
|
+
# Creates a submit button with the text <tt>value</tt> as the caption. If options contains a pair with the key of "disable_with",
|
119
|
+
# then the value will be used to rename a disabled version of the submit button.
|
124
120
|
def submit_tag(value = "Save changes", options = {})
|
125
|
-
|
121
|
+
options.stringify_keys!
|
122
|
+
|
123
|
+
if disable_with = options.delete("disable_with")
|
124
|
+
options["onclick"] = "this.disabled=true;this.value='#{disable_with}';this.form.submit();#{options["onclick"]}"
|
125
|
+
end
|
126
|
+
|
127
|
+
tag :input, { "type" => "submit", "name" => "commit", "value" => value }.update(options.stringify_keys)
|
126
128
|
end
|
127
129
|
|
128
130
|
# Displays an image which when clicked will submit the form.
|
129
131
|
#
|
130
132
|
# <tt>source</tt> is passed to AssetTagHelper#image_path
|
131
133
|
def image_submit_tag(source, options = {})
|
132
|
-
tag
|
134
|
+
tag :input, { "type" => "image", "src" => image_path(source) }.update(options.stringify_keys)
|
133
135
|
end
|
134
136
|
end
|
135
137
|
end
|
@@ -12,11 +12,11 @@ module ActionView
|
|
12
12
|
#
|
13
13
|
# A form is automatically created and displayed when the user clicks the element,
|
14
14
|
# something like this:
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
15
|
+
# <form id="myElement-in-place-edit-form" target="specified url">
|
16
|
+
# <input name="value" text="The content of myElement"/>
|
17
|
+
# <input type="submit" value="ok"/>
|
18
|
+
# <a onclick="javascript to cancel the editing">cancel</a>
|
19
|
+
# </form>
|
20
20
|
#
|
21
21
|
# The form is serialized and sent to the server using an AJAX call, the action on
|
22
22
|
# the server should process the value and return the updated value in the body of
|
@@ -29,12 +29,17 @@ module ActionView
|
|
29
29
|
#
|
30
30
|
# Addtional +options+ are:
|
31
31
|
# <tt>:rows</tt>:: Number of rows (more than 1 will use a TEXTAREA)
|
32
|
+
# <tt>:cols</tt>:: Number of characters the text input should span (works for both INPUT and TEXTAREA)
|
33
|
+
# <tt>:size</tt>:: Synonym for :cols when using a single line text input.
|
32
34
|
# <tt>:cancel_text</tt>:: The text on the cancel link. (default: "cancel")
|
33
35
|
# <tt>:save_text</tt>:: The text on the save link. (default: "ok")
|
36
|
+
# <tt>:loading_text</tt>:: The text to display when submitting to the server (default: "Saving...")
|
34
37
|
# <tt>:external_control</tt>:: The id of an external control used to enter edit mode.
|
38
|
+
# <tt>:load_text_url</tt>:: URL where initial value of editor (content) is retrieved.
|
35
39
|
# <tt>:options</tt>:: Pass through options to the AJAX call (see prototype's Ajax.Updater)
|
36
40
|
# <tt>:with</tt>:: JavaScript snippet that should return what is to be sent
|
37
41
|
# in the AJAX call, +form+ is an implicit parameter
|
42
|
+
# <tt>:script</tt>:: Instructs the in-place editor to evaluate the remote JavaScript response (default: false)
|
38
43
|
def in_place_editor(field_id, options = {})
|
39
44
|
function = "new Ajax.InPlaceEditor("
|
40
45
|
function << "'#{field_id}', "
|
@@ -43,9 +48,14 @@ module ActionView
|
|
43
48
|
js_options = {}
|
44
49
|
js_options['cancelText'] = %('#{options[:cancel_text]}') if options[:cancel_text]
|
45
50
|
js_options['okText'] = %('#{options[:save_text]}') if options[:save_text]
|
51
|
+
js_options['loadingText'] = %('#{options[:loading_text]}') if options[:loading_text]
|
46
52
|
js_options['rows'] = options[:rows] if options[:rows]
|
47
|
-
js_options['
|
53
|
+
js_options['cols'] = options[:cols] if options[:cols]
|
54
|
+
js_options['size'] = options[:size] if options[:size]
|
55
|
+
js_options['externalControl'] = "'#{options[:external_control]}'" if options[:external_control]
|
56
|
+
js_options['loadTextURL'] = "'#{url_for(options[:load_text_url])}'" if options[:load_text_url]
|
48
57
|
js_options['ajaxOptions'] = options[:options] if options[:options]
|
58
|
+
js_options['evalScripts'] = options[:script] if options[:script]
|
49
59
|
js_options['callback'] = "function(form) { return #{options[:with]} }" if options[:with]
|
50
60
|
function << (', ' + options_for_javascript(js_options)) unless js_options.empty?
|
51
61
|
|
@@ -72,8 +82,12 @@ module ActionView
|
|
72
82
|
# or nothing if no entries should be displayed for autocompletion.
|
73
83
|
#
|
74
84
|
# You'll probably want to turn the browser's built-in autocompletion off,
|
75
|
-
#
|
85
|
+
# so be sure to include a autocomplete="off" attribute with your text
|
76
86
|
# input field.
|
87
|
+
#
|
88
|
+
# The autocompleter object is assigned to a Javascript variable named <tt>field_id</tt>_auto_completer.
|
89
|
+
# This object is useful if you for example want to trigger the auto-complete suggestions through
|
90
|
+
# other means than user input (for that specific case, call the <tt>activate</tt> method on that object).
|
77
91
|
#
|
78
92
|
# Required +options+ are:
|
79
93
|
# <tt>:url</tt>:: URL to call for autocompletion results
|
@@ -105,8 +119,11 @@ module ActionView
|
|
105
119
|
# innerHTML is replaced.
|
106
120
|
# <tt>:on_show</tt>:: Like on_hide, only now the expression is called
|
107
121
|
# then the div is shown.
|
122
|
+
# <tt>:select</tt>:: Pick the class of the element from which the value for
|
123
|
+
# insertion should be extracted. If this is not specified,
|
124
|
+
# the entire element is used.
|
108
125
|
def auto_complete_field(field_id, options = {})
|
109
|
-
function = "new Ajax.Autocompleter("
|
126
|
+
function = "var #{field_id}_auto_completer = new Ajax.Autocompleter("
|
110
127
|
function << "'#{field_id}', "
|
111
128
|
function << "'" + (options[:update] || "#{field_id}_auto_complete") + "', "
|
112
129
|
function << "'#{url_for(options[:url])}'"
|
@@ -115,9 +132,12 @@ module ActionView
|
|
115
132
|
js_options[:tokens] = array_or_string_for_javascript(options[:tokens]) if options[:tokens]
|
116
133
|
js_options[:callback] = "function(element, value) { return #{options[:with]} }" if options[:with]
|
117
134
|
js_options[:indicator] = "'#{options[:indicator]}'" if options[:indicator]
|
118
|
-
|
135
|
+
js_options[:select] = "'#{options[:select]}'" if options[:select]
|
136
|
+
|
137
|
+
{ :on_show => :onShow, :on_hide => :onHide, :min_chars => :minChars }.each do |k,v|
|
119
138
|
js_options[v] = options[k] if options[k]
|
120
139
|
end
|
140
|
+
|
121
141
|
function << (', ' + options_for_javascript(js_options) + ')')
|
122
142
|
|
123
143
|
javascript_tag(function)
|
@@ -2,295 +2,80 @@ require File.dirname(__FILE__) + '/tag_helper'
|
|
2
2
|
|
3
3
|
module ActionView
|
4
4
|
module Helpers
|
5
|
-
# Provides
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
5
|
+
# Provides functionality for working with JavaScript in your views.
|
6
|
+
#
|
7
|
+
# == Ajax, controls and visual effects
|
8
|
+
#
|
9
|
+
# * For information on using Ajax, see
|
10
|
+
# ActionView::Helpers::PrototypeHelper.
|
11
|
+
# * For information on using controls and visual effects, see
|
12
|
+
# ActionView::Helpers::ScriptaculousHelper.
|
9
13
|
#
|
10
|
-
#
|
11
|
-
# script.aculo.us (which both come with Rails) on your pages. Choose one of these options:
|
14
|
+
# == Including the JavaScript libraries into your pages
|
12
15
|
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
# which means you are able to use all basic AJAX functionality. For the script.aculo.us-based JavaScript helpers,
|
19
|
-
# like visual effects, autocompletion, drag and drop and so on, you should use the method described above.
|
20
|
-
# * Use <tt><%= define_javascript_functions %></tt>: this will copy all the JavaScript support functions within a single
|
21
|
-
# script block.
|
16
|
+
# Rails includes the Prototype JavaScript framework and the Scriptaculous
|
17
|
+
# JavaScript controls and visual effects library. If you wish to use
|
18
|
+
# these libraries and their helpers (ActionView::Helpers::PrototypeHelper
|
19
|
+
# and ActionView::Helpers::ScriptaculousHelper), you must do one of the
|
20
|
+
# following:
|
22
21
|
#
|
23
|
-
#
|
22
|
+
# * Use <tt><%= javascript_include_tag :defaults %></tt> in the HEAD
|
23
|
+
# section of your page (recommended): This function will return
|
24
|
+
# references to the JavaScript files created by the +rails+ command in
|
25
|
+
# your <tt>public/javascripts</tt> directory. Using it is recommended as
|
26
|
+
# the browser can then cache the libraries instead of fetching all the
|
27
|
+
# functions anew on every request.
|
28
|
+
# * Use <tt><%= javascript_include_tag 'prototype' %></tt>: As above, but
|
29
|
+
# will only include the Prototype core library, which means you are able
|
30
|
+
# to use all basic AJAX functionality. For the Scriptaculous-based
|
31
|
+
# JavaScript helpers, like visual effects, autocompletion, drag and drop
|
32
|
+
# and so on, you should use the method described above.
|
33
|
+
# * Use <tt><%= define_javascript_functions %></tt>: this will copy all the
|
34
|
+
# JavaScript support functions within a single script block. Not
|
35
|
+
# recommended.
|
24
36
|
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
module JavaScriptHelper
|
28
|
-
unless const_defined? :
|
29
|
-
CALLBACKS =
|
30
|
-
[:uninitialized, :loading, :loaded, :interactive, :complete, :failure, :success].push((100..599).to_a).flatten
|
31
|
-
AJAX_OPTIONS = [ :before, :after, :condition, :url, :asynchronous, :method,
|
32
|
-
:insertion, :position, :form, :with, :update, :script ].concat(CALLBACKS)
|
37
|
+
# For documentation on +javascript_include_tag+ see
|
38
|
+
# ActionView::Helpers::AssetTagHelper.
|
39
|
+
module JavaScriptHelper
|
40
|
+
unless const_defined? :JAVASCRIPT_PATH
|
33
41
|
JAVASCRIPT_PATH = File.join(File.dirname(__FILE__), 'javascripts')
|
34
42
|
end
|
35
43
|
|
36
|
-
# Returns a link that'll trigger a
|
44
|
+
# Returns a link that'll trigger a JavaScript +function+ using the
|
37
45
|
# onclick handler and return false after the fact.
|
38
46
|
#
|
39
47
|
# Examples:
|
40
48
|
# link_to_function "Greeting", "alert('Hello world!')"
|
41
49
|
# link_to_function(image_tag("delete"), "if confirm('Really?'){ do_delete(); }")
|
42
50
|
def link_to_function(name, function, html_options = {})
|
51
|
+
html_options.symbolize_keys!
|
43
52
|
content_tag(
|
44
53
|
"a", name,
|
45
|
-
|
54
|
+
html_options.merge({
|
55
|
+
:href => html_options[:href] || "#",
|
56
|
+
:onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function}; return false;"
|
57
|
+
})
|
46
58
|
)
|
47
59
|
end
|
48
|
-
|
49
|
-
# Returns a link to a remote action defined by <tt>options[:url]</tt>
|
50
|
-
# (using the url_for format) that's called in the background using
|
51
|
-
# XMLHttpRequest. The result of that request can then be inserted into a
|
52
|
-
# DOM object whose id can be specified with <tt>options[:update]</tt>.
|
53
|
-
# Usually, the result would be a partial prepared by the controller with
|
54
|
-
# either render_partial or render_partial_collection.
|
55
|
-
#
|
56
|
-
# Examples:
|
57
|
-
# link_to_remote "Delete this post", :update => "posts", :url => { :action => "destroy", :id => post.id }
|
58
|
-
# link_to_remote(image_tag("refresh"), :update => "emails", :url => { :action => "list_emails" })
|
59
|
-
#
|
60
|
-
# You can also specify a hash for <tt>options[:update]</tt> to allow for
|
61
|
-
# easy redirection of output to an other DOM element if a server-side error occurs:
|
62
|
-
#
|
63
|
-
# Example:
|
64
|
-
# link_to_remote "Delete this post",
|
65
|
-
# :url => { :action => "destroy", :id => post.id },
|
66
|
-
# :update => { :success => "posts", :failure => "error" }
|
67
|
-
#
|
68
|
-
# Optionally, you can use the <tt>options[:position]</tt> parameter to influence
|
69
|
-
# how the target DOM element is updated. It must be one of
|
70
|
-
# <tt>:before</tt>, <tt>:top</tt>, <tt>:bottom</tt>, or <tt>:after</tt>.
|
71
|
-
#
|
72
|
-
# By default, these remote requests are processed asynchronous during
|
73
|
-
# which various JavaScript callbacks can be triggered (for progress indicators and
|
74
|
-
# the likes). All callbacks get access to the <tt>request</tt> object,
|
75
|
-
# which holds the underlying XMLHttpRequest.
|
76
|
-
#
|
77
|
-
# To access the server response, use <tt>request.responseText</tt>, to
|
78
|
-
# find out the HTTP status, use <tt>request.status</tt>.
|
79
|
-
#
|
80
|
-
# Example:
|
81
|
-
# link_to_remote word,
|
82
|
-
# :url => { :action => "undo", :n => word_counter },
|
83
|
-
# :complete => "undoRequestCompleted(request)"
|
84
|
-
#
|
85
|
-
# The callbacks that may be specified are (in order):
|
86
|
-
#
|
87
|
-
# <tt>:loading</tt>:: Called when the remote document is being
|
88
|
-
# loaded with data by the browser.
|
89
|
-
# <tt>:loaded</tt>:: Called when the browser has finished loading
|
90
|
-
# the remote document.
|
91
|
-
# <tt>:interactive</tt>:: Called when the user can interact with the
|
92
|
-
# remote document, even though it has not
|
93
|
-
# finished loading.
|
94
|
-
# <tt>:success</tt>:: Called when the XMLHttpRequest is completed,
|
95
|
-
# and the HTTP status code is in the 2XX range.
|
96
|
-
# <tt>:failure</tt>:: Called when the XMLHttpRequest is completed,
|
97
|
-
# and the HTTP status code is not in the 2XX
|
98
|
-
# range.
|
99
|
-
# <tt>:complete</tt>:: Called when the XMLHttpRequest is complete
|
100
|
-
# (fires after success/failure if they are present).,
|
101
|
-
#
|
102
|
-
# You can further refine <tt>:success</tt> and <tt>:failure</tt> by adding additional
|
103
|
-
# callbacks for specific status codes:
|
104
|
-
#
|
105
|
-
# Example:
|
106
|
-
# link_to_remote word,
|
107
|
-
# :url => { :action => "action" },
|
108
|
-
# 404 => "alert('Not found...? Wrong URL...?')",
|
109
|
-
# :failure => "alert('HTTP Error ' + request.status + '!')"
|
110
|
-
#
|
111
|
-
# A status code callback overrides the success/failure handlers if present.
|
112
|
-
#
|
113
|
-
# If you for some reason or another need synchronous processing (that'll
|
114
|
-
# block the browser while the request is happening), you can specify
|
115
|
-
# <tt>options[:type] = :synchronous</tt>.
|
116
|
-
#
|
117
|
-
# You can customize further browser side call logic by passing
|
118
|
-
# in JavaScript code snippets via some optional parameters. In
|
119
|
-
# their order of use these are:
|
120
|
-
#
|
121
|
-
# <tt>:confirm</tt>:: Adds confirmation dialog.
|
122
|
-
# <tt>:condition</tt>:: Perform remote request conditionally
|
123
|
-
# by this expression. Use this to
|
124
|
-
# describe browser-side conditions when
|
125
|
-
# request should not be initiated.
|
126
|
-
# <tt>:before</tt>:: Called before request is initiated.
|
127
|
-
# <tt>:after</tt>:: Called immediately after request was
|
128
|
-
# initiated and before <tt>:loading</tt>.
|
129
|
-
# <tt>:submit</tt>:: Specifies the DOM element ID that's used
|
130
|
-
# as the parent of the form elements. By
|
131
|
-
# default this is the current form, but
|
132
|
-
# it could just as well be the ID of a
|
133
|
-
# table row or any other DOM element.
|
134
|
-
def link_to_remote(name, options = {}, html_options = {})
|
135
|
-
link_to_function(name, remote_function(options), html_options)
|
136
|
-
end
|
137
|
-
|
138
|
-
# Periodically calls the specified url (<tt>options[:url]</tt>) every <tt>options[:frequency]</tt> seconds (default is 10).
|
139
|
-
# Usually used to update a specified div (<tt>options[:update]</tt>) with the results of the remote call.
|
140
|
-
# The options for specifying the target with :url and defining callbacks is the same as link_to_remote.
|
141
|
-
def periodically_call_remote(options = {})
|
142
|
-
frequency = options[:frequency] || 10 # every ten seconds by default
|
143
|
-
code = "new PeriodicalExecuter(function() {#{remote_function(options)}}, #{frequency})"
|
144
|
-
javascript_tag(code)
|
145
|
-
end
|
146
|
-
|
147
|
-
# Returns a form tag that will submit using XMLHttpRequest in the background instead of the regular
|
148
|
-
# reloading POST arrangement. Even though it's using JavaScript to serialize the form elements, the form submission
|
149
|
-
# will work just like a regular submission as viewed by the receiving side (all elements available in @params).
|
150
|
-
# The options for specifying the target with :url and defining callbacks is the same as link_to_remote.
|
151
|
-
#
|
152
|
-
# A "fall-through" target for browsers that doesn't do JavaScript can be specified with the :action/:method options on :html
|
153
|
-
#
|
154
|
-
# form_remote_tag :html => { :action => url_for(:controller => "some", :action => "place") }
|
155
|
-
# The Hash passed to the :html key is equivalent to the options (2nd) argument in the FormTagHelper.form_tag method.
|
156
|
-
#
|
157
|
-
# By default the fall-through action is the same as the one specified in the :url (and the default method is :post).
|
158
|
-
def form_remote_tag(options = {})
|
159
|
-
options[:form] = true
|
160
|
-
|
161
|
-
options[:html] ||= {}
|
162
|
-
options[:html][:onsubmit] = "#{remote_function(options)}; return false;"
|
163
|
-
options[:html][:action] = options[:html][:action] || url_for(options[:url])
|
164
|
-
options[:html][:method] = options[:html][:method] || "post"
|
165
|
-
|
166
|
-
tag("form", options[:html], true)
|
167
|
-
end
|
168
60
|
|
169
|
-
# Returns a
|
170
|
-
#
|
171
|
-
def submit_to_remote(name, value, options = {})
|
172
|
-
options[:with] ||= 'Form.serialize(this.form)'
|
173
|
-
|
174
|
-
options[:html] ||= {}
|
175
|
-
options[:html][:type] = 'button'
|
176
|
-
options[:html][:onclick] = "#{remote_function(options)}; return false;"
|
177
|
-
options[:html][:name] = name
|
178
|
-
options[:html][:value] = value
|
179
|
-
|
180
|
-
tag("input", options[:html], false)
|
181
|
-
end
|
182
|
-
|
183
|
-
# Returns a Javascript function (or expression) that'll update a DOM element according to the options passed.
|
184
|
-
#
|
185
|
-
# * <tt>:content</tt>: The content to use for updating. Can be left out if using block, see example.
|
186
|
-
# * <tt>:action</tt>: Valid options are :update (assumed by default), :empty, :remove
|
187
|
-
# * <tt>:position</tt> If the :action is :update, you can optionally specify one of the following positions: :before, :top, :bottom, :after.
|
61
|
+
# Returns a link that'll trigger a JavaScript +function+ using the
|
62
|
+
# onclick handler.
|
188
63
|
#
|
189
64
|
# Examples:
|
190
|
-
#
|
191
|
-
#
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
#
|
199
|
-
# This method can also be used in combination with remote method call where the result is evaluated afterwards to cause
|
200
|
-
# multiple updates on a page. Example:
|
201
|
-
#
|
202
|
-
# # Calling view
|
203
|
-
# <%= form_remote_tag :url => { :action => "buy" }, :complete => evaluate_remote_response %>
|
204
|
-
# all the inputs here...
|
205
|
-
#
|
206
|
-
# # Controller action
|
207
|
-
# def buy
|
208
|
-
# @product = Product.find(1)
|
209
|
-
# end
|
210
|
-
#
|
211
|
-
# # Returning view
|
212
|
-
# <%= update_element_function(
|
213
|
-
# "cart", :action => :update, :position => :bottom,
|
214
|
-
# :content => "<p>New Product: #{@product.name}</p>")) %>
|
215
|
-
# <% update_element_function("status", :binding => binding) do %>
|
216
|
-
# You've bought a new product!
|
217
|
-
# <% end %>
|
218
|
-
#
|
219
|
-
# Notice how the second call doesn't need to be in an ERb output block since it uses a block and passes in the binding
|
220
|
-
# to render directly. This trick will however only work in ERb (not Builder or other template forms).
|
221
|
-
def update_element_function(element_id, options = {}, &block)
|
222
|
-
|
223
|
-
content = escape_javascript(options[:content] || '')
|
224
|
-
content = escape_javascript(capture(&block)) if block
|
225
|
-
|
226
|
-
javascript_function = case (options[:action] || :update)
|
227
|
-
when :update
|
228
|
-
if options[:position]
|
229
|
-
"new Insertion.#{options[:position].to_s.camelize}('#{element_id}','#{content}')"
|
230
|
-
else
|
231
|
-
"$('#{element_id}').innerHTML = '#{content}'"
|
232
|
-
end
|
233
|
-
|
234
|
-
when :empty
|
235
|
-
"$('#{element_id}').innerHTML = ''"
|
236
|
-
|
237
|
-
when :remove
|
238
|
-
"Element.remove('#{element_id}')"
|
239
|
-
|
240
|
-
else
|
241
|
-
raise ArgumentError, "Invalid action, choose one of :update, :remove, :empty"
|
242
|
-
end
|
243
|
-
|
244
|
-
javascript_function << ";\n"
|
245
|
-
options[:binding] ? concat(javascript_function, options[:binding]) : javascript_function
|
246
|
-
end
|
247
|
-
|
248
|
-
# Returns 'eval(request.responseText)' which is the Javascript function that form_remote_tag can call in :complete to
|
249
|
-
# evaluate a multiple update return document using update_element_function calls.
|
250
|
-
def evaluate_remote_response
|
251
|
-
"eval(request.responseText)"
|
252
|
-
end
|
253
|
-
|
254
|
-
# Returns the javascript needed for a remote function.
|
255
|
-
# Takes the same arguments as link_to_remote.
|
256
|
-
#
|
257
|
-
# Example:
|
258
|
-
# <select id="options" onchange="<%= remote_function(:update => "options", :url => { :action => :update_options }) %>">
|
259
|
-
# <option value="0">Hello</option>
|
260
|
-
# <option value="1">World</option>
|
261
|
-
# </select>
|
262
|
-
def remote_function(options)
|
263
|
-
javascript_options = options_for_ajax(options)
|
264
|
-
|
265
|
-
update = ''
|
266
|
-
if options[:update] and options[:update].is_a?Hash
|
267
|
-
update = []
|
268
|
-
update << "success:'#{options[:update][:success]}'" if options[:update][:success]
|
269
|
-
update << "failure:'#{options[:update][:failure]}'" if options[:update][:failure]
|
270
|
-
update = '{' + update.join(',') + '}'
|
271
|
-
elsif options[:update]
|
272
|
-
update << "'#{options[:update]}'"
|
273
|
-
end
|
274
|
-
|
275
|
-
function = update.empty? ?
|
276
|
-
"new Ajax.Request(" :
|
277
|
-
"new Ajax.Updater(#{update}, "
|
278
|
-
|
279
|
-
function << "'#{url_for(options[:url])}'"
|
280
|
-
function << ", #{javascript_options})"
|
281
|
-
|
282
|
-
function = "#{options[:before]}; #{function}" if options[:before]
|
283
|
-
function = "#{function}; #{options[:after]}" if options[:after]
|
284
|
-
function = "if (#{options[:condition]}) { #{function}; }" if options[:condition]
|
285
|
-
function = "if (confirm('#{escape_javascript(options[:confirm])}')) { #{function}; }" if options[:confirm]
|
286
|
-
|
287
|
-
return function
|
65
|
+
# 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 = {})
|
68
|
+
html_options.symbolize_keys!
|
69
|
+
tag(:input, html_options.merge({
|
70
|
+
:type => "button", :value => name,
|
71
|
+
:onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};"
|
72
|
+
}))
|
288
73
|
end
|
289
74
|
|
290
75
|
# Includes the Action Pack JavaScript libraries inside a single <script>
|
291
76
|
# tag. The function first includes prototype.js and then its core extensions,
|
292
77
|
# (determined by filenames starting with "prototype").
|
293
|
-
# Afterwards, any additional scripts will be included in
|
78
|
+
# Afterwards, any additional scripts will be included in undefined order.
|
294
79
|
#
|
295
80
|
# Note: The recommended approach is to copy the contents of
|
296
81
|
# lib/action_view/helpers/javascripts/ into your application's
|
@@ -312,142 +97,6 @@ module ActionView
|
|
312
97
|
javascript << '</script>'
|
313
98
|
end
|
314
99
|
|
315
|
-
# Observes the field with the DOM ID specified by +field_id+ and makes
|
316
|
-
# an AJAX call when its contents have changed.
|
317
|
-
#
|
318
|
-
# Required +options+ are:
|
319
|
-
# <tt>:url</tt>:: +url_for+-style options for the action to call
|
320
|
-
# when the field has changed.
|
321
|
-
#
|
322
|
-
# Additional options are:
|
323
|
-
# <tt>:frequency</tt>:: The frequency (in seconds) at which changes to
|
324
|
-
# this field will be detected. Not setting this
|
325
|
-
# option at all or to a value equal to or less than
|
326
|
-
# zero will use event based observation instead of
|
327
|
-
# time based observation.
|
328
|
-
# <tt>:update</tt>:: Specifies the DOM ID of the element whose
|
329
|
-
# innerHTML should be updated with the
|
330
|
-
# XMLHttpRequest response text.
|
331
|
-
# <tt>:with</tt>:: A JavaScript expression specifying the
|
332
|
-
# parameters for the XMLHttpRequest. This defaults
|
333
|
-
# to 'value', which in the evaluated context
|
334
|
-
# refers to the new field value.
|
335
|
-
#
|
336
|
-
# Additionally, you may specify any of the options documented in
|
337
|
-
# link_to_remote.
|
338
|
-
def observe_field(field_id, options = {})
|
339
|
-
if options[:frequency] and options[:frequency] > 0
|
340
|
-
build_observer('Form.Element.Observer', field_id, options)
|
341
|
-
else
|
342
|
-
build_observer('Form.Element.EventObserver', field_id, options)
|
343
|
-
end
|
344
|
-
end
|
345
|
-
|
346
|
-
# Like +observe_field+, but operates on an entire form identified by the
|
347
|
-
# DOM ID +form_id+. +options+ are the same as +observe_field+, except
|
348
|
-
# the default value of the <tt>:with</tt> option evaluates to the
|
349
|
-
# serialized (request string) value of the form.
|
350
|
-
def observe_form(form_id, options = {})
|
351
|
-
if options[:frequency]
|
352
|
-
build_observer('Form.Observer', form_id, options)
|
353
|
-
else
|
354
|
-
build_observer('Form.EventObserver', form_id, options)
|
355
|
-
end
|
356
|
-
end
|
357
|
-
|
358
|
-
# Returns a JavaScript snippet to be used on the AJAX callbacks for starting
|
359
|
-
# visual effects.
|
360
|
-
#
|
361
|
-
# This method requires the inclusion of the script.aculo.us JavaScript library.
|
362
|
-
#
|
363
|
-
# Example:
|
364
|
-
# <%= link_to_remote "Reload", :update => "posts",
|
365
|
-
# :url => { :action => "reload" },
|
366
|
-
# :complete => visual_effect(:highlight, "posts", :duration => 0.5 )
|
367
|
-
#
|
368
|
-
# If no element_id is given, it assumes "element" which should be a local
|
369
|
-
# variable in the generated JavaScript execution context. This can be used
|
370
|
-
# for example with drop_receiving_element:
|
371
|
-
#
|
372
|
-
# <%= drop_receving_element (...), :loading => visual_effect(:fade) %>
|
373
|
-
#
|
374
|
-
# This would fade the element that was dropped on the drop receiving element.
|
375
|
-
#
|
376
|
-
# You can change the behaviour with various options, see
|
377
|
-
# http://script.aculo.us for more documentation.
|
378
|
-
def visual_effect(name, element_id = false, js_options = {})
|
379
|
-
element = element_id ? "'#{element_id}'" : "element"
|
380
|
-
js_options[:queue] = "'#{js_options[:queue]}'" if js_options[:queue]
|
381
|
-
"new Effect.#{name.to_s.camelize}(#{element},#{options_for_javascript(js_options)});"
|
382
|
-
end
|
383
|
-
|
384
|
-
# Makes the element with the DOM ID specified by +element_id+ sortable
|
385
|
-
# by drag-and-drop and make an AJAX call whenever the sort order has
|
386
|
-
# changed. By default, the action called gets the serialized sortable
|
387
|
-
# element as parameters.
|
388
|
-
#
|
389
|
-
# This method requires the inclusion of the script.aculo.us JavaScript library.
|
390
|
-
#
|
391
|
-
# Example:
|
392
|
-
# <%= sortable_element("my_list", :url => { :action => "order" }) %>
|
393
|
-
#
|
394
|
-
# In the example, the action gets a "my_list" array parameter
|
395
|
-
# containing the values of the ids of elements the sortable consists
|
396
|
-
# of, in the current order.
|
397
|
-
#
|
398
|
-
# You can change the behaviour with various options, see
|
399
|
-
# http://script.aculo.us for more documentation.
|
400
|
-
def sortable_element(element_id, options = {})
|
401
|
-
options[:with] ||= "Sortable.serialize('#{element_id}')"
|
402
|
-
options[:onUpdate] ||= "function(){" + remote_function(options) + "}"
|
403
|
-
options.delete_if { |key, value| AJAX_OPTIONS.include?(key) }
|
404
|
-
|
405
|
-
[:tag, :overlap, :constraint, :handle].each do |option|
|
406
|
-
options[option] = "'#{options[option]}'" if options[option]
|
407
|
-
end
|
408
|
-
|
409
|
-
options[:containment] = array_or_string_for_javascript(options[:containment]) if options[:containment]
|
410
|
-
options[:only] = array_or_string_for_javascript(options[:only]) if options[:only]
|
411
|
-
|
412
|
-
javascript_tag("Sortable.create('#{element_id}', #{options_for_javascript(options)})")
|
413
|
-
end
|
414
|
-
|
415
|
-
# Makes the element with the DOM ID specified by +element_id+ draggable.
|
416
|
-
#
|
417
|
-
# This method requires the inclusion of the script.aculo.us JavaScript library.
|
418
|
-
#
|
419
|
-
# Example:
|
420
|
-
# <%= draggable_element("my_image", :revert => true)
|
421
|
-
#
|
422
|
-
# You can change the behaviour with various options, see
|
423
|
-
# http://script.aculo.us for more documentation.
|
424
|
-
def draggable_element(element_id, options = {})
|
425
|
-
javascript_tag("new Draggable('#{element_id}', #{options_for_javascript(options)})")
|
426
|
-
end
|
427
|
-
|
428
|
-
# Makes the element with the DOM ID specified by +element_id+ receive
|
429
|
-
# dropped draggable elements (created by draggable_element).
|
430
|
-
# and make an AJAX call By default, the action called gets the DOM ID of the
|
431
|
-
# element as parameter.
|
432
|
-
#
|
433
|
-
# This method requires the inclusion of the script.aculo.us JavaScript library.
|
434
|
-
#
|
435
|
-
# Example:
|
436
|
-
# <%= drop_receiving_element("my_cart", :url => { :controller => "cart", :action => "add" }) %>
|
437
|
-
#
|
438
|
-
# You can change the behaviour with various options, see
|
439
|
-
# http://script.aculo.us for more documentation.
|
440
|
-
def drop_receiving_element(element_id, options = {})
|
441
|
-
options[:with] ||= "'id=' + encodeURIComponent(element.id)"
|
442
|
-
options[:onDrop] ||= "function(element){" + remote_function(options) + "}"
|
443
|
-
options.delete_if { |key, value| AJAX_OPTIONS.include?(key) }
|
444
|
-
|
445
|
-
options[:accept] = array_or_string_for_javascript(options[:accept]) if options[:accept]
|
446
|
-
options[:hoverclass] = "'#{options[:hoverclass]}'" if options[:hoverclass]
|
447
|
-
|
448
|
-
javascript_tag("Droppables.add('#{element_id}', #{options_for_javascript(options)})")
|
449
|
-
end
|
450
|
-
|
451
100
|
# Escape carrier returns and single and double quotes for JavaScript segments.
|
452
101
|
def escape_javascript(javascript)
|
453
102
|
(javascript || '').gsub(/\r\n|\n|\r/, "\\n").gsub(/["']/) { |m| "\\#{m}" }
|
@@ -463,7 +112,7 @@ module ActionView
|
|
463
112
|
"\n//#{cdata_section("\n#{content}\n//")}\n"
|
464
113
|
end
|
465
114
|
|
466
|
-
|
115
|
+
protected
|
467
116
|
def options_for_javascript(options)
|
468
117
|
'{' + options.map {|k, v| "#{k}:#{v}"}.sort.join(', ') + '}'
|
469
118
|
end
|
@@ -476,51 +125,6 @@ module ActionView
|
|
476
125
|
end
|
477
126
|
js_option
|
478
127
|
end
|
479
|
-
|
480
|
-
def options_for_ajax(options)
|
481
|
-
js_options = build_callbacks(options)
|
482
|
-
|
483
|
-
js_options['asynchronous'] = options[:type] != :synchronous
|
484
|
-
js_options['method'] = method_option_to_s(options[:method]) if options[:method]
|
485
|
-
js_options['insertion'] = "Insertion.#{options[:position].to_s.camelize}" if options[:position]
|
486
|
-
js_options['evalScripts'] = options[:script].nil? || options[:script]
|
487
|
-
|
488
|
-
if options[:form]
|
489
|
-
js_options['parameters'] = 'Form.serialize(this)'
|
490
|
-
elsif options[:submit]
|
491
|
-
js_options['parameters'] = "Form.serialize(document.getElementById('#{options[:submit]}'))"
|
492
|
-
elsif options[:with]
|
493
|
-
js_options['parameters'] = options[:with]
|
494
|
-
end
|
495
|
-
|
496
|
-
options_for_javascript(js_options)
|
497
|
-
end
|
498
|
-
|
499
|
-
def method_option_to_s(method)
|
500
|
-
(method.is_a?(String) and !method.index("'").nil?) ? method : "'#{method}'"
|
501
|
-
end
|
502
|
-
|
503
|
-
def build_observer(klass, name, options = {})
|
504
|
-
options[:with] ||= 'value' if options[:update]
|
505
|
-
callback = remote_function(options)
|
506
|
-
javascript = "new #{klass}('#{name}', "
|
507
|
-
javascript << "#{options[:frequency]}, " if options[:frequency]
|
508
|
-
javascript << "function(element, value) {"
|
509
|
-
javascript << "#{callback}})"
|
510
|
-
javascript_tag(javascript)
|
511
|
-
end
|
512
|
-
|
513
|
-
def build_callbacks(options)
|
514
|
-
callbacks = {}
|
515
|
-
options.each do |callback, code|
|
516
|
-
if CALLBACKS.include?(callback)
|
517
|
-
name = 'on' + callback.to_s.capitalize
|
518
|
-
callbacks[name] = "function(request){#{code}}"
|
519
|
-
end
|
520
|
-
end
|
521
|
-
callbacks
|
522
|
-
end
|
523
|
-
|
524
128
|
end
|
525
129
|
|
526
130
|
JavascriptHelper = JavaScriptHelper unless const_defined? :JavascriptHelper
|