From 7fcf8590e788cef8b64cc266f75931c418902ca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 21 Jan 2010 23:14:20 +0100 Subject: Massive cleanup in Railties and load stack. --- actionpack/lib/action_controller/railtie.rb | 6 ------ 1 file changed, 6 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb index 7ea64c1923..ee94bf8364 100644 --- a/actionpack/lib/action_controller/railtie.rb +++ b/actionpack/lib/action_controller/railtie.rb @@ -19,12 +19,6 @@ module ActionController ActionController::Base.logger ||= Rails.logger end - # Routing must be initialized after plugins to allow the former to extend the routes - initializer "action_controller.initialize_routing" do |app| - app.route_configuration_files << app.config.routes_configuration_file - app.route_configuration_files << app.config.builtin_routes_configuration_file - end - initializer "action_controller.initialize_framework_caches" do ActionController::Base.cache_store ||= RAILS_CACHE end -- cgit v1.2.3 From 02c5137eadbb3530033d919b7aebeb6f4f389b83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Fri, 22 Jan 2010 01:10:31 +0100 Subject: Add view paths to Engine setup. --- actionpack/lib/action_controller/railtie.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb index ee94bf8364..621dd9373c 100644 --- a/actionpack/lib/action_controller/railtie.rb +++ b/actionpack/lib/action_controller/railtie.rb @@ -29,8 +29,7 @@ module ActionController # set to use Configuration#view_path. initializer "action_controller.initialize_framework_views" do |app| # TODO: this should be combined with the logic for default config.action_controller.view_paths - view_path = ActionView::PathSet.type_cast(app.config.view_path, app.config.cache_classes) - ActionController::Base.view_paths = view_path if ActionController::Base.view_paths.blank? + ActionController::Base.view_paths = [] if ActionController::Base.view_paths.blank? end end -- cgit v1.2.3 From dcb925369389fa98d1548b25504c8e3a07eaeea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim=20and=20Mikel=20Lindsaar?= Date: Fri, 22 Jan 2010 13:27:20 +0100 Subject: Add basic template rendering to new DSL. --- actionpack/lib/action_view/render/rendering.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb index ec278ca783..7c33f1334a 100644 --- a/actionpack/lib/action_view/render/rendering.rb +++ b/actionpack/lib/action_view/render/rendering.rb @@ -1,3 +1,5 @@ +require 'active_support/core_ext/object/try' + module ActionView module Rendering # Returns the result of a render that's dictated by the options hash. The primary options are: -- cgit v1.2.3 From c8cc8a987213bf90fe6922517d52befb7c0587a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Fri, 22 Jan 2010 20:44:29 +0100 Subject: Moved more configuration away from bootstrap. --- actionpack/lib/action_controller/railtie.rb | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb index 621dd9373c..6b270d1136 100644 --- a/actionpack/lib/action_controller/railtie.rb +++ b/actionpack/lib/action_controller/railtie.rb @@ -22,15 +22,5 @@ module ActionController initializer "action_controller.initialize_framework_caches" do ActionController::Base.cache_store ||= RAILS_CACHE end - - # Sets +ActionController::Base#view_paths+ and +ActionMailer::Base#template_root+ - # (but only for those frameworks that are to be loaded). If the framework's - # paths have already been set, it is not changed, otherwise it is - # set to use Configuration#view_path. - initializer "action_controller.initialize_framework_views" do |app| - # TODO: this should be combined with the logic for default config.action_controller.view_paths - ActionController::Base.view_paths = [] if ActionController::Base.view_paths.blank? - end - end end -- cgit v1.2.3 From 98240c49b05093d6d14b9384a9bd695b58eefb59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 23 Jan 2010 01:29:29 +0100 Subject: Get rid of initializers global and create i18n railtie. --- actionpack/lib/action_controller/metal/helpers.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/metal/helpers.rb b/actionpack/lib/action_controller/metal/helpers.rb index cdd14560e1..24f8cb8a57 100644 --- a/actionpack/lib/action_controller/metal/helpers.rb +++ b/actionpack/lib/action_controller/metal/helpers.rb @@ -51,6 +51,8 @@ module ActionController included do # Set the default directory for helpers + # TODO This should support multiple directories in order + # to work with engines extlib_inheritable_accessor(:helpers_dir) do defined?(Rails.root) ? "#{Rails.root}/app/helpers" : "app/helpers" end -- cgit v1.2.3 From ddfc0725a062880131745a1c529e94541d4c9ee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim=20and=20Mikel=20Lindsaar?= Date: Sat, 23 Jan 2010 10:23:06 +0100 Subject: Added AbstractController::Collector. --- actionpack/lib/abstract_controller.rb | 1 + actionpack/lib/abstract_controller/collector.rb | 30 ++++++++++++ .../lib/action_controller/metal/mime_responds.rb | 29 ++--------- actionpack/test/abstract/collector_test.rb | 57 ++++++++++++++++++++++ 4 files changed, 91 insertions(+), 26 deletions(-) create mode 100644 actionpack/lib/abstract_controller/collector.rb create mode 100644 actionpack/test/abstract/collector_test.rb (limited to 'actionpack') diff --git a/actionpack/lib/abstract_controller.rb b/actionpack/lib/abstract_controller.rb index 725d8fb8fc..2c2ef16622 100644 --- a/actionpack/lib/abstract_controller.rb +++ b/actionpack/lib/abstract_controller.rb @@ -10,6 +10,7 @@ module AbstractController autoload :Base autoload :Callbacks + autoload :Collector autoload :Helpers autoload :Layouts autoload :LocalizedCache diff --git a/actionpack/lib/abstract_controller/collector.rb b/actionpack/lib/abstract_controller/collector.rb new file mode 100644 index 0000000000..d429333661 --- /dev/null +++ b/actionpack/lib/abstract_controller/collector.rb @@ -0,0 +1,30 @@ +module AbstractController + module Collector + def self.generate_method_for_mime(mime) + sym = mime.is_a?(Symbol) ? mime : mime.to_sym + const = sym.to_s.upcase + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{sym}(*args, &block) # def html(*args, &block) + custom(Mime::#{const}, *args, &block) # custom(Mime::HTML, *args, &block) + end # end + RUBY + end + + Mime::SET.each do |mime| + generate_method_for_mime(mime) + end + + protected + + def method_missing(symbol, &block) + mime_constant = Mime.const_get(symbol.to_s.upcase) + + if Mime::SET.include?(mime_constant) + AbstractController::Collector.generate_method_for_mime(mime_constant) + send(symbol, &block) + else + super + end + end + end +end \ No newline at end of file diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb index 4c02677729..08599d660e 100644 --- a/actionpack/lib/action_controller/metal/mime_responds.rb +++ b/actionpack/lib/action_controller/metal/mime_responds.rb @@ -1,3 +1,5 @@ +require 'abstract_controller/collector' + module ActionController #:nodoc: module MimeResponds #:nodoc: extend ActiveSupport::Concern @@ -265,6 +267,7 @@ module ActionController #:nodoc: end class Collector #:nodoc: + include AbstractController::Collector attr_accessor :order def initialize(&block) @@ -289,32 +292,6 @@ module ActionController #:nodoc: def response_for(mime) @responses[mime] || @responses[Mime::ALL] || @default_response end - - def self.generate_method_for_mime(mime) - sym = mime.is_a?(Symbol) ? mime : mime.to_sym - const = sym.to_s.upcase - class_eval <<-RUBY, __FILE__, __LINE__ + 1 - def #{sym}(&block) # def html(&block) - custom(Mime::#{const}, &block) # custom(Mime::HTML, &block) - end # end - RUBY - end - - Mime::SET.each do |mime| - generate_method_for_mime(mime) - end - - def method_missing(symbol, &block) - mime_constant = Mime.const_get(symbol.to_s.upcase) - - if Mime::SET.include?(mime_constant) - self.class.generate_method_for_mime(mime_constant) - send(symbol, &block) - else - super - end - end - end end end diff --git a/actionpack/test/abstract/collector_test.rb b/actionpack/test/abstract/collector_test.rb new file mode 100644 index 0000000000..2ebcebbbb7 --- /dev/null +++ b/actionpack/test/abstract/collector_test.rb @@ -0,0 +1,57 @@ +require 'abstract_unit' + +module AbstractController + module Testing + class MyCollector + include Collector + attr_accessor :responses + + def initialize + @responses = [] + end + + def custom(mime, *args, &block) + @responses << [mime, args, block] + end + end + + class TestCollector < ActiveSupport::TestCase + test "responds to default mime types" do + collector = MyCollector.new + assert_respond_to collector, :html + assert_respond_to collector, :text + end + + test "does not respond to unknown mime types" do + collector = MyCollector.new + assert !collector.respond_to?(:unknown) + end + + test "register mime types on method missing" do + AbstractController::Collector.send(:remove_method, :js) + collector = MyCollector.new + assert !collector.respond_to?(:js) + collector.js + assert_respond_to collector, :js + end + + test "does not register unknown mime types" do + collector = MyCollector.new + assert_raise NameError do + collector.unknown + end + end + + test "generated methods call custom with args received" do + collector = MyCollector.new + collector.html + collector.text(:foo) + collector.js(:bar) { :baz } + assert_equal [Mime::HTML, [], nil], collector.responses[0] + assert_equal [Mime::TEXT, [:foo], nil], collector.responses[1] + assert_equal [Mime::JS, [:bar]], collector.responses[2][0,2] + assert_equal :baz, collector.responses[2][2].call + end + end + end +end \ No newline at end of file -- cgit v1.2.3 From 502028a32bfa46ad18337d2a69f03e8b5dec3c4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim=20and=20Mikel=20Lindsaar?= Date: Sat, 23 Jan 2010 10:29:22 +0100 Subject: Move double render check out of AbstractController. --- actionpack/lib/abstract_controller/rendering.rb | 4 ---- actionpack/lib/action_controller/metal/rendering.rb | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb index a168b1b4c5..1dec3f2c3e 100644 --- a/actionpack/lib/abstract_controller/rendering.rb +++ b/actionpack/lib/abstract_controller/rendering.rb @@ -41,10 +41,6 @@ module AbstractController # Mostly abstracts the fact that calling render twice is a DoubleRenderError. # Delegates render_to_body and sticks the result in self.response_body. def render(*args, &block) - if response_body - raise AbstractController::DoubleRenderError - end - options = _normalize_options(*args, &block) self.response_body = render_to_body(options) end diff --git a/actionpack/lib/action_controller/metal/rendering.rb b/actionpack/lib/action_controller/metal/rendering.rb index 72e2bbd00e..8f03035b2b 100644 --- a/actionpack/lib/action_controller/metal/rendering.rb +++ b/actionpack/lib/action_controller/metal/rendering.rb @@ -13,6 +13,10 @@ module ActionController end def render(*args) + if response_body + raise ::AbstractController::DoubleRenderError + end + args << {} unless args.last.is_a?(Hash) super(*args) self.content_type ||= args.last[:_template].mime_type.to_s -- cgit v1.2.3 From 80130d1201c3bf9dc17b0e1fcd81c6b22e893b0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 23 Jan 2010 15:05:13 +0100 Subject: Extract routes reloading responsibilities from application and load them just upon a request. --- actionpack/lib/action_dispatch/middleware/callbacks.rb | 2 +- actionpack/lib/action_dispatch/railtie.rb | 16 ++++------------ 2 files changed, 5 insertions(+), 13 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/middleware/callbacks.rb b/actionpack/lib/action_dispatch/middleware/callbacks.rb index d07841218a..7cf75ffe63 100644 --- a/actionpack/lib/action_dispatch/middleware/callbacks.rb +++ b/actionpack/lib/action_dispatch/middleware/callbacks.rb @@ -37,7 +37,7 @@ module ActionDispatch def initialize(app, prepare_each_request = false) @app, @prepare_each_request = app, prepare_each_request - run_callbacks(:prepare) + run_callbacks(:prepare) unless @prepare_each_request end def call(env) diff --git a/actionpack/lib/action_dispatch/railtie.rb b/actionpack/lib/action_dispatch/railtie.rb index e4bd143e78..bd15ca9b3b 100644 --- a/actionpack/lib/action_dispatch/railtie.rb +++ b/actionpack/lib/action_dispatch/railtie.rb @@ -5,22 +5,14 @@ module ActionDispatch class Railtie < Rails::Railtie plugin_name :action_dispatch + # Initialize route files to an array + config.action_dispatch.route_files = [] + # Prepare dispatcher callbacks and run 'prepare' callbacks initializer "action_dispatch.prepare_dispatcher" do |app| # TODO: This used to say unless defined?(Dispatcher). Find out why and fix. require 'rails/dispatcher' - - unless app.config.cache_classes - # Setup dev mode route reloading - routes_last_modified = app.routes_changed_at - reload_routes = lambda do - unless app.routes_changed_at == routes_last_modified - routes_last_modified = app.routes_changed_at - app.reload_routes! - end - end - ActionDispatch::Callbacks.before { |callbacks| reload_routes.call } - end + ActionDispatch::Callbacks.to_prepare { app.routes_reloader.reload_if_changed } end end end \ No newline at end of file -- cgit v1.2.3 From 2fde9d774b322fc708990675671231c64c691a33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sun, 24 Jan 2010 09:00:18 +0100 Subject: Solve some pendencies. --- actionpack/lib/action_dispatch/railtie.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/railtie.rb b/actionpack/lib/action_dispatch/railtie.rb index bd15ca9b3b..9cc47e53ed 100644 --- a/actionpack/lib/action_dispatch/railtie.rb +++ b/actionpack/lib/action_dispatch/railtie.rb @@ -6,7 +6,7 @@ module ActionDispatch plugin_name :action_dispatch # Initialize route files to an array - config.action_dispatch.route_files = [] + config.action_dispatch.route_paths = [] # Prepare dispatcher callbacks and run 'prepare' callbacks initializer "action_dispatch.prepare_dispatcher" do |app| -- cgit v1.2.3 From e0bdc4f446686a498c3117e27ed8561f5c6d34f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sun, 24 Jan 2010 11:06:06 +0100 Subject: Ensure namespaced controllers in engines work. --- .../lib/action_dispatch/routing/route_set.rb | 28 ++++++---------------- 1 file changed, 7 insertions(+), 21 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 660d28dbec..c49ac70562 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -222,19 +222,18 @@ module ActionDispatch end end - attr_accessor :routes, :named_routes - attr_accessor :disable_clear_and_finalize + attr_accessor :routes, :named_routes, :controller_namespaces + attr_accessor :disable_clear_and_finalize, :resources_path_names def self.default_resources_path_names { :new => 'new', :edit => 'edit' } end - attr_accessor :resources_path_names - def initialize self.routes = [] self.named_routes = NamedRouteCollection.new - self.resources_path_names = self.class.default_resources_path_names + self.resources_path_names = self.class.default_resources_path_names.dup + self.controller_namespaces = Set.new @disable_clear_and_finalize = false end @@ -281,32 +280,19 @@ module ActionDispatch def controller_constraints @controller_constraints ||= begin - source = controller_namespaces.map { |ns| "#{Regexp.escape(ns)}/#{CONTROLLER_REGEXP.source}" } + namespaces = controller_namespaces + in_memory_controller_namespaces + source = namespaces.map { |ns| "#{Regexp.escape(ns)}/#{CONTROLLER_REGEXP.source}" } source << CONTROLLER_REGEXP.source Regexp.compile(source.sort.reverse.join('|')) end end - def controller_namespaces + def in_memory_controller_namespaces namespaces = Set.new - - # Find any nested controllers already in memory ActionController::Base.subclasses.each do |klass| controller_name = klass.underscore namespaces << controller_name.split('/')[0...-1].join('/') end - - # TODO: Move this into Railties - if defined?(Rails.application) - # Find namespaces in controllers/ directory - Rails.application.config.controller_paths.each do |load_path| - load_path = File.expand_path(load_path) - Dir["#{load_path}/**/*_controller.rb"].collect do |path| - namespaces << File.dirname(path).sub(/#{load_path}\/?/, '') - end - end - end - namespaces.delete('') namespaces end -- cgit v1.2.3 From 37e4deb2606557e5340b48169ffc1435bb331439 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sun, 24 Jan 2010 12:04:37 +0100 Subject: Ensure helpers work from configured path. --- actionpack/lib/action_controller/base.rb | 2 +- actionpack/lib/action_controller/metal/helpers.rb | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index f46231d72b..215b70734c 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -7,7 +7,6 @@ module ActionController include AbstractController::Translation include ActionController::Helpers - helper :all # By default, all helpers should be included include ActionController::HideActions include ActionController::UrlFor @@ -67,6 +66,7 @@ module ActionController def self.inherited(klass) ::ActionController::Base.subclasses << klass.to_s super + klass.helper :all end def self.subclasses diff --git a/actionpack/lib/action_controller/metal/helpers.rb b/actionpack/lib/action_controller/metal/helpers.rb index 24f8cb8a57..757ce3c319 100644 --- a/actionpack/lib/action_controller/metal/helpers.rb +++ b/actionpack/lib/action_controller/metal/helpers.rb @@ -50,11 +50,8 @@ module ActionController include AbstractController::Helpers included do - # Set the default directory for helpers - # TODO This should support multiple directories in order - # to work with engines - extlib_inheritable_accessor(:helpers_dir) do - defined?(Rails.root) ? "#{Rails.root}/app/helpers" : "app/helpers" + extlib_inheritable_accessor(:helpers_path) do + defined?(Rails::Application) ? Rails::Application.paths.app.helpers.to_a : [] end end @@ -107,10 +104,15 @@ module ActionController raise e unless e.missing_name? "#{module_name}Helper" end - # Extract helper names from files in app/helpers/**/*.rb + # Extract helper names from files in app/helpers/**/*_helper.rb def all_application_helpers - extract = /^#{Regexp.quote(helpers_dir)}\/?(.*)_helper.rb$/ - Dir["#{helpers_dir}/**/*_helper.rb"].map { |file| file.sub extract, '\1' } + helpers = [] + helpers_path.each do |path| + extract = /^#{Regexp.quote(path)}\/?(.*)_helper.rb$/ + helpers += Dir["#{path}/**/*_helper.rb"].map { |file| file.sub(extract, '\1') } + end + helpers.uniq! + helpers end end end -- cgit v1.2.3 From e548f96b1d5cb6529dd6fbc6544f03a3a840b48c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sun, 24 Jan 2010 12:23:21 +0100 Subject: Rename plugin_name to railtie_name and engine_name. --- actionpack/lib/action_controller/railtie.rb | 2 +- actionpack/lib/action_dispatch/railtie.rb | 2 +- actionpack/lib/action_view/railtie.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb index 6b270d1136..f15c012471 100644 --- a/actionpack/lib/action_controller/railtie.rb +++ b/actionpack/lib/action_controller/railtie.rb @@ -3,7 +3,7 @@ require "rails" module ActionController class Railtie < Rails::Railtie - plugin_name :action_controller + railtie_name :action_controller require "action_controller/railties/subscriber" subscriber ActionController::Railties::Subscriber.new diff --git a/actionpack/lib/action_dispatch/railtie.rb b/actionpack/lib/action_dispatch/railtie.rb index 9cc47e53ed..979679712a 100644 --- a/actionpack/lib/action_dispatch/railtie.rb +++ b/actionpack/lib/action_dispatch/railtie.rb @@ -3,7 +3,7 @@ require "rails" module ActionDispatch class Railtie < Rails::Railtie - plugin_name :action_dispatch + railtie_name :action_dispatch # Initialize route files to an array config.action_dispatch.route_paths = [] diff --git a/actionpack/lib/action_view/railtie.rb b/actionpack/lib/action_view/railtie.rb index 968dc7b25e..d9e2557d89 100644 --- a/actionpack/lib/action_view/railtie.rb +++ b/actionpack/lib/action_view/railtie.rb @@ -3,7 +3,7 @@ require "rails" module ActionView class Railtie < Rails::Railtie - plugin_name :action_view + railtie_name :action_view require "action_view/railties/subscriber" subscriber ActionView::Railties::Subscriber.new -- cgit v1.2.3 From 84ebfa4550b2325c6c89bc13aa6f904ff88d0db7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sun, 24 Jan 2010 14:48:00 +0100 Subject: Ensure metals and initializers in plugins are loaded. --- actionpack/lib/action_dispatch/railtie.rb | 3 --- 1 file changed, 3 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/railtie.rb b/actionpack/lib/action_dispatch/railtie.rb index 979679712a..335daafc01 100644 --- a/actionpack/lib/action_dispatch/railtie.rb +++ b/actionpack/lib/action_dispatch/railtie.rb @@ -5,9 +5,6 @@ module ActionDispatch class Railtie < Rails::Railtie railtie_name :action_dispatch - # Initialize route files to an array - config.action_dispatch.route_paths = [] - # Prepare dispatcher callbacks and run 'prepare' callbacks initializer "action_dispatch.prepare_dispatcher" do |app| # TODO: This used to say unless defined?(Dispatcher). Find out why and fix. -- cgit v1.2.3 From 6545a68264682e8d0a0ee0e913fa98d92fef9428 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sun, 24 Jan 2010 15:08:06 +0100 Subject: Fix failing tests after merge. --- actionpack/lib/action_controller/metal/helpers.rb | 1 + actionpack/test/abstract/helper_test.rb | 2 +- actionpack/test/controller/helper_test.rb | 4 ++-- actionpack/test/fixtures/helpers/fun/games_helper.rb | 6 ++++-- actionpack/test/fixtures/helpers/fun/pdf_helper.rb | 6 ++++-- 5 files changed, 12 insertions(+), 7 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/metal/helpers.rb b/actionpack/lib/action_controller/metal/helpers.rb index 757ce3c319..0e3db86861 100644 --- a/actionpack/lib/action_controller/metal/helpers.rb +++ b/actionpack/lib/action_controller/metal/helpers.rb @@ -111,6 +111,7 @@ module ActionController extract = /^#{Regexp.quote(path)}\/?(.*)_helper.rb$/ helpers += Dir["#{path}/**/*_helper.rb"].map { |file| file.sub(extract, '\1') } end + helpers.sort! helpers.uniq! helpers end diff --git a/actionpack/test/abstract/helper_test.rb b/actionpack/test/abstract/helper_test.rb index ade29140ba..0cdf5c2298 100644 --- a/actionpack/test/abstract/helper_test.rb +++ b/actionpack/test/abstract/helper_test.rb @@ -1,6 +1,6 @@ require 'abstract_unit' -ActionController::Base.helpers_dir = File.dirname(__FILE__) + '/../fixtures/helpers' +ActionController::Base.helpers_path = [File.dirname(__FILE__) + '/../fixtures/helpers'] module AbstractController module Testing diff --git a/actionpack/test/controller/helper_test.rb b/actionpack/test/controller/helper_test.rb index 9030e562bb..fe0961e575 100644 --- a/actionpack/test/controller/helper_test.rb +++ b/actionpack/test/controller/helper_test.rb @@ -1,7 +1,7 @@ require 'abstract_unit' require 'active_support/core_ext/kernel/reporting' -ActionController::Base.helpers_dir = File.dirname(__FILE__) + '/../fixtures/helpers' +ActionController::Base.helpers_path = [File.dirname(__FILE__) + '/../fixtures/helpers'] module Fun class GamesController < ActionController::Base @@ -106,7 +106,7 @@ class HelperTest < Test::Unit::TestCase end def test_all_helpers_with_alternate_helper_dir - @controller_class.helpers_dir = File.dirname(__FILE__) + '/../fixtures/alternate_helpers' + @controller_class.helpers_path = [File.dirname(__FILE__) + '/../fixtures/alternate_helpers'] # Reload helpers @controller_class._helpers = Module.new diff --git a/actionpack/test/fixtures/helpers/fun/games_helper.rb b/actionpack/test/fixtures/helpers/fun/games_helper.rb index bf60d9db0c..3b7adce086 100644 --- a/actionpack/test/fixtures/helpers/fun/games_helper.rb +++ b/actionpack/test/fixtures/helpers/fun/games_helper.rb @@ -1,3 +1,5 @@ -module Fun::GamesHelper - def stratego() "Iz guuut!" end +module Fun + module GamesHelper + def stratego() "Iz guuut!" end + end end \ No newline at end of file diff --git a/actionpack/test/fixtures/helpers/fun/pdf_helper.rb b/actionpack/test/fixtures/helpers/fun/pdf_helper.rb index c4aea5a3f3..0171be8500 100644 --- a/actionpack/test/fixtures/helpers/fun/pdf_helper.rb +++ b/actionpack/test/fixtures/helpers/fun/pdf_helper.rb @@ -1,3 +1,5 @@ -module Fun::PdfHelper - def foobar() 'baz' end +module Fun + module PdfHelper + def foobar() 'baz' end + end end -- cgit v1.2.3 From 3b6f659fb6b1ffd323c0bbad36630cc97b96bd5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 25 Jan 2010 01:06:12 +0100 Subject: Add active_model/railtie back to generated boot.rb, add models back to paths, load active_support/railtie since we need it and ensure default logger is set before config. --- actionpack/lib/action_controller/deprecated.rb | 1 + actionpack/lib/action_controller/railtie.rb | 9 ++++----- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/deprecated.rb b/actionpack/lib/action_controller/deprecated.rb index 589061e77c..edc0e5b3fe 100644 --- a/actionpack/lib/action_controller/deprecated.rb +++ b/actionpack/lib/action_controller/deprecated.rb @@ -2,3 +2,4 @@ ActionController::AbstractRequest = ActionController::Request = ActionDispatch:: ActionController::AbstractResponse = ActionController::Response = ActionDispatch::Response ActionController::Routing = ActionDispatch::Routing ActionController::Routing::Routes = ActionDispatch::Routing::RouteSet.new +ActionController::UrlWriter = AbstractController::UrlFor diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb index f15c012471..29a0a346ec 100644 --- a/actionpack/lib/action_controller/railtie.rb +++ b/actionpack/lib/action_controller/railtie.rb @@ -8,17 +8,16 @@ module ActionController require "action_controller/railties/subscriber" subscriber ActionController::Railties::Subscriber.new + initializer "action_controller.logger" do + ActionController::Base.logger ||= Rails.logger + end + initializer "action_controller.set_configs" do |app| app.config.action_controller.each do |k,v| ActionController::Base.send "#{k}=", v end end - # TODO: ActionController::Base.logger should delegate to its own config.logger - initializer "action_controller.logger" do - ActionController::Base.logger ||= Rails.logger - end - initializer "action_controller.initialize_framework_caches" do ActionController::Base.cache_store ||= RAILS_CACHE end -- cgit v1.2.3 From 02908e11425069e5b91cbf8ec3c8344a58493ef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 25 Jan 2010 22:59:08 +0100 Subject: As first step setup the load path and lazy compare middlewares. --- actionpack/lib/action_dispatch/middleware/stack.rb | 14 +++++++++++++- actionpack/test/dispatch/middleware_stack_test.rb | 6 ++++++ 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/middleware/stack.rb b/actionpack/lib/action_dispatch/middleware/stack.rb index 0dc1d70e37..18a2922fa7 100644 --- a/actionpack/lib/action_dispatch/middleware/stack.rb +++ b/actionpack/lib/action_dispatch/middleware/stack.rb @@ -55,7 +55,11 @@ module ActionDispatch when Class klass == middleware else - klass == ActiveSupport::Inflector.constantize(middleware.to_s) + if lazy_compare?(@klass) && lazy_compare?(middleware) + normalize(@klass) == normalize(middleware) + else + klass == ActiveSupport::Inflector.constantize(middleware.to_s) + end end end @@ -72,6 +76,14 @@ module ActionDispatch end private + def lazy_compare?(object) + object.is_a?(String) || object.is_a?(Symbol) + end + + def normalize(object) + object.to_s.strip.sub(/^::/, '') + end + def build_args Array(args).map { |arg| arg.respond_to?(:call) ? arg.call : arg } end diff --git a/actionpack/test/dispatch/middleware_stack_test.rb b/actionpack/test/dispatch/middleware_stack_test.rb index f4e18308ae..7cf6365af3 100644 --- a/actionpack/test/dispatch/middleware_stack_test.rb +++ b/actionpack/test/dispatch/middleware_stack_test.rb @@ -87,4 +87,10 @@ class MiddlewareStackTest < ActiveSupport::TestCase end assert_equal [:foo], @stack.last.send(:build_args) end + + test "lazy compares so unloaded constants can be loaded" do + @stack.use "UnknownMiddleware" + @stack.use :"MiddlewareStackTest::BazMiddleware" + assert @stack.include?("::MiddlewareStackTest::BazMiddleware") + end end -- cgit v1.2.3 From 49be3316c21ae1b779fc26a5eb51890deff56915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 25 Jan 2010 23:38:47 +0100 Subject: Add a deprecation for helpers_dir. --- actionpack/lib/action_controller/metal/helpers.rb | 12 ++++++++++++ actionpack/test/controller/helper_test.rb | 15 +++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/metal/helpers.rb b/actionpack/lib/action_controller/metal/helpers.rb index 0e3db86861..ef3b89db14 100644 --- a/actionpack/lib/action_controller/metal/helpers.rb +++ b/actionpack/lib/action_controller/metal/helpers.rb @@ -56,6 +56,18 @@ module ActionController end module ClassMethods + def helpers_dir + ActiveSupport::Deprecation.warn "ActionController::Base.helpers_dir is deprecated. " << + "Please use ActionController::Base.helpers_path (which returns an array)" + self.helpers_path + end + + def helpers_dir=(value) + ActiveSupport::Deprecation.warn "ActionController::Base.helpers_dir= is deprecated. " << + "Please use ActionController::Base.helpers_path= (which is an array)" + self.helpers_path = Array(value) + end + def inherited(klass) klass.class_eval { default_helper_module! unless name.blank? } super diff --git a/actionpack/test/controller/helper_test.rb b/actionpack/test/controller/helper_test.rb index fe0961e575..75a96d6497 100644 --- a/actionpack/test/controller/helper_test.rb +++ b/actionpack/test/controller/helper_test.rb @@ -31,7 +31,7 @@ module LocalAbcHelper def c() end end -class HelperTest < Test::Unit::TestCase +class HelperTest < ActiveSupport::TestCase class TestController < ActionController::Base attr_accessor :delegate_attr def delegate_method() end @@ -135,6 +135,17 @@ class HelperTest < Test::Unit::TestCase assert methods.include?('foobar') end + def test_deprecation + assert_deprecated do + ActionController::Base.helpers_dir = "some/foo/bar" + end + assert_deprecated do + assert_equal ["some/foo/bar"], ActionController::Base.helpers_dir + end + ensure + ActionController::Base.helpers_path = [File.dirname(__FILE__) + '/../fixtures/helpers'] + end + private def expected_helper_methods TestHelper.instance_methods.map {|m| m.to_s } @@ -154,7 +165,7 @@ class HelperTest < Test::Unit::TestCase end -class IsolatedHelpersTest < Test::Unit::TestCase +class IsolatedHelpersTest < ActiveSupport::TestCase class A < ActionController::Base def index render :inline => '<%= shout %>' -- cgit v1.2.3 From 8974dac92e05dcab8ee552a5f40108c6ac25dc36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 26 Jan 2010 00:55:26 +0100 Subject: Ensure root routes inside optional scopes works as expected. --- actionpack/lib/action_dispatch/routing/mapper.rb | 5 +++-- actionpack/test/dispatch/routing_test.rb | 21 ++++++++++++++------- 2 files changed, 17 insertions(+), 9 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index fcbb70749f..5199984814 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -157,10 +157,11 @@ module ActionDispatch end # Invokes Rack::Mount::Utils.normalize path and ensure that - # (:locale) becomes (/:locale) instead of /(:locale). + # (:locale) becomes (/:locale) instead of /(:locale). Except + # for root cases, where the latter is the correct one. def self.normalize_path(path) path = Rack::Mount::Utils.normalize_path(path) - path.sub!(%r{/\(+/?:}, '(/:') + path.sub!(%r{/(\(+)/?:}, '\1/:') unless path =~ %r{^/\(+:.*\)$} path end diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 6dccabdb3f..dfe824fd70 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -141,19 +141,18 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest resources :rooms end - scope '(:locale)', :locale => /en|pl/ do - resources :descriptions - end + match '/info' => 'projects#info', :as => 'info' namespace :admin do - scope '(/:locale)', :locale => /en|pl/ do + scope '(:locale)', :locale => /en|pl/ do resources :descriptions end end - match '/info' => 'projects#info', :as => 'info' - - root :to => 'projects#index' + scope '(:locale)', :locale => /en|pl/ do + resources :descriptions + root :to => 'projects#index' + end end end @@ -660,6 +659,14 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end + def test_optional_scoped_root + with_test_routes do + assert_equal '/en', root_path("en") + get '/en' + assert_equal 'projects#index', @response.body + end + end + def test_optional_scoped_path with_test_routes do assert_equal '/en/descriptions', descriptions_path("en") -- cgit v1.2.3 From f74fbf9d326091200121d42cd895588d5371daa7 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Tue, 26 Jan 2010 08:51:50 -0600 Subject: Keep ActionController::Base.helpers_dir around for a bit longer --- actionpack/lib/action_controller/metal/helpers.rb | 70 +++++++++++------------ 1 file changed, 33 insertions(+), 37 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/metal/helpers.rb b/actionpack/lib/action_controller/metal/helpers.rb index ef3b89db14..0ebdf07911 100644 --- a/actionpack/lib/action_controller/metal/helpers.rb +++ b/actionpack/lib/action_controller/metal/helpers.rb @@ -57,14 +57,10 @@ module ActionController module ClassMethods def helpers_dir - ActiveSupport::Deprecation.warn "ActionController::Base.helpers_dir is deprecated. " << - "Please use ActionController::Base.helpers_path (which returns an array)" self.helpers_path end def helpers_dir=(value) - ActiveSupport::Deprecation.warn "ActionController::Base.helpers_dir= is deprecated. " << - "Please use ActionController::Base.helpers_path= (which is an array)" self.helpers_path = Array(value) end @@ -91,42 +87,42 @@ module ActionController @helper_proxy ||= ActionView::Base.new.extend(_helpers) end - private - # Overwrite _modules_for_helpers to accept :all as argument, which loads - # all helpers in helpers_dir. - # - # ==== Parameters - # args:: A list of helpers - # - # ==== Returns - # Array[Module]:: A normalized list of modules for the list of - # helpers provided. - def _modules_for_helpers(args) - args += all_application_helpers if args.delete(:all) - super(args) - end + private + # Overwrite _modules_for_helpers to accept :all as argument, which loads + # all helpers in helpers_dir. + # + # ==== Parameters + # args:: A list of helpers + # + # ==== Returns + # Array[Module]:: A normalized list of modules for the list of + # helpers provided. + def _modules_for_helpers(args) + args += all_application_helpers if args.delete(:all) + super(args) + end - def default_helper_module! - module_name = name.sub(/Controller$/, '') - module_path = module_name.underscore - helper module_path - rescue MissingSourceFile => e - raise e unless e.is_missing? "helpers/#{module_path}_helper" - rescue NameError => e - raise e unless e.missing_name? "#{module_name}Helper" - end + def default_helper_module! + module_name = name.sub(/Controller$/, '') + module_path = module_name.underscore + helper module_path + rescue MissingSourceFile => e + raise e unless e.is_missing? "helpers/#{module_path}_helper" + rescue NameError => e + raise e unless e.missing_name? "#{module_name}Helper" + end - # Extract helper names from files in app/helpers/**/*_helper.rb - def all_application_helpers - helpers = [] - helpers_path.each do |path| - extract = /^#{Regexp.quote(path)}\/?(.*)_helper.rb$/ - helpers += Dir["#{path}/**/*_helper.rb"].map { |file| file.sub(extract, '\1') } + # Extract helper names from files in app/helpers/**/*_helper.rb + def all_application_helpers + helpers = [] + helpers_path.each do |path| + extract = /^#{Regexp.quote(path)}\/?(.*)_helper.rb$/ + helpers += Dir["#{path}/**/*_helper.rb"].map { |file| file.sub(extract, '\1') } + end + helpers.sort! + helpers.uniq! + helpers end - helpers.sort! - helpers.uniq! - helpers - end end end end -- cgit v1.2.3 From e274eb1df1dcf526febb7c3a1a8dc2c02325d68c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 26 Jan 2010 16:34:25 +0100 Subject: Bring layouts with proc back alive. --- actionpack/lib/abstract_controller/layouts.rb | 3 +++ actionpack/test/abstract/layouts_test.rb | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb index 6fbf6bc392..56ddf9bf01 100644 --- a/actionpack/lib/abstract_controller/layouts.rb +++ b/actionpack/lib/abstract_controller/layouts.rb @@ -270,6 +270,9 @@ module AbstractController end end ruby_eval + when Proc + define_method :_layout_from_proc, &@_layout + self.class_eval %{def _layout(details) _layout_from_proc(self) end} when false self.class_eval %{def _layout(details) end} when true diff --git a/actionpack/test/abstract/layouts_test.rb b/actionpack/test/abstract/layouts_test.rb index df73d948f0..8cbb72dc83 100644 --- a/actionpack/test/abstract/layouts_test.rb +++ b/actionpack/test/abstract/layouts_test.rb @@ -67,7 +67,15 @@ module AbstractControllerTests class WithChildOfImplied < WithStringImpliedChild end - + + class WithProc < Base + layout proc { |c| "omg" } + + def index + render :_template => ActionView::Template::Text.new("Hello proc!") + end + end + class WithSymbol < Base layout :hello @@ -198,6 +206,12 @@ module AbstractControllerTests controller.process(:index) assert_equal "Hello nil!", controller.response_body end + + test "when layout is specified as a proc, call it and use the layout returned" do + controller = WithProc.new + controller.process(:index) + assert_equal "OMGHI2U Hello proc!", controller.response_body + end test "when layout is specified as a symbol, call the requested method and use the layout returned" do controller = WithSymbol.new -- cgit v1.2.3 From dc57d545bb3e8ff4123892e5e311e658ab506252 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 26 Jan 2010 20:43:35 +0100 Subject: Fix t('.helper'). --- actionpack/lib/action_view/base.rb | 6 ++++-- .../lib/action_view/helpers/translation_helper.rb | 8 ++++++-- actionpack/lib/action_view/template.rb | 4 ++-- actionpack/lib/action_view/template/resolver.rb | 13 ++++++++----- actionpack/test/controller/helper_test.rb | 21 +++++++++++---------- actionpack/test/fixtures/test/translation.erb | 1 + actionpack/test/template/translation_helper_test.rb | 10 +++++----- 7 files changed, 37 insertions(+), 26 deletions(-) create mode 100644 actionpack/test/fixtures/test/translation.erb (limited to 'actionpack') diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index c4b0455c2a..af13f2cd3e 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -276,9 +276,11 @@ module ActionView #:nodoc: @config = nil @formats = formats @assigns = assigns_for_first_render.each { |key, value| instance_variable_set("@#{key}", value) } - @_controller = controller @helpers = self.class.helpers || Module.new - @_content_for = Hash.new {|h,k| h[k] = ActionView::SafeBuffer.new } + + @_controller = controller + @_content_for = Hash.new {|h,k| h[k] = ActionView::SafeBuffer.new } + @_virtual_path = nil self.view_paths = view_paths end diff --git a/actionpack/lib/action_view/helpers/translation_helper.rb b/actionpack/lib/action_view/helpers/translation_helper.rb index 35c431d78d..ad18339c60 100644 --- a/actionpack/lib/action_view/helpers/translation_helper.rb +++ b/actionpack/lib/action_view/helpers/translation_helper.rb @@ -25,11 +25,15 @@ module ActionView end alias :l :localize - private + def scope_key_by_partial(key) if key.to_s.first == "." - template.path_without_format_and_extension.gsub(%r{/_?}, ".") + key.to_s + if @_virtual_path + @_virtual_path.gsub(%r{/_?}, ".") + key.to_s + else + raise "Cannot use t(#{key.inspect}) shortcut because path is not available" + end else key end diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb index adaf6544a7..cd6b1930a1 100644 --- a/actionpack/lib/action_view/template.rb +++ b/actionpack/lib/action_view/template.rb @@ -87,9 +87,9 @@ module ActionView source = <<-end_src def #{method_name}(local_assigns) - old_output_buffer = output_buffer;#{locals_code};#{code} + _old_virtual_path, @_virtual_path = @_virtual_path, #{@details[:virtual_path].inspect};_old_output_buffer = output_buffer;#{locals_code};#{code} ensure - self.output_buffer = old_output_buffer + @_virtual_path, self.output_buffer = _old_virtual_path, _old_output_buffer end end_src diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index c6a17907ff..340a6afe5e 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -117,15 +117,18 @@ module ActionView # # :api: plugin def path_to_details(path) # [:erb, :format => :html, :locale => :en, :partial => true/false] - if m = path.match(%r'(?:^|/)(_)?[\w-]+((?:\.[\w-]+)*)\.(\w+)$') - partial = m[1] == '_' - details = (m[2]||"").split('.').reject { |e| e.empty? } - handler = Template.handler_class_for_extension(m[3]) + if m = path.match(%r'((^|.*/)(_)?[\w-]+)((?:\.[\w-]+)*)\.(\w+)$') + partial = m[3] == '_' + details = (m[4]||"").split('.').reject { |e| e.empty? } + handler = Template.handler_class_for_extension(m[5]) format = Mime[details.last] && details.pop.to_sym locale = details.last && details.pop.to_sym - return handler, :format => format, :locale => locale, :partial => partial + virtual_path = (m[1].gsub("#{@path}/", "") << details.join(".")) + + return handler, :format => format, :locale => locale, :partial => partial, + :virtual_path => virtual_path end end end diff --git a/actionpack/test/controller/helper_test.rb b/actionpack/test/controller/helper_test.rb index 75a96d6497..e53e62d1ff 100644 --- a/actionpack/test/controller/helper_test.rb +++ b/actionpack/test/controller/helper_test.rb @@ -135,16 +135,17 @@ class HelperTest < ActiveSupport::TestCase assert methods.include?('foobar') end - def test_deprecation - assert_deprecated do - ActionController::Base.helpers_dir = "some/foo/bar" - end - assert_deprecated do - assert_equal ["some/foo/bar"], ActionController::Base.helpers_dir - end - ensure - ActionController::Base.helpers_path = [File.dirname(__FILE__) + '/../fixtures/helpers'] - end + # TODO Add this deprecation back before Rails 3.0 final release + # def test_deprecation + # assert_deprecated do + # ActionController::Base.helpers_dir = "some/foo/bar" + # end + # assert_deprecated do + # assert_equal ["some/foo/bar"], ActionController::Base.helpers_dir + # end + # ensure + # ActionController::Base.helpers_path = [File.dirname(__FILE__) + '/../fixtures/helpers'] + # end private def expected_helper_methods diff --git a/actionpack/test/fixtures/test/translation.erb b/actionpack/test/fixtures/test/translation.erb new file mode 100644 index 0000000000..81a837d1ff --- /dev/null +++ b/actionpack/test/fixtures/test/translation.erb @@ -0,0 +1 @@ +<%= t('.helper') %> \ No newline at end of file diff --git a/actionpack/test/template/translation_helper_test.rb b/actionpack/test/template/translation_helper_test.rb index d67d2c7911..4b73c44f7e 100644 --- a/actionpack/test/template/translation_helper_test.rb +++ b/actionpack/test/template/translation_helper_test.rb @@ -1,9 +1,9 @@ require 'abstract_unit' -class TranslationHelperTest < Test::Unit::TestCase +class TranslationHelperTest < ActiveSupport::TestCase include ActionView::Helpers::TagHelper include ActionView::Helpers::TranslationHelper - + attr_reader :request def setup end @@ -25,8 +25,8 @@ class TranslationHelperTest < Test::Unit::TestCase end def test_scoping_by_partial - expects(:template).returns(stub(:path_without_format_and_extension => "people/index")) - I18n.expects(:translate).with("people.index.foo", :locale => 'en', :raise => true).returns("") - translate ".foo", :locale => 'en' + I18n.expects(:translate).with("test.translation.helper", :raise => true).returns("helper") + @view = ActionView::Base.new(ActionController::Base.view_paths, {}) + assert_equal "helper", @view.render(:file => "test/translation") end end -- cgit v1.2.3 From 6404feee500dc5a2268da1e41af08a5ff847338a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 26 Jan 2010 21:05:50 +0100 Subject: AC railtie should configure helpers path. --- actionpack/lib/action_controller/metal/helpers.rb | 5 ++--- actionpack/lib/action_controller/railtie.rb | 4 ++++ 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/metal/helpers.rb b/actionpack/lib/action_controller/metal/helpers.rb index 0ebdf07911..03ba4b3f83 100644 --- a/actionpack/lib/action_controller/metal/helpers.rb +++ b/actionpack/lib/action_controller/metal/helpers.rb @@ -50,9 +50,8 @@ module ActionController include AbstractController::Helpers included do - extlib_inheritable_accessor(:helpers_path) do - defined?(Rails::Application) ? Rails::Application.paths.app.helpers.to_a : [] - end + extlib_inheritable_accessor(:helpers_path) + self.helpers_path = [] end module ClassMethods diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb index 29a0a346ec..9151de4462 100644 --- a/actionpack/lib/action_controller/railtie.rb +++ b/actionpack/lib/action_controller/railtie.rb @@ -21,5 +21,9 @@ module ActionController initializer "action_controller.initialize_framework_caches" do ActionController::Base.cache_store ||= RAILS_CACHE end + + initializer "action_controller.set_helpers_path" do |app| + ActionController::Base.helpers_path = app.config.paths.app.helpers.to_a + end end end -- cgit v1.2.3 From 7d312e54bad9c39634c137caec07dfc8df471650 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Tue, 26 Jan 2010 22:57:27 +0100 Subject: deletes no void files removal.rb and class_test.rb --- actionpack/test/abstract/layouts_test.rb | 1 - 1 file changed, 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/test/abstract/layouts_test.rb b/actionpack/test/abstract/layouts_test.rb index df73d948f0..5c96d1cfff 100644 --- a/actionpack/test/abstract/layouts_test.rb +++ b/actionpack/test/abstract/layouts_test.rb @@ -1,5 +1,4 @@ require 'abstract_unit' -require 'active_support/core_ext/class/removal' module AbstractControllerTests module Layouts -- cgit v1.2.3 From 3c6891593d84b83c70441b4c953080481bdcc4bf Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Tue, 26 Jan 2010 23:08:00 +0100 Subject: removes now void extending.rb --- actionpack/lib/action_view/helpers/prototype_helper.rb | 1 - 1 file changed, 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index ff7bc3b34e..bef93dd0f8 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -1,6 +1,5 @@ require 'set' require 'active_support/json' -require 'active_support/core_ext/object/extending' require 'active_support/core_ext/object/returning' module ActionView -- cgit v1.2.3 From a792ee5665fff4bd3751e97e1d949b60e73e333d Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Wed, 23 Sep 2009 00:18:10 -0700 Subject: Added the beginnings of the observe_field helper --- actionpack/lib/action_view/helpers/ajax_helper.rb | 14 +++++- actionpack/test/template/ajax_test.rb | 55 +++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 9cc2acc239..1246ec7107 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -33,7 +33,19 @@ module ActionView tag(:input, html_options) end - + + def observe_field(name, options = {}, html_options = {}) + url = options.delete(:url) + url = url_for(url) if url.is_a?(Hash) + + if frequency = options.delete(:frequency) + html_options[:"data-frequency"] = frequency + end + + html_options.merge!(:"data-observe" => true, :"data-url" => url) + tag(:input, html_options) + end + module Rails2Compatibility def set_callbacks(options, html) [:complete, :failure, :success, :interactive, :loaded, :loading].each do |type| diff --git a/actionpack/test/template/ajax_test.rb b/actionpack/test/template/ajax_test.rb index aeb7c09b09..d212134d1d 100644 --- a/actionpack/test/template/ajax_test.rb +++ b/actionpack/test/template/ajax_test.rb @@ -112,3 +112,58 @@ class ButtonToRemoteTest < AjaxTestCase end end end + +class ObserveFieldTest < AjaxTestCase + def url_for(hash) + "/blog/update" + end + + def protect_against_forgery? + false + end + + def field(options = {}) + observe_field("title", options) + end + + test "basic" do + assert_html field, + %w(data-observe="true") + end + + test "with a :frequency option" do + assert_html field(:frequency => 5.minutes), + %w(data-observe="true" data-frequency="300") + end + + test "using a url string" do + assert_html field(:url => "/some/other/url"), + %w(data-observe="true" data-url="/some/other/url") + end + + test "using a url hash" do + assert_html field(:url => {:controller => :blog, :action => :update}), + %w(data-observe="true" data-url="/blog/update") + end + +# def test_observe_field +# assert_dom_equal %(), +# observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" }) +# end +# +# def test_observe_field_using_with_option +# expected = %() +# assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => 'id') +# assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "'id=' + encodeURIComponent(value)") +# end +# +# def test_observe_field_using_json_in_with_option +# expected = %() +# assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "{'id':value}") +# end +# +# def test_observe_field_using_function_for_callback +# assert_dom_equal %(), +# observe_field("glass", :frequency => 5.minutes, :function => "alert('Element changed')") +# end +end -- cgit v1.2.3 From c44682f6ab7f9b6dd3773752723aa8c46d019bde Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Wed, 23 Sep 2009 01:05:45 -0700 Subject: Implemented a fuller stub in AjaxTestCase for url_for because link_to calls url_for on all urls passed to it. Tests that were testing different input types for the url were failing because of this. --- actionpack/lib/action_view/helpers/ajax_helper.rb | 2 +- actionpack/test/template/ajax_test.rb | 37 +++++++++++++++++------ 2 files changed, 29 insertions(+), 10 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 1246ec7107..3be8878f97 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -19,7 +19,7 @@ module ActionView html["data-remote"] = "true" html.merge!(options) - + url = url_for(url) if url.is_a?(Hash) link_to(name, url, html) end diff --git a/actionpack/test/template/ajax_test.rb b/actionpack/test/template/ajax_test.rb index d212134d1d..afaa16874d 100644 --- a/actionpack/test/template/ajax_test.rb +++ b/actionpack/test/template/ajax_test.rb @@ -4,6 +4,17 @@ class AjaxTestCase < ActiveSupport::TestCase include ActionView::Helpers::AjaxHelper include ActionView::Helpers::TagHelper + def url_for(url) + case url + when Hash + "/url/hash" + when String + url + else + raise TypeError.new("Unsupported url type (#{url.class}) for this test helper") + end + end + def assert_html(html, matches) matches.each do |match| assert_match(Regexp.new(Regexp.escape(match)), html) @@ -23,26 +34,27 @@ class AjaxTestCase < ActiveSupport::TestCase end class LinkToRemoteTest < AjaxTestCase - def url_for(hash) - "/blog/destroy/4" - end - def link(options = {}) link_to_remote("Delete this post", "/blog/destroy/3", options) end - test "with no update" do - assert_html link, %w(href="/blog/destroy/4" Delete\ this\ post data-remote="true") - end - test "basic" do assert_html link(:update => "#posts"), %w(data-update-success="#posts") end + test "using a url string" do + assert_html link_to_remote("Test", "/blog/update/1"), + %w(href="/blog/update/1") + end + test "using a url hash" do link = link_to_remote("Delete this post", {:controller => :blog}, :update => "#posts") - assert_html link, %w(href="/blog/destroy/4" data-update-success="#posts") + assert_html link, %w(href="/url/hash" data-update-success="#posts") + end + + test "with no update" do + assert_html link, %w(href="/blog/destroy/4" Delete\ this\ post data-remote="true") end test "with :html options" do @@ -90,6 +102,7 @@ class ButtonToRemoteTest < AjaxTestCase button_to_remote("Remote outpost", options, html) end +<<<<<<< HEAD:actionpack/test/template/ajax_test.rb def url_for(*) "/whatnot" end @@ -101,6 +114,12 @@ class ButtonToRemoteTest < AjaxTestCase /data-url="\/whatnot"/].each do |match| assert_match(match, button) end +======= + class StandardTest < ButtonToRemoteTest + test "basic" do + assert_html button({:url => {:action => "whatnot"}}, {:class => "fine"}), + %w(input class="fine" type="button" value="Remote outpost" data-url="/url/hash") +>>>>>>> ea876bd... Implemented a fuller stub in AjaxTestCase for url_for because link_to calls url_for on all urls passed to it. Tests that were testing different input types for the url were failing because of this.:actionpack/test/javascript/ajax_test.rb end end -- cgit v1.2.3 From 77fc50a08be40abe7eea715755b5497f0e9b91f5 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 21 Jan 2010 17:21:43 -0600 Subject: fixed failing tests --- actionpack/test/javascript/ajax_test.rb | 114 ++++++++++++++++++++++++++++++++ actionpack/test/template/ajax_test.rb | 22 ++---- 2 files changed, 118 insertions(+), 18 deletions(-) create mode 100644 actionpack/test/javascript/ajax_test.rb (limited to 'actionpack') diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb new file mode 100644 index 0000000000..b616bba703 --- /dev/null +++ b/actionpack/test/javascript/ajax_test.rb @@ -0,0 +1,114 @@ +require "abstract_unit" + +class AjaxTestCase < ActiveSupport::TestCase + include ActionView::Helpers::AjaxHelper + include ActionView::Helpers::TagHelper + + def assert_html(html, matches) + matches.each do |match| + assert_match Regexp.new(Regexp.escape(match)), html + end + end + + def self.assert_callbacks_work(&blk) + define_method(:assert_callbacks_work, &blk) + + [:complete, :failure, :success, :interactive, :loaded, :loading, 404].each do |callback| + test "#{callback} callback" do + markup = assert_callbacks_work(callback) + assert_html markup, %W(data-#{callback}-code="undoRequestCompleted\(request\)") + end + end + end +end + +class LinkToRemoteTest < AjaxTestCase + def url_for(hash) + "/blog/destroy/4" + end + + def link(options = {}) + link_to_remote("Delete this post", "/blog/destroy/4", options) + end + + test "with no update" do + assert_html link, %w(href="/blog/destroy/4" Delete\ this\ post data-remote="true") + end + + test "basic" do + assert_html link(:update => "#posts"), + %w(data-update-success="#posts") + end + + test "using a url hash" do + link = link_to_remote("Delete this post", {:controller => :blog}, :update => "#posts") + assert_html link, %w(href="/blog/destroy/4" data-update-success="#posts") + end + + test "with :html options" do + expected = %{Delete this post} + assert_equal expected, link(:update => "#posts", :html => {"data-custom" => "me"}) + end + + test "with a hash for :update" do + link = link(:update => {:success => "#posts", :failure => "#error"}) + assert_html link, %w(data-remote="true" data-update-success="#posts" data-update-failure="#error") + end + + test "with positional parameters" do + link = link(:position => :top, :update => "#posts") + assert_match /data\-update\-position="top"/, link + end + + test "with an optional method" do + link = link(:method => "delete") + assert_match /data-method="delete"/, link + end + + class LegacyLinkToRemoteTest < AjaxTestCase + include ActionView::Helpers::AjaxHelper::Rails2Compatibility + + def link(options) + link_to_remote("Delete this post", "/blog/destroy/4", options) + end + + test "basic link_to_remote with :url =>" do + expected = %{Delete this post} + assert_equal expected, + link_to_remote("Delete this post", :url => "/blog/destroy/4", :update => "#posts") + end + + assert_callbacks_work do |callback| + link(callback => "undoRequestCompleted(request)") + end + end +end + +class ButtonToRemoteTest < AjaxTestCase + def button(options, html = {}) + button_to_remote("Remote outpost", options, html) + end + + def url_for(*) + "/whatnot" + end + + class StandardTest < ButtonToRemoteTest + test "basic" do + button = button({:url => {:action => "whatnot"}}, {:class => "fine"}) + [/input/, /class="fine"/, /type="button"/, /value="Remote outpost"/, + /data-url="\/whatnot"/].each do |match| + assert_match match, button + end + end + end + + class LegacyButtonToRemoteTest < ButtonToRemoteTest + include ActionView::Helpers::AjaxHelper::Rails2Compatibility + + assert_callbacks_work do |callback| + button(callback => "undoRequestCompleted(request)") + end + end + +end \ No newline at end of file diff --git a/actionpack/test/template/ajax_test.rb b/actionpack/test/template/ajax_test.rb index afaa16874d..86932d754f 100644 --- a/actionpack/test/template/ajax_test.rb +++ b/actionpack/test/template/ajax_test.rb @@ -54,11 +54,11 @@ class LinkToRemoteTest < AjaxTestCase end test "with no update" do - assert_html link, %w(href="/blog/destroy/4" Delete\ this\ post data-remote="true") + assert_html link, %w(href="/blog/destroy/3" Delete\ this\ post data-remote="true") end test "with :html options" do - expected = %{Delete this post} + expected = %{Delete this post} assert_equal expected, link(:update => "#posts", :html => {"data-custom" => "me"}) end @@ -86,9 +86,9 @@ class LinkToRemoteTest < AjaxTestCase end test "basic link_to_remote with :url =>" do - expected = %{Delete this post} + expected = %{Delete this post} assert_equal expected, - link_to_remote("Delete this post", :url => "/blog/destroy/3", :update => "#posts") + link_to_remote("Delete this post", :url => "/blog/destroy/4", :update => "#posts") end assert_callbacks_work do |callback| @@ -102,24 +102,10 @@ class ButtonToRemoteTest < AjaxTestCase button_to_remote("Remote outpost", options, html) end -<<<<<<< HEAD:actionpack/test/template/ajax_test.rb - def url_for(*) - "/whatnot" - end - - class StandardTest < ButtonToRemoteTest - test "basic" do - button = button({:url => {:action => "whatnot"}}, {:class => "fine"}) - [/input/, /class="fine"/, /type="button"/, /value="Remote outpost"/, - /data-url="\/whatnot"/].each do |match| - assert_match(match, button) - end -======= class StandardTest < ButtonToRemoteTest test "basic" do assert_html button({:url => {:action => "whatnot"}}, {:class => "fine"}), %w(input class="fine" type="button" value="Remote outpost" data-url="/url/hash") ->>>>>>> ea876bd... Implemented a fuller stub in AjaxTestCase for url_for because link_to calls url_for on all urls passed to it. Tests that were testing different input types for the url were failing because of this.:actionpack/test/javascript/ajax_test.rb end end -- cgit v1.2.3 From fab8b25c15064a020e62e2baca11ed1f551f4d6f Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Wed, 23 Sep 2009 01:15:31 -0700 Subject: ObserveFieldTest uses url_for from AjaxTestCase --- actionpack/test/javascript/ajax_test.rb | 52 ++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb index b616bba703..6539583398 100644 --- a/actionpack/test/javascript/ajax_test.rb +++ b/actionpack/test/javascript/ajax_test.rb @@ -110,5 +110,55 @@ class ButtonToRemoteTest < AjaxTestCase button(callback => "undoRequestCompleted(request)") end end +end + +class ObserveFieldTest < AjaxTestCase + def protect_against_forgery? + false + end + + def field(options = {}) + observe_field("title", options) + end + + test "basic" do + assert_html field, + %w(data-observe="true") + end + + test "with a :frequency option" do + assert_html field(:frequency => 5.minutes), + %w(data-observe="true" data-frequency="300") + end -end \ No newline at end of file + test "using a url string" do + assert_html field(:url => "/some/other/url"), + %w(data-observe="true" data-url="/some/other/url") + end + + test "using a url hash" do + assert_html field(:url => {:controller => :blog, :action => :update}), + %w(data-observe="true" data-url="/url/hash") + end + +# def test_observe_field +# assert_dom_equal %(), +# observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" }) +# end +# +# def test_observe_field_using_with_option +# expected = %() +# assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => 'id') +# assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "'id=' + encodeURIComponent(value)") +# end +# +# def test_observe_field_using_json_in_with_option +# expected = %() +# assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "{'id':value}") +# end +# +# def test_observe_field_using_function_for_callback +# assert_dom_equal %(), +# observe_field("glass", :frequency => 5.minutes, :function => "alert('Element changed')") +# end +end -- cgit v1.2.3 From 88e793e5e77efbd43a5a2bb4eaba283255f6a262 Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Wed, 23 Sep 2009 15:06:56 -0700 Subject: Changed the observe field node into a div with display:none --- actionpack/lib/action_view/helpers/ajax_helper.rb | 11 ++++++++--- actionpack/test/javascript/ajax_test.rb | 20 ++++++++++++-------- 2 files changed, 20 insertions(+), 11 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 3be8878f97..6a13bcb432 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -38,12 +38,17 @@ module ActionView url = options.delete(:url) url = url_for(url) if url.is_a?(Hash) - if frequency = options.delete(:frequency) + frequency = options.delete(:frequency) + if frequency && frequency > 0 html_options[:"data-frequency"] = frequency end - html_options.merge!(:"data-observe" => true, :"data-url" => url) - tag(:input, html_options) + html_options.merge!(:style => "display:none", + :"data-observe-field" => name, + :"data-observe" => true, + :"data-url" => url) + + tag(:div, html_options) end module Rails2Compatibility diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb index 6539583398..e46e346d79 100644 --- a/actionpack/test/javascript/ajax_test.rb +++ b/actionpack/test/javascript/ajax_test.rb @@ -123,22 +123,26 @@ class ObserveFieldTest < AjaxTestCase test "basic" do assert_html field, - %w(data-observe="true") - end - - test "with a :frequency option" do - assert_html field(:frequency => 5.minutes), - %w(data-observe="true" data-frequency="300") + %w(div style="display:none" data-observe="true" data-observe-field="title") end test "using a url string" do assert_html field(:url => "/some/other/url"), - %w(data-observe="true" data-url="/some/other/url") + %w(data-url="/some/other/url") end test "using a url hash" do assert_html field(:url => {:controller => :blog, :action => :update}), - %w(data-observe="true" data-url="/url/hash") + %w(data-url="/url/hash") + end + + test "with a :frequency option" do + assert_html field(:frequency => 5.minutes), + %w(data-frequency="300") + end + + test "with a :frequency option of 0" do + assert_no_match /data-frequency/, field(:frequency => 0) end # def test_observe_field -- cgit v1.2.3 From 6fa8f81d7d730527f92d8e373dfc32199799681b Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Thu, 24 Sep 2009 00:18:52 -0700 Subject: Took another stab at observe_field. Now implementing data only helpers as script elements. --- actionpack/lib/action_view/helpers/ajax_helper.rb | 52 ++++++++++++++++++----- actionpack/test/javascript/ajax_test.rb | 51 ++++++++++++---------- 2 files changed, 69 insertions(+), 34 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 6a13bcb432..43856acbc8 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -34,21 +34,51 @@ module ActionView tag(:input, html_options) end - def observe_field(name, options = {}, html_options = {}) - url = options.delete(:url) - url = url_for(url) if url.is_a?(Hash) + def observe_field(name, options = {}) + if options[:url] + options[:url] = options[:url].is_a?(Hash) ? url_for(options[:url]) : options[:url] + end + + if options[:frequency] + case options[:frequency] + when 0 + options.delete(:frequency) + else + options[:frequency] = options[:frequency].to_i + end + end + + if options[:with] && (options[:with] !~ /[\{=(.]/) + options[:with] = "'#{options[:with]}=' + encodeURIComponent(value)" + else + options[:with] ||= 'value' unless options[:function] + end - frequency = options.delete(:frequency) - if frequency && frequency > 0 - html_options[:"data-frequency"] = frequency + if options[:function] + statements = options[:function] # || remote_function(options) # TODO: Need to implement remote function - BR + options[:function] = JSFunction.new(statements, "element", "value") end - html_options.merge!(:style => "display:none", - :"data-observe-field" => name, - :"data-observe" => true, - :"data-url" => url) + options[:name] = name + + <<-SCRIPT + + SCRIPT + end - tag(:div, html_options) + # TODO: Move to javascript helpers - BR + class JSFunction + def initialize(statements, *arguments) + @statements, @arguments = statements, arguments + end + + def as_json(options = nil) + "function(#{@arguments.join(", ")}) {#{@statements}}" + end end module Rails2Compatibility diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb index e46e346d79..97a69ba732 100644 --- a/actionpack/test/javascript/ajax_test.rb +++ b/actionpack/test/javascript/ajax_test.rb @@ -112,6 +112,8 @@ class ButtonToRemoteTest < AjaxTestCase end end +# TODO: We need a better way to test JSON being returned from data only helpers - BR +# TODO: We might also need a lower level data only helper method??? - BR class ObserveFieldTest < AjaxTestCase def protect_against_forgery? false @@ -123,46 +125,49 @@ class ObserveFieldTest < AjaxTestCase test "basic" do assert_html field, - %w(div style="display:none" data-observe="true" data-observe-field="title") + %w(script type="application/json" data-rails-type="observe_field") end test "using a url string" do assert_html field(:url => "/some/other/url"), - %w(data-url="/some/other/url") + %w("url":"/some/other/url") end test "using a url hash" do assert_html field(:url => {:controller => :blog, :action => :update}), - %w(data-url="/url/hash") + %w("url":"/url/hash") end - test "with a :frequency option" do + test "using a :frequency option" do assert_html field(:frequency => 5.minutes), - %w(data-frequency="300") + %w("frequency":300) end - test "with a :frequency option of 0" do - assert_no_match /data-frequency/, field(:frequency => 0) + test "using a :frequency option of 0" do + assert_no_match /frequency/, field(:frequency => 0) end + # TODO: Finish when remote_function or some equivilent is finished -BR # def test_observe_field # assert_dom_equal %(), # observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" }) # end -# -# def test_observe_field_using_with_option -# expected = %() -# assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => 'id') -# assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "'id=' + encodeURIComponent(value)") -# end -# -# def test_observe_field_using_json_in_with_option -# expected = %() -# assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "{'id':value}") -# end -# -# def test_observe_field_using_function_for_callback -# assert_dom_equal %(), -# observe_field("glass", :frequency => 5.minutes, :function => "alert('Element changed')") -# end + + # TODO: Consider using JSON instead of strings. Is using 'value' as a magical reference to the value of the observed field weird? (Rails2 does this) - BR + test "using a :with option" do + assert_html field(:with => "foo"), + %w("with":"'foo=' + encodeURIComponent(value)") + assert_html field(:with => "'foo=' + encodeURIComponent(value)"), + %w("with":"'foo=' + encodeURIComponent(value)") + end + + test "using json in a :with option" do + assert_html field(:with => "{'id':value}"), + %w("with":"{'id':value}") + end + + test "using :function for callback" do + assert_html field(:function => "alert('Element changed')"), + %w("function":"function(element, value) {alert('Element changed')}") + end end -- cgit v1.2.3 From 0955f5791555127d2ea3ab1c8a2450bca5a4236a Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Thu, 24 Sep 2009 21:12:11 -0700 Subject: Added assert_data_element_json test helper for data element helpers --- actionpack/lib/action_view/helpers/ajax_helper.rb | 10 +++--- actionpack/test/javascript/ajax_test.rb | 44 ++++++++++++++--------- 2 files changed, 34 insertions(+), 20 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 43856acbc8..688a5262c7 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -48,10 +48,12 @@ module ActionView end end - if options[:with] && (options[:with] !~ /[\{=(.]/) - options[:with] = "'#{options[:with]}=' + encodeURIComponent(value)" - else - options[:with] ||= 'value' unless options[:function] + if options[:with] + if options[:with] !~ /[\{=(.]/ + options[:with] = "'#{options[:with]}=' + encodeURIComponent(value)" + else + options[:with] ||= 'value' unless options[:function] + end end if options[:function] diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb index 97a69ba732..dc1f7c14fd 100644 --- a/actionpack/test/javascript/ajax_test.rb +++ b/actionpack/test/javascript/ajax_test.rb @@ -10,6 +10,20 @@ class AjaxTestCase < ActiveSupport::TestCase end end + def extract_json_from_data_element(data_element) + root = HTML::Document.new(data_element).root + script = root.find(:tag => "script") + cdata = script.children.detect {|child| child.to_s =~ / "/some/other/url"), - %w("url":"/some/other/url") + assert_data_element_json field(:url => "/some/other/url"), + "url" => "/some/other/url", "name" => "title" end test "using a url hash" do - assert_html field(:url => {:controller => :blog, :action => :update}), - %w("url":"/url/hash") + assert_data_element_json field(:url => {:controller => :blog, :action => :update}), + "url" => "/url/hash", "name" => "title" end test "using a :frequency option" do - assert_html field(:frequency => 5.minutes), - %w("frequency":300) + assert_data_element_json field(:url => { :controller => :blog }, :frequency => 5.minutes), + "url" => "/url/hash", "name" => "title", "frequency" => 300 end test "using a :frequency option of 0" do @@ -155,19 +167,19 @@ class ObserveFieldTest < AjaxTestCase # TODO: Consider using JSON instead of strings. Is using 'value' as a magical reference to the value of the observed field weird? (Rails2 does this) - BR test "using a :with option" do - assert_html field(:with => "foo"), - %w("with":"'foo=' + encodeURIComponent(value)") - assert_html field(:with => "'foo=' + encodeURIComponent(value)"), - %w("with":"'foo=' + encodeURIComponent(value)") + assert_data_element_json field(:with => "foo"), + "name" => "title", "with" => "'foo=' + encodeURIComponent(value)" + assert_data_element_json field(:with => "'foo=' + encodeURIComponent(value)"), + "name" => "title", "with" => "'foo=' + encodeURIComponent(value)" end test "using json in a :with option" do - assert_html field(:with => "{'id':value}"), - %w("with":"{'id':value}") + assert_data_element_json field(:with => "{'id':value}"), + "name" => "title", "with" => "{'id':value}" end test "using :function for callback" do - assert_html field(:function => "alert('Element changed')"), - %w("function":"function(element, value) {alert('Element changed')}") + assert_data_element_json field(:function => "alert('Element changed')"), + "name" => "title", "function" => "function(element, value) {alert('Element changed')}" end end -- cgit v1.2.3 From 118a720a018fdf7358e619fc9cd949d5f336bf07 Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Fri, 25 Sep 2009 01:27:20 -0700 Subject: Took first stab at reimplementing form_remote_tag helpers --- actionpack/lib/action_view/helpers/ajax_helper.rb | 65 +++++++----- actionpack/test/javascript/ajax_test.rb | 123 ++++++++++++++++++++++ 2 files changed, 164 insertions(+), 24 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 688a5262c7..e127641f4f 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -2,26 +2,41 @@ module ActionView module Helpers module AjaxHelper include UrlHelper - - def link_to_remote(name, url, options = {}) - html = options.delete(:html) || {} + + def form_remote_tag(options = {}, &block) + attributes = {} + attributes.merge!(extract_remote_attributes!(options)) + attributes.merge!(options) + + url = attributes.delete(:url) + form_tag(attributes.delete(:action) || url_for(url), attributes, &block) + end + + def extract_remote_attributes!(options) + attributes = options.delete(:html) || {} update = options.delete(:update) if update.is_a?(Hash) - html["data-update-success"] = update[:success] - html["data-update-failure"] = update[:failure] + attributes["data-update-success"] = update[:success] + attributes["data-update-failure"] = update[:failure] else - html["data-update-success"] = update + attributes["data-update-success"] = update end - html["data-update-position"] = options.delete(:position) - html["data-method"] = options.delete(:method) - html["data-remote"] = "true" - - html.merge!(options) + attributes["data-update-position"] = options.delete(:position) + attributes["data-method"] = options.delete(:method) + attributes["data-remote"] = true + + attributes + end + + def link_to_remote(name, url, options = {}) + attributes = {} + attributes.merge!(extract_remote_attributes!(options)) + attributes.merge!(options) url = url_for(url) if url.is_a?(Hash) - link_to(name, url, html) + link_to(name, url, attributes) end def button_to_remote(name, options = {}, html_options = {}) @@ -72,17 +87,6 @@ module ActionView SCRIPT end - # TODO: Move to javascript helpers - BR - class JSFunction - def initialize(statements, *arguments) - @statements, @arguments = statements, arguments - end - - def as_json(options = nil) - "function(#{@arguments.join(", ")}) {#{@statements}}" - end - end - module Rails2Compatibility def set_callbacks(options, html) [:complete, :failure, :success, :interactive, :loaded, :loading].each do |type| @@ -111,7 +115,20 @@ module ActionView super end end - + + private + + # TODO: Move to javascript helpers - BR + class JSFunction + def initialize(statements, *arguments) + @statements, @arguments = statements, arguments + end + + def as_json(options = nil) + "function(#{@arguments.join(", ")}) {#{@statements}}" + end + end + end end end \ No newline at end of file diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb index dc1f7c14fd..49942f6681 100644 --- a/actionpack/test/javascript/ajax_test.rb +++ b/actionpack/test/javascript/ajax_test.rb @@ -2,7 +2,22 @@ require "abstract_unit" class AjaxTestCase < ActiveSupport::TestCase include ActionView::Helpers::AjaxHelper + + # TODO: Ask Katz: Should these be included by the AjaxHelper? - BR include ActionView::Helpers::TagHelper + include ActionView::Helpers::FormTagHelper + + # TODO: Replace with the real url_for method - BR + def url_for(url) + case url + when Hash + "/url/hash" + when String + url + else + raise TypeError.new("Unsupported url type (#{url.class}) for this test helper") + end + end def assert_html(html, matches) matches.each do |match| @@ -10,6 +25,12 @@ class AjaxTestCase < ActiveSupport::TestCase end end + def assert_html_not_present(html, matches) + matches.each do |match| + assert_no_match Regexp.new(Regexp.escape(match)), html + end + end + def extract_json_from_data_element(data_element) root = HTML::Document.new(data_element).root script = root.find(:tag => "script") @@ -98,6 +119,108 @@ class LinkToRemoteTest < AjaxTestCase end end +class FormRemoteTagTest < AjaxTestCase + + def protect_against_forgery? + false + end + + def request_forgery_protection_token + "token_name" + end + + def form_authenticity_token + "t0k3n" + end + + def authenticity_input_attributes + %w(input type="hidden" name="token_name" value="t0k3n") + end + + # TODO: Play with using assert_dom_equal + test "basic" do + assert_html form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }), + %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer") + end + + test "when protect_against_forgery? is true" do + def protect_against_forgery? + true + end + + expected_form_attributes = %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer") + expected_patterns = expected_form_attributes + authenticity_input_attributes + + assert_equal true, protect_against_forgery? + assert_html form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }), expected_patterns + end + + test ":action is used when it is present" do + html = form_remote_tag(:update => "#glass_of_beer", :action => "foo") + + assert_html html, %w(form action="foo" method="post" data-remote="true" data-update-success="#glass_of_beer") + assert_no_match /url="foo"/, html + end + + test ":url is used when :action is not present" do + html = form_remote_tag(:update => "#glass_of_beer", :url => "bar") + + assert_html html, %w(form action="bar" method="post" data-remote="true" data-update-success="#glass_of_beer") + assert_no_match /url="bar"/, html + end + + test "when protect_against_forgery? is false" do + assert_equal false, protect_against_forgery? + assert_html_not_present form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }), + authenticity_input_attributes + end + + test "update callbacks" do + assert_html form_remote_tag(:update => { :success => "#glass_of_beer" }, :url => { :action => :fast }), + %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer") + + assert_html form_remote_tag(:update => { :failure => "#glass_of_water" }, :url => { :action => :fast }), + %w(form action="/url/hash" method="post" data-remote="true" data-update-failure="#glass_of_water") + + assert_html form_remote_tag(:update => { :success => "#glass_of_beer", :failure => "#glass_of_water" }, :url => { :action => :fast }), + %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer" data-update-failure="#glass_of_water") + end + + test "using a :method option" do + expected_form_attributes = %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer") + # TODO: Ask Katz: Why does rails do this? Some web servers don't allow PUT or DELETE from what I remember... - BR + expected_input_attributes = %w(input name="_method" type="hidden" value="put") + + assert_html form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }, :html => { :method => :put }), + expected_form_attributes + expected_input_attributes + end + + + # FIXME: This test is janky as hell. We are essentially rewriting capture and concat and they don't really work right + # because output is out of order. This test passes because it's only doing a regex match on the buffer, but this really + # needs to be fixed by using the real helper methods that rails provides. capture, concat, url_for etc. should be + # implemented by their *real* methods or we need to find a better workaround so that our tests aren't written so + # poorly. - BR + test "form_remote_tag with block in erb" do + def capture(*args, &block) + @buffer = [] + block.call(*args) if block_given? + end + def concat(str) + @buffer << str + end + + expected_form_attributes = %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer" /form) + expected_inner_html = %w(w00t!) + + form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }) { concat expected_inner_html } + assert_html @buffer.to_s, + expected_form_attributes + expected_inner_html + end + + +end + class ButtonToRemoteTest < AjaxTestCase def button(options, html = {}) button_to_remote("Remote outpost", options, html) -- cgit v1.2.3 From 29811533b457c2926c23fa07de64fdc0b8d0e7af Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Wed, 30 Sep 2009 13:36:52 -0700 Subject: remote_form_for tests pass --- actionpack/test/javascript/ajax_test.rb | 103 ++++++++++++++++++++++++++++---- 1 file changed, 93 insertions(+), 10 deletions(-) (limited to 'actionpack') diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb index 49942f6681..3004cac97f 100644 --- a/actionpack/test/javascript/ajax_test.rb +++ b/actionpack/test/javascript/ajax_test.rb @@ -1,21 +1,18 @@ require "abstract_unit" -class AjaxTestCase < ActiveSupport::TestCase - include ActionView::Helpers::AjaxHelper +#TODO: Switch to assert_dom_equal where appropriate. assert_html is not robust enough for all tests - BR - # TODO: Ask Katz: Should these be included by the AjaxHelper? - BR - include ActionView::Helpers::TagHelper - include ActionView::Helpers::FormTagHelper +class AjaxTestCase < ActionView::TestCase + include ActionView::Helpers::AjaxHelper - # TODO: Replace with the real url_for method - BR - def url_for(url) - case url + def url_for(options) + case options when Hash "/url/hash" when String - url + options else - raise TypeError.new("Unsupported url type (#{url.class}) for this test helper") + raise TypeError.new("Unsupported url type (#{options.class}) for this test helper") end end @@ -218,7 +215,93 @@ class FormRemoteTagTest < AjaxTestCase expected_form_attributes + expected_inner_html end +class Author + extend ActiveModel::Naming + include ActiveModel::Conversion + + attr_reader :id + + def save; @id = 1 end + def new_record?; @id.nil? end + def name + @id.nil? ? 'new author' : "author ##{@id}" + end +end + +class Article + extend ActiveModel::Naming + include ActiveModel::Conversion + attr_reader :id + attr_reader :author_id + def save; @id = 1; @author_id = 1 end + def new_record?; @id.nil? end + def name + @id.nil? ? 'new article' : "article ##{@id}" + end +end + +class RemoteFormForTest < AjaxTestCase + + def setup + super + @record = @author = Author.new + @article = Article.new + end + + test "remote_form_for with record identification with new record" do + remote_form_for(@record, {:html => { :id => 'create-author' }}) {} + + expected = %(
) + assert_dom_equal expected, output_buffer + end + + test "remote_form_for with record identification without html options" do + remote_form_for(@record) {} + + expected = %(
) + assert_dom_equal expected, output_buffer + end + + test "remote_form_for with record identification with existing record" do + @record.save + remote_form_for(@record) {} + + expected = %(
) + assert_dom_equal expected, output_buffer + end + + test "remote_form_for with new object in list" do + remote_form_for([@author, @article]) {} + expected = %(
) + assert_dom_equal expected, output_buffer + end + + test "remote_form_for with existing object in list" do + @author.save + @article.save + remote_form_for([@author, @article]) {} + + expected = %(
) + assert_dom_equal expected, output_buffer + end + + protected + def author_path(record) + "/authors/#{record.id}" + end + + def authors_path + "/authors" + end + + def author_articles_path(author) + "/authors/#{author.id}/articles" + end + + def author_article_path(author, article) + "/authors/#{author.id}/articles/#{article.id}" + end end class ButtonToRemoteTest < AjaxTestCase -- cgit v1.2.3 From efb70f0f9fa1a33363f8eabb58caf707cba8382d Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Wed, 7 Oct 2009 19:51:40 -0700 Subject: Changed data-remote='true' to data-js-type='remote' --- actionpack/lib/action_view/helpers/ajax_helper.rb | 2 +- actionpack/test/javascript/ajax_test.rb | 45 ++++++++++++++--------- 2 files changed, 29 insertions(+), 18 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index e127641f4f..510980da08 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -25,7 +25,7 @@ module ActionView attributes["data-update-position"] = options.delete(:position) attributes["data-method"] = options.delete(:method) - attributes["data-remote"] = true + attributes["data-js-type"] = "remote" attributes end diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb index 3004cac97f..fc6928b8c1 100644 --- a/actionpack/test/javascript/ajax_test.rb +++ b/actionpack/test/javascript/ajax_test.rb @@ -74,17 +74,21 @@ class LinkToRemoteTest < AjaxTestCase test "using a url hash" do link = link_to_remote("Delete this post", {:controller => :blog}, :update => "#posts") - assert_html link, %w(href="/blog/destroy/4" data-update-success="#posts") + assert_html link, %w(href="/url/hash" data-update-success="#posts") + end + + test "with no update" do + assert_html link, %w(href="/blog/destroy/4" Delete\ this\ post data-js-type="remote") end test "with :html options" do - expected = %{Delete this post} + expected = %{Delete this post} assert_equal expected, link(:update => "#posts", :html => {"data-custom" => "me"}) end test "with a hash for :update" do link = link(:update => {:success => "#posts", :failure => "#error"}) - assert_html link, %w(data-remote="true" data-update-success="#posts" data-update-failure="#error") + assert_html link, %w(data-js-type="remote" data-update-success="#posts" data-update-failure="#error") end test "with positional parameters" do @@ -105,7 +109,7 @@ class LinkToRemoteTest < AjaxTestCase end test "basic link_to_remote with :url =>" do - expected = %{Delete this post} + expected = %{Delete this post} assert_equal expected, link_to_remote("Delete this post", :url => "/blog/destroy/4", :update => "#posts") end @@ -137,7 +141,7 @@ class FormRemoteTagTest < AjaxTestCase # TODO: Play with using assert_dom_equal test "basic" do assert_html form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }), - %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer") + %w(form action="/url/hash" method="post" data-js-type="remote" data-update-success="#glass_of_beer") end test "when protect_against_forgery? is true" do @@ -145,7 +149,7 @@ class FormRemoteTagTest < AjaxTestCase true end - expected_form_attributes = %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer") + expected_form_attributes = %w(form action="/url/hash" method="post" data-js-type="remote" data-update-success="#glass_of_beer") expected_patterns = expected_form_attributes + authenticity_input_attributes assert_equal true, protect_against_forgery? @@ -155,14 +159,14 @@ class FormRemoteTagTest < AjaxTestCase test ":action is used when it is present" do html = form_remote_tag(:update => "#glass_of_beer", :action => "foo") - assert_html html, %w(form action="foo" method="post" data-remote="true" data-update-success="#glass_of_beer") + assert_html html, %w(form action="foo" method="post" data-js-type="remote" data-update-success="#glass_of_beer") assert_no_match /url="foo"/, html end test ":url is used when :action is not present" do html = form_remote_tag(:update => "#glass_of_beer", :url => "bar") - assert_html html, %w(form action="bar" method="post" data-remote="true" data-update-success="#glass_of_beer") + assert_html html, %w(form action="bar" method="post" data-js-type="remote" data-update-success="#glass_of_beer") assert_no_match /url="bar"/, html end @@ -174,18 +178,25 @@ class FormRemoteTagTest < AjaxTestCase test "update callbacks" do assert_html form_remote_tag(:update => { :success => "#glass_of_beer" }, :url => { :action => :fast }), - %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer") + %w(form action="/url/hash" method="post" data-js-type="remote" data-update-success="#glass_of_beer") assert_html form_remote_tag(:update => { :failure => "#glass_of_water" }, :url => { :action => :fast }), - %w(form action="/url/hash" method="post" data-remote="true" data-update-failure="#glass_of_water") + %w(form action="/url/hash" method="post" data-js-type="remote" data-update-failure="#glass_of_water") assert_html form_remote_tag(:update => { :success => "#glass_of_beer", :failure => "#glass_of_water" }, :url => { :action => :fast }), - %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer" data-update-failure="#glass_of_water") + %w(form action="/url/hash" method="post" data-js-type="remote" data-update-success="#glass_of_beer" data-update-failure="#glass_of_water") end test "using a :method option" do +<<<<<<< HEAD expected_form_attributes = %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer") # TODO: Ask Katz: Why does rails do this? Some web servers don't allow PUT or DELETE from what I remember... - BR +======= + expected_form_attributes = %w(form action="/url/hash" method="post" data-js-type="remote" data-update-success="#glass_of_beer") + # TODO: Experiment with not using this _method param. Apparently this is done to address browser incompatibilities, but since + # we have a layer between the HTML and the JS libs now, we can probably get away with letting JS the JS libs handle the requirement + # for an extra field if needed. +>>>>>>> 6af9c2f... Changed data-remote='true' to data-js-type='remote' expected_input_attributes = %w(input name="_method" type="hidden" value="put") assert_html form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }, :html => { :method => :put }), @@ -207,7 +218,7 @@ class FormRemoteTagTest < AjaxTestCase @buffer << str end - expected_form_attributes = %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer" /form) + expected_form_attributes = %w(form action="/url/hash" method="post" data-js-type="remote" data-update-success="#glass_of_beer" /form) expected_inner_html = %w(w00t!) form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }) { concat expected_inner_html } @@ -251,14 +262,14 @@ class RemoteFormForTest < AjaxTestCase test "remote_form_for with record identification with new record" do remote_form_for(@record, {:html => { :id => 'create-author' }}) {} - expected = %(
) + expected = %(
) assert_dom_equal expected, output_buffer end test "remote_form_for with record identification without html options" do remote_form_for(@record) {} - expected = %(
) + expected = %(
) assert_dom_equal expected, output_buffer end @@ -266,14 +277,14 @@ class RemoteFormForTest < AjaxTestCase @record.save remote_form_for(@record) {} - expected = %(
) + expected = %(
) assert_dom_equal expected, output_buffer end test "remote_form_for with new object in list" do remote_form_for([@author, @article]) {} - expected = %(
) + expected = %(
) assert_dom_equal expected, output_buffer end @@ -282,7 +293,7 @@ class RemoteFormForTest < AjaxTestCase @article.save remote_form_for([@author, @article]) {} - expected = %(
) + expected = %(
) assert_dom_equal expected, output_buffer end -- cgit v1.2.3 From 081e057b174620993bdf4e534f5aba3fe266e88e Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Wed, 7 Oct 2009 20:52:46 -0700 Subject: Changed data-rails-type to data-js-type --- actionpack/lib/action_view/helpers/ajax_helper.rb | 2 +- actionpack/test/javascript/ajax_test.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 510980da08..246ad10371 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -79,7 +79,7 @@ module ActionView options[:name] = name <<-SCRIPT - - SCRIPT + script_decorator("field_observer", options) + end + + def script_decorator(js_type, options) + attributes = [%(type="application/json"), %(data-js-type="#{js_type}")] + attributes += options.map{|k, v| %(data-#{k}="#{v}")} + "" end module Rails2Compatibility @@ -124,11 +128,11 @@ module ActionView @statements, @arguments = statements, arguments end - def as_json(options = nil) + def to_s(options = nil) "function(#{@arguments.join(", ")}) {#{@statements}}" end end end end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 20e9916d62..1615f135b4 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -262,23 +262,8 @@ module ActionView # FormTagHelper#form_tag. def form_for(record_or_name_or_array, *args, &proc) raise ArgumentError, "Missing block" unless block_given? - options = args.extract_options! - - case record_or_name_or_array - when String, Symbol - object_name = record_or_name_or_array - when Array - object = record_or_name_or_array.last - object_name = ActionController::RecordIdentifier.singular_class_name(object) - apply_form_for_options!(record_or_name_or_array, options) - args.unshift object - else - object = record_or_name_or_array - object_name = ActionController::RecordIdentifier.singular_class_name(object) - apply_form_for_options!([object], options) - args.unshift object - end + object_name = extract_object_name_for_form!(args, options, record_or_name_or_array) concat(form_tag(options.delete(:url) || {}, options.delete(:html) || {})) fields_for(object_name, *(args << options), &proc) @@ -742,6 +727,25 @@ module ActionView def radio_button(object_name, method, tag_value, options = {}) InstanceTag.new(object_name, method, self, options.delete(:object)).to_radio_button_tag(tag_value, options) end + + private + def extract_object_name_for_form!(args, options, record_or_name_or_array) + case record_or_name_or_array + when String, Symbol + object_name = record_or_name_or_array + when Array + object = record_or_name_or_array.last + object_name = ActionController::RecordIdentifier.singular_class_name(object) + apply_form_for_options!(record_or_name_or_array, options) + args.unshift object + else + object = record_or_name_or_array + object_name = ActionController::RecordIdentifier.singular_class_name(object) + apply_form_for_options!([object], options) + args.unshift object + end + object_name + end end module InstanceTagMethods #:nodoc: diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb index 41bfdbd9b9..5e62677a92 100644 --- a/actionpack/test/javascript/ajax_test.rb +++ b/actionpack/test/javascript/ajax_test.rb @@ -188,15 +188,10 @@ class FormRemoteTagTest < AjaxTestCase end test "using a :method option" do -<<<<<<< HEAD - expected_form_attributes = %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer") - # TODO: Ask Katz: Why does rails do this? Some web servers don't allow PUT or DELETE from what I remember... - BR -======= expected_form_attributes = %w(form action="/url/hash" method="post" data-js-type="remote" data-update-success="#glass_of_beer") # TODO: Experiment with not using this _method param. Apparently this is done to address browser incompatibilities, but since # we have a layer between the HTML and the JS libs now, we can probably get away with letting JS the JS libs handle the requirement # for an extra field if needed. ->>>>>>> 6af9c2f... Changed data-remote='true' to data-js-type='remote' expected_input_attributes = %w(input name="_method" type="hidden" value="put") assert_html form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }, :html => { :method => :put }), @@ -341,6 +336,20 @@ class ButtonToRemoteTest < AjaxTestCase button(callback => "undoRequestCompleted(request)") end end +<<<<<<< HEAD +======= +end + +class ScriptDecoratorTest < AjaxTestCase + def decorator() + script_decorator("foo_type", :foo => "bar", :baz => "bang") + end + + test "basic" do + expected = %() + assert_dom_equal expected, decorator + end +>>>>>>> bd54253... Applied Yehuda's patch; Sharing extract_object_name_for_form! between form_helper and ajax_helper; Added script_decorator helper end class ObserveFieldTest < AjaxTestCase @@ -358,18 +367,18 @@ class ObserveFieldTest < AjaxTestCase end test "using a url string" do - assert_data_element_json field(:url => "/some/other/url"), - "url" => "/some/other/url", "name" => "title" + assert_html field(:url => "/some/other/url"), + %w(script data-url="/some/other/url" data-name="title") end test "using a url hash" do - assert_data_element_json field(:url => {:controller => :blog, :action => :update}), - "url" => "/url/hash", "name" => "title" + assert_html field(:url => {:controller => :blog, :action => :update}), + %w(script data-url="/url/hash" data-name="title") end test "using a :frequency option" do - assert_data_element_json field(:url => { :controller => :blog }, :frequency => 5.minutes), - "url" => "/url/hash", "name" => "title", "frequency" => 300 + assert_html field(:url => { :controller => :blog }, :frequency => 5.minutes), + %w(script data-url="/url/hash" data-name="title" data-frequency="300") end test "using a :frequency option of 0" do @@ -384,19 +393,22 @@ class ObserveFieldTest < AjaxTestCase # TODO: Consider using JSON instead of strings. Is using 'value' as a magical reference to the value of the observed field weird? (Rails2 does this) - BR test "using a :with option" do - assert_data_element_json field(:with => "foo"), - "name" => "title", "with" => "'foo=' + encodeURIComponent(value)" - assert_data_element_json field(:with => "'foo=' + encodeURIComponent(value)"), - "name" => "title", "with" => "'foo=' + encodeURIComponent(value)" + assert_html field(:with => "foo"), + %w(script data-name="title" data-with="'foo=' + encodeURIComponent(value)") + + assert_html field(:with => "'foo=' + encodeURIComponent(value)"), + %w(script data-name="title" data-with="'foo=' + encodeURIComponent(value)") + end test "using json in a :with option" do - assert_data_element_json field(:with => "{'id':value}"), - "name" => "title", "with" => "{'id':value}" + assert_html field(:with => "{'id':value}"), + %w(script data-name="title" data-with="{'id':value}") end test "using :function for callback" do - assert_data_element_json field(:function => "alert('Element changed')"), - "name" => "title", "function" => "function(element, value) {alert('Element changed')}" + assert_html field(:function => "alert('Element changed')"), + %w(script data-function="function(element, value) {alert('Element changed')}") + end end -- cgit v1.2.3 From 4536191d557b03c8155ba8793411d76958a810a2 Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Wed, 4 Nov 2009 01:51:54 -0800 Subject: Refactored ajax helpers so they use a little bit more coherent pattern; Removed code duplication from form_remote_tag --- actionpack/lib/action_view/helpers/ajax_helper.rb | 134 +++++++++++++--------- actionpack/test/javascript/ajax_test.rb | 81 +++++++------ 2 files changed, 124 insertions(+), 91 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index d6c43a1a15..93a79766dc 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -3,6 +3,16 @@ module ActionView module AjaxHelper include UrlHelper + def extract_remote_attributes!(options) + attributes = options.delete(:html) || {} + + attributes.merge!(extract_update_attributes!(options)) + attributes.merge!(extract_request_attributes!(options)) + attributes["data-js-type"] = options.delete(:js_type) || "remote" + + attributes + end + def remote_form_for(record_or_name_or_array, *args, &proc) options = args.extract_options! object_name = extract_object_name_for_form!(args, options, record_or_name_or_array) @@ -18,26 +28,8 @@ module ActionView attributes.merge!(extract_remote_attributes!(options)) attributes.merge!(options) - url = attributes.delete(:url) - form_tag(attributes.delete(:action) || url_for(url), attributes, &block) - end - - def extract_remote_attributes!(options) - attributes = options.delete(:html) || {} - - update = options.delete(:update) - if update.is_a?(Hash) - attributes["data-update-success"] = update[:success] - attributes["data-update-failure"] = update[:failure] - else - attributes["data-update-success"] = update - end - - attributes["data-update-position"] = options.delete(:position) - attributes["data-method"] = options.delete(:method) - attributes["data-js-type"] = "remote" - - attributes + url = attributes.delete("data-url") + form_tag(attributes.delete(:action) || url, attributes, &block) end def link_to_remote(name, url, options = {}) @@ -48,49 +40,45 @@ module ActionView url = url_for(url) if url.is_a?(Hash) link_to(name, url, attributes) end - + def button_to_remote(name, options = {}, html_options = {}) - url = options.delete(:url) - url = url_for(url) if url.is_a?(Hash) - - html_options.merge!(:type => "button", :value => name, - :"data-url" => url) - - tag(:input, html_options) + attributes = html_options.merge!(:type => "button") + attributes.merge!(extract_remote_attributes!(options)) + + tag(:input, attributes) + end + + def periodically_call_remote(options = {}) +# frequency = options[:frequency] || 10 # every ten seconds by default +# code = "new PeriodicalExecuter(function() {#{remote_function(options)}}, #{frequency})" +# javascript_tag(code) end def observe_field(name, options = {}) - url = options[:url] - options[:url] = url_for(url) if url && url.is_a?(Hash) - + attributes = extract_remote_attributes!(options) + callback = options.delete(:function) frequency = options.delete(:frequency) - if frequency && frequency != 0 - options[:frequency] = frequency.to_i - end - if with = options[:with] - if with !~ /[\{=(.]/ - options[:with] = "'#{options[:with]}=' + encodeURIComponent(value)" - else - options[:with] ||= 'value' unless options[:function] - end - end + attributes["data-name"] = name + attributes["data-js-type"] = "field_observer" - if function = options[:function] - statements = function # || remote_function(options) # TODO: Need to implement remote function - BR - options[:function] = JSFunction.new(statements, "element", "value") + if callback + attributes["data-observer-code"] = create_js_function(callback, "element", "value") + end + if frequency && frequency != 0 + attributes["data-frequency"] = frequency.to_i end - options[:name] = name - script_decorator("field_observer", options) + script_decorator(attributes) end - def script_decorator(js_type, options) - attributes = [%(type="application/json"), %(data-js-type="#{js_type}")] - attributes += options.map{|k, v| %(data-#{k}="#{v}")} + def script_decorator(options) + attributes = %w(type="application/json") + attributes += options.map{|k, v| k + '="' + v.to_s + '"'} "" end + # TODO: All evaled goes here per wycats module Rails2Compatibility def set_callbacks(options, html) [:complete, :failure, :success, :interactive, :loaded, :loading].each do |type| @@ -108,7 +96,6 @@ module ActionView if !options && url.is_a?(Hash) && url.key?(:url) url, options = url.delete(:url), url end - set_callbacks(options, options[:html] ||= {}) super @@ -122,15 +109,50 @@ module ActionView private - # TODO: Move to javascript helpers - BR - class JSFunction - def initialize(statements, *arguments) - @statements, @arguments = statements, arguments + def extract_request_attributes!(options) + attributes = {} + attributes["data-method"] = options.delete(:method) + + url = options.delete(:url) + attributes["data-url"] = url.is_a?(Hash) ? url_for(url) : url + + #TODO: Remove all references to prototype - BR + if options.delete(:form) + attributes["data-parameters"] = 'Form.serialize(this)' + elsif submit = options.delete(:submit) + attributes["data-parameters"] = "Form.serialize('#{submit}')" + elsif with = options.delete(:with) + if with !~ /[\{=(.]/ + attributes["data-with"] = "'#{with}=' + encodeURIComponent(value)" + else + attributes["data-with"] = with + end end - def to_s(options = nil) - "function(#{@arguments.join(", ")}) {#{@statements}}" + purge_unused_attributes!(attributes) + end + + def extract_update_attributes!(options) + attributes = {} + update = options.delete(:update) + if update.is_a?(Hash) + attributes["data-update-success"] = update[:success] + attributes["data-update-failure"] = update[:failure] + else + attributes["data-update-success"] = update end + attributes["data-update-position"] = options.delete(:position) + + purge_unused_attributes!(attributes) + end + + def purge_unused_attributes!(attributes) + attributes.delete_if {|key, value| value.nil? } + attributes + end + + def create_js_function(statements, *arguments) + "function(#{arguments.join(", ")}) {#{statements}}" end end diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb index 5e62677a92..2ca47344e5 100644 --- a/actionpack/test/javascript/ajax_test.rb +++ b/actionpack/test/javascript/ajax_test.rb @@ -1,7 +1,5 @@ require "abstract_unit" -#TODO: Switch to assert_dom_equal where appropriate. assert_html is not robust enough for all tests - BR - class AjaxTestCase < ActionView::TestCase include ActionView::Helpers::AjaxHelper @@ -28,20 +26,6 @@ class AjaxTestCase < ActionView::TestCase end end - def extract_json_from_data_element(data_element) - root = HTML::Document.new(data_element).root - script = root.find(:tag => "script") - cdata = script.children.detect {|child| child.to_s =~ / "#glass_of_beer", :url => { :action => :fast }), - %w(form action="/url/hash" method="post" data-js-type="remote" data-update-success="#glass_of_beer") + assert_dom_equal %(
), + form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }) end test "when protect_against_forgery? is true" do @@ -246,6 +230,42 @@ class Article end end +class ExtractRemoteAttributesTest < AjaxTestCase + attr_reader :attributes + + test "extract_remote_attributes! html" do + attributes = extract_remote_attributes!(:html => { :class => "css_klass", :style => "border:1px solid"}) + assert_equal "css_klass", attributes[:class] + assert_equal "border:1px solid", attributes[:style] + end + + test "extract_remote_attributes! update options when :update is a hash" do + attributes = extract_remote_attributes!(:update => { :success => "foo", :failure => "bar" }) + assert_equal "foo", attributes["data-update-success"] + assert_equal "bar", attributes["data-update-failure"] + end + + test "extract_remote_attributes! update options when :update is string" do + attributes = extract_remote_attributes!(:update => "baz") + assert_equal "baz", attributes["data-update-success"] + end + + test "extract_remote_attributes! position" do + attributes = extract_remote_attributes!(:position => "before") + assert_equal "before", attributes["data-update-position"] + end + + test "extract_remote_attributes! data-js-type when it is NOT passed" do + attributes = extract_remote_attributes!({}) + assert_equal "remote", attributes["data-js-type"] + end + + test "extract_remote_attributes! data-js-type when it passed" do + attributes = extract_remote_attributes!(:js_type => "some_type") + assert_equal "some_type", attributes["data-js-type"] + end +end + class RemoteFormForTest < AjaxTestCase def setup @@ -321,11 +341,8 @@ class ButtonToRemoteTest < AjaxTestCase class StandardTest < ButtonToRemoteTest test "basic" do - button = button({:url => {:action => "whatnot"}}, {:class => "fine"}) - [/input/, /class="fine"/, /type="button"/, /value="Remote outpost"/, - /data-url="\/whatnot"/].each do |match| - assert_match match, button - end + assert_html button({:url => {:action => "whatnot"}}, {:class => "fine", :value => "RemoteOutpost"}), + %w(input class="fine" type="button" value="RemoteOutpost" data-url="/url/hash") end end @@ -336,20 +353,17 @@ class ButtonToRemoteTest < AjaxTestCase button(callback => "undoRequestCompleted(request)") end end -<<<<<<< HEAD -======= end class ScriptDecoratorTest < AjaxTestCase def decorator() - script_decorator("foo_type", :foo => "bar", :baz => "bang") + script_decorator("data-js-type" => "foo_type", "data-foo" => "bar", "data-baz" => "bang") end test "basic" do expected = %() assert_dom_equal expected, decorator end ->>>>>>> bd54253... Applied Yehuda's patch; Sharing extract_object_name_for_form! between form_helper and ajax_helper; Added script_decorator helper end class ObserveFieldTest < AjaxTestCase @@ -385,11 +399,10 @@ class ObserveFieldTest < AjaxTestCase assert_no_match /frequency/, field(:frequency => 0) end - # TODO: Finish when remote_function or some equivilent is finished -BR -# def test_observe_field -# assert_dom_equal %(), -# observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" }) -# end + test "observe field with common options" do + assert_html observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" }), + %w(script data-name="glass" data-frequency="300" data-url="/url/hash") + end # TODO: Consider using JSON instead of strings. Is using 'value' as a magical reference to the value of the observed field weird? (Rails2 does this) - BR test "using a :with option" do @@ -398,7 +411,6 @@ class ObserveFieldTest < AjaxTestCase assert_html field(:with => "'foo=' + encodeURIComponent(value)"), %w(script data-name="title" data-with="'foo=' + encodeURIComponent(value)") - end test "using json in a :with option" do @@ -408,7 +420,6 @@ class ObserveFieldTest < AjaxTestCase test "using :function for callback" do assert_html field(:function => "alert('Element changed')"), - %w(script data-function="function(element, value) {alert('Element changed')}") - + %w(script data-observer-code="function(element, value) {alert('Element changed')}") end end -- cgit v1.2.3 From d9765c3af5acbd8b709482dfbea3e8fffdc36556 Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Wed, 4 Nov 2009 02:14:30 -0800 Subject: Changed data-name to data-observed on observe_field --- actionpack/lib/action_view/helpers/ajax_helper.rb | 30 ++++++++++++++--------- actionpack/test/javascript/ajax_test.rb | 14 +++++------ 2 files changed, 26 insertions(+), 18 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 93a79766dc..807c943d2c 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -55,20 +55,12 @@ module ActionView end def observe_field(name, options = {}) - attributes = extract_remote_attributes!(options) - callback = options.delete(:function) - frequency = options.delete(:frequency) + options[:observed] = name - attributes["data-name"] = name + attributes = extract_remote_attributes!(options) + attributes.merge!(extract_observer_attributes!(options)) attributes["data-js-type"] = "field_observer" - if callback - attributes["data-observer-code"] = create_js_function(callback, "element", "value") - end - if frequency && frequency != 0 - attributes["data-frequency"] = frequency.to_i - end - script_decorator(attributes) end @@ -146,6 +138,22 @@ module ActionView purge_unused_attributes!(attributes) end + def extract_observer_attributes!(options) + attributes = {} + attributes["data-observed"] = options.delete(:observed) + + callback = options.delete(:function) + frequency = options.delete(:frequency) + if callback + attributes["data-observer-code"] = create_js_function(callback, "element", "value") + end + if frequency && frequency != 0 + attributes["data-frequency"] = frequency.to_i + end + + attributes + end + def purge_unused_attributes!(attributes) attributes.delete_if {|key, value| value.nil? } attributes diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb index 2ca47344e5..0cc4460870 100644 --- a/actionpack/test/javascript/ajax_test.rb +++ b/actionpack/test/javascript/ajax_test.rb @@ -382,17 +382,17 @@ class ObserveFieldTest < AjaxTestCase test "using a url string" do assert_html field(:url => "/some/other/url"), - %w(script data-url="/some/other/url" data-name="title") + %w(script data-url="/some/other/url" data-observed="title") end test "using a url hash" do assert_html field(:url => {:controller => :blog, :action => :update}), - %w(script data-url="/url/hash" data-name="title") + %w(script data-url="/url/hash" data-observed="title") end test "using a :frequency option" do assert_html field(:url => { :controller => :blog }, :frequency => 5.minutes), - %w(script data-url="/url/hash" data-name="title" data-frequency="300") + %w(script data-url="/url/hash" data-observed="title" data-frequency="300") end test "using a :frequency option of 0" do @@ -401,21 +401,21 @@ class ObserveFieldTest < AjaxTestCase test "observe field with common options" do assert_html observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" }), - %w(script data-name="glass" data-frequency="300" data-url="/url/hash") + %w(script data-observed="glass" data-frequency="300" data-url="/url/hash") end # TODO: Consider using JSON instead of strings. Is using 'value' as a magical reference to the value of the observed field weird? (Rails2 does this) - BR test "using a :with option" do assert_html field(:with => "foo"), - %w(script data-name="title" data-with="'foo=' + encodeURIComponent(value)") + %w(script data-observed="title" data-with="'foo=' + encodeURIComponent(value)") assert_html field(:with => "'foo=' + encodeURIComponent(value)"), - %w(script data-name="title" data-with="'foo=' + encodeURIComponent(value)") + %w(script data-observed="title" data-with="'foo=' + encodeURIComponent(value)") end test "using json in a :with option" do assert_html field(:with => "{'id':value}"), - %w(script data-name="title" data-with="{'id':value}") + %w(script data-observed="title" data-with="{'id':value}") end test "using :function for callback" do -- cgit v1.2.3 From 67b73ff27206fa63a65926faf3b5c69019595c47 Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Wed, 4 Nov 2009 02:35:16 -0800 Subject: Removed duplication --- actionpack/lib/action_view/helpers/ajax_helper.rb | 16 ++++++++-------- actionpack/test/javascript/ajax_test.rb | 12 ++++++++++++ 2 files changed, 20 insertions(+), 8 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 807c943d2c..9f1ca138eb 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -49,16 +49,16 @@ module ActionView end def periodically_call_remote(options = {}) -# frequency = options[:frequency] || 10 # every ten seconds by default -# code = "new PeriodicalExecuter(function() {#{remote_function(options)}}, #{frequency})" -# javascript_tag(code) + attributes = extract_observer_attributes!(options) + attributes["data-js-type"] = "periodical_executer" + + script_decorator(attributes) end + #TODO: Should name change to a css query? - BR def observe_field(name, options = {}) options[:observed] = name - - attributes = extract_remote_attributes!(options) - attributes.merge!(extract_observer_attributes!(options)) + attributes = extract_observer_attributes!(options) attributes["data-js-type"] = "field_observer" script_decorator(attributes) @@ -139,7 +139,7 @@ module ActionView end def extract_observer_attributes!(options) - attributes = {} + attributes = extract_remote_attributes!(options) attributes["data-observed"] = options.delete(:observed) callback = options.delete(:function) @@ -151,7 +151,7 @@ module ActionView attributes["data-frequency"] = frequency.to_i end - attributes + purge_unused_attributes!(attributes) end def purge_unused_attributes!(attributes) diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb index 0cc4460870..f1207e938d 100644 --- a/actionpack/test/javascript/ajax_test.rb +++ b/actionpack/test/javascript/ajax_test.rb @@ -423,3 +423,15 @@ class ObserveFieldTest < AjaxTestCase %w(script data-observer-code="function(element, value) {alert('Element changed')}") end end + +class PeriodicallyCallRemoteTest < AjaxTestCase + test "basic" do + assert_html periodically_call_remote(:update => "#schremser_bier", :url => { :action => "mehr_bier" }), + %w(script data-url="/url/hash" data-update-success="#schremser_bier") + end + + test "periodically call remote with :frequency" do + assert_html periodically_call_remote(:frequency => 2, :url => "/url/string"), + %w(script data-url="/url/string" data-frequency="2") + end +end -- cgit v1.2.3 From 8c43c11a9dfd713cf613bb04c6074c82810d2f36 Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Wed, 4 Nov 2009 23:18:15 -0800 Subject: Added submit_to_remote helper --- actionpack/lib/action_view/helpers/ajax_helper.rb | 10 ++++++++++ actionpack/test/javascript/ajax_test.rb | 12 +++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 9f1ca138eb..1a75f9372b 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -48,6 +48,16 @@ module ActionView tag(:input, attributes) end + def submit_to_remote(name, value, options = {}) + html_options = options.delete(:html) || {} + html_options.merge!(:name => name, :value => value, :type => "submit") + + attributes = extract_remote_attributes!(options) + attributes.merge!(html_options) + + tag(:input, attributes) + end + def periodically_call_remote(options = {}) attributes = extract_observer_attributes!(options) attributes["data-js-type"] = "periodical_executer" diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb index f1207e938d..f4e766d77e 100644 --- a/actionpack/test/javascript/ajax_test.rb +++ b/actionpack/test/javascript/ajax_test.rb @@ -332,7 +332,7 @@ end class ButtonToRemoteTest < AjaxTestCase def button(options, html = {}) - button_to_remote("Remote outpost", options, html) + button_to_remote("RemoteOutpost", options, html) end def url_for(*) @@ -355,6 +355,16 @@ class ButtonToRemoteTest < AjaxTestCase end end +class SubmitToRemoteTest < AjaxTestCase + test "basic" do + expected = %() + options = { :url => {:action => "whatnot"}, :update => ".klass", :html => { :class => "fine" } } + + assert_dom_equal expected, + submit_to_remote("foo", "bar", options) + end +end + class ScriptDecoratorTest < AjaxTestCase def decorator() script_decorator("data-js-type" => "foo_type", "data-foo" => "bar", "data-baz" => "bang") -- cgit v1.2.3 From b599c4c7ee9af9943a983fd1ca4e061975dd5629 Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Wed, 4 Nov 2009 23:33:21 -0800 Subject: Added observe_form --- actionpack/lib/action_view/helpers/ajax_helper.rb | 8 ++++++++ actionpack/test/javascript/ajax_test.rb | 23 +++++++++++++++-------- 2 files changed, 23 insertions(+), 8 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 1a75f9372b..5de33868e9 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -74,6 +74,14 @@ module ActionView script_decorator(attributes) end + def observe_form(name, options = {}) + options[:observed] = name + attributes = extract_observer_attributes!(options) + attributes["data-js-type"] = "form_observer" + + script_decorator(attributes) + end + def script_decorator(options) attributes = %w(type="application/json") attributes += options.map{|k, v| k + '="' + v.to_s + '"'} diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb index f4e766d77e..32b6352c3c 100644 --- a/actionpack/test/javascript/ajax_test.rb +++ b/actionpack/test/javascript/ajax_test.rb @@ -392,17 +392,17 @@ class ObserveFieldTest < AjaxTestCase test "using a url string" do assert_html field(:url => "/some/other/url"), - %w(script data-url="/some/other/url" data-observed="title") + %w(script data-js-type="field_observer" data-url="/some/other/url" data-observed="title") end test "using a url hash" do assert_html field(:url => {:controller => :blog, :action => :update}), - %w(script data-url="/url/hash" data-observed="title") + %w(script data-js-type="field_observer" data-url="/url/hash" data-observed="title") end test "using a :frequency option" do assert_html field(:url => { :controller => :blog }, :frequency => 5.minutes), - %w(script data-url="/url/hash" data-observed="title" data-frequency="300") + %w(script data-js-type="field_observer" data-url="/url/hash" data-observed="title" data-frequency="300") end test "using a :frequency option of 0" do @@ -411,26 +411,33 @@ class ObserveFieldTest < AjaxTestCase test "observe field with common options" do assert_html observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" }), - %w(script data-observed="glass" data-frequency="300" data-url="/url/hash") + %w(script data-js-type="field_observer" data-observed="glass" data-frequency="300" data-url="/url/hash") end # TODO: Consider using JSON instead of strings. Is using 'value' as a magical reference to the value of the observed field weird? (Rails2 does this) - BR test "using a :with option" do assert_html field(:with => "foo"), - %w(script data-observed="title" data-with="'foo=' + encodeURIComponent(value)") + %w(script data-js-type="field_observer" data-observed="title" data-with="'foo=' + encodeURIComponent(value)") assert_html field(:with => "'foo=' + encodeURIComponent(value)"), - %w(script data-observed="title" data-with="'foo=' + encodeURIComponent(value)") + %w(script data-js-type="field_observer" data-observed="title" data-with="'foo=' + encodeURIComponent(value)") end test "using json in a :with option" do assert_html field(:with => "{'id':value}"), - %w(script data-observed="title" data-with="{'id':value}") + %w(script data-js-type="field_observer" data-observed="title" data-with="{'id':value}") end test "using :function for callback" do assert_html field(:function => "alert('Element changed')"), - %w(script data-observer-code="function(element, value) {alert('Element changed')}") + %w(script data-js-type="field_observer" data-observer-code="function(element, value) {alert('Element changed')}") + end +end + +class ObserveFormTest < AjaxTestCase + test "basic" do + assert_html observe_form("some_form", :frequency => 2, :url => { :action => "hash" }), + %w(script data-js-type="form_observer" data-url="/url/hash" data-observed="some_form" data-frequency="2") end end -- cgit v1.2.3 From 23275d1b793c21ea9481383402a881c177e8111c Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Wed, 23 Sep 2009 00:18:10 -0700 Subject: Added the beginnings of the observe_field helper --- actionpack/lib/action_view/helpers/ajax_helper.rb | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 5de33868e9..5cb8e96ae6 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -74,21 +74,18 @@ module ActionView script_decorator(attributes) end - def observe_form(name, options = {}) - options[:observed] = name - attributes = extract_observer_attributes!(options) - attributes["data-js-type"] = "form_observer" + def observe_field(name, options = {}, html_options = {}) + url = options.delete(:url) + url = url_for(url) if url.is_a?(Hash) - script_decorator(attributes) - end + if frequency = options.delete(:frequency) + html_options[:"data-frequency"] = frequency + end - def script_decorator(options) - attributes = %w(type="application/json") - attributes += options.map{|k, v| k + '="' + v.to_s + '"'} - "" + html_options.merge!(:"data-observe" => true, :"data-url" => url) + tag(:input, html_options) end - # TODO: All evaled goes here per wycats module Rails2Compatibility def set_callbacks(options, html) [:complete, :failure, :success, :interactive, :loaded, :loading].each do |type| -- cgit v1.2.3 From 773c4929fda3eff30e096813d25a61802638ab65 Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Wed, 23 Sep 2009 01:05:45 -0700 Subject: Implemented a fuller stub in AjaxTestCase for url_for because link_to calls url_for on all urls passed to it. Tests that were testing different input types for the url were failing because of this. --- actionpack/lib/action_view/helpers/ajax_helper.rb | 6 ++++++ actionpack/test/template/ajax_test.rb | 13 ++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 5cb8e96ae6..02245d9a1e 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -37,6 +37,12 @@ module ActionView attributes.merge!(extract_remote_attributes!(options)) attributes.merge!(options) + html["data-update-position"] = options.delete(:position) + html["data-method"] = options.delete(:method) + html["data-remote"] = "true" + + html.merge!(options) + url = url_for(url) if url.is_a?(Hash) link_to(name, url, attributes) end diff --git a/actionpack/test/template/ajax_test.rb b/actionpack/test/template/ajax_test.rb index 86932d754f..8770401b96 100644 --- a/actionpack/test/template/ajax_test.rb +++ b/actionpack/test/template/ajax_test.rb @@ -54,7 +54,7 @@ class LinkToRemoteTest < AjaxTestCase end test "with no update" do - assert_html link, %w(href="/blog/destroy/3" Delete\ this\ post data-remote="true") + assert_html link, %w(href="/blog/destroy/4" Delete\ this\ post data-remote="true") end test "with :html options" do @@ -102,10 +102,17 @@ class ButtonToRemoteTest < AjaxTestCase button_to_remote("Remote outpost", options, html) end + def url_for(*) + "/whatnot" + end + class StandardTest < ButtonToRemoteTest test "basic" do - assert_html button({:url => {:action => "whatnot"}}, {:class => "fine"}), - %w(input class="fine" type="button" value="Remote outpost" data-url="/url/hash") + button = button({:url => {:action => "whatnot"}}, {:class => "fine"}) + [/input/, /class="fine"/, /type="button"/, /value="Remote outpost"/, + /data-url="\/whatnot"/].each do |match| + assert_match(match, button) + end end end -- cgit v1.2.3 From 8f97e03fb01c39038f40f4a30fa2fe8e493e4691 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 21 Jan 2010 17:21:43 -0600 Subject: fixed failing tests --- actionpack/test/javascript/ajax_test.rb | 365 ++------------------------------ actionpack/test/template/ajax_test.rb | 13 +- 2 files changed, 15 insertions(+), 363 deletions(-) (limited to 'actionpack') diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb index 32b6352c3c..5b61524984 100644 --- a/actionpack/test/javascript/ajax_test.rb +++ b/actionpack/test/javascript/ajax_test.rb @@ -1,18 +1,8 @@ require "abstract_unit" -class AjaxTestCase < ActionView::TestCase +class AjaxTestCase < ActiveSupport::TestCase include ActionView::Helpers::AjaxHelper - - def url_for(options) - case options - when Hash - "/url/hash" - when String - options - else - raise TypeError.new("Unsupported url type (#{options.class}) for this test helper") - end - end + include ActionView::Helpers::TagHelper def assert_html(html, matches) matches.each do |match| @@ -20,12 +10,6 @@ class AjaxTestCase < ActionView::TestCase end end - def assert_html_not_present(html, matches) - matches.each do |match| - assert_no_match Regexp.new(Regexp.escape(match)), html - end - end - def self.assert_callbacks_work(&blk) define_method(:assert_callbacks_work, &blk) @@ -58,21 +42,17 @@ class LinkToRemoteTest < AjaxTestCase test "using a url hash" do link = link_to_remote("Delete this post", {:controller => :blog}, :update => "#posts") - assert_html link, %w(href="/url/hash" data-update-success="#posts") - end - - test "with no update" do - assert_html link, %w(href="/blog/destroy/4" Delete\ this\ post data-js-type="remote") + assert_html link, %w(href="/blog/destroy/4" data-update-success="#posts") end test "with :html options" do - expected = %{Delete this post} + expected = %{Delete this post} assert_equal expected, link(:update => "#posts", :html => {"data-custom" => "me"}) end test "with a hash for :update" do link = link(:update => {:success => "#posts", :failure => "#error"}) - assert_html link, %w(data-js-type="remote" data-update-success="#posts" data-update-failure="#error") + assert_html link, %w(data-remote="true" data-update-success="#posts" data-update-failure="#error") end test "with positional parameters" do @@ -93,7 +73,7 @@ class LinkToRemoteTest < AjaxTestCase end test "basic link_to_remote with :url =>" do - expected = %{Delete this post} + expected = %{Delete this post} assert_equal expected, link_to_remote("Delete this post", :url => "/blog/destroy/4", :update => "#posts") end @@ -104,235 +84,9 @@ class LinkToRemoteTest < AjaxTestCase end end -class FormRemoteTagTest < AjaxTestCase - - def protect_against_forgery? - false - end - - def request_forgery_protection_token - "token_name" - end - - def form_authenticity_token - "t0k3n" - end - - def authenticity_input_attributes - %w(input type="hidden" name="token_name" value="t0k3n") - end - - # TODO: Play with using assert_dom_equal - test "basic" do - assert_dom_equal %(), - form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }) - end - - test "when protect_against_forgery? is true" do - def protect_against_forgery? - true - end - - expected_form_attributes = %w(form action="/url/hash" method="post" data-js-type="remote" data-update-success="#glass_of_beer") - expected_patterns = expected_form_attributes + authenticity_input_attributes - - assert_equal true, protect_against_forgery? - assert_html form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }), expected_patterns - end - - test ":action is used when it is present" do - html = form_remote_tag(:update => "#glass_of_beer", :action => "foo") - - assert_html html, %w(form action="foo" method="post" data-js-type="remote" data-update-success="#glass_of_beer") - assert_no_match /url="foo"/, html - end - - test ":url is used when :action is not present" do - html = form_remote_tag(:update => "#glass_of_beer", :url => "bar") - - assert_html html, %w(form action="bar" method="post" data-js-type="remote" data-update-success="#glass_of_beer") - assert_no_match /url="bar"/, html - end - - test "when protect_against_forgery? is false" do - assert_equal false, protect_against_forgery? - assert_html_not_present form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }), - authenticity_input_attributes - end - - test "update callbacks" do - assert_html form_remote_tag(:update => { :success => "#glass_of_beer" }, :url => { :action => :fast }), - %w(form action="/url/hash" method="post" data-js-type="remote" data-update-success="#glass_of_beer") - - assert_html form_remote_tag(:update => { :failure => "#glass_of_water" }, :url => { :action => :fast }), - %w(form action="/url/hash" method="post" data-js-type="remote" data-update-failure="#glass_of_water") - - assert_html form_remote_tag(:update => { :success => "#glass_of_beer", :failure => "#glass_of_water" }, :url => { :action => :fast }), - %w(form action="/url/hash" method="post" data-js-type="remote" data-update-success="#glass_of_beer" data-update-failure="#glass_of_water") - end - - test "using a :method option" do - expected_form_attributes = %w(form action="/url/hash" method="post" data-js-type="remote" data-update-success="#glass_of_beer") - # TODO: Experiment with not using this _method param. Apparently this is done to address browser incompatibilities, but since - # we have a layer between the HTML and the JS libs now, we can probably get away with letting JS the JS libs handle the requirement - # for an extra field if needed. - expected_input_attributes = %w(input name="_method" type="hidden" value="put") - - assert_html form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }, :html => { :method => :put }), - expected_form_attributes + expected_input_attributes - end - - - # FIXME: This test is janky as hell. We are essentially rewriting capture and concat and they don't really work right - # because output is out of order. This test passes because it's only doing a regex match on the buffer, but this really - # needs to be fixed by using the real helper methods that rails provides. capture, concat, url_for etc. should be - # implemented by their *real* methods or we need to find a better workaround so that our tests aren't written so - # poorly. - BR - test "form_remote_tag with block in erb" do - def capture(*args, &block) - @buffer = [] - block.call(*args) if block_given? - end - def concat(str) - @buffer << str - end - - expected_form_attributes = %w(form action="/url/hash" method="post" data-js-type="remote" data-update-success="#glass_of_beer" /form) - expected_inner_html = %w(w00t!) - - form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }) { concat expected_inner_html } - assert_html @buffer.to_s, - expected_form_attributes + expected_inner_html - end - -class Author - extend ActiveModel::Naming - include ActiveModel::Conversion - - attr_reader :id - - def save; @id = 1 end - def new_record?; @id.nil? end - def name - @id.nil? ? 'new author' : "author ##{@id}" - end -end - -class Article - extend ActiveModel::Naming - include ActiveModel::Conversion - attr_reader :id - attr_reader :author_id - def save; @id = 1; @author_id = 1 end - def new_record?; @id.nil? end - def name - @id.nil? ? 'new article' : "article ##{@id}" - end -end - -class ExtractRemoteAttributesTest < AjaxTestCase - attr_reader :attributes - - test "extract_remote_attributes! html" do - attributes = extract_remote_attributes!(:html => { :class => "css_klass", :style => "border:1px solid"}) - assert_equal "css_klass", attributes[:class] - assert_equal "border:1px solid", attributes[:style] - end - - test "extract_remote_attributes! update options when :update is a hash" do - attributes = extract_remote_attributes!(:update => { :success => "foo", :failure => "bar" }) - assert_equal "foo", attributes["data-update-success"] - assert_equal "bar", attributes["data-update-failure"] - end - - test "extract_remote_attributes! update options when :update is string" do - attributes = extract_remote_attributes!(:update => "baz") - assert_equal "baz", attributes["data-update-success"] - end - - test "extract_remote_attributes! position" do - attributes = extract_remote_attributes!(:position => "before") - assert_equal "before", attributes["data-update-position"] - end - - test "extract_remote_attributes! data-js-type when it is NOT passed" do - attributes = extract_remote_attributes!({}) - assert_equal "remote", attributes["data-js-type"] - end - - test "extract_remote_attributes! data-js-type when it passed" do - attributes = extract_remote_attributes!(:js_type => "some_type") - assert_equal "some_type", attributes["data-js-type"] - end -end - -class RemoteFormForTest < AjaxTestCase - - def setup - super - @record = @author = Author.new - @article = Article.new - end - - test "remote_form_for with record identification with new record" do - remote_form_for(@record, {:html => { :id => 'create-author' }}) {} - - expected = %() - assert_dom_equal expected, output_buffer - end - - test "remote_form_for with record identification without html options" do - remote_form_for(@record) {} - - expected = %(
) - assert_dom_equal expected, output_buffer - end - - test "remote_form_for with record identification with existing record" do - @record.save - remote_form_for(@record) {} - - expected = %(
) - assert_dom_equal expected, output_buffer - end - - test "remote_form_for with new object in list" do - remote_form_for([@author, @article]) {} - - expected = %(
) - assert_dom_equal expected, output_buffer - end - - test "remote_form_for with existing object in list" do - @author.save - @article.save - remote_form_for([@author, @article]) {} - - expected = %(
) - assert_dom_equal expected, output_buffer - end - - protected - def author_path(record) - "/authors/#{record.id}" - end - - def authors_path - "/authors" - end - - def author_articles_path(author) - "/authors/#{author.id}/articles" - end - - def author_article_path(author, article) - "/authors/#{author.id}/articles/#{article.id}" - end -end - class ButtonToRemoteTest < AjaxTestCase def button(options, html = {}) - button_to_remote("RemoteOutpost", options, html) + button_to_remote("Remote outpost", options, html) end def url_for(*) @@ -341,8 +95,11 @@ class ButtonToRemoteTest < AjaxTestCase class StandardTest < ButtonToRemoteTest test "basic" do - assert_html button({:url => {:action => "whatnot"}}, {:class => "fine", :value => "RemoteOutpost"}), - %w(input class="fine" type="button" value="RemoteOutpost" data-url="/url/hash") + button = button({:url => {:action => "whatnot"}}, {:class => "fine"}) + [/input/, /class="fine"/, /type="button"/, /value="Remote outpost"/, + /data-url="\/whatnot"/].each do |match| + assert_match match, button + end end end @@ -354,101 +111,3 @@ class ButtonToRemoteTest < AjaxTestCase end end end - -class SubmitToRemoteTest < AjaxTestCase - test "basic" do - expected = %() - options = { :url => {:action => "whatnot"}, :update => ".klass", :html => { :class => "fine" } } - - assert_dom_equal expected, - submit_to_remote("foo", "bar", options) - end -end - -class ScriptDecoratorTest < AjaxTestCase - def decorator() - script_decorator("data-js-type" => "foo_type", "data-foo" => "bar", "data-baz" => "bang") - end - - test "basic" do - expected = %() - assert_dom_equal expected, decorator - end -end - -class ObserveFieldTest < AjaxTestCase - def protect_against_forgery? - false - end - - def field(options = {}) - observe_field("title", options) - end - - test "basic" do - assert_html field, - %w(script type="application/json" data-js-type="field_observer") - end - - test "using a url string" do - assert_html field(:url => "/some/other/url"), - %w(script data-js-type="field_observer" data-url="/some/other/url" data-observed="title") - end - - test "using a url hash" do - assert_html field(:url => {:controller => :blog, :action => :update}), - %w(script data-js-type="field_observer" data-url="/url/hash" data-observed="title") - end - - test "using a :frequency option" do - assert_html field(:url => { :controller => :blog }, :frequency => 5.minutes), - %w(script data-js-type="field_observer" data-url="/url/hash" data-observed="title" data-frequency="300") - end - - test "using a :frequency option of 0" do - assert_no_match /frequency/, field(:frequency => 0) - end - - test "observe field with common options" do - assert_html observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" }), - %w(script data-js-type="field_observer" data-observed="glass" data-frequency="300" data-url="/url/hash") - end - - # TODO: Consider using JSON instead of strings. Is using 'value' as a magical reference to the value of the observed field weird? (Rails2 does this) - BR - test "using a :with option" do - assert_html field(:with => "foo"), - %w(script data-js-type="field_observer" data-observed="title" data-with="'foo=' + encodeURIComponent(value)") - - assert_html field(:with => "'foo=' + encodeURIComponent(value)"), - %w(script data-js-type="field_observer" data-observed="title" data-with="'foo=' + encodeURIComponent(value)") - end - - test "using json in a :with option" do - assert_html field(:with => "{'id':value}"), - %w(script data-js-type="field_observer" data-observed="title" data-with="{'id':value}") - end - - test "using :function for callback" do - assert_html field(:function => "alert('Element changed')"), - %w(script data-js-type="field_observer" data-observer-code="function(element, value) {alert('Element changed')}") - end -end - -class ObserveFormTest < AjaxTestCase - test "basic" do - assert_html observe_form("some_form", :frequency => 2, :url => { :action => "hash" }), - %w(script data-js-type="form_observer" data-url="/url/hash" data-observed="some_form" data-frequency="2") - end -end - -class PeriodicallyCallRemoteTest < AjaxTestCase - test "basic" do - assert_html periodically_call_remote(:update => "#schremser_bier", :url => { :action => "mehr_bier" }), - %w(script data-url="/url/hash" data-update-success="#schremser_bier") - end - - test "periodically call remote with :frequency" do - assert_html periodically_call_remote(:frequency => 2, :url => "/url/string"), - %w(script data-url="/url/string" data-frequency="2") - end -end diff --git a/actionpack/test/template/ajax_test.rb b/actionpack/test/template/ajax_test.rb index 8770401b96..86932d754f 100644 --- a/actionpack/test/template/ajax_test.rb +++ b/actionpack/test/template/ajax_test.rb @@ -54,7 +54,7 @@ class LinkToRemoteTest < AjaxTestCase end test "with no update" do - assert_html link, %w(href="/blog/destroy/4" Delete\ this\ post data-remote="true") + assert_html link, %w(href="/blog/destroy/3" Delete\ this\ post data-remote="true") end test "with :html options" do @@ -102,17 +102,10 @@ class ButtonToRemoteTest < AjaxTestCase button_to_remote("Remote outpost", options, html) end - def url_for(*) - "/whatnot" - end - class StandardTest < ButtonToRemoteTest test "basic" do - button = button({:url => {:action => "whatnot"}}, {:class => "fine"}) - [/input/, /class="fine"/, /type="button"/, /value="Remote outpost"/, - /data-url="\/whatnot"/].each do |match| - assert_match(match, button) - end + assert_html button({:url => {:action => "whatnot"}}, {:class => "fine"}), + %w(input class="fine" type="button" value="Remote outpost" data-url="/url/hash") end end -- cgit v1.2.3 From 25c5ddd021333f47d9728d6e2a31927d1224a869 Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Wed, 23 Sep 2009 01:15:31 -0700 Subject: ObserveFieldTest uses url_for from AjaxTestCase --- actionpack/test/javascript/ajax_test.rb | 51 +++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'actionpack') diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb index 5b61524984..6539583398 100644 --- a/actionpack/test/javascript/ajax_test.rb +++ b/actionpack/test/javascript/ajax_test.rb @@ -111,3 +111,54 @@ class ButtonToRemoteTest < AjaxTestCase end end end + +class ObserveFieldTest < AjaxTestCase + def protect_against_forgery? + false + end + + def field(options = {}) + observe_field("title", options) + end + + test "basic" do + assert_html field, + %w(data-observe="true") + end + + test "with a :frequency option" do + assert_html field(:frequency => 5.minutes), + %w(data-observe="true" data-frequency="300") + end + + test "using a url string" do + assert_html field(:url => "/some/other/url"), + %w(data-observe="true" data-url="/some/other/url") + end + + test "using a url hash" do + assert_html field(:url => {:controller => :blog, :action => :update}), + %w(data-observe="true" data-url="/url/hash") + end + +# def test_observe_field +# assert_dom_equal %(), +# observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" }) +# end +# +# def test_observe_field_using_with_option +# expected = %() +# assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => 'id') +# assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "'id=' + encodeURIComponent(value)") +# end +# +# def test_observe_field_using_json_in_with_option +# expected = %() +# assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "{'id':value}") +# end +# +# def test_observe_field_using_function_for_callback +# assert_dom_equal %(), +# observe_field("glass", :frequency => 5.minutes, :function => "alert('Element changed')") +# end +end -- cgit v1.2.3 From d383f057c0821faf1d1d472b471628b37cf8d67c Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Wed, 23 Sep 2009 15:06:56 -0700 Subject: Changed the observe field node into a div with display:none --- actionpack/lib/action_view/helpers/ajax_helper.rb | 11 ++++++++--- actionpack/test/javascript/ajax_test.rb | 20 ++++++++++++-------- 2 files changed, 20 insertions(+), 11 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 02245d9a1e..fce756869c 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -84,12 +84,17 @@ module ActionView url = options.delete(:url) url = url_for(url) if url.is_a?(Hash) - if frequency = options.delete(:frequency) + frequency = options.delete(:frequency) + if frequency && frequency > 0 html_options[:"data-frequency"] = frequency end - html_options.merge!(:"data-observe" => true, :"data-url" => url) - tag(:input, html_options) + html_options.merge!(:style => "display:none", + :"data-observe-field" => name, + :"data-observe" => true, + :"data-url" => url) + + tag(:div, html_options) end module Rails2Compatibility diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb index 6539583398..e46e346d79 100644 --- a/actionpack/test/javascript/ajax_test.rb +++ b/actionpack/test/javascript/ajax_test.rb @@ -123,22 +123,26 @@ class ObserveFieldTest < AjaxTestCase test "basic" do assert_html field, - %w(data-observe="true") - end - - test "with a :frequency option" do - assert_html field(:frequency => 5.minutes), - %w(data-observe="true" data-frequency="300") + %w(div style="display:none" data-observe="true" data-observe-field="title") end test "using a url string" do assert_html field(:url => "/some/other/url"), - %w(data-observe="true" data-url="/some/other/url") + %w(data-url="/some/other/url") end test "using a url hash" do assert_html field(:url => {:controller => :blog, :action => :update}), - %w(data-observe="true" data-url="/url/hash") + %w(data-url="/url/hash") + end + + test "with a :frequency option" do + assert_html field(:frequency => 5.minutes), + %w(data-frequency="300") + end + + test "with a :frequency option of 0" do + assert_no_match /data-frequency/, field(:frequency => 0) end # def test_observe_field -- cgit v1.2.3 From afdecbc0a85fb6a61e58b8017f476fe29507e6bf Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Thu, 24 Sep 2009 00:18:52 -0700 Subject: Took another stab at observe_field. Now implementing data only helpers as script elements. --- actionpack/lib/action_view/helpers/ajax_helper.rb | 52 ++++++++++++++++++----- actionpack/test/javascript/ajax_test.rb | 51 ++++++++++++---------- 2 files changed, 69 insertions(+), 34 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index fce756869c..05e5fca484 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -80,21 +80,51 @@ module ActionView script_decorator(attributes) end - def observe_field(name, options = {}, html_options = {}) - url = options.delete(:url) - url = url_for(url) if url.is_a?(Hash) + def observe_field(name, options = {}) + if options[:url] + options[:url] = options[:url].is_a?(Hash) ? url_for(options[:url]) : options[:url] + end + + if options[:frequency] + case options[:frequency] + when 0 + options.delete(:frequency) + else + options[:frequency] = options[:frequency].to_i + end + end - frequency = options.delete(:frequency) - if frequency && frequency > 0 - html_options[:"data-frequency"] = frequency + if options[:with] && (options[:with] !~ /[\{=(.]/) + options[:with] = "'#{options[:with]}=' + encodeURIComponent(value)" + else + options[:with] ||= 'value' unless options[:function] + end + + if options[:function] + statements = options[:function] # || remote_function(options) # TODO: Need to implement remote function - BR + options[:function] = JSFunction.new(statements, "element", "value") end - html_options.merge!(:style => "display:none", - :"data-observe-field" => name, - :"data-observe" => true, - :"data-url" => url) + options[:name] = name + + <<-SCRIPT + + SCRIPT + end + + # TODO: Move to javascript helpers - BR + class JSFunction + def initialize(statements, *arguments) + @statements, @arguments = statements, arguments + end - tag(:div, html_options) + def as_json(options = nil) + "function(#{@arguments.join(", ")}) {#{@statements}}" + end end module Rails2Compatibility diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb index e46e346d79..97a69ba732 100644 --- a/actionpack/test/javascript/ajax_test.rb +++ b/actionpack/test/javascript/ajax_test.rb @@ -112,6 +112,8 @@ class ButtonToRemoteTest < AjaxTestCase end end +# TODO: We need a better way to test JSON being returned from data only helpers - BR +# TODO: We might also need a lower level data only helper method??? - BR class ObserveFieldTest < AjaxTestCase def protect_against_forgery? false @@ -123,46 +125,49 @@ class ObserveFieldTest < AjaxTestCase test "basic" do assert_html field, - %w(div style="display:none" data-observe="true" data-observe-field="title") + %w(script type="application/json" data-rails-type="observe_field") end test "using a url string" do assert_html field(:url => "/some/other/url"), - %w(data-url="/some/other/url") + %w("url":"/some/other/url") end test "using a url hash" do assert_html field(:url => {:controller => :blog, :action => :update}), - %w(data-url="/url/hash") + %w("url":"/url/hash") end - test "with a :frequency option" do + test "using a :frequency option" do assert_html field(:frequency => 5.minutes), - %w(data-frequency="300") + %w("frequency":300) end - test "with a :frequency option of 0" do - assert_no_match /data-frequency/, field(:frequency => 0) + test "using a :frequency option of 0" do + assert_no_match /frequency/, field(:frequency => 0) end + # TODO: Finish when remote_function or some equivilent is finished -BR # def test_observe_field # assert_dom_equal %(), # observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" }) # end -# -# def test_observe_field_using_with_option -# expected = %() -# assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => 'id') -# assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "'id=' + encodeURIComponent(value)") -# end -# -# def test_observe_field_using_json_in_with_option -# expected = %() -# assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "{'id':value}") -# end -# -# def test_observe_field_using_function_for_callback -# assert_dom_equal %(), -# observe_field("glass", :frequency => 5.minutes, :function => "alert('Element changed')") -# end + + # TODO: Consider using JSON instead of strings. Is using 'value' as a magical reference to the value of the observed field weird? (Rails2 does this) - BR + test "using a :with option" do + assert_html field(:with => "foo"), + %w("with":"'foo=' + encodeURIComponent(value)") + assert_html field(:with => "'foo=' + encodeURIComponent(value)"), + %w("with":"'foo=' + encodeURIComponent(value)") + end + + test "using json in a :with option" do + assert_html field(:with => "{'id':value}"), + %w("with":"{'id':value}") + end + + test "using :function for callback" do + assert_html field(:function => "alert('Element changed')"), + %w("function":"function(element, value) {alert('Element changed')}") + end end -- cgit v1.2.3 From b225de9711e012a8ade32cc4fc947f41cbb184a1 Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Thu, 24 Sep 2009 21:12:11 -0700 Subject: Added assert_data_element_json test helper for data element helpers --- actionpack/lib/action_view/helpers/ajax_helper.rb | 10 +++--- actionpack/test/javascript/ajax_test.rb | 44 ++++++++++++++--------- 2 files changed, 34 insertions(+), 20 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 05e5fca484..18b4c4991f 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -94,10 +94,12 @@ module ActionView end end - if options[:with] && (options[:with] !~ /[\{=(.]/) - options[:with] = "'#{options[:with]}=' + encodeURIComponent(value)" - else - options[:with] ||= 'value' unless options[:function] + if options[:with] + if options[:with] !~ /[\{=(.]/ + options[:with] = "'#{options[:with]}=' + encodeURIComponent(value)" + else + options[:with] ||= 'value' unless options[:function] + end end if options[:function] diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb index 97a69ba732..dc1f7c14fd 100644 --- a/actionpack/test/javascript/ajax_test.rb +++ b/actionpack/test/javascript/ajax_test.rb @@ -10,6 +10,20 @@ class AjaxTestCase < ActiveSupport::TestCase end end + def extract_json_from_data_element(data_element) + root = HTML::Document.new(data_element).root + script = root.find(:tag => "script") + cdata = script.children.detect {|child| child.to_s =~ / "/some/other/url"), - %w("url":"/some/other/url") + assert_data_element_json field(:url => "/some/other/url"), + "url" => "/some/other/url", "name" => "title" end test "using a url hash" do - assert_html field(:url => {:controller => :blog, :action => :update}), - %w("url":"/url/hash") + assert_data_element_json field(:url => {:controller => :blog, :action => :update}), + "url" => "/url/hash", "name" => "title" end test "using a :frequency option" do - assert_html field(:frequency => 5.minutes), - %w("frequency":300) + assert_data_element_json field(:url => { :controller => :blog }, :frequency => 5.minutes), + "url" => "/url/hash", "name" => "title", "frequency" => 300 end test "using a :frequency option of 0" do @@ -155,19 +167,19 @@ class ObserveFieldTest < AjaxTestCase # TODO: Consider using JSON instead of strings. Is using 'value' as a magical reference to the value of the observed field weird? (Rails2 does this) - BR test "using a :with option" do - assert_html field(:with => "foo"), - %w("with":"'foo=' + encodeURIComponent(value)") - assert_html field(:with => "'foo=' + encodeURIComponent(value)"), - %w("with":"'foo=' + encodeURIComponent(value)") + assert_data_element_json field(:with => "foo"), + "name" => "title", "with" => "'foo=' + encodeURIComponent(value)" + assert_data_element_json field(:with => "'foo=' + encodeURIComponent(value)"), + "name" => "title", "with" => "'foo=' + encodeURIComponent(value)" end test "using json in a :with option" do - assert_html field(:with => "{'id':value}"), - %w("with":"{'id':value}") + assert_data_element_json field(:with => "{'id':value}"), + "name" => "title", "with" => "{'id':value}" end test "using :function for callback" do - assert_html field(:function => "alert('Element changed')"), - %w("function":"function(element, value) {alert('Element changed')}") + assert_data_element_json field(:function => "alert('Element changed')"), + "name" => "title", "function" => "function(element, value) {alert('Element changed')}" end end -- cgit v1.2.3 From 5316e77db1c34dca15f83dd6a10e78e847c356c3 Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Fri, 25 Sep 2009 01:27:20 -0700 Subject: Took first stab at reimplementing form_remote_tag helpers --- actionpack/lib/action_view/helpers/ajax_helper.rb | 122 +++++---------------- actionpack/test/javascript/ajax_test.rb | 123 ++++++++++++++++++++++ 2 files changed, 149 insertions(+), 96 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 18b4c4991f..92e1d916c9 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -3,33 +3,31 @@ module ActionView module AjaxHelper include UrlHelper - def extract_remote_attributes!(options) - attributes = options.delete(:html) || {} - - attributes.merge!(extract_update_attributes!(options)) - attributes.merge!(extract_request_attributes!(options)) - attributes["data-js-type"] = options.delete(:js_type) || "remote" - - attributes - end - - def remote_form_for(record_or_name_or_array, *args, &proc) - options = args.extract_options! - object_name = extract_object_name_for_form!(args, options, record_or_name_or_array) - - concat(form_remote_tag(options)) - fields_for(object_name, *(args << options), &proc) - concat(''.html_safe!) - end - alias_method :form_remote_for, :remote_form_for - def form_remote_tag(options = {}, &block) attributes = {} attributes.merge!(extract_remote_attributes!(options)) attributes.merge!(options) - url = attributes.delete("data-url") - form_tag(attributes.delete(:action) || url, attributes, &block) + url = attributes.delete(:url) + form_tag(attributes.delete(:action) || url_for(url), attributes, &block) + end + + def extract_remote_attributes!(options) + attributes = options.delete(:html) || {} + + update = options.delete(:update) + if update.is_a?(Hash) + attributes["data-update-success"] = update[:success] + attributes["data-update-failure"] = update[:failure] + else + attributes["data-update-success"] = update + end + + attributes["data-update-position"] = options.delete(:position) + attributes["data-method"] = options.delete(:method) + attributes["data-remote"] = true + + attributes end def link_to_remote(name, url, options = {}) @@ -37,12 +35,6 @@ module ActionView attributes.merge!(extract_remote_attributes!(options)) attributes.merge!(options) - html["data-update-position"] = options.delete(:position) - html["data-method"] = options.delete(:method) - html["data-remote"] = "true" - - html.merge!(options) - url = url_for(url) if url.is_a?(Hash) link_to(name, url, attributes) end @@ -118,17 +110,6 @@ module ActionView SCRIPT end - # TODO: Move to javascript helpers - BR - class JSFunction - def initialize(statements, *arguments) - @statements, @arguments = statements, arguments - end - - def as_json(options = nil) - "function(#{@arguments.join(", ")}) {#{@statements}}" - end - end - module Rails2Compatibility def set_callbacks(options, html) [:complete, :failure, :success, :interactive, :loaded, :loading].each do |type| @@ -159,66 +140,15 @@ module ActionView private - def extract_request_attributes!(options) - attributes = {} - attributes["data-method"] = options.delete(:method) - - url = options.delete(:url) - attributes["data-url"] = url.is_a?(Hash) ? url_for(url) : url - - #TODO: Remove all references to prototype - BR - if options.delete(:form) - attributes["data-parameters"] = 'Form.serialize(this)' - elsif submit = options.delete(:submit) - attributes["data-parameters"] = "Form.serialize('#{submit}')" - elsif with = options.delete(:with) - if with !~ /[\{=(.]/ - attributes["data-with"] = "'#{with}=' + encodeURIComponent(value)" - else - attributes["data-with"] = with - end - end - - purge_unused_attributes!(attributes) - end - - def extract_update_attributes!(options) - attributes = {} - update = options.delete(:update) - if update.is_a?(Hash) - attributes["data-update-success"] = update[:success] - attributes["data-update-failure"] = update[:failure] - else - attributes["data-update-success"] = update + # TODO: Move to javascript helpers - BR + class JSFunction + def initialize(statements, *arguments) + @statements, @arguments = statements, arguments end - attributes["data-update-position"] = options.delete(:position) - purge_unused_attributes!(attributes) - end - - def extract_observer_attributes!(options) - attributes = extract_remote_attributes!(options) - attributes["data-observed"] = options.delete(:observed) - - callback = options.delete(:function) - frequency = options.delete(:frequency) - if callback - attributes["data-observer-code"] = create_js_function(callback, "element", "value") - end - if frequency && frequency != 0 - attributes["data-frequency"] = frequency.to_i + def as_json(options = nil) + "function(#{@arguments.join(", ")}) {#{@statements}}" end - - purge_unused_attributes!(attributes) - end - - def purge_unused_attributes!(attributes) - attributes.delete_if {|key, value| value.nil? } - attributes - end - - def create_js_function(statements, *arguments) - "function(#{arguments.join(", ")}) {#{statements}}" end end diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb index dc1f7c14fd..49942f6681 100644 --- a/actionpack/test/javascript/ajax_test.rb +++ b/actionpack/test/javascript/ajax_test.rb @@ -2,7 +2,22 @@ require "abstract_unit" class AjaxTestCase < ActiveSupport::TestCase include ActionView::Helpers::AjaxHelper + + # TODO: Ask Katz: Should these be included by the AjaxHelper? - BR include ActionView::Helpers::TagHelper + include ActionView::Helpers::FormTagHelper + + # TODO: Replace with the real url_for method - BR + def url_for(url) + case url + when Hash + "/url/hash" + when String + url + else + raise TypeError.new("Unsupported url type (#{url.class}) for this test helper") + end + end def assert_html(html, matches) matches.each do |match| @@ -10,6 +25,12 @@ class AjaxTestCase < ActiveSupport::TestCase end end + def assert_html_not_present(html, matches) + matches.each do |match| + assert_no_match Regexp.new(Regexp.escape(match)), html + end + end + def extract_json_from_data_element(data_element) root = HTML::Document.new(data_element).root script = root.find(:tag => "script") @@ -98,6 +119,108 @@ class LinkToRemoteTest < AjaxTestCase end end +class FormRemoteTagTest < AjaxTestCase + + def protect_against_forgery? + false + end + + def request_forgery_protection_token + "token_name" + end + + def form_authenticity_token + "t0k3n" + end + + def authenticity_input_attributes + %w(input type="hidden" name="token_name" value="t0k3n") + end + + # TODO: Play with using assert_dom_equal + test "basic" do + assert_html form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }), + %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer") + end + + test "when protect_against_forgery? is true" do + def protect_against_forgery? + true + end + + expected_form_attributes = %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer") + expected_patterns = expected_form_attributes + authenticity_input_attributes + + assert_equal true, protect_against_forgery? + assert_html form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }), expected_patterns + end + + test ":action is used when it is present" do + html = form_remote_tag(:update => "#glass_of_beer", :action => "foo") + + assert_html html, %w(form action="foo" method="post" data-remote="true" data-update-success="#glass_of_beer") + assert_no_match /url="foo"/, html + end + + test ":url is used when :action is not present" do + html = form_remote_tag(:update => "#glass_of_beer", :url => "bar") + + assert_html html, %w(form action="bar" method="post" data-remote="true" data-update-success="#glass_of_beer") + assert_no_match /url="bar"/, html + end + + test "when protect_against_forgery? is false" do + assert_equal false, protect_against_forgery? + assert_html_not_present form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }), + authenticity_input_attributes + end + + test "update callbacks" do + assert_html form_remote_tag(:update => { :success => "#glass_of_beer" }, :url => { :action => :fast }), + %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer") + + assert_html form_remote_tag(:update => { :failure => "#glass_of_water" }, :url => { :action => :fast }), + %w(form action="/url/hash" method="post" data-remote="true" data-update-failure="#glass_of_water") + + assert_html form_remote_tag(:update => { :success => "#glass_of_beer", :failure => "#glass_of_water" }, :url => { :action => :fast }), + %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer" data-update-failure="#glass_of_water") + end + + test "using a :method option" do + expected_form_attributes = %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer") + # TODO: Ask Katz: Why does rails do this? Some web servers don't allow PUT or DELETE from what I remember... - BR + expected_input_attributes = %w(input name="_method" type="hidden" value="put") + + assert_html form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }, :html => { :method => :put }), + expected_form_attributes + expected_input_attributes + end + + + # FIXME: This test is janky as hell. We are essentially rewriting capture and concat and they don't really work right + # because output is out of order. This test passes because it's only doing a regex match on the buffer, but this really + # needs to be fixed by using the real helper methods that rails provides. capture, concat, url_for etc. should be + # implemented by their *real* methods or we need to find a better workaround so that our tests aren't written so + # poorly. - BR + test "form_remote_tag with block in erb" do + def capture(*args, &block) + @buffer = [] + block.call(*args) if block_given? + end + def concat(str) + @buffer << str + end + + expected_form_attributes = %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer" /form) + expected_inner_html = %w(w00t!) + + form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }) { concat expected_inner_html } + assert_html @buffer.to_s, + expected_form_attributes + expected_inner_html + end + + +end + class ButtonToRemoteTest < AjaxTestCase def button(options, html = {}) button_to_remote("Remote outpost", options, html) -- cgit v1.2.3 From 631537a25d8158085657b10357072873646e0cb5 Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Wed, 30 Sep 2009 13:36:52 -0700 Subject: remote_form_for tests pass --- actionpack/test/javascript/ajax_test.rb | 103 ++++++++++++++++++++++++++++---- 1 file changed, 93 insertions(+), 10 deletions(-) (limited to 'actionpack') diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb index 49942f6681..3004cac97f 100644 --- a/actionpack/test/javascript/ajax_test.rb +++ b/actionpack/test/javascript/ajax_test.rb @@ -1,21 +1,18 @@ require "abstract_unit" -class AjaxTestCase < ActiveSupport::TestCase - include ActionView::Helpers::AjaxHelper +#TODO: Switch to assert_dom_equal where appropriate. assert_html is not robust enough for all tests - BR - # TODO: Ask Katz: Should these be included by the AjaxHelper? - BR - include ActionView::Helpers::TagHelper - include ActionView::Helpers::FormTagHelper +class AjaxTestCase < ActionView::TestCase + include ActionView::Helpers::AjaxHelper - # TODO: Replace with the real url_for method - BR - def url_for(url) - case url + def url_for(options) + case options when Hash "/url/hash" when String - url + options else - raise TypeError.new("Unsupported url type (#{url.class}) for this test helper") + raise TypeError.new("Unsupported url type (#{options.class}) for this test helper") end end @@ -218,7 +215,93 @@ class FormRemoteTagTest < AjaxTestCase expected_form_attributes + expected_inner_html end +class Author + extend ActiveModel::Naming + include ActiveModel::Conversion + + attr_reader :id + + def save; @id = 1 end + def new_record?; @id.nil? end + def name + @id.nil? ? 'new author' : "author ##{@id}" + end +end + +class Article + extend ActiveModel::Naming + include ActiveModel::Conversion + attr_reader :id + attr_reader :author_id + def save; @id = 1; @author_id = 1 end + def new_record?; @id.nil? end + def name + @id.nil? ? 'new article' : "article ##{@id}" + end +end + +class RemoteFormForTest < AjaxTestCase + + def setup + super + @record = @author = Author.new + @article = Article.new + end + + test "remote_form_for with record identification with new record" do + remote_form_for(@record, {:html => { :id => 'create-author' }}) {} + + expected = %(
) + assert_dom_equal expected, output_buffer + end + + test "remote_form_for with record identification without html options" do + remote_form_for(@record) {} + + expected = %(
) + assert_dom_equal expected, output_buffer + end + + test "remote_form_for with record identification with existing record" do + @record.save + remote_form_for(@record) {} + + expected = %(
) + assert_dom_equal expected, output_buffer + end + + test "remote_form_for with new object in list" do + remote_form_for([@author, @article]) {} + expected = %(
) + assert_dom_equal expected, output_buffer + end + + test "remote_form_for with existing object in list" do + @author.save + @article.save + remote_form_for([@author, @article]) {} + + expected = %(
) + assert_dom_equal expected, output_buffer + end + + protected + def author_path(record) + "/authors/#{record.id}" + end + + def authors_path + "/authors" + end + + def author_articles_path(author) + "/authors/#{author.id}/articles" + end + + def author_article_path(author, article) + "/authors/#{author.id}/articles/#{article.id}" + end end class ButtonToRemoteTest < AjaxTestCase -- cgit v1.2.3 From bd65e7f73d6aba48d4baadba916f1652a6c8aade Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Wed, 7 Oct 2009 19:51:40 -0700 Subject: Changed data-remote='true' to data-js-type='remote' --- actionpack/lib/action_view/helpers/ajax_helper.rb | 2 +- actionpack/test/javascript/ajax_test.rb | 45 ++++++++++++++--------- 2 files changed, 29 insertions(+), 18 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 92e1d916c9..e4684c4992 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -25,7 +25,7 @@ module ActionView attributes["data-update-position"] = options.delete(:position) attributes["data-method"] = options.delete(:method) - attributes["data-remote"] = true + attributes["data-js-type"] = "remote" attributes end diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb index 3004cac97f..fc6928b8c1 100644 --- a/actionpack/test/javascript/ajax_test.rb +++ b/actionpack/test/javascript/ajax_test.rb @@ -74,17 +74,21 @@ class LinkToRemoteTest < AjaxTestCase test "using a url hash" do link = link_to_remote("Delete this post", {:controller => :blog}, :update => "#posts") - assert_html link, %w(href="/blog/destroy/4" data-update-success="#posts") + assert_html link, %w(href="/url/hash" data-update-success="#posts") + end + + test "with no update" do + assert_html link, %w(href="/blog/destroy/4" Delete\ this\ post data-js-type="remote") end test "with :html options" do - expected = %{Delete this post} + expected = %{Delete this post} assert_equal expected, link(:update => "#posts", :html => {"data-custom" => "me"}) end test "with a hash for :update" do link = link(:update => {:success => "#posts", :failure => "#error"}) - assert_html link, %w(data-remote="true" data-update-success="#posts" data-update-failure="#error") + assert_html link, %w(data-js-type="remote" data-update-success="#posts" data-update-failure="#error") end test "with positional parameters" do @@ -105,7 +109,7 @@ class LinkToRemoteTest < AjaxTestCase end test "basic link_to_remote with :url =>" do - expected = %{Delete this post} + expected = %{Delete this post} assert_equal expected, link_to_remote("Delete this post", :url => "/blog/destroy/4", :update => "#posts") end @@ -137,7 +141,7 @@ class FormRemoteTagTest < AjaxTestCase # TODO: Play with using assert_dom_equal test "basic" do assert_html form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }), - %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer") + %w(form action="/url/hash" method="post" data-js-type="remote" data-update-success="#glass_of_beer") end test "when protect_against_forgery? is true" do @@ -145,7 +149,7 @@ class FormRemoteTagTest < AjaxTestCase true end - expected_form_attributes = %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer") + expected_form_attributes = %w(form action="/url/hash" method="post" data-js-type="remote" data-update-success="#glass_of_beer") expected_patterns = expected_form_attributes + authenticity_input_attributes assert_equal true, protect_against_forgery? @@ -155,14 +159,14 @@ class FormRemoteTagTest < AjaxTestCase test ":action is used when it is present" do html = form_remote_tag(:update => "#glass_of_beer", :action => "foo") - assert_html html, %w(form action="foo" method="post" data-remote="true" data-update-success="#glass_of_beer") + assert_html html, %w(form action="foo" method="post" data-js-type="remote" data-update-success="#glass_of_beer") assert_no_match /url="foo"/, html end test ":url is used when :action is not present" do html = form_remote_tag(:update => "#glass_of_beer", :url => "bar") - assert_html html, %w(form action="bar" method="post" data-remote="true" data-update-success="#glass_of_beer") + assert_html html, %w(form action="bar" method="post" data-js-type="remote" data-update-success="#glass_of_beer") assert_no_match /url="bar"/, html end @@ -174,18 +178,25 @@ class FormRemoteTagTest < AjaxTestCase test "update callbacks" do assert_html form_remote_tag(:update => { :success => "#glass_of_beer" }, :url => { :action => :fast }), - %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer") + %w(form action="/url/hash" method="post" data-js-type="remote" data-update-success="#glass_of_beer") assert_html form_remote_tag(:update => { :failure => "#glass_of_water" }, :url => { :action => :fast }), - %w(form action="/url/hash" method="post" data-remote="true" data-update-failure="#glass_of_water") + %w(form action="/url/hash" method="post" data-js-type="remote" data-update-failure="#glass_of_water") assert_html form_remote_tag(:update => { :success => "#glass_of_beer", :failure => "#glass_of_water" }, :url => { :action => :fast }), - %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer" data-update-failure="#glass_of_water") + %w(form action="/url/hash" method="post" data-js-type="remote" data-update-success="#glass_of_beer" data-update-failure="#glass_of_water") end test "using a :method option" do +<<<<<<< HEAD expected_form_attributes = %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer") # TODO: Ask Katz: Why does rails do this? Some web servers don't allow PUT or DELETE from what I remember... - BR +======= + expected_form_attributes = %w(form action="/url/hash" method="post" data-js-type="remote" data-update-success="#glass_of_beer") + # TODO: Experiment with not using this _method param. Apparently this is done to address browser incompatibilities, but since + # we have a layer between the HTML and the JS libs now, we can probably get away with letting JS the JS libs handle the requirement + # for an extra field if needed. +>>>>>>> 6af9c2f... Changed data-remote='true' to data-js-type='remote' expected_input_attributes = %w(input name="_method" type="hidden" value="put") assert_html form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }, :html => { :method => :put }), @@ -207,7 +218,7 @@ class FormRemoteTagTest < AjaxTestCase @buffer << str end - expected_form_attributes = %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer" /form) + expected_form_attributes = %w(form action="/url/hash" method="post" data-js-type="remote" data-update-success="#glass_of_beer" /form) expected_inner_html = %w(w00t!) form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }) { concat expected_inner_html } @@ -251,14 +262,14 @@ class RemoteFormForTest < AjaxTestCase test "remote_form_for with record identification with new record" do remote_form_for(@record, {:html => { :id => 'create-author' }}) {} - expected = %(
) + expected = %(
) assert_dom_equal expected, output_buffer end test "remote_form_for with record identification without html options" do remote_form_for(@record) {} - expected = %(
) + expected = %(
) assert_dom_equal expected, output_buffer end @@ -266,14 +277,14 @@ class RemoteFormForTest < AjaxTestCase @record.save remote_form_for(@record) {} - expected = %(
) + expected = %(
) assert_dom_equal expected, output_buffer end test "remote_form_for with new object in list" do remote_form_for([@author, @article]) {} - expected = %(
) + expected = %(
) assert_dom_equal expected, output_buffer end @@ -282,7 +293,7 @@ class RemoteFormForTest < AjaxTestCase @article.save remote_form_for([@author, @article]) {} - expected = %(
) + expected = %(
) assert_dom_equal expected, output_buffer end -- cgit v1.2.3 From 9c12e66748ea96a1f869946cac68259b13a70e86 Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Wed, 7 Oct 2009 20:52:46 -0700 Subject: Changed data-rails-type to data-js-type --- actionpack/lib/action_view/helpers/ajax_helper.rb | 2 +- actionpack/test/javascript/ajax_test.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index e4684c4992..b94eb6c973 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -102,7 +102,7 @@ module ActionView options[:name] = name <<-SCRIPT - - SCRIPT + script_decorator("field_observer", options) + end + + def script_decorator(js_type, options) + attributes = [%(type="application/json"), %(data-js-type="#{js_type}")] + attributes += options.map{|k, v| %(data-#{k}="#{v}")} + "" end module Rails2Compatibility @@ -146,7 +150,7 @@ module ActionView @statements, @arguments = statements, arguments end - def as_json(options = nil) + def to_s(options = nil) "function(#{@arguments.join(", ")}) {#{@statements}}" end end diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb index 41bfdbd9b9..5e62677a92 100644 --- a/actionpack/test/javascript/ajax_test.rb +++ b/actionpack/test/javascript/ajax_test.rb @@ -188,15 +188,10 @@ class FormRemoteTagTest < AjaxTestCase end test "using a :method option" do -<<<<<<< HEAD - expected_form_attributes = %w(form action="/url/hash" method="post" data-remote="true" data-update-success="#glass_of_beer") - # TODO: Ask Katz: Why does rails do this? Some web servers don't allow PUT or DELETE from what I remember... - BR -======= expected_form_attributes = %w(form action="/url/hash" method="post" data-js-type="remote" data-update-success="#glass_of_beer") # TODO: Experiment with not using this _method param. Apparently this is done to address browser incompatibilities, but since # we have a layer between the HTML and the JS libs now, we can probably get away with letting JS the JS libs handle the requirement # for an extra field if needed. ->>>>>>> 6af9c2f... Changed data-remote='true' to data-js-type='remote' expected_input_attributes = %w(input name="_method" type="hidden" value="put") assert_html form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }, :html => { :method => :put }), @@ -341,6 +336,20 @@ class ButtonToRemoteTest < AjaxTestCase button(callback => "undoRequestCompleted(request)") end end +<<<<<<< HEAD +======= +end + +class ScriptDecoratorTest < AjaxTestCase + def decorator() + script_decorator("foo_type", :foo => "bar", :baz => "bang") + end + + test "basic" do + expected = %() + assert_dom_equal expected, decorator + end +>>>>>>> bd54253... Applied Yehuda's patch; Sharing extract_object_name_for_form! between form_helper and ajax_helper; Added script_decorator helper end class ObserveFieldTest < AjaxTestCase @@ -358,18 +367,18 @@ class ObserveFieldTest < AjaxTestCase end test "using a url string" do - assert_data_element_json field(:url => "/some/other/url"), - "url" => "/some/other/url", "name" => "title" + assert_html field(:url => "/some/other/url"), + %w(script data-url="/some/other/url" data-name="title") end test "using a url hash" do - assert_data_element_json field(:url => {:controller => :blog, :action => :update}), - "url" => "/url/hash", "name" => "title" + assert_html field(:url => {:controller => :blog, :action => :update}), + %w(script data-url="/url/hash" data-name="title") end test "using a :frequency option" do - assert_data_element_json field(:url => { :controller => :blog }, :frequency => 5.minutes), - "url" => "/url/hash", "name" => "title", "frequency" => 300 + assert_html field(:url => { :controller => :blog }, :frequency => 5.minutes), + %w(script data-url="/url/hash" data-name="title" data-frequency="300") end test "using a :frequency option of 0" do @@ -384,19 +393,22 @@ class ObserveFieldTest < AjaxTestCase # TODO: Consider using JSON instead of strings. Is using 'value' as a magical reference to the value of the observed field weird? (Rails2 does this) - BR test "using a :with option" do - assert_data_element_json field(:with => "foo"), - "name" => "title", "with" => "'foo=' + encodeURIComponent(value)" - assert_data_element_json field(:with => "'foo=' + encodeURIComponent(value)"), - "name" => "title", "with" => "'foo=' + encodeURIComponent(value)" + assert_html field(:with => "foo"), + %w(script data-name="title" data-with="'foo=' + encodeURIComponent(value)") + + assert_html field(:with => "'foo=' + encodeURIComponent(value)"), + %w(script data-name="title" data-with="'foo=' + encodeURIComponent(value)") + end test "using json in a :with option" do - assert_data_element_json field(:with => "{'id':value}"), - "name" => "title", "with" => "{'id':value}" + assert_html field(:with => "{'id':value}"), + %w(script data-name="title" data-with="{'id':value}") end test "using :function for callback" do - assert_data_element_json field(:function => "alert('Element changed')"), - "name" => "title", "function" => "function(element, value) {alert('Element changed')}" + assert_html field(:function => "alert('Element changed')"), + %w(script data-function="function(element, value) {alert('Element changed')}") + end end -- cgit v1.2.3 From 261654becf2b689654a32f18f610a078a15608c6 Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Wed, 4 Nov 2009 01:51:54 -0800 Subject: Refactored ajax helpers so they use a little bit more coherent pattern; Removed code duplication from form_remote_tag --- actionpack/lib/action_view/helpers/ajax_helper.rb | 140 +++++++++++----------- actionpack/test/javascript/ajax_test.rb | 81 +++++++------ 2 files changed, 116 insertions(+), 105 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index da639b0658..93a79766dc 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -3,6 +3,16 @@ module ActionView module AjaxHelper include UrlHelper + def extract_remote_attributes!(options) + attributes = options.delete(:html) || {} + + attributes.merge!(extract_update_attributes!(options)) + attributes.merge!(extract_request_attributes!(options)) + attributes["data-js-type"] = options.delete(:js_type) || "remote" + + attributes + end + def remote_form_for(record_or_name_or_array, *args, &proc) options = args.extract_options! object_name = extract_object_name_for_form!(args, options, record_or_name_or_array) @@ -18,26 +28,8 @@ module ActionView attributes.merge!(extract_remote_attributes!(options)) attributes.merge!(options) - url = attributes.delete(:url) - form_tag(attributes.delete(:action) || url_for(url), attributes, &block) - end - - def extract_remote_attributes!(options) - attributes = options.delete(:html) || {} - - update = options.delete(:update) - if update.is_a?(Hash) - attributes["data-update-success"] = update[:success] - attributes["data-update-failure"] = update[:failure] - else - attributes["data-update-success"] = update - end - - attributes["data-update-position"] = options.delete(:position) - attributes["data-method"] = options.delete(:method) - attributes["data-js-type"] = "remote" - - attributes + url = attributes.delete("data-url") + form_tag(attributes.delete(:action) || url, attributes, &block) end def link_to_remote(name, url, options = {}) @@ -56,64 +48,37 @@ module ActionView tag(:input, attributes) end - def submit_to_remote(name, value, options = {}) - html_options = options.delete(:html) || {} - html_options.merge!(:name => name, :value => value, :type => "submit") - - attributes = extract_remote_attributes!(options) - attributes.merge!(html_options) - - tag(:input, attributes) - end - def periodically_call_remote(options = {}) - attributes = extract_observer_attributes!(options) - attributes["data-js-type"] = "periodical_executer" - - script_decorator(attributes) +# frequency = options[:frequency] || 10 # every ten seconds by default +# code = "new PeriodicalExecuter(function() {#{remote_function(options)}}, #{frequency})" +# javascript_tag(code) end - #TODO: Should name change to a css query? - BR def observe_field(name, options = {}) - options[:observed] = name - attributes = extract_observer_attributes!(options) - attributes["data-js-type"] = "field_observer" - - script_decorator(attributes) - end - - def observe_field(name, options = {}) - url = options[:url] - options[:url] = url_for(url) if url && url.is_a?(Hash) - + attributes = extract_remote_attributes!(options) + callback = options.delete(:function) frequency = options.delete(:frequency) - if frequency && frequency != 0 - options[:frequency] = frequency.to_i - end - if with = options[:with] - if with !~ /[\{=(.]/ - options[:with] = "'#{options[:with]}=' + encodeURIComponent(value)" - else - options[:with] ||= 'value' unless options[:function] - end - end + attributes["data-name"] = name + attributes["data-js-type"] = "field_observer" - if function = options[:function] - statements = function # || remote_function(options) # TODO: Need to implement remote function - BR - options[:function] = JSFunction.new(statements, "element", "value") + if callback + attributes["data-observer-code"] = create_js_function(callback, "element", "value") + end + if frequency && frequency != 0 + attributes["data-frequency"] = frequency.to_i end - options[:name] = name - script_decorator("field_observer", options) + script_decorator(attributes) end - def script_decorator(js_type, options) - attributes = [%(type="application/json"), %(data-js-type="#{js_type}")] - attributes += options.map{|k, v| %(data-#{k}="#{v}")} + def script_decorator(options) + attributes = %w(type="application/json") + attributes += options.map{|k, v| k + '="' + v.to_s + '"'} "" end + # TODO: All evaled goes here per wycats module Rails2Compatibility def set_callbacks(options, html) [:complete, :failure, :success, :interactive, :loaded, :loading].each do |type| @@ -144,15 +109,50 @@ module ActionView private - # TODO: Move to javascript helpers - BR - class JSFunction - def initialize(statements, *arguments) - @statements, @arguments = statements, arguments + def extract_request_attributes!(options) + attributes = {} + attributes["data-method"] = options.delete(:method) + + url = options.delete(:url) + attributes["data-url"] = url.is_a?(Hash) ? url_for(url) : url + + #TODO: Remove all references to prototype - BR + if options.delete(:form) + attributes["data-parameters"] = 'Form.serialize(this)' + elsif submit = options.delete(:submit) + attributes["data-parameters"] = "Form.serialize('#{submit}')" + elsif with = options.delete(:with) + if with !~ /[\{=(.]/ + attributes["data-with"] = "'#{with}=' + encodeURIComponent(value)" + else + attributes["data-with"] = with + end end - def to_s(options = nil) - "function(#{@arguments.join(", ")}) {#{@statements}}" + purge_unused_attributes!(attributes) + end + + def extract_update_attributes!(options) + attributes = {} + update = options.delete(:update) + if update.is_a?(Hash) + attributes["data-update-success"] = update[:success] + attributes["data-update-failure"] = update[:failure] + else + attributes["data-update-success"] = update end + attributes["data-update-position"] = options.delete(:position) + + purge_unused_attributes!(attributes) + end + + def purge_unused_attributes!(attributes) + attributes.delete_if {|key, value| value.nil? } + attributes + end + + def create_js_function(statements, *arguments) + "function(#{arguments.join(", ")}) {#{statements}}" end end diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb index 5e62677a92..2ca47344e5 100644 --- a/actionpack/test/javascript/ajax_test.rb +++ b/actionpack/test/javascript/ajax_test.rb @@ -1,7 +1,5 @@ require "abstract_unit" -#TODO: Switch to assert_dom_equal where appropriate. assert_html is not robust enough for all tests - BR - class AjaxTestCase < ActionView::TestCase include ActionView::Helpers::AjaxHelper @@ -28,20 +26,6 @@ class AjaxTestCase < ActionView::TestCase end end - def extract_json_from_data_element(data_element) - root = HTML::Document.new(data_element).root - script = root.find(:tag => "script") - cdata = script.children.detect {|child| child.to_s =~ / "#glass_of_beer", :url => { :action => :fast }), - %w(form action="/url/hash" method="post" data-js-type="remote" data-update-success="#glass_of_beer") + assert_dom_equal %(
), + form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }) end test "when protect_against_forgery? is true" do @@ -246,6 +230,42 @@ class Article end end +class ExtractRemoteAttributesTest < AjaxTestCase + attr_reader :attributes + + test "extract_remote_attributes! html" do + attributes = extract_remote_attributes!(:html => { :class => "css_klass", :style => "border:1px solid"}) + assert_equal "css_klass", attributes[:class] + assert_equal "border:1px solid", attributes[:style] + end + + test "extract_remote_attributes! update options when :update is a hash" do + attributes = extract_remote_attributes!(:update => { :success => "foo", :failure => "bar" }) + assert_equal "foo", attributes["data-update-success"] + assert_equal "bar", attributes["data-update-failure"] + end + + test "extract_remote_attributes! update options when :update is string" do + attributes = extract_remote_attributes!(:update => "baz") + assert_equal "baz", attributes["data-update-success"] + end + + test "extract_remote_attributes! position" do + attributes = extract_remote_attributes!(:position => "before") + assert_equal "before", attributes["data-update-position"] + end + + test "extract_remote_attributes! data-js-type when it is NOT passed" do + attributes = extract_remote_attributes!({}) + assert_equal "remote", attributes["data-js-type"] + end + + test "extract_remote_attributes! data-js-type when it passed" do + attributes = extract_remote_attributes!(:js_type => "some_type") + assert_equal "some_type", attributes["data-js-type"] + end +end + class RemoteFormForTest < AjaxTestCase def setup @@ -321,11 +341,8 @@ class ButtonToRemoteTest < AjaxTestCase class StandardTest < ButtonToRemoteTest test "basic" do - button = button({:url => {:action => "whatnot"}}, {:class => "fine"}) - [/input/, /class="fine"/, /type="button"/, /value="Remote outpost"/, - /data-url="\/whatnot"/].each do |match| - assert_match match, button - end + assert_html button({:url => {:action => "whatnot"}}, {:class => "fine", :value => "RemoteOutpost"}), + %w(input class="fine" type="button" value="RemoteOutpost" data-url="/url/hash") end end @@ -336,20 +353,17 @@ class ButtonToRemoteTest < AjaxTestCase button(callback => "undoRequestCompleted(request)") end end -<<<<<<< HEAD -======= end class ScriptDecoratorTest < AjaxTestCase def decorator() - script_decorator("foo_type", :foo => "bar", :baz => "bang") + script_decorator("data-js-type" => "foo_type", "data-foo" => "bar", "data-baz" => "bang") end test "basic" do expected = %() assert_dom_equal expected, decorator end ->>>>>>> bd54253... Applied Yehuda's patch; Sharing extract_object_name_for_form! between form_helper and ajax_helper; Added script_decorator helper end class ObserveFieldTest < AjaxTestCase @@ -385,11 +399,10 @@ class ObserveFieldTest < AjaxTestCase assert_no_match /frequency/, field(:frequency => 0) end - # TODO: Finish when remote_function or some equivilent is finished -BR -# def test_observe_field -# assert_dom_equal %(), -# observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" }) -# end + test "observe field with common options" do + assert_html observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" }), + %w(script data-name="glass" data-frequency="300" data-url="/url/hash") + end # TODO: Consider using JSON instead of strings. Is using 'value' as a magical reference to the value of the observed field weird? (Rails2 does this) - BR test "using a :with option" do @@ -398,7 +411,6 @@ class ObserveFieldTest < AjaxTestCase assert_html field(:with => "'foo=' + encodeURIComponent(value)"), %w(script data-name="title" data-with="'foo=' + encodeURIComponent(value)") - end test "using json in a :with option" do @@ -408,7 +420,6 @@ class ObserveFieldTest < AjaxTestCase test "using :function for callback" do assert_html field(:function => "alert('Element changed')"), - %w(script data-function="function(element, value) {alert('Element changed')}") - + %w(script data-observer-code="function(element, value) {alert('Element changed')}") end end -- cgit v1.2.3 From 8e172f13d7f43b999b7028153ac6327ff592c72a Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Wed, 4 Nov 2009 02:14:30 -0800 Subject: Changed data-name to data-observed on observe_field --- actionpack/lib/action_view/helpers/ajax_helper.rb | 30 ++++++++++++++--------- actionpack/test/javascript/ajax_test.rb | 14 +++++------ 2 files changed, 26 insertions(+), 18 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 93a79766dc..807c943d2c 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -55,20 +55,12 @@ module ActionView end def observe_field(name, options = {}) - attributes = extract_remote_attributes!(options) - callback = options.delete(:function) - frequency = options.delete(:frequency) + options[:observed] = name - attributes["data-name"] = name + attributes = extract_remote_attributes!(options) + attributes.merge!(extract_observer_attributes!(options)) attributes["data-js-type"] = "field_observer" - if callback - attributes["data-observer-code"] = create_js_function(callback, "element", "value") - end - if frequency && frequency != 0 - attributes["data-frequency"] = frequency.to_i - end - script_decorator(attributes) end @@ -146,6 +138,22 @@ module ActionView purge_unused_attributes!(attributes) end + def extract_observer_attributes!(options) + attributes = {} + attributes["data-observed"] = options.delete(:observed) + + callback = options.delete(:function) + frequency = options.delete(:frequency) + if callback + attributes["data-observer-code"] = create_js_function(callback, "element", "value") + end + if frequency && frequency != 0 + attributes["data-frequency"] = frequency.to_i + end + + attributes + end + def purge_unused_attributes!(attributes) attributes.delete_if {|key, value| value.nil? } attributes diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb index 2ca47344e5..0cc4460870 100644 --- a/actionpack/test/javascript/ajax_test.rb +++ b/actionpack/test/javascript/ajax_test.rb @@ -382,17 +382,17 @@ class ObserveFieldTest < AjaxTestCase test "using a url string" do assert_html field(:url => "/some/other/url"), - %w(script data-url="/some/other/url" data-name="title") + %w(script data-url="/some/other/url" data-observed="title") end test "using a url hash" do assert_html field(:url => {:controller => :blog, :action => :update}), - %w(script data-url="/url/hash" data-name="title") + %w(script data-url="/url/hash" data-observed="title") end test "using a :frequency option" do assert_html field(:url => { :controller => :blog }, :frequency => 5.minutes), - %w(script data-url="/url/hash" data-name="title" data-frequency="300") + %w(script data-url="/url/hash" data-observed="title" data-frequency="300") end test "using a :frequency option of 0" do @@ -401,21 +401,21 @@ class ObserveFieldTest < AjaxTestCase test "observe field with common options" do assert_html observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" }), - %w(script data-name="glass" data-frequency="300" data-url="/url/hash") + %w(script data-observed="glass" data-frequency="300" data-url="/url/hash") end # TODO: Consider using JSON instead of strings. Is using 'value' as a magical reference to the value of the observed field weird? (Rails2 does this) - BR test "using a :with option" do assert_html field(:with => "foo"), - %w(script data-name="title" data-with="'foo=' + encodeURIComponent(value)") + %w(script data-observed="title" data-with="'foo=' + encodeURIComponent(value)") assert_html field(:with => "'foo=' + encodeURIComponent(value)"), - %w(script data-name="title" data-with="'foo=' + encodeURIComponent(value)") + %w(script data-observed="title" data-with="'foo=' + encodeURIComponent(value)") end test "using json in a :with option" do assert_html field(:with => "{'id':value}"), - %w(script data-name="title" data-with="{'id':value}") + %w(script data-observed="title" data-with="{'id':value}") end test "using :function for callback" do -- cgit v1.2.3 From 39ec7ce6a93945bc97f599d8cb503711a66f3952 Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Wed, 4 Nov 2009 02:35:16 -0800 Subject: Removed duplication --- actionpack/lib/action_view/helpers/ajax_helper.rb | 16 ++++++++-------- actionpack/test/javascript/ajax_test.rb | 12 ++++++++++++ 2 files changed, 20 insertions(+), 8 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 807c943d2c..9f1ca138eb 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -49,16 +49,16 @@ module ActionView end def periodically_call_remote(options = {}) -# frequency = options[:frequency] || 10 # every ten seconds by default -# code = "new PeriodicalExecuter(function() {#{remote_function(options)}}, #{frequency})" -# javascript_tag(code) + attributes = extract_observer_attributes!(options) + attributes["data-js-type"] = "periodical_executer" + + script_decorator(attributes) end + #TODO: Should name change to a css query? - BR def observe_field(name, options = {}) options[:observed] = name - - attributes = extract_remote_attributes!(options) - attributes.merge!(extract_observer_attributes!(options)) + attributes = extract_observer_attributes!(options) attributes["data-js-type"] = "field_observer" script_decorator(attributes) @@ -139,7 +139,7 @@ module ActionView end def extract_observer_attributes!(options) - attributes = {} + attributes = extract_remote_attributes!(options) attributes["data-observed"] = options.delete(:observed) callback = options.delete(:function) @@ -151,7 +151,7 @@ module ActionView attributes["data-frequency"] = frequency.to_i end - attributes + purge_unused_attributes!(attributes) end def purge_unused_attributes!(attributes) diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb index 0cc4460870..f1207e938d 100644 --- a/actionpack/test/javascript/ajax_test.rb +++ b/actionpack/test/javascript/ajax_test.rb @@ -423,3 +423,15 @@ class ObserveFieldTest < AjaxTestCase %w(script data-observer-code="function(element, value) {alert('Element changed')}") end end + +class PeriodicallyCallRemoteTest < AjaxTestCase + test "basic" do + assert_html periodically_call_remote(:update => "#schremser_bier", :url => { :action => "mehr_bier" }), + %w(script data-url="/url/hash" data-update-success="#schremser_bier") + end + + test "periodically call remote with :frequency" do + assert_html periodically_call_remote(:frequency => 2, :url => "/url/string"), + %w(script data-url="/url/string" data-frequency="2") + end +end -- cgit v1.2.3 From 7d34975214e80d54786f92cf1daee7ec7847a07c Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Wed, 4 Nov 2009 23:18:15 -0800 Subject: Added submit_to_remote helper --- actionpack/lib/action_view/helpers/ajax_helper.rb | 10 ++++++++++ actionpack/test/javascript/ajax_test.rb | 12 +++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 9f1ca138eb..1a75f9372b 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -48,6 +48,16 @@ module ActionView tag(:input, attributes) end + def submit_to_remote(name, value, options = {}) + html_options = options.delete(:html) || {} + html_options.merge!(:name => name, :value => value, :type => "submit") + + attributes = extract_remote_attributes!(options) + attributes.merge!(html_options) + + tag(:input, attributes) + end + def periodically_call_remote(options = {}) attributes = extract_observer_attributes!(options) attributes["data-js-type"] = "periodical_executer" diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb index f1207e938d..f4e766d77e 100644 --- a/actionpack/test/javascript/ajax_test.rb +++ b/actionpack/test/javascript/ajax_test.rb @@ -332,7 +332,7 @@ end class ButtonToRemoteTest < AjaxTestCase def button(options, html = {}) - button_to_remote("Remote outpost", options, html) + button_to_remote("RemoteOutpost", options, html) end def url_for(*) @@ -355,6 +355,16 @@ class ButtonToRemoteTest < AjaxTestCase end end +class SubmitToRemoteTest < AjaxTestCase + test "basic" do + expected = %() + options = { :url => {:action => "whatnot"}, :update => ".klass", :html => { :class => "fine" } } + + assert_dom_equal expected, + submit_to_remote("foo", "bar", options) + end +end + class ScriptDecoratorTest < AjaxTestCase def decorator() script_decorator("data-js-type" => "foo_type", "data-foo" => "bar", "data-baz" => "bang") -- cgit v1.2.3 From 95b77e925f22376bd12698a8700259894b94dc57 Mon Sep 17 00:00:00 2001 From: Bob Remeika Date: Wed, 4 Nov 2009 23:33:21 -0800 Subject: Added observe_form --- actionpack/lib/action_view/helpers/ajax_helper.rb | 8 ++++++++ actionpack/test/javascript/ajax_test.rb | 23 +++++++++++++++-------- 2 files changed, 23 insertions(+), 8 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 1a75f9372b..5de33868e9 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -74,6 +74,14 @@ module ActionView script_decorator(attributes) end + def observe_form(name, options = {}) + options[:observed] = name + attributes = extract_observer_attributes!(options) + attributes["data-js-type"] = "form_observer" + + script_decorator(attributes) + end + def script_decorator(options) attributes = %w(type="application/json") attributes += options.map{|k, v| k + '="' + v.to_s + '"'} diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb index f4e766d77e..32b6352c3c 100644 --- a/actionpack/test/javascript/ajax_test.rb +++ b/actionpack/test/javascript/ajax_test.rb @@ -392,17 +392,17 @@ class ObserveFieldTest < AjaxTestCase test "using a url string" do assert_html field(:url => "/some/other/url"), - %w(script data-url="/some/other/url" data-observed="title") + %w(script data-js-type="field_observer" data-url="/some/other/url" data-observed="title") end test "using a url hash" do assert_html field(:url => {:controller => :blog, :action => :update}), - %w(script data-url="/url/hash" data-observed="title") + %w(script data-js-type="field_observer" data-url="/url/hash" data-observed="title") end test "using a :frequency option" do assert_html field(:url => { :controller => :blog }, :frequency => 5.minutes), - %w(script data-url="/url/hash" data-observed="title" data-frequency="300") + %w(script data-js-type="field_observer" data-url="/url/hash" data-observed="title" data-frequency="300") end test "using a :frequency option of 0" do @@ -411,26 +411,33 @@ class ObserveFieldTest < AjaxTestCase test "observe field with common options" do assert_html observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" }), - %w(script data-observed="glass" data-frequency="300" data-url="/url/hash") + %w(script data-js-type="field_observer" data-observed="glass" data-frequency="300" data-url="/url/hash") end # TODO: Consider using JSON instead of strings. Is using 'value' as a magical reference to the value of the observed field weird? (Rails2 does this) - BR test "using a :with option" do assert_html field(:with => "foo"), - %w(script data-observed="title" data-with="'foo=' + encodeURIComponent(value)") + %w(script data-js-type="field_observer" data-observed="title" data-with="'foo=' + encodeURIComponent(value)") assert_html field(:with => "'foo=' + encodeURIComponent(value)"), - %w(script data-observed="title" data-with="'foo=' + encodeURIComponent(value)") + %w(script data-js-type="field_observer" data-observed="title" data-with="'foo=' + encodeURIComponent(value)") end test "using json in a :with option" do assert_html field(:with => "{'id':value}"), - %w(script data-observed="title" data-with="{'id':value}") + %w(script data-js-type="field_observer" data-observed="title" data-with="{'id':value}") end test "using :function for callback" do assert_html field(:function => "alert('Element changed')"), - %w(script data-observer-code="function(element, value) {alert('Element changed')}") + %w(script data-js-type="field_observer" data-observer-code="function(element, value) {alert('Element changed')}") + end +end + +class ObserveFormTest < AjaxTestCase + test "basic" do + assert_html observe_form("some_form", :frequency => 2, :url => { :action => "hash" }), + %w(script data-js-type="form_observer" data-url="/url/hash" data-observed="some_form" data-frequency="2") end end -- cgit v1.2.3 From 27d52e00d90604af845bcfdcc23cf54cd652e3e0 Mon Sep 17 00:00:00 2001 From: "Stephen St. Martin" Date: Sat, 23 Jan 2010 11:43:22 -0500 Subject: extract_remote_attributes should be a private method --- actionpack/lib/action_view/helpers/ajax_helper.rb | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 5de33868e9..68ce755604 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -3,16 +3,6 @@ module ActionView module AjaxHelper include UrlHelper - def extract_remote_attributes!(options) - attributes = options.delete(:html) || {} - - attributes.merge!(extract_update_attributes!(options)) - attributes.merge!(extract_request_attributes!(options)) - attributes["data-js-type"] = options.delete(:js_type) || "remote" - - attributes - end - def remote_form_for(record_or_name_or_array, *args, &proc) options = args.extract_options! object_name = extract_object_name_for_form!(args, options, record_or_name_or_array) @@ -119,6 +109,16 @@ module ActionView private + def extract_remote_attributes!(options) + attributes = options.delete(:html) || {} + + attributes.merge!(extract_update_attributes!(options)) + attributes.merge!(extract_request_attributes!(options)) + attributes["data-js-type"] = options.delete(:js_type) || "remote" + + attributes + end + def extract_request_attributes!(options) attributes = {} attributes["data-method"] = options.delete(:method) -- cgit v1.2.3 From 62a2d5178c75d4d5f1721f3c11af71ca54db296e Mon Sep 17 00:00:00 2001 From: "Stephen St. Martin" Date: Sat, 23 Jan 2010 11:52:16 -0500 Subject: cleanup some spacing --- actionpack/lib/action_view/helpers/ajax_helper.rb | 151 +++++++++++----------- 1 file changed, 75 insertions(+), 76 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 68ce755604..7d97fb9698 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -78,7 +78,81 @@ module ActionView "" end - # TODO: All evaled goes here per wycats + private + + def extract_remote_attributes!(options) + attributes = options.delete(:html) || {} + + attributes.merge!(extract_update_attributes!(options)) + attributes.merge!(extract_request_attributes!(options)) + attributes["data-js-type"] = options.delete(:js_type) || "remote" + + attributes + end + + def extract_request_attributes!(options) + attributes = {} + attributes["data-method"] = options.delete(:method) + + url = options.delete(:url) + attributes["data-url"] = url.is_a?(Hash) ? url_for(url) : url + + #TODO: Remove all references to prototype - BR + if options.delete(:form) + attributes["data-parameters"] = 'Form.serialize(this)' + elsif submit = options.delete(:submit) + attributes["data-parameters"] = "Form.serialize('#{submit}')" + elsif with = options.delete(:with) + if with !~ /[\{=(.]/ + attributes["data-with"] = "'#{with}=' + encodeURIComponent(value)" + else + attributes["data-with"] = with + end + end + + purge_unused_attributes!(attributes) + end + + def extract_update_attributes!(options) + attributes = {} + update = options.delete(:update) + if update.is_a?(Hash) + attributes["data-update-success"] = update[:success] + attributes["data-update-failure"] = update[:failure] + else + attributes["data-update-success"] = update + end + attributes["data-update-position"] = options.delete(:position) + + purge_unused_attributes!(attributes) + end + + def extract_observer_attributes!(options) + attributes = extract_remote_attributes!(options) + attributes["data-observed"] = options.delete(:observed) + + callback = options.delete(:function) + frequency = options.delete(:frequency) + if callback + attributes["data-observer-code"] = create_js_function(callback, "element", "value") + end + if frequency && frequency != 0 + attributes["data-frequency"] = frequency.to_i + end + + purge_unused_attributes!(attributes) + end + + def purge_unused_attributes!(attributes) + attributes.delete_if {|key, value| value.nil? } + attributes + end + + def create_js_function(statements, *arguments) + "function(#{arguments.join(", ")}) {#{statements}}" + end + + # TODO: All evaled goes here per wycat module Rails2Compatibility def set_callbacks(options, html) [:complete, :failure, :success, :interactive, :loaded, :loading].each do |type| @@ -106,81 +180,6 @@ module ActionView super end end - - private - - def extract_remote_attributes!(options) - attributes = options.delete(:html) || {} - - attributes.merge!(extract_update_attributes!(options)) - attributes.merge!(extract_request_attributes!(options)) - attributes["data-js-type"] = options.delete(:js_type) || "remote" - - attributes - end - - def extract_request_attributes!(options) - attributes = {} - attributes["data-method"] = options.delete(:method) - - url = options.delete(:url) - attributes["data-url"] = url.is_a?(Hash) ? url_for(url) : url - - #TODO: Remove all references to prototype - BR - if options.delete(:form) - attributes["data-parameters"] = 'Form.serialize(this)' - elsif submit = options.delete(:submit) - attributes["data-parameters"] = "Form.serialize('#{submit}')" - elsif with = options.delete(:with) - if with !~ /[\{=(.]/ - attributes["data-with"] = "'#{with}=' + encodeURIComponent(value)" - else - attributes["data-with"] = with - end - end - - purge_unused_attributes!(attributes) - end - - def extract_update_attributes!(options) - attributes = {} - update = options.delete(:update) - if update.is_a?(Hash) - attributes["data-update-success"] = update[:success] - attributes["data-update-failure"] = update[:failure] - else - attributes["data-update-success"] = update - end - attributes["data-update-position"] = options.delete(:position) - - purge_unused_attributes!(attributes) - end - - def extract_observer_attributes!(options) - attributes = extract_remote_attributes!(options) - attributes["data-observed"] = options.delete(:observed) - - callback = options.delete(:function) - frequency = options.delete(:frequency) - if callback - attributes["data-observer-code"] = create_js_function(callback, "element", "value") - end - if frequency && frequency != 0 - attributes["data-frequency"] = frequency.to_i - end - - purge_unused_attributes!(attributes) - end - - def purge_unused_attributes!(attributes) - attributes.delete_if {|key, value| value.nil? } - attributes - end - - def create_js_function(statements, *arguments) - "function(#{arguments.join(", ")}) {#{statements}}" - end - end end end -- cgit v1.2.3 From 143d0764d057bfa890534a61ef065b7a1055b998 Mon Sep 17 00:00:00 2001 From: "Stephen St. Martin" Date: Sat, 23 Jan 2010 12:14:02 -0500 Subject: nuke what appears to be a duplicate and unused test file --- actionpack/test/javascript/ajax_test.rb | 454 -------------------------------- 1 file changed, 454 deletions(-) delete mode 100644 actionpack/test/javascript/ajax_test.rb (limited to 'actionpack') diff --git a/actionpack/test/javascript/ajax_test.rb b/actionpack/test/javascript/ajax_test.rb deleted file mode 100644 index 32b6352c3c..0000000000 --- a/actionpack/test/javascript/ajax_test.rb +++ /dev/null @@ -1,454 +0,0 @@ -require "abstract_unit" - -class AjaxTestCase < ActionView::TestCase - include ActionView::Helpers::AjaxHelper - - def url_for(options) - case options - when Hash - "/url/hash" - when String - options - else - raise TypeError.new("Unsupported url type (#{options.class}) for this test helper") - end - end - - def assert_html(html, matches) - matches.each do |match| - assert_match Regexp.new(Regexp.escape(match)), html - end - end - - def assert_html_not_present(html, matches) - matches.each do |match| - assert_no_match Regexp.new(Regexp.escape(match)), html - end - end - - def self.assert_callbacks_work(&blk) - define_method(:assert_callbacks_work, &blk) - - [:complete, :failure, :success, :interactive, :loaded, :loading, 404].each do |callback| - test "#{callback} callback" do - markup = assert_callbacks_work(callback) - assert_html markup, %W(data-#{callback}-code="undoRequestCompleted\(request\)") - end - end - end -end - -class LinkToRemoteTest < AjaxTestCase - def url_for(hash) - "/blog/destroy/4" - end - - def link(options = {}) - link_to_remote("Delete this post", "/blog/destroy/4", options) - end - - test "with no update" do - assert_html link, %w(href="/blog/destroy/4" Delete\ this\ post data-remote="true") - end - - test "basic" do - assert_html link(:update => "#posts"), - %w(data-update-success="#posts") - end - - test "using a url hash" do - link = link_to_remote("Delete this post", {:controller => :blog}, :update => "#posts") - assert_html link, %w(href="/url/hash" data-update-success="#posts") - end - - test "with no update" do - assert_html link, %w(href="/blog/destroy/4" Delete\ this\ post data-js-type="remote") - end - - test "with :html options" do - expected = %{Delete this post} - assert_equal expected, link(:update => "#posts", :html => {"data-custom" => "me"}) - end - - test "with a hash for :update" do - link = link(:update => {:success => "#posts", :failure => "#error"}) - assert_html link, %w(data-js-type="remote" data-update-success="#posts" data-update-failure="#error") - end - - test "with positional parameters" do - link = link(:position => :top, :update => "#posts") - assert_match /data\-update\-position="top"/, link - end - - test "with an optional method" do - link = link(:method => "delete") - assert_match /data-method="delete"/, link - end - - class LegacyLinkToRemoteTest < AjaxTestCase - include ActionView::Helpers::AjaxHelper::Rails2Compatibility - - def link(options) - link_to_remote("Delete this post", "/blog/destroy/4", options) - end - - test "basic link_to_remote with :url =>" do - expected = %{Delete this post} - assert_equal expected, - link_to_remote("Delete this post", :url => "/blog/destroy/4", :update => "#posts") - end - - assert_callbacks_work do |callback| - link(callback => "undoRequestCompleted(request)") - end - end -end - -class FormRemoteTagTest < AjaxTestCase - - def protect_against_forgery? - false - end - - def request_forgery_protection_token - "token_name" - end - - def form_authenticity_token - "t0k3n" - end - - def authenticity_input_attributes - %w(input type="hidden" name="token_name" value="t0k3n") - end - - # TODO: Play with using assert_dom_equal - test "basic" do - assert_dom_equal %(), - form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }) - end - - test "when protect_against_forgery? is true" do - def protect_against_forgery? - true - end - - expected_form_attributes = %w(form action="/url/hash" method="post" data-js-type="remote" data-update-success="#glass_of_beer") - expected_patterns = expected_form_attributes + authenticity_input_attributes - - assert_equal true, protect_against_forgery? - assert_html form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }), expected_patterns - end - - test ":action is used when it is present" do - html = form_remote_tag(:update => "#glass_of_beer", :action => "foo") - - assert_html html, %w(form action="foo" method="post" data-js-type="remote" data-update-success="#glass_of_beer") - assert_no_match /url="foo"/, html - end - - test ":url is used when :action is not present" do - html = form_remote_tag(:update => "#glass_of_beer", :url => "bar") - - assert_html html, %w(form action="bar" method="post" data-js-type="remote" data-update-success="#glass_of_beer") - assert_no_match /url="bar"/, html - end - - test "when protect_against_forgery? is false" do - assert_equal false, protect_against_forgery? - assert_html_not_present form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }), - authenticity_input_attributes - end - - test "update callbacks" do - assert_html form_remote_tag(:update => { :success => "#glass_of_beer" }, :url => { :action => :fast }), - %w(form action="/url/hash" method="post" data-js-type="remote" data-update-success="#glass_of_beer") - - assert_html form_remote_tag(:update => { :failure => "#glass_of_water" }, :url => { :action => :fast }), - %w(form action="/url/hash" method="post" data-js-type="remote" data-update-failure="#glass_of_water") - - assert_html form_remote_tag(:update => { :success => "#glass_of_beer", :failure => "#glass_of_water" }, :url => { :action => :fast }), - %w(form action="/url/hash" method="post" data-js-type="remote" data-update-success="#glass_of_beer" data-update-failure="#glass_of_water") - end - - test "using a :method option" do - expected_form_attributes = %w(form action="/url/hash" method="post" data-js-type="remote" data-update-success="#glass_of_beer") - # TODO: Experiment with not using this _method param. Apparently this is done to address browser incompatibilities, but since - # we have a layer between the HTML and the JS libs now, we can probably get away with letting JS the JS libs handle the requirement - # for an extra field if needed. - expected_input_attributes = %w(input name="_method" type="hidden" value="put") - - assert_html form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }, :html => { :method => :put }), - expected_form_attributes + expected_input_attributes - end - - - # FIXME: This test is janky as hell. We are essentially rewriting capture and concat and they don't really work right - # because output is out of order. This test passes because it's only doing a regex match on the buffer, but this really - # needs to be fixed by using the real helper methods that rails provides. capture, concat, url_for etc. should be - # implemented by their *real* methods or we need to find a better workaround so that our tests aren't written so - # poorly. - BR - test "form_remote_tag with block in erb" do - def capture(*args, &block) - @buffer = [] - block.call(*args) if block_given? - end - def concat(str) - @buffer << str - end - - expected_form_attributes = %w(form action="/url/hash" method="post" data-js-type="remote" data-update-success="#glass_of_beer" /form) - expected_inner_html = %w(w00t!) - - form_remote_tag(:update => "#glass_of_beer", :url => { :action => :fast }) { concat expected_inner_html } - assert_html @buffer.to_s, - expected_form_attributes + expected_inner_html - end - -class Author - extend ActiveModel::Naming - include ActiveModel::Conversion - - attr_reader :id - - def save; @id = 1 end - def new_record?; @id.nil? end - def name - @id.nil? ? 'new author' : "author ##{@id}" - end -end - -class Article - extend ActiveModel::Naming - include ActiveModel::Conversion - attr_reader :id - attr_reader :author_id - def save; @id = 1; @author_id = 1 end - def new_record?; @id.nil? end - def name - @id.nil? ? 'new article' : "article ##{@id}" - end -end - -class ExtractRemoteAttributesTest < AjaxTestCase - attr_reader :attributes - - test "extract_remote_attributes! html" do - attributes = extract_remote_attributes!(:html => { :class => "css_klass", :style => "border:1px solid"}) - assert_equal "css_klass", attributes[:class] - assert_equal "border:1px solid", attributes[:style] - end - - test "extract_remote_attributes! update options when :update is a hash" do - attributes = extract_remote_attributes!(:update => { :success => "foo", :failure => "bar" }) - assert_equal "foo", attributes["data-update-success"] - assert_equal "bar", attributes["data-update-failure"] - end - - test "extract_remote_attributes! update options when :update is string" do - attributes = extract_remote_attributes!(:update => "baz") - assert_equal "baz", attributes["data-update-success"] - end - - test "extract_remote_attributes! position" do - attributes = extract_remote_attributes!(:position => "before") - assert_equal "before", attributes["data-update-position"] - end - - test "extract_remote_attributes! data-js-type when it is NOT passed" do - attributes = extract_remote_attributes!({}) - assert_equal "remote", attributes["data-js-type"] - end - - test "extract_remote_attributes! data-js-type when it passed" do - attributes = extract_remote_attributes!(:js_type => "some_type") - assert_equal "some_type", attributes["data-js-type"] - end -end - -class RemoteFormForTest < AjaxTestCase - - def setup - super - @record = @author = Author.new - @article = Article.new - end - - test "remote_form_for with record identification with new record" do - remote_form_for(@record, {:html => { :id => 'create-author' }}) {} - - expected = %() - assert_dom_equal expected, output_buffer - end - - test "remote_form_for with record identification without html options" do - remote_form_for(@record) {} - - expected = %(
) - assert_dom_equal expected, output_buffer - end - - test "remote_form_for with record identification with existing record" do - @record.save - remote_form_for(@record) {} - - expected = %(
) - assert_dom_equal expected, output_buffer - end - - test "remote_form_for with new object in list" do - remote_form_for([@author, @article]) {} - - expected = %(
) - assert_dom_equal expected, output_buffer - end - - test "remote_form_for with existing object in list" do - @author.save - @article.save - remote_form_for([@author, @article]) {} - - expected = %(
) - assert_dom_equal expected, output_buffer - end - - protected - def author_path(record) - "/authors/#{record.id}" - end - - def authors_path - "/authors" - end - - def author_articles_path(author) - "/authors/#{author.id}/articles" - end - - def author_article_path(author, article) - "/authors/#{author.id}/articles/#{article.id}" - end -end - -class ButtonToRemoteTest < AjaxTestCase - def button(options, html = {}) - button_to_remote("RemoteOutpost", options, html) - end - - def url_for(*) - "/whatnot" - end - - class StandardTest < ButtonToRemoteTest - test "basic" do - assert_html button({:url => {:action => "whatnot"}}, {:class => "fine", :value => "RemoteOutpost"}), - %w(input class="fine" type="button" value="RemoteOutpost" data-url="/url/hash") - end - end - - class LegacyButtonToRemoteTest < ButtonToRemoteTest - include ActionView::Helpers::AjaxHelper::Rails2Compatibility - - assert_callbacks_work do |callback| - button(callback => "undoRequestCompleted(request)") - end - end -end - -class SubmitToRemoteTest < AjaxTestCase - test "basic" do - expected = %() - options = { :url => {:action => "whatnot"}, :update => ".klass", :html => { :class => "fine" } } - - assert_dom_equal expected, - submit_to_remote("foo", "bar", options) - end -end - -class ScriptDecoratorTest < AjaxTestCase - def decorator() - script_decorator("data-js-type" => "foo_type", "data-foo" => "bar", "data-baz" => "bang") - end - - test "basic" do - expected = %() - assert_dom_equal expected, decorator - end -end - -class ObserveFieldTest < AjaxTestCase - def protect_against_forgery? - false - end - - def field(options = {}) - observe_field("title", options) - end - - test "basic" do - assert_html field, - %w(script type="application/json" data-js-type="field_observer") - end - - test "using a url string" do - assert_html field(:url => "/some/other/url"), - %w(script data-js-type="field_observer" data-url="/some/other/url" data-observed="title") - end - - test "using a url hash" do - assert_html field(:url => {:controller => :blog, :action => :update}), - %w(script data-js-type="field_observer" data-url="/url/hash" data-observed="title") - end - - test "using a :frequency option" do - assert_html field(:url => { :controller => :blog }, :frequency => 5.minutes), - %w(script data-js-type="field_observer" data-url="/url/hash" data-observed="title" data-frequency="300") - end - - test "using a :frequency option of 0" do - assert_no_match /frequency/, field(:frequency => 0) - end - - test "observe field with common options" do - assert_html observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" }), - %w(script data-js-type="field_observer" data-observed="glass" data-frequency="300" data-url="/url/hash") - end - - # TODO: Consider using JSON instead of strings. Is using 'value' as a magical reference to the value of the observed field weird? (Rails2 does this) - BR - test "using a :with option" do - assert_html field(:with => "foo"), - %w(script data-js-type="field_observer" data-observed="title" data-with="'foo=' + encodeURIComponent(value)") - - assert_html field(:with => "'foo=' + encodeURIComponent(value)"), - %w(script data-js-type="field_observer" data-observed="title" data-with="'foo=' + encodeURIComponent(value)") - end - - test "using json in a :with option" do - assert_html field(:with => "{'id':value}"), - %w(script data-js-type="field_observer" data-observed="title" data-with="{'id':value}") - end - - test "using :function for callback" do - assert_html field(:function => "alert('Element changed')"), - %w(script data-js-type="field_observer" data-observer-code="function(element, value) {alert('Element changed')}") - end -end - -class ObserveFormTest < AjaxTestCase - test "basic" do - assert_html observe_form("some_form", :frequency => 2, :url => { :action => "hash" }), - %w(script data-js-type="form_observer" data-url="/url/hash" data-observed="some_form" data-frequency="2") - end -end - -class PeriodicallyCallRemoteTest < AjaxTestCase - test "basic" do - assert_html periodically_call_remote(:update => "#schremser_bier", :url => { :action => "mehr_bier" }), - %w(script data-url="/url/hash" data-update-success="#schremser_bier") - end - - test "periodically call remote with :frequency" do - assert_html periodically_call_remote(:frequency => 2, :url => "/url/string"), - %w(script data-url="/url/string" data-frequency="2") - end -end -- cgit v1.2.3 From 07299eb60d4ae625b3be2e919be4dbd737fb01be Mon Sep 17 00:00:00 2001 From: "Stephen St. Martin" Date: Sat, 23 Jan 2010 12:19:29 -0500 Subject: rename ajax_test.rb to ajax_helper_test.rb for consistency --- actionpack/test/template/ajax_helper_test.rb | 174 +++++++++++++++++++++++++++ actionpack/test/template/ajax_test.rb | 174 --------------------------- 2 files changed, 174 insertions(+), 174 deletions(-) create mode 100644 actionpack/test/template/ajax_helper_test.rb delete mode 100644 actionpack/test/template/ajax_test.rb (limited to 'actionpack') diff --git a/actionpack/test/template/ajax_helper_test.rb b/actionpack/test/template/ajax_helper_test.rb new file mode 100644 index 0000000000..86932d754f --- /dev/null +++ b/actionpack/test/template/ajax_helper_test.rb @@ -0,0 +1,174 @@ +require "abstract_unit" + +class AjaxTestCase < ActiveSupport::TestCase + include ActionView::Helpers::AjaxHelper + include ActionView::Helpers::TagHelper + + def url_for(url) + case url + when Hash + "/url/hash" + when String + url + else + raise TypeError.new("Unsupported url type (#{url.class}) for this test helper") + end + end + + def assert_html(html, matches) + matches.each do |match| + assert_match(Regexp.new(Regexp.escape(match)), html) + end + end + + def self.assert_callbacks_work(&blk) + define_method(:assert_callbacks_work, &blk) + + [:complete, :failure, :success, :interactive, :loaded, :loading, 404].each do |callback| + test "#{callback} callback" do + markup = assert_callbacks_work(callback) + assert_html markup, %W(data-#{callback}-code="undoRequestCompleted\(request\)") + end + end + end +end + +class LinkToRemoteTest < AjaxTestCase + def link(options = {}) + link_to_remote("Delete this post", "/blog/destroy/3", options) + end + + test "basic" do + assert_html link(:update => "#posts"), + %w(data-update-success="#posts") + end + + test "using a url string" do + assert_html link_to_remote("Test", "/blog/update/1"), + %w(href="/blog/update/1") + end + + test "using a url hash" do + link = link_to_remote("Delete this post", {:controller => :blog}, :update => "#posts") + assert_html link, %w(href="/url/hash" data-update-success="#posts") + end + + test "with no update" do + assert_html link, %w(href="/blog/destroy/3" Delete\ this\ post data-remote="true") + end + + test "with :html options" do + expected = %{Delete this post} + assert_equal expected, link(:update => "#posts", :html => {"data-custom" => "me"}) + end + + test "with a hash for :update" do + link = link(:update => {:success => "#posts", :failure => "#error"}) + assert_match(/data-update-success="#posts"/, link) + assert_match(/data-update-failure="#error"/, link) + end + + test "with positional parameters" do + link = link(:position => :top, :update => "#posts") + assert_match(/data\-update\-position="top"/, link) + end + + test "with an optional method" do + link = link(:method => "delete") + assert_match(/data-method="delete"/, link) + end + + class LegacyLinkToRemoteTest < AjaxTestCase + include ActionView::Helpers::AjaxHelper::Rails2Compatibility + + def link(options) + link_to_remote("Delete this post", "/blog/destroy/3", options) + end + + test "basic link_to_remote with :url =>" do + expected = %{Delete this post} + assert_equal expected, + link_to_remote("Delete this post", :url => "/blog/destroy/4", :update => "#posts") + end + + assert_callbacks_work do |callback| + link(callback => "undoRequestCompleted(request)") + end + end +end + +class ButtonToRemoteTest < AjaxTestCase + def button(options, html = {}) + button_to_remote("Remote outpost", options, html) + end + + class StandardTest < ButtonToRemoteTest + test "basic" do + assert_html button({:url => {:action => "whatnot"}}, {:class => "fine"}), + %w(input class="fine" type="button" value="Remote outpost" data-url="/url/hash") + end + end + + class LegacyButtonToRemoteTest < ButtonToRemoteTest + include ActionView::Helpers::AjaxHelper::Rails2Compatibility + + assert_callbacks_work do |callback| + button(callback => "undoRequestCompleted(request)") + end + end +end + +class ObserveFieldTest < AjaxTestCase + def url_for(hash) + "/blog/update" + end + + def protect_against_forgery? + false + end + + def field(options = {}) + observe_field("title", options) + end + + test "basic" do + assert_html field, + %w(data-observe="true") + end + + test "with a :frequency option" do + assert_html field(:frequency => 5.minutes), + %w(data-observe="true" data-frequency="300") + end + + test "using a url string" do + assert_html field(:url => "/some/other/url"), + %w(data-observe="true" data-url="/some/other/url") + end + + test "using a url hash" do + assert_html field(:url => {:controller => :blog, :action => :update}), + %w(data-observe="true" data-url="/blog/update") + end + +# def test_observe_field +# assert_dom_equal %(), +# observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" }) +# end +# +# def test_observe_field_using_with_option +# expected = %() +# assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => 'id') +# assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "'id=' + encodeURIComponent(value)") +# end +# +# def test_observe_field_using_json_in_with_option +# expected = %() +# assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "{'id':value}") +# end +# +# def test_observe_field_using_function_for_callback +# assert_dom_equal %(), +# observe_field("glass", :frequency => 5.minutes, :function => "alert('Element changed')") +# end +end diff --git a/actionpack/test/template/ajax_test.rb b/actionpack/test/template/ajax_test.rb deleted file mode 100644 index 86932d754f..0000000000 --- a/actionpack/test/template/ajax_test.rb +++ /dev/null @@ -1,174 +0,0 @@ -require "abstract_unit" - -class AjaxTestCase < ActiveSupport::TestCase - include ActionView::Helpers::AjaxHelper - include ActionView::Helpers::TagHelper - - def url_for(url) - case url - when Hash - "/url/hash" - when String - url - else - raise TypeError.new("Unsupported url type (#{url.class}) for this test helper") - end - end - - def assert_html(html, matches) - matches.each do |match| - assert_match(Regexp.new(Regexp.escape(match)), html) - end - end - - def self.assert_callbacks_work(&blk) - define_method(:assert_callbacks_work, &blk) - - [:complete, :failure, :success, :interactive, :loaded, :loading, 404].each do |callback| - test "#{callback} callback" do - markup = assert_callbacks_work(callback) - assert_html markup, %W(data-#{callback}-code="undoRequestCompleted\(request\)") - end - end - end -end - -class LinkToRemoteTest < AjaxTestCase - def link(options = {}) - link_to_remote("Delete this post", "/blog/destroy/3", options) - end - - test "basic" do - assert_html link(:update => "#posts"), - %w(data-update-success="#posts") - end - - test "using a url string" do - assert_html link_to_remote("Test", "/blog/update/1"), - %w(href="/blog/update/1") - end - - test "using a url hash" do - link = link_to_remote("Delete this post", {:controller => :blog}, :update => "#posts") - assert_html link, %w(href="/url/hash" data-update-success="#posts") - end - - test "with no update" do - assert_html link, %w(href="/blog/destroy/3" Delete\ this\ post data-remote="true") - end - - test "with :html options" do - expected = %{Delete this post} - assert_equal expected, link(:update => "#posts", :html => {"data-custom" => "me"}) - end - - test "with a hash for :update" do - link = link(:update => {:success => "#posts", :failure => "#error"}) - assert_match(/data-update-success="#posts"/, link) - assert_match(/data-update-failure="#error"/, link) - end - - test "with positional parameters" do - link = link(:position => :top, :update => "#posts") - assert_match(/data\-update\-position="top"/, link) - end - - test "with an optional method" do - link = link(:method => "delete") - assert_match(/data-method="delete"/, link) - end - - class LegacyLinkToRemoteTest < AjaxTestCase - include ActionView::Helpers::AjaxHelper::Rails2Compatibility - - def link(options) - link_to_remote("Delete this post", "/blog/destroy/3", options) - end - - test "basic link_to_remote with :url =>" do - expected = %{Delete this post} - assert_equal expected, - link_to_remote("Delete this post", :url => "/blog/destroy/4", :update => "#posts") - end - - assert_callbacks_work do |callback| - link(callback => "undoRequestCompleted(request)") - end - end -end - -class ButtonToRemoteTest < AjaxTestCase - def button(options, html = {}) - button_to_remote("Remote outpost", options, html) - end - - class StandardTest < ButtonToRemoteTest - test "basic" do - assert_html button({:url => {:action => "whatnot"}}, {:class => "fine"}), - %w(input class="fine" type="button" value="Remote outpost" data-url="/url/hash") - end - end - - class LegacyButtonToRemoteTest < ButtonToRemoteTest - include ActionView::Helpers::AjaxHelper::Rails2Compatibility - - assert_callbacks_work do |callback| - button(callback => "undoRequestCompleted(request)") - end - end -end - -class ObserveFieldTest < AjaxTestCase - def url_for(hash) - "/blog/update" - end - - def protect_against_forgery? - false - end - - def field(options = {}) - observe_field("title", options) - end - - test "basic" do - assert_html field, - %w(data-observe="true") - end - - test "with a :frequency option" do - assert_html field(:frequency => 5.minutes), - %w(data-observe="true" data-frequency="300") - end - - test "using a url string" do - assert_html field(:url => "/some/other/url"), - %w(data-observe="true" data-url="/some/other/url") - end - - test "using a url hash" do - assert_html field(:url => {:controller => :blog, :action => :update}), - %w(data-observe="true" data-url="/blog/update") - end - -# def test_observe_field -# assert_dom_equal %(), -# observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" }) -# end -# -# def test_observe_field_using_with_option -# expected = %() -# assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => 'id') -# assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "'id=' + encodeURIComponent(value)") -# end -# -# def test_observe_field_using_json_in_with_option -# expected = %() -# assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "{'id':value}") -# end -# -# def test_observe_field_using_function_for_callback -# assert_dom_equal %(), -# observe_field("glass", :frequency => 5.minutes, :function => "alert('Element changed')") -# end -end -- cgit v1.2.3 From 49e84a59439074fb7742b662db21e9638d41cfd0 Mon Sep 17 00:00:00 2001 From: "Stephen St. Martin" Date: Sat, 23 Jan 2010 12:48:11 -0500 Subject: fix failing tests from fork/merge --- actionpack/lib/action_view/helpers/ajax_helper.rb | 7 ++++--- actionpack/test/template/ajax_helper_test.rb | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 7d97fb9698..f2ff424576 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -32,8 +32,9 @@ module ActionView end def button_to_remote(name, options = {}, html_options = {}) - attributes = html_options.merge!(:type => "button") + attributes = html_options.merge!(:type => "button", :value => name) attributes.merge!(extract_remote_attributes!(options)) + attributes.merge!(extract_request_attributes!(options)) tag(:input, attributes) end @@ -59,7 +60,7 @@ module ActionView def observe_field(name, options = {}) options[:observed] = name attributes = extract_observer_attributes!(options) - attributes["data-js-type"] = "field_observer" + attributes["data-observe"] = true script_decorator(attributes) end @@ -85,7 +86,7 @@ module ActionView attributes.merge!(extract_update_attributes!(options)) attributes.merge!(extract_request_attributes!(options)) - attributes["data-js-type"] = options.delete(:js_type) || "remote" + attributes["data-remote"] = true attributes end diff --git a/actionpack/test/template/ajax_helper_test.rb b/actionpack/test/template/ajax_helper_test.rb index 86932d754f..95c839b96e 100644 --- a/actionpack/test/template/ajax_helper_test.rb +++ b/actionpack/test/template/ajax_helper_test.rb @@ -104,8 +104,8 @@ class ButtonToRemoteTest < AjaxTestCase class StandardTest < ButtonToRemoteTest test "basic" do - assert_html button({:url => {:action => "whatnot"}}, {:class => "fine"}), - %w(input class="fine" type="button" value="Remote outpost" data-url="/url/hash") + expected = %{} + assert_equal expected, button({:url => "/url/hash"}, {:class => "fine"}) end end -- cgit v1.2.3 From f115fb011169cadfd1977c7e6d6ddef2eecc96de Mon Sep 17 00:00:00 2001 From: "Stephen St. Martin" Date: Sat, 23 Jan 2010 13:06:24 -0500 Subject: make observers a little more dry --- actionpack/lib/action_view/helpers/ajax_helper.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index f2ff424576..4081117ad1 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -60,7 +60,6 @@ module ActionView def observe_field(name, options = {}) options[:observed] = name attributes = extract_observer_attributes!(options) - attributes["data-observe"] = true script_decorator(attributes) end @@ -68,7 +67,6 @@ module ActionView def observe_form(name, options = {}) options[:observed] = name attributes = extract_observer_attributes!(options) - attributes["data-js-type"] = "form_observer" script_decorator(attributes) end @@ -130,6 +128,7 @@ module ActionView def extract_observer_attributes!(options) attributes = extract_remote_attributes!(options) + attributes["data-observe"] = true attributes["data-observed"] = options.delete(:observed) callback = options.delete(:function) -- cgit v1.2.3 From 1cd8b98d0193a298b6fb68443f3d24ccb4aa9447 Mon Sep 17 00:00:00 2001 From: "Erik St. Martin" Date: Sat, 23 Jan 2010 12:37:54 -0500 Subject: javascript_helper now correctly pulls in ajax_helper instead of prototype_helper. prototype_helper is pulled in by ajax_helper for reverse compatibility --- actionpack/lib/action_view/helpers/ajax_helper.rb | 4 ++-- actionpack/lib/action_view/helpers/javascript_helper.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 4081117ad1..9c1d6a722d 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -1,7 +1,7 @@ module ActionView module Helpers module AjaxHelper - include UrlHelper + include PrototypeHelper def remote_form_for(record_or_name_or_array, *args, &proc) options = args.extract_options! @@ -28,7 +28,7 @@ module ActionView attributes.merge!(options) url = url_for(url) if url.is_a?(Hash) - link_to(name, url, attributes) + content_tag(:a, name, attributes.merge(:href => url)) end def button_to_remote(name, options = {}, html_options = {}) diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb index 8f64acf102..9f6ec28a9e 100644 --- a/actionpack/lib/action_view/helpers/javascript_helper.rb +++ b/actionpack/lib/action_view/helpers/javascript_helper.rb @@ -39,7 +39,7 @@ module ActionView JAVASCRIPT_PATH = File.join(File.dirname(__FILE__), 'javascripts') end - include PrototypeHelper + include AjaxHelper::Rails2Compatibility # Returns a link of the given +name+ that will trigger a JavaScript +function+ using the # onclick handler and return false after the fact. -- cgit v1.2.3 From 5462caf434d7313b0a5bff75fd2bca35bbaf42a6 Mon Sep 17 00:00:00 2001 From: "Erik St. Martin" Date: Sat, 23 Jan 2010 13:12:08 -0500 Subject: fixing failing tests from last commit, order of attributes matters should probably change this later --- actionpack/test/template/ajax_helper_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/test/template/ajax_helper_test.rb b/actionpack/test/template/ajax_helper_test.rb index 95c839b96e..80d1f42327 100644 --- a/actionpack/test/template/ajax_helper_test.rb +++ b/actionpack/test/template/ajax_helper_test.rb @@ -58,7 +58,7 @@ class LinkToRemoteTest < AjaxTestCase end test "with :html options" do - expected = %{Delete this post} + expected = %{Delete this post} assert_equal expected, link(:update => "#posts", :html => {"data-custom" => "me"}) end @@ -86,7 +86,7 @@ class LinkToRemoteTest < AjaxTestCase end test "basic link_to_remote with :url =>" do - expected = %{Delete this post} + expected = %{Delete this post} assert_equal expected, link_to_remote("Delete this post", :url => "/blog/destroy/4", :update => "#posts") end -- cgit v1.2.3 From 565a696e71606a6e4dfe5b1c7f9fadbce50e04b1 Mon Sep 17 00:00:00 2001 From: "Erik St. Martin" Date: Sat, 23 Jan 2010 14:10:24 -0500 Subject: Removed all helpers from PrototypeHelper that are implemented in AjaxHelper. Modified tests that extended with PrototypeHelper to now extend using AjaxHelper. AjaxHelper is now included by default in view helper --- actionpack/lib/action_view/helpers.rb | 4 +- actionpack/lib/action_view/helpers/ajax_helper.rb | 5 +- .../lib/action_view/helpers/prototype_helper.rb | 446 --------------------- actionpack/test/template/form_helper_test.rb | 8 +- actionpack/test/template/prototype_helper_test.rb | 193 --------- 5 files changed, 10 insertions(+), 646 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers.rb b/actionpack/lib/action_view/helpers.rb index 3d088678fc..268ea984e3 100644 --- a/actionpack/lib/action_view/helpers.rb +++ b/actionpack/lib/action_view/helpers.rb @@ -15,7 +15,7 @@ module ActionView #:nodoc: autoload :FormTagHelper, 'action_view/helpers/form_tag_helper' autoload :JavaScriptHelper, 'action_view/helpers/javascript_helper' autoload :NumberHelper, 'action_view/helpers/number_helper' - autoload :PrototypeHelper, 'action_view/helpers/prototype_helper' + autoload :AjaxHelper, 'action_view/helpers/ajax_helper' autoload :RawOutputHelper, 'action_view/helpers/raw_output_helper' autoload :RecordIdentificationHelper, 'action_view/helpers/record_identification_helper' autoload :RecordTagHelper, 'action_view/helpers/record_tag_helper' @@ -48,7 +48,7 @@ module ActionView #:nodoc: include FormTagHelper include JavaScriptHelper include NumberHelper - include PrototypeHelper + include AjaxHelper include RawOutputHelper include RecordIdentificationHelper include RecordTagHelper diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 9c1d6a722d..550f7fbbe2 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -1,7 +1,9 @@ module ActionView module Helpers module AjaxHelper - include PrototypeHelper + # Included for backwards compatibility / RJS functionality + # Rails classes should not be aware of individual JS frameworks + include PrototypeHelper def remote_form_for(record_or_name_or_array, *args, &proc) options = args.extract_options! @@ -19,6 +21,7 @@ module ActionView attributes.merge!(options) url = attributes.delete("data-url") + attributes.delete(:builder) form_tag(attributes.delete(:action) || url, attributes, &block) end diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index bef93dd0f8..2bd6afba56 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -27,40 +27,6 @@ module ActionView # ActionView::Helpers::JavaScriptHelper for more information on including # this and other JavaScript files in your Rails templates.) # - # Now you're ready to call a remote action either through a link... - # - # link_to_remote "Add to cart", - # :url => { :action => "add", :id => product.id }, - # :update => { :success => "cart", :failure => "error" } - # - # ...through a form... - # - # <% form_remote_tag :url => '/shipping' do -%> - #
<%= submit_tag 'Recalculate Shipping' %>
- # <% end -%> - # - # ...periodically... - # - # periodically_call_remote(:url => 'update', :frequency => '5', :update => 'ticker') - # - # ...or through an observer (i.e., a form or field that is observed and calls a remote - # action when changed). - # - # <%= observe_field(:searchbox, - # :url => { :action => :live_search }), - # :frequency => 0.5, - # :update => :hits, - # :with => 'query' - # %> - # - # As you can see, there are numerous ways to use Prototype's Ajax functions (and actually more than - # are listed here); check out the documentation for each method to find out more about its usage and options. - # - # === Common Options - # See link_to_remote for documentation of options common to all Ajax - # helpers; any of the options specified by link_to_remote can be used - # by the other helpers. - # # == Designing your Rails actions for Ajax # When building your action handlers (that is, the Rails actions that receive your background requests), it's # important to remember a few things. First, whatever your action would normally return to the browser, it will @@ -116,325 +82,6 @@ module ActionView :form, :with, :update, :script, :type ]).merge(CALLBACKS) end - # Returns a link to a remote action defined by options[:url] - # (using the url_for format) that's called in the background using - # XMLHttpRequest. The result of that request can then be inserted into a - # DOM object whose id can be specified with options[:update]. - # Usually, the result would be a partial prepared by the controller with - # render :partial. - # - # Examples: - # # Generates: Delete this post - # link_to_remote "Delete this post", :update => "posts", - # :url => { :action => "destroy", :id => post.id } - # - # # Generates: Refresh - # link_to_remote(image_tag("refresh"), :update => "emails", - # :url => { :action => "list_emails" }) - # - # You can override the generated HTML options by specifying a hash in - # options[:html]. - # - # link_to_remote "Delete this post", :update => "posts", - # :url => post_url(@post), :method => :delete, - # :html => { :class => "destructive" } - # - # You can also specify a hash for options[:update] to allow for - # easy redirection of output to an other DOM element if a server-side - # error occurs: - # - # Example: - # # Generates: Delete this post - # link_to_remote "Delete this post", - # :url => { :action => "destroy", :id => post.id }, - # :update => { :success => "posts", :failure => "error" } - # - # Optionally, you can use the options[:position] parameter to - # influence how the target DOM element is updated. It must be one of - # :before, :top, :bottom, or :after. - # - # The method used is by default POST. You can also specify GET or you - # can simulate PUT or DELETE over POST. All specified with options[:method] - # - # Example: - # # Generates: Destroy - # link_to_remote "Destroy", :url => person_url(:id => person), :method => :delete - # - # By default, these remote requests are processed asynchronous during - # which various JavaScript callbacks can be triggered (for progress - # indicators and the likes). All callbacks get access to the - # request object, which holds the underlying XMLHttpRequest. - # - # To access the server response, use request.responseText, to - # find out the HTTP status, use request.status. - # - # Example: - # # Generates: hello - # word = 'hello' - # link_to_remote word, - # :url => { :action => "undo", :n => word_counter }, - # :complete => "undoRequestCompleted(request)" - # - # The callbacks that may be specified are (in order): - # - # :loading:: Called when the remote document is being - # loaded with data by the browser. - # :loaded:: Called when the browser has finished loading - # the remote document. - # :interactive:: Called when the user can interact with the - # remote document, even though it has not - # finished loading. - # :success:: Called when the XMLHttpRequest is completed, - # and the HTTP status code is in the 2XX range. - # :failure:: Called when the XMLHttpRequest is completed, - # and the HTTP status code is not in the 2XX - # range. - # :complete:: Called when the XMLHttpRequest is complete - # (fires after success/failure if they are - # present). - # - # You can further refine :success and :failure by - # adding additional callbacks for specific status codes. - # - # Example: - # # Generates: hello - # link_to_remote word, - # :url => { :action => "action" }, - # 404 => "alert('Not found...? Wrong URL...?')", - # :failure => "alert('HTTP Error ' + request.status + '!')" - # - # A status code callback overrides the success/failure handlers if - # present. - # - # If you for some reason or another need synchronous processing (that'll - # block the browser while the request is happening), you can specify - # options[:type] = :synchronous. - # - # You can customize further browser side call logic by passing in - # JavaScript code snippets via some optional parameters. In their order - # of use these are: - # - # :confirm:: Adds confirmation dialog. - # :condition:: Perform remote request conditionally - # by this expression. Use this to - # describe browser-side conditions when - # request should not be initiated. - # :before:: Called before request is initiated. - # :after:: Called immediately after request was - # initiated and before :loading. - # :submit:: Specifies the DOM element ID that's used - # as the parent of the form elements. By - # default this is the current form, but - # it could just as well be the ID of a - # table row or any other DOM element. - # :with:: A JavaScript expression specifying - # the parameters for the XMLHttpRequest. - # Any expressions should return a valid - # URL query string. - # - # Example: - # - # :with => "'name=' + $('name').value" - # - # You can generate a link that uses AJAX in the general case, while - # degrading gracefully to plain link behavior in the absence of - # JavaScript by setting html_options[:href] to an alternate URL. - # Note the extra curly braces around the options hash separate - # it as the second parameter from html_options, the third. - # - # Example: - # link_to_remote "Delete this post", - # { :update => "posts", :url => { :action => "destroy", :id => post.id } }, - # :href => url_for(:action => "destroy", :id => post.id) - def link_to_remote(name, options = {}, html_options = nil) - link_to_function(name, remote_function(options), html_options || options.delete(:html)) - end - - # Creates a button with an onclick event which calls a remote action - # via XMLHttpRequest - # The options for specifying the target with :url - # and defining callbacks is the same as link_to_remote. - def button_to_remote(name, options = {}, html_options = {}) - button_to_function(name, remote_function(options), html_options) - end - - # Periodically calls the specified url (options[:url]) every - # options[:frequency] seconds (default is 10). Usually used to - # update a specified div (options[:update]) with the results - # of the remote call. The options for specifying the target with :url - # and defining callbacks is the same as link_to_remote. - # Examples: - # # Call get_averages and put its results in 'avg' every 10 seconds - # # Generates: - # # new PeriodicalExecuter(function() {new Ajax.Updater('avg', '/grades/get_averages', - # # {asynchronous:true, evalScripts:true})}, 10) - # periodically_call_remote(:url => { :action => 'get_averages' }, :update => 'avg') - # - # # Call invoice every 10 seconds with the id of the customer - # # If it succeeds, update the invoice DIV; if it fails, update the error DIV - # # Generates: - # # new PeriodicalExecuter(function() {new Ajax.Updater({success:'invoice',failure:'error'}, - # # '/testing/invoice/16', {asynchronous:true, evalScripts:true})}, 10) - # periodically_call_remote(:url => { :action => 'invoice', :id => customer.id }, - # :update => { :success => "invoice", :failure => "error" } - # - # # Call update every 20 seconds and update the new_block DIV - # # Generates: - # # new PeriodicalExecuter(function() {new Ajax.Updater('news_block', 'update', {asynchronous:true, evalScripts:true})}, 20) - # periodically_call_remote(:url => 'update', :frequency => '20', :update => 'news_block') - # - def periodically_call_remote(options = {}) - frequency = options[:frequency] || 10 # every ten seconds by default - code = "new PeriodicalExecuter(function() {#{remote_function(options)}}, #{frequency})" - javascript_tag(code) - end - - # Returns a form tag that will submit using XMLHttpRequest in the - # background instead of the regular reloading POST arrangement. Even - # though it's using JavaScript to serialize the form elements, the form - # submission will work just like a regular submission as viewed by the - # receiving side (all elements available in params). The options for - # specifying the target with :url and defining callbacks is the same as - # +link_to_remote+. - # - # A "fall-through" target for browsers that doesn't do JavaScript can be - # specified with the :action/:method options on :html. - # - # Example: - # # Generates: - # #
- # form_remote_tag :html => { :action => - # url_for(:controller => "some", :action => "place") } - # - # The Hash passed to the :html key is equivalent to the options (2nd) - # argument in the FormTagHelper.form_tag method. - # - # By default the fall-through action is the same as the one specified in - # the :url (and the default method is :post). - # - # form_remote_tag also takes a block, like form_tag: - # # Generates: - # #
- # #
- # <% form_remote_tag :url => '/posts' do -%> - #
<%= submit_tag 'Save' %>
- # <% end -%> - def form_remote_tag(options = {}, &block) - options[:form] = true - - options[:html] ||= {} - options[:html][:onsubmit] = - (options[:html][:onsubmit] ? options[:html][:onsubmit] + "; " : "") + - "#{remote_function(options)}; return false;" - - form_tag(options[:html].delete(:action) || url_for(options[:url]), options[:html], &block) - end - - # Creates a form that will submit using XMLHttpRequest in the background - # instead of the regular reloading POST arrangement and a scope around a - # specific resource that is used as a base for questioning about - # values for the fields. - # - # === Resource - # - # Example: - # <% remote_form_for(@post) do |f| %> - # ... - # <% end %> - # - # This will expand to be the same as: - # - # <% remote_form_for :post, @post, :url => post_path(@post), :html => { :method => :put, :class => "edit_post", :id => "edit_post_45" } do |f| %> - # ... - # <% end %> - # - # === Nested Resource - # - # Example: - # <% remote_form_for([@post, @comment]) do |f| %> - # ... - # <% end %> - # - # This will expand to be the same as: - # - # <% remote_form_for :comment, @comment, :url => post_comment_path(@post, @comment), :html => { :method => :put, :class => "edit_comment", :id => "edit_comment_45" } do |f| %> - # ... - # <% end %> - # - # If you don't need to attach a form to a resource, then check out form_remote_tag. - # - # See FormHelper#form_for for additional semantics. - def remote_form_for(record_or_name_or_array, *args, &proc) - options = args.extract_options! - - case record_or_name_or_array - when String, Symbol - object_name = record_or_name_or_array - when Array - object = record_or_name_or_array.last - object_name = ActionController::RecordIdentifier.singular_class_name(object) - apply_form_for_options!(record_or_name_or_array, options) - args.unshift object - else - object = record_or_name_or_array - object_name = ActionController::RecordIdentifier.singular_class_name(record_or_name_or_array) - apply_form_for_options!(object, options) - args.unshift object - end - - concat(form_remote_tag(options)) - fields_for(object_name, *(args << options), &proc) - concat(''.html_safe!) - end - alias_method :form_remote_for, :remote_form_for - - # Returns a button input tag with the element name of +name+ and a value (i.e., display text) of +value+ - # that will submit form using XMLHttpRequest in the background instead of a regular POST request that - # reloads the page. - # - # # Create a button that submits to the create action - # # - # # Generates: - # <%= submit_to_remote 'create_btn', 'Create', :url => { :action => 'create' } %> - # - # # Submit to the remote action update and update the DIV succeed or fail based - # # on the success or failure of the request - # # - # # Generates: - # <%= submit_to_remote 'update_btn', 'Update', :url => { :action => 'update' }, - # :update => { :success => "succeed", :failure => "fail" } - # - # options argument is the same as in form_remote_tag. - def submit_to_remote(name, value, options = {}) - options[:with] ||= 'Form.serialize(this.form)' - - html_options = options.delete(:html) || {} - html_options[:name] = name - - button_to_remote(value, options, html_options) - end - - # Returns 'eval(request.responseText)' which is the JavaScript function - # that +form_remote_tag+ can call in :complete to evaluate a multiple - # update return document using +update_element_function+ calls. - def evaluate_remote_response - "eval(request.responseText)" - end - # Returns the JavaScript needed for a remote function. # Takes the same arguments as link_to_remote. # @@ -476,99 +123,6 @@ module ActionView return function end - # Observes the field with the DOM ID specified by +field_id+ and calls a - # callback when its contents have changed. The default callback is an - # Ajax call. By default the value of the observed field is sent as a - # parameter with the Ajax call. - # - # Example: - # # Generates: new Form.Element.Observer('suggest', 0.25, function(element, value) {new Ajax.Updater('suggest', - # # '/testing/find_suggestion', {asynchronous:true, evalScripts:true, parameters:'q=' + value})}) - # <%= observe_field :suggest, :url => { :action => :find_suggestion }, - # :frequency => 0.25, - # :update => :suggest, - # :with => 'q' - # %> - # - # Required +options+ are either of: - # :url:: +url_for+-style options for the action to call - # when the field has changed. - # :function:: Instead of making a remote call to a URL, you - # can specify javascript code to be called instead. - # Note that the value of this option is used as the - # *body* of the javascript function, a function definition - # with parameters named element and value will be generated for you - # for example: - # observe_field("glass", :frequency => 1, :function => "alert('Element changed')") - # will generate: - # new Form.Element.Observer('glass', 1, function(element, value) {alert('Element changed')}) - # The element parameter is the DOM element being observed, and the value is its value at the - # time the observer is triggered. - # - # Additional options are: - # :frequency:: The frequency (in seconds) at which changes to - # this field will be detected. Not setting this - # option at all or to a value equal to or less than - # zero will use event based observation instead of - # time based observation. - # :update:: Specifies the DOM ID of the element whose - # innerHTML should be updated with the - # XMLHttpRequest response text. - # :with:: A JavaScript expression specifying the parameters - # for the XMLHttpRequest. The default is to send the - # key and value of the observed field. Any custom - # expressions should return a valid URL query string. - # The value of the field is stored in the JavaScript - # variable +value+. - # - # Examples - # - # :with => "'my_custom_key=' + value" - # :with => "'person[name]=' + prompt('New name')" - # :with => "Form.Element.serialize('other-field')" - # - # Finally - # :with => 'name' - # is shorthand for - # :with => "'name=' + value" - # This essentially just changes the key of the parameter. - # - # Additionally, you may specify any of the options documented in the - # Common options section at the top of this document. - # - # Example: - # - # # Sends params: {:title => 'Title of the book'} when the book_title input - # # field is changed. - # observe_field 'book_title', - # :url => 'http://example.com/books/edit/1', - # :with => 'title' - # - # - def observe_field(field_id, options = {}) - if options[:frequency] && options[:frequency] > 0 - build_observer('Form.Element.Observer', field_id, options) - else - build_observer('Form.Element.EventObserver', field_id, options) - end - end - - # Observes the form with the DOM ID specified by +form_id+ and calls a - # callback when its contents have changed. The default callback is an - # Ajax call. By default all fields of the observed field are sent as - # parameters with the Ajax call. - # - # The +options+ for +observe_form+ are the same as the options for - # +observe_field+. The JavaScript variable +value+ available to the - # :with option is set to the serialized form by default. - def observe_form(form_id, options = {}) - if options[:frequency] - build_observer('Form.Observer', form_id, options) - else - build_observer('Form.EventObserver', form_id, options) - end - end - # All the methods were moved to GeneratorMethods so that # #include_helpers_from_context has nothing to overwrite. class JavaScriptGenerator #:nodoc: diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index 0c5c5d17ee..147d3dc05d 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -1232,7 +1232,7 @@ class FormHelperTest < ActionView::TestCase # Perhaps this test should be moved to prototype helper tests. def test_remote_form_for_with_labelled_builder - self.extend ActionView::Helpers::PrototypeHelper + self.extend ActionView::Helpers::AjaxHelper remote_form_for(:post, @post, :builder => LabelledFormBuilder) do |f| concat f.text_field(:title) @@ -1241,7 +1241,7 @@ class FormHelperTest < ActionView::TestCase end expected = - %(
) + + %() + "
" + "
" + "
" + @@ -1397,10 +1397,10 @@ class FormHelperTest < ActionView::TestCase end def test_remote_form_for_with_html_options_adds_options_to_form_tag - self.extend ActionView::Helpers::PrototypeHelper + self.extend ActionView::Helpers::AjaxHelper remote_form_for(:post, @post, :html => {:id => 'some_form', :class => 'some_class'}) do |f| end - expected = "
" + expected = "
" assert_dom_equal expected, output_buffer end diff --git a/actionpack/test/template/prototype_helper_test.rb b/actionpack/test/template/prototype_helper_test.rb index 9225153798..86f9c231c0 100644 --- a/actionpack/test/template/prototype_helper_test.rb +++ b/actionpack/test/template/prototype_helper_test.rb @@ -82,199 +82,6 @@ class PrototypeHelperTest < PrototypeHelperBaseTest super end - def test_link_to_remote - assert_dom_equal %(Remote outauthor), - link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }}, { :class => "fine" }) - assert_dom_equal %(Remote outauthor), - link_to_remote("Remote outauthor", :complete => "alert(request.responseText)", :url => { :action => "whatnot" }) - assert_dom_equal %(Remote outauthor), - link_to_remote("Remote outauthor", :success => "alert(request.responseText)", :url => { :action => "whatnot" }) - assert_dom_equal %(Remote outauthor), - link_to_remote("Remote outauthor", :failure => "alert(request.responseText)", :url => { :action => "whatnot" }) - assert_dom_equal %(Remote outauthor), - link_to_remote("Remote outauthor", :failure => "alert(request.responseText)", :url => { :action => "whatnot", :a => '10', :b => '20' }) - assert_dom_equal %(Remote outauthor), - link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :type => :synchronous) - assert_dom_equal %(Remote outauthor), - link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :position => :bottom) - end - - def test_link_to_remote_html_options - assert_dom_equal %(Remote outauthor), - link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }, :html => { :class => "fine" } }) - end - - def test_link_to_remote_url_quote_escaping - assert_dom_equal %(Remote), - link_to_remote("Remote", { :url => { :action => "whatnot's" } }) - end - - def test_button_to_remote - assert_dom_equal %(), - button_to_remote("Remote outpost", { :url => { :action => "whatnot" }}, { :class => "fine" }) - assert_dom_equal %(), - button_to_remote("Remote outpost", :complete => "alert(request.reponseText)", :url => { :action => "whatnot" }) - assert_dom_equal %(), - button_to_remote("Remote outpost", :success => "alert(request.reponseText)", :url => { :action => "whatnot" }) - assert_dom_equal %(), - button_to_remote("Remote outpost", :failure => "alert(request.reponseText)", :url => { :action => "whatnot" }) - assert_dom_equal %(), - button_to_remote("Remote outpost", :failure => "alert(request.reponseText)", :url => { :action => "whatnot", :a => '10', :b => '20' }) - end - - def test_periodically_call_remote - assert_dom_equal %(), - periodically_call_remote(:update => "schremser_bier", :url => { :action => "mehr_bier" }) - end - - def test_periodically_call_remote_with_frequency - assert_dom_equal( - "", - periodically_call_remote(:frequency => 2) - ) - end - - def test_form_remote_tag - assert_dom_equal %(
), - form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) - assert_dom_equal %(), - form_remote_tag(:update => { :success => "glass_of_beer" }, :url => { :action => :fast }) - assert_dom_equal %(), - form_remote_tag(:update => { :failure => "glass_of_water" }, :url => { :action => :fast }) - assert_dom_equal %(), - form_remote_tag(:update => { :success => 'glass_of_beer', :failure => "glass_of_water" }, :url => { :action => :fast }) - end - - def test_form_remote_tag_with_method - assert_dom_equal %(
), - form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, :html => { :method => :put }) - end - - def test_form_remote_tag_with_block_in_erb - __in_erb_template = '' - form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) { concat "Hello world!" } - assert_dom_equal %(Hello world!
), output_buffer - end - - def test_remote_form_for_with_record_identification_with_new_record - remote_form_for(@record, {:html => { :id => 'create-author' }}) {} - - expected = %(
) - assert_dom_equal expected, output_buffer - end - - def test_remote_form_for_with_record_identification_without_html_options - remote_form_for(@record) {} - - expected = %(
) - assert_dom_equal expected, output_buffer - end - - def test_remote_form_for_with_record_identification_with_existing_record - @record.save - remote_form_for(@record) {} - - expected = %(
) - assert_dom_equal expected, output_buffer - end - - def test_remote_form_for_with_new_object_in_list - remote_form_for([@author, @article]) {} - - expected = %(
) - assert_dom_equal expected, output_buffer - end - - def test_remote_form_for_with_existing_object_in_list - @author.save - @article.save - remote_form_for([@author, @article]) {} - - expected = %(
) - assert_dom_equal expected, output_buffer - end - - def test_on_callbacks - callbacks = [:uninitialized, :loading, :loaded, :interactive, :complete, :success, :failure] - callbacks.each do |callback| - assert_dom_equal %(
), - form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();") - assert_dom_equal %(), - form_remote_tag(:update => { :success => "glass_of_beer" }, :url => { :action => :fast }, callback=>"monkeys();") - assert_dom_equal %(), - form_remote_tag(:update => { :failure => "glass_of_beer" }, :url => { :action => :fast }, callback=>"monkeys();") - assert_dom_equal %(), - form_remote_tag(:update => { :success => "glass_of_beer", :failure => "glass_of_water" }, :url => { :action => :fast }, callback=>"monkeys();") - end - - #HTTP status codes 200 up to 599 have callbacks - #these should work - 100.upto(599) do |callback| - assert_dom_equal %(), - form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();") - end - - #test 200 and 404 - assert_dom_equal %(), - form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, 200=>"monkeys();", 404=>"bananas();") - - #these shouldn't - 1.upto(99) do |callback| - assert_dom_equal %(), - form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();") - end - 600.upto(999) do |callback| - assert_dom_equal %(), - form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();") - end - - #test ultimate combo - assert_dom_equal %(), - form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, :loading => "c1()", :success => "s()", :failure => "f();", :complete => "c();", 200=>"monkeys();", 404=>"bananas();") - - end - - def test_submit_to_remote - assert_dom_equal %(), - submit_to_remote("More beer!", 1_000_000, :update => "empty_bottle") - end - - def test_observe_field - assert_dom_equal %(), - observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" }) - end - - def test_observe_field_using_with_option - expected = %() - assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => 'id') - assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "'id=' + encodeURIComponent(value)") - end - - def test_observe_field_using_json_in_with_option - expected = %() - assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "{'id':value}") - end - - def test_observe_field_using_function_for_callback - assert_dom_equal %(), - observe_field("glass", :frequency => 5.minutes, :function => "alert('Element changed')") - end - - def test_observe_form - assert_dom_equal %(), - observe_form("cart", :frequency => 2, :url => { :action => "cart_changed" }) - end - - def test_observe_form_using_function_for_callback - assert_dom_equal %(), - observe_form("cart", :frequency => 2, :function => "alert('Form changed')") - end - - def test_observe_field_without_frequency - assert_dom_equal %(), - observe_field("glass") - end - def test_update_page old_output_buffer = output_buffer -- cgit v1.2.3 From d8343a6ad7d6bffb88a075cb9e575d85e098e4b1 Mon Sep 17 00:00:00 2001 From: "Stephen St. Martin" Date: Sat, 23 Jan 2010 15:33:05 -0500 Subject: restructure compatibility module so it is no longer a child --- actionpack/lib/action_view/helpers.rb | 4 +- actionpack/lib/action_view/helpers/ajax_helper.rb | 47 ++++++++++++---------- .../lib/action_view/helpers/javascript_helper.rb | 2 +- 3 files changed, 28 insertions(+), 25 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers.rb b/actionpack/lib/action_view/helpers.rb index 268ea984e3..215a697cce 100644 --- a/actionpack/lib/action_view/helpers.rb +++ b/actionpack/lib/action_view/helpers.rb @@ -3,7 +3,7 @@ require 'active_support/benchmarkable' module ActionView #:nodoc: module Helpers #:nodoc: autoload :ActiveModelHelper, 'action_view/helpers/active_model_helper' - autoload :AjaxHelper, 'action_view/helpers/ajax_helper' + autoload :AjaxHelperCompat, 'action_view/helpers/ajax_helper' autoload :AssetTagHelper, 'action_view/helpers/asset_tag_helper' autoload :AtomFeedHelper, 'action_view/helpers/atom_feed_helper' autoload :CacheHelper, 'action_view/helpers/cache_helper' @@ -48,7 +48,7 @@ module ActionView #:nodoc: include FormTagHelper include JavaScriptHelper include NumberHelper - include AjaxHelper + include AjaxHelperCompat include RawOutputHelper include RecordIdentificationHelper include RecordTagHelper diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 550f7fbbe2..ab4f5d53e9 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -154,34 +154,37 @@ module ActionView def create_js_function(statements, *arguments) "function(#{arguments.join(", ")}) {#{statements}}" end + end - # TODO: All evaled goes here per wycat - module Rails2Compatibility - def set_callbacks(options, html) - [:complete, :failure, :success, :interactive, :loaded, :loading].each do |type| - html["data-#{type}-code"] = options.delete(type.to_sym) - end + # TODO: All evaled goes here per wycat + module AjaxHelperCompat + include AjaxHelper - options.each do |option, value| - if option.is_a?(Integer) - html["data-#{option}-code"] = options.delete(option) - end - end + def set_callbacks(options, html) + [:complete, :failure, :success, :interactive, :loaded, :loading].each do |type| + html["data-#{type}-code"] = options.delete(type.to_sym) end - - def link_to_remote(name, url, options = nil) - if !options && url.is_a?(Hash) && url.key?(:url) - url, options = url.delete(:url), url + + options.each do |option, value| + if option.is_a?(Integer) + html["data-#{option}-code"] = options.delete(option) end - set_callbacks(options, options[:html] ||= {}) - - super end - - def button_to_remote(name, options = {}, html_options = {}) - set_callbacks(options, html_options) - super + end + + def link_to_remote(name, url, options = nil) + if !options && url.is_a?(Hash) && url.key?(:url) + url, options = url.delete(:url), url end + set_callbacks(options, options[:html] ||= {}) + + super + end + + def button_to_remote(name, options = {}, html_options = {}) + html_options.merge!(:testing => true) + set_callbacks(options, html_options) + super end end end diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb index 9f6ec28a9e..adb35ccfa2 100644 --- a/actionpack/lib/action_view/helpers/javascript_helper.rb +++ b/actionpack/lib/action_view/helpers/javascript_helper.rb @@ -39,7 +39,7 @@ module ActionView JAVASCRIPT_PATH = File.join(File.dirname(__FILE__), 'javascripts') end - include AjaxHelper::Rails2Compatibility + include AjaxHelperCompat # Returns a link of the given +name+ that will trigger a JavaScript +function+ using the # onclick handler and return false after the fact. -- cgit v1.2.3 From 20c6c71e6a998a3157e2545e834e3d678d231ec5 Mon Sep 17 00:00:00 2001 From: "Stephen St. Martin" Date: Sat, 23 Jan 2010 15:34:17 -0500 Subject: oops, remove test code --- actionpack/lib/action_view/helpers/ajax_helper.rb | 1 - 1 file changed, 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index ab4f5d53e9..02b2588c42 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -182,7 +182,6 @@ module ActionView end def button_to_remote(name, options = {}, html_options = {}) - html_options.merge!(:testing => true) set_callbacks(options, html_options) super end -- cgit v1.2.3 From 255066b6c7a5877de20e9aef9b58f886c7e66e13 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Sat, 23 Jan 2010 14:41:08 -0600 Subject: first round of documenation for ujs --- actionpack/lib/action_view/helpers/ajax_helper.rb | 404 +++++++++++++++++++++- 1 file changed, 401 insertions(+), 3 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 02b2588c42..54915e3c89 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -5,6 +5,55 @@ module ActionView # Rails classes should not be aware of individual JS frameworks include PrototypeHelper + # Creates a form that will submit using XMLHttpRequest in the background + # instead of the regular reloading POST arrangement and a scope around a + # specific resource that is used as a base for questioning about + # values for the fields. + # + # === Resource + # + # Example: + # + # # Generates: + # # ... + # # + # <% remote_form_for(@post) do |f| %> + # ... + # <% end %> + # + # This will expand to be the same as: + # + # <% remote_form_for :post, @post, :url => post_path(@post), :html => { :method => :put, :class => "edit_post", :id => "edit_post_45" } do |f| %> + # ... + # <% end %> + # + # === Nested Resource + # + # Example: + # # Generates: + # # ... + # # + # <% remote_form_for([@post, @comment]) do |f| %> + # ... + # <% end %> + # + # This will expand to be the same as: + # + # <% remote_form_for :comment, @comment, :url => post_comment_path(@post, @comment), :html => { :method => :put, :class => "edit_comment", :id => "edit_comment_45" } do |f| %> + # ... + # <% end %> + # + # If you don't need to attach a form to a resource, then check out form_remote_tag. + # + # See FormHelper#form_for for additional semantics. def remote_form_for(record_or_name_or_array, *args, &proc) options = args.extract_options! object_name = extract_object_name_for_form!(args, options, record_or_name_or_array) @@ -15,6 +64,46 @@ module ActionView end alias_method :form_remote_for, :remote_form_for + # Returns a form tag that will submit using XMLHttpRequest in the + # background instead of the regular reloading POST arrangement. Even + # though it's using JavaScript to serialize the form elements, the form + # submission will work just like a regular submission as viewed by the + # receiving side (all elements available in params). The options for + # specifying the target with :url and defining callbacks is the same as + # +link_to_remote+. + # + # A "fall-through" target for browsers that doesn't do JavaScript can be + # specified with the :action/:method options on :html. + # + # Example: + # + # # Generates: + # # ... + # # + # form_remote_tag :html => { :action => + # url_for(:controller => "some", :action => "place") } + # < form data-remote action="/some/place" method="post" > + # + # The Hash passed to the :html key is equivalent to the options (2nd) + # argument in the FormTagHelper.form_tag method. + # + # By default the fall-through action is the same as the one specified in + # the :url (and the default method is :post). + # + # form_remote_tag also takes a block, like form_tag: + # # Generates: + # # + # #
+ # # + # # + # <% form_remote_tag :url => '/posts' do -%> + #
<%= submit_tag 'Save' %>
+ # <% end -%> + def form_remote_tag(options = {}, &block) attributes = {} attributes.merge!(extract_remote_attributes!(options)) @@ -25,6 +114,179 @@ module ActionView form_tag(attributes.delete(:action) || url, attributes, &block) end + # Returns a link to a remote action defined by options[:url] + # (using the url_for format) that's called in the background using + # XMLHttpRequest. The result of that request can then be inserted into a + # DOM object whose id can be specified with options[:update]. + # Usually, the result would be a partial prepared by the controller with + # render :partial. + # + # Examples: + # + # # Generates: + # # Delete this post + # # + # link_to_remote "Delete this post", :update => "posts", + # :url => { :action => "destroy", :id => post.id } + # + # # Generates: + # # + # # + # # + # link_to_remote(image_tag("refresh"), :update => "emails", + # :url => { :action => "list_emails" }) + # + # You can override the generated HTML options by specifying a hash in + # options[:html]. + # + # # Generates: + # # Delete this post + # # + # link_to_remote "Delete this post", :update => "posts", + # :url => post_url(@post), :method => :delete, + # :html => { :class => "destructive" } + # + # You can also specify a hash for options[:update] to allow for + # easy redirection of output to an other DOM element if a server-side + # error occurs: + # + # Example: + # # Generates: + # # Delete this post + # # + # link_to_remote "Delete this post", + # :url => { :action => "destroy", :id => post.id }, + # :update => { :success => "posts", :failure => "error" } + # + # Optionally, you can use the options[:position] parameter to + # influence how the target DOM element is updated. It must be one of + # :before, :top, :bottom, or :after. + # + # The method used is by default POST. You can also specify GET or you + # can simulate PUT or DELETE over POST. All specified with options[:method] + # + # Example: + # # Generates: + # # Destroy + # # + # link_to_remote "Destroy", :url => person_url(:id => person), :method => :delete + # + # By default, these remote requests are processed asynchronous during + # which various JavaScript callbacks can be triggered (for progress + # indicators and the likes). All callbacks get access to the + # request object, which holds the underlying XMLHttpRequest. + # + # To access the server response, use request.responseText, to + # find out the HTTP status, use request.status. + # + # Example: + # # Generates: + # # hello + # # + # word = 'hello' + # link_to_remote word, + # :url => { :action => "undo", :n => word_counter }, + # :complete => "undoRequestCompleted(request)" + # + # The callbacks that may be specified are (in order): (deprecated) + # + # :loading:: Called when the remote document is being + # loaded with data by the browser. + # :loaded:: Called when the browser has finished loading + # the remote document. + # :interactive:: Called when the user can interact with the + # remote document, even though it has not + # finished loading. + # :success:: Called when the XMLHttpRequest is completed, + # and the HTTP status code is in the 2XX range. + # :failure:: Called when the XMLHttpRequest is completed, + # and the HTTP status code is not in the 2XX + # range. + # :complete:: Called when the XMLHttpRequest is complete + # (fires after success/failure if they are + # present). + # + # You can further refine :success and :failure by + # adding additional callbacks for specific status codes. + # + # Example: + # + # # Generates: + # # Hello + # # + # link_to_remote word, + # :url => { :action => "action" }, + # 404 => "alert('Not found...? Wrong URL...?')", + # :failure => "alert('HTTP Error ' + request.status + '!')" + # + # A status code callback overrides the success/failure handlers if + # present. + # + # If you for some reason or another need synchronous processing (that'll + # block the browser while the request is happening), you can specify + # options[:type] = :synchronous. + # + # You can customize further browser side call logic by passing in + # JavaScript code snippets via some optional parameters. In their order + # of use these are: + # + # :confirm:: Adds confirmation dialog. + # :condition:: Perform remote request conditionally + # by this expression. Use this to + # describe browser-side conditions when + # request should not be initiated. + # :before:: Called before request is initiated. + # :after:: Called immediately after request was + # initiated and before :loading. + # :submit:: Specifies the DOM element ID that's used + # as the parent of the form elements. By + # default this is the current form, but + # it could just as well be the ID of a + # table row or any other DOM element. + # :with:: A JavaScript expression specifying + # the parameters for the XMLHttpRequest. + # Any expressions should return a valid + # URL query string. + # + # Example: + # + # :with => "'name=' + $('name').value" + # + # You can generate a link that uses AJAX in the general case, while + # degrading gracefully to plain link behavior in the absence of + # JavaScript by setting html_options[:href] to an alternate URL. + # Note the extra curly braces around the options hash separate + # it as the second parameter from html_options, the third. + # + # Example: + # + # # Generates: + # # Delete this post + # # + # link_to_remote "Delete this post", + # { :update => "posts", :url => { :action => "destroy", :id => post.id } }, + # :href => url_for(:action => "destroy", :id => post.id) def link_to_remote(name, url, options = {}) attributes = {} attributes.merge!(extract_remote_attributes!(options)) @@ -33,7 +295,11 @@ module ActionView url = url_for(url) if url.is_a?(Hash) content_tag(:a, name, attributes.merge(:href => url)) end - + + # Creates a button with an onclick event which calls a remote action + # via XMLHttpRequest + # The options for specifying the target with :url + # and defining callbacks is the same as link_to_remote. def button_to_remote(name, options = {}, html_options = {}) attributes = html_options.merge!(:type => "button", :value => name) attributes.merge!(extract_remote_attributes!(options)) @@ -42,6 +308,37 @@ module ActionView tag(:input, attributes) end + # Returns a button input tag with the element name of +name+ and a value (i.e., display text) of +value+ + # that will submit form using XMLHttpRequest in the background instead of a regular POST request that + # reloads the page. + # + # # Create a button that submits to the create action + # # + # # Generates: + # # + # # + # <%= submit_to_remote 'create_btn', 'Create', :url => { :action => 'create' } %> + # + # # Submit to the remote action update and update the DIV succeed or fail based + # # on the success or failure of the request + # # + # # Generates: + # # + # # + # <%= submit_to_remote 'update_btn', 'Update', :url => { :action => 'update' }, + # :update => { :success => "succeed", :failure => "fail" } + # + # options argument is the same as in form_remote_tag. def submit_to_remote(name, value, options = {}) html_options = options.delete(:html) || {} html_options.merge!(:name => name, :value => value, :type => "submit") @@ -52,6 +349,31 @@ module ActionView tag(:input, attributes) end + # Periodically calls the specified url (options[:url]) every + # options[:frequency] seconds (default is 10). Usually used to + # update a specified div (options[:update]) with the results + # of the remote call. The options for specifying the target with :url + # and defining callbacks is the same as link_to_remote. + # Examples: + # # Call get_averages and put its results in 'avg' every 10 seconds + # # Generates: + # # new PeriodicalExecuter(function() {new Ajax.Updater('avg', '/grades/get_averages', + # # {asynchronous:true, evalScripts:true})}, 10) + # periodically_call_remote(:url => { :action => 'get_averages' }, :update => 'avg') + # + # # Call invoice every 10 seconds with the id of the customer + # # If it succeeds, update the invoice DIV; if it fails, update the error DIV + # # Generates: + # # new PeriodicalExecuter(function() {new Ajax.Updater({success:'invoice',failure:'error'}, + # # '/testing/invoice/16', {asynchronous:true, evalScripts:true})}, 10) + # periodically_call_remote(:url => { :action => 'invoice', :id => customer.id }, + # :update => { :success => "invoice", :failure => "error" } + # + # # Call update every 20 seconds and update the new_block DIV + # # Generates: + # # new PeriodicalExecuter(function() {new Ajax.Updater('news_block', 'update', {asynchronous:true, evalScripts:true})}, 20) + # periodically_call_remote(:url => 'update', :frequency => '20', :update => 'news_block') + # def periodically_call_remote(options = {}) attributes = extract_observer_attributes!(options) attributes["data-js-type"] = "periodical_executer" @@ -59,14 +381,90 @@ module ActionView script_decorator(attributes) end - #TODO: Should name change to a css query? - BR + # Observes the field with the DOM ID specified by +field_id+ and calls a + # callback when its contents have changed. The default callback is an + # Ajax call. By default the value of the observed field is sent as a + # parameter with the Ajax call. + # + # Example: + # # Generates: new Form.Element.Observer('suggest', 0.25, function(element, value) {new Ajax.Updater('suggest', + # # '/testing/find_suggestion', {asynchronous:true, evalScripts:true, parameters:'q=' + value})}) + # <%= observe_field :suggest, :url => { :action => :find_suggestion }, + # :frequency => 0.25, + # :update => :suggest, + # :with => 'q' + # %> + # + # Required +options+ are either of: + # :url:: +url_for+-style options for the action to call + # when the field has changed. + # :function:: Instead of making a remote call to a URL, you + # can specify javascript code to be called instead. + # Note that the value of this option is used as the + # *body* of the javascript function, a function definition + # with parameters named element and value will be generated for you + # for example: + # observe_field("glass", :frequency => 1, :function => "alert('Element changed')") + # will generate: + # new Form.Element.Observer('glass', 1, function(element, value) {alert('Element changed')}) + # The element parameter is the DOM element being observed, and the value is its value at the + # time the observer is triggered. + # + # Additional options are: + # :frequency:: The frequency (in seconds) at which changes to + # this field will be detected. Not setting this + # option at all or to a value equal to or less than + # zero will use event based observation instead of + # time based observation. + # :update:: Specifies the DOM ID of the element whose + # innerHTML should be updated with the + # XMLHttpRequest response text. + # :with:: A JavaScript expression specifying the parameters + # for the XMLHttpRequest. The default is to send the + # key and value of the observed field. Any custom + # expressions should return a valid URL query string. + # The value of the field is stored in the JavaScript + # variable +value+. + # + # Examples + # + # :with => "'my_custom_key=' + value" + # :with => "'person[name]=' + prompt('New name')" + # :with => "Form.Element.serialize('other-field')" + # + # Finally + # :with => 'name' + # is shorthand for + # :with => "'name=' + value" + # This essentially just changes the key of the parameter. + # + # Additionally, you may specify any of the options documented in the + # Common options section at the top of this document. + # + # Example: + # + # # Sends params: {:title => 'Title of the book'} when the book_title input + # # field is changed. + # observe_field 'book_title', + # :url => 'http://example.com/books/edit/1', + # :with => 'title' + # + # def observe_field(name, options = {}) options[:observed] = name attributes = extract_observer_attributes!(options) script_decorator(attributes) end - + + # Observes the form with the DOM ID specified by +form_id+ and calls a + # callback when its contents have changed. The default callback is an + # Ajax call. By default all fields of the observed field are sent as + # parameters with the Ajax call. + # + # The +options+ for +observe_form+ are the same as the options for + # +observe_field+. The JavaScript variable +value+ available to the + # :with option is set to the serialized form by default. def observe_form(name, options = {}) options[:observed] = name attributes = extract_observer_attributes!(options) -- cgit v1.2.3 From 7bf5aef907a90a9896c05ae3c6ed371a70aa6b8f Mon Sep 17 00:00:00 2001 From: "Erik St. Martin" Date: Sat, 23 Jan 2010 16:10:44 -0500 Subject: fixed current tests that were failing do to module location change, this is temporary to fix state of repo till all the new tests are complete --- actionpack/lib/action_view/helpers/ajax_helper.rb | 2 ++ actionpack/test/template/ajax_helper_test.rb | 11 ++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 54915e3c89..6f7f3750bc 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -574,6 +574,8 @@ module ActionView if !options && url.is_a?(Hash) && url.key?(:url) url, options = url.delete(:url), url end + options = {} if options.nil? + set_callbacks(options, options[:html] ||= {}) super diff --git a/actionpack/test/template/ajax_helper_test.rb b/actionpack/test/template/ajax_helper_test.rb index 80d1f42327..4ca130d010 100644 --- a/actionpack/test/template/ajax_helper_test.rb +++ b/actionpack/test/template/ajax_helper_test.rb @@ -1,7 +1,6 @@ require "abstract_unit" class AjaxTestCase < ActiveSupport::TestCase - include ActionView::Helpers::AjaxHelper include ActionView::Helpers::TagHelper def url_for(url) @@ -34,6 +33,8 @@ class AjaxTestCase < ActiveSupport::TestCase end class LinkToRemoteTest < AjaxTestCase + include ActionView::Helpers::AjaxHelperCompat + def link(options = {}) link_to_remote("Delete this post", "/blog/destroy/3", options) end @@ -79,7 +80,7 @@ class LinkToRemoteTest < AjaxTestCase end class LegacyLinkToRemoteTest < AjaxTestCase - include ActionView::Helpers::AjaxHelper::Rails2Compatibility + include ActionView::Helpers::AjaxHelperCompat def link(options) link_to_remote("Delete this post", "/blog/destroy/3", options) @@ -98,6 +99,8 @@ class LinkToRemoteTest < AjaxTestCase end class ButtonToRemoteTest < AjaxTestCase + include ActionView::Helpers::AjaxHelperCompat + def button(options, html = {}) button_to_remote("Remote outpost", options, html) end @@ -110,7 +113,7 @@ class ButtonToRemoteTest < AjaxTestCase end class LegacyButtonToRemoteTest < ButtonToRemoteTest - include ActionView::Helpers::AjaxHelper::Rails2Compatibility + include ActionView::Helpers::AjaxHelperCompat assert_callbacks_work do |callback| button(callback => "undoRequestCompleted(request)") @@ -119,6 +122,8 @@ class ButtonToRemoteTest < AjaxTestCase end class ObserveFieldTest < AjaxTestCase + include ActionView::Helpers::AjaxHelperCompat + def url_for(hash) "/blog/update" end -- cgit v1.2.3 From 37ad57596b7afdf38be443f06130b736539dd2af Mon Sep 17 00:00:00 2001 From: "Stephen St. Martin" Date: Sat, 23 Jan 2010 19:45:01 -0500 Subject: port existing test suite to check for new output, and fix all breaking tests --- actionpack/lib/action_view/helpers/ajax_helper.rb | 86 +++--- actionpack/test/template/ajax_helper_test.rb | 344 ++++++++++++++-------- 2 files changed, 268 insertions(+), 162 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 6f7f3750bc..7d164929f0 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -105,13 +105,15 @@ module ActionView # <% end -%> def form_remote_tag(options = {}, &block) + html_options = options.delete(:callbacks) + attributes = {} attributes.merge!(extract_remote_attributes!(options)) + attributes.merge!(html_options) if html_options attributes.merge!(options) - - url = attributes.delete("data-url") attributes.delete(:builder) - form_tag(attributes.delete(:action) || url, attributes, &block) + + form_tag(attributes.delete(:action) || attributes.delete("data-url"), attributes, &block) end # Returns a link to a remote action defined by options[:url] @@ -287,13 +289,12 @@ module ActionView # link_to_remote "Delete this post", # { :update => "posts", :url => { :action => "destroy", :id => post.id } }, # :href => url_for(:action => "destroy", :id => post.id) - def link_to_remote(name, url, options = {}) + def link_to_remote(name, options, html_options = {}) attributes = {} attributes.merge!(extract_remote_attributes!(options)) - attributes.merge!(options) + attributes.merge!(html_options) - url = url_for(url) if url.is_a?(Hash) - content_tag(:a, name, attributes.merge(:href => url)) + content_tag(:a, name, attributes.merge(:href => "#")) end # Creates a button with an onclick event which calls a remote action @@ -303,7 +304,6 @@ module ActionView def button_to_remote(name, options = {}, html_options = {}) attributes = html_options.merge!(:type => "button", :value => name) attributes.merge!(extract_remote_attributes!(options)) - attributes.merge!(extract_request_attributes!(options)) tag(:input, attributes) end @@ -341,10 +341,12 @@ module ActionView # options argument is the same as in form_remote_tag. def submit_to_remote(name, value, options = {}) html_options = options.delete(:html) || {} - html_options.merge!(:name => name, :value => value, :type => "submit") + html_options.merge!(:name => name, :value => value, :type => "button") attributes = extract_remote_attributes!(options) attributes.merge!(html_options) + attributes["data-submit"] = true + attributes.delete("data-remote") tag(:input, attributes) end @@ -376,7 +378,7 @@ module ActionView # def periodically_call_remote(options = {}) attributes = extract_observer_attributes!(options) - attributes["data-js-type"] = "periodical_executer" + attributes["data-periodical"] = true script_decorator(attributes) end @@ -493,9 +495,11 @@ module ActionView def extract_request_attributes!(options) attributes = {} attributes["data-method"] = options.delete(:method) + attributes["data-remote-type"] = options.delete(:type) - url = options.delete(:url) - attributes["data-url"] = url.is_a?(Hash) ? url_for(url) : url + url_options = options.delete(:url) + url_options = url_options.merge(:escape => false) if url_options.is_a?(Hash) + attributes["data-url"] = escape_javascript(url_for(url_options)) #TODO: Remove all references to prototype - BR if options.delete(:form) @@ -528,18 +532,16 @@ module ActionView end def extract_observer_attributes!(options) + callback = options.delete(:function) + frequency = options.delete(:frequency) + + attributes = extract_remote_attributes!(options) attributes["data-observe"] = true attributes["data-observed"] = options.delete(:observed) - - callback = options.delete(:function) - frequency = options.delete(:frequency) - if callback - attributes["data-observer-code"] = create_js_function(callback, "element", "value") - end - if frequency && frequency != 0 - attributes["data-frequency"] = frequency.to_i - end + attributes["data-onobserve"] = create_js_function(callback, "element", "value") if callback + attributes["data-frequency"] = frequency.to_i if frequency && frequency != 0 + attributes.delete("data-remote") purge_unused_attributes!(attributes) end @@ -558,26 +560,8 @@ module ActionView module AjaxHelperCompat include AjaxHelper - def set_callbacks(options, html) - [:complete, :failure, :success, :interactive, :loaded, :loading].each do |type| - html["data-#{type}-code"] = options.delete(type.to_sym) - end - - options.each do |option, value| - if option.is_a?(Integer) - html["data-#{option}-code"] = options.delete(option) - end - end - end - - def link_to_remote(name, url, options = nil) - if !options && url.is_a?(Hash) && url.key?(:url) - url, options = url.delete(:url), url - end - options = {} if options.nil? - - set_callbacks(options, options[:html] ||= {}) - + def link_to_remote(name, options, html_options = {}) + set_callbacks(options, html_options) super end @@ -585,6 +569,26 @@ module ActionView set_callbacks(options, html_options) super end + + def form_remote_tag(options, &block) + html = {} + set_callbacks(options, html) + options.merge!(:callbacks => html) + super + end + + private + def set_callbacks(options, html) + [:uninitialized, :complete, :failure, :success, :interactive, :loaded, :loading].each do |type| + html["data-on#{type}"] = options.delete(type.to_sym) + end + + options.each do |option, value| + if option.is_a?(Integer) + html["data-on#{option}"] = options.delete(option) + end + end + end end end end diff --git a/actionpack/test/template/ajax_helper_test.rb b/actionpack/test/template/ajax_helper_test.rb index 4ca130d010..cb28448913 100644 --- a/actionpack/test/template/ajax_helper_test.rb +++ b/actionpack/test/template/ajax_helper_test.rb @@ -1,179 +1,281 @@ -require "abstract_unit" - -class AjaxTestCase < ActiveSupport::TestCase - include ActionView::Helpers::TagHelper - - def url_for(url) - case url - when Hash - "/url/hash" - when String - url - else - raise TypeError.new("Unsupported url type (#{url.class}) for this test helper") - end +require 'abstract_unit' +require 'active_model' + +class Author + extend ActiveModel::Naming + include ActiveModel::Conversion + + attr_reader :id + def save; @id = 1 end + def new_record?; @id.nil? end + def name + @id.nil? ? 'new author' : "author ##{@id}" end +end - def assert_html(html, matches) - matches.each do |match| - assert_match(Regexp.new(Regexp.escape(match)), html) - end +class Article + extend ActiveModel::Naming + include ActiveModel::Conversion + attr_reader :id + attr_reader :author_id + def save; @id = 1; @author_id = 1 end + def new_record?; @id.nil? end + def name + @id.nil? ? 'new article' : "article ##{@id}" end +end + +class AjaxHelperBaseTest < ActionView::TestCase + attr_accessor :formats, :output_buffer - def self.assert_callbacks_work(&blk) - define_method(:assert_callbacks_work, &blk) + def reset_formats(format) + @format = format + end - [:complete, :failure, :success, :interactive, :loaded, :loading, 404].each do |callback| - test "#{callback} callback" do - markup = assert_callbacks_work(callback) - assert_html markup, %W(data-#{callback}-code="undoRequestCompleted\(request\)") + def setup + super + @template = self + @controller = Class.new do + def url_for(options) + if options.is_a?(String) + options + else + url = "http://www.example.com/" + url << options[:action].to_s if options and options[:action] + url << "?a=#{options[:a]}" if options && options[:a] + url << "&b=#{options[:b]}" if options && options[:a] && options[:b] + url + end end - end + end.new end + + protected + def request_forgery_protection_token + nil + end + + def protect_against_forgery? + false + end end -class LinkToRemoteTest < AjaxTestCase - include ActionView::Helpers::AjaxHelperCompat +class AjaxHelperTest < AjaxHelperBaseTest + def _evaluate_assigns_and_ivars() end - def link(options = {}) - link_to_remote("Delete this post", "/blog/destroy/3", options) + def setup + @record = @author = Author.new + @article = Article.new + super end - test "basic" do - assert_html link(:update => "#posts"), - %w(data-update-success="#posts") + test "link_to_remote" do + assert_dom_equal %(Remote outauthor), + link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }}, { :class => "fine" }) + assert_dom_equal %(Remote outauthor), + link_to_remote("Remote outauthor", :complete => "alert(request.responseText)", :url => { :action => "whatnot" }) + assert_dom_equal %(Remote outauthor), + link_to_remote("Remote outauthor", :success => "alert(request.responseText)", :url => { :action => "whatnot" }) + assert_dom_equal %(Remote outauthor), + link_to_remote("Remote outauthor", :failure => "alert(request.responseText)", :url => { :action => "whatnot" }) + assert_dom_equal %(Remote outauthor), + link_to_remote("Remote outauthor", :failure => "alert(request.responseText)", :url => { :action => "whatnot", :a => '10', :b => '20' }) + assert_dom_equal %(Remote outauthor), + link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :type => :synchronous) + assert_dom_equal %(Remote outauthor), + link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :position => :bottom) end - test "using a url string" do - assert_html link_to_remote("Test", "/blog/update/1"), - %w(href="/blog/update/1") + test "link_to_remote html options" do + assert_dom_equal %(Remote outauthor), + link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }, :html => { :class => "fine" } }) end - test "using a url hash" do - link = link_to_remote("Delete this post", {:controller => :blog}, :update => "#posts") - assert_html link, %w(href="/url/hash" data-update-success="#posts") + test "link_to_remote url quote escaping" do + assert_dom_equal %(Remote), + link_to_remote("Remote", { :url => { :action => "whatnot's" } }) end - test "with no update" do - assert_html link, %w(href="/blog/destroy/3" Delete\ this\ post data-remote="true") + test "button_to_remote" do + assert_dom_equal %(), + button_to_remote("Remote outpost", { :url => { :action => "whatnot" }}, { :class => "fine" }) + assert_dom_equal %(), + button_to_remote("Remote outpost", :complete => "alert(request.reponseText)", :url => { :action => "whatnot" }) + assert_dom_equal %(), + button_to_remote("Remote outpost", :success => "alert(request.reponseText)", :url => { :action => "whatnot" }) + assert_dom_equal %(), + button_to_remote("Remote outpost", :failure => "alert(request.reponseText)", :url => { :action => "whatnot" }) + assert_dom_equal %(), + button_to_remote("Remote outpost", :failure => "alert(request.reponseText)", :url => { :action => "whatnot", :a => '10', :b => '20' }) end - test "with :html options" do - expected = %{Delete this post} - assert_equal expected, link(:update => "#posts", :html => {"data-custom" => "me"}) + test "periodically_call_remote" do + assert_dom_equal %(), + periodically_call_remote(:update => "schremser_bier", :url => { :action => "mehr_bier" }) end - test "with a hash for :update" do - link = link(:update => {:success => "#posts", :failure => "#error"}) - assert_match(/data-update-success="#posts"/, link) - assert_match(/data-update-failure="#error"/, link) + test "periodically_call_remote_with_frequency" do + assert_dom_equal( + "", + periodically_call_remote(:frequency => 2) + ) end - test "with positional parameters" do - link = link(:position => :top, :update => "#posts") - assert_match(/data\-update\-position="top"/, link) + test "form_remote_tag" do + assert_dom_equal %(
), + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) + assert_dom_equal %(), + form_remote_tag(:update => { :success => "glass_of_beer" }, :url => { :action => :fast }) + assert_dom_equal %(), + form_remote_tag(:update => { :failure => "glass_of_water" }, :url => { :action => :fast }) + assert_dom_equal %(), + form_remote_tag(:update => { :success => 'glass_of_beer', :failure => "glass_of_water" }, :url => { :action => :fast }) end - test "with an optional method" do - link = link(:method => "delete") - assert_match(/data-method="delete"/, link) + test "form_remote_tag with method" do + assert_dom_equal %(
), + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, :html => { :method => :put }) end - class LegacyLinkToRemoteTest < AjaxTestCase - include ActionView::Helpers::AjaxHelperCompat + test "form_remote_tag with block in erb" do + __in_erb_template = '' + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) { concat "Hello world!" } + assert_dom_equal %(Hello world!
), output_buffer + end - def link(options) - link_to_remote("Delete this post", "/blog/destroy/3", options) - end + test "remote_form_for with record identification with new record" do + remote_form_for(@record, {:html => { :id => 'create-author' }}) {} - test "basic link_to_remote with :url =>" do - expected = %{Delete this post} - assert_equal expected, - link_to_remote("Delete this post", :url => "/blog/destroy/4", :update => "#posts") - end + expected = %(
) + assert_dom_equal expected, output_buffer + end - assert_callbacks_work do |callback| - link(callback => "undoRequestCompleted(request)") - end + test "remote_form_for with record identification without html options" do + remote_form_for(@record) {} + + expected = %(
) + assert_dom_equal expected, output_buffer end -end -class ButtonToRemoteTest < AjaxTestCase - include ActionView::Helpers::AjaxHelperCompat + test "remote_form_for with record identification with existing record" do + @record.save + remote_form_for(@record) {} - def button(options, html = {}) - button_to_remote("Remote outpost", options, html) + expected = %(
) + assert_dom_equal expected, output_buffer end - class StandardTest < ButtonToRemoteTest - test "basic" do - expected = %{} - assert_equal expected, button({:url => "/url/hash"}, {:class => "fine"}) - end + test "remote_form_for with new object in list" do + remote_form_for([@author, @article]) {} + + expected = %(
) + assert_dom_equal expected, output_buffer end - class LegacyButtonToRemoteTest < ButtonToRemoteTest - include ActionView::Helpers::AjaxHelperCompat + test "remote_form_for with existing object in list" do + @author.save + @article.save + remote_form_for([@author, @article]) {} - assert_callbacks_work do |callback| - button(callback => "undoRequestCompleted(request)") + expected = %(
) + assert_dom_equal expected, output_buffer + end + + test "on callbacks" do + callbacks = [:uninitialized, :loading, :loaded, :interactive, :complete, :success, :failure] + callbacks.each do |callback| + assert_dom_equal %(
), + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();") + assert_dom_equal %(), + form_remote_tag(:update => { :success => "glass_of_beer" }, :url => { :action => :fast }, callback=>"monkeys();") + assert_dom_equal %(), + form_remote_tag(:update => { :failure => "glass_of_beer" }, :url => { :action => :fast }, callback=>"monkeys();") + assert_dom_equal %(), + form_remote_tag(:update => { :success => "glass_of_beer", :failure => "glass_of_water" }, :url => { :action => :fast }, callback=>"monkeys();") + end + + #HTTP status codes 200 up to 599 have callbacks + #these should work + 100.upto(599) do |callback| + assert_dom_equal %(), + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();") + end + + #test 200 and 404 + assert_dom_equal %(), + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, 200=>"monkeys();", 404=>"bananas();") + + #these shouldn't + 1.upto(99) do |callback| + assert_dom_equal %(), + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();") + end + 600.upto(999) do |callback| + assert_dom_equal %(), + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();") end + + #test ultimate combo + assert_dom_equal %(), + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, :loading => "c1()", :success => "s()", :failure => "f();", :complete => "c();", 200=>"monkeys();", 404=>"bananas();") + end -end -class ObserveFieldTest < AjaxTestCase - include ActionView::Helpers::AjaxHelperCompat + test "submit_to_remote" do + assert_dom_equal %(), + submit_to_remote("More beer!", 1_000_000, :update => "empty_bottle") + end - def url_for(hash) - "/blog/update" + test "observe_field" do + assert_dom_equal %(), + observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" }) end - def protect_against_forgery? - false + test "observe_field using with option" do + expected = %() + assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => 'id') + assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "'id=' + encodeURIComponent(value)") end - def field(options = {}) - observe_field("title", options) + test "observe_field using json in with option" do + expected = %() + assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "{'id':value}") end - test "basic" do - assert_html field, - %w(data-observe="true") + test "observe_field using function for callback" do + assert_dom_equal %(), + observe_field("glass", :frequency => 5.minutes, :function => "alert('Element changed')") end - test "with a :frequency option" do - assert_html field(:frequency => 5.minutes), - %w(data-observe="true" data-frequency="300") + test "observe_form" do + assert_dom_equal %(), + observe_form("cart", :frequency => 2, :url => { :action => "cart_changed" }) end - test "using a url string" do - assert_html field(:url => "/some/other/url"), - %w(data-observe="true" data-url="/some/other/url") + test "observe_form using function for callback" do + assert_dom_equal %(), + observe_form("cart", :frequency => 2, :function => "alert('Form changed')") end - test "using a url hash" do - assert_html field(:url => {:controller => :blog, :action => :update}), - %w(data-observe="true" data-url="/blog/update") + test "observe_field without frequency" do + assert_dom_equal %(), + observe_field("glass") end -# def test_observe_field -# assert_dom_equal %(), -# observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" }) -# end -# -# def test_observe_field_using_with_option -# expected = %() -# assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => 'id') -# assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "'id=' + encodeURIComponent(value)") -# end -# -# def test_observe_field_using_json_in_with_option -# expected = %() -# assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "{'id':value}") -# end -# -# def test_observe_field_using_function_for_callback -# assert_dom_equal %(), -# observe_field("glass", :frequency => 5.minutes, :function => "alert('Element changed')") -# end + protected + def author_path(record) + "/authors/#{record.id}" + end + + def authors_path + "/authors" + end + + def author_articles_path(author) + "/authors/#{author.id}/articles" + end + + def author_article_path(author, article) + "/authors/#{author.id}/articles/#{article.id}" + end end -- cgit v1.2.3 From 9f5cb3d3b48d0e7d702144d87208ac18778e3d38 Mon Sep 17 00:00:00 2001 From: "Erik St. Martin" Date: Sun, 24 Jan 2010 08:33:27 -0500 Subject: moving include of ScriptaculousHelper into PrototypeHelper, ActionView should know as little as possible about individual frameworks --- actionpack/lib/action_view/helpers.rb | 2 -- actionpack/lib/action_view/helpers/prototype_helper.rb | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers.rb b/actionpack/lib/action_view/helpers.rb index 215a697cce..080eb87445 100644 --- a/actionpack/lib/action_view/helpers.rb +++ b/actionpack/lib/action_view/helpers.rb @@ -20,7 +20,6 @@ module ActionView #:nodoc: autoload :RecordIdentificationHelper, 'action_view/helpers/record_identification_helper' autoload :RecordTagHelper, 'action_view/helpers/record_tag_helper' autoload :SanitizeHelper, 'action_view/helpers/sanitize_helper' - autoload :ScriptaculousHelper, 'action_view/helpers/scriptaculous_helper' autoload :TagHelper, 'action_view/helpers/tag_helper' autoload :TextHelper, 'action_view/helpers/text_helper' autoload :TranslationHelper, 'action_view/helpers/translation_helper' @@ -53,7 +52,6 @@ module ActionView #:nodoc: include RecordIdentificationHelper include RecordTagHelper include SanitizeHelper - include ScriptaculousHelper include TagHelper include TextHelper include TranslationHelper diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index 2bd6afba56..d861810f19 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -1,6 +1,7 @@ require 'set' require 'active_support/json' require 'active_support/core_ext/object/returning' +require 'action_view/helpers/scriptaculous_helper' module ActionView module Helpers @@ -73,6 +74,8 @@ module ActionView # See JavaScriptGenerator for information on updating multiple elements # on the page in an Ajax response. module PrototypeHelper + include ScriptaculousHelper + unless const_defined? :CALLBACKS CALLBACKS = Set.new([ :create, :uninitialized, :loading, :loaded, :interactive, :complete, :failure, :success ] + -- cgit v1.2.3 From 9ad8d348b52e5603bb2432ee7fe326142ce5084b Mon Sep 17 00:00:00 2001 From: "Stephen St. Martin" Date: Sun, 24 Jan 2010 09:09:10 -0500 Subject: test :method option of link_to_remote, and ensure rel='nofollow' is added when :method => 'delete' --- actionpack/lib/action_view/helpers/ajax_helper.rb | 1 + actionpack/test/template/ajax_helper_test.rb | 5 +++++ 2 files changed, 6 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 7d164929f0..06a57efd95 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -291,6 +291,7 @@ module ActionView # :href => url_for(:action => "destroy", :id => post.id) def link_to_remote(name, options, html_options = {}) attributes = {} + attributes.merge!(:rel => "nofollow") if options[:method] && options[:method].downcase == "delete" attributes.merge!(extract_remote_attributes!(options)) attributes.merge!(html_options) diff --git a/actionpack/test/template/ajax_helper_test.rb b/actionpack/test/template/ajax_helper_test.rb index cb28448913..77d1510bab 100644 --- a/actionpack/test/template/ajax_helper_test.rb +++ b/actionpack/test/template/ajax_helper_test.rb @@ -86,6 +86,11 @@ class AjaxHelperTest < AjaxHelperBaseTest link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :position => :bottom) end + test "link_to_remote with method delete" do + assert_dom_equal %(Remote outauthor), + link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }, :method => "delete"}, { :class => "fine" }) + end + test "link_to_remote html options" do assert_dom_equal %(Remote outauthor), link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }, :html => { :class => "fine" } }) -- cgit v1.2.3 From c3baf8b767bdfb27b90b2120f9512d9697e5e932 Mon Sep 17 00:00:00 2001 From: "Erik St. Martin" Date: Sun, 24 Jan 2010 09:57:09 -0500 Subject: link_to_remote and button_to_remote now support :confirm --- actionpack/lib/action_view/helpers/ajax_helper.rb | 12 ++++++++++++ actionpack/test/template/ajax_helper_test.rb | 10 ++++++++++ 2 files changed, 22 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 06a57efd95..79e4167292 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -293,6 +293,7 @@ module ActionView attributes = {} attributes.merge!(:rel => "nofollow") if options[:method] && options[:method].downcase == "delete" attributes.merge!(extract_remote_attributes!(options)) + attributes.merge!(extract_confirm_attributes!(options)) attributes.merge!(html_options) content_tag(:a, name, attributes.merge(:href => "#")) @@ -304,6 +305,7 @@ module ActionView # and defining callbacks is the same as link_to_remote. def button_to_remote(name, options = {}, html_options = {}) attributes = html_options.merge!(:type => "button", :value => name) + attributes.merge!(extract_confirm_attributes!(options)) attributes.merge!(extract_remote_attributes!(options)) tag(:input, attributes) @@ -483,6 +485,16 @@ module ActionView private + def extract_confirm_attributes!(options) + attributes = {} + + if options && options[:confirm] + attributes["data-confirm"] = options.delete(:confirm) + end + + attributes + end + def extract_remote_attributes!(options) attributes = options.delete(:html) || {} diff --git a/actionpack/test/template/ajax_helper_test.rb b/actionpack/test/template/ajax_helper_test.rb index 77d1510bab..095454977e 100644 --- a/actionpack/test/template/ajax_helper_test.rb +++ b/actionpack/test/template/ajax_helper_test.rb @@ -101,6 +101,11 @@ class AjaxHelperTest < AjaxHelperBaseTest link_to_remote("Remote", { :url => { :action => "whatnot's" } }) end + test "link_to_remote with confirm" do + assert_dom_equal %(Remote confirm), + link_to_remote("Remote confirm", { :url => { :action => "whatnot" }, :method => "delete", :confirm => "Are you sure?"}, { :class => "fine" }) + end + test "button_to_remote" do assert_dom_equal %(), button_to_remote("Remote outpost", { :url => { :action => "whatnot" }}, { :class => "fine" }) @@ -114,6 +119,11 @@ class AjaxHelperTest < AjaxHelperBaseTest button_to_remote("Remote outpost", :failure => "alert(request.reponseText)", :url => { :action => "whatnot", :a => '10', :b => '20' }) end + test "button_to_remote with confirm" do + assert_dom_equal %(), + button_to_remote("Remote outpost", { :url => { :action => "whatnot" }, :confirm => "Are you sure?"}, { :class => "fine" }) + end + test "periodically_call_remote" do assert_dom_equal %(), periodically_call_remote(:update => "schremser_bier", :url => { :action => "mehr_bier" }) -- cgit v1.2.3 From 463fc7110755485ee2644690cb87023357f92f9a Mon Sep 17 00:00:00 2001 From: "Erik St. Martin" Date: Sun, 24 Jan 2010 11:57:38 -0500 Subject: making non remote versions of link_to, button_to, submit_tag and image_submit_tag output data attributes for things like :confirm, :method, :popup, and :disable_with --- .../lib/action_view/helpers/form_tag_helper.rb | 20 ++------ .../lib/action_view/helpers/javascript_helper.rb | 41 ++++++++++++++++ actionpack/lib/action_view/helpers/url_helper.rb | 54 +--------------------- actionpack/test/template/form_tag_helper_test.rb | 12 ++--- actionpack/test/template/url_helper_test.rb | 28 +++++------ 5 files changed, 68 insertions(+), 87 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index 048bedc7ba..ebce5c1513 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -352,33 +352,24 @@ module ActionView # # => # # submit_tag "Complete sale", :disable_with => "Please wait..." - # # => # # submit_tag nil, :class => "form_submit" # # => # # submit_tag "Edit", :disable_with => "Editing...", :class => "edit-button" - # # => def submit_tag(value = "Save changes", options = {}) options.stringify_keys! if disable_with = options.delete("disable_with") - disable_with = "this.value='#{disable_with}'" - disable_with << ";#{options.delete('onclick')}" if options['onclick'] - - options["onclick"] = "if (window.hiddenCommit) { window.hiddenCommit.setAttribute('value', this.value); }" - options["onclick"] << "else { hiddenCommit = document.createElement('input');hiddenCommit.type = 'hidden';" - options["onclick"] << "hiddenCommit.value = this.value;hiddenCommit.name = this.name;this.form.appendChild(hiddenCommit); }" - options["onclick"] << "this.setAttribute('originalValue', this.value);this.disabled = true;#{disable_with};" - options["onclick"] << "result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit());" - options["onclick"] << "if (result == false) { this.value = this.getAttribute('originalValue');this.disabled = false; }return result;" + add_disable_with_to_attributes!(options, disable_with) end if confirm = options.delete("confirm") - options["onclick"] ||= 'return true;' - options["onclick"] = "if (!#{confirm_javascript_function(confirm)}) return false; #{options['onclick']}" + add_confirm_to_attributes!(options, confirm) end tag :input, { "type" => "submit", "name" => "commit", "value" => value }.update(options.stringify_keys) @@ -411,8 +402,7 @@ module ActionView options.stringify_keys! if confirm = options.delete("confirm") - options["onclick"] ||= '' - options["onclick"] += "return #{confirm_javascript_function(confirm)};" + add_confirm_to_attributes!(options, confirm) end tag :input, { "type" => "image", "src" => path_to_image(source) }.update(options.stringify_keys) diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb index adb35ccfa2..ba6aefca26 100644 --- a/actionpack/lib/action_view/helpers/javascript_helper.rb +++ b/actionpack/lib/action_view/helpers/javascript_helper.rb @@ -188,6 +188,47 @@ module ActionView end protected + def convert_options_to_javascript!(html_options, url = '') + confirm, popup = html_options.delete("confirm"), html_options.delete("popup") + + method, href = html_options.delete("method"), html_options['href'] + + if popup && method + raise ActionView::ActionViewError, "You can't use :popup and :method in the same link" + elsif confirm && popup + add_confirm_to_attributes!(html_options, confirm) + html_options["data-popup"] = popup_attributes(popup) + elsif confirm && method + add_confirm_to_attributes!(html_options, confirm) + add_method_to_attributes!(html_options, method, url) + elsif confirm + add_confirm_to_attributes!(html_options, confirm) + elsif method + add_method_to_attributes!(html_options, method, url) + elsif popup + html_options["data-popup"] = popup_attributes(popup) + end + end + + def add_confirm_to_attributes!(html_options, confirm) + html_options["data-confirm"] = confirm if confirm + end + + def add_method_to_attributes!(html_options, method, url = nil) + html_options["data-method"] = method + if url.size > 0 + html_options["data-url"] = url + end + end + + def add_disable_with_to_attributes!(html_options, disable_with) + html_options["data-disable-with"] = disable_with if disable_with + end + + def popup_attributes(popup) + popup.is_a?(Array) ? "{title: '#{popup.first}', options: '#{popup.last}'}" : "true" + end + def options_for_javascript(options) if options.empty? '{}' diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index 511386fede..4424dbba42 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -305,12 +305,11 @@ module ActionView request_token_tag = tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token) end - if confirm = html_options.delete("confirm") - html_options["onclick"] = "return #{confirm_javascript_function(confirm)};" - end url = options.is_a?(String) ? options : self.url_for(options) name ||= url + + convert_options_to_javascript!(html_options, url) html_options.merge!("type" => "submit", "value" => name) @@ -563,55 +562,6 @@ module ActionView end private - def convert_options_to_javascript!(html_options, url = '') - confirm, popup = html_options.delete("confirm"), html_options.delete("popup") - - method, href = html_options.delete("method"), html_options['href'] - - html_options["onclick"] = case - when popup && method - raise ActionView::ActionViewError, "You can't use :popup and :method in the same link" - when confirm && popup - "if (#{confirm_javascript_function(confirm)}) { #{popup_javascript_function(popup)} };return false;" - when confirm && method - "if (#{confirm_javascript_function(confirm)}) { #{method_javascript_function(method, url, href)} };return false;" - when confirm - "return #{confirm_javascript_function(confirm)};" - when method - "#{method_javascript_function(method, url, href)}return false;" - when popup - "#{popup_javascript_function(popup)}return false;" - else - html_options["onclick"] - end - end - - def confirm_javascript_function(confirm) - "confirm('#{escape_javascript(confirm)}')" - end - - def popup_javascript_function(popup) - popup.is_a?(Array) ? "window.open(this.href,'#{popup.first}','#{popup.last}');" : "window.open(this.href);" - end - - def method_javascript_function(method, url = '', href = nil) - action = (href && url.size > 0) ? "'#{url}'" : 'this.href' - submit_function = - "var f = document.createElement('form'); f.style.display = 'none'; " + - "this.parentNode.appendChild(f); f.method = 'POST'; f.action = #{action};" - - unless method == :post - submit_function << "var m = document.createElement('input'); m.setAttribute('type', 'hidden'); " - submit_function << "m.setAttribute('name', '_method'); m.setAttribute('value', '#{method}'); f.appendChild(m);" - end - - if protect_against_forgery? - submit_function << "var s = document.createElement('input'); s.setAttribute('type', 'hidden'); " - submit_function << "s.setAttribute('name', '#{request_forgery_protection_token}'); s.setAttribute('value', '#{escape_javascript form_authenticity_token}'); f.appendChild(s);" - end - submit_function << "f.submit();" - end - # Processes the +html_options+ hash, converting the boolean # attributes from true/false form into the form required by # HTML/XHTML. (An attribute is considered to be boolean if diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb index 47462b1237..c8d929cee8 100644 --- a/actionpack/test/template/form_tag_helper_test.rb +++ b/actionpack/test/template/form_tag_helper_test.rb @@ -285,35 +285,35 @@ class FormTagHelperTest < ActionView::TestCase def test_submit_tag assert_dom_equal( - %(), - submit_tag("Save", :disable_with => "Saving...", :onclick => "alert('hello!')") + %(), + submit_tag("Save", :disable_with => "Saving...", :onclick => "alert('hello!');") ) end def test_submit_tag_with_no_onclick_options assert_dom_equal( - %(), + %(), submit_tag("Save", :disable_with => "Saving...") ) end def test_submit_tag_with_confirmation assert_dom_equal( - %(), + %(), submit_tag("Save", :confirm => "Are you sure?") ) end def test_submit_tag_with_confirmation_and_with_disable_with assert_dom_equal( - %(), + %(), submit_tag("Save", :disable_with => "Saving...", :confirm => "Are you sure?") ) end def test_image_submit_tag_with_confirmation assert_dom_equal( - %(), + %(), image_submit_tag("save.gif", :confirm => "Are you sure?") ) end diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb index d4b58efe1e..4298be7a1e 100644 --- a/actionpack/test/template/url_helper_test.rb +++ b/actionpack/test/template/url_helper_test.rb @@ -76,7 +76,7 @@ class UrlHelperTest < ActionView::TestCase def test_button_to_with_javascript_confirm assert_dom_equal( - "
", + "
", button_to("Hello", "http://www.example.com", :confirm => "Are you sure?") ) end @@ -170,76 +170,76 @@ class UrlHelperTest < ActionView::TestCase def test_link_tag_with_javascript_confirm assert_dom_equal( - "Hello", + "Hello", link_to("Hello", "http://www.example.com", :confirm => "Are you sure?") ) assert_dom_equal( - "Hello", + "Hello", link_to("Hello", "http://www.example.com", :confirm => "You can't possibly be sure, can you?") ) assert_dom_equal( - "Hello", + "Hello", link_to("Hello", "http://www.example.com", :confirm => "You can't possibly be sure,\n can you?") ) end def test_link_tag_with_popup assert_dom_equal( - "Hello", + "Hello", link_to("Hello", "http://www.example.com", :popup => true) ) assert_dom_equal( - "Hello", + "Hello", link_to("Hello", "http://www.example.com", :popup => 'true') ) assert_dom_equal( - "Hello", + "Hello", link_to("Hello", "http://www.example.com", :popup => ['window_name', 'width=300,height=300']) ) end def test_link_tag_with_popup_and_javascript_confirm assert_dom_equal( - "Hello", + "Hello", link_to("Hello", "http://www.example.com", { :popup => true, :confirm => "Fo' sho'?" }) ) assert_dom_equal( - "Hello", + "Hello", link_to("Hello", "http://www.example.com", { :popup => ['window_name', 'width=300,height=300'], :confirm => "Are you serious?" }) ) end def test_link_tag_using_post_javascript assert_dom_equal( - "Hello", + "Hello", link_to("Hello", "http://www.example.com", :method => :post) ) end def test_link_tag_using_delete_javascript assert_dom_equal( - "Destroy", + "Destroy", link_to("Destroy", "http://www.example.com", :method => :delete) ) end def test_link_tag_using_delete_javascript_and_href assert_dom_equal( - "Destroy", + "Destroy", link_to("Destroy", "http://www.example.com", :method => :delete, :href => '#') ) end def test_link_tag_using_post_javascript_and_confirm assert_dom_equal( - "Hello", + "Hello", link_to("Hello", "http://www.example.com", :method => :post, :confirm => "Are you serious?") ) end def test_link_tag_using_delete_javascript_and_href_and_confirm assert_dom_equal( - "Destroy", + "Destroy", link_to("Destroy", "http://www.example.com", :method => :delete, :href => '#', :confirm => "Are you serious?"), "When specifying url, form should be generated with it, but not this.href" ) -- cgit v1.2.3 From fbb56f7ee80078c6ec1ea3166b2e37d8feff496a Mon Sep 17 00:00:00 2001 From: "Erik St. Martin" Date: Sun, 24 Jan 2010 12:37:26 -0500 Subject: refactoring AjaxHelper a bit so that it calls shared method from JavascriptHelper to add attributes for :confirm --- actionpack/lib/action_view/helpers/ajax_helper.rb | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 79e4167292..7e7d4a0557 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -293,7 +293,11 @@ module ActionView attributes = {} attributes.merge!(:rel => "nofollow") if options[:method] && options[:method].downcase == "delete" attributes.merge!(extract_remote_attributes!(options)) - attributes.merge!(extract_confirm_attributes!(options)) + + if confirm = options.delete(:confirm) + add_confirm_to_attributes!(attributes, confirm) + end + attributes.merge!(html_options) content_tag(:a, name, attributes.merge(:href => "#")) @@ -305,7 +309,11 @@ module ActionView # and defining callbacks is the same as link_to_remote. def button_to_remote(name, options = {}, html_options = {}) attributes = html_options.merge!(:type => "button", :value => name) - attributes.merge!(extract_confirm_attributes!(options)) + + if confirm = options.delete(:confirm) + add_confirm_to_attributes!(attributes, confirm) + end + attributes.merge!(extract_remote_attributes!(options)) tag(:input, attributes) @@ -485,16 +493,6 @@ module ActionView private - def extract_confirm_attributes!(options) - attributes = {} - - if options && options[:confirm] - attributes["data-confirm"] = options.delete(:confirm) - end - - attributes - end - def extract_remote_attributes!(options) attributes = options.delete(:html) || {} -- cgit v1.2.3 From d7698971713bf42efb12bac10fff0303d5a8ac4e Mon Sep 17 00:00:00 2001 From: "Erik St. Martin" Date: Sun, 24 Jan 2010 12:57:19 -0500 Subject: modified helper that adds attributes for :method to include rel='nofollow' if :method => :delete, same as its remote_ equivalent --- actionpack/lib/action_view/helpers/javascript_helper.rb | 1 + actionpack/test/template/url_helper_test.rb | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb index ba6aefca26..ee6481b86d 100644 --- a/actionpack/lib/action_view/helpers/javascript_helper.rb +++ b/actionpack/lib/action_view/helpers/javascript_helper.rb @@ -215,6 +215,7 @@ module ActionView end def add_method_to_attributes!(html_options, method, url = nil) + html_options["rel"] = "nofollow" if method.to_s.downcase == "delete" html_options["data-method"] = method if url.size > 0 html_options["data-url"] = url diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb index 4298be7a1e..c0e6826ec5 100644 --- a/actionpack/test/template/url_helper_test.rb +++ b/actionpack/test/template/url_helper_test.rb @@ -218,14 +218,14 @@ class UrlHelperTest < ActionView::TestCase def test_link_tag_using_delete_javascript assert_dom_equal( - "Destroy", + "Destroy", link_to("Destroy", "http://www.example.com", :method => :delete) ) end def test_link_tag_using_delete_javascript_and_href assert_dom_equal( - "Destroy", + "Destroy", link_to("Destroy", "http://www.example.com", :method => :delete, :href => '#') ) end @@ -239,7 +239,7 @@ class UrlHelperTest < ActionView::TestCase def test_link_tag_using_delete_javascript_and_href_and_confirm assert_dom_equal( - "Destroy", + "Destroy", link_to("Destroy", "http://www.example.com", :method => :delete, :href => '#', :confirm => "Are you serious?"), "When specifying url, form should be generated with it, but not this.href" ) -- cgit v1.2.3 From 9821648644e904efcad55961cc7082f574c11414 Mon Sep 17 00:00:00 2001 From: "Erik St. Martin" Date: Sun, 24 Jan 2010 09:57:09 -0500 Subject: link_to_remote and button_to_remote now support :confirm --- actionpack/lib/action_view/helpers/ajax_helper.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 7e7d4a0557..5a9c4e7386 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -493,6 +493,16 @@ module ActionView private + def extract_confirm_attributes!(options) + attributes = {} + + if options && options[:confirm] + attributes["data-confirm"] = options.delete(:confirm) + end + + attributes + end + def extract_remote_attributes!(options) attributes = options.delete(:html) || {} -- cgit v1.2.3 From 426a6b2e00665b04bab4fa5cee664fefd9957960 Mon Sep 17 00:00:00 2001 From: "Erik St. Martin" Date: Sun, 24 Jan 2010 11:57:38 -0500 Subject: making non remote versions of link_to, button_to, submit_tag and image_submit_tag output data attributes for things like :confirm, :method, :popup, and :disable_with --- actionpack/lib/action_view/helpers/javascript_helper.rb | 3 +++ 1 file changed, 3 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb index ee6481b86d..58a92387b5 100644 --- a/actionpack/lib/action_view/helpers/javascript_helper.rb +++ b/actionpack/lib/action_view/helpers/javascript_helper.rb @@ -215,7 +215,10 @@ module ActionView end def add_method_to_attributes!(html_options, method, url = nil) +<<<<<<< HEAD html_options["rel"] = "nofollow" if method.to_s.downcase == "delete" +======= +>>>>>>> making non remote versions of link_to, button_to, submit_tag and image_submit_tag output data attributes for things like :confirm, :method, :popup, and :disable_with html_options["data-method"] = method if url.size > 0 html_options["data-url"] = url -- cgit v1.2.3 From 133f6011d08ee043dcb5ae95bb441a81f6206bd9 Mon Sep 17 00:00:00 2001 From: "Stephen St. Martin" Date: Sun, 24 Jan 2010 12:59:29 -0500 Subject: add missing :before and :after callbacks for link_to_remote --- actionpack/lib/action_view/helpers/ajax_helper.rb | 2 +- actionpack/test/template/ajax_helper_test.rb | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 5a9c4e7386..f6c9952031 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -600,7 +600,7 @@ module ActionView private def set_callbacks(options, html) - [:uninitialized, :complete, :failure, :success, :interactive, :loaded, :loading].each do |type| + [:before, :after, :uninitialized, :complete, :failure, :success, :interactive, :loaded, :loading].each do |type| html["data-on#{type}"] = options.delete(type.to_sym) end diff --git a/actionpack/test/template/ajax_helper_test.rb b/actionpack/test/template/ajax_helper_test.rb index 095454977e..4d76007d52 100644 --- a/actionpack/test/template/ajax_helper_test.rb +++ b/actionpack/test/template/ajax_helper_test.rb @@ -86,6 +86,11 @@ class AjaxHelperTest < AjaxHelperBaseTest link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :position => :bottom) end + test "link_to_remote with before/after callbacks" do + assert_dom_equal %(Remote outauthor), + link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :before => "before();", :after => "after();") + end + test "link_to_remote with method delete" do assert_dom_equal %(Remote outauthor), link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }, :method => "delete"}, { :class => "fine" }) -- cgit v1.2.3 From 9e3e1b3f24e2ba47f675ecbfc44c269323637985 Mon Sep 17 00:00:00 2001 From: "Erik St. Martin" Date: Sun, 24 Jan 2010 13:13:40 -0500 Subject: fixing last merge breakage --- actionpack/lib/action_view/helpers/ajax_helper.rb | 10 ---------- actionpack/lib/action_view/helpers/javascript_helper.rb | 3 --- 2 files changed, 13 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index f6c9952031..e8dd960e6b 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -493,16 +493,6 @@ module ActionView private - def extract_confirm_attributes!(options) - attributes = {} - - if options && options[:confirm] - attributes["data-confirm"] = options.delete(:confirm) - end - - attributes - end - def extract_remote_attributes!(options) attributes = options.delete(:html) || {} diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb index 58a92387b5..ee6481b86d 100644 --- a/actionpack/lib/action_view/helpers/javascript_helper.rb +++ b/actionpack/lib/action_view/helpers/javascript_helper.rb @@ -215,10 +215,7 @@ module ActionView end def add_method_to_attributes!(html_options, method, url = nil) -<<<<<<< HEAD html_options["rel"] = "nofollow" if method.to_s.downcase == "delete" -======= ->>>>>>> making non remote versions of link_to, button_to, submit_tag and image_submit_tag output data attributes for things like :confirm, :method, :popup, and :disable_with html_options["data-method"] = method if url.size > 0 html_options["data-url"] = url -- cgit v1.2.3 From a5e9d033e81152e1b2280042ba6289c8a231e8bf Mon Sep 17 00:00:00 2001 From: "Stephen St. Martin" Date: Sun, 24 Jan 2010 13:21:35 -0500 Subject: add missing test for :with option to link_to_remote --- actionpack/test/template/ajax_helper_test.rb | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'actionpack') diff --git a/actionpack/test/template/ajax_helper_test.rb b/actionpack/test/template/ajax_helper_test.rb index 4d76007d52..6fa8a95d42 100644 --- a/actionpack/test/template/ajax_helper_test.rb +++ b/actionpack/test/template/ajax_helper_test.rb @@ -90,6 +90,12 @@ class AjaxHelperTest < AjaxHelperBaseTest assert_dom_equal %(Remote outauthor), link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :before => "before();", :after => "after();") end + + test "link_to_remote using :with expression" do + expected = %(Remote outauthor) + assert_dom_equal expected, link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :with => "id") + assert_dom_equal expected, link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :with => "'id=' + encodeURIComponent(value)") + end test "link_to_remote with method delete" do assert_dom_equal %(Remote outauthor), -- cgit v1.2.3 From d9af0dfac4c4935097671ff0d8b21876ff6c019a Mon Sep 17 00:00:00 2001 From: "Stephen St. Martin" Date: Sun, 24 Jan 2010 13:33:07 -0500 Subject: refactor params and with into copat module --- actionpack/lib/action_view/helpers/ajax_helper.rb | 39 +++++++++++++++-------- 1 file changed, 26 insertions(+), 13 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index e8dd960e6b..fac7b8c44b 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -464,8 +464,11 @@ module ActionView # # def observe_field(name, options = {}) + html_options = options.delete(:callbacks) + options[:observed] = name attributes = extract_observer_attributes!(options) + attributes.merge!(html_options) if html_options script_decorator(attributes) end @@ -512,19 +515,6 @@ module ActionView url_options = url_options.merge(:escape => false) if url_options.is_a?(Hash) attributes["data-url"] = escape_javascript(url_for(url_options)) - #TODO: Remove all references to prototype - BR - if options.delete(:form) - attributes["data-parameters"] = 'Form.serialize(this)' - elsif submit = options.delete(:submit) - attributes["data-parameters"] = "Form.serialize('#{submit}')" - elsif with = options.delete(:with) - if with !~ /[\{=(.]/ - attributes["data-with"] = "'#{with}=' + encodeURIComponent(value)" - else - attributes["data-with"] = with - end - end - purge_unused_attributes!(attributes) end @@ -573,6 +563,7 @@ module ActionView def link_to_remote(name, options, html_options = {}) set_callbacks(options, html_options) + set_conditions(options, html_options) super end @@ -588,6 +579,13 @@ module ActionView super end + def observe_field(name, options = {}) + html = {} + set_conditions(options, html) + options.merge!(:callbacks => html) + super + end + private def set_callbacks(options, html) [:before, :after, :uninitialized, :complete, :failure, :success, :interactive, :loaded, :loading].each do |type| @@ -600,6 +598,21 @@ module ActionView end end end + + def set_conditions(options, html) + #TODO: Remove all references to prototype - BR + if options.delete(:form) + html["data-parameters"] = 'Form.serialize(this)' + elsif submit = options.delete(:submit) + html["data-parameters"] = "Form.serialize('#{submit}')" + elsif with = options.delete(:with) + if with !~ /[\{=(.]/ + html["data-with"] = "'#{with}=' + encodeURIComponent(value)" + else + html["data-with"] = with + end + end + end end end end -- cgit v1.2.3 From 06dd23d67133601f2639695a0fadab81213f6200 Mon Sep 17 00:00:00 2001 From: "Erik St. Martin" Date: Sun, 24 Jan 2010 14:32:55 -0500 Subject: removing Prototype inline js for attributes for :with and :condition, it now is free form js that can be placed there, also moved :submit out into AjaxHelper, updated tests to reflect changes --- actionpack/lib/action_view/helpers/ajax_helper.rb | 28 ++++++++++----------- actionpack/test/template/ajax_helper_test.rb | 30 ++++++++++++++++++----- 2 files changed, 38 insertions(+), 20 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index fac7b8c44b..b29dc50c8d 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -503,6 +503,10 @@ module ActionView attributes.merge!(extract_request_attributes!(options)) attributes["data-remote"] = true + if submit = options.delete(:submit) + attributes["data-submit"] = submit + end + attributes end @@ -563,12 +567,13 @@ module ActionView def link_to_remote(name, options, html_options = {}) set_callbacks(options, html_options) - set_conditions(options, html_options) + set_with_and_condition_attributes(options, html_options) super end def button_to_remote(name, options = {}, html_options = {}) set_callbacks(options, html_options) + set_with_and_condition_attributes(options, html_options) super end @@ -581,7 +586,7 @@ module ActionView def observe_field(name, options = {}) html = {} - set_conditions(options, html) + set_with_and_condition_attributes(options, html) options.merge!(:callbacks => html) super end @@ -599,18 +604,13 @@ module ActionView end end - def set_conditions(options, html) - #TODO: Remove all references to prototype - BR - if options.delete(:form) - html["data-parameters"] = 'Form.serialize(this)' - elsif submit = options.delete(:submit) - html["data-parameters"] = "Form.serialize('#{submit}')" - elsif with = options.delete(:with) - if with !~ /[\{=(.]/ - html["data-with"] = "'#{with}=' + encodeURIComponent(value)" - else - html["data-with"] = with - end + def set_with_and_condition_attributes(options, html) + if with = options.delete(:with) + html["data-with"] = with + end + + if condition = options.delete(:condition) + html["data-condition"] = condition end end end diff --git a/actionpack/test/template/ajax_helper_test.rb b/actionpack/test/template/ajax_helper_test.rb index 6fa8a95d42..c688b25f70 100644 --- a/actionpack/test/template/ajax_helper_test.rb +++ b/actionpack/test/template/ajax_helper_test.rb @@ -92,9 +92,18 @@ class AjaxHelperTest < AjaxHelperBaseTest end test "link_to_remote using :with expression" do - expected = %(Remote outauthor) - assert_dom_equal expected, link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :with => "id") - assert_dom_equal expected, link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :with => "'id=' + encodeURIComponent(value)") + expected = %(Remote outauthor) + assert_dom_equal expected, link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :with => "id=123") + end + + test "link_to_remote using :condition expression" do + expected = %(Remote outauthor) + assert_dom_equal expected, link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :condition => '$(\'foo\').val() == true') + end + + test "link_to_remote using :submit" do + expected = %(Remote outauthor) + assert_dom_equal expected, link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :submit => 'myForm') end test "link_to_remote with method delete" do @@ -135,6 +144,11 @@ class AjaxHelperTest < AjaxHelperBaseTest button_to_remote("Remote outpost", { :url => { :action => "whatnot" }, :confirm => "Are you sure?"}, { :class => "fine" }) end + test "button_to_remote with :submit" do + assert_dom_equal %(), + button_to_remote("Remote outpost", { :url => { :action => "whatnot" }, :submit => "myForm"}, { :class => "fine" }) + end + test "periodically_call_remote" do assert_dom_equal %(), periodically_call_remote(:update => "schremser_bier", :url => { :action => "mehr_bier" }) @@ -258,9 +272,13 @@ class AjaxHelperTest < AjaxHelperBaseTest end test "observe_field using with option" do - expected = %() - assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => 'id') - assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "'id=' + encodeURIComponent(value)") + expected = %() + assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => 'id=123') + end + + test "observe_field using condition option" do + expected = %() + assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :condition => '$(\'foo\').val() == true') end test "observe_field using json in with option" do -- cgit v1.2.3 From 5a75f1ab900d9637a6e7390abb9ea7faf9a85647 Mon Sep 17 00:00:00 2001 From: "Stephen St. Martin" Date: Mon, 25 Jan 2010 17:32:24 -0500 Subject: add missing call to set_with_and_condition_attributes for form_remote_tag --- actionpack/lib/action_view/helpers/ajax_helper.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index b29dc50c8d..adb686aad4 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -580,6 +580,7 @@ module ActionView def form_remote_tag(options, &block) html = {} set_callbacks(options, html) + set_with_and_condition_attributes(options, html) options.merge!(:callbacks => html) super end -- cgit v1.2.3 From 44542bd7daf03057fe502f21f3eb2a5c09ffea57 Mon Sep 17 00:00:00 2001 From: "Erik St. Martin" Date: Mon, 25 Jan 2010 19:48:39 -0500 Subject: account for the fact a few options may be passed as symbols and need to be converted to string --- actionpack/lib/action_view/helpers/ajax_helper.rb | 16 ++++++++++++---- actionpack/test/template/ajax_helper_test.rb | 5 +++++ 2 files changed, 17 insertions(+), 4 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index adb686aad4..52b7db4de9 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -291,7 +291,7 @@ module ActionView # :href => url_for(:action => "destroy", :id => post.id) def link_to_remote(name, options, html_options = {}) attributes = {} - attributes.merge!(:rel => "nofollow") if options[:method] && options[:method].downcase == "delete" + attributes.merge!(:rel => "nofollow") if options[:method] && options[:method].to_s.downcase == "delete" attributes.merge!(extract_remote_attributes!(options)) if confirm = options.delete(:confirm) @@ -512,8 +512,13 @@ module ActionView def extract_request_attributes!(options) attributes = {} - attributes["data-method"] = options.delete(:method) - attributes["data-remote-type"] = options.delete(:type) + if method = options.delete(:method) + attributes["data-method"] = method.to_s + end + + if type = options.delete(:type) + attributes["data-remote-type"] = type.to_s + end url_options = options.delete(:url) url_options = url_options.merge(:escape => false) if url_options.is_a?(Hash) @@ -531,7 +536,10 @@ module ActionView else attributes["data-update-success"] = update end - attributes["data-update-position"] = options.delete(:position) + + if position = options.delete(:position) + attributes["data-update-position"] = position.to_s + end purge_unused_attributes!(attributes) end diff --git a/actionpack/test/template/ajax_helper_test.rb b/actionpack/test/template/ajax_helper_test.rb index c688b25f70..2e46a38656 100644 --- a/actionpack/test/template/ajax_helper_test.rb +++ b/actionpack/test/template/ajax_helper_test.rb @@ -111,6 +111,11 @@ class AjaxHelperTest < AjaxHelperBaseTest link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }, :method => "delete"}, { :class => "fine" }) end + test "link_to_remote with method delete as symbol" do + assert_dom_equal %(Remote outauthor), + link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }, :method => :delete}, { :class => "fine" }) + end + test "link_to_remote html options" do assert_dom_equal %(Remote outauthor), link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }, :html => { :class => "fine" } }) -- cgit v1.2.3 From eb2d32f30916c57f3011480e12772dd801f67070 Mon Sep 17 00:00:00 2001 From: "Erik St. Martin" Date: Mon, 25 Jan 2010 21:25:51 -0500 Subject: remote_form_for now supports :confirm --- actionpack/lib/action_view/helpers/ajax_helper.rb | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 52b7db4de9..1a396215fc 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -56,6 +56,11 @@ module ActionView # See FormHelper#form_for for additional semantics. def remote_form_for(record_or_name_or_array, *args, &proc) options = args.extract_options! + + if confirm = options.delete(:confirm) + add_confirm_to_attributes!(options, confirm) + end + object_name = extract_object_name_for_form!(args, options, record_or_name_or_array) concat(form_remote_tag(options)) -- cgit v1.2.3 From 8b7cd5ae7ef2d8072779d756281f440f19f9500d Mon Sep 17 00:00:00 2001 From: "Stephen St. Martin" Date: Mon, 25 Jan 2010 22:45:44 -0500 Subject: fix duplidate data-submit attribute, submit_to_remote should test url --- actionpack/lib/action_view/helpers/ajax_helper.rb | 2 +- actionpack/test/template/ajax_helper_test.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 1a396215fc..ae37802f02 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -361,7 +361,7 @@ module ActionView attributes = extract_remote_attributes!(options) attributes.merge!(html_options) - attributes["data-submit"] = true + attributes["data-remote-submit"] = true attributes.delete("data-remote") tag(:input, attributes) diff --git a/actionpack/test/template/ajax_helper_test.rb b/actionpack/test/template/ajax_helper_test.rb index 2e46a38656..4a84ce47e0 100644 --- a/actionpack/test/template/ajax_helper_test.rb +++ b/actionpack/test/template/ajax_helper_test.rb @@ -267,8 +267,8 @@ class AjaxHelperTest < AjaxHelperBaseTest end test "submit_to_remote" do - assert_dom_equal %(), - submit_to_remote("More beer!", 1_000_000, :update => "empty_bottle") + assert_dom_equal %(), + submit_to_remote("More beer!", 1_000_000, :url => { :action => 'empty_bottle' }, :update => "empty_bottle") end test "observe_field" do -- cgit v1.2.3 From 56ae6550b8a7e24bc731f25b66fc3a5d246e221c Mon Sep 17 00:00:00 2001 From: "Erik St. Martin" Date: Mon, 25 Jan 2010 23:46:54 -0500 Subject: adding support for :disable_with to button_to_remote --- actionpack/lib/action_view/helpers/ajax_helper.rb | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index ae37802f02..e79801c46d 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -319,6 +319,10 @@ module ActionView add_confirm_to_attributes!(attributes, confirm) end + if disable_with = options.delete(:disable_with) + add_disable_with_to_attributes!(attributes, disable_with) + end + attributes.merge!(extract_remote_attributes!(options)) tag(:input, attributes) -- cgit v1.2.3 From 9fe845670daa15fac72df826138206471c8398a0 Mon Sep 17 00:00:00 2001 From: "Erik St. Martin" Date: Tue, 26 Jan 2010 03:00:38 -0500 Subject: adding :href override to link_to_remote --- actionpack/lib/action_view/helpers/ajax_helper.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index e79801c46d..6eba108ff0 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -304,8 +304,10 @@ module ActionView end attributes.merge!(html_options) + href = options[:href].nil? ? "#" : options[:href] + attributes.merge!(:href => href) - content_tag(:a, name, attributes.merge(:href => "#")) + content_tag(:a, name, attributes) end # Creates a button with an onclick event which calls a remote action -- cgit v1.2.3 From ad26b3934ecb9f5034453b4cd7d924048798d429 Mon Sep 17 00:00:00 2001 From: "Erik St. Martin" Date: Tue, 26 Jan 2010 10:54:59 -0500 Subject: test to go with last commit, explicit :href for link_to_remote --- actionpack/test/template/ajax_helper_test.rb | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'actionpack') diff --git a/actionpack/test/template/ajax_helper_test.rb b/actionpack/test/template/ajax_helper_test.rb index 4a84ce47e0..d31e4daf08 100644 --- a/actionpack/test/template/ajax_helper_test.rb +++ b/actionpack/test/template/ajax_helper_test.rb @@ -101,6 +101,11 @@ class AjaxHelperTest < AjaxHelperBaseTest assert_dom_equal expected, link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :condition => '$(\'foo\').val() == true') end + test "link_to_remote using explicit :href" do + expected = %(Remote outauthor) + assert_dom_equal expected, link_to_remote("Remote outauthor", :href => 'http://www.example.com/testhref', :url => { :action => "whatnot" }, :condition => '$(\'foo\').val() == true') + end + test "link_to_remote using :submit" do expected = %(Remote outauthor) assert_dom_equal expected, link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :submit => 'myForm') -- cgit v1.2.3 From 6a8da2053eb1e833347e5ed5dc578fc47cdf9309 Mon Sep 17 00:00:00 2001 From: "Erik St. Martin" Date: Tue, 26 Jan 2010 10:59:18 -0500 Subject: need to tell erb that our " + "".html_safe! end private -- cgit v1.2.3 From 0215466832faddd2fc5ebef9500f06fa1b95228e Mon Sep 17 00:00:00 2001 From: "Erik St. Martin" Date: Tue, 26 Jan 2010 11:06:58 -0500 Subject: periodically_call_remote does not need data-observe=true --- actionpack/lib/action_view/helpers/ajax_helper.rb | 3 +++ actionpack/test/template/ajax_helper_test.rb | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index b570eb44a7..8d09ca1187 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -402,6 +402,9 @@ module ActionView attributes = extract_observer_attributes!(options) attributes["data-periodical"] = true + # periodically_call_remote does not need data-observe=true + attributes.delete('data-observe') + script_decorator(attributes) end diff --git a/actionpack/test/template/ajax_helper_test.rb b/actionpack/test/template/ajax_helper_test.rb index d31e4daf08..47d458e4ef 100644 --- a/actionpack/test/template/ajax_helper_test.rb +++ b/actionpack/test/template/ajax_helper_test.rb @@ -160,13 +160,13 @@ class AjaxHelperTest < AjaxHelperBaseTest end test "periodically_call_remote" do - assert_dom_equal %(), + assert_dom_equal %(), periodically_call_remote(:update => "schremser_bier", :url => { :action => "mehr_bier" }) end test "periodically_call_remote_with_frequency" do assert_dom_equal( - "", + "", periodically_call_remote(:frequency => 2) ) end -- cgit v1.2.3 From a6cd35ba68c6d210f097a37ff737bbc1e5c61972 Mon Sep 17 00:00:00 2001 From: "Erik St. Martin" Date: Tue, 26 Jan 2010 11:59:19 -0500 Subject: moving html_safe call into helpers directly as they only work from that level --- actionpack/lib/action_view/helpers/ajax_helper.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 8d09ca1187..5b706ba942 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -405,7 +405,7 @@ module ActionView # periodically_call_remote does not need data-observe=true attributes.delete('data-observe') - script_decorator(attributes) + script_decorator(attributes).html_safe! end # Observes the field with the DOM ID specified by +field_id+ and calls a @@ -484,7 +484,7 @@ module ActionView attributes = extract_observer_attributes!(options) attributes.merge!(html_options) if html_options - script_decorator(attributes) + script_decorator(attributes).html_safe! end # Observes the form with the DOM ID specified by +form_id+ and calls a @@ -499,13 +499,13 @@ module ActionView options[:observed] = name attributes = extract_observer_attributes!(options) - script_decorator(attributes) + script_decorator(attributes).html_safe! end def script_decorator(options) attributes = %w(type="application/json") attributes += options.map{|k, v| k + '="' + v.to_s + '"'} - "".html_safe! + "" end private -- cgit v1.2.3 From f661a3bc599ac336aeaf643a8d1d388fe905a07d Mon Sep 17 00:00:00 2001 From: "Erik St. Martin" Date: Tue, 26 Jan 2010 12:40:29 -0500 Subject: removing container inline js function of observed elements :function callback --- actionpack/lib/action_view/helpers/ajax_helper.rb | 6 +----- actionpack/test/template/ajax_helper_test.rb | 11 +++++++++-- 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 5b706ba942..65315fd709 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -566,7 +566,7 @@ module ActionView attributes = extract_remote_attributes!(options) attributes["data-observe"] = true attributes["data-observed"] = options.delete(:observed) - attributes["data-onobserve"] = create_js_function(callback, "element", "value") if callback + attributes["data-onobserve"] = callback if callback attributes["data-frequency"] = frequency.to_i if frequency && frequency != 0 attributes.delete("data-remote") @@ -577,10 +577,6 @@ module ActionView attributes.delete_if {|key, value| value.nil? } attributes end - - def create_js_function(statements, *arguments) - "function(#{arguments.join(", ")}) {#{statements}}" - end end # TODO: All evaled goes here per wycat diff --git a/actionpack/test/template/ajax_helper_test.rb b/actionpack/test/template/ajax_helper_test.rb index 47d458e4ef..6d332d4fca 100644 --- a/actionpack/test/template/ajax_helper_test.rb +++ b/actionpack/test/template/ajax_helper_test.rb @@ -171,6 +171,13 @@ class AjaxHelperTest < AjaxHelperBaseTest ) end + test "periodically_call_remote_with_function" do + assert_dom_equal( + "", + periodically_call_remote(:frequency => 2, :function => "alert('test')") + ) + end + test "form_remote_tag" do assert_dom_equal %(
), form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) @@ -297,7 +304,7 @@ class AjaxHelperTest < AjaxHelperBaseTest end test "observe_field using function for callback" do - assert_dom_equal %(), + assert_dom_equal %(), observe_field("glass", :frequency => 5.minutes, :function => "alert('Element changed')") end @@ -307,7 +314,7 @@ class AjaxHelperTest < AjaxHelperBaseTest end test "observe_form using function for callback" do - assert_dom_equal %(), + assert_dom_equal %(), observe_form("cart", :frequency => 2, :function => "alert('Form changed')") end -- cgit v1.2.3 From c0f63883ea24925d4e03c258b874e49cf507cc33 Mon Sep 17 00:00:00 2001 From: "Erik St. Martin" Date: Tue, 26 Jan 2010 14:38:57 -0500 Subject: :href should be comming in through html_options and not options --- actionpack/lib/action_view/helpers/ajax_helper.rb | 2 +- actionpack/test/template/ajax_helper_test.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 65315fd709..2ef791b834 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -304,7 +304,7 @@ module ActionView end attributes.merge!(html_options) - href = options[:href].nil? ? "#" : options[:href] + href = html_options[:href].nil? ? "#" : html_options[:href] attributes.merge!(:href => href) content_tag(:a, name, attributes) diff --git a/actionpack/test/template/ajax_helper_test.rb b/actionpack/test/template/ajax_helper_test.rb index 6d332d4fca..4e48543c81 100644 --- a/actionpack/test/template/ajax_helper_test.rb +++ b/actionpack/test/template/ajax_helper_test.rb @@ -103,7 +103,7 @@ class AjaxHelperTest < AjaxHelperBaseTest test "link_to_remote using explicit :href" do expected = %(Remote outauthor) - assert_dom_equal expected, link_to_remote("Remote outauthor", :href => 'http://www.example.com/testhref', :url => { :action => "whatnot" }, :condition => '$(\'foo\').val() == true') + assert_dom_equal expected, link_to_remote("Remote outauthor", {:url => { :action => "whatnot" }, :condition => '$(\'foo\').val() == true'}, :href => 'http://www.example.com/testhref') end test "link_to_remote using :submit" do -- cgit v1.2.3 From 1b8ced53c4031170538c455c3d3fae3c967cc247 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 26 Jan 2010 14:08:10 -0600 Subject: Added regression tests that discovered the previous issue. --- actionpack/test/template/ajax_helper_test.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'actionpack') diff --git a/actionpack/test/template/ajax_helper_test.rb b/actionpack/test/template/ajax_helper_test.rb index 4e48543c81..ed020d74f8 100644 --- a/actionpack/test/template/ajax_helper_test.rb +++ b/actionpack/test/template/ajax_helper_test.rb @@ -86,6 +86,20 @@ class AjaxHelperTest < AjaxHelperBaseTest link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :position => :bottom) end + test "link_to_remote using both url and href" do + expected = 'Delete this Post' + assert_dom_equal expected, link_to_remote( "Delete this Post", + { :update => "posts", + :url => { :action => "destroy" } }, + :href => url_for(:action => "destroy")) + end + + test "link_to_remote with update-success and url" do + expected = 'Delete this Post' + assert_dom_equal expected, link_to_remote( "Delete this Post", :url => { :action => "destroy", :id => 5 }, + :update => { :success => "posts", :failure => "error" }) + end + test "link_to_remote with before/after callbacks" do assert_dom_equal %(Remote outauthor), link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :before => "before();", :after => "after();") -- cgit v1.2.3 From 3c7d39d65f6ad55543cd2d12aec22dd8f927f1c6 Mon Sep 17 00:00:00 2001 From: "Erik St. Martin" Date: Tue, 26 Jan 2010 16:20:25 -0500 Subject: observe_form now supports :with option as it should --- actionpack/lib/action_view/helpers/ajax_helper.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 2ef791b834..343bd78bbd 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -496,8 +496,11 @@ module ActionView # +observe_field+. The JavaScript variable +value+ available to the # :with option is set to the serialized form by default. def observe_form(name, options = {}) + html_options = options.delete(:callbacks) + options[:observed] = name attributes = extract_observer_attributes!(options) + attributes.merge!(html_options) if html_options script_decorator(attributes).html_safe! end @@ -609,6 +612,13 @@ module ActionView options.merge!(:callbacks => html) super end + + def observe_form(name, options = {}) + html = {} + set_with_and_condition_attributes(options, html) + options.merge!(:callbacks => html) + super + end private def set_callbacks(options, html) -- cgit v1.2.3 From 253f335294d8207e050d3994eaabe2c8c1fca8b6 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 26 Jan 2010 00:50:26 -0600 Subject: tests + docs --- actionpack/lib/action_view/helpers/ajax_helper.rb | 152 +++++++++++++--------- 1 file changed, 90 insertions(+), 62 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 343bd78bbd..445e59d3a5 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -5,23 +5,26 @@ module ActionView # Rails classes should not be aware of individual JS frameworks include PrototypeHelper - # Creates a form that will submit using XMLHttpRequest in the background - # instead of the regular reloading POST arrangement and a scope around a - # specific resource that is used as a base for questioning about - # values for the fields. + # Returns a form that will allow the unobtrusive JavaScript drivers to submit the + # form the dynamic nature of their choice. The default behaviour is an XMLHttpRequest + # in the background instead of the regular POST arrangement. Even though it's using + # JavaScript to serialize the form elements, the form submission will work just like + # a regular submission as viewed by the receiving side (all elements available in + # params). The options for specifying the target with :url and + # defining callbacks is the same as +link_to_remote+. # # === Resource # # Example: # # # Generates: - # # ... + # # ... # # - # <% remote_form_for(@post) do |f| %> + # <% remote_form_for(@record, {:html => { :id => 'create-author' }}) do |f| %> # ... # <% end %> # @@ -47,7 +50,10 @@ module ActionView # # This will expand to be the same as: # - # <% remote_form_for :comment, @comment, :url => post_comment_path(@post, @comment), :html => { :method => :put, :class => "edit_comment", :id => "edit_comment_45" } do |f| %> + # <% remote_form_for :comment, @comment, :url => post_comment_path(@post, @comment), + # :html => { :method => :put, + # :class => "edit_comment", + # :id => "edit_comment_45" } do |f| %> # ... # <% end %> # @@ -69,13 +75,14 @@ module ActionView end alias_method :form_remote_for, :remote_form_for - # Returns a form tag that will submit using XMLHttpRequest in the - # background instead of the regular reloading POST arrangement. Even - # though it's using JavaScript to serialize the form elements, the form - # submission will work just like a regular submission as viewed by the - # receiving side (all elements available in params). The options for - # specifying the target with :url and defining callbacks is the same as - # +link_to_remote+. + # Returns a form tag that will allow the unobtrusive JavaScript drivers to submit the + # form via the dynamic behaviour of choice. The default behaviour is an XMLHttpRequest + # in the background instead of the regular POST arrangement. Even though it's using + # JavaScript to serialize the form elements, the form submission will work just like + # a regular submission as viewed by the receiving side (all elements available in + # params). The options for specifying the target with :url and + # defining callbacks is the same as +link_to_remote+. + # # # A "fall-through" target for browsers that doesn't do JavaScript can be # specified with the :action/:method options on :html. @@ -83,13 +90,12 @@ module ActionView # Example: # # # Generates: - # #
... + # # # # - # form_remote_tag :html => { :action => - # url_for(:controller => "some", :action => "place") } - # < form data-remote action="/some/place" method="post" > + # form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) # # The Hash passed to the :html key is equivalent to the options (2nd) # argument in the FormTagHelper.form_tag method. @@ -108,7 +114,17 @@ module ActionView # <% form_remote_tag :url => '/posts' do -%> #
<%= submit_tag 'Save' %>
# <% end -%> - + # + # # Generates: + # # Hello world!
+ # # + # <% form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) do -%> + # <% concat "Hello world!" %> + # <% end -%> + # def form_remote_tag(options = {}, &block) html_options = options.delete(:callbacks) @@ -121,43 +137,40 @@ module ActionView form_tag(attributes.delete(:action) || attributes.delete("data-url"), attributes, &block) end - # Returns a link to a remote action defined by options[:url] - # (using the url_for format) that's called in the background using - # XMLHttpRequest. The result of that request can then be inserted into a - # DOM object whose id can be specified with options[:update]. - # Usually, the result would be a partial prepared by the controller with - # render :partial. + # Returns a link that will allow unobtrusive JavaScript to dynamical adjust its + # behaviour. The default behaviour is an XMLHttpRequest in the background instead + # of the regular GET arrangement. The result of that request can then be inserted + # into a DOM object whose id can be specified with options[:update]. Usually, + # the result would be a partial prepared by the controller with render :partial. # # Examples: # - # # Generates: - # # Delete this post + # # Generates: + # # Remove Author # # - # link_to_remote "Delete this post", :update => "posts", - # :url => { :action => "destroy", :id => post.id } + # link_to_remote("Remove Author", { :url => { :action => "whatnot" }, + # :method => "delete"}) # - # # Generates: - # # - # # - # # - # link_to_remote(image_tag("refresh"), :update => "emails", - # :url => { :action => "list_emails" }) # # You can override the generated HTML options by specifying a hash in # options[:html]. # - # # Generates: - # # Delete this post + # # Generates: + # # Remove Author # # - # link_to_remote "Delete this post", :update => "posts", - # :url => post_url(@post), :method => :delete, - # :html => { :class => "destructive" } + # link_to_remote("Remove Author", { :url => { :action => "whatnot" }, + # :method => "delete", + # :html => { :class => "fine" }}) + # # # You can also specify a hash for options[:update] to allow for # easy redirection of output to an other DOM element if a server-side @@ -210,7 +223,7 @@ module ActionView # :url => { :action => "undo", :n => word_counter }, # :complete => "undoRequestCompleted(request)" # - # The callbacks that may be specified are (in order): (deprecated) + # The callbacks that may be specified are (in order): # # :loading:: Called when the remote document is being # loaded with data by the browser. @@ -292,8 +305,8 @@ module ActionView # # data-method='delete'> Delete this post # # # link_to_remote "Delete this post", - # { :update => "posts", :url => { :action => "destroy", :id => post.id } }, - # :href => url_for(:action => "destroy", :id => post.id) + # { :update => "posts", :url => { :action => "destroy", :id => post.id } } + # def link_to_remote(name, options, html_options = {}) attributes = {} attributes.merge!(:rel => "nofollow") if options[:method] && options[:method].to_s.downcase == "delete" @@ -310,10 +323,23 @@ module ActionView content_tag(:a, name, attributes) end - # Creates a button with an onclick event which calls a remote action - # via XMLHttpRequest - # The options for specifying the target with :url - # and defining callbacks is the same as link_to_remote. + # Returns an input of type button, which allows the unobtrusive JavaScript driver + # to dynamically adjust its behaviour. The default driver behaviour is to call a + # remote action via XMLHttpRequest in the background. + # The options for specifying the target with :url and defining callbacks is the same + # as link_to_remote. + # + # Example: + # + # # Generates: + # # + # # + # button_to_remote("Remote outpost", { :url => { :action => "whatnot" }}, { :class => "fine" }) + # def button_to_remote(name, options = {}, html_options = {}) attributes = html_options.merge!(:type => "button", :value => name) @@ -330,9 +356,11 @@ module ActionView tag(:input, attributes) end - # Returns a button input tag with the element name of +name+ and a value (i.e., display text) of +value+ - # that will submit form using XMLHttpRequest in the background instead of a regular POST request that - # reloads the page. + # Returns an input tag of type button, with the element name of +name+ and a value (i.e., display text) + # of +value+ which will allow the unobtrusive JavaScript driver to dynamically adjust its behaviour + # The default behaviour is to call a remote action via XMLHttpRequest in the background. + # + # request that reloads the page. # # # Create a button that submits to the create action # # -- cgit v1.2.3 From 2e338aed706b3ee8fb8d51040be87689597e087b Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 27 Jan 2010 12:35:32 -0600 Subject: updated tests + docs, plus minor inconsistency fixes --- actionpack/lib/action_view/helpers/ajax_helper.rb | 142 +++++++----- actionpack/test/template/ajax_helper_test.rb | 268 +++++++++++++++------- 2 files changed, 272 insertions(+), 138 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/ajax_helper.rb b/actionpack/lib/action_view/helpers/ajax_helper.rb index 445e59d3a5..169a803848 100644 --- a/actionpack/lib/action_view/helpers/ajax_helper.rb +++ b/actionpack/lib/action_view/helpers/ajax_helper.rb @@ -6,12 +6,11 @@ module ActionView include PrototypeHelper # Returns a form that will allow the unobtrusive JavaScript drivers to submit the - # form the dynamic nature of their choice. The default behaviour is an XMLHttpRequest - # in the background instead of the regular POST arrangement. Even though it's using - # JavaScript to serialize the form elements, the form submission will work just like - # a regular submission as viewed by the receiving side (all elements available in - # params). The options for specifying the target with :url and - # defining callbacks is the same as +link_to_remote+. + # form dynamically. The default driver behaviour is an XMLHttpRequest in the background + # instead of the regular POST arrangement. Even though it's using JavaScript to serialize + # the form elements, the form submission will work just like a regular submission as + # viewed by the receiving side (all elements available in params). The options + # for specifying the target with :url anddefining callbacks is the same as +link_to_remote+. # # === Resource # @@ -30,7 +29,10 @@ module ActionView # # This will expand to be the same as: # - # <% remote_form_for :post, @post, :url => post_path(@post), :html => { :method => :put, :class => "edit_post", :id => "edit_post_45" } do |f| %> + # <% remote_form_for :post, @post, :url => post_path(@post), + # :html => { :method => :put, + # :class => "edit_post", + # :id => "edit_post_45" } do |f| %> # ... # <% end %> # @@ -38,22 +40,22 @@ module ActionView # # Example: # # Generates: - # #
... + # # id='new_article'>
# # - # <% remote_form_for([@post, @comment]) do |f| %> + # <% remote_form_for([@author, @article]) do |f| %> # ... # <% end %> # # This will expand to be the same as: # - # <% remote_form_for :comment, @comment, :url => post_comment_path(@post, @comment), + # <% remote_form_for :article, @article, :url => author_article_path(@author, @article), # :html => { :method => :put, - # :class => "edit_comment", - # :id => "edit_comment_45" } do |f| %> + # :class => "new_article", + # :id => "new_comment" } do |f| %> # ... # <% end %> # @@ -76,14 +78,13 @@ module ActionView alias_method :form_remote_for, :remote_form_for # Returns a form tag that will allow the unobtrusive JavaScript drivers to submit the - # form via the dynamic behaviour of choice. The default behaviour is an XMLHttpRequest + # form dynamically. The default JavaScript driver behaviour is an XMLHttpRequest # in the background instead of the regular POST arrangement. Even though it's using # JavaScript to serialize the form elements, the form submission will work just like # a regular submission as viewed by the receiving side (all elements available in # params). The options for specifying the target with :url and # defining callbacks is the same as +link_to_remote+. # - # # A "fall-through" target for browsers that doesn't do JavaScript can be # specified with the :action/:method options on :html. # @@ -93,9 +94,9 @@ module ActionView # #
+ # # data-update-success="glass_of_beer">
# # - # form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) + # form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) {} # # The Hash passed to the :html key is equivalent to the options (2nd) # argument in the FormTagHelper.form_tag method. @@ -105,14 +106,14 @@ module ActionView # # form_remote_tag also takes a block, like form_tag: # # Generates: - # #
- # #
+ # # # #
# # # <% form_remote_tag :url => '/posts' do -%> - #
<%= submit_tag 'Save' %>
+ # <%= submit_tag 'Save' %> # <% end -%> # # # Generates: @@ -122,7 +123,7 @@ module ActionView # # data-update-success="glass_of_beer">Hello world! # # # <% form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) do -%> - # <% concat "Hello world!" %> + # "Hello world!" # <% end -%> # def form_remote_tag(options = {}, &block) @@ -178,27 +179,38 @@ module ActionView # # Example: # # Generates: - # # Delete this post + # # + # # Delete this Post' # # # link_to_remote "Delete this post", - # :url => { :action => "destroy", :id => post.id }, + # :url => { :action => "destroy"}, # :update => { :success => "posts", :failure => "error" } # # Optionally, you can use the options[:position] parameter to # influence how the target DOM element is updated. It must be one of # :before, :top, :bottom, or :after. # + # Example: + # # Generates: + # # Remove Author + # # + # link_to_remote("Remove Author", :url => { :action => "whatnot" }, :position => :bottom) + # + # # The method used is by default POST. You can also specify GET or you # can simulate PUT or DELETE over POST. All specified with options[:method] # # Example: # # Generates: - # # Destroy @@ -215,12 +227,14 @@ module ActionView # # Example: # # Generates: - # # hello # # - # word = 'hello' - # link_to_remote word, - # :url => { :action => "undo", :n => word_counter }, + # # undo + # # + # link_to_remote "undo", + # :url => { :controller => "words", :action => "undo", :n => word_counter }, # :complete => "undoRequestCompleted(request)" # # The callbacks that may be specified are (in order): @@ -290,7 +304,7 @@ module ActionView # # :with => "'name=' + $('name').value" # - # You can generate a link that uses AJAX in the general case, while + # You can generate a link that uses the UJS drivers in the general case, while # degrading gracefully to plain link behavior in the absence of # JavaScript by setting html_options[:href] to an alternate URL. # Note the extra curly braces around the options hash separate @@ -309,6 +323,7 @@ module ActionView # def link_to_remote(name, options, html_options = {}) attributes = {} + attributes.merge!(:rel => "nofollow") if options[:method] && options[:method].to_s.downcase == "delete" attributes.merge!(extract_remote_attributes!(options)) @@ -369,7 +384,7 @@ module ActionView # # type='button' # # value='Create' # # data-remote='true' - # # data-url='/testing/create' /> + # # data-url='/create' /> # # # <%= submit_to_remote 'create_btn', 'Create', :url => { :action => 'create' } %> # @@ -380,7 +395,7 @@ module ActionView # # @@ -401,34 +416,49 @@ module ActionView tag(:input, attributes) end - # Periodically calls the specified url (options[:url]) every - # options[:frequency] seconds (default is 10). Usually used to + # Periodically provides the UJS driver with the information to call the specified + # url (options[:url]) every options[:frequency] seconds (default is 10). Usually used to # update a specified div (options[:update]) with the results # of the remote call. The options for specifying the target with :url # and defining callbacks is the same as link_to_remote. # Examples: # # Call get_averages and put its results in 'avg' every 10 seconds # # Generates: - # # new PeriodicalExecuter(function() {new Ajax.Updater('avg', '/grades/get_averages', - # # {asynchronous:true, evalScripts:true})}, 10) + # # + # # # periodically_call_remote(:url => { :action => 'get_averages' }, :update => 'avg') # # # Call invoice every 10 seconds with the id of the customer # # If it succeeds, update the invoice DIV; if it fails, update the error DIV # # Generates: - # # new PeriodicalExecuter(function() {new Ajax.Updater({success:'invoice',failure:'error'}, - # # '/testing/invoice/16', {asynchronous:true, evalScripts:true})}, 10) - # periodically_call_remote(:url => { :action => 'invoice', :id => customer.id }, + # # " + # # + # periodically_call_remote(:url => { :action => 'invoice', :id => 1 }, # :update => { :success => "invoice", :failure => "error" } # # # Call update every 20 seconds and update the new_block DIV # # Generates: - # # new PeriodicalExecuter(function() {new Ajax.Updater('news_block', 'update', {asynchronous:true, evalScripts:true})}, 20) + # # + # # # periodically_call_remote(:url => 'update', :frequency => '20', :update => 'news_block') # def periodically_call_remote(options = {}) attributes = extract_observer_attributes!(options) attributes["data-periodical"] = true + attributes["data-frequency"] ||= 10 # periodically_call_remote does not need data-observe=true attributes.delete('data-observe') @@ -442,8 +472,16 @@ module ActionView # parameter with the Ajax call. # # Example: - # # Generates: new Form.Element.Observer('suggest', 0.25, function(element, value) {new Ajax.Updater('suggest', - # # '/testing/find_suggestion', {asynchronous:true, evalScripts:true, parameters:'q=' + value})}) + # # Generates: + # # "" + # # # <%= observe_field :suggest, :url => { :action => :find_suggestion }, # :frequency => 0.25, # :update => :suggest, @@ -567,7 +605,7 @@ module ActionView url_options = options.delete(:url) url_options = url_options.merge(:escape => false) if url_options.is_a?(Hash) - attributes["data-url"] = escape_javascript(url_for(url_options)) + attributes["data-url"] = escape_javascript(url_for(url_options)) if url_options purge_unused_attributes!(attributes) end @@ -591,14 +629,14 @@ module ActionView def extract_observer_attributes!(options) callback = options.delete(:function) - frequency = options.delete(:frequency) + frequency = options.delete(:frequency) || 10 attributes = extract_remote_attributes!(options) attributes["data-observe"] = true attributes["data-observed"] = options.delete(:observed) attributes["data-onobserve"] = callback if callback - attributes["data-frequency"] = frequency.to_i if frequency && frequency != 0 + attributes["data-frequency"] = frequency if frequency && frequency.to_f != 0 attributes.delete("data-remote") purge_unused_attributes!(attributes) diff --git a/actionpack/test/template/ajax_helper_test.rb b/actionpack/test/template/ajax_helper_test.rb index ed020d74f8..c925dbb8f6 100644 --- a/actionpack/test/template/ajax_helper_test.rb +++ b/actionpack/test/template/ajax_helper_test.rb @@ -6,8 +6,14 @@ class Author include ActiveModel::Conversion attr_reader :id - def save; @id = 1 end - def new_record?; @id.nil? end + def save + @id = 1 + end + + def new_record? + @id.nil? + end + def name @id.nil? ? 'new author' : "author ##{@id}" end @@ -18,8 +24,16 @@ class Article include ActiveModel::Conversion attr_reader :id attr_reader :author_id - def save; @id = 1; @author_id = 1 end - def new_record?; @id.nil? end + + def save + @id = 1 + @author_id = 1 + end + + def new_record? + @id.nil? + end + def name @id.nil? ? 'new article' : "article ##{@id}" end @@ -36,17 +50,34 @@ class AjaxHelperBaseTest < ActionView::TestCase super @template = self @controller = Class.new do + def url_for(options) - if options.is_a?(String) - options - else - url = "http://www.example.com/" - url << options[:action].to_s if options and options[:action] - url << "?a=#{options[:a]}" if options && options[:a] - url << "&b=#{options[:b]}" if options && options[:a] && options[:b] - url + return optons unless options.is_a?(Hash) + + url = options.delete(:only_path) ? '/' : 'http://www.example.com' + + if controller = options.delete(:controller) + url << '/' << controller.to_s + end + if action = options.delete(:action) + url << '/' << action.to_s end + + if id = options.delete(:id) + url << '/' << id.to_s + end + + url << hash_to_param(options) if options.any? + + url.gsub!(/\/\/+/,'/') + + url end + + private + def hash_to_param(hash) + hash.map { |k,v| "#{k}=#{v}" }.join('&').insert(0,'?') + end end.new end @@ -70,24 +101,36 @@ class AjaxHelperTest < AjaxHelperBaseTest end test "link_to_remote" do - assert_dom_equal %(Remote outauthor), - link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }}, { :class => "fine" }) - assert_dom_equal %(Remote outauthor), - link_to_remote("Remote outauthor", :complete => "alert(request.responseText)", :url => { :action => "whatnot" }) - assert_dom_equal %(Remote outauthor), - link_to_remote("Remote outauthor", :success => "alert(request.responseText)", :url => { :action => "whatnot" }) - assert_dom_equal %(Remote outauthor), - link_to_remote("Remote outauthor", :failure => "alert(request.responseText)", :url => { :action => "whatnot" }) - assert_dom_equal %(Remote outauthor), - link_to_remote("Remote outauthor", :failure => "alert(request.responseText)", :url => { :action => "whatnot", :a => '10', :b => '20' }) - assert_dom_equal %(Remote outauthor), - link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :type => :synchronous) - assert_dom_equal %(Remote outauthor), - link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :position => :bottom) + assert_dom_equal %(Remove Author), + link_to_remote("Remove Author", { :url => { :action => "whatnot" }}, { :class => "fine" }) + assert_dom_equal %(Remove Author), + link_to_remote("Remove Author", :complete => "alert(request.responseText)", :url => { :action => "whatnot" }) + assert_dom_equal %(Remove Author), + link_to_remote("Remove Author", :success => "alert(request.responseText)", :url => { :action => "whatnot" }) + assert_dom_equal %(Remove Author), + link_to_remote("Remove Author", :failure => "alert(request.responseText)", :url => { :action => "whatnot" }) + assert_dom_equal %(Remove Author), + link_to_remote("Remove Author", :failure => "alert(request.responseText)", :url => { :action => "whatnot", :a => '10', :b => '20' }) + assert_dom_equal %(Remove Author), + link_to_remote("Remove Author", :url => { :action => "whatnot" }, :type => :synchronous) + assert_dom_equal %(Remove Author), + link_to_remote("Remove Author", :url => { :action => "whatnot" }, :position => :bottom) + end + + test "link_to_remote with url and oncomplete" do + actual = link_to_remote "undo", :url => { :controller => "words", :action => "undo", :n => 5 }, :complete => "undoRequestCompleted(request)" + expected = 'undo' + assert_dom_equal expected, actual + end + + test "link_to_remote with delete" do + actual = link_to_remote("Remove Author", { :url => { :action => "whatnot" }, :method => 'delete'}, { :class => "fine" }) + expected = 'Remove Author' + assert_dom_equal expected, actual end - + test "link_to_remote using both url and href" do - expected = 'Delete this Post' + expected = 'Delete this Post' assert_dom_equal expected, link_to_remote( "Delete this Post", { :update => "posts", :url => { :action => "destroy" } }, @@ -95,135 +138,162 @@ class AjaxHelperTest < AjaxHelperBaseTest end test "link_to_remote with update-success and url" do - expected = 'Delete this Post' - assert_dom_equal expected, link_to_remote( "Delete this Post", :url => { :action => "destroy", :id => 5 }, + expected = 'Delete this Post' + assert_dom_equal expected, link_to_remote( "Delete this Post", :url => { :action => "destroy"}, :update => { :success => "posts", :failure => "error" }) end test "link_to_remote with before/after callbacks" do - assert_dom_equal %(Remote outauthor), + assert_dom_equal %(Remote outauthor), link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :before => "before();", :after => "after();") end test "link_to_remote using :with expression" do - expected = %(Remote outauthor) + expected = %(Remote outauthor) assert_dom_equal expected, link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :with => "id=123") end test "link_to_remote using :condition expression" do - expected = %(Remote outauthor) + expected = %(Remote outauthor) assert_dom_equal expected, link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :condition => '$(\'foo\').val() == true') end test "link_to_remote using explicit :href" do - expected = %(Remote outauthor) + expected = %(Remote outauthor) assert_dom_equal expected, link_to_remote("Remote outauthor", {:url => { :action => "whatnot" }, :condition => '$(\'foo\').val() == true'}, :href => 'http://www.example.com/testhref') end test "link_to_remote using :submit" do - expected = %(Remote outauthor) + expected = %(Remote outauthor) assert_dom_equal expected, link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :submit => 'myForm') end test "link_to_remote with method delete" do - assert_dom_equal %(Remote outauthor), + assert_dom_equal %(Remote outauthor), link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }, :method => "delete"}, { :class => "fine" }) end test "link_to_remote with method delete as symbol" do - assert_dom_equal %(Remote outauthor), + assert_dom_equal %(Remote outauthor), link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }, :method => :delete}, { :class => "fine" }) end test "link_to_remote html options" do - assert_dom_equal %(Remote outauthor), + assert_dom_equal %(Remote outauthor), link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }, :html => { :class => "fine" } }) end test "link_to_remote url quote escaping" do - assert_dom_equal %(Remote), + assert_dom_equal %(Remote), link_to_remote("Remote", { :url => { :action => "whatnot's" } }) end test "link_to_remote with confirm" do - assert_dom_equal %(Remote confirm), + assert_dom_equal %(Remote confirm), link_to_remote("Remote confirm", { :url => { :action => "whatnot" }, :method => "delete", :confirm => "Are you sure?"}, { :class => "fine" }) end test "button_to_remote" do - assert_dom_equal %(), + assert_dom_equal %(), button_to_remote("Remote outpost", { :url => { :action => "whatnot" }}, { :class => "fine" }) - assert_dom_equal %(), + assert_dom_equal %(), button_to_remote("Remote outpost", :complete => "alert(request.reponseText)", :url => { :action => "whatnot" }) - assert_dom_equal %(), + assert_dom_equal %(), button_to_remote("Remote outpost", :success => "alert(request.reponseText)", :url => { :action => "whatnot" }) - assert_dom_equal %(), + assert_dom_equal %(), button_to_remote("Remote outpost", :failure => "alert(request.reponseText)", :url => { :action => "whatnot" }) - assert_dom_equal %(), + assert_dom_equal %(), button_to_remote("Remote outpost", :failure => "alert(request.reponseText)", :url => { :action => "whatnot", :a => '10', :b => '20' }) end test "button_to_remote with confirm" do - assert_dom_equal %(), + assert_dom_equal %(), button_to_remote("Remote outpost", { :url => { :action => "whatnot" }, :confirm => "Are you sure?"}, { :class => "fine" }) end test "button_to_remote with :submit" do - assert_dom_equal %(), + assert_dom_equal %(), button_to_remote("Remote outpost", { :url => { :action => "whatnot" }, :submit => "myForm"}, { :class => "fine" }) end test "periodically_call_remote" do - assert_dom_equal %(), - periodically_call_remote(:update => "schremser_bier", :url => { :action => "mehr_bier" }) + expected = "" + actual = periodically_call_remote(:update => "schremser_bier", :url => { :action => "mehr_bier" }) + assert_dom_equal expected, actual end test "periodically_call_remote_with_frequency" do - assert_dom_equal( - "", - periodically_call_remote(:frequency => 2) - ) + expected = "" + actual = periodically_call_remote(:frequency => 2) + assert_dom_equal expected, actual end test "periodically_call_remote_with_function" do - assert_dom_equal( - "", - periodically_call_remote(:frequency => 2, :function => "alert('test')") - ) + expected = "" + actual = periodically_call_remote(:frequency => 2, :function => "alert('test')") + assert_dom_equal expected, actual + end + + test "periodically_call_remote_with_update" do + actual = periodically_call_remote(:url => { :action => 'get_averages' }, :update => 'avg') + expected = "" + assert_dom_equal expected, actual + end + + test "periodically_call_remote with update success and failure" do + actual = periodically_call_remote(:url => { :action => 'invoice', :id => 1 },:update => { :success => "invoice", :failure => "error" }) + expected = "" + assert_dom_equal expected, actual + end + + test "periodically_call_remote with frequency and update" do + actual = periodically_call_remote(:url => 'update', :frequency => '20', :update => 'news_block') + expected = "" + assert_dom_equal expected, actual end test "form_remote_tag" do - assert_dom_equal %(
), - form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) - assert_dom_equal %(), + assert_dom_equal %(), + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast } ) + assert_dom_equal %(), form_remote_tag(:update => { :success => "glass_of_beer" }, :url => { :action => :fast }) - assert_dom_equal %(), + assert_dom_equal %(), form_remote_tag(:update => { :failure => "glass_of_water" }, :url => { :action => :fast }) - assert_dom_equal %(), + assert_dom_equal %(), form_remote_tag(:update => { :success => 'glass_of_beer', :failure => "glass_of_water" }, :url => { :action => :fast }) end test "form_remote_tag with method" do - assert_dom_equal %(
), + assert_dom_equal %(
), form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, :html => { :method => :put }) end + test "form_remote_tag with url" do + form_remote_tag(:url => '/posts' ){} + expected = "
" + assert_dom_equal expected, output_buffer + end + test "form_remote_tag with block in erb" do __in_erb_template = '' form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) { concat "Hello world!" } - assert_dom_equal %(
Hello world!
), output_buffer + assert_dom_equal %(
Hello world!
), output_buffer end test "remote_form_for with record identification with new record" do remote_form_for(@record, {:html => { :id => 'create-author' }}) {} - expected = %(
) assert_dom_equal expected, output_buffer end + test "remote_form_for with url" do + remote_form_for(@record, {:html => { :id => 'create-author' }}) {} + expected = "
" + assert_dom_equal expected, output_buffer + end + test "remote_form_for with record identification without html options" do remote_form_for(@record) {} - expected = %(
) assert_dom_equal expected, output_buffer end @@ -236,7 +306,8 @@ class AjaxHelperTest < AjaxHelperBaseTest assert_dom_equal expected, output_buffer end - test "remote_form_for with new object in list" do + test "remote_form_for with new nested object and an excisting parent" do + @author.save remote_form_for([@author, @article]) {} expected = %(
) @@ -246,94 +317,119 @@ class AjaxHelperTest < AjaxHelperBaseTest test "remote_form_for with existing object in list" do @author.save @article.save + remote_form_for([@author, @article]) {} - expected = %(
) + expected = %(
) assert_dom_equal expected, output_buffer end test "on callbacks" do callbacks = [:uninitialized, :loading, :loaded, :interactive, :complete, :success, :failure] callbacks.each do |callback| - assert_dom_equal %(
), + assert_dom_equal %(), form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();") - assert_dom_equal %(), + assert_dom_equal %(), form_remote_tag(:update => { :success => "glass_of_beer" }, :url => { :action => :fast }, callback=>"monkeys();") - assert_dom_equal %(), + assert_dom_equal %(), form_remote_tag(:update => { :failure => "glass_of_beer" }, :url => { :action => :fast }, callback=>"monkeys();") - assert_dom_equal %(), + assert_dom_equal %(), form_remote_tag(:update => { :success => "glass_of_beer", :failure => "glass_of_water" }, :url => { :action => :fast }, callback=>"monkeys();") end #HTTP status codes 200 up to 599 have callbacks #these should work 100.upto(599) do |callback| - assert_dom_equal %(), + assert_dom_equal %(), form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();") end #test 200 and 404 - assert_dom_equal %(), + assert_dom_equal %(), form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, 200=>"monkeys();", 404=>"bananas();") #these shouldn't 1.upto(99) do |callback| - assert_dom_equal %(), + assert_dom_equal %(), form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();") end 600.upto(999) do |callback| - assert_dom_equal %(), + assert_dom_equal %(), form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();") end #test ultimate combo - assert_dom_equal %(), + assert_dom_equal %(), form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, :loading => "c1()", :success => "s()", :failure => "f();", :complete => "c();", 200=>"monkeys();", 404=>"bananas();") end test "submit_to_remote" do - assert_dom_equal %(), + assert_dom_equal %(), submit_to_remote("More beer!", 1_000_000, :url => { :action => 'empty_bottle' }, :update => "empty_bottle") end + test "submit_to_remote simple" do + expected = "" + actual = submit_to_remote 'create_btn', 'Create', :url => { :action => 'create' } + assert_dom_equal expected, actual + end + + test "submit_to_remote with success and failure" do + expected = "" + actual = submit_to_remote 'update_btn', 'Update', :url => { :action => 'update' }, :update => { :success => "succeed", :failure => "fail" } + assert_dom_equal expected, actual + end + test "observe_field" do - assert_dom_equal %(), + assert_dom_equal %(), observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" }) end + test "observe_field with url, frequency, update and with" do + actual = observe_field :suggest, :url => { :action => :find_suggestion }, :frequency => 0.25, :update => :suggest, :with => 'q' + expected = "" + assert_dom_equal actual, expected + end + + test "observe_field default frequency" do + actual = observe_field :suggest + expected = "" + assert_dom_equal actual, expected + end + test "observe_field using with option" do - expected = %() + expected = %() assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => 'id=123') end test "observe_field using condition option" do - expected = %() + expected = %() assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :condition => '$(\'foo\').val() == true') end test "observe_field using json in with option" do - expected = %() + expected = %() assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "{'id':value}") end test "observe_field using function for callback" do - assert_dom_equal %(), + assert_dom_equal %(), observe_field("glass", :frequency => 5.minutes, :function => "alert('Element changed')") end test "observe_form" do - assert_dom_equal %(), + assert_dom_equal %(), observe_form("cart", :frequency => 2, :url => { :action => "cart_changed" }) end test "observe_form using function for callback" do - assert_dom_equal %(), + assert_dom_equal %(), observe_form("cart", :frequency => 2, :function => "alert('Form changed')") end test "observe_field without frequency" do - assert_dom_equal %(), + assert_dom_equal %(), observe_field("glass") end -- cgit v1.2.3