diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 79a77ebe4b392f5cfd59d3f7ba1dcbaf8476565b..d23d46e2bbe8a59dfbc508446d64588befa3a3f6 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,15 @@ *SVN* +* Added element and collection proxies to RJS [DHH]. Examples: + + page['blank_slate'] # => $('blank_slate'); + page['blank_slate'].show # => $('blank_slate').show(); + page['blank_slate'].show('first').up # => $('blank_slate').show('first').up(); + + page.select('p') # => $$('p'); + page.select('p.welcome b').first # => $$('p.welcome b').first(); + page.select('p.welcome b').first.hide # => $$('p.welcome b').first().hide(); + * Add JavaScriptGenerator#replace_element for replacing an element's "outer HTML". #3246 [tom@craz8.com, Sam Stephenson] * Remove over-engineered form_for code for a leaner implementation. [Nicholas Seckar] diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index 26d877c00a6ba4eb9523c48de5f5ac06b8918d30..f0d2b405d255eb5cfcc17ba1b230d84469ddafb2 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -416,6 +416,26 @@ def initialize(context, &block) #:nodoc: def to_s #:nodoc: @lines * $/ end + + # Returns a element reference by finding it through +id+ in the DOM. This element can then be + # used for further method calls. Examples: + # + # page['blank_slate'] # => $('blank_slate'); + # page['blank_slate'].show # => $('blank_slate').show(); + # page['blank_slate'].show('first').up # => $('blank_slate').show('first').up(); + def [](id) + JavaScriptElementProxy.new(self, "$('#{id}')") + 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: + # + # page.select('p') # => $$('p'); + # page.select('p.welcome b').first # => $$('p.welcome b').first(); + # page.select('p.welcome b').first.hide # => $$('p.welcome b').first().hide(); + def select(pattern) + JavaScriptElementProxy.new(self, "$$('#{pattern}')") + end # Inserts HTML at the specified +position+ relative to the DOM element # identified by the given +id+. @@ -644,5 +664,24 @@ def build_callbacks(options) callbacks end end + + # Converts chained method calls on DOM proxy elements into JavaScript chains + class JavaScriptElementProxy < Builder::BlankSlate #:nodoc: + def initialize(generator, root) + @generator = generator + @generator << root + end + + private + def method_missing(method, *arguments) + method_chain = @generator.instance_variable_get("@lines") + + last_method = method_chain[-1] + method_chain[-1] = last_method[0..-2] if last_method[-1..-1] == ";" # strip trailing ; from last method call + method_chain[-1] += ".#{method}(#{@generator.send(:arguments_for_call, arguments)});" + + self + end + end end end diff --git a/actionpack/test/template/prototype_helper_test.rb b/actionpack/test/template/prototype_helper_test.rb index fc4ebeccc32b06b37f170fe55243775a6d16898b..8657b1f107cc35dbdf3dc21d5e91029c660a24c0 100644 --- a/actionpack/test/template/prototype_helper_test.rb +++ b/actionpack/test/template/prototype_helper_test.rb @@ -227,4 +227,27 @@ def test_to_s Element.update("baz", "

This is a test

"); EOS end -end + + def test_element_access + assert_equal %($('hello');), @generator['hello'] + end + + def test_element_proxy_one_deep + @generator['hello'].hide + assert_equal %($('hello').hide();), @generator.to_s + end + + def test_element_proxy_two_deep + @generator['hello'].hide("first").display + assert_equal %($('hello').hide("first").display();), @generator.to_s + end + + def test_select_access + assert_equal %($$('div.hello');), @generator.select('div.hello') + end + + def test_select_proxy_one_deep + @generator.select('p.welcome b').first.hide + assert_equal %($$('p.welcome b').first().hide();), @generator.to_s + end +end \ No newline at end of file