Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 289 lines (246 sloc) 9.063 kb
974ed5a @jlong Added additional view helpers for escaping content, access to params …
authored
1 module Serve #:nodoc:
b37924b @jlong integrated Tilt; appears to be working
authored
2 # Many of the methods here have been extracted in some form from Rails
974ed5a @jlong Added additional view helpers for escaping content, access to params …
authored
3
4 module EscapeHelpers
5 HTML_ESCAPE = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;' }
6 JSON_ESCAPE = { '&' => '\u0026', '>' => '\u003E', '<' => '\u003C' }
7
8 # A utility method for escaping HTML tag characters.
9 # This method is also aliased as <tt>h</tt>.
10 #
11 # In your ERb templates, use this method to escape any unsafe content. For example:
12 # <%=h @person.name %>
13 #
14 # ==== Example:
15 # puts html_escape("is a > 0 & a < 10?")
16 # # => is a &gt; 0 &amp; a &lt; 10?
17 def html_escape(s)
18 s.to_s.gsub(/[&"><]/) { |special| HTML_ESCAPE[special] }
19 end
20 alias h html_escape
21
22 # A utility method for escaping HTML entities in JSON strings.
23 # This method is also aliased as <tt>j</tt>.
24 #
25 # In your ERb templates, use this method to escape any HTML entities:
26 # <%=j @person.to_json %>
27 #
28 # ==== Example:
29 # puts json_escape("is a > 0 & a < 10?")
30 # # => is a \u003E 0 \u0026 a \u003C 10?
31 def json_escape(s)
32 s.to_s.gsub(/[&"><]/) { |special| JSON_ESCAPE[special] }
33 end
34 alias j json_escape
35 end
36
37 module ContentHelpers
38 def content_for(symbol, &block)
e26df67 @jlong reworked capture -- still does not work with slim
authored
39 set_content_for(symbol, capture(&block))
974ed5a @jlong Added additional view helpers for escaping content, access to params …
authored
40 end
41
42 def content_for?(symbol)
43 !(get_content_for(symbol)).nil?
44 end
45
46 def get_content_for(symbol = :content)
47 if symbol.to_s.intern == :content
48 @content
49 else
50 instance_variable_get("@content_for_#{symbol}")
51 end
52 end
53
54 def set_content_for(symbol, value)
55 instance_variable_set("@content_for_#{symbol}", value)
56 end
e26df67 @jlong reworked capture -- still does not work with slim
authored
57
58 def capture_erb(&block)
59 buffer = ""
1985abe @jlong get capture working for ERB again
authored
60 old_buffer, @_out_buf = @_out_buf, buffer
e26df67 @jlong reworked capture -- still does not work with slim
authored
61 yield
62 buffer
63 ensure
1985abe @jlong get capture working for ERB again
authored
64 @_out_buf = old_buffer
e26df67 @jlong reworked capture -- still does not work with slim
authored
65 end
66 alias capture_rhtml capture_erb
ddffc20 @jlong Added support for erubis templates
authored
67 alias capture_erubis capture_erb
e26df67 @jlong reworked capture -- still does not work with slim
authored
68
69 def capture(&block)
70 capture_method = "capture_#{script_extension}"
71 if respond_to? capture_method
72 send capture_method, &block
73 else
74 raise "Capture not supported for `#{script_extension}' template (#{engine_name})"
75 end
76 end
77
78 private
79
80 def engine_name
81 Tilt[script_extension].to_s
82 end
83
84 def script_extension
85 parser.script_extension
86 end
974ed5a @jlong Added additional view helpers for escaping content, access to params …
authored
87 end
88
89 module FlashHelpers
90 def flash
91 @flash ||= {}
92 end
93 end
94
95 module ParamHelpers
96
97 # Key based access to query parameters. Keys can be strings or symbols.
98 def params
99 @params ||= HashWithIndifferentAccess.new(request.query)
100 end
101
102 # Extract the value for a bool param. Handy for rendering templates in
103 # different states.
104 def boolean_param(key, default = false)
105 key = key.to_s.intern
106 value = params[key]
107 return default if value.blank?
108 case value.strip.downcase
71d9d55 @jlong Added support for Ruby 1.9
authored
109 when 'true', '1' then true
110 when 'false', '0' then false
974ed5a @jlong Added additional view helpers for escaping content, access to params …
authored
111 else raise 'Invalid value'
112 end
113 end
114 end
115
116 module RenderHelpers
16675c1 @jlong Changed render helper to support passing the name of the partial as t…
authored
117 def render(partial, options={})
118 if partial.is_a?(Hash)
119 options = options.merge(partial)
120 partial = options.delete(:partial)
121 end
974ed5a @jlong Added additional view helpers for escaping content, access to params …
authored
122 template = options.delete(:template)
123 case
124 when partial
50a604a @jlong Added support for locals in partials. Closes #15. [heikki]
authored
125 render_partial(partial, options)
974ed5a @jlong Added additional view helpers for escaping content, access to params …
authored
126 when template
127 render_template(template)
128 else
129 raise "render options not supported #{options.inspect}"
130 end
131 end
132
50a604a @jlong Added support for locals in partials. Closes #15. [heikki]
authored
133 def render_partial(partial, options={})
134 render_template(partial, options.merge(:partial => true))
974ed5a @jlong Added additional view helpers for escaping content, access to params …
authored
135 end
136
137 def render_template(template, options={})
138 path = File.dirname(parser.script_filename)
139 if template =~ %r{^/}
140 template = template[1..-1]
141 path = @root_path
142 end
143 filename = template_filename(File.join(path, template), :partial => options.delete(:partial))
144 if File.file?(filename)
50a604a @jlong Added support for locals in partials. Closes #15. [heikki]
authored
145 parser.parse_file(filename, options[:locals])
974ed5a @jlong Added additional view helpers for escaping content, access to params …
authored
146 else
147 raise "File does not exist #{filename.inspect}"
148 end
149 end
150
151 private
152
153 def template_filename(name, options)
154 path = File.dirname(name)
155 template = File.basename(name)
156 template = "_" + template if options.delete(:partial)
157 template += extname(parser.script_filename) unless name =~ /\.[a-z]{3,4}$/
158 File.join(path, template)
159 end
160
161 def extname(filename)
162 /(\.[a-z]{3,4}\.[a-z]{3,4})$/.match(filename)
163 $1 || File.extname(filename) || ''
164 end
165 end
166
167 module TagHelpers
168 def content_tag(name, content, html_options={})
169 %{<#{name}#{html_attributes(html_options)}>#{content}</#{name}>}
170 end
171
172 def tag(name, html_options={})
173 %{<#{name}#{html_attributes(html_options)} />}
174 end
175
176 def image_tag(src, html_options = {})
177 tag(:img, html_options.merge({:src=>src}))
178 end
179
180 def image(name, options = {})
ce717ee @jlong fixed image helper; version bump
authored
181 image_tag(append_image_extension("/images/#{name}"), options)
974ed5a @jlong Added additional view helpers for escaping content, access to params …
authored
182 end
183
184 def javascript_tag(content = nil, html_options = {})
185 content_tag(:script, javascript_cdata_section(content), html_options.merge(:type => "text/javascript"))
186 end
187
188 def link_to(name, href, html_options = {})
189 html_options = html_options.stringify_keys
190 confirm = html_options.delete("confirm")
191 onclick = "if (!confirm('#{html_escape(confirm)}')) return false;" if confirm
192 content_tag(:a, name, html_options.merge(:href => href, :onclick=>onclick))
193 end
194
195 def link_to_function(name, *args, &block)
196 html_options = {}
197 html_options = args.pop if args.last.is_a? Hash
198 function = args[0] || ''
199 onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function}; return false;"
200 href = html_options[:href] || '#'
201 content_tag(:a, name, html_options.merge(:href => href, :onclick => onclick))
202 end
203
204 def mail_to(email_address, name = nil, html_options = {})
205 html_options = html_options.stringify_keys
206 encode = html_options.delete("encode").to_s
207 cc, bcc, subject, body = html_options.delete("cc"), html_options.delete("bcc"), html_options.delete("subject"), html_options.delete("body")
208
209 string = ''
210 extras = ''
211 extras << "cc=#{CGI.escape(cc).gsub("+", "%20")}&" unless cc.nil?
212 extras << "bcc=#{CGI.escape(bcc).gsub("+", "%20")}&" unless bcc.nil?
213 extras << "body=#{CGI.escape(body).gsub("+", "%20")}&" unless body.nil?
214 extras << "subject=#{CGI.escape(subject).gsub("+", "%20")}&" unless subject.nil?
215 extras = "?" << extras.gsub!(/&?$/,"") unless extras.empty?
216
217 email_address = email_address.to_s
218
219 email_address_obfuscated = email_address.dup
220 email_address_obfuscated.gsub!(/@/, html_options.delete("replace_at")) if html_options.has_key?("replace_at")
221 email_address_obfuscated.gsub!(/\./, html_options.delete("replace_dot")) if html_options.has_key?("replace_dot")
222
223 if encode == "javascript"
224 "document.write('#{content_tag("a", name || email_address_obfuscated, html_options.merge({ "href" => "mailto:"+email_address+extras }))}');".each_byte do |c|
225 string << sprintf("%%%x", c)
226 end
227 "<script type=\"#{Mime::JS}\">eval(decodeURIComponent('#{string}'))</script>"
228 elsif encode == "hex"
229 email_address_encoded = ''
230 email_address_obfuscated.each_byte do |c|
231 email_address_encoded << sprintf("&#%d;", c)
232 end
233
234 protocol = 'mailto:'
235 protocol.each_byte { |c| string << sprintf("&#%d;", c) }
236
237 email_address.each_byte do |c|
238 char = c.chr
239 string << (char =~ /\w/ ? sprintf("%%%x", c) : char)
240 end
241 content_tag "a", name || email_address_encoded, html_options.merge({ "href" => "#{string}#{extras}" })
242 else
243 content_tag "a", name || email_address_obfuscated, html_options.merge({ "href" => "mailto:#{email_address}#{extras}" })
244 end
245 end
246
247 private
248
249 def cdata_section(content)
250 "<![CDATA[#{content}]]>"
251 end
252
253 def javascript_cdata_section(content) #:nodoc:
254 "\n//#{cdata_section("\n#{content}\n//")}\n"
255 end
256
257 def html_attributes(options)
258 unless options.blank?
259 attrs = []
260 options.each_pair do |key, value|
261 if value == true
262 attrs << %(#{key}="#{key}") if value
263 else
264 attrs << %(#{key}="#{value}") unless value.nil?
265 end
266 end
267 " #{attrs.sort * ' '}" unless attrs.empty?
268 end
269 end
270
271 def append_image_extension(name)
272 unless name =~ /\.(.*?)$/
273 name + '.png'
274 else
275 name
276 end
277 end
278 end
279
280 module ViewHelpers #:nodoc:
281 include EscapeHelpers
282 include ContentHelpers
283 include FlashHelpers
284 include ParamHelpers
285 include RenderHelpers
286 include TagHelpers
287 end
ce717ee @jlong fixed image helper; version bump
authored
288 end
Something went wrong with that request. Please try again.