aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_view
diff options
context:
space:
mode:
authorJeremy Kemper <jeremy@bitsweat.net>2008-12-29 14:38:54 -0800
committerJeremy Kemper <jeremy@bitsweat.net>2008-12-29 14:38:54 -0800
commit276ec16007b03d0a527fb0b83a7ee0b81e460fa1 (patch)
tree224491aa1948d613a551189028746d73400fccce /actionpack/lib/action_view
parent2e053aec9bafa8735d70886f36dea06ea10dc4ce (diff)
parent490c26c8433a6d278bc61118782da360e8889646 (diff)
downloadrails-276ec16007b03d0a527fb0b83a7ee0b81e460fa1.tar.gz
rails-276ec16007b03d0a527fb0b83a7ee0b81e460fa1.tar.bz2
rails-276ec16007b03d0a527fb0b83a7ee0b81e460fa1.zip
Merge branch 'master' of git@github.com:rails/rails
Diffstat (limited to 'actionpack/lib/action_view')
-rw-r--r--actionpack/lib/action_view/base.rb62
-rw-r--r--actionpack/lib/action_view/helpers/date_helper.rb75
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb10
-rw-r--r--actionpack/lib/action_view/helpers/prototype_helper.rb11
-rw-r--r--actionpack/lib/action_view/locale/en.yml7
-rw-r--r--actionpack/lib/action_view/partials.rb2
-rw-r--r--actionpack/lib/action_view/paths.rb41
-rw-r--r--actionpack/lib/action_view/renderable.rb22
-rw-r--r--actionpack/lib/action_view/template.rb28
9 files changed, 148 insertions, 110 deletions
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index 33517ffb7b..8958e61e9d 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -3,7 +3,10 @@ module ActionView #:nodoc:
end
class MissingTemplate < ActionViewError #:nodoc:
+ attr_reader :path
+
def initialize(paths, path, template_format = nil)
+ @path = path
full_template_path = path.include?('.') ? path : "#{path}.erb"
display_paths = paths.compact.join(":")
template_type = (path =~ /layouts/i) ? 'layout' : 'template'
@@ -172,17 +175,6 @@ module ActionView #:nodoc:
delegate :logger, :to => 'ActionController::Base'
end
- # Templates that are exempt from layouts
- @@exempt_from_layout = Set.new([/\.rjs$/])
-
- # Don't render layouts for templates with the given extensions.
- def self.exempt_from_layout(*extensions)
- regexps = extensions.collect do |extension|
- extension.is_a?(Regexp) ? extension : /\.#{Regexp.escape(extension.to_s)}$/
- end
- @@exempt_from_layout.merge(regexps)
- end
-
@@debug_rjs = false
##
# :singleton-method:
@@ -190,12 +182,6 @@ module ActionView #:nodoc:
# that alert()s the caught exception (and then re-raises it).
cattr_accessor :debug_rjs
- @@warn_cache_misses = false
- ##
- # :singleton-method:
- # A warning will be displayed whenever an action results in a cache miss on your view paths.
- cattr_accessor :warn_cache_misses
-
attr_internal :request
delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers,
@@ -257,7 +243,8 @@ module ActionView #:nodoc:
if options[:layout]
_render_with_layout(options, local_assigns, &block)
elsif options[:file]
- _pick_template(options[:file]).render_template(self, options[:locals])
+ tempalte = self.view_paths.find_template(options[:file], template_format)
+ tempalte.render_template(self, options[:locals])
elsif options[:partial]
render_partial(options)
elsif options[:inline]
@@ -315,45 +302,6 @@ module ActionView #:nodoc:
end
end
- def _pick_template(template_path)
- return template_path if template_path.respond_to?(:render)
-
- path = template_path.sub(/^\//, '')
- if m = path.match(/(.*)\.(\w+)$/)
- template_file_name, template_file_extension = m[1], m[2]
- else
- template_file_name = path
- end
-
- # OPTIMIZE: Checks to lookup template in view path
- if template = self.view_paths.find_template(template_file_name, template_format)
- template
- elsif (first_render = @_render_stack.first) && first_render.respond_to?(:format_and_extension) &&
- (template = self.view_paths["#{template_file_name}.#{first_render.format_and_extension}"])
- template
- else
- template = Template.new(template_path, view_paths)
-
- if self.class.warn_cache_misses && logger
- logger.debug "[PERFORMANCE] Rendering a template that was " +
- "not found in view path. Templates outside the view path are " +
- "not cached and result in expensive disk operations. Move this " +
- "file into #{view_paths.join(':')} or add the folder to your " +
- "view path list"
- end
-
- template
- end
- end
- memoize :_pick_template
-
- def _exempt_from_layout?(template_path) #:nodoc:
- template = _pick_template(template_path).to_s
- @@exempt_from_layout.any? { |ext| template =~ ext }
- rescue ActionView::MissingTemplate
- return false
- end
-
def _render_with_layout(options, local_assigns, &block) #:nodoc:
partial_layout = options.delete(:layout)
diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb
index a04bb8c598..4305617ac8 100644
--- a/actionpack/lib/action_view/helpers/date_helper.rb
+++ b/actionpack/lib/action_view/helpers/date_helper.rb
@@ -136,6 +136,10 @@ module ActionView
# dates.
# * <tt>:default</tt> - Set a default date if the affected date isn't set or is nil.
# * <tt>:disabled</tt> - Set to true if you want show the select fields as disabled.
+ # * <tt>:prompt</tt> - Set to true (for a generic prompt), a prompt string or a hash of prompt strings
+ # for <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>, <tt>:hour</tt>, <tt>:minute</tt> and <tt>:second</tt>.
+ # Setting this option prepends a select option with a generic prompt (Day, Month, Year, Hour, Minute, Seconds)
+ # or the given prompt string.
#
# If anything is passed in the +html_options+ hash it will be applied to every select tag in the set.
#
@@ -171,6 +175,9 @@ module ActionView
# # that will have a default day of 20.
# date_select("credit_card", "bill_due", :default => { :day => 20 })
#
+ # # Generates a date select with custom prompts
+ # date_select("post", "written_on", :prompt => { :day => 'Select day', :month => 'Select month', :year => 'Select year' })
+ #
# The selects are prepared for multi-parameter assignment to an Active Record object.
#
# Note: If the day is not included as an option but the month is, the day will be set to the 1st to ensure that
@@ -210,6 +217,11 @@ module ActionView
# # You can set the :minute_step to 15 which will give you: 00, 15, 30 and 45.
# time_select 'game', 'game_time', {:minute_step => 15}
#
+ # # Creates a time select tag with a custom prompt. Use :prompt => true for generic prompts.
+ # time_select("post", "written_on", :prompt => {:hour => 'Choose hour', :minute => 'Choose minute', :second => 'Choose seconds'})
+ # time_select("post", "written_on", :prompt => {:hour => true}) # generic prompt for hours
+ # time_select("post", "written_on", :prompt => true) # generic prompts for all
+ #
# The selects are prepared for multi-parameter assignment to an Active Record object.
#
# Note: If the day is not included as an option but the month is, the day will be set to the 1st to ensure that
@@ -241,6 +253,11 @@ module ActionView
# # as the written_on attribute.
# datetime_select("post", "written_on", :discard_type => true)
#
+ # # Generates a datetime select with a custom prompt. Use :prompt=>true for generic prompts.
+ # datetime_select("post", "written_on", :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'})
+ # datetime_select("post", "written_on", :prompt => {:hour => true}) # generic prompt for hours
+ # datetime_select("post", "written_on", :prompt => true) # generic prompts for all
+ #
# The selects are prepared for multi-parameter assignment to an Active Record object.
def datetime_select(object_name, method, options = {}, html_options = {})
InstanceTag.new(object_name, method, self, options.delete(:object)).to_datetime_select_tag(options, html_options)
@@ -285,6 +302,11 @@ module ActionView
# # prefixed with 'payday' rather than 'date'
# select_datetime(my_date_time, :prefix => 'payday')
#
+ # # Generates a datetime select with a custom prompt. Use :prompt=>true for generic prompts.
+ # select_datetime(my_date_time, :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'})
+ # select_datetime(my_date_time, :prompt => {:hour => true}) # generic prompt for hours
+ # select_datetime(my_date_time, :prompt => true) # generic prompts for all
+ #
def select_datetime(datetime = Time.current, options = {}, html_options = {})
DateTimeSelector.new(datetime, options, html_options).select_datetime
end
@@ -321,6 +343,11 @@ module ActionView
# # prefixed with 'payday' rather than 'date'
# select_date(my_date, :prefix => 'payday')
#
+ # # Generates a date select with a custom prompt. Use :prompt=>true for generic prompts.
+ # select_date(my_date, :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'})
+ # select_date(my_date, :prompt => {:hour => true}) # generic prompt for hours
+ # select_date(my_date, :prompt => true) # generic prompts for all
+ #
def select_date(date = Date.current, options = {}, html_options = {})
DateTimeSelector.new(date, options, html_options).select_date
end
@@ -352,6 +379,11 @@ module ActionView
# # separated by ':' and includes an input for seconds
# select_time(my_time, :time_separator => ':', :include_seconds => true)
#
+ # # Generates a time select with a custom prompt. Use :prompt=>true for generic prompts.
+ # select_time(my_time, :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'})
+ # select_time(my_time, :prompt => {:hour => true}) # generic prompt for hours
+ # select_time(my_time, :prompt => true) # generic prompts for all
+ #
def select_time(datetime = Time.current, options = {}, html_options = {})
DateTimeSelector.new(datetime, options, html_options).select_time
end
@@ -373,6 +405,10 @@ module ActionView
# # that is named 'interval' rather than 'second'
# select_second(my_time, :field_name => 'interval')
#
+ # # Generates a select field for seconds with a custom prompt. Use :prompt=>true for a
+ # # generic prompt.
+ # select_minute(14, :prompt => 'Choose seconds')
+ #
def select_second(datetime, options = {}, html_options = {})
DateTimeSelector.new(datetime, options, html_options).select_second
end
@@ -395,6 +431,10 @@ module ActionView
# # that is named 'stride' rather than 'second'
# select_minute(my_time, :field_name => 'stride')
#
+ # # Generates a select field for minutes with a custom prompt. Use :prompt=>true for a
+ # # generic prompt.
+ # select_minute(14, :prompt => 'Choose minutes')
+ #
def select_minute(datetime, options = {}, html_options = {})
DateTimeSelector.new(datetime, options, html_options).select_minute
end
@@ -416,6 +456,10 @@ module ActionView
# # that is named 'stride' rather than 'second'
# select_hour(my_time, :field_name => 'stride')
#
+ # # Generates a select field for hours with a custom prompt. Use :prompt => true for a
+ # # generic prompt.
+ # select_hour(13, :prompt =>'Choose hour')
+ #
def select_hour(datetime, options = {}, html_options = {})
DateTimeSelector.new(datetime, options, html_options).select_hour
end
@@ -437,6 +481,10 @@ module ActionView
# # that is named 'due' rather than 'day'
# select_day(my_time, :field_name => 'due')
#
+ # # Generates a select field for days with a custom prompt. Use :prompt => true for a
+ # # generic prompt.
+ # select_day(5, :prompt => 'Choose day')
+ #
def select_day(date, options = {}, html_options = {})
DateTimeSelector.new(date, options, html_options).select_day
end
@@ -475,6 +523,10 @@ module ActionView
# # will use keys like "Januar", "Marts."
# select_month(Date.today, :use_month_names => %w(Januar Februar Marts ...))
#
+ # # Generates a select field for months with a custom prompt. Use :prompt => true for a
+ # # generic prompt.
+ # select_month(14, :prompt => 'Choose month')
+ #
def select_month(date, options = {}, html_options = {})
DateTimeSelector.new(date, options, html_options).select_month
end
@@ -502,6 +554,10 @@ module ActionView
# # has ascending year values
# select_year(2006, :start_year => 2000, :end_year => 2010)
#
+ # # Generates a select field for years with a custom prompt. Use :prompt => true for a
+ # # generic prompt.
+ # select_year(14, :prompt => 'Choose year')
+ #
def select_year(date, options = {}, html_options = {})
DateTimeSelector.new(date, options, html_options).select_year
end
@@ -764,11 +820,30 @@ module ActionView
select_html = "\n"
select_html << content_tag(:option, '', :value => '') + "\n" if @options[:include_blank]
+ select_html << prompt_option_tag(type, @options[:prompt]) + "\n" if @options[:prompt]
select_html << select_options_as_html.to_s
content_tag(:select, select_html, select_options) + "\n"
end
+ # Builds a prompt option tag with supplied options or from default options
+ # prompt_option_tag(:month, :prompt => 'Select month')
+ # => "<option value="">Select month</option>"
+ def prompt_option_tag(type, options)
+ default_options = {:year => false, :month => false, :day => false, :hour => false, :minute => false, :second => false}
+
+ case options
+ when Hash
+ prompt = default_options.merge(options)[type.to_sym]
+ when String
+ prompt = options
+ else
+ prompt = I18n.translate(('datetime.prompts.' + type.to_s).to_sym, :locale => @options[:locale])
+ end
+
+ prompt ? content_tag(:option, prompt, :value => '') : ''
+ end
+
# Builds hidden input tag for date part and value
# build_hidden(:year, 2008)
# => "<input id="post_written_on_1i" name="post[written_on(1i)]" type="hidden" value="2008" />"
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index 621e2946b5..a85751c657 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -737,9 +737,13 @@ module ActionView
(field_helpers - %w(label check_box radio_button fields_for)).each do |selector|
src = <<-end_src
- def #{selector}(method, options = {})
- @template.send(#{selector.inspect}, @object_name, method, objectify_options(options))
- end
+ def #{selector}(method, options = {}) # def text_field(method, options = {})
+ @template.send( # @template.send(
+ #{selector.inspect}, # "text_field",
+ @object_name, # @object_name,
+ method, # method,
+ objectify_options(options)) # objectify_options(options))
+ end # end
end_src
class_eval src, __FILE__, __LINE__
end
diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb
index 7fab3102e7..18a209dcea 100644
--- a/actionpack/lib/action_view/helpers/prototype_helper.rb
+++ b/actionpack/lib/action_view/helpers/prototype_helper.rb
@@ -531,11 +531,6 @@ module ActionView
# is shorthand for
# :with => "'name=' + value"
# This essentially just changes the key of the parameter.
- # <tt>:on</tt>:: Specifies which event handler to observe. By default,
- # it's set to "changed" for text fields and areas and
- # "click" for radio buttons and checkboxes. With this,
- # you can specify it instead to be "blur" or "focus" or
- # any other event.
#
# Additionally, you may specify any of the options documented in the
# <em>Common options</em> section at the top of this document.
@@ -548,11 +543,6 @@ module ActionView
# :url => 'http://example.com/books/edit/1',
# :with => 'title'
#
- # # Sends params: {:book_title => 'Title of the book'} when the focus leaves
- # # the input field.
- # observe_field 'book_title',
- # :url => 'http://example.com/books/edit/1',
- # :on => 'blur'
#
def observe_field(field_id, options = {})
if options[:frequency] && options[:frequency] > 0
@@ -1094,7 +1084,6 @@ module ActionView
javascript << "#{options[:frequency]}, " if options[:frequency]
javascript << "function(element, value) {"
javascript << "#{callback}}"
- javascript << ", '#{options[:on]}'" if options[:on]
javascript << ")"
javascript_tag(javascript)
end
diff --git a/actionpack/lib/action_view/locale/en.yml b/actionpack/lib/action_view/locale/en.yml
index 9542b035aa..a880fd83ef 100644
--- a/actionpack/lib/action_view/locale/en.yml
+++ b/actionpack/lib/action_view/locale/en.yml
@@ -80,6 +80,13 @@
over_x_years:
one: "over 1 year"
other: "over {{count}} years"
+ prompts:
+ year: "Year"
+ month: "Month"
+ day: "Day"
+ hour: "Hour"
+ minute: "Minute"
+ second: "Seconds"
activerecord:
errors:
diff --git a/actionpack/lib/action_view/partials.rb b/actionpack/lib/action_view/partials.rb
index bbc995a340..59e82b98a4 100644
--- a/actionpack/lib/action_view/partials.rb
+++ b/actionpack/lib/action_view/partials.rb
@@ -228,7 +228,7 @@ module ActionView
path = "_#{partial_path}"
end
- _pick_template(path)
+ self.view_paths.find_template(path, self.template_format)
end
memoize :_pick_partial_template
end
diff --git a/actionpack/lib/action_view/paths.rb b/actionpack/lib/action_view/paths.rb
index 623b9ff6b0..b030156889 100644
--- a/actionpack/lib/action_view/paths.rb
+++ b/actionpack/lib/action_view/paths.rb
@@ -2,13 +2,6 @@ module ActionView #:nodoc:
class PathSet < Array #:nodoc:
def self.type_cast(obj)
if obj.is_a?(String)
- if Base.warn_cache_misses && defined?(Rails) && Rails.initialized?
- Base.logger.debug "[PERFORMANCE] Processing view path during a " +
- "request. This an expense disk operation that should be done at " +
- "boot. You can manually process this view path with " +
- "ActionView::Base.process_view_paths(#{obj.inspect}) and set it " +
- "as your view path"
- end
Path.new(obj)
else
obj
@@ -92,7 +85,7 @@ module ActionView #:nodoc:
else
Dir.glob("#{@path}/#{path}*").each do |file|
template = create_template(file)
- if path == template.path_without_extension || path == template.path
+ if template.accessible_paths.include?(path)
return template
end
end
@@ -115,8 +108,9 @@ module ActionView #:nodoc:
templates_in_path do |template|
template.load!
- @paths[template.path] = template
- @paths[template.path_without_extension] ||= template
+ template.accessible_paths.each do |path|
+ @paths[path] = template
+ end
end
@paths.freeze
@@ -143,28 +137,19 @@ module ActionView #:nodoc:
each { |path| path.reload! }
end
- def [](template_path)
- each do |path|
- if template = path[template_path]
- return template
- end
- end
- nil
- end
+ def find_template(original_template_path, format = nil)
+ return original_template_path if original_template_path.respond_to?(:render)
+ template_path = original_template_path.sub(/^\//, '')
- def find_template(path, *formats)
- if formats && formats.first == :all
- formats = Mime::EXTENSION_LOOKUP.values.map(&:to_sym)
- end
- formats.each do |format|
- if template = self["#{path}.#{format}"]
+ each do |load_path|
+ if format && (template = load_path["#{template_path}.#{format}"])
+ return template
+ elsif template = load_path[template_path]
return template
end
end
- if template = self[path]
- return template
- end
- nil
+
+ Template.new(original_template_path, self)
end
end
end
diff --git a/actionpack/lib/action_view/renderable.rb b/actionpack/lib/action_view/renderable.rb
index 7c0e62f1d7..d8e72f1179 100644
--- a/actionpack/lib/action_view/renderable.rb
+++ b/actionpack/lib/action_view/renderable.rb
@@ -4,10 +4,6 @@ module ActionView
module Renderable #:nodoc:
extend ActiveSupport::Memoizable
- def self.included(base)
- @@mutex = Mutex.new
- end
-
def filename
'compiled-template'
end
@@ -22,6 +18,11 @@ module ActionView
end
memoize :compiled_source
+ def method_name_without_locals
+ ['_run', extension, method_segment].compact.join('_')
+ end
+ memoize :method_name_without_locals
+
def render(view, local_assigns = {})
compile(local_assigns)
@@ -46,9 +47,12 @@ module ActionView
def method_name(local_assigns)
if local_assigns && local_assigns.any?
- local_assigns_keys = "locals_#{local_assigns.keys.map { |k| k.to_s }.sort.join('_')}"
+ method_name = method_name_without_locals.dup
+ method_name << "_locals_#{local_assigns.keys.map { |k| k.to_s }.sort.join('_')}"
+ else
+ method_name = method_name_without_locals
end
- ['_run', extension, method_segment, local_assigns_keys].compact.join('_').to_sym
+ method_name.to_sym
end
private
@@ -56,10 +60,8 @@ module ActionView
def compile(local_assigns)
render_symbol = method_name(local_assigns)
- @@mutex.synchronize do
- if recompile?(render_symbol)
- compile!(render_symbol, local_assigns)
- end
+ if recompile?(render_symbol)
+ compile!(render_symbol, local_assigns)
end
end
diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb
index 93748638c3..5b384d0e4d 100644
--- a/actionpack/lib/action_view/template.rb
+++ b/actionpack/lib/action_view/template.rb
@@ -4,6 +4,17 @@ module ActionView #:nodoc:
extend ActiveSupport::Memoizable
include Renderable
+ # Templates that are exempt from layouts
+ @@exempt_from_layout = Set.new([/\.rjs$/])
+
+ # Don't render layouts for templates with the given extensions.
+ def self.exempt_from_layout(*extensions)
+ regexps = extensions.collect do |extension|
+ extension.is_a?(Regexp) ? extension : /\.#{Regexp.escape(extension.to_s)}$/
+ end
+ @@exempt_from_layout.merge(regexps)
+ end
+
attr_accessor :filename, :load_path, :base_path, :name, :format, :extension
delegate :to_s, :to => :path
@@ -17,6 +28,18 @@ module ActionView #:nodoc:
extend RenderablePartial if @name =~ /^_/
end
+ def accessible_paths
+ paths = []
+ paths << path
+ paths << path_without_extension
+ if multipart?
+ formats = format.split(".")
+ paths << "#{path_without_format_and_extension}.#{formats.first}"
+ paths << "#{path_without_format_and_extension}.#{formats.second}"
+ end
+ paths
+ end
+
def format_and_extension
(extensions = [format, extension].compact.join(".")).blank? ? nil : extensions
end
@@ -57,6 +80,10 @@ module ActionView #:nodoc:
end
memoize :relative_path
+ def exempt_from_layout?
+ @@exempt_from_layout.any? { |exempted| path =~ exempted }
+ end
+
def mtime
File.mtime(filename)
end
@@ -94,6 +121,7 @@ module ActionView #:nodoc:
def load!
@loaded = true
+ compile({})
freeze
end