haml 4.0.0 → 5.0.0
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 +7 -0
- data/.yardopts +1 -1
- data/CHANGELOG.md +117 -5
- data/FAQ.md +7 -17
- data/MIT-LICENSE +1 -1
- data/README.md +85 -42
- data/REFERENCE.md +181 -86
- data/Rakefile +47 -51
- data/lib/haml/attribute_builder.rb +163 -0
- data/lib/haml/attribute_compiler.rb +215 -0
- data/lib/haml/attribute_parser.rb +144 -0
- data/lib/haml/buffer.rb +38 -128
- data/lib/haml/compiler.rb +88 -295
- data/lib/haml/engine.rb +25 -41
- data/lib/haml/error.rb +3 -0
- data/lib/haml/escapable.rb +49 -0
- data/lib/haml/exec.rb +33 -19
- data/lib/haml/filters.rb +20 -24
- data/lib/haml/generator.rb +41 -0
- data/lib/haml/helpers/action_view_extensions.rb +3 -2
- data/lib/haml/helpers/action_view_mods.rb +44 -66
- data/lib/haml/helpers/action_view_xss_mods.rb +1 -0
- data/lib/haml/helpers/safe_erubi_template.rb +27 -0
- data/lib/haml/helpers/safe_erubis_template.rb +16 -4
- data/lib/haml/helpers/xss_mods.rb +18 -12
- data/lib/haml/helpers.rb +122 -58
- data/lib/haml/options.rb +39 -46
- data/lib/haml/parser.rb +278 -217
- data/lib/haml/{template/plugin.rb → plugin.rb} +8 -15
- data/lib/haml/railtie.rb +21 -11
- data/lib/haml/sass_rails_filter.rb +17 -4
- data/lib/haml/template/options.rb +12 -2
- data/lib/haml/template.rb +12 -6
- data/lib/haml/temple_engine.rb +120 -0
- data/lib/haml/temple_line_counter.rb +29 -0
- data/lib/haml/util.rb +80 -199
- data/lib/haml/version.rb +2 -1
- data/lib/haml.rb +2 -1
- data/test/attribute_parser_test.rb +101 -0
- data/test/engine_test.rb +306 -176
- data/test/filters_test.rb +32 -19
- data/test/gemfiles/Gemfile.rails-4.0.x +11 -0
- data/test/gemfiles/Gemfile.rails-4.0.x.lock +87 -0
- data/test/gemfiles/Gemfile.rails-4.1.x +5 -0
- data/test/gemfiles/Gemfile.rails-4.2.x +5 -0
- data/test/gemfiles/Gemfile.rails-5.0.x +4 -0
- data/test/helper_test.rb +282 -96
- data/test/options_test.rb +22 -0
- data/test/parser_test.rb +71 -4
- data/test/results/bemit.xhtml +4 -0
- data/test/results/eval_suppressed.xhtml +4 -4
- data/test/results/helpers.xhtml +43 -41
- data/test/results/helpful.xhtml +6 -3
- data/test/results/just_stuff.xhtml +21 -20
- data/test/results/list.xhtml +9 -9
- data/test/results/nuke_inner_whitespace.xhtml +22 -22
- data/test/results/nuke_outer_whitespace.xhtml +84 -92
- data/test/results/original_engine.xhtml +17 -17
- data/test/results/partial_layout.xhtml +4 -3
- data/test/results/partial_layout_erb.xhtml +4 -3
- data/test/results/partials.xhtml +11 -10
- data/test/results/silent_script.xhtml +63 -63
- data/test/results/standard.xhtml +156 -159
- data/test/results/tag_parsing.xhtml +19 -19
- data/test/results/very_basic.xhtml +2 -2
- data/test/results/whitespace_handling.xhtml +56 -50
- data/test/template_test.rb +44 -53
- data/test/template_test_helper.rb +38 -0
- data/test/templates/_text_area_helper.html.haml +4 -0
- data/test/templates/bemit.haml +3 -0
- data/test/templates/just_stuff.haml +1 -0
- data/test/templates/partial_layout_erb.erb +1 -1
- data/test/templates/standard_ugly.haml +1 -0
- data/test/templates/with_bom.haml +1 -0
- data/test/temple_line_counter_test.rb +40 -0
- data/test/test_helper.rb +26 -12
- data/test/util_test.rb +6 -47
- metadata +88 -106
- data/lib/haml/helpers/rails_323_textarea_fix.rb +0 -24
- 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-master +0 -4
- data/test/templates/_av_partial_1_ugly.haml +0 -9
- data/test/templates/_av_partial_2_ugly.haml +0 -5
- data/test/templates/action_view_ugly.haml +0 -47
- data/test/templates/standard_ugly.haml +0 -43
data/lib/haml/compiler.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: false
|
2
|
+
require 'haml/attribute_builder'
|
3
|
+
require 'haml/attribute_compiler'
|
4
|
+
require 'haml/temple_line_counter'
|
2
5
|
|
3
6
|
module Haml
|
4
7
|
class Compiler
|
@@ -7,15 +10,20 @@ module Haml
|
|
7
10
|
attr_accessor :options
|
8
11
|
|
9
12
|
def initialize(options)
|
10
|
-
@options = options
|
11
|
-
@output_tabs = 0
|
13
|
+
@options = Options.wrap(options)
|
12
14
|
@to_merge = []
|
13
|
-
@
|
15
|
+
@temple = [:multi]
|
16
|
+
@node = nil
|
17
|
+
@attribute_compiler = AttributeCompiler.new(@options)
|
18
|
+
end
|
19
|
+
|
20
|
+
def call(node)
|
21
|
+
compile(node)
|
22
|
+
@temple
|
14
23
|
end
|
15
24
|
|
16
25
|
def compile(node)
|
17
|
-
parent
|
18
|
-
@node = node
|
26
|
+
parent, @node = @node, node
|
19
27
|
if node.children.empty?
|
20
28
|
send(:"compile_#{node.type}")
|
21
29
|
else
|
@@ -25,79 +33,16 @@ module Haml
|
|
25
33
|
@node = parent
|
26
34
|
end
|
27
35
|
|
28
|
-
if RUBY_VERSION < "1.9"
|
29
|
-
# The source code that is evaluated to produce the Haml document.
|
30
|
-
#
|
31
|
-
# In Ruby 1.9, this is automatically converted to the correct encoding
|
32
|
-
# (see {file:REFERENCE.md#encodings the `:encoding` option}).
|
33
|
-
#
|
34
|
-
# @return [String]
|
35
|
-
def precompiled
|
36
|
-
@precompiled
|
37
|
-
end
|
38
|
-
else
|
39
|
-
def precompiled
|
40
|
-
encoding = Encoding.find(@options[:encoding])
|
41
|
-
return @precompiled.force_encoding(encoding) if encoding == Encoding::BINARY
|
42
|
-
return @precompiled.encode(encoding)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def precompiled_with_return_value
|
47
|
-
precompiled + ";" + precompiled_method_return_value
|
48
|
-
end
|
49
|
-
|
50
|
-
# Returns the precompiled string with the preamble and postamble.
|
51
|
-
#
|
52
|
-
# Initializes to ActionView::OutputBuffer when available; this is necessary
|
53
|
-
# to avoid ordering issues with partial layouts in Rails. If not available,
|
54
|
-
# initializes to nil.
|
55
|
-
def precompiled_with_ambles(local_names)
|
56
|
-
preamble = <<END.gsub("\n", ";")
|
57
|
-
begin
|
58
|
-
extend Haml::Helpers
|
59
|
-
_hamlout = @haml_buffer = Haml::Buffer.new(haml_buffer, #{options.for_buffer.inspect})
|
60
|
-
_erbout = _hamlout.buffer
|
61
|
-
@output_buffer = output_buffer ||= ActionView::OutputBuffer.new rescue nil
|
62
|
-
END
|
63
|
-
postamble = <<END.gsub("\n", ";")
|
64
|
-
#{precompiled_method_return_value}
|
65
|
-
ensure
|
66
|
-
@haml_buffer = @haml_buffer.upper if @haml_buffer
|
67
|
-
end
|
68
|
-
END
|
69
|
-
preamble + locals_code(local_names) + precompiled + postamble
|
70
|
-
end
|
71
|
-
|
72
36
|
private
|
73
37
|
|
74
|
-
# Returns the string used as the return value of the precompiled method.
|
75
|
-
# This method exists so it can be monkeypatched to return modified values.
|
76
|
-
def precompiled_method_return_value
|
77
|
-
"_erbout"
|
78
|
-
end
|
79
|
-
|
80
|
-
def locals_code(names)
|
81
|
-
names = names.keys if Hash == names
|
82
|
-
|
83
|
-
names.map do |name|
|
84
|
-
# Can't use || because someone might explicitly pass in false with a symbol
|
85
|
-
sym_local = "_haml_locals[#{inspect_obj(name.to_sym)}]"
|
86
|
-
str_local = "_haml_locals[#{inspect_obj(name.to_s)}]"
|
87
|
-
"#{name} = #{sym_local}.nil? ? #{str_local} : #{sym_local}"
|
88
|
-
end.join(';') + ';'
|
89
|
-
end
|
90
|
-
|
91
38
|
def compile_root
|
92
|
-
@dont_indent_next_line = @dont_tab_up_next_text = false
|
93
39
|
@output_line = 1
|
94
|
-
|
95
|
-
yield
|
40
|
+
yield if block_given?
|
96
41
|
flush_merged_text
|
97
42
|
end
|
98
43
|
|
99
44
|
def compile_plain
|
100
|
-
push_text
|
45
|
+
push_text("#{@node.value[:text]}\n")
|
101
46
|
end
|
102
47
|
|
103
48
|
def nuke_inner_whitespace?(node)
|
@@ -119,15 +64,11 @@ END
|
|
119
64
|
end
|
120
65
|
|
121
66
|
def compile_silent_script
|
122
|
-
return if @options
|
67
|
+
return if @options.suppress_eval
|
123
68
|
push_silent(@node.value[:text])
|
124
69
|
keyword = @node.value[:keyword]
|
125
70
|
|
126
71
|
if block_given?
|
127
|
-
# Store these values because for conditional statements,
|
128
|
-
# we want to restore them for each branch
|
129
|
-
@node.value[:dont_indent_next_line] = @dont_indent_next_line
|
130
|
-
@node.value[:dont_tab_up_next_text] = @dont_tab_up_next_text
|
131
72
|
yield
|
132
73
|
push_silent("end", :can_suppress) unless @node.value[:dont_push_end]
|
133
74
|
elsif keyword == "end"
|
@@ -137,10 +78,6 @@ END
|
|
137
78
|
@node.parent.value[:dont_push_end] = true
|
138
79
|
end
|
139
80
|
# Don't restore dont_* for end because it isn't a conditional branch.
|
140
|
-
elsif Parser::MID_BLOCK_KEYWORDS.include?(keyword)
|
141
|
-
# Restore dont_* for this conditional branch
|
142
|
-
@dont_indent_next_line = @node.parent.value[:dont_indent_next_line]
|
143
|
-
@dont_tab_up_next_text = @node.parent.value[:dont_tab_up_next_text]
|
144
81
|
end
|
145
82
|
end
|
146
83
|
|
@@ -152,113 +89,82 @@ END
|
|
152
89
|
# Get rid of whitespace outside of the tag if we need to
|
153
90
|
rstrip_buffer! if t[:nuke_outer_whitespace]
|
154
91
|
|
155
|
-
|
156
|
-
|
157
|
-
(t[:nuke_inner_whitespace] && block_given?)
|
158
|
-
|
159
|
-
if @options[:suppress_eval]
|
160
|
-
object_ref = "nil"
|
92
|
+
if @options.suppress_eval
|
93
|
+
object_ref = :nil
|
161
94
|
parse = false
|
162
95
|
value = t[:parse] ? nil : t[:value]
|
163
|
-
|
96
|
+
dynamic_attributes = Haml::Parser::DynamicAttributes.new
|
164
97
|
preserve_script = false
|
165
98
|
else
|
166
99
|
object_ref = t[:object_ref]
|
167
100
|
parse = t[:parse]
|
168
101
|
value = t[:value]
|
169
|
-
|
102
|
+
dynamic_attributes = t[:dynamic_attributes]
|
170
103
|
preserve_script = t[:preserve_script]
|
171
104
|
end
|
172
105
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
open_tag = prerender_tag(t[:name], t[:self_closing], t[:attributes])
|
178
|
-
if tag_closed
|
179
|
-
open_tag << "#{value}</#{t[:name]}>"
|
180
|
-
open_tag << "\n" unless t[:nuke_outer_whitespace]
|
181
|
-
elsif !(parse || t[:nuke_inner_whitespace] ||
|
182
|
-
(t[:self_closing] && t[:nuke_outer_whitespace]))
|
183
|
-
open_tag << "\n"
|
184
|
-
end
|
185
|
-
|
186
|
-
push_merged_text(open_tag,
|
187
|
-
tag_closed || t[:self_closing] || t[:nuke_inner_whitespace] ? 0 : 1,
|
188
|
-
!t[:nuke_outer_whitespace])
|
106
|
+
if @options[:trace]
|
107
|
+
t[:attributes].merge!({"data-trace" => @options.filename.split('/views').last << ":" << @node.line.to_s})
|
108
|
+
end
|
189
109
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
if
|
194
|
-
|
195
|
-
elsif attributes_hashes.size == 1
|
196
|
-
attributes_hashes = ", #{attributes_hashes.first}"
|
110
|
+
push_text("<#{t[:name]}")
|
111
|
+
push_temple(@attribute_compiler.compile(t[:attributes], object_ref, dynamic_attributes))
|
112
|
+
push_text(
|
113
|
+
if t[:self_closing] && @options.xhtml?
|
114
|
+
" />#{"\n" unless t[:nuke_outer_whitespace]}"
|
197
115
|
else
|
198
|
-
|
116
|
+
">#{"\n" unless (t[:self_closing] && @options.html?) ? t[:nuke_outer_whitespace] : (!block_given? || t[:preserve_tag] || t[:nuke_inner_whitespace])}"
|
199
117
|
end
|
118
|
+
)
|
200
119
|
|
201
|
-
|
202
|
-
|
203
|
-
"_hamlout.attributes(#{inspect_obj(t[:attributes])}, #{object_ref}#{attributes_hashes})")
|
204
|
-
concat_merged_text(
|
205
|
-
if t[:self_closing] && @options.xhtml?
|
206
|
-
" />" + (t[:nuke_outer_whitespace] ? "" : "\n")
|
207
|
-
else
|
208
|
-
">" + ((if t[:self_closing] && @options.html?
|
209
|
-
t[:nuke_outer_whitespace]
|
210
|
-
else
|
211
|
-
!block_given? || t[:preserve_tag] || t[:nuke_inner_whitespace]
|
212
|
-
end) ? "" : "\n")
|
213
|
-
end)
|
214
|
-
|
215
|
-
if value && !parse
|
216
|
-
concat_merged_text("#{value}</#{t[:name]}>#{t[:nuke_outer_whitespace] ? "" : "\n"}")
|
217
|
-
elsif !t[:nuke_inner_whitespace] && !t[:self_closing]
|
218
|
-
@to_merge << [:text, '', 1]
|
219
|
-
end
|
220
|
-
|
221
|
-
@dont_indent_next_line = dont_indent_next_line
|
120
|
+
if value && !parse
|
121
|
+
push_text("#{value}</#{t[:name]}>#{"\n" unless t[:nuke_outer_whitespace]}")
|
222
122
|
end
|
223
123
|
|
224
124
|
return if t[:self_closing]
|
225
125
|
|
226
126
|
if value.nil?
|
227
|
-
@output_tabs += 1 unless t[:nuke_inner_whitespace]
|
228
127
|
yield if block_given?
|
229
|
-
@output_tabs -= 1 unless t[:nuke_inner_whitespace]
|
230
128
|
rstrip_buffer! if t[:nuke_inner_whitespace]
|
231
|
-
|
232
|
-
t[:nuke_inner_whitespace] ? 0 : -1, !t[:nuke_inner_whitespace])
|
233
|
-
@dont_indent_next_line = t[:nuke_outer_whitespace]
|
129
|
+
push_text("</#{t[:name]}>#{"\n" unless t[:nuke_outer_whitespace]}")
|
234
130
|
return
|
235
131
|
end
|
236
132
|
|
237
133
|
if parse
|
238
134
|
push_script(value, t.merge(:in_tag => true))
|
239
|
-
|
135
|
+
push_text("</#{t[:name]}>#{"\n" unless t[:nuke_outer_whitespace]}")
|
240
136
|
end
|
241
137
|
end
|
242
138
|
|
243
139
|
def compile_comment
|
244
|
-
|
140
|
+
condition = "#{@node.value[:conditional]}>" if @node.value[:conditional]
|
141
|
+
revealed = @node.value[:revealed]
|
142
|
+
|
143
|
+
open = "<!--#{condition}#{'<!-->' if revealed}"
|
144
|
+
|
145
|
+
close = "#{'<!--' if revealed}#{'<![endif]' if condition}-->"
|
245
146
|
|
246
|
-
# Render it statically if possible
|
247
147
|
unless block_given?
|
248
|
-
push_text("#{open}
|
148
|
+
push_text("#{open} ")
|
149
|
+
|
150
|
+
if @node.value[:parse]
|
151
|
+
push_script(@node.value[:text], :in_tag => true, :nuke_inner_whitespace => true)
|
152
|
+
else
|
153
|
+
push_text(@node.value[:text])
|
154
|
+
end
|
155
|
+
|
156
|
+
push_text(" #{close}\n")
|
249
157
|
return
|
250
158
|
end
|
251
159
|
|
252
|
-
push_text(open
|
253
|
-
@output_tabs += 1
|
160
|
+
push_text("#{open}\n")
|
254
161
|
yield if block_given?
|
255
|
-
|
256
|
-
push_text(@node.value[:conditional] ? "<![endif]-->" : "-->", -1)
|
162
|
+
push_text("#{close}\n")
|
257
163
|
end
|
258
164
|
|
259
165
|
def compile_doctype
|
260
166
|
doctype = text_for_doctype
|
261
|
-
push_text
|
167
|
+
push_text("#{doctype}\n") if doctype
|
262
168
|
end
|
263
169
|
|
264
170
|
def compile_filter
|
@@ -276,7 +182,7 @@ END
|
|
276
182
|
def text_for_doctype
|
277
183
|
if @node.value[:type] == "xml"
|
278
184
|
return nil if @options.html?
|
279
|
-
wrapper = @options
|
185
|
+
wrapper = @options.attr_wrapper
|
280
186
|
return "<?xml version=#{wrapper}1.0#{wrapper} encoding=#{wrapper}#{@node.value[:encoding] || "utf-8"}#{wrapper} ?>"
|
281
187
|
end
|
282
188
|
|
@@ -315,83 +221,52 @@ END
|
|
315
221
|
flush_merged_text
|
316
222
|
return if can_suppress && @options.suppress_eval?
|
317
223
|
newline = (text == "end") ? ";" : "\n"
|
318
|
-
@
|
319
|
-
@output_line
|
320
|
-
end
|
321
|
-
|
322
|
-
# Adds `text` to `@buffer` with appropriate tabulation
|
323
|
-
# without parsing it.
|
324
|
-
def push_merged_text(text, tab_change = 0, indent = true)
|
325
|
-
text = !indent || @dont_indent_next_line || @options[:ugly] ? text : "#{' ' * @output_tabs}#{text}"
|
326
|
-
@to_merge << [:text, text, tab_change]
|
327
|
-
@dont_indent_next_line = false
|
224
|
+
@temple << [:code, "#{resolve_newlines}#{text}#{newline}"]
|
225
|
+
@output_line = @output_line + text.count("\n") + newline.count("\n")
|
328
226
|
end
|
329
227
|
|
330
|
-
#
|
331
|
-
def
|
332
|
-
@to_merge << [:text, text
|
228
|
+
# Adds `text` to `@buffer`.
|
229
|
+
def push_text(text)
|
230
|
+
@to_merge << [:text, text]
|
333
231
|
end
|
334
232
|
|
335
|
-
def
|
336
|
-
|
233
|
+
def push_temple(temple)
|
234
|
+
flush_merged_text
|
235
|
+
@temple.concat([[:newline]] * resolve_newlines.count("\n"))
|
236
|
+
@temple << temple
|
237
|
+
@output_line += TempleLineCounter.count_lines(temple)
|
337
238
|
end
|
338
239
|
|
339
240
|
def flush_merged_text
|
340
241
|
return if @to_merge.empty?
|
341
242
|
|
342
|
-
|
343
|
-
mtabs = 0
|
344
|
-
@to_merge.each do |type, val, tabs|
|
243
|
+
@to_merge.each do |type, val|
|
345
244
|
case type
|
346
245
|
when :text
|
347
|
-
|
348
|
-
mtabs += tabs
|
246
|
+
@temple << [:static, val]
|
349
247
|
when :script
|
350
|
-
|
351
|
-
val = "_hamlout.adjust_tabs(#{mtabs}); " + val
|
352
|
-
end
|
353
|
-
str << "\#{#{val}}"
|
354
|
-
mtabs = 0
|
248
|
+
@temple << [:dynamic, val]
|
355
249
|
else
|
356
250
|
raise SyntaxError.new("[HAML BUG] Undefined entry in Haml::Compiler@to_merge.")
|
357
251
|
end
|
358
252
|
end
|
359
253
|
|
360
|
-
unless str.empty?
|
361
|
-
@precompiled <<
|
362
|
-
if @options[:ugly]
|
363
|
-
"_hamlout.buffer << \"#{str}\";"
|
364
|
-
else
|
365
|
-
"_hamlout.push_text(\"#{str}\", #{mtabs}, #{@dont_tab_up_next_text.inspect});"
|
366
|
-
end
|
367
|
-
end
|
368
254
|
@to_merge = []
|
369
|
-
@dont_tab_up_next_text = false
|
370
255
|
end
|
371
256
|
|
372
257
|
# Causes `text` to be evaluated in the context of
|
373
258
|
# the scope object and the result to be added to `@buffer`.
|
374
259
|
#
|
375
|
-
# If `opts[:preserve_script]` is true, Haml::Helpers#
|
260
|
+
# If `opts[:preserve_script]` is true, Haml::Helpers#find_and_preserve is run on
|
376
261
|
# the result before it is added to `@buffer`
|
377
262
|
def push_script(text, opts = {})
|
378
263
|
return if @options.suppress_eval?
|
379
264
|
|
380
|
-
|
381
|
-
args.map! {|name| opts[name.to_sym]}
|
382
|
-
args << !block_given? << @options[:ugly]
|
383
|
-
|
384
|
-
no_format = @options[:ugly] &&
|
385
|
-
!(opts[:preserve_script] || opts[:preserve_tag] || opts[:escape_html])
|
386
|
-
output_expr = "(#{text}\n)"
|
387
|
-
static_method = "_hamlout.#{static_method_name(:format_script, *args)}"
|
388
|
-
|
389
|
-
# Prerender tabulation unless we're in a tag
|
390
|
-
push_merged_text '' unless opts[:in_tag]
|
265
|
+
no_format = !(opts[:preserve_script] || opts[:preserve_tag] || opts[:escape_html])
|
391
266
|
|
392
267
|
unless block_given?
|
393
|
-
push_generated_script(no_format ? "#{text}\n" : "
|
394
|
-
|
268
|
+
push_generated_script(no_format ? "(#{text}\n).to_s" : build_script_formatter("(#{text}\n)", opts))
|
269
|
+
push_text("\n") unless opts[:in_tag] || opts[:nuke_inner_whitespace]
|
395
270
|
return
|
396
271
|
end
|
397
272
|
|
@@ -399,116 +274,35 @@ END
|
|
399
274
|
push_silent "haml_temp = #{text}"
|
400
275
|
yield
|
401
276
|
push_silent('end', :can_suppress) unless @node.value[:dont_push_end]
|
402
|
-
@
|
403
|
-
concat_merged_text("\n") unless opts[:in_tag] || opts[:nuke_inner_whitespace] || @options[:ugly]
|
277
|
+
@temple << [:dynamic, no_format ? 'haml_temp.to_s;' : build_script_formatter('haml_temp', opts)]
|
404
278
|
end
|
405
279
|
|
406
|
-
def
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
# This is a class method so it can be accessed from Buffer.
|
412
|
-
def self.build_attributes(is_html, attr_wrapper, escape_attrs, hyphenate_data_attrs, attributes = {})
|
413
|
-
# @TODO this is an absolutely ridiculous amount of arguments. At least
|
414
|
-
# some of this needs to be moved into an instance method.
|
415
|
-
quote_escape = attr_wrapper == '"' ? """ : "'"
|
416
|
-
other_quote_char = attr_wrapper == '"' ? "'" : '"'
|
417
|
-
join_char = hyphenate_data_attrs ? '-' : '_'
|
418
|
-
|
419
|
-
attributes.each do |key, value|
|
420
|
-
if value.is_a?(Hash)
|
421
|
-
data_attributes = attributes.delete(key)
|
422
|
-
data_attributes = flatten_data_attributes(data_attributes, '', join_char)
|
423
|
-
data_attributes = build_data_keys(data_attributes, hyphenate_data_attrs, key)
|
424
|
-
attributes = data_attributes.merge(attributes)
|
425
|
-
end
|
426
|
-
end
|
427
|
-
|
428
|
-
result = attributes.collect do |attr, value|
|
429
|
-
next if value.nil?
|
430
|
-
|
431
|
-
value = filter_and_join(value, ' ') if attr == 'class'
|
432
|
-
value = filter_and_join(value, '_') if attr == 'id'
|
433
|
-
|
434
|
-
if value == true
|
435
|
-
next " #{attr}" if is_html
|
436
|
-
next " #{attr}=#{attr_wrapper}#{attr}#{attr_wrapper}"
|
437
|
-
elsif value == false
|
438
|
-
next
|
439
|
-
end
|
440
|
-
|
441
|
-
escaped =
|
442
|
-
if escape_attrs == :once
|
443
|
-
Haml::Helpers.escape_once(value.to_s)
|
444
|
-
elsif escape_attrs
|
445
|
-
Haml::Helpers.html_escape(value.to_s)
|
446
|
-
else
|
447
|
-
value.to_s
|
448
|
-
end
|
449
|
-
value = Haml::Helpers.preserve(escaped)
|
450
|
-
if escape_attrs
|
451
|
-
# We want to decide whether or not to escape quotes
|
452
|
-
value = value.gsub('"', '"').gsub('"', '"')
|
453
|
-
this_attr_wrapper = attr_wrapper
|
454
|
-
if value.include? attr_wrapper
|
455
|
-
if value.include? other_quote_char
|
456
|
-
value = value.gsub(attr_wrapper, quote_escape)
|
457
|
-
else
|
458
|
-
this_attr_wrapper = other_quote_char
|
459
|
-
end
|
460
|
-
end
|
461
|
-
else
|
462
|
-
this_attr_wrapper = attr_wrapper
|
463
|
-
end
|
464
|
-
" #{attr}=#{this_attr_wrapper}#{value}#{this_attr_wrapper}"
|
280
|
+
def build_script_formatter(text, opts)
|
281
|
+
text = "(#{text}).to_s"
|
282
|
+
if opts[:escape_html]
|
283
|
+
text = "::Haml::Helpers.html_escape(#{text})"
|
465
284
|
end
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
def self.filter_and_join(value, separator)
|
470
|
-
return "" if value == ""
|
471
|
-
value = [value] unless value.is_a?(Array)
|
472
|
-
value = value.flatten.collect {|item| item ? item.to_s : nil}.compact.join(separator)
|
473
|
-
return !value.empty? && value
|
474
|
-
end
|
475
|
-
|
476
|
-
def self.build_data_keys(data_hash, hyphenate, attr_name="data")
|
477
|
-
Hash[data_hash.map do |name, value|
|
478
|
-
if name == nil
|
479
|
-
[attr_name, value]
|
480
|
-
elsif hyphenate
|
481
|
-
["#{attr_name}-#{name.to_s.gsub(/_/, '-')}", value]
|
482
|
-
else
|
483
|
-
["#{attr_name}-#{name}", value]
|
484
|
-
end
|
485
|
-
end]
|
486
|
-
end
|
487
|
-
|
488
|
-
def self.flatten_data_attributes(data, key, join_char, seen = [])
|
489
|
-
return {key => nil} if seen.include? data.object_id
|
490
|
-
seen << data.object_id
|
491
|
-
|
492
|
-
return {key => data} unless data.is_a?(Hash)
|
493
|
-
data.sort {|x, y| x[0].to_s <=> y[0].to_s}.inject({}) do |hash, array|
|
494
|
-
k, v = array
|
495
|
-
joined = key == '' ? k : [key, k].join(join_char)
|
496
|
-
hash.merge! flatten_data_attributes(v, joined, join_char, seen)
|
285
|
+
if opts[:nuke_inner_whitespace]
|
286
|
+
text = "(#{text}).strip"
|
497
287
|
end
|
288
|
+
if opts[:preserve_tag]
|
289
|
+
text = "::Haml::Helpers.preserve(#{text})"
|
290
|
+
elsif opts[:preserve_script]
|
291
|
+
text = "::Haml::Helpers.find_and_preserve(#{text}, _hamlout.options[:preserve])"
|
292
|
+
end
|
293
|
+
"_hamlout.fix_textareas!(#{text});"
|
498
294
|
end
|
499
295
|
|
500
|
-
def
|
501
|
-
|
502
|
-
|
503
|
-
@options.html?, @options[:attr_wrapper], @options[:escape_attrs], @options[:hyphenate_data_attrs], attributes)
|
504
|
-
"<#{name}#{attributes_string}#{self_close && @options.xhtml? ? ' /' : ''}>"
|
296
|
+
def push_generated_script(text)
|
297
|
+
@to_merge << [:script, resolve_newlines + text]
|
298
|
+
@output_line += text.count("\n")
|
505
299
|
end
|
506
300
|
|
507
301
|
def resolve_newlines
|
508
302
|
diff = @node.line - @output_line
|
509
303
|
return "" if diff <= 0
|
510
304
|
@output_line = @node.line
|
511
|
-
"\n" *
|
305
|
+
"\n" * diff
|
512
306
|
end
|
513
307
|
|
514
308
|
# Get rid of and whitespace at the end of the buffer
|
@@ -517,7 +311,6 @@ END
|
|
517
311
|
last = @to_merge[index]
|
518
312
|
if last.nil?
|
519
313
|
push_silent("_hamlout.rstrip!", false)
|
520
|
-
@dont_tab_up_next_text = true
|
521
314
|
return
|
522
315
|
end
|
523
316
|
|