Changeset 3754
- Timestamp:
- 03/03/06 19:34:23 (3 years ago)
- Files:
-
- trunk/actionpack/lib/action_view/helpers/prototype_helper.rb (modified) (6 diffs)
- trunk/actionpack/test/template/prototype_helper_test.rb (modified) (3 diffs)
- trunk/activesupport/lib/active_support/json.rb (modified) (1 diff)
- trunk/activesupport/lib/active_support/json/encoders/core.rb (modified) (1 diff)
- trunk/activesupport/test/json.rb (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/actionpack/lib/action_view/helpers/prototype_helper.rb
r3667 r3754 435 435 # page.select('p.welcome b').first.hide # => $$('p.welcome b').first().hide(); 436 436 def select(pattern) 437 JavaScript CollectionProxy.new(self, pattern)437 JavaScriptElementCollectionProxy.new(self, pattern) 438 438 end 439 439 … … 688 688 # Converts chained method calls on DOM proxy elements into JavaScript chains 689 689 class JavaScriptProxy < Builder::BlankSlate #:nodoc: 690 def initialize(generator, root )690 def initialize(generator, root = nil) 691 691 @generator = generator 692 @generator << root 692 @generator << root if root 693 693 end 694 694 … … 698 698 assign($1, arguments.first) 699 699 else 700 call( method, *arguments)700 call("#{method.to_s.first}#{method.to_s.classify[1..-1]}", *arguments) 701 701 end 702 702 end … … 708 708 709 709 def assign(variable, value) 710 append_to_function_chain! "#{variable} = #{@generator.send(:javascript_object_for, value)}"710 append_to_function_chain!("#{variable} = #{@generator.send(:javascript_object_for, value)}") 711 711 end 712 712 … … 716 716 717 717 def append_to_function_chain!(call) 718 function_chain[-1] = function_chain[-1][0..-2] if function_chain[-1][-1..-1] == ";" # strip last ;718 function_chain[-1].chomp!(';') 719 719 function_chain[-1] += ".#{call};" 720 720 end … … 738 738 replace :partial => @id.to_s 739 739 end 740 740 741 end 741 742 743 class JavaScriptVariableProxy < JavaScriptProxy #:nodoc: 744 def initialize(generator, variable) 745 @variable = variable 746 @empty = true # only record lines if we have to. gets rid of unnecessary linebreaks 747 super(generator) 748 end 749 750 # The JSON Encoder calls this to check for the #to_json method 751 # Since it's a blank slate object, I suppose it responds to anything. 752 def respond_to?(method) 753 true 754 end 755 756 def to_json 757 @variable 758 end 759 760 private 761 def append_to_function_chain!(call) 762 @generator << @variable if @empty 763 @empty = false 764 super 765 end 766 end 767 742 768 class JavaScriptCollectionProxy < JavaScriptProxy #:nodoc: 769 ENUMERABLE_METHODS_WITH_RETURN = [:all, :any, :collect, :map, :detect, :find, :findAll, :select, :max, :min, :partition, :reject, :sortBy] 770 ENUMERABLE_METHODS = ENUMERABLE_METHODS_WITH_RETURN + [:each] 771 743 772 def initialize(generator, pattern) 744 @pattern = pattern 773 super(generator, @pattern = pattern) 774 end 775 776 def grep(variable, pattern, &block) 777 enumerable_method("grep(#{pattern.to_json}, function(value, index) {", variable, %w(value index), &block) 778 end 779 780 def inject(variable, memo, &block) 781 enumerable_method("inject(#{memo.to_json}, function(memo, value, index) {", variable, %w(memo value index), &block) 782 end 783 784 def pluck(variable, property) 785 add_variable_assignment!(variable) 786 append_enumerable_function!("pluck(#{property.to_json});") 787 end 788 789 def zip(variable, *arguments, &block) 790 add_variable_assignment!(variable) 791 append_enumerable_function!("zip(#{arguments.collect { |a| a.to_json } * ', '}") 792 if block 793 function_chain[-1] += ", function(array) {" 794 yield @generator, ActiveSupport::JSON::Variable.new('array') 795 add_return_statement! 796 @generator << '});' 797 else 798 function_chain[-1] += ');' 799 end 800 end 801 802 private 803 def method_missing(method, *arguments, &block) 804 ENUMERABLE_METHODS.include?(method) ? enumerate(method, ENUMERABLE_METHODS_WITH_RETURN.include?(method), &block) : super 805 end 806 807 def enumerate(enumerable, variable = nil, &block) 808 enumerable_method("#{enumerable}(function(value, index) {", variable, %w(value index), &block) 809 end 810 811 def enumerable_method(enumerable, variable, yield_params, &block) 812 add_variable_assignment!(variable) if variable 813 append_enumerable_function!(enumerable) 814 yield *([@generator] + yield_params.collect { |p| JavaScriptVariableProxy.new(@generator, p) }) 815 add_return_statement! if variable 816 @generator << '});' 817 end 818 819 def add_variable_assignment!(variable) 820 function_chain.push("#{variable} = #{function_chain.pop}") 821 end 822 823 def add_return_statement! 824 unless function_chain.last =~ /return/ 825 function_chain.push("return #{function_chain.pop.chomp(';')};") 826 end 827 end 828 829 def append_enumerable_function!(call) 830 function_chain[-1].chomp!(';') 831 function_chain[-1] += ".#{call}" 832 end 833 end 834 835 class JavaScriptElementCollectionProxy < JavaScriptCollectionProxy #:nodoc:\ 836 def initialize(generator, pattern) 745 837 super(generator, "$$('#{pattern}')") 746 838 end 747 748 # TODO: Implement funky stuff like .each749 839 end 750 840 end trunk/actionpack/test/template/prototype_helper_test.rb
r3667 r3754 149 149 end 150 150 151 ActionView::Helpers::JavaScriptCollectionProxy.send :public, :enumerate 152 151 153 class JavaScriptGeneratorTest < Test::Unit::TestCase 152 154 include BaseTest … … 245 247 246 248 def test_element_proxy_two_deep 247 @generator['hello'].hide("first"). display248 assert_equal %($('hello').hide("first"). display();), @generator.to_s249 @generator['hello'].hide("first").clean_whitespace 250 assert_equal %($('hello').hide("first").cleanWhitespace();), @generator.to_s 249 251 end 250 252 … … 282 284 @generator.drop_receiving('blah', :url => { :action => "order" }) 283 285 end 286 287 def test_collection_proxy_with_each 288 @generator.select('p.welcome b').each do |page, value| 289 value.remove_class_name 'selected' 290 end 291 @generator.select('p.welcome b').each do |page, value, index| 292 page.call 'alert', index 293 page.call 'alert', value, 'selected' 294 end 295 assert_equal <<-EOS.strip, @generator.to_s 296 $$('p.welcome b').each(function(value, index) { 297 value.removeClassName("selected"); 298 }); 299 $$('p.welcome b').each(function(value, index) { 300 alert(index); 301 alert(value, "selected"); 302 }); 303 EOS 304 end 305 306 def test_collection_proxy_on_enumerables_with_return_and_index 307 iterator = Proc.new { |page, value| page << '(value.className == "welcome")' } 308 iterator_with_index = Proc.new { |page, value, index| page.call 'alert', index ; page << '(value.className == "welcome")' } 309 ActionView::Helpers::JavaScriptCollectionProxy::ENUMERABLE_METHODS_WITH_RETURN.each do |enum| 310 @generator.select('p').enumerate(enum, 'a', &iterator) 311 @generator.select('p').enumerate(enum, 'b', &iterator_with_index) 312 313 assert_equal <<-EOS.strip, @generator.to_s 314 a = $$('p').#{enum}(function(value, index) { 315 return (value.className == "welcome"); 316 }); 317 b = $$('p').#{enum}(function(value, index) { 318 alert(index); 319 return (value.className == "welcome"); 320 }); 321 EOS 322 @generator = create_generator 323 end 324 end 325 326 def test_collection_proxy_with_grep 327 @generator.select('p').grep 'a', /^a/ do |page, value| 328 page << '(value.className == "welcome")' 329 end 330 @generator.select('p').grep 'b', /b$/ do |page, value, index| 331 page.call 'alert', value 332 page << '(value.className == "welcome")' 333 end 334 335 assert_equal <<-EOS.strip, @generator.to_s 336 a = $$('p').grep(/^a/, function(value, index) { 337 return (value.className == "welcome"); 338 }); 339 b = $$('p').grep(/b$/, function(value, index) { 340 alert(value); 341 return (value.className == "welcome"); 342 }); 343 EOS 344 end 345 346 def test_collection_proxy_with_inject 347 @generator.select('p').inject 'a', [] do |page, memo, value| 348 page << '(value.className == "welcome")' 349 end 350 @generator.select('p').inject 'b', nil do |page, memo, value, index| 351 page.call 'alert', memo 352 page << '(value.className == "welcome")' 353 end 354 355 assert_equal <<-EOS.strip, @generator.to_s 356 a = $$('p').inject([], function(memo, value, index) { 357 return (value.className == "welcome"); 358 }); 359 b = $$('p').inject(null, function(memo, value, index) { 360 alert(memo); 361 return (value.className == "welcome"); 362 }); 363 EOS 364 end 365 366 def test_collection_proxy_with_pluck 367 @generator.select('p').pluck('a', 'className') 368 assert_equal %(a = $$('p').pluck("className");), @generator.to_s 369 end 370 371 def test_collection_proxy_with_zip 372 ActionView::Helpers::JavaScriptCollectionProxy.new(@generator, '[1, 2, 3]').zip('a', [4, 5, 6], [7, 8, 9]) 373 ActionView::Helpers::JavaScriptCollectionProxy.new(@generator, '[1, 2, 3]').zip('b', [4, 5, 6], [7, 8, 9]) do |page, array| 374 page.call 'array.reverse' 375 end 376 377 assert_equal <<-EOS.strip, @generator.to_s 378 a = [1, 2, 3].zip([4, 5, 6], [7, 8, 9]); 379 b = [1, 2, 3].zip([4, 5, 6], [7, 8, 9], function(array) { 380 return array.reverse(); 381 }); 382 EOS 383 end 284 384 end trunk/activesupport/lib/active_support/json.rb
r3356 r3754 4 4 module JSON #:nodoc: 5 5 class CircularReferenceError < StandardError; end 6 6 # returns the literal string as its JSON encoded form. Useful for passing javascript variables into functions. 7 # 8 # page.call 'Element.show', ActiveSupport::JSON::Variable.new("$$(#items li)") 9 class Variable < String 10 def to_json 11 self 12 end 13 end 14 7 15 class << self 8 16 REFERENCE_STACK_VARIABLE = :json_reference_stack trunk/activesupport/lib/active_support/json/encoders/core.rb
r3356 r3754 57 57 end 58 58 end 59 60 define_encoder Regexp do |regexp| 61 regexp.inspect 62 end 59 63 end 60 64 end trunk/activesupport/test/json.rb
r3356 r3754 10 10 11 11 class TestJSONEmitters < Test::Unit::TestCase 12 TrueTests = [[ true, %(true) ]]13 FalseTests = [[ false, %(false) ]]14 NilTests = [[ nil, %(null) ]]15 NumericTests = [[ 1, %(1) ],16 [ 2.5, %(2.5) ]]12 TrueTests = [[ true, %(true) ]] 13 FalseTests = [[ false, %(false) ]] 14 NilTests = [[ nil, %(null) ]] 15 NumericTests = [[ 1, %(1) ], 16 [ 2.5, %(2.5) ]] 17 17 18 StringTests = [[ 'this is the string', %("this is the string") ],19 [ 'a "string" with quotes', %("a \\"string\\" with quotes") ]]18 StringTests = [[ 'this is the string', %("this is the string") ], 19 [ 'a "string" with quotes', %("a \\"string\\" with quotes") ]] 20 20 21 ArrayTests = [[ ['a', 'b', 'c'], %([\"a\", \"b\", \"c\"]) ],22 [ [1, 'a', :b, nil, false], %([1, \"a\", \"b\", null, false]) ]]21 ArrayTests = [[ ['a', 'b', 'c'], %([\"a\", \"b\", \"c\"]) ], 22 [ [1, 'a', :b, nil, false], %([1, \"a\", \"b\", null, false]) ]] 23 23 24 HashTests = [[ {:a => :b, :c => :d}, %({\"c\": \"d\", \"a\": \"b\"}) ]]24 HashTests = [[ {:a => :b, :c => :d}, %({\"c\": \"d\", \"a\": \"b\"}) ]] 25 25 26 SymbolTests = [[ :a, %("a") ],27 [ :this, %("this") ],28 [ :"a b", %("a b") ]]26 SymbolTests = [[ :a, %("a") ], 27 [ :this, %("this") ], 28 [ :"a b", %("a b") ]] 29 29 30 ObjectTests = [[ Foo.new(1, 2), %({\"a\": 1, \"b\": 2}) ]] 31 30 ObjectTests = [[ Foo.new(1, 2), %({\"a\": 1, \"b\": 2}) ]] 31 32 VariableTests = [[ ActiveSupport::JSON::Variable.new('foo'), 'foo'], 33 [ ActiveSupport::JSON::Variable.new('alert("foo")'), 'alert("foo")']] 34 RegexpTests = [[ /^a/, '/^a/' ], /^\w{1,2}[a-z]+/ix, '/^\\w{1,2}[a-z]+/ix'] 35 32 36 constants.grep(/Tests$/).each do |class_tests| 33 37 define_method("test_#{class_tests[0..-6].downcase}") do