padrino-helpers 0.13.3 → 0.13.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/padrino-helpers/asset_tag_helpers.rb +7 -7
- data/lib/padrino-helpers/form_builder/abstract_form_builder.rb +6 -6
- data/lib/padrino-helpers/form_helpers.rb +3 -3
- data/lib/padrino-helpers/form_helpers/errors.rb +8 -8
- data/lib/padrino-helpers/form_helpers/options.rb +1 -1
- data/lib/padrino-helpers/format_helpers.rb +1 -1
- data/lib/padrino-helpers/number_helpers.rb +5 -8
- data/lib/padrino-helpers/output_helpers.rb +4 -4
- data/lib/padrino-helpers/output_helpers/abstract_handler.rb +1 -1
- data/lib/padrino-helpers/render_helpers.rb +3 -3
- data/lib/padrino-helpers/tag_helpers.rb +1 -1
- data/lib/padrino/core_ext/output_safety.rb +25 -0
- data/lib/padrino/rendering.rb +6 -5
- data/lib/padrino/rendering/erb_template.rb +1 -1
- data/lib/padrino/rendering/erubis_template.rb +2 -2
- data/lib/padrino/rendering/slim_template.rb +17 -1
- data/lib/padrino/safe_buffer.rb +118 -0
- data/test/helper.rb +2 -2
- data/test/test_format_helpers.rb +5 -5
- data/test/test_render_helpers.rb +10 -0
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5dd540d3a9472d8c134bab1741faf3f69ae62166
|
4
|
+
data.tar.gz: 036a523946eefb56ec7892ead4e6df2c5f200d87
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 734ebfd2d7817d8feb9221f9037df2da53923552cc961b7a6a60573539410dab665fbcc99f40296492f8cca611147c0aef6d64b533ba27d93f974f34c0e378b8
|
7
|
+
data.tar.gz: f8b6b1a10621c16c53786bc20b3494508f07e160bf94b788020a55e407ac443ebcb779e33c7282d7a1b47238e8b9f111b36c306eb1bbc8cd04d3250bfd1d5b1c
|
@@ -32,9 +32,9 @@ module Padrino
|
|
32
32
|
def flash_tag(*args)
|
33
33
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
34
34
|
bootstrap = options.delete(:bootstrap) if options[:bootstrap]
|
35
|
-
args.inject(
|
36
|
-
|
37
|
-
|
35
|
+
args.inject(SafeBuffer.new) do |html,kind|
|
36
|
+
next html unless flash[kind]
|
37
|
+
flash_text = SafeBuffer.new << flash[kind]
|
38
38
|
flash_text << content_tag(:button, '×'.html_safe, {:type => :button, :class => :close, :'data-dismiss' => :alert}) if bootstrap
|
39
39
|
html << content_tag(:div, flash_text, { :class => kind }.update(options))
|
40
40
|
end
|
@@ -243,8 +243,8 @@ module Padrino
|
|
243
243
|
options = {
|
244
244
|
:rel => 'stylesheet',
|
245
245
|
:type => 'text/css'
|
246
|
-
}.update(sources.last.is_a?(Hash) ? sources.pop
|
247
|
-
sources.flatten.inject(
|
246
|
+
}.update(sources.last.is_a?(Hash) ? Utils.symbolize_keys(sources.pop) : {})
|
247
|
+
sources.flatten.inject(SafeBuffer.new) do |all,source|
|
248
248
|
all << tag(:link, { :href => asset_path(:css, source) }.update(options))
|
249
249
|
end
|
250
250
|
end
|
@@ -266,8 +266,8 @@ module Padrino
|
|
266
266
|
def javascript_include_tag(*sources)
|
267
267
|
options = {
|
268
268
|
:type => 'text/javascript'
|
269
|
-
}.update(sources.last.is_a?(Hash) ? sources.pop
|
270
|
-
sources.flatten.inject(
|
269
|
+
}.update(sources.last.is_a?(Hash) ? Utils.symbolize_keys(sources.pop) : {})
|
270
|
+
sources.flatten.inject(SafeBuffer.new) do |all,source|
|
271
271
|
all << content_tag(:script, nil, { :src => asset_path(:js, source) }.update(options))
|
272
272
|
end
|
273
273
|
end
|
@@ -155,7 +155,7 @@ module Padrino
|
|
155
155
|
include_index = default_collection.respond_to?(:each)
|
156
156
|
|
157
157
|
nested_options = { :parent => self, :association => child_association }
|
158
|
-
Array(collection).each_with_index.inject(
|
158
|
+
Array(collection).each_with_index.inject(SafeBuffer.new) do |all,(child_instance,index)|
|
159
159
|
nested_options[:index] = options[:index] || (include_index ? index : nil)
|
160
160
|
all << @template.fields_for(child_instance, { :nested => nested_options, :builder => self.class }, &block) << "\n"
|
161
161
|
end
|
@@ -196,7 +196,7 @@ module Padrino
|
|
196
196
|
# field_name(:street) => "user[addresses_attributes][0][street]"
|
197
197
|
def field_name(field=nil)
|
198
198
|
result = field_name_fragment
|
199
|
-
result << "[#{field}]"
|
199
|
+
result << "[#{field}]" if field
|
200
200
|
result
|
201
201
|
end
|
202
202
|
|
@@ -209,8 +209,8 @@ module Padrino
|
|
209
209
|
def field_id(field=nil, value=nil)
|
210
210
|
result = (namespace && !is_nested) ? "#{namespace}_" : ''
|
211
211
|
result << field_id_fragment
|
212
|
-
result << "_#{field}"
|
213
|
-
result << "_#{value}"
|
212
|
+
result << "_#{field}" if field
|
213
|
+
result << "_#{value}" if value
|
214
214
|
result
|
215
215
|
end
|
216
216
|
|
@@ -242,7 +242,7 @@ module Padrino
|
|
242
242
|
options = { :id => field_id(field), :selected => field_value(field) }.update(options)
|
243
243
|
options.update(error_class(field)){ |_,*values| values.compact.join(' ') }
|
244
244
|
selected_values = resolve_checked_values(field, options)
|
245
|
-
variants_for_group(options).inject(
|
245
|
+
variants_for_group(options).inject(SafeBuffer.new) do |html, (caption,value)|
|
246
246
|
variant_id = "#{options[:id]}_#{value}"
|
247
247
|
attributes = { :value => value, :id => variant_id, :checked => selected_values.include?(value) }
|
248
248
|
caption = yield(attributes) << ' ' << caption
|
@@ -308,7 +308,7 @@ module Padrino
|
|
308
308
|
|
309
309
|
def error_class(field)
|
310
310
|
error = @object.errors[field] if @object.respond_to?(:errors)
|
311
|
-
error.
|
311
|
+
error.nil? || error.empty? ? {} : { :class => 'invalid' }
|
312
312
|
end
|
313
313
|
|
314
314
|
def default_options(field, options, defaults={})
|
@@ -121,7 +121,7 @@ module Padrino
|
|
121
121
|
# hidden_form_method_field('delete')
|
122
122
|
#
|
123
123
|
def hidden_form_method_field(desired_method)
|
124
|
-
return
|
124
|
+
return SafeBuffer.new if desired_method.nil? || desired_method.to_s =~ /get|post/i
|
125
125
|
hidden_field_tag(:_method, :value => desired_method)
|
126
126
|
end
|
127
127
|
|
@@ -144,7 +144,7 @@ module Padrino
|
|
144
144
|
#
|
145
145
|
def field_set_tag(*args, &block)
|
146
146
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
147
|
-
legend_html = args.empty? ?
|
147
|
+
legend_html = args.empty? ? SafeBuffer.new : content_tag(:legend, args.first)
|
148
148
|
concat_content content_tag(:fieldset, legend_html << capture_html(&block), options)
|
149
149
|
end
|
150
150
|
|
@@ -168,7 +168,7 @@ module Padrino
|
|
168
168
|
#
|
169
169
|
def label_tag(name, options={}, &block)
|
170
170
|
options = { :caption => "#{name.to_s.humanize}: ", :for => name }.update(options)
|
171
|
-
caption_text =
|
171
|
+
caption_text = SafeBuffer.new << options.delete(:caption)
|
172
172
|
caption_text << "<span class='required'>*</span> ".html_safe if options.delete(:required)
|
173
173
|
|
174
174
|
if block_given?
|
@@ -37,10 +37,10 @@ module Padrino
|
|
37
37
|
# error_messages_for :user
|
38
38
|
#
|
39
39
|
def error_messages_for(*objects)
|
40
|
-
options = objects.last.is_a?(Hash) ? objects.pop
|
40
|
+
options = objects.last.is_a?(Hash) ? Utils.symbolize_keys(objects.pop) : {}
|
41
41
|
objects = objects.map{ |obj| resolve_object(obj) }.compact
|
42
42
|
count = objects.inject(0){ |sum, object| sum + object.errors.count }
|
43
|
-
return
|
43
|
+
return SafeBuffer.new if count.zero?
|
44
44
|
|
45
45
|
content_tag(:div, error_contents(objects, count, options), error_html_attributes(options))
|
46
46
|
end
|
@@ -78,7 +78,7 @@ module Padrino
|
|
78
78
|
# @api public
|
79
79
|
def error_message_on(object, field, options={})
|
80
80
|
error = Array(resolve_object(object).errors[field]).first
|
81
|
-
return
|
81
|
+
return SafeBuffer.new unless error
|
82
82
|
options = { :tag => :span, :class => :error }.update(options)
|
83
83
|
tag = options.delete(:tag)
|
84
84
|
error = [options.delete(:prepend), error, options.delete(:append)].compact.join(" ")
|
@@ -90,7 +90,7 @@ module Padrino
|
|
90
90
|
def error_contents(objects, count, options)
|
91
91
|
object_name = options[:object_name] || objects.first.class.to_s.underscore.gsub(/\//, ' ')
|
92
92
|
|
93
|
-
contents =
|
93
|
+
contents = SafeBuffer.new
|
94
94
|
contents << error_header_tag(options, object_name, count)
|
95
95
|
contents << error_body_tag(options)
|
96
96
|
contents << error_list_tag(objects, object_name)
|
@@ -98,7 +98,7 @@ module Padrino
|
|
98
98
|
|
99
99
|
def error_list_tag(objects, object_name)
|
100
100
|
errors = objects.inject({}){ |all,object| all.update(object.errors) }
|
101
|
-
error_messages = errors.inject(
|
101
|
+
error_messages = errors.inject(SafeBuffer.new) do |all, (field, message)|
|
102
102
|
field_name = I18n.t(field, :default => field.to_s.humanize, :scope => [:models, object_name, :attributes])
|
103
103
|
all << content_tag(:li, "#{field_name} #{message}")
|
104
104
|
end
|
@@ -110,19 +110,19 @@ module Padrino
|
|
110
110
|
model_name = I18n.t(:name, :default => object_name.humanize, :scope => [:models, object_name], :count => 1)
|
111
111
|
I18n.t :header, :count => count, :model => model_name, :locale => options[:locale], :scope => [:models, :errors, :template]
|
112
112
|
end
|
113
|
-
content_tag(options[:header_tag] || :h2, header_message)
|
113
|
+
content_tag(options[:header_tag] || :h2, header_message) unless header_message.empty?
|
114
114
|
end
|
115
115
|
|
116
116
|
def error_body_tag(options)
|
117
117
|
body_message = options[:message] || I18n.t(:body, :locale => options[:locale], :scope => [:models, :errors, :template])
|
118
|
-
content_tag(:p, body_message)
|
118
|
+
content_tag(:p, body_message) unless body_message.empty?
|
119
119
|
end
|
120
120
|
|
121
121
|
def error_html_attributes(options)
|
122
122
|
[:id, :class, :style].each_with_object({}) do |key,all|
|
123
123
|
if options.include?(key)
|
124
124
|
value = options[key]
|
125
|
-
all[key] = value
|
125
|
+
all[key] = value if value
|
126
126
|
else
|
127
127
|
all[key] = 'field-errors' unless key == :style
|
128
128
|
end
|
@@ -55,7 +55,7 @@ module Padrino
|
|
55
55
|
# Returns the options tags for a select based on the given option items.
|
56
56
|
#
|
57
57
|
def options_for_select(option_items, state = {})
|
58
|
-
return [] if option_items.
|
58
|
+
return [] if option_items.count == 0
|
59
59
|
option_items.map do |caption, value, attributes|
|
60
60
|
html_attributes = { :value => value || caption }.merge(attributes||{})
|
61
61
|
html_attributes[:selected] ||= option_is_selected?(html_attributes[:value], caption, state[:selected])
|
@@ -216,7 +216,7 @@ module Padrino
|
|
216
216
|
def highlight(text, words, *args)
|
217
217
|
options = { :highlighter => '<strong class="highlight">\1</strong>' }.update(args.last.is_a?(Hash) ? args.pop : {})
|
218
218
|
|
219
|
-
if text.
|
219
|
+
if text.empty? || words.empty?
|
220
220
|
text
|
221
221
|
else
|
222
222
|
match = Array(words).map { |p| Regexp.escape(p) }.join('|')
|
@@ -41,7 +41,7 @@ module Padrino
|
|
41
41
|
# # => 1234567890,50 £
|
42
42
|
#
|
43
43
|
def number_to_currency(number, options = {})
|
44
|
-
options.symbolize_keys
|
44
|
+
options = Utils.symbolize_keys(options)
|
45
45
|
|
46
46
|
defaults = I18n.translate(:'number.format', :locale => options[:locale], :raise => true) rescue {}
|
47
47
|
currency = I18n.translate(:'number.currency.format', :locale => options[:locale], :raise => true) rescue {}
|
@@ -89,7 +89,7 @@ module Padrino
|
|
89
89
|
# number_to_percentage(302.24398923423, :precision => 5) # => 302.24399%
|
90
90
|
#
|
91
91
|
def number_to_percentage(number, options = {})
|
92
|
-
options.symbolize_keys
|
92
|
+
options = Utils.symbolize_keys(options)
|
93
93
|
|
94
94
|
defaults = I18n.translate(:'number.format', :locale => options[:locale], :raise => true) rescue {}
|
95
95
|
percentage = I18n.translate(:'number.percentage.format', :locale => options[:locale], :raise => true) rescue {}
|
@@ -134,8 +134,7 @@ module Padrino
|
|
134
134
|
# # => 98 765 432,98
|
135
135
|
#
|
136
136
|
def number_with_delimiter(number, *args)
|
137
|
-
options = args.last.is_a?(Hash) ? args.pop : {}
|
138
|
-
options.symbolize_keys!
|
137
|
+
options = args.last.is_a?(Hash) ? Utils.symbolize_keys(args.pop) : {}
|
139
138
|
|
140
139
|
defaults = I18n.translate(:'number.format', :locale => options[:locale], :raise => true) rescue {}
|
141
140
|
|
@@ -178,8 +177,7 @@ module Padrino
|
|
178
177
|
# # => 1.111,23
|
179
178
|
#
|
180
179
|
def number_with_precision(number, *args)
|
181
|
-
options = args.last.is_a?(Hash) ? args.pop : {}
|
182
|
-
options.symbolize_keys!
|
180
|
+
options = args.last.is_a?(Hash) ? Utils.symbolize_keys(args.pop) : {}
|
183
181
|
|
184
182
|
defaults = I18n.translate(:'number.format', :locale => options[:locale], :raise => true) rescue {}
|
185
183
|
precision_defaults = I18n.translate(:'number.precision.format', :locale => options[:locale],
|
@@ -239,8 +237,7 @@ module Padrino
|
|
239
237
|
def number_to_human_size(number, *args)
|
240
238
|
return nil if number.nil?
|
241
239
|
|
242
|
-
options = args.last.is_a?(Hash) ? args.pop : {}
|
243
|
-
options.symbolize_keys!
|
240
|
+
options = args.last.is_a?(Hash) ? Utils.symbolize_keys(args.pop) : {}
|
244
241
|
|
245
242
|
defaults = I18n.translate(:'number.format', :locale => options[:locale], :raise => true) rescue {}
|
246
243
|
human = I18n.translate(:'number.human.format', :locale => options[:locale], :raise => true) rescue {}
|
@@ -53,9 +53,9 @@ module Padrino
|
|
53
53
|
# capture_html(object_for_block, &block) => "...html..."
|
54
54
|
#
|
55
55
|
# @example
|
56
|
-
#
|
56
|
+
# SafeBuffer.new + capture_html { "<foo>" }
|
57
57
|
# # => "<foo>"
|
58
|
-
#
|
58
|
+
# SafeBuffer.new.safe_concat(capture_html { "<foo>" })
|
59
59
|
# # => "<foo>"
|
60
60
|
#
|
61
61
|
def capture_html(*args, &block)
|
@@ -181,7 +181,7 @@ module Padrino
|
|
181
181
|
def yield_content(key, *args)
|
182
182
|
blocks = content_blocks[key.to_sym]
|
183
183
|
return nil if blocks.empty?
|
184
|
-
blocks.inject(
|
184
|
+
blocks.inject(SafeBuffer.new){ |all,content| all << capture_html(*args, &content) }
|
185
185
|
end
|
186
186
|
|
187
187
|
protected
|
@@ -213,7 +213,7 @@ module Padrino
|
|
213
213
|
#
|
214
214
|
# @param [String, Array<String>] the values to be marked safe.
|
215
215
|
#
|
216
|
-
# @return [
|
216
|
+
# @return [SafeBuffer, Array<SafeBuffer>]
|
217
217
|
def mark_safe(value)
|
218
218
|
if value.respond_to? :map!
|
219
219
|
value.map!{|v| v.html_safe if v }
|
@@ -29,7 +29,7 @@ module Padrino
|
|
29
29
|
# @handler.capture_from_template(&block) => "...html..."
|
30
30
|
#
|
31
31
|
def capture_from_template(*args, &block)
|
32
|
-
self.output_buffer, _buf_was =
|
32
|
+
self.output_buffer, _buf_was = SafeBuffer.new, self.output_buffer
|
33
33
|
raw = yield(*args)
|
34
34
|
captured = template.instance_variable_get(:@_out_buf)
|
35
35
|
self.output_buffer = _buf_was
|
@@ -34,8 +34,8 @@ module Padrino
|
|
34
34
|
options = { :locals => {}, :layout => false }.update(options)
|
35
35
|
explicit_engine = options.delete(:engine)
|
36
36
|
|
37
|
-
path, name =
|
38
|
-
template_path =
|
37
|
+
path, _, name = template.to_s.rpartition(File::SEPARATOR)
|
38
|
+
template_path = path.empty? ? :"_#{name}" : :"#{path}#{File::SEPARATOR}_#{name}"
|
39
39
|
item_name = name.partition('.').first.to_sym
|
40
40
|
|
41
41
|
items, counter = if options[:collection].respond_to?(:inject)
|
@@ -45,7 +45,7 @@ module Padrino
|
|
45
45
|
end
|
46
46
|
|
47
47
|
locals = options[:locals]
|
48
|
-
items.each_with_object(
|
48
|
+
items.each_with_object(SafeBuffer.new) do |item,html|
|
49
49
|
locals[item_name] = item if item
|
50
50
|
locals["#{item_name}_counter".to_sym] = counter += 1 if counter
|
51
51
|
content =
|
@@ -124,7 +124,7 @@ module Padrino
|
|
124
124
|
|
125
125
|
options = parse_data_options(name, options)
|
126
126
|
attributes = tag_attributes(options)
|
127
|
-
output =
|
127
|
+
output = SafeBuffer.new
|
128
128
|
output.safe_concat "<#{name}#{attributes}>"
|
129
129
|
if content.respond_to?(:each) && !content.is_a?(String)
|
130
130
|
content.each{ |item| output.concat item; output.safe_concat NEWLINE }
|
@@ -0,0 +1,25 @@
|
|
1
|
+
if defined?(ActiveSupport::SafeBuffer)
|
2
|
+
SafeBuffer = ActiveSupport::SafeBuffer
|
3
|
+
else
|
4
|
+
require 'padrino/safe_buffer'
|
5
|
+
|
6
|
+
SafeBuffer = Padrino::SafeBuffer
|
7
|
+
|
8
|
+
class String
|
9
|
+
def html_safe
|
10
|
+
SafeBuffer.new(self)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Object
|
15
|
+
def html_safe?
|
16
|
+
false
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Numeric
|
21
|
+
def html_safe?
|
22
|
+
true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/padrino/rendering.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'padrino/core_ext/output_safety'
|
1
2
|
require 'padrino-support'
|
2
3
|
require 'pathname'
|
3
4
|
|
@@ -206,7 +207,7 @@ module Padrino
|
|
206
207
|
|
207
208
|
# Cleanup the template.
|
208
209
|
@current_engine, engine_was = engine, @current_engine
|
209
|
-
@_out_buf, buf_was =
|
210
|
+
@_out_buf, buf_was = SafeBuffer.new, @_out_buf
|
210
211
|
|
211
212
|
# Pass arguments to Sinatra render method.
|
212
213
|
super(engine, data, with_layout(options), locals, &block)
|
@@ -276,7 +277,7 @@ module Padrino
|
|
276
277
|
template_candidates = glob_templates(layouts_path, template_path)
|
277
278
|
selected_template = select_template(template_candidates, *rendering_options)
|
278
279
|
|
279
|
-
fail TemplateNotFound, "Layout '#{template_path}' not found in '#{layouts_path}'" if !selected_template && layout
|
280
|
+
fail TemplateNotFound, "Layout '#{template_path}' not found in '#{layouts_path}'" if !selected_template && layout
|
280
281
|
selected_template
|
281
282
|
end
|
282
283
|
end
|
@@ -287,7 +288,7 @@ module Padrino
|
|
287
288
|
return options if layout == false
|
288
289
|
|
289
290
|
layout = @layout if !layout || layout == true
|
290
|
-
return options if settings.templates.has_key?(:layout) && layout
|
291
|
+
return options if settings.templates.has_key?(:layout) && !layout
|
291
292
|
|
292
293
|
if layout.kind_of?(String) && Pathname.new(layout).absolute?
|
293
294
|
layout_path, _, layout = layout.rpartition('/')
|
@@ -300,8 +301,8 @@ module Padrino
|
|
300
301
|
|
301
302
|
def glob_templates(views_path, template_path)
|
302
303
|
parts = []
|
303
|
-
parts << views_path if views_path
|
304
|
-
if respond_to?(:request) && request.respond_to?(:controller) && request.controller
|
304
|
+
parts << views_path if views_path
|
305
|
+
if respond_to?(:request) && request.respond_to?(:controller) && request.controller && Pathname.new(template_path).relative?
|
305
306
|
parts << "{,#{request.controller}}"
|
306
307
|
end
|
307
308
|
parts << template_path.chomp(File.extname(template_path)) + '.*'
|
@@ -16,7 +16,7 @@ module Padrino
|
|
16
16
|
def set_eoutvar(compiler, eoutvar = '_erbout')
|
17
17
|
compiler.put_cmd = "#{eoutvar}.safe_concat"
|
18
18
|
compiler.insert_cmd = "#{eoutvar}.concat"
|
19
|
-
compiler.pre_cmd = ["#{eoutvar} =
|
19
|
+
compiler.pre_cmd = ["#{eoutvar} = SafeBuffer.new"]
|
20
20
|
compiler.post_cmd = ["#{eoutvar}.force_encoding(__ENCODING__)"]
|
21
21
|
end
|
22
22
|
end
|
@@ -2,7 +2,7 @@ module Padrino
|
|
2
2
|
module Rendering
|
3
3
|
##
|
4
4
|
# SafeBufferEnhancer is an Erubis Enhancer that compiles templates that
|
5
|
-
# are fit for using
|
5
|
+
# are fit for using SafeBuffer as a Buffer.
|
6
6
|
#
|
7
7
|
# @api private
|
8
8
|
module SafeBufferEnhancer
|
@@ -53,7 +53,7 @@ module Padrino
|
|
53
53
|
def precompiled_preamble(locals)
|
54
54
|
original = super
|
55
55
|
return original unless @is_padrino_app
|
56
|
-
"__in_erb_template = true\n" << original.rpartition("\n").first << "#{@outvar} = _buf =
|
56
|
+
"__in_erb_template = true\n" << original.rpartition("\n").first << "#{@outvar} = _buf = SafeBuffer.new\n"
|
57
57
|
end
|
58
58
|
end
|
59
59
|
end
|
@@ -1,5 +1,21 @@
|
|
1
1
|
module Padrino
|
2
2
|
module Rendering
|
3
|
+
class SlimOutputBuffer < Temple::Generators::StringBuffer
|
4
|
+
define_options :buffer_class => 'SafeBuffer'
|
5
|
+
|
6
|
+
def call(exp)
|
7
|
+
[preamble, compile(exp), postamble].flatten.compact.join('; '.freeze)
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_buffer
|
11
|
+
"#{buffer} = #{options[:buffer_class]}.new"
|
12
|
+
end
|
13
|
+
|
14
|
+
def concat(str)
|
15
|
+
"#{buffer}.safe_concat((#{str}))"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
3
19
|
class SlimTemplate < Slim::Template
|
4
20
|
include SafeTemplate
|
5
21
|
|
@@ -13,7 +29,7 @@ end
|
|
13
29
|
Tilt.prefer(Padrino::Rendering::SlimTemplate, :slim)
|
14
30
|
|
15
31
|
Padrino::Rendering.engine_configurations[:slim] = {
|
16
|
-
:generator =>
|
32
|
+
:generator => Padrino::Rendering::SlimOutputBuffer,
|
17
33
|
:buffer => "@_out_buf",
|
18
34
|
:use_html_safe => true,
|
19
35
|
:disable_capture => true,
|
@@ -0,0 +1,118 @@
|
|
1
|
+
module Padrino
|
2
|
+
##
|
3
|
+
# Padrino::SafeBuffer is based on ActiveSupport::SafeBuffer
|
4
|
+
#
|
5
|
+
class SafeBuffer < String
|
6
|
+
UNSAFE_STRING_METHODS = %w(
|
7
|
+
capitalize chomp chop delete downcase gsub lstrip next reverse rstrip
|
8
|
+
slice squeeze strip sub succ swapcase tr tr_s upcase
|
9
|
+
)
|
10
|
+
|
11
|
+
alias_method :original_concat, :concat
|
12
|
+
private :original_concat
|
13
|
+
|
14
|
+
class SafeConcatError < StandardError
|
15
|
+
def initialize
|
16
|
+
super "Could not concatenate to the buffer because it is not html safe."
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def [](*args)
|
21
|
+
if args.size < 2
|
22
|
+
super
|
23
|
+
else
|
24
|
+
if html_safe?
|
25
|
+
new_safe_buffer = super
|
26
|
+
|
27
|
+
if new_safe_buffer
|
28
|
+
new_safe_buffer.instance_variable_set :@html_safe, true
|
29
|
+
end
|
30
|
+
|
31
|
+
new_safe_buffer
|
32
|
+
else
|
33
|
+
to_str[*args]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def safe_concat(value)
|
39
|
+
raise SafeConcatError unless html_safe?
|
40
|
+
original_concat(value)
|
41
|
+
end
|
42
|
+
|
43
|
+
def initialize(str = "")
|
44
|
+
@html_safe = true
|
45
|
+
super
|
46
|
+
end
|
47
|
+
|
48
|
+
def initialize_copy(other)
|
49
|
+
super
|
50
|
+
@html_safe = other.html_safe?
|
51
|
+
end
|
52
|
+
|
53
|
+
def clone_empty
|
54
|
+
self[0, 0]
|
55
|
+
end
|
56
|
+
|
57
|
+
def concat(value)
|
58
|
+
super(html_escape_interpolated_argument(value))
|
59
|
+
end
|
60
|
+
alias << concat
|
61
|
+
|
62
|
+
def prepend(value)
|
63
|
+
super(html_escape_interpolated_argument(value))
|
64
|
+
end
|
65
|
+
|
66
|
+
def +(other)
|
67
|
+
dup.concat(other)
|
68
|
+
end
|
69
|
+
|
70
|
+
def %(args)
|
71
|
+
case args
|
72
|
+
when Hash
|
73
|
+
escaped_args = Hash[args.map { |k,arg| [k, html_escape_interpolated_argument(arg)] }]
|
74
|
+
else
|
75
|
+
escaped_args = Array(args).map { |arg| html_escape_interpolated_argument(arg) }
|
76
|
+
end
|
77
|
+
|
78
|
+
self.class.new(super(escaped_args))
|
79
|
+
end
|
80
|
+
|
81
|
+
def html_safe?
|
82
|
+
defined?(@html_safe) && @html_safe
|
83
|
+
end
|
84
|
+
|
85
|
+
def to_s
|
86
|
+
self
|
87
|
+
end
|
88
|
+
|
89
|
+
def to_param
|
90
|
+
to_str
|
91
|
+
end
|
92
|
+
|
93
|
+
def encode_with(coder)
|
94
|
+
coder.represent_object nil, to_str
|
95
|
+
end
|
96
|
+
|
97
|
+
UNSAFE_STRING_METHODS.each do |unsafe_method|
|
98
|
+
if unsafe_method.respond_to?(unsafe_method)
|
99
|
+
class_eval <<-EOT, __FILE__, __LINE__ + 1
|
100
|
+
def #{unsafe_method}(*args, &block) # def capitalize(*args, &block)
|
101
|
+
to_str.#{unsafe_method}(*args, &block) # to_str.capitalize(*args, &block)
|
102
|
+
end # end
|
103
|
+
|
104
|
+
def #{unsafe_method}!(*args) # def capitalize!(*args)
|
105
|
+
@html_safe = false # @html_safe = false
|
106
|
+
super # super
|
107
|
+
end # end
|
108
|
+
EOT
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def html_escape_interpolated_argument(arg)
|
115
|
+
(!html_safe? || arg.html_safe?) ? arg : CGI.escapeHTML(arg.to_s)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
data/test/helper.rb
CHANGED
@@ -44,8 +44,8 @@ class MiniTest::Spec
|
|
44
44
|
FileUtils.mkdir_p(File.dirname(__FILE__) + "/views")
|
45
45
|
FileUtils.mkdir_p(File.dirname(__FILE__) + "/views/layouts")
|
46
46
|
path = "/views/#{name}"
|
47
|
-
path += ".#{options.delete(:locale)}" if options[:locale]
|
48
|
-
path += ".#{options[:format]}" if options[:format]
|
47
|
+
path += ".#{options.delete(:locale)}" if options[:locale]
|
48
|
+
path += ".#{options[:format]}" if options[:format]
|
49
49
|
path += ".erb" unless options[:format].to_s =~ /erb|slim|haml|rss|atom|builder|liquid/
|
50
50
|
path += ".builder" if options[:format].to_s =~ /rss|atom/
|
51
51
|
file = File.dirname(__FILE__) + path
|
data/test/test_format_helpers.rb
CHANGED
@@ -209,23 +209,23 @@ describe "FormatHelpers" do
|
|
209
209
|
describe 'for #js_escape_html method' do
|
210
210
|
it 'should escape double quotes' do
|
211
211
|
assert_equal "\\\"hello\\\"", js_escape_html('"hello"')
|
212
|
-
assert_equal "\\\"hello\\\"", js_escape_html(
|
212
|
+
assert_equal "\\\"hello\\\"", js_escape_html(SafeBuffer.new('"hello"'))
|
213
213
|
end
|
214
214
|
it 'should escape single quotes' do
|
215
215
|
assert_equal "\\'hello\\'", js_escape_html("'hello'")
|
216
|
-
assert_equal "\\'hello\\'", js_escape_html(
|
216
|
+
assert_equal "\\'hello\\'", js_escape_html(SafeBuffer.new("'hello'"))
|
217
217
|
end
|
218
218
|
it 'should escape html tags and breaks' do
|
219
219
|
assert_equal "\\n\\n<p>hello<\\/p>\\n", js_escape_html("\n\r<p>hello</p>\r\n")
|
220
|
-
assert_equal "\\n\\n<p>hello<\\/p>\\n", js_escape_html(
|
220
|
+
assert_equal "\\n\\n<p>hello<\\/p>\\n", js_escape_html(SafeBuffer.new("\n\r<p>hello</p>\r\n"))
|
221
221
|
end
|
222
222
|
it 'should escape data-confirm attribute' do
|
223
223
|
assert_equal "<data-confirm=\\\"are you sure\\\">", js_escape_html("<data-confirm=\"are you sure\">")
|
224
|
-
assert_equal "<data-confirm=\\\"are you sure\\\">", js_escape_html(
|
224
|
+
assert_equal "<data-confirm=\\\"are you sure\\\">", js_escape_html(SafeBuffer.new("<data-confirm=\"are you sure\">"))
|
225
225
|
end
|
226
226
|
it 'should keep html_safe content html_safe' do
|
227
227
|
assert_equal false, js_escape_html('"hello"').html_safe?
|
228
|
-
assert_equal true, js_escape_html(
|
228
|
+
assert_equal true, js_escape_html(SafeBuffer.new('"hello"')).html_safe?
|
229
229
|
end
|
230
230
|
end
|
231
231
|
end
|
data/test/test_render_helpers.rb
CHANGED
@@ -253,5 +253,15 @@ describe "RenderHelpers" do
|
|
253
253
|
end
|
254
254
|
assert_equal 'existing', Standalone3.new.partial('none')
|
255
255
|
end
|
256
|
+
|
257
|
+
it 'should not add "./" to partial template name' do
|
258
|
+
class Standalone4
|
259
|
+
def render(_, file, *)
|
260
|
+
file.to_s
|
261
|
+
end
|
262
|
+
include Padrino::Helpers::RenderHelpers
|
263
|
+
end
|
264
|
+
assert_equal '_none', Standalone4.new.partial('none')
|
265
|
+
end
|
256
266
|
end
|
257
267
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: padrino-helpers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.13.3
|
4
|
+
version: 0.13.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Padrino Team
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2016-08-
|
14
|
+
date: 2016-08-30 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: padrino-support
|
@@ -19,14 +19,14 @@ dependencies:
|
|
19
19
|
requirements:
|
20
20
|
- - '='
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 0.13.3
|
22
|
+
version: 0.13.3.1
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
27
|
- - '='
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: 0.13.3
|
29
|
+
version: 0.13.3.1
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: tilt
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -120,11 +120,13 @@ files:
|
|
120
120
|
- lib/padrino-helpers/render_helpers.rb
|
121
121
|
- lib/padrino-helpers/tag_helpers.rb
|
122
122
|
- lib/padrino-helpers/translation_helpers.rb
|
123
|
+
- lib/padrino/core_ext/output_safety.rb
|
123
124
|
- lib/padrino/rendering.rb
|
124
125
|
- lib/padrino/rendering/erb_template.rb
|
125
126
|
- lib/padrino/rendering/erubis_template.rb
|
126
127
|
- lib/padrino/rendering/haml_template.rb
|
127
128
|
- lib/padrino/rendering/slim_template.rb
|
129
|
+
- lib/padrino/safe_buffer.rb
|
128
130
|
- padrino-helpers.gemspec
|
129
131
|
- test/fixtures/apps/.components
|
130
132
|
- test/fixtures/apps/.gitignore
|
@@ -245,7 +247,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
245
247
|
version: 1.3.6
|
246
248
|
requirements: []
|
247
249
|
rubyforge_project: padrino-helpers
|
248
|
-
rubygems_version: 2.
|
250
|
+
rubygems_version: 2.5.1
|
249
251
|
signing_key:
|
250
252
|
specification_version: 4
|
251
253
|
summary: Helpers for padrino
|