aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack
diff options
context:
space:
mode:
authorMarcel Molina <marcel@vernix.org>2005-11-17 21:28:59 +0000
committerMarcel Molina <marcel@vernix.org>2005-11-17 21:28:59 +0000
commit06e74b6c91d48cd482ef7ee32817510dcd07f97a (patch)
tree6d93c120a7c396482c79144a56bd07a50c0e88b0 /actionpack
parentfd66ccb01658b7cc7654e42233fd760b4fc788ff (diff)
downloadrails-06e74b6c91d48cd482ef7ee32817510dcd07f97a.tar.gz
rails-06e74b6c91d48cd482ef7ee32817510dcd07f97a.tar.bz2
rails-06e74b6c91d48cd482ef7ee32817510dcd07f97a.zip
Add support for new rjs templates which wrap an update_page block.
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@3078 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
Diffstat (limited to 'actionpack')
-rw-r--r--actionpack/CHANGELOG2
-rw-r--r--actionpack/lib/action_view/base.rb89
-rw-r--r--actionpack/test/controller/new_render_test.rb29
-rw-r--r--actionpack/test/fixtures/test/delete_with_js.rjs2
4 files changed, 99 insertions, 23 deletions
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index 5587b4116b..155c3723b0 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -1,5 +1,7 @@
*SVN*
+* Add support for new rjs templates which wrap an update_page block. [Marcel Molina Jr.]
+
* Rename Version constant to VERSION. #2802 [Marcel Molina Jr.]
* Correct time_zone_options_for_select docs. #2892 [pudeyo@rpi.com]
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index 83bb318ce5..798d00673a 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -5,8 +5,9 @@ module ActionView #:nodoc:
class ActionViewError < StandardError #:nodoc:
end
- # Action View templates can be written in two ways. If the template file has a +.rhtml+ extension then it uses a mixture of ERb
- # (included in Ruby) and HTML. If the template file has a +.rxml+ extension then Jim Weirich's Builder::XmlMarkup library is used.
+ # Action View templates can be written in three ways. If the template file has a +.rhtml+ extension then it uses a mixture of ERb
+ # (included in Ruby) and HTML. If the template file has a +.rxml+ extension then Jim Weirich's Builder::XmlMarkup library is used.
+ # If the template file has a +.rjs+ extension then it will use ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.
#
# = ERb
#
@@ -73,7 +74,7 @@ module ActionView #:nodoc:
# xml.em("emphasized") # => <em>emphasized</em>
# xml.em { xml.b("emp & bold") } # => <em><b>emph &amp; bold</b></em>
# xml.a("A Link", "href"=>"http://onestepback.org") # => <a href="http://onestepback.org">A Link</a>
- # xm.target("name"=>"compile", "option"=>"fast") # => <target option="fast" name="compile"\>
+ # xml.target("name"=>"compile", "option"=>"fast") # => <target option="fast" name="compile"\>
# # NOTE: order of attributes is not specified.
#
# Any method with a block will be treated as an XML markup tag with nested markup in the block. For example, the following:
@@ -115,6 +116,29 @@ module ActionView #:nodoc:
# end
#
# More builder documentation can be found at http://builder.rubyforge.org.
+ #
+ # == JavaScriptGenerator
+ #
+ # JavaScriptGenerator templates end in +.rjs+. Unlike conventional templates which are used to
+ # render the results of an action, these templates generate instructions on how to modify an already rendered page. This makes it easy to
+ # modify multiple elements on your page in one declarative Ajax response. Actions with these templates are called in the background with Ajax
+ # and make updates to the page where the request originated from.
+ #
+ # An instance of the JavaScriptGenerator object named +page+ is automatically made available to your template, which is implicitly wrapped in an ActionView::Helpers::PrototypeHelper#update_page block.
+ #
+ # When an .rjs action is called with +link_to_remote+, the generated JavaScript is automatically evaluated. Example:
+ #
+ # link_to_remote :url => {:action => 'delete'}
+ #
+ # The subsequently rendered +delete.rjs+ might look like:
+ #
+ # page.replace_html 'sidebar', :partial => 'sidebar'
+ # page.remove "person-#{@person.id}"
+ # page.visual_effect :highlight, 'user-list'
+ #
+ # This refreshes the sidebar, removes a person element and highlights the user list.
+ #
+ # See the ActionView::Helpers::PrototypeHelper::JavaScriptGenerator documentation for more details.
class Base
include ERB::Util
@@ -273,12 +297,11 @@ module ActionView #:nodoc:
def pick_template_extension(template_path)#:nodoc:
if match = delegate_template_exists?(template_path)
match.first
- elsif template_exists?(template_path, :rhtml)
- 'rhtml'
- elsif template_exists?(template_path, :rxml)
- 'rxml'
+ elsif erb_template_exists?(template_path): 'rhtml'
+ elsif builder_template_exists?(template_path): 'rxml'
+ elsif javascript_template_exists?(template_path): 'rjs'
else
- raise ActionViewError, "No rhtml, rxml, or delegate template found for #{template_path}"
+ raise ActionViewError, "No rhtml, rxml, rjs or delegate template found for #{template_path}"
end
end
@@ -293,9 +316,15 @@ module ActionView #:nodoc:
def builder_template_exists?(template_path)#:nodoc:
template_exists?(template_path, :rxml)
end
+
+ def javascript_template_exists?(template_path)#:nodoc:
+ template_exists?(template_path, :rjs)
+ end
def file_exists?(template_path)#:nodoc:
- erb_template_exists?(template_path) || builder_template_exists?(template_path) || delegate_template_exists?(template_path)
+ %w(erb builder javascript delegate).any? do |template_type|
+ send("#{template_type}_template_exists?", template_path)
+ end
end
# Returns true is the file may be rendered implicitly.
@@ -345,7 +374,7 @@ module ActionView #:nodoc:
# Or if local_assigns has a new key, which isn't supported by the compiled code yet.
# Or if the file has changed on disk and checking file mods hasn't been disabled.
def compile_template?(template, file_name, local_assigns)
- method_key = file_name || template
+ method_key = file_name || template
render_symbol = @@method_names[method_key]
if @@compile_time[render_symbol] && supports_local_assigns?(render_symbol, local_assigns)
@@ -359,10 +388,16 @@ module ActionView #:nodoc:
# Create source code for given template
def create_template_source(extension, template, render_symbol, locals)
- if extension && (extension.to_sym == :rxml)
- body = "xml = Builder::XmlMarkup.new(:indent => 2)\n" +
- "@controller.headers['Content-Type'] ||= 'text/xml'\n" +
- template
+ if template_requires_setup?(extension)
+ body = case extension.to_sym
+ when :rxml
+ "xml = Builder::XmlMarkup.new(:indent => 2)\n" +
+ "@controller.headers['Content-Type'] ||= 'text/xml'\n" +
+ template
+ when :rjs
+ "@controller.headers['Content-Type'] ||= 'text/javascript'\n" +
+ "update_page do |page|\n#{template}\nend"
+ end
else
body = ERB.new(template, nil, @@erb_trim_mode).src
end
@@ -379,14 +414,17 @@ module ActionView #:nodoc:
"def #{render_symbol}(local_assigns)\n#{locals_code}#{body}\nend"
end
+ def template_requires_setup?(extension)
+ templates_requiring_setup.include? extension.to_s
+ end
+
+ def templates_requiring_setup
+ %w(rxml rjs)
+ end
+
def assign_method_name(extension, template, file_name)
method_name = '_run_'
-
- if extension && (extension.to_sym == :rxml)
- method_name << 'xml_'
- else
- method_name << 'html_'
- end
+ method_name << "#{extension}_" if extension
if file_name
file_path = File.expand_path(file_name)
@@ -396,7 +434,7 @@ module ActionView #:nodoc:
l = base_path.length
method_name_file_part = i ? file_path[i+l+1,file_path.length-l-1] : file_path.clone
- method_name_file_part.sub!(/\.r(ht|x)ml$/,'')
+ method_name_file_part.sub!(/\.r(html|xml|js)$/,'')
method_name_file_part.tr!('/:-', '_')
method_name_file_part.gsub!(/[^a-zA-Z0-9_]/){|s| s[0].to_s}
@@ -416,8 +454,13 @@ module ActionView #:nodoc:
render_source = create_template_source(extension, template, render_symbol, local_assigns.keys)
line_offset = @@template_args[render_symbol].size
- line_offset += 2 if extension && (extension.to_sym == :rxml)
-
+ if extension
+ case extension.to_sym
+ when :rxml, :rjs
+ line_offset += 2
+ end
+ end
+
begin
unless file_name.blank?
CompiledTemplates.module_eval(render_source, file_name, -line_offset)
diff --git a/actionpack/test/controller/new_render_test.rb b/actionpack/test/controller/new_render_test.rb
index 919875e8c3..7cd17f1d55 100644
--- a/actionpack/test/controller/new_render_test.rb
+++ b/actionpack/test/controller/new_render_test.rb
@@ -154,6 +154,20 @@ class NewRenderTestController < ActionController::Base
render :action => "potential_conflicts"
end
+ def delete_with_js
+ @project_id = 4
+ end
+
+ def render_js_with_explicit_template
+ @project_id = 4
+ render :template => 'test/delete_with_js'
+ end
+
+ def render_js_with_explicit_action_template
+ @project_id = 4
+ render :action => 'delete_with_js'
+ end
+
def action_talk_to_layout
# Action template sets variable that's picked up by layout
end
@@ -279,6 +293,21 @@ class NewRenderTest < Test::Unit::TestCase
assert_equal "<p>This is grand!</p>\n", @response.body
end
+ def test_render_rjs_with_default
+ get :delete_with_js
+ assert_equal %!["person"].each(Element.remove);\nnew Effect.Highlight('project-4',{});!, @response.body
+ end
+
+ def test_render_rjs_template_explicitly
+ get :render_js_with_explicit_template
+ assert_equal %!["person"].each(Element.remove);\nnew Effect.Highlight('project-4',{});!, @response.body
+ end
+
+ def test_rendering_rjs_action_explicitly
+ get :render_js_with_explicit_action_template
+ assert_equal %!["person"].each(Element.remove);\nnew Effect.Highlight('project-4',{});!, @response.body
+ end
+
def test_layout_rendering
get :layout_test
assert_equal "<html>Hello world!</html>", @response.body
diff --git a/actionpack/test/fixtures/test/delete_with_js.rjs b/actionpack/test/fixtures/test/delete_with_js.rjs
new file mode 100644
index 0000000000..4b75a955ad
--- /dev/null
+++ b/actionpack/test/fixtures/test/delete_with_js.rjs
@@ -0,0 +1,2 @@
+page.remove 'person'
+page.visual_effect :highlight, "project-#{@project_id}"