提交 351a224d 编写于 作者: S Sam Stephenson

Add support for converting blocks into function arguments in...

Add support for converting blocks into function arguments in JavaScriptGenerator#call and JavaScriptProxy#call.  
Add JavaScriptGenerator#literal for wrapping a string in an object whose #to_json is the string itself.


git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@5323 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
上级 dbd0bd5e
*SVN*
* Add support for converting blocks into function arguments to JavaScriptGenerator#call and JavaScriptProxy#call. [Sam Stephenson]
* Add JavaScriptGenerator#literal for wrapping a string in an object whose #to_json is the string itself. [Sam Stephenson]
* Add <%= escape_once html %> to escape html while leaving any currently escaped entities alone. Fix button_to double-escaping issue. [Rick]
* Fix double-escaped entities, such as &amp;amp;, &amp;#123;, etc. [Rick]
......
......@@ -458,6 +458,12 @@ def [](id)
JavaScriptElementProxy.new(self, id)
end
# Returns an object whose <tt>#to_json</tt> evaluates to +code+. Use this to pass a literal JavaScript
# expression as an argument to another JavaScriptGenerator method.
def literal(code)
JavaScriptLiteral.new(code)
end
# Returns a collection reference by finding it through a CSS +pattern+ in the DOM. This collection can then be
# used for further method calls. Examples:
#
......@@ -578,16 +584,18 @@ def alert(message)
call 'alert', message
end
# Redirects the browser to the given +location+, in the same form as
# +url_for+.
# Redirects the browser to the given +location+, in the same form as +url_for+.
def redirect_to(location)
assign 'window.location.href', @context.url_for(location)
end
# Calls the JavaScript +function+, optionally with the given
# +arguments+.
def call(function, *arguments)
record "#{function}(#{arguments_for_call(arguments)})"
# Calls the JavaScript +function+, optionally with the given +arguments+.
#
# If a block is given, the block will be passed to a new JavaScriptGenerator;
# the resulting JavaScript code will then be wrapped inside <tt>function() { ... }</tt>
# and passed as the called function's final argument.
def call(function, *arguments, &block)
record "#{function}(#{arguments_for_call(arguments, block)})"
end
# Assigns the JavaScript +variable+ the given +value+.
......@@ -649,7 +657,7 @@ def page
end
def record(line)
returning line = "#{line.to_s.chomp.gsub /\;$/, ''};" do
returning line = "#{line.to_s.chomp.gsub(/\;\z/, '')};" do
self << line
end
end
......@@ -664,10 +672,16 @@ def javascript_object_for(object)
object.respond_to?(:to_json) ? object.to_json : object.inspect
end
def arguments_for_call(arguments)
def arguments_for_call(arguments, block = nil)
arguments << block_to_function(block) if block
arguments.map { |argument| javascript_object_for(argument) }.join ', '
end
def block_to_function(block)
generator = self.class.new(@context, &block)
literal("function() { #{generator.to_s} }")
end
def method_missing(method, *arguments)
JavaScriptProxy.new(self, method.to_s.camelize)
end
......@@ -744,6 +758,13 @@ def build_callbacks(options)
end
end
# Bypasses string escaping so you can pass around raw JavaScript
class JavaScriptLiteral < String #:nodoc:
def to_json
to_s
end
end
# Converts chained method calls on DOM proxy elements into JavaScript chains
class JavaScriptProxy < Builder::BlankSlate #:nodoc:
def initialize(generator, root = nil)
......@@ -752,16 +773,16 @@ def initialize(generator, root = nil)
end
private
def method_missing(method, *arguments)
def method_missing(method, *arguments, &block)
if method.to_s =~ /(.*)=$/
assign($1, arguments.first)
else
call("#{method.to_s.camelize(:lower)}", *arguments)
call("#{method.to_s.camelize(:lower)}", *arguments, &block)
end
end
def call(function, *arguments)
append_to_function_chain!("#{function}(#{@generator.send(:arguments_for_call, arguments)})")
def call(function, *arguments, &block)
append_to_function_chain!("#{function}(#{@generator.send(:arguments_for_call, arguments, block)})")
self
end
......@@ -770,7 +791,7 @@ def assign(variable, value)
end
def function_chain
@function_chain ||= @generator.instance_variable_get("@lines")
@function_chain ||= @generator.instance_variable_get(:@lines)
end
def append_to_function_chain!(call)
......
......@@ -448,10 +448,37 @@ def test_debug_rjs
ensure
ActionView::Base.debug_rjs = false
end
def test_literal
literal = @generator.literal("function() {}")
assert_equal "function() {}", literal.to_json
assert_equal "", @generator.to_s
end
def test_class_proxy
@generator.form.focus('my_field')
assert_equal "Form.focus(\"my_field\");", @generator.to_s
end
def test_call_with_block
@generator.call(:before)
@generator.call(:my_method) do |p|
p[:one].show
p[:two].hide
end
@generator.call(:in_between)
@generator.call(:my_method_with_arguments, true, "hello") do |p|
p[:three].visual_effect(:highlight)
end
assert_equal "before();\nmy_method(function() { $(\"one\").show();\n$(\"two\").hide(); });\nin_between();\nmy_method_with_arguments(true, \"hello\", function() { $(\"three\").visualEffect(\"highlight\"); });", @generator.to_s
end
def test_class_proxy_call_with_block
@generator.my_object.my_method do |p|
p[:one].show
p[:two].hide
end
assert_equal "MyObject.myMethod(function() { $(\"one\").show();\n$(\"two\").hide(); });", @generator.to_s
end
end
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册