haml 4.0.7 → 5.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.github/workflows/test.yml +36 -0
- data/.gitignore +19 -0
- data/.gitmodules +3 -0
- data/.yardopts +2 -3
- data/CHANGELOG.md +146 -4
- data/FAQ.md +4 -14
- data/Gemfile +16 -0
- data/MIT-LICENSE +2 -2
- data/README.md +90 -47
- data/REFERENCE.md +160 -74
- data/Rakefile +44 -63
- data/TODO +24 -0
- data/benchmark.rb +70 -0
- data/haml.gemspec +45 -0
- data/lib/haml/.gitattributes +1 -0
- data/lib/haml/attribute_builder.rb +219 -0
- data/lib/haml/attribute_compiler.rb +237 -0
- data/lib/haml/attribute_parser.rb +150 -0
- data/lib/haml/buffer.rb +12 -175
- data/lib/haml/compiler.rb +110 -320
- data/lib/haml/engine.rb +34 -41
- data/lib/haml/error.rb +28 -24
- data/lib/haml/escapable.rb +77 -0
- data/lib/haml/exec.rb +38 -20
- data/lib/haml/filters.rb +22 -27
- data/lib/haml/generator.rb +42 -0
- data/lib/haml/helpers/action_view_extensions.rb +4 -2
- data/lib/haml/helpers/action_view_mods.rb +45 -60
- data/lib/haml/helpers/action_view_xss_mods.rb +2 -0
- data/lib/haml/helpers/safe_erubi_template.rb +20 -0
- data/lib/haml/helpers/safe_erubis_template.rb +5 -1
- data/lib/haml/helpers/xss_mods.rb +23 -13
- data/lib/haml/helpers.rb +134 -89
- data/lib/haml/options.rb +63 -69
- data/lib/haml/parser.rb +319 -227
- data/lib/haml/plugin.rb +54 -0
- data/lib/haml/railtie.rb +43 -12
- data/lib/haml/sass_rails_filter.rb +18 -4
- data/lib/haml/template/options.rb +13 -2
- data/lib/haml/template.rb +13 -6
- data/lib/haml/temple_engine.rb +124 -0
- data/lib/haml/temple_line_counter.rb +30 -0
- data/lib/haml/util.rb +83 -202
- data/lib/haml/version.rb +3 -1
- data/lib/haml.rb +2 -0
- data/yard/default/.gitignore +1 -0
- data/yard/default/fulldoc/html/css/common.sass +15 -0
- data/yard/default/layout/html/footer.erb +12 -0
- metadata +73 -115
- data/lib/haml/template/plugin.rb +0 -41
- data/test/engine_test.rb +0 -2013
- data/test/erb/_av_partial_1.erb +0 -12
- data/test/erb/_av_partial_2.erb +0 -8
- data/test/erb/action_view.erb +0 -62
- data/test/erb/standard.erb +0 -55
- data/test/filters_test.rb +0 -254
- data/test/gemfiles/Gemfile.rails-3.0.x +0 -5
- data/test/gemfiles/Gemfile.rails-3.1.x +0 -6
- data/test/gemfiles/Gemfile.rails-3.2.x +0 -5
- data/test/gemfiles/Gemfile.rails-4.0.x +0 -5
- data/test/haml-spec/LICENSE +0 -14
- data/test/haml-spec/README.md +0 -106
- data/test/haml-spec/lua_haml_spec.lua +0 -38
- data/test/haml-spec/perl_haml_test.pl +0 -81
- data/test/haml-spec/ruby_haml_test.rb +0 -23
- data/test/haml-spec/tests.json +0 -660
- data/test/helper_test.rb +0 -583
- data/test/markaby/standard.mab +0 -52
- data/test/mocks/article.rb +0 -6
- data/test/parser_test.rb +0 -105
- data/test/results/content_for_layout.xhtml +0 -12
- data/test/results/eval_suppressed.xhtml +0 -9
- data/test/results/helpers.xhtml +0 -70
- data/test/results/helpful.xhtml +0 -10
- data/test/results/just_stuff.xhtml +0 -70
- data/test/results/list.xhtml +0 -12
- data/test/results/nuke_inner_whitespace.xhtml +0 -40
- data/test/results/nuke_outer_whitespace.xhtml +0 -148
- data/test/results/original_engine.xhtml +0 -20
- data/test/results/partial_layout.xhtml +0 -5
- data/test/results/partial_layout_erb.xhtml +0 -5
- data/test/results/partials.xhtml +0 -21
- data/test/results/render_layout.xhtml +0 -3
- data/test/results/silent_script.xhtml +0 -74
- data/test/results/standard.xhtml +0 -162
- data/test/results/tag_parsing.xhtml +0 -23
- data/test/results/very_basic.xhtml +0 -5
- data/test/results/whitespace_handling.xhtml +0 -90
- data/test/template_test.rb +0 -354
- data/test/templates/_av_partial_1.haml +0 -9
- data/test/templates/_av_partial_1_ugly.haml +0 -9
- data/test/templates/_av_partial_2.haml +0 -5
- data/test/templates/_av_partial_2_ugly.haml +0 -5
- data/test/templates/_layout.erb +0 -3
- data/test/templates/_layout_for_partial.haml +0 -3
- data/test/templates/_partial.haml +0 -8
- data/test/templates/_text_area.haml +0 -3
- data/test/templates/_text_area_helper.html.haml +0 -4
- data/test/templates/action_view.haml +0 -47
- data/test/templates/action_view_ugly.haml +0 -47
- data/test/templates/breakage.haml +0 -8
- data/test/templates/content_for_layout.haml +0 -8
- data/test/templates/eval_suppressed.haml +0 -11
- data/test/templates/helpers.haml +0 -55
- data/test/templates/helpful.haml +0 -11
- data/test/templates/just_stuff.haml +0 -85
- data/test/templates/list.haml +0 -12
- data/test/templates/nuke_inner_whitespace.haml +0 -32
- data/test/templates/nuke_outer_whitespace.haml +0 -144
- data/test/templates/original_engine.haml +0 -17
- data/test/templates/partial_layout.haml +0 -3
- data/test/templates/partial_layout_erb.erb +0 -4
- data/test/templates/partialize.haml +0 -1
- data/test/templates/partials.haml +0 -12
- data/test/templates/render_layout.haml +0 -2
- data/test/templates/silent_script.haml +0 -45
- data/test/templates/standard.haml +0 -43
- data/test/templates/standard_ugly.haml +0 -43
- data/test/templates/tag_parsing.haml +0 -21
- data/test/templates/very_basic.haml +0 -4
- data/test/templates/whitespace_handling.haml +0 -87
- data/test/test_helper.rb +0 -81
- data/test/util_test.rb +0 -63
|
@@ -1,40 +1,41 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Haml
|
|
4
|
+
module Helpers
|
|
5
|
+
module ActionViewMods
|
|
6
|
+
def render(*args, &block)
|
|
7
|
+
options = args.first
|
|
8
|
+
|
|
9
|
+
# If render :layout is used with a block, it concats rather than returning
|
|
10
|
+
# a string so we need it to keep thinking it's Haml until it hits the
|
|
11
|
+
# sub-render.
|
|
12
|
+
if is_haml? && !(options.is_a?(Hash) && options[:layout] && block_given?)
|
|
13
|
+
return non_haml { super }
|
|
14
|
+
end
|
|
15
|
+
super
|
|
11
16
|
end
|
|
12
|
-
render_without_haml(*args, &block)
|
|
13
|
-
end
|
|
14
|
-
alias_method :render_without_haml, :render
|
|
15
|
-
alias_method :render, :render_with_haml
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
alias_method :output_buffer_without_haml, :output_buffer
|
|
22
|
-
alias_method :output_buffer, :output_buffer_with_haml
|
|
18
|
+
def output_buffer
|
|
19
|
+
return haml_buffer.buffer if is_haml?
|
|
20
|
+
super
|
|
21
|
+
end
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
def output_buffer=(new_buffer)
|
|
24
|
+
if is_haml?
|
|
25
|
+
if Haml::Util.rails_xss_safe? && new_buffer.is_a?(ActiveSupport::SafeBuffer)
|
|
26
|
+
new_buffer = String.new(new_buffer)
|
|
27
|
+
end
|
|
28
|
+
haml_buffer.buffer = new_buffer
|
|
29
|
+
else
|
|
30
|
+
super
|
|
28
31
|
end
|
|
29
|
-
haml_buffer.buffer = new_buffer
|
|
30
|
-
else
|
|
31
|
-
set_output_buffer_without_haml new_buffer
|
|
32
32
|
end
|
|
33
33
|
end
|
|
34
|
-
|
|
35
|
-
alias_method :output_buffer=, :set_output_buffer_with_haml
|
|
34
|
+
ActionView::Base.send(:prepend, ActionViewMods)
|
|
36
35
|
end
|
|
36
|
+
end
|
|
37
37
|
|
|
38
|
+
module ActionView
|
|
38
39
|
module Helpers
|
|
39
40
|
module CaptureHelper
|
|
40
41
|
def capture_with_haml(*args, &block)
|
|
@@ -42,12 +43,7 @@ module ActionView
|
|
|
42
43
|
#double assignment is to avoid warnings
|
|
43
44
|
_hamlout = _hamlout = eval('_hamlout', block.binding) # Necessary since capture_haml checks _hamlout
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
# NonCattingString is present in Rails less than 3.1.0. When support
|
|
48
|
-
# for 3.0 is dropped, this can be removed.
|
|
49
|
-
return ActionView::NonConcattingString.new(str) if str && defined?(ActionView::NonConcattingString)
|
|
50
|
-
return str
|
|
46
|
+
capture_haml(*args, &block)
|
|
51
47
|
else
|
|
52
48
|
capture_without_haml(*args, &block)
|
|
53
49
|
end
|
|
@@ -57,17 +53,23 @@ module ActionView
|
|
|
57
53
|
end
|
|
58
54
|
|
|
59
55
|
module TagHelper
|
|
56
|
+
DEFAULT_PRESERVE_OPTIONS = %w(textarea pre code).freeze
|
|
57
|
+
|
|
60
58
|
def content_tag_with_haml(name, *args, &block)
|
|
61
59
|
return content_tag_without_haml(name, *args, &block) unless is_haml?
|
|
62
60
|
|
|
63
|
-
preserve = haml_buffer.options
|
|
61
|
+
preserve = haml_buffer.options.fetch(:preserve, DEFAULT_PRESERVE_OPTIONS).include?(name.to_s)
|
|
64
62
|
|
|
65
63
|
if block_given? && block_is_haml?(block) && preserve
|
|
66
|
-
return content_tag_without_haml(name, *args)
|
|
64
|
+
return content_tag_without_haml(name, *args) do
|
|
65
|
+
haml_buffer.fix_textareas!(Haml::Helpers.preserve(&block)).html_safe
|
|
66
|
+
end
|
|
67
67
|
end
|
|
68
68
|
|
|
69
69
|
content = content_tag_without_haml(name, *args, &block)
|
|
70
|
-
|
|
70
|
+
if preserve && content
|
|
71
|
+
content = haml_buffer.fix_textareas!(Haml::Helpers.preserve(content)).html_safe
|
|
72
|
+
end
|
|
71
73
|
content
|
|
72
74
|
end
|
|
73
75
|
|
|
@@ -87,11 +89,9 @@ module ActionView
|
|
|
87
89
|
end
|
|
88
90
|
end
|
|
89
91
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
include HamlSupport
|
|
94
|
-
end
|
|
92
|
+
module Tags
|
|
93
|
+
class TextArea
|
|
94
|
+
include HamlSupport
|
|
95
95
|
end
|
|
96
96
|
end
|
|
97
97
|
|
|
@@ -118,7 +118,7 @@ module ActionView
|
|
|
118
118
|
with_tabs(1) {oldproc.call(*args)}
|
|
119
119
|
end
|
|
120
120
|
end
|
|
121
|
-
res = form_tag_without_haml(url_for_options, options, *parameters_for_url, &proc)
|
|
121
|
+
res = form_tag_without_haml(url_for_options, options, *parameters_for_url, &proc) << "\n"
|
|
122
122
|
res << "\n" if wrap_block
|
|
123
123
|
res
|
|
124
124
|
else
|
|
@@ -128,20 +128,5 @@ module ActionView
|
|
|
128
128
|
alias_method :form_tag_without_haml, :form_tag
|
|
129
129
|
alias_method :form_tag, :form_tag_with_haml
|
|
130
130
|
end
|
|
131
|
-
|
|
132
|
-
module FormHelper
|
|
133
|
-
def form_for_with_haml(object_name, *args, &proc)
|
|
134
|
-
wrap_block = block_given? && is_haml? && block_is_haml?(proc)
|
|
135
|
-
if wrap_block
|
|
136
|
-
oldproc = proc
|
|
137
|
-
proc = proc {|*subargs| with_tabs(1) {oldproc.call(*subargs)}}
|
|
138
|
-
end
|
|
139
|
-
res = form_for_without_haml(object_name, *args, &proc)
|
|
140
|
-
res << "\n" if wrap_block
|
|
141
|
-
res
|
|
142
|
-
end
|
|
143
|
-
alias_method :form_for_without_haml, :form_for
|
|
144
|
-
alias_method :form_for, :form_for_with_haml
|
|
145
|
-
end
|
|
146
131
|
end
|
|
147
|
-
end
|
|
132
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'action_view'
|
|
4
|
+
|
|
5
|
+
module Haml
|
|
6
|
+
class ErubiTemplateHandler < ActionView::Template::Handlers::ERB::Erubi
|
|
7
|
+
|
|
8
|
+
def initialize(*args, &blk)
|
|
9
|
+
@newline_pending = 0
|
|
10
|
+
super
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class SafeErubiTemplate < Tilt::ErubiTemplate
|
|
15
|
+
def prepare
|
|
16
|
+
@options.merge! engine_class: Haml::ErubiTemplateHandler
|
|
17
|
+
super
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Haml
|
|
2
4
|
module Helpers
|
|
3
5
|
# This module overrides Haml helpers to work properly
|
|
@@ -6,12 +8,15 @@ module Haml
|
|
|
6
8
|
# to work with Rails' XSS protection methods.
|
|
7
9
|
module XssMods
|
|
8
10
|
def self.included(base)
|
|
9
|
-
%w[
|
|
10
|
-
precede succeed capture_haml haml_concat haml_indent
|
|
11
|
-
haml_tag escape_once].each do |name|
|
|
11
|
+
%w[find_and_preserve preserve list_of surround
|
|
12
|
+
precede succeed capture_haml haml_concat haml_internal_concat haml_indent].each do |name|
|
|
12
13
|
base.send(:alias_method, "#{name}_without_haml_xss", name)
|
|
13
14
|
base.send(:alias_method, name, "#{name}_with_haml_xss")
|
|
14
15
|
end
|
|
16
|
+
# Those two always have _without_haml_xss
|
|
17
|
+
%w[html_escape escape_once].each do |name|
|
|
18
|
+
base.send(:alias_method, name, "#{name}_with_haml_xss")
|
|
19
|
+
end
|
|
15
20
|
end
|
|
16
21
|
|
|
17
22
|
# Don't escape text that's already safe,
|
|
@@ -61,24 +66,29 @@ module Haml
|
|
|
61
66
|
Haml::Util.html_safe(capture_haml_without_haml_xss(*args, &block))
|
|
62
67
|
end
|
|
63
68
|
|
|
64
|
-
# Input is
|
|
69
|
+
# Input will be escaped unless this is in a `with_raw_haml_concat`
|
|
70
|
+
# block. See #Haml::Helpers::ActionViewExtensions#with_raw_haml_concat.
|
|
65
71
|
def haml_concat_with_haml_xss(text = "")
|
|
66
|
-
raw = instance_variable_defined?(
|
|
67
|
-
|
|
72
|
+
raw = instance_variable_defined?(:@_haml_concat_raw) ? @_haml_concat_raw : false
|
|
73
|
+
if raw
|
|
74
|
+
haml_internal_concat_raw text
|
|
75
|
+
else
|
|
76
|
+
haml_internal_concat text
|
|
77
|
+
end
|
|
78
|
+
ErrorReturn.new("haml_concat")
|
|
68
79
|
end
|
|
69
80
|
|
|
81
|
+
# Input is escaped
|
|
82
|
+
def haml_internal_concat_with_haml_xss(text="", newline=true, indent=true)
|
|
83
|
+
haml_internal_concat_without_haml_xss(haml_xss_html_escape(text), newline, indent)
|
|
84
|
+
end
|
|
85
|
+
private :haml_internal_concat_with_haml_xss
|
|
86
|
+
|
|
70
87
|
# Output is always HTML safe
|
|
71
88
|
def haml_indent_with_haml_xss
|
|
72
89
|
Haml::Util.html_safe(haml_indent_without_haml_xss)
|
|
73
90
|
end
|
|
74
91
|
|
|
75
|
-
# Input is escaped, haml_concat'ed output is always HTML safe
|
|
76
|
-
def haml_tag_with_haml_xss(name, *rest, &block)
|
|
77
|
-
name = haml_xss_html_escape(name.to_s)
|
|
78
|
-
rest.unshift(haml_xss_html_escape(rest.shift.to_s)) unless [Symbol, Hash, NilClass].any? {|t| rest.first.is_a? t}
|
|
79
|
-
with_raw_haml_concat {haml_tag_without_haml_xss(name, *rest, &block)}
|
|
80
|
-
end
|
|
81
|
-
|
|
82
92
|
# Output is always HTML safe
|
|
83
93
|
def escape_once_with_haml_xss(*args)
|
|
84
94
|
Haml::Util.html_safe(escape_once_without_haml_xss(*args))
|
data/lib/haml/helpers.rb
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'erb'
|
|
4
|
+
|
|
1
5
|
module Haml
|
|
2
6
|
# This module contains various helpful methods to make it easier to do various tasks.
|
|
3
7
|
# {Haml::Helpers} is automatically included in the context
|
|
@@ -106,7 +110,8 @@ MESSAGE
|
|
|
106
110
|
# @yield The block within which to escape newlines
|
|
107
111
|
def find_and_preserve(input = nil, tags = haml_buffer.options[:preserve], &block)
|
|
108
112
|
return find_and_preserve(capture_haml(&block), input || tags) if block
|
|
109
|
-
|
|
113
|
+
tags = tags.map { |tag| Regexp.escape(tag) }.join('|')
|
|
114
|
+
re = /<(#{tags})([^>]*)>(.*?)(<\/\1>)/im
|
|
110
115
|
input.to_s.gsub(re) do |s|
|
|
111
116
|
s =~ re # Can't rely on $1, etc. existing since Rails' SafeBuffer#gsub is incompatible
|
|
112
117
|
"<#{$1}#{$2}>#{preserve($3)}</#{$1}>"
|
|
@@ -117,17 +122,20 @@ MESSAGE
|
|
|
117
122
|
# HTML entities so they'll render correctly in
|
|
118
123
|
# whitespace-sensitive tags without screwing up the indentation.
|
|
119
124
|
#
|
|
120
|
-
# @overload
|
|
125
|
+
# @overload preserve(input)
|
|
121
126
|
# Escapes newlines within a string.
|
|
122
127
|
#
|
|
123
128
|
# @param input [String] The string within which to escape all newlines
|
|
124
|
-
# @overload
|
|
129
|
+
# @overload preserve
|
|
125
130
|
# Escapes newlines within a block of Haml code.
|
|
126
131
|
#
|
|
127
132
|
# @yield The block within which to escape newlines
|
|
128
133
|
def preserve(input = nil, &block)
|
|
129
134
|
return preserve(capture_haml(&block)) if block
|
|
130
|
-
input.to_s.chomp("\n")
|
|
135
|
+
s = input.to_s.chomp("\n")
|
|
136
|
+
s.gsub!(/\n/, '
')
|
|
137
|
+
s.delete!("\r")
|
|
138
|
+
s
|
|
131
139
|
end
|
|
132
140
|
alias_method :flatten, :preserve
|
|
133
141
|
|
|
@@ -190,20 +198,19 @@ MESSAGE
|
|
|
190
198
|
# @yield [item] A block which contains Haml code that goes within list items
|
|
191
199
|
# @yieldparam item An element of `enum`
|
|
192
200
|
def list_of(enum, opts={}, &block)
|
|
193
|
-
opts_attributes = opts.
|
|
194
|
-
|
|
201
|
+
opts_attributes = opts.map { |k, v| " #{k}='#{v}'" }.join
|
|
202
|
+
enum.map do |i|
|
|
195
203
|
result = capture_haml(i, &block)
|
|
196
204
|
|
|
197
205
|
if result.count("\n") > 1
|
|
198
|
-
result
|
|
206
|
+
result.gsub!("\n", "\n ")
|
|
199
207
|
result = "\n #{result.strip}\n"
|
|
200
208
|
else
|
|
201
|
-
result
|
|
209
|
+
result.strip!
|
|
202
210
|
end
|
|
203
211
|
|
|
204
212
|
%Q!<li#{opts_attributes}>#{result}</li>!
|
|
205
|
-
end
|
|
206
|
-
to_return.join("\n")
|
|
213
|
+
end.join("\n")
|
|
207
214
|
end
|
|
208
215
|
|
|
209
216
|
# Returns a hash containing default assignments for the `xmlns`, `lang`, and `xml:lang`
|
|
@@ -219,7 +226,11 @@ MESSAGE
|
|
|
219
226
|
# @param lang [String] The value of `xml:lang` and `lang`
|
|
220
227
|
# @return [{#to_s => String}] The attribute hash
|
|
221
228
|
def html_attrs(lang = 'en-US')
|
|
222
|
-
|
|
229
|
+
if haml_buffer.options[:format] == :xhtml
|
|
230
|
+
{:xmlns => "http://www.w3.org/1999/xhtml", 'xml:lang' => lang, :lang => lang}
|
|
231
|
+
else
|
|
232
|
+
{:lang => lang}
|
|
233
|
+
end
|
|
223
234
|
end
|
|
224
235
|
|
|
225
236
|
# Increments the number of tabs the buffer automatically adds
|
|
@@ -370,12 +381,10 @@ MESSAGE
|
|
|
370
381
|
captured = haml_buffer.buffer.slice!(position..-1)
|
|
371
382
|
|
|
372
383
|
if captured == '' and value != haml_buffer.buffer
|
|
373
|
-
|
|
384
|
+
captured = (value.is_a?(String) ? value : nil)
|
|
374
385
|
end
|
|
375
386
|
|
|
376
|
-
|
|
377
|
-
return (haml_buffer.options[:ugly] ? captured : prettify(captured))
|
|
378
|
-
|
|
387
|
+
captured
|
|
379
388
|
end
|
|
380
389
|
ensure
|
|
381
390
|
haml_buffer.capture_position = nil
|
|
@@ -385,14 +394,34 @@ MESSAGE
|
|
|
385
394
|
#
|
|
386
395
|
# @param text [#to_s] The text to output
|
|
387
396
|
def haml_concat(text = "")
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
397
|
+
haml_internal_concat text
|
|
398
|
+
ErrorReturn.new("haml_concat")
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
# Internal method to write directly to the buffer with control of
|
|
402
|
+
# whether the first line should be indented, and if there should be a
|
|
403
|
+
# final newline.
|
|
404
|
+
#
|
|
405
|
+
# Lines added will have the proper indentation. This can be controlled
|
|
406
|
+
# for the first line.
|
|
407
|
+
#
|
|
408
|
+
# Used by #haml_concat and #haml_tag.
|
|
409
|
+
#
|
|
410
|
+
# @param text [#to_s] The text to output
|
|
411
|
+
# @param newline [Boolean] Whether to add a newline after the text
|
|
412
|
+
# @param indent [Boolean] Whether to add indentation to the first line
|
|
413
|
+
def haml_internal_concat(text = "", newline = true, indent = true)
|
|
414
|
+
if haml_buffer.tabulation == 0
|
|
415
|
+
haml_buffer.buffer << "#{text}#{"\n" if newline}"
|
|
391
416
|
else
|
|
392
|
-
haml_buffer.buffer << text.to_s
|
|
417
|
+
haml_buffer.buffer << %[#{haml_indent if indent}#{text.to_s.gsub("\n", "\n#{haml_indent}")}#{"\n" if newline}]
|
|
393
418
|
end
|
|
394
|
-
ErrorReturn.new("haml_concat")
|
|
395
419
|
end
|
|
420
|
+
private :haml_internal_concat
|
|
421
|
+
|
|
422
|
+
# Allows writing raw content. `haml_internal_concat_raw` isn't
|
|
423
|
+
# effected by XSS mods. Used by #haml_tag to write the actual tags.
|
|
424
|
+
alias :haml_internal_concat_raw :haml_internal_concat
|
|
396
425
|
|
|
397
426
|
# @return [String] The indentation string for the current line
|
|
398
427
|
def haml_indent
|
|
@@ -466,14 +495,14 @@ MESSAGE
|
|
|
466
495
|
attrs.keys.each {|key| attrs[key.to_s] = attrs.delete(key)} unless attrs.empty?
|
|
467
496
|
name, attrs = merge_name_and_attributes(name.to_s, attrs)
|
|
468
497
|
|
|
469
|
-
attributes = Haml::
|
|
498
|
+
attributes = Haml::AttributeBuilder.build_attributes(haml_buffer.html?,
|
|
470
499
|
haml_buffer.options[:attr_wrapper],
|
|
471
500
|
haml_buffer.options[:escape_attrs],
|
|
472
501
|
haml_buffer.options[:hyphenate_data_attrs],
|
|
473
502
|
attrs)
|
|
474
503
|
|
|
475
504
|
if text.nil? && block.nil? && (haml_buffer.options[:autoclose].include?(name) || flags.include?(:/))
|
|
476
|
-
|
|
505
|
+
haml_internal_concat_raw "<#{name}#{attributes}#{' /' if haml_buffer.options[:format] == :xhtml}>"
|
|
477
506
|
return ret
|
|
478
507
|
end
|
|
479
508
|
|
|
@@ -483,17 +512,19 @@ MESSAGE
|
|
|
483
512
|
end
|
|
484
513
|
|
|
485
514
|
tag = "<#{name}#{attributes}>"
|
|
515
|
+
end_tag = "</#{name}>"
|
|
486
516
|
if block.nil?
|
|
487
517
|
text = text.to_s
|
|
488
518
|
if text.include?("\n")
|
|
489
|
-
|
|
519
|
+
haml_internal_concat_raw tag
|
|
490
520
|
tab_up
|
|
491
|
-
|
|
521
|
+
haml_internal_concat text
|
|
492
522
|
tab_down
|
|
493
|
-
|
|
523
|
+
haml_internal_concat_raw end_tag
|
|
494
524
|
else
|
|
495
|
-
tag
|
|
496
|
-
|
|
525
|
+
haml_internal_concat_raw tag, false
|
|
526
|
+
haml_internal_concat text, false, false
|
|
527
|
+
haml_internal_concat_raw end_tag, true, false
|
|
497
528
|
end
|
|
498
529
|
return ret
|
|
499
530
|
end
|
|
@@ -503,69 +534,100 @@ MESSAGE
|
|
|
503
534
|
end
|
|
504
535
|
|
|
505
536
|
if flags.include?(:<)
|
|
506
|
-
tag
|
|
507
|
-
|
|
537
|
+
haml_internal_concat_raw tag, false
|
|
538
|
+
haml_internal_concat "#{capture_haml(&block).strip}", false, false
|
|
539
|
+
haml_internal_concat_raw end_tag, true, false
|
|
508
540
|
return ret
|
|
509
541
|
end
|
|
510
542
|
|
|
511
|
-
|
|
543
|
+
haml_internal_concat_raw tag
|
|
512
544
|
tab_up
|
|
513
545
|
block.call
|
|
514
546
|
tab_down
|
|
515
|
-
|
|
547
|
+
haml_internal_concat_raw end_tag
|
|
516
548
|
|
|
517
549
|
ret
|
|
518
550
|
end
|
|
519
551
|
|
|
520
|
-
#
|
|
521
|
-
|
|
552
|
+
# Conditionally wrap a block in an element. If `condition` is `true` then
|
|
553
|
+
# this method renders the tag described by the arguments in `tag` (using
|
|
554
|
+
# \{#haml_tag}) with the given block inside, otherwise it just renders the block.
|
|
555
|
+
#
|
|
556
|
+
# For example,
|
|
557
|
+
#
|
|
558
|
+
# - haml_tag_if important, '.important' do
|
|
559
|
+
# %p
|
|
560
|
+
# A (possibly) important paragraph.
|
|
561
|
+
#
|
|
562
|
+
# will produce
|
|
563
|
+
#
|
|
564
|
+
# <div class='important'>
|
|
565
|
+
# <p>
|
|
566
|
+
# A (possibly) important paragraph.
|
|
567
|
+
# </p>
|
|
568
|
+
# </div>
|
|
569
|
+
#
|
|
570
|
+
# if `important` is truthy, and just
|
|
571
|
+
#
|
|
572
|
+
# <p>
|
|
573
|
+
# A (possibly) important paragraph.
|
|
574
|
+
# </p>
|
|
575
|
+
#
|
|
576
|
+
# otherwise.
|
|
577
|
+
#
|
|
578
|
+
# Like \{#haml_tag}, `haml_tag_if` outputs directly to the buffer and its
|
|
579
|
+
# return value should not be used. Use \{#capture_haml} if you need to use
|
|
580
|
+
# its results as a string.
|
|
581
|
+
#
|
|
582
|
+
# @param condition The condition to test to determine whether to render
|
|
583
|
+
# the enclosing tag
|
|
584
|
+
# @param tag Definition of the enclosing tag. See \{#haml_tag} for details
|
|
585
|
+
# (specifically the form that takes a block)
|
|
586
|
+
def haml_tag_if(condition, *tag)
|
|
587
|
+
if condition
|
|
588
|
+
haml_tag(*tag){ yield }
|
|
589
|
+
else
|
|
590
|
+
yield
|
|
591
|
+
end
|
|
592
|
+
ErrorReturn.new("haml_tag_if")
|
|
593
|
+
end
|
|
522
594
|
|
|
523
|
-
|
|
595
|
+
# Characters that need to be escaped to HTML entities from user input
|
|
596
|
+
HTML_ESCAPE = {'&' => '&', '<' => '<', '>' => '>', '"' => '"', "'" => '''}.freeze
|
|
524
597
|
|
|
525
|
-
|
|
526
|
-
# Include docs here so they are picked up by Yard
|
|
598
|
+
HTML_ESCAPE_REGEX = /['"><&]/
|
|
527
599
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
text.gsub(HTML_ESCAPE_REGEX, HTML_ESCAPE)
|
|
540
|
-
end
|
|
541
|
-
else
|
|
542
|
-
def html_escape(text)
|
|
543
|
-
text = text.to_s
|
|
544
|
-
text.gsub(HTML_ESCAPE_REGEX) {|s| HTML_ESCAPE[s]}
|
|
545
|
-
end
|
|
600
|
+
# Returns a copy of `text` with ampersands, angle brackets and quotes
|
|
601
|
+
# escaped into HTML entities.
|
|
602
|
+
#
|
|
603
|
+
# Note that if ActionView is loaded and XSS protection is enabled
|
|
604
|
+
# (as is the default for Rails 3.0+, and optional for version 2.3.5+),
|
|
605
|
+
# this won't escape text declared as "safe".
|
|
606
|
+
#
|
|
607
|
+
# @param text [String] The string to sanitize
|
|
608
|
+
# @return [String] The sanitized string
|
|
609
|
+
def html_escape(text)
|
|
610
|
+
CGI.escapeHTML(text.to_s)
|
|
546
611
|
end
|
|
547
612
|
|
|
548
|
-
|
|
613
|
+
# Always escape text regardless of html_safe?
|
|
614
|
+
alias_method :html_escape_without_haml_xss, :html_escape
|
|
549
615
|
|
|
550
|
-
|
|
551
|
-
# Include docs here so they are picked up by Yard
|
|
616
|
+
HTML_ESCAPE_ONCE_REGEX = /['"><]|&(?!(?:[a-zA-Z]+|#(?:\d+|[xX][0-9a-fA-F]+));)/
|
|
552
617
|
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
end
|
|
562
|
-
else
|
|
563
|
-
def escape_once(text)
|
|
564
|
-
text = text.to_s
|
|
565
|
-
text.gsub(HTML_ESCAPE_ONCE_REGEX){|s| HTML_ESCAPE[s]}
|
|
566
|
-
end
|
|
618
|
+
# Escapes HTML entities in `text`, but without escaping an ampersand
|
|
619
|
+
# that is already part of an escaped entity.
|
|
620
|
+
#
|
|
621
|
+
# @param text [String] The string to sanitize
|
|
622
|
+
# @return [String] The sanitized string
|
|
623
|
+
def escape_once(text)
|
|
624
|
+
text = text.to_s
|
|
625
|
+
text.gsub(HTML_ESCAPE_ONCE_REGEX, HTML_ESCAPE)
|
|
567
626
|
end
|
|
568
627
|
|
|
628
|
+
# Always escape text once regardless of html_safe?
|
|
629
|
+
alias_method :escape_once_without_haml_xss, :escape_once
|
|
630
|
+
|
|
569
631
|
# Returns whether or not the current template is a Haml template.
|
|
570
632
|
#
|
|
571
633
|
# This function, unlike other {Haml::Helpers} functions,
|
|
@@ -593,7 +655,7 @@ MESSAGE
|
|
|
593
655
|
# skip merging if no ids or classes found in name
|
|
594
656
|
return name, attributes_hash unless name =~ /^(.+?)?([\.#].*)$/
|
|
595
657
|
|
|
596
|
-
return $1 || "div",
|
|
658
|
+
return $1 || "div", AttributeBuilder.merge_attributes!(
|
|
597
659
|
Haml::Parser.parse_class_and_id($2), attributes_hash)
|
|
598
660
|
end
|
|
599
661
|
|
|
@@ -630,22 +692,6 @@ MESSAGE
|
|
|
630
692
|
_erbout = _erbout = _hamlout.buffer
|
|
631
693
|
proc { |*args| proc.call(*args) }
|
|
632
694
|
end
|
|
633
|
-
|
|
634
|
-
def prettify(text)
|
|
635
|
-
text = text.split(/^/)
|
|
636
|
-
text.delete('')
|
|
637
|
-
|
|
638
|
-
min_tabs = nil
|
|
639
|
-
text.each do |line|
|
|
640
|
-
tabs = line.index(/[^ ]/) || line.length
|
|
641
|
-
min_tabs ||= tabs
|
|
642
|
-
min_tabs = min_tabs > tabs ? tabs : min_tabs
|
|
643
|
-
end
|
|
644
|
-
|
|
645
|
-
text.map do |line|
|
|
646
|
-
line.slice(min_tabs, line.length)
|
|
647
|
-
end.join
|
|
648
|
-
end
|
|
649
695
|
end
|
|
650
696
|
end
|
|
651
697
|
|
|
@@ -661,4 +707,3 @@ class Object
|
|
|
661
707
|
false
|
|
662
708
|
end
|
|
663
709
|
end
|
|
664
|
-
|