wunderbar 0.17.3 → 0.18.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.
- data/README.md +29 -3
- data/lib/wunderbar/builder.rb +95 -139
- data/lib/wunderbar/cgi-methods.rb +7 -7
- data/lib/wunderbar/cssproxy.rb +20 -50
- data/lib/wunderbar/environment.rb +11 -1
- data/lib/wunderbar/html-methods.rb +161 -133
- data/lib/wunderbar/node.rb +208 -0
- data/lib/wunderbar/polymer-v0.0.20131003.min.js +36 -0
- data/lib/wunderbar/polymer.rb +56 -0
- data/lib/wunderbar/rails.rb +1 -1
- data/lib/wunderbar/server.rb +17 -0
- data/lib/wunderbar/sinatra.rb +8 -8
- data/lib/wunderbar/version.rb +2 -2
- data/lib/wunderbar.rb +1 -1
- data/wunderbar.gemspec +5 -8
- metadata +12 -19
- checksums.yaml +0 -15
@@ -1,6 +1,30 @@
|
|
1
1
|
# Wrapper class that understands HTML
|
2
2
|
module Wunderbar
|
3
|
-
|
3
|
+
# factored out so that these methods can be overriden (e.g., by opal.rb)
|
4
|
+
class Overridable < BuilderBase
|
5
|
+
def _script(*args, &block)
|
6
|
+
args << {} unless Hash === args.last
|
7
|
+
args.last[:lang] ||= 'text/javascript'
|
8
|
+
args.unshift ScriptNode
|
9
|
+
proxiable_tag! 'script', *args, &block
|
10
|
+
end
|
11
|
+
|
12
|
+
def _style(*args, &block)
|
13
|
+
if args == [:system]
|
14
|
+
args[0] = %{
|
15
|
+
pre._stdin {font-weight: bold; color: #800080; margin: 1em 0 0 0}
|
16
|
+
pre._stdout {font-weight: bold; color: #000; margin: 0}
|
17
|
+
pre._stderr {font-weight: bold; color: #F00; margin: 0}
|
18
|
+
}
|
19
|
+
end
|
20
|
+
args << {} unless Hash === args.last
|
21
|
+
args.last[:type] ||= 'text/css'
|
22
|
+
args.unshift StyleNode
|
23
|
+
proxiable_tag! 'style', *args, &block
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class HtmlMarkup < Overridable
|
4
28
|
VOID = %w(
|
5
29
|
area base br col command embed hr img input keygen
|
6
30
|
link meta param source track wbr
|
@@ -13,9 +37,11 @@ module Wunderbar
|
|
13
37
|
hr noscript ol output p pre section table tfoot ul video
|
14
38
|
)
|
15
39
|
|
40
|
+
HEAD = %w(title base link style meta)
|
41
|
+
|
16
42
|
def initialize(scope)
|
17
43
|
@_scope = scope
|
18
|
-
@x = XmlMarkup.new :scope => scope, :indent => 2
|
44
|
+
@x = XmlMarkup.new :scope => scope, :indent => 2
|
19
45
|
end
|
20
46
|
|
21
47
|
def html(*args, &block)
|
@@ -23,21 +49,66 @@ module Wunderbar
|
|
23
49
|
args << {} if args.empty?
|
24
50
|
if Hash === args.first
|
25
51
|
args.first[:xmlns] ||= 'http://www.w3.org/1999/xhtml'
|
52
|
+
@_width = args.first.delete(:_width).to_i if args.first[:_width]
|
53
|
+
end
|
54
|
+
|
55
|
+
if ''.respond_to? :encoding
|
56
|
+
bom = "\ufeff"
|
57
|
+
else
|
58
|
+
bom = "\xEF\xBB\xBF"
|
26
59
|
end
|
27
|
-
@_width = args.first.delete(:_width) if Hash === args.first
|
28
60
|
|
29
|
-
@x.text! "\xEF\xBB\xBF"
|
30
61
|
@x.declare! :DOCTYPE, :html
|
31
|
-
|
62
|
+
html = tag! :html, *args do
|
32
63
|
set_variables_from_params
|
33
64
|
instance_eval(&block)
|
34
65
|
end
|
35
66
|
|
36
|
-
|
37
|
-
|
67
|
+
pending_head = []
|
68
|
+
pending_body = []
|
69
|
+
head = nil
|
70
|
+
body = nil
|
71
|
+
html.children.each do |child|
|
72
|
+
next unless child
|
73
|
+
if child.name == 'head'
|
74
|
+
head = child
|
75
|
+
elsif child.name == 'body'
|
76
|
+
body = child
|
77
|
+
elsif HEAD.include? child.name
|
78
|
+
pending_head << child
|
79
|
+
elsif child.name == 'script'
|
80
|
+
if pending_body.empty?
|
81
|
+
pending_head << child
|
82
|
+
else
|
83
|
+
pending_body << child
|
84
|
+
end
|
85
|
+
else
|
86
|
+
pending_body << child
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
@x.instance_eval {@node = html}
|
91
|
+
head = _head_ if not head
|
92
|
+
body = _body nil if not body
|
93
|
+
html.children.unshift(head.parent.children.delete(head))
|
94
|
+
html.children.push(body.parent.children.delete(body))
|
95
|
+
head.parent = body.parent = html
|
96
|
+
head.children.compact!
|
97
|
+
body.children.compact!
|
98
|
+
|
99
|
+
[ [pending_head, head], [pending_body, body] ].each do |list, node|
|
100
|
+
list.each do |child|
|
101
|
+
html.children.delete(child)
|
102
|
+
node.add_child child
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
if not head.children.any? {|child| child.name == 'title'}
|
107
|
+
h1 = body.children.find {|child| child.name == 'h1'}
|
108
|
+
head.add_child Node.new('title', h1.text) if h1 and h1.text
|
38
109
|
end
|
39
110
|
|
40
|
-
@x.target
|
111
|
+
bom + @x.target!
|
41
112
|
end
|
42
113
|
|
43
114
|
def _html(*args, &block)
|
@@ -45,7 +116,7 @@ module Wunderbar
|
|
45
116
|
end
|
46
117
|
|
47
118
|
def method_missing(name, *args, &block)
|
48
|
-
if name
|
119
|
+
if name =~ /^_(\w+)(!|\?|)$/
|
49
120
|
name, flag = $1, $2
|
50
121
|
elsif @_scope and @_scope.respond_to? name
|
51
122
|
return @_scope.__send__ name, *args, &block
|
@@ -56,69 +127,26 @@ module Wunderbar
|
|
56
127
|
end
|
57
128
|
|
58
129
|
if name.sub!(/_$/,'')
|
59
|
-
@x.
|
130
|
+
@x.spaced!
|
60
131
|
return __send__ "_#{name}", *args, &block if respond_to? "_#{name}"
|
61
132
|
end
|
62
133
|
|
63
|
-
|
64
|
-
if %w(script style).include?(name)
|
65
|
-
if String === args.first and not block
|
66
|
-
text = args.shift
|
67
|
-
if !text.include? '&' and !text.include? '<'
|
68
|
-
block = Proc.new do
|
69
|
-
@x.indented_data!(text)
|
70
|
-
end
|
71
|
-
elsif name == 'style'
|
72
|
-
block = Proc.new do
|
73
|
-
@x.indented_data!(text, "/*<![CDATA[*/", "/*]]>*/")
|
74
|
-
end
|
75
|
-
else
|
76
|
-
block = Proc.new do
|
77
|
-
@x.indented_data!(text, "//<![CDATA[", "//]]>")
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
args << {} if args.length == 0
|
83
|
-
if Hash === args.last
|
84
|
-
args.last[:lang] ||= 'text/javascript' if name == 'script'
|
85
|
-
args.last[:type] ||= 'text/css' if name == 'style'
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
# ensure that non-void elements are explicitly closed
|
90
|
-
if not block and not VOID.include?(name)
|
91
|
-
args[0] = '' if args.length > 1 and args.first == nil
|
92
|
-
symbol = (args.shift if args.length > 0 and Symbol === args.first)
|
93
|
-
if args.length == 0 or (args.length == 1 and Hash === args.first)
|
94
|
-
args.unshift ''
|
95
|
-
end
|
96
|
-
args.unshift(symbol) if symbol
|
97
|
-
end
|
134
|
+
name = name.to_s.gsub('_', '-')
|
98
135
|
|
136
|
+
if flag != '!'
|
99
137
|
if String === args.first and args.first.respond_to? :html_safe?
|
100
138
|
if args.first.html_safe? and not block and args.first =~ /[>&]/
|
101
139
|
markup = args.shift
|
102
140
|
block = Proc.new {_ {markup}}
|
103
141
|
end
|
104
142
|
end
|
105
|
-
|
106
|
-
if Hash === args.last
|
107
|
-
# remove attributes with nil, false values
|
108
|
-
args.last.delete_if {|key, value| !value}
|
109
|
-
|
110
|
-
# replace boolean 'true' attributes with the name of the attribute
|
111
|
-
args.last.each {|key, value| args.last[key]=key if value == true}
|
112
|
-
end
|
113
143
|
end
|
114
144
|
|
115
145
|
if flag == '!'
|
116
|
-
@x.
|
117
|
-
@x.tag! name, *args, &block
|
118
|
-
end
|
146
|
+
@x.compact!(@_width) { tag! name, *args, &block }
|
119
147
|
elsif flag == '?'
|
120
148
|
# capture exceptions, produce filtered tracebacks
|
121
|
-
|
149
|
+
tag!(name, *args) do
|
122
150
|
begin
|
123
151
|
block.call
|
124
152
|
rescue ::Exception => exception
|
@@ -127,14 +155,44 @@ module Wunderbar
|
|
127
155
|
_exception exception, options
|
128
156
|
end
|
129
157
|
end
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
158
|
+
elsif Wunderbar.templates.include? name
|
159
|
+
x = self.class.new({})
|
160
|
+
instance_variables.each do |ivar|
|
161
|
+
x.instance_variable_set ivar, instance_variable_get(ivar)
|
162
|
+
end
|
163
|
+
if Hash === args.last
|
164
|
+
args.last.each do |name, value|
|
165
|
+
x.instance_variable_set "@#{name}", value
|
135
166
|
end
|
136
167
|
end
|
137
|
-
|
168
|
+
save_yield = Wunderbar.templates['yield']
|
169
|
+
begin
|
170
|
+
Wunderbar.templates['yield'] = block if block
|
171
|
+
x.instance_eval &Wunderbar.templates[name]
|
172
|
+
ensure
|
173
|
+
Wunderbar.templates['yield'] = save_yield
|
174
|
+
Wunderbar.templates.delete 'yield' unless save_yield
|
175
|
+
end
|
176
|
+
else
|
177
|
+
tag! name, *args, &block
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def tag!(name, *args, &block)
|
182
|
+
node = @x.tag! name, *args, &block
|
183
|
+
if !block and args.empty?
|
184
|
+
CssProxy.new(self, node)
|
185
|
+
else
|
186
|
+
node
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def proxiable_tag!(name, *args, &block)
|
191
|
+
node = @x.tag! name, *args, &block
|
192
|
+
if !block
|
193
|
+
CssProxy.new(self, node)
|
194
|
+
else
|
195
|
+
node
|
138
196
|
end
|
139
197
|
end
|
140
198
|
|
@@ -157,9 +215,9 @@ module Wunderbar
|
|
157
215
|
end
|
158
216
|
|
159
217
|
if traceback_class
|
160
|
-
|
218
|
+
tag! :pre, text, :class=>traceback_class
|
161
219
|
else
|
162
|
-
|
220
|
+
tag! :pre, text, :style=>traceback_style
|
163
221
|
end
|
164
222
|
else
|
165
223
|
super
|
@@ -167,8 +225,8 @@ module Wunderbar
|
|
167
225
|
end
|
168
226
|
|
169
227
|
def _head(*args, &block)
|
170
|
-
|
171
|
-
|
228
|
+
tag!('head', *args) do
|
229
|
+
tag! :meta, :charset => 'utf-8'
|
172
230
|
block.call if block
|
173
231
|
instance_eval &Wunderbar::Asset.declarations
|
174
232
|
end
|
@@ -177,7 +235,7 @@ module Wunderbar
|
|
177
235
|
def _p(*args, &block)
|
178
236
|
if args.length >= 1 and String === args.first and args.first.include? "\n"
|
179
237
|
text = args.shift
|
180
|
-
|
238
|
+
tag! :p, *args do
|
181
239
|
@x.indented_text! text
|
182
240
|
end
|
183
241
|
else
|
@@ -188,7 +246,7 @@ module Wunderbar
|
|
188
246
|
def _svg(*args, &block)
|
189
247
|
args << {} if args.empty?
|
190
248
|
args.first['xmlns'] = 'http://www.w3.org/2000/svg' if Hash === args.first
|
191
|
-
|
249
|
+
proxiable_tag! :svg, *args, &block
|
192
250
|
end
|
193
251
|
|
194
252
|
def _math(*args, &block)
|
@@ -196,16 +254,46 @@ module Wunderbar
|
|
196
254
|
if Hash === args.first
|
197
255
|
args.first['xmlns'] = 'http://www.w3.org/1998/Math/MathML'
|
198
256
|
end
|
199
|
-
|
257
|
+
proxiable_tag! :math, *args, &block
|
200
258
|
end
|
201
259
|
|
202
260
|
def _pre(*args, &block)
|
203
261
|
args.first.chomp! if String === args.first and args.first.end_with? "\n"
|
204
|
-
@x.
|
262
|
+
@x.compact!(@_width) { tag! :pre, *args, &block }
|
263
|
+
end
|
264
|
+
|
265
|
+
def _ul(*args, &block)
|
266
|
+
iterable = args.first.respond_to? :each
|
267
|
+
if iterable and (args.length > 1 or not args.first.respond_to? :to_hash)
|
268
|
+
list = args.shift.dup
|
269
|
+
tag!(:ul, *args) {list.each {|arg| _li arg }}
|
270
|
+
else
|
271
|
+
super
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
def _ol(*args, &block)
|
276
|
+
iterable = args.first.respond_to? :each
|
277
|
+
if iterable and (args.length > 1 or not args.first.respond_to? :to_hash)
|
278
|
+
list = args.shift
|
279
|
+
tag!(:ol, *args) {list.each {|arg| _li arg }}
|
280
|
+
else
|
281
|
+
super
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
def _tr(*args, &block)
|
286
|
+
iterable = args.first.respond_to? :each
|
287
|
+
if iterable and (args.length > 1 or not args.first.respond_to? :to_hash)
|
288
|
+
list = args.shift
|
289
|
+
tag!(:tr, *args) {list.each {|arg| _td arg }}
|
290
|
+
else
|
291
|
+
super
|
292
|
+
end
|
205
293
|
end
|
206
294
|
|
207
295
|
def _!(text)
|
208
|
-
@x.text! text.to_s
|
296
|
+
@x.text! text.to_s.chomp
|
209
297
|
end
|
210
298
|
|
211
299
|
def _(text=nil, &block)
|
@@ -244,7 +332,7 @@ module Wunderbar
|
|
244
332
|
end
|
245
333
|
|
246
334
|
def clear!
|
247
|
-
@x.
|
335
|
+
@x.clear!
|
248
336
|
end
|
249
337
|
|
250
338
|
def self.flatten?(children)
|
@@ -264,65 +352,5 @@ module Wunderbar
|
|
264
352
|
end
|
265
353
|
flatten
|
266
354
|
end
|
267
|
-
|
268
|
-
# reflow long lines
|
269
|
-
def self.reflow(stream, width)
|
270
|
-
source = stream.slice!(0..-1)
|
271
|
-
indent = col = 0
|
272
|
-
breakable = true
|
273
|
-
pre = false
|
274
|
-
while not source.empty?
|
275
|
-
token = source.shift
|
276
|
-
indent = token[/^ */].length if col == 0
|
277
|
-
|
278
|
-
if token.start_with? '<'
|
279
|
-
breakable = false
|
280
|
-
pre = true if token == '<pre'
|
281
|
-
end
|
282
|
-
|
283
|
-
# flow text
|
284
|
-
while token.length + col > width and breakable and not pre
|
285
|
-
break if token[0...-1].include? "\n"
|
286
|
-
split = token.rindex(' ', [width-col,0].max) || token.index(' ')
|
287
|
-
break unless split
|
288
|
-
break if col+split < indent+width/2
|
289
|
-
stream << token[0...split] << "\n" << (' '*indent)
|
290
|
-
col = indent
|
291
|
-
token = token[split+1..-1]
|
292
|
-
end
|
293
|
-
|
294
|
-
# break around tags
|
295
|
-
if token.end_with? '>'
|
296
|
-
if col > indent + 4 and stream[-2..-1] == ['<br', '/']
|
297
|
-
stream << token << "\n"
|
298
|
-
col = 0
|
299
|
-
token = ' '*indent
|
300
|
-
source[0] = source.first.lstrip unless source.empty?
|
301
|
-
elsif col > width and not pre
|
302
|
-
# break on previous space within text
|
303
|
-
pcol = col
|
304
|
-
stream.reverse_each do |xtoken|
|
305
|
-
break if xtoken.include? "\n"
|
306
|
-
split = xtoken.rindex(' ')
|
307
|
-
breakable = false if xtoken.end_with? '>'
|
308
|
-
if breakable and split
|
309
|
-
col = col - pcol + xtoken.length - split + indent
|
310
|
-
xtoken[split] = "\n#{' '*indent}"
|
311
|
-
break
|
312
|
-
end
|
313
|
-
breakable = true if xtoken.start_with? '<'
|
314
|
-
pcol -= xtoken.length
|
315
|
-
break if pcol < (width + indent)/2
|
316
|
-
end
|
317
|
-
end
|
318
|
-
breakable = true
|
319
|
-
pre = false if token == '</pre>'
|
320
|
-
end
|
321
|
-
|
322
|
-
stream << token
|
323
|
-
col += token.length
|
324
|
-
col = 0 if token.end_with? "\n"
|
325
|
-
end
|
326
|
-
end
|
327
355
|
end
|
328
356
|
end
|
@@ -0,0 +1,208 @@
|
|
1
|
+
module Wunderbar
|
2
|
+
class Node
|
3
|
+
attr_accessor :name, :text, :attrs, :node, :children, :parent
|
4
|
+
|
5
|
+
VOID = %w(
|
6
|
+
area base br col command embed hr img input keygen
|
7
|
+
link meta param source track wbr
|
8
|
+
)
|
9
|
+
|
10
|
+
ESCAPE = {
|
11
|
+
"'" => ''',
|
12
|
+
'&' => '&',
|
13
|
+
'"' => '"',
|
14
|
+
'<' => '<',
|
15
|
+
'>' => '>',
|
16
|
+
}
|
17
|
+
|
18
|
+
def initialize(name, *args)
|
19
|
+
@name = name
|
20
|
+
@text = nil
|
21
|
+
@attrs = {}
|
22
|
+
@children = []
|
23
|
+
@name += args.shift.inspect if Symbol === args.first
|
24
|
+
@attrs = args.pop.to_hash if args.last.respond_to? :to_hash
|
25
|
+
@text = args.shift.to_s unless args.empty?
|
26
|
+
end
|
27
|
+
|
28
|
+
def method_missing(*args)
|
29
|
+
if args.length == 0
|
30
|
+
attrs[:class] = (attrs[:class].to_s.split(' ') + [name]).join(' ')
|
31
|
+
else
|
32
|
+
name = args.first.to_s
|
33
|
+
err = NameError.new "undefined local variable or method `#{name}'", name
|
34
|
+
err.set_backtrace caller
|
35
|
+
raise err
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_child(child)
|
40
|
+
@children << child
|
41
|
+
child.parent = self
|
42
|
+
end
|
43
|
+
|
44
|
+
def add_text(text)
|
45
|
+
@children << text.to_s.gsub(/[&<>]/,ESCAPE)
|
46
|
+
end
|
47
|
+
|
48
|
+
def walk(result, indent, options)
|
49
|
+
indent += options[:indent] if indent and parent
|
50
|
+
first = true
|
51
|
+
spaced = false
|
52
|
+
children.each do |child|
|
53
|
+
next unless child
|
54
|
+
result << '' if (spaced or SpacedNode === child) and not first
|
55
|
+
if String === child
|
56
|
+
result << child
|
57
|
+
else
|
58
|
+
child.serialize(options, result, indent)
|
59
|
+
end
|
60
|
+
first = false
|
61
|
+
spaced = (SpacedNode === child)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def serialize(options = {}, result = [], indent = '')
|
66
|
+
line = "#{indent}<#{name}"
|
67
|
+
|
68
|
+
attrs.each do |name, value|
|
69
|
+
next unless value
|
70
|
+
name = name.to_s.gsub('_','-') if Symbol === name
|
71
|
+
value=name if value==true
|
72
|
+
line += " #{name}=\"#{value.to_s.gsub(/[&\"<>]/,ESCAPE)}\""
|
73
|
+
end
|
74
|
+
|
75
|
+
if children.empty?
|
76
|
+
if text
|
77
|
+
if options[:pre]
|
78
|
+
line += ">#{options[:pre]}#{text}#{options[:post]}</#{name}>"
|
79
|
+
else
|
80
|
+
line += ">#{text.to_s.gsub(/[&<>]/,ESCAPE)}</#{name}>"
|
81
|
+
end
|
82
|
+
elsif VOID.include? name.to_s
|
83
|
+
line += "/>"
|
84
|
+
else
|
85
|
+
line += "></#{name}>"
|
86
|
+
end
|
87
|
+
elsif CompactNode === self
|
88
|
+
work = []
|
89
|
+
walk(work, nil, options)
|
90
|
+
if @width
|
91
|
+
line += ">"
|
92
|
+
(work+["</#{name}>"]).each do |node|
|
93
|
+
if line.length + node.length > @width
|
94
|
+
result << line.rstrip
|
95
|
+
line = indent
|
96
|
+
end
|
97
|
+
line += node
|
98
|
+
end
|
99
|
+
else
|
100
|
+
line += ">#{work.join}</#{name}>"
|
101
|
+
end
|
102
|
+
else
|
103
|
+
result << line+">#{options[:pre]}" if parent
|
104
|
+
|
105
|
+
walk(result, indent, options) unless children.empty?
|
106
|
+
|
107
|
+
line = "#{indent}#{options[:post]}</#{name}>"
|
108
|
+
end
|
109
|
+
|
110
|
+
result << line if parent
|
111
|
+
result
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
class CommentNode
|
116
|
+
def initialize(text)
|
117
|
+
@text = text
|
118
|
+
end
|
119
|
+
|
120
|
+
def serialize(options, result, indent)
|
121
|
+
result << "#{indent}<!-- #{@text} -->"
|
122
|
+
result
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
class DocTypeNode
|
127
|
+
def initialize(*args)
|
128
|
+
@declare = args.shift
|
129
|
+
@name = args.shift
|
130
|
+
end
|
131
|
+
|
132
|
+
def serialize(options, result, indent)
|
133
|
+
result << "<!#{@declare} #{@name.to_s}>"
|
134
|
+
result
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
class CDATANode < Node
|
139
|
+
def self.normalize(data, indent)
|
140
|
+
data = data.sub(/\n\s*\Z/, '').sub(/\A\s*\n/, '')
|
141
|
+
|
142
|
+
unindent = data.sub(/s+\Z/,'').scan(/^ *\S/).map(&:length).min || 0
|
143
|
+
|
144
|
+
before = ::Regexp.new('^'.ljust(unindent))
|
145
|
+
node = @node
|
146
|
+
data.gsub! before, indent
|
147
|
+
data.gsub! /^#{indent}$/, '' if unindent == 0
|
148
|
+
data
|
149
|
+
end
|
150
|
+
|
151
|
+
def serialize(options = {}, result = [], indent='')
|
152
|
+
if @text and @text.include? "\n"
|
153
|
+
tindent = (indent ? "#{indent}#{options[:indent]}" : indent)
|
154
|
+
children.unshift CDATANode.normalize(@text, tindent).rstrip
|
155
|
+
@text = nil
|
156
|
+
end
|
157
|
+
|
158
|
+
if @text and @text =~ /[<^>]/
|
159
|
+
indent += ' ' if indent
|
160
|
+
children.unshift @text.gsub(/^/, indent).gsub(/^ +$/,'').rstrip
|
161
|
+
@text = nil
|
162
|
+
super(options.merge(pre: pre, post: post), result, indent)
|
163
|
+
elsif children && children.any? {|node| String===node && node =~ /[<^>]/}
|
164
|
+
super(options.merge(pre: pre, post: post), result, indent)
|
165
|
+
else
|
166
|
+
super
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def add_text(text)
|
171
|
+
@children << text
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
class IndentedTextNode < Node
|
176
|
+
def serialize(options, result, indent)
|
177
|
+
if indent
|
178
|
+
text = CDATANode.normalize(name, indent)
|
179
|
+
else
|
180
|
+
text = name
|
181
|
+
end
|
182
|
+
|
183
|
+
result << text.to_s.gsub(/[&<>]/,ESCAPE)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
class ScriptNode < CDATANode
|
188
|
+
def pre; "//<![CDATA["; end
|
189
|
+
def post; "//]]>"; end
|
190
|
+
end
|
191
|
+
|
192
|
+
class StyleNode < CDATANode
|
193
|
+
def pre; "/*<![CDATA[*/"; end
|
194
|
+
def post; "/*]]>*/"; end
|
195
|
+
end
|
196
|
+
|
197
|
+
module CompactNode
|
198
|
+
def width=(value)
|
199
|
+
@width = value
|
200
|
+
end
|
201
|
+
def width
|
202
|
+
@width
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
module SpacedNode; end
|
207
|
+
|
208
|
+
end
|