Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

388 lines (336 sloc) 13.043 kb
module Serve #:nodoc:
# Many of the methods here have been extracted in some form from Rails
module EscapeHelpers
HTML_ESCAPE = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;' }
JSON_ESCAPE = { '&' => '\u0026', '>' => '\u003E', '<' => '\u003C' }
# A utility method for escaping HTML tag characters.
# This method is also aliased as <tt>h</tt>.
#
# In your ERb templates, use this method to escape any unsafe content. For example:
# <%=h @person.name %>
#
# ==== Example:
# puts html_escape("is a > 0 & a < 10?")
# # => is a &gt; 0 &amp; a &lt; 10?
def html_escape(s)
s.to_s.gsub(/[&"><]/) { |special| HTML_ESCAPE[special] }
end
alias h html_escape
# A utility method for escaping HTML entities in JSON strings.
# This method is also aliased as <tt>j</tt>.
#
# In your ERb templates, use this method to escape any HTML entities:
# <%=j @person.to_json %>
#
# ==== Example:
# puts json_escape("is a > 0 & a < 10?")
# # => is a \u003E 0 \u0026 a \u003C 10?
def json_escape(s)
s.to_s.gsub(/[&"><]/) { |special| JSON_ESCAPE[special] }
end
alias j json_escape
end
module ContentHelpers
def content_for(symbol, content = nil, &block)
content = capture(&block) if block_given?
set_content_for(symbol, content) if content
get_content_for(symbol) unless content
end
def content_for?(symbol)
!(get_content_for(symbol)).nil?
end
def get_content_for(symbol = :content)
if symbol.to_s.intern == :content
@content
else
instance_variable_get("@content_for_#{symbol}")
end
end
def set_content_for(symbol, value)
instance_variable_set("@content_for_#{symbol}", value)
end
def capture_erb(&block)
buffer = ""
old_buffer, @_out_buf = @_out_buf, buffer
yield
buffer
ensure
@_out_buf = old_buffer
end
alias capture_rhtml capture_erb
alias capture_erubis capture_erb
def capture(&block)
capture_method = "capture_#{script_extension}"
if respond_to? capture_method
send capture_method, &block
else
raise "Capture not supported for `#{script_extension}' template (#{engine_name})"
end
end
private
def engine_name
Tilt[script_extension].to_s
end
def script_extension
parser.script_extension
end
end
module FlashHelpers
def flash
@flash ||= {}
end
end
module ParamHelpers
# Key based access to query parameters. Keys can be strings or symbols.
def params
@params ||= request.params
end
# Extract the value for a bool param. Handy for rendering templates in
# different states.
def boolean_param(key, default = false)
key = key.to_s.intern
value = params[key]
return default if value.blank?
case value.strip.downcase
when 'true', '1' then true
when 'false', '0' then false
else raise 'Invalid value'
end
end
end
module RenderHelpers
def render(partial, options={})
if partial.is_a?(Hash)
options = options.merge(partial)
partial = options.delete(:partial)
end
template = options.delete(:template)
case
when partial
render_partial(partial, options)
when template
render_template(template)
else
raise "render options not supported #{options.inspect}"
end
end
def render_partial(partial, options={})
render_template(partial, options.merge(:partial => true))
end
def render_template(template, options={})
path = parser.template_path
if template =~ %r{^/}
template = template[1..-1]
path = @root_path
end
filename = template_filename(path, template, :partial => options[:partial])
if filename && File.file?(filename)
parser.parse(File.read(filename), File.extname(filename).split(".").last, options[:locals])
else
raise "File does not exist #{filename.inspect}"
end
end
private
def template_filename(path, template, options)
template_path = File.dirname(template)
template_file = File.basename(template)
template_file = "_" + template_file if options[:partial]
route = Serve::Router.resolve(path, File.join(template_path, template_file))
(route && File.join(path, route))
end
def extname(filename)
/(\.[a-z]+\.[a-z]+)$/.match(filename)
$1 || File.extname(filename) || ''
end
end
module TagHelpers
def content_tag(name, content, html_options={})
%{<#{name}#{html_attributes(html_options)}>#{content}</#{name}>}
end
def tag(name, html_options={})
%{<#{name}#{html_attributes(html_options)} />}
end
def image_tag(src, html_options = {})
tag(:img, html_options.merge({:src=>src}))
end
def image(name, options = {})
image_tag(ensure_path(ensure_extension(name, 'png'), 'images'), options)
end
def javascript_tag(content = nil, html_options = {})
content_tag(:script, javascript_cdata_section(content), html_options.merge(:type => "text/javascript"))
end
def link_to(name, href, html_options = {})
html_options = html_options.stringify_keys
confirm = html_options.delete("confirm")
onclick = "if (!confirm('#{html_escape(confirm)}')) return false;" if confirm
content_tag(:a, name, html_options.merge(:href => href, :onclick=>onclick))
end
def link_to_function(name, *args, &block)
html_options = extract_options!(args)
function = args[0] || ''
onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function}; return false;"
href = html_options[:href] || '#'
content_tag(:a, name, html_options.merge(:href => href, :onclick => onclick))
end
def mail_to(email_address, name = nil, html_options = {})
html_options = html_options.stringify_keys
encode = html_options.delete("encode").to_s
cc, bcc, subject, body = html_options.delete("cc"), html_options.delete("bcc"), html_options.delete("subject"), html_options.delete("body")
string = ''
extras = ''
extras << "cc=#{CGI.escape(cc).gsub("+", "%20")}&" unless cc.nil?
extras << "bcc=#{CGI.escape(bcc).gsub("+", "%20")}&" unless bcc.nil?
extras << "body=#{CGI.escape(body).gsub("+", "%20")}&" unless body.nil?
extras << "subject=#{CGI.escape(subject).gsub("+", "%20")}&" unless subject.nil?
extras = "?" << extras.gsub!(/&?$/,"") unless extras.empty?
email_address = email_address.to_s
email_address_obfuscated = email_address.dup
email_address_obfuscated.gsub!(/@/, html_options.delete("replace_at")) if html_options.has_key?("replace_at")
email_address_obfuscated.gsub!(/\./, html_options.delete("replace_dot")) if html_options.has_key?("replace_dot")
if encode == "javascript"
"document.write('#{content_tag("a", name || email_address_obfuscated, html_options.merge({ "href" => "mailto:"+email_address+extras }))}');".each_byte do |c|
string << sprintf("%%%x", c)
end
"<script type=\"#{Mime::JS}\">eval(decodeURIComponent('#{string}'))</script>"
elsif encode == "hex"
email_address_encoded = ''
email_address_obfuscated.each_byte do |c|
email_address_encoded << sprintf("&#%d;", c)
end
protocol = 'mailto:'
protocol.each_byte { |c| string << sprintf("&#%d;", c) }
email_address.each_byte do |c|
char = c.chr
string << (char =~ /\w/ ? sprintf("%%%x", c) : char)
end
content_tag "a", name || email_address_encoded, html_options.merge({ "href" => "#{string}#{extras}" })
else
content_tag "a", name || email_address_obfuscated, html_options.merge({ "href" => "mailto:#{email_address}#{extras}" })
end
end
# Generates JavaScript script tags for the sources given as arguments.
#
# If the .js extension is not given, it will be appended to the source.
#
# Examples
# javascript_include_tag 'application' # =>
# <script src="/javascripts/application.js" type="text/javascript" />
#
# javascript_include_tag 'https://cdn/jquery.js' # =>
# <script src="https://cdn/jquery.js" type="text/javascript" />
#
# javascript_include_tag 'application', 'books' # =>
# <script src="/javascripts/application.js" type="text/javascript" />
# <script src="/javascripts/books.js" type="text/javascript" />
#
def javascript_include_tag(*sources)
options = extract_options!(sources)
sources.map do |source|
content_tag('script', '', {
'type' => 'text/javascript',
'src' => ensure_path(ensure_extension(source, 'js'), 'javascripts')
}.merge(options))
end.join("\n")
end
# Generates stylesheet link tags for the sources given as arguments.
#
# If the .css extension is not given, it will be appended to the source.
#
# Examples
# stylesheet_link_tag 'screen' # =>
# <link href="/stylesheets/screen.css" media="screen" rel="stylesheet" type="text/css" />
#
# stylesheet_link_tag 'print', :media => 'print' # =>
# <link href="/stylesheets/print.css" media="print" rel="stylesheet" type="text/css" />
#
# stylesheet_link_tag 'application', 'books', 'authors' # =>
# <link href="/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />
# <link href="/stylesheets/books.css" media="screen" rel="stylesheet" type="text/css" />
# <link href="/stylesheets/authors.css" media="screen" rel="stylesheet" type="text/css" />
#
def stylesheet_link_tag(*sources)
options = extract_options!(sources)
sources.map do |source|
tag('link', {
'rel' => 'stylesheet',
'type' => 'text/css',
'media' => 'screen',
'href' => ensure_path(ensure_extension(source, 'css'), 'stylesheets')
}.merge(options))
end.join("\n")
end
private
def cdata_section(content)
"<![CDATA[#{content}]]>"
end
def javascript_cdata_section(content) #:nodoc:
"\n//#{cdata_section("\n#{content}\n//")}\n"
end
def html_attributes(options)
unless options.blank?
attrs = []
options.each_pair do |key, value|
if value == true
attrs << %(#{key}="#{key}") if value
else
attrs << %(#{key}="#{value}") unless value.nil?
end
end
" #{attrs.sort * ' '}" unless attrs.empty?
end
end
# Ensures a proper extension is appended to the filename.
#
# If a URI with the http or https scheme name is given, it is assumed
# to be absolute and will not be altered.
#
# Examples
# ensure_extension('screen', 'css') => 'screen.css'
# ensure_extension('screen.css', 'css') => 'screen.css'
# ensure_extension('jquery.min', 'js') => 'jquery.min.js'
# ensure_extension('https://cdn/jquery', 'js') => 'https://cdn/jquery'
#
def ensure_extension(source, extension)
if source =~ /^https?:/ || source.end_with?(".#{extension}")
return source
end
"#{source}.#{extension}"
end
# Ensures the proper path to the given source.
#
# If the source begins at the root of the public directory or is a URI
# with the http or https scheme name, it is assumed to be absolute and
# will not be altered.
#
# Examples
# ensure_path('screen.css', 'stylesheets') => '/stylesheets/screen.css'
# ensure_path('/screen.css', 'stylesheets') => '/screen.css'
# ensure_path('http://cdn/jquery.js', 'javascripts') => 'http://cdn/jquery.js'
#
def ensure_path(source, path)
if source =~ /^(\/|https?)/
return source
end
File.join('', path, source)
end
# Returns a hash of options if they exist at the end of an array.
#
# This is useful when working with splats.
#
# Examples
# extract_options!([1, 2, { :name => 'sunny' }]) => { :name => 'sunny' }
# extract_options!([1, 2, 3]) => {}
#
def extract_options!(array)
array.last.instance_of?(Hash) ? array.pop : {}
end
end
module ViewHelpers #:nodoc:
include EscapeHelpers
include ContentHelpers
include FlashHelpers
include ParamHelpers
include RenderHelpers
include TagHelpers
end
end
Jump to Line
Something went wrong with that request. Please try again.