www_app 1.3.0 → 2.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 +4 -4
- data/.gitignore +4 -0
- data/README.md +42 -24
- data/VERSION +1 -1
- data/bin/www_app +15 -4
- data/lib/public/vendor/hogan-3.0.2.min.js +5 -0
- data/lib/public/vendor/instruct_instruct_instruct.js +247 -0
- data/lib/public/vendor/jquery-2.1.3.min.js +4 -0
- data/lib/public/vendor/lodash.min.js +89 -0
- data/lib/public/www_app.js +885 -625
- data/lib/www_app/CSS.rb +310 -0
- data/lib/www_app/HTML.rb +219 -0
- data/lib/www_app/JavaScript.rb +51 -0
- data/lib/www_app/TO.rb +897 -0
- data/lib/www_app.rb +324 -945
- data/playground/config.ru +102 -0
- data/specs/client-side/index.html +1 -1
- data/specs/client-side/index.js +31 -379
- data/specs/lib/config.ru +60 -31
- data/specs/lib/helpers.rb +24 -2
- data/specs/server-side/0000-new.rb +1 -1
- data/specs/server-side/0001-underscore-double.rb +38 -0
- data/specs/server-side/0001-underscore.rb +73 -0
- data/specs/server-side/0010-attrs.rb +3 -4
- data/specs/server-side/0011-id.rb +5 -5
- data/specs/server-side/0020-tag.rb +2 -2
- data/specs/server-side/0020-tag_content.rb +1 -1
- data/specs/server-side/0021-body.rb +1 -1
- data/specs/server-side/0021-script.rb +66 -20
- data/specs/server-side/{0021-page_title.rb → 0021-title.rb} +5 -3
- data/specs/server-side/0030-mustache.rb +27 -20
- data/specs/server-side/0030-style.rb +64 -21
- data/specs/server-side/0040-css.rb +4 -4
- data/specs/server-side/0041-pseudo.rb +55 -0
- data/specs/server-side/0042-slash.rb +20 -0
- data/specs/server-side/0060-text.rb +26 -0
- metadata +18 -13
- data/lib/public/jquery-2.1.1.js +0 -4
- data/lib/public/underscore-1.7.0.js +0 -6
- data/lib/public/underscore-min.map +0 -1
- data/lib/public/underscore.string-2.3.0.js +0 -1
- data/lib/www_app/Clean.rb +0 -169
- data/lib/www_app/dsl.rb +0 -86
- data/lib/www_app/source.rb +0 -53
- data/specs/server-side/0050-on.rb +0 -64
- data/specs/server-side/0060-string.rb +0 -32
- /data/lib/public/{jquery.serialize-object.min.js → vendor/jquery.serialize-object.min.js} +0 -0
data/lib/www_app.rb
CHANGED
@@ -1,99 +1,17 @@
|
|
1
1
|
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
# ===================================================================
|
8
|
-
# === Mustache customizations: ======================================
|
9
|
-
# ===================================================================
|
10
|
-
Mustache.raise_on_context_miss = true
|
11
|
-
|
12
|
-
class Mustache
|
13
|
-
|
14
|
-
def render(data = template, ctx = {})
|
15
|
-
ctx = data
|
16
|
-
tpl = templateify(template)
|
17
|
-
|
18
|
-
begin
|
19
|
-
context.push(ctx)
|
20
|
-
tpl.render(context)
|
21
|
-
ensure
|
22
|
-
context.pop
|
23
|
-
end
|
24
|
-
end # === def render
|
25
|
-
|
26
|
-
class Context
|
27
|
-
|
28
|
-
def find *args
|
29
|
-
fail "No longer needed."
|
30
|
-
end
|
31
|
-
|
32
|
-
def fetch *args
|
33
|
-
raise ContextMiss.new("Can't find: #{args.inspect}") if args.size != 2
|
34
|
-
|
35
|
-
meth, key = args
|
36
|
-
|
37
|
-
@stack.each { |frame|
|
38
|
-
case
|
39
|
-
when frame.is_a?(Hash) && meth == :coll && !frame.has_key?(key)
|
40
|
-
return false
|
41
|
-
|
42
|
-
when frame.is_a?(Hash) && meth == :coll && frame.has_key?(key)
|
43
|
-
target = frame[key]
|
44
|
-
if target == true || target == false || target == nil || target.is_a?(Array) || target.is_a?(Hash)
|
45
|
-
return target
|
46
|
-
end
|
47
|
-
fail "Invalid value: #{key.inspect} (#{key.class})"
|
48
|
-
|
49
|
-
when frame.is_a?(Hash) && frame.has_key?(key)
|
50
|
-
return ::Escape_Escape_Escape.send(meth, frame[key])
|
51
|
-
|
52
|
-
end
|
53
|
-
}
|
54
|
-
|
55
|
-
raise ContextMiss.new("Can't find .#{meth}(#{key.inspect})")
|
56
|
-
end
|
57
|
-
|
58
|
-
alias_method :[], :fetch
|
59
|
-
|
60
|
-
end # === class Context
|
61
|
-
|
62
|
-
class Generator
|
63
|
-
|
64
|
-
alias_method :w_syms_on_fetch, :on_fetch
|
65
|
-
|
66
|
-
def on_fetch(names)
|
67
|
-
if names.length == 2
|
68
|
-
"ctx[#{names.first.to_sym.inspect}, #{names.last.to_sym.inspect}]"
|
69
|
-
else
|
70
|
-
w_syms_on_fetch(names)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
end # === class Generator
|
75
|
-
|
76
|
-
end # === class Mustache
|
77
|
-
# ===================================================================
|
78
|
-
|
79
|
-
|
80
|
-
# ===================================================================
|
81
|
-
# === Symbol customizations: ========================================
|
82
|
-
# ===================================================================
|
83
|
-
class Symbol
|
84
|
-
|
85
|
-
def to_mustache meth
|
86
|
-
WWW_App::Sanitize.mustache meth, self
|
87
|
-
end
|
88
|
-
|
89
|
-
end # === class Symbol
|
90
|
-
# ===================================================================
|
3
|
+
class WWW_App < BasicObject
|
4
|
+
end # === class WWW_App
|
91
5
|
|
6
|
+
require 'www_app/CSS'
|
7
|
+
require 'www_app/HTML'
|
8
|
+
require 'www_app/JavaScript'
|
9
|
+
require 'www_app/TO'
|
92
10
|
|
93
11
|
# ===================================================================
|
94
12
|
# === WWW_App ====================================================
|
95
13
|
# ===================================================================
|
96
|
-
class WWW_App
|
14
|
+
class WWW_App
|
97
15
|
# ===================================================================
|
98
16
|
|
99
17
|
include ::Kernel
|
@@ -106,982 +24,443 @@ class WWW_App < BasicObject
|
|
106
24
|
|
107
25
|
ALWAYS_END_TAGS = [:script]
|
108
26
|
|
109
|
-
SYM_CACHE = { attrs: {}, css_props: {}}
|
110
|
-
|
111
|
-
Classes = []
|
112
27
|
INVALID_ATTR_CHARS = /[^a-z0-9\_\-]/i
|
113
28
|
IMAGE_AT_END = /image\z/i
|
114
29
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
SPACE = ' '
|
120
|
-
BLANK = ''
|
121
|
-
BODY = 'body'
|
122
|
-
UNDERSCORE = '_'
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
sup sub
|
140
|
-
form input button
|
141
|
-
|
142
|
-
link
|
143
|
-
|
144
|
-
script
|
145
|
-
|
146
|
-
].map(&:to_sym),
|
147
|
-
|
148
|
-
:attributes => {
|
149
|
-
:all => [:id, :class],
|
150
|
-
:a => [:href, :rel],
|
151
|
-
:form => [:action, :method, :accept_charset],
|
152
|
-
:input => [:type, :name, :value],
|
153
|
-
:style => [:type],
|
154
|
-
:script => [:type, :src, :language],
|
155
|
-
:link => [:rel, :type, :sizes, :href, :title],
|
156
|
-
:meta => [:name, :http_equiv, :property, :content, :charset],
|
157
|
-
:img => [:src, :width, :height]
|
158
|
-
},
|
159
|
-
|
160
|
-
:css => {
|
161
|
-
:at_rules => [ 'font-face', 'media' ],
|
162
|
-
:protocols => [ :relative ],
|
163
|
-
|
164
|
-
:pseudo => %w[
|
165
|
-
active checked default dir() disabled
|
166
|
-
empty enabled
|
167
|
-
first first-child first-of-type fullscreen focus
|
168
|
-
hover
|
169
|
-
indeterminate in-range invalid
|
170
|
-
lang() last-child last-of-type left link
|
171
|
-
not() nth-child() nth-last-child() nth-last-of-type() nth-of-type()
|
172
|
-
only-child only-of-type optional out-of-range
|
173
|
-
read-only read-write required right root
|
174
|
-
scope
|
175
|
-
target
|
176
|
-
valid visited
|
177
|
-
].select { |name| name[/\A[a-z0-9\-]+\Z/] }.map { |name| name.gsub('-', '_').to_sym },
|
178
|
-
|
179
|
-
# From: Sanitize::Config::RELAXED[:css][:properties]
|
180
|
-
:properties => %w[
|
181
|
-
background bottom font_variant_numeric position
|
182
|
-
background_attachment box_decoration_break font_variant_position quotes
|
183
|
-
background_clip box_shadow font_weight resize
|
184
|
-
background_color box_sizing height right
|
185
|
-
background_image clear hyphens tab_size
|
186
|
-
background_origin clip icon table_layout
|
187
|
-
background_position clip_path image_orientation text_align
|
188
|
-
background_repeat color image_rendering text_align_last
|
189
|
-
background_size column_count image_resolution text_combine_horizontal
|
190
|
-
border column_fill ime_mode text_decoration
|
191
|
-
border_bottom column_gap justify_content text_decoration_color
|
192
|
-
border_bottom_color column_rule left text_decoration_line
|
193
|
-
border_bottom_left_radius column_rule_color letter_spacing text_decoration_style
|
194
|
-
border_bottom_right_radius column_rule_style line_height text_indent
|
195
|
-
border_bottom_style column_rule_width list_style text_orientation
|
196
|
-
border_bottom_width column_span list_style_image text_overflow
|
197
|
-
border_collapse column_width list_style_position text_rendering
|
198
|
-
border_color columns list_style_type text_shadow
|
199
|
-
border_image content margin text_transform
|
200
|
-
border_image_outset counter_increment margin_bottom text_underline_position
|
201
|
-
border_image_repeat counter_reset margin_left top
|
202
|
-
border_image_slice cursor margin_right touch_action
|
203
|
-
border_image_source direction margin_top transform
|
204
|
-
border_image_width display marks transform_origin
|
205
|
-
border_left empty_cells mask transform_style
|
206
|
-
border_left_color filter mask_type transition
|
207
|
-
border_left_style float max_height transition_delay
|
208
|
-
border_left_width font max_width transition_duration
|
209
|
-
border_radius font_family min_height transition_property
|
210
|
-
border_right font_feature_settings min_width transition_timing_function
|
211
|
-
border_right_color font_kerning opacity unicode_bidi
|
212
|
-
border_right_style font_language_override order unicode_range
|
213
|
-
border_right_width font_size orphans vertical_align
|
214
|
-
border_spacing font_size_adjust overflow visibility
|
215
|
-
border_style font_stretch overflow_wrap white_space
|
216
|
-
border_top font_style overflow_x widows
|
217
|
-
border_top_color font_synthesis overflow_y width
|
218
|
-
border_top_left_radius font_variant padding word_break
|
219
|
-
border_top_right_radius font_variant_alternates padding_bottom word_spacing
|
220
|
-
border_top_style font_variant_caps padding_left word_wrap
|
221
|
-
border_top_width font_variant_east_asian padding_right z_index
|
222
|
-
border_width font_variant_ligatures padding_top
|
223
|
-
].map(&:to_sym)
|
224
|
-
}
|
225
|
-
|
226
|
-
} # === end Methods
|
227
|
-
|
228
|
-
ALLOWED_ATTRS = Methods[:attributes].inject({}) { |memo, (tag, attrs)|
|
229
|
-
attrs.each { |a|
|
230
|
-
memo[a] ||= []
|
231
|
-
memo[a] << tag
|
30
|
+
NEW_LINE = "\n".freeze
|
31
|
+
HASH = '#'.freeze
|
32
|
+
DOT = '.'.freeze
|
33
|
+
BANG = '!'.freeze
|
34
|
+
SPACE = ' '.freeze
|
35
|
+
BLANK = ''.freeze
|
36
|
+
BODY = 'body'.freeze
|
37
|
+
UNDERSCORE = '_'.freeze
|
38
|
+
|
39
|
+
class << self
|
40
|
+
end # === class << self
|
41
|
+
|
42
|
+
include CSS
|
43
|
+
include HTML
|
44
|
+
include JavaScript
|
45
|
+
include TO
|
46
|
+
|
47
|
+
mods = included_modules.reject { |mod| mod == ::Kernel }
|
48
|
+
MULTI_DEFINED_METHS = mods.inject({}) { |memo, mod|
|
49
|
+
mod.instance_methods.each { |meth|
|
50
|
+
defs = mods.select { |o| o.instance_methods.include?(meth) }
|
51
|
+
if defs.size > 1
|
52
|
+
memo[meth] ||= defs
|
53
|
+
end
|
232
54
|
}
|
233
55
|
memo
|
234
56
|
}
|
235
57
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
def initialize *files
|
240
|
-
@js = []
|
241
|
-
@style = {}
|
242
|
-
@css_arr = []
|
243
|
-
@css_id_override = nil
|
244
|
-
@render_it = true
|
245
|
-
|
246
|
-
@title = nil
|
247
|
-
@scripts = []
|
248
|
-
@body = []
|
249
|
-
@compiled = nil
|
250
|
-
@cache = {}
|
251
|
-
@is_doc = false
|
252
|
-
@page_title = nil
|
253
|
-
@default_ids = {}
|
254
|
-
|
255
|
-
@state = [:create]
|
256
|
-
@ids = {}
|
257
|
-
|
258
|
-
@tag_arr = []
|
259
|
-
@current_tag_index = nil
|
260
|
-
@mustache = nil
|
261
|
-
|
262
|
-
@html_ids = {}
|
263
|
-
|
264
|
-
tag(:head) {
|
58
|
+
if !MULTI_DEFINED_METHS.empty?
|
59
|
+
fail ::ArgumentError, "Methods already defined:\n#{MULTI_DEFINED_METHS.inspect}"
|
60
|
+
end
|
265
61
|
|
266
|
-
|
62
|
+
private # ===============================================
|
267
63
|
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
tag(:script) {
|
274
|
-
tag![:content] = @js
|
275
|
-
}
|
64
|
+
def initialize &blok
|
65
|
+
@html_ids = {}
|
66
|
+
@tags = []
|
67
|
+
@tag = nil
|
276
68
|
|
277
|
-
|
278
|
-
|
279
|
-
tag(:body) {
|
69
|
+
instance_eval &blok
|
70
|
+
end
|
280
71
|
|
281
|
-
|
72
|
+
def SPACES indent
|
73
|
+
SPACE * indent
|
74
|
+
end
|
282
75
|
|
283
|
-
|
284
|
-
|
285
|
-
|
76
|
+
def args_to_traversal_args *args
|
77
|
+
tags = nil
|
78
|
+
tag = nil
|
79
|
+
syms = []
|
286
80
|
|
287
|
-
|
81
|
+
args.each { |a|
|
82
|
+
case a
|
83
|
+
when ::Symbol
|
84
|
+
syms << a
|
85
|
+
when ::Array
|
86
|
+
tags = a
|
87
|
+
when ::Hash
|
88
|
+
tag = a
|
89
|
+
tags = [a]
|
90
|
+
else
|
91
|
+
fail ::ArgumentError, "#{args.inspect}"
|
92
|
+
end
|
288
93
|
}
|
289
94
|
|
290
|
-
|
291
|
-
@
|
292
|
-
|
293
|
-
freeze
|
294
|
-
end # === def new_class
|
295
|
-
|
296
|
-
def render_if name
|
297
|
-
tag(:render_if) { tag![:attrs][:key] = name; yield }
|
298
|
-
nil
|
95
|
+
tags ||= @tags.dup
|
96
|
+
tag ||= @tag
|
97
|
+
return [tags, tag, syms]
|
299
98
|
end
|
300
99
|
|
301
|
-
def
|
302
|
-
|
303
|
-
|
304
|
-
end
|
305
|
-
|
306
|
-
def render raw_data = {}
|
307
|
-
@mustache.render raw_data
|
308
|
-
end
|
100
|
+
def de_ref tag
|
101
|
+
t_name = tag[:tag_name]
|
102
|
+
return tag unless t_name == :_
|
309
103
|
|
310
|
-
|
311
|
-
|
312
|
-
|
104
|
+
# === Remove unneeded values from tag:
|
105
|
+
dup = tag.dup
|
106
|
+
dup.delete :tag_name
|
107
|
+
dup.delete :parent
|
313
108
|
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
Allowed[:attr].each { |name, tags|
|
324
|
-
eval <<-EOF, nil, __FILE__, __LINE__ + 1
|
325
|
-
def #{name} val
|
326
|
-
allowed = Allowed[:attr][:#{name}]
|
327
|
-
allowed = allowed && allowed[tag![:tag]]
|
328
|
-
return super unless allowed
|
329
|
-
|
330
|
-
tag![:attrs][:#{name}] = val
|
109
|
+
# === Find the true parent:
|
110
|
+
parent = tag
|
111
|
+
while parent && [:_, :style, :group].freeze.include?(parent[:tag_name])
|
112
|
+
parent = parent[:parent]
|
113
|
+
end
|
114
|
+
if !parent
|
115
|
+
parent = {:tag_name=>:body}
|
116
|
+
end
|
331
117
|
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
}
|
118
|
+
# === Merge, Freeze, and Return:
|
119
|
+
t = {}
|
120
|
+
t.merge! parent
|
121
|
+
t.merge! dup
|
122
|
+
t.freeze
|
123
|
+
t
|
124
|
+
end # === def de_ref
|
340
125
|
|
126
|
+
# Ex:
|
341
127
|
#
|
342
|
-
#
|
343
|
-
#
|
128
|
+
# find_all :body, :style, :span
|
129
|
+
# find_all [], :body, :a
|
130
|
+
# find_all {tag}, :body, :a
|
344
131
|
#
|
345
|
-
def *
|
346
|
-
|
132
|
+
def find_all *raw_args
|
133
|
+
tags, tag, syms = args_to_traversal_args(*raw_args)
|
347
134
|
|
348
|
-
|
349
|
-
fail("Id already set: #{old_id} new: #{id}") if old_id
|
135
|
+
fail ::ArgumentError, "tag names to find empty: #{syms.inspect}" if syms.empty?
|
350
136
|
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
137
|
+
found = []
|
138
|
+
while !tags.empty?
|
139
|
+
t = tags.shift
|
140
|
+
if t[:children]
|
141
|
+
tags = t[:children].dup.concat tags
|
142
|
+
end
|
355
143
|
|
356
|
-
|
357
|
-
close_tag { yield }
|
358
|
-
else
|
359
|
-
self
|
144
|
+
(found << t) if syms.include?(t[:tag_name])
|
360
145
|
end
|
146
|
+
|
147
|
+
found
|
361
148
|
end
|
362
149
|
|
363
150
|
#
|
364
|
-
#
|
365
|
-
# div.^(:alert, :red_hot) { 'my content' }
|
151
|
+
# Ex:
|
366
152
|
#
|
367
|
-
|
368
|
-
|
153
|
+
# detect :body, :style, :span
|
154
|
+
# detect [], :body, :a
|
155
|
+
# detect {tag}, :body, :a
|
156
|
+
#
|
157
|
+
def detect *raw_args
|
158
|
+
tags, tag, syms = args_to_traversal_args(*raw_args)
|
159
|
+
|
160
|
+
found = nil
|
161
|
+
while !found && !tags.empty?
|
162
|
+
found = tags.shift
|
163
|
+
if !syms.include?(found[:tag_name])
|
164
|
+
if found[:children]
|
165
|
+
tags = found[:children].dup.concat tags
|
166
|
+
end
|
167
|
+
found = nil
|
168
|
+
end
|
169
|
+
end
|
369
170
|
|
370
|
-
|
371
|
-
|
171
|
+
found
|
172
|
+
end
|
173
|
+
|
174
|
+
def tag? *args
|
175
|
+
case args.size
|
176
|
+
when 1
|
177
|
+
tag = @tag
|
178
|
+
name = args.first
|
179
|
+
when 2
|
180
|
+
tag = args.first
|
181
|
+
name = args.last
|
372
182
|
else
|
373
|
-
|
183
|
+
fail "Unknown args: #{args.inspect}"
|
374
184
|
end
|
185
|
+
|
186
|
+
tag && (tag[:tag_name] == name || !!tag[name])
|
375
187
|
end
|
376
188
|
|
377
|
-
|
189
|
+
def tag_or_ancestor? *args
|
190
|
+
!!find_nearest(*args)
|
191
|
+
end
|
378
192
|
|
379
|
-
|
380
|
-
|
381
|
-
|
193
|
+
def ancestor? *args
|
194
|
+
!!(find_ancestor *args)
|
195
|
+
end
|
382
196
|
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
str_name = name.to_s.gsub('_', '-')
|
389
|
-
eval <<-EOF, nil, __FILE__, __LINE__ + 1
|
390
|
-
def #{name} *args
|
391
|
-
css_property(:#{name}, *args) {
|
392
|
-
yield if block_given?
|
393
|
-
}
|
394
|
-
end
|
395
|
-
EOF
|
396
|
-
}
|
197
|
+
def find_nearest *raw_args
|
198
|
+
tags, tag, syms = args_to_traversal_args(*raw_args)
|
199
|
+
return tag if tag?(tag, syms.first)
|
200
|
+
find_ancestor *raw_args
|
201
|
+
end
|
397
202
|
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
if block_given?
|
402
|
-
tag(:#{name}, *args) { yield }
|
403
|
-
else
|
404
|
-
tag(:#{name}, *args)
|
405
|
-
end
|
406
|
-
end
|
407
|
-
EOF
|
408
|
-
}
|
203
|
+
def find_ancestor *raw_args
|
204
|
+
tags, tag, syms = args_to_traversal_args(*raw_args)
|
205
|
+
name = syms.first
|
409
206
|
|
410
|
-
|
411
|
-
|
412
|
-
|
207
|
+
return nil unless tag
|
208
|
+
ancestor = tag[:parent]
|
209
|
+
while ancestor && !tag?(ancestor, name)
|
210
|
+
ancestor = ancestor[:parent]
|
211
|
+
end
|
413
212
|
|
414
|
-
|
415
|
-
fail
|
213
|
+
return ancestor if tag?(ancestor, name)
|
416
214
|
end
|
417
215
|
|
418
|
-
def
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
def in_middle_of
|
423
|
-
fail
|
216
|
+
def go_up_to_if_exists name
|
217
|
+
target = find_ancestor name
|
218
|
+
(@tag = target) if target
|
219
|
+
self
|
424
220
|
end
|
425
221
|
|
426
|
-
def
|
427
|
-
|
222
|
+
def go_up_to name
|
223
|
+
go_up_to_if_exists name
|
224
|
+
fail "No parent found: #{name.inspect}" unless tag?(name)
|
225
|
+
self
|
428
226
|
end
|
429
227
|
|
228
|
+
def stay_or_go_up_to_if_exists name
|
229
|
+
return self if tag?(name)
|
230
|
+
target = find_ancestor(name)
|
231
|
+
(@tag = target) if target
|
430
232
|
|
431
|
-
|
432
|
-
|
433
|
-
# =================================================================
|
233
|
+
self
|
234
|
+
end
|
434
235
|
|
435
|
-
def
|
436
|
-
|
236
|
+
def stay_or_go_up_to name
|
237
|
+
stay_or_go_up_to_if_exists name
|
238
|
+
fail "No parent found: #{name.inspect}" unless tag?(name)
|
239
|
+
self
|
437
240
|
end
|
438
241
|
|
439
|
-
def
|
440
|
-
tag
|
242
|
+
def go_up
|
243
|
+
@tag = @tag[:parent]
|
244
|
+
self
|
441
245
|
end
|
442
246
|
|
443
|
-
def
|
444
|
-
|
247
|
+
def first_class
|
248
|
+
tag[:class] && tag[:class].first
|
445
249
|
end
|
446
250
|
|
447
251
|
def dom_id?
|
448
|
-
tag
|
252
|
+
tag && !!tag[:id]
|
449
253
|
end
|
450
254
|
|
451
255
|
#
|
452
|
-
#
|
453
|
-
# dom_id -> the current dom id of the current element
|
454
|
-
# dom_id :default -> if no dom it, set/get default of current element
|
455
|
-
# dom_id {:element:} -> dom id of element: {:type=>:html, :tag=>...}
|
256
|
+
# Ex:
|
456
257
|
#
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
258
|
+
# parent?
|
259
|
+
# parent? :body
|
260
|
+
# parent? tag, :div
|
261
|
+
#
|
262
|
+
def parent? *args
|
461
263
|
case
|
462
|
-
when args.
|
463
|
-
|
464
|
-
|
264
|
+
when args.length == 0
|
265
|
+
tag = @tag[:parent]
|
266
|
+
name = nil
|
465
267
|
|
466
|
-
when args.
|
467
|
-
|
468
|
-
|
268
|
+
when args.length == 1 && args.first.is_a?(::Symbol)
|
269
|
+
tag = @tag
|
270
|
+
name = args.first
|
469
271
|
|
470
|
-
when args.
|
471
|
-
|
272
|
+
when args.length == 2
|
273
|
+
tag = args.first
|
274
|
+
name = args.last
|
472
275
|
|
473
276
|
else
|
474
|
-
fail "Unknown args: #{args.inspect}"
|
475
|
-
end
|
476
|
-
|
477
|
-
id = e[:attrs][:id]
|
478
|
-
return id if id
|
479
|
-
return nil unless use_default
|
480
|
-
|
481
|
-
e[:default_id] ||= begin
|
482
|
-
key = e[:tag]
|
483
|
-
@default_ids[key] ||= -1
|
484
|
-
@default_ids[key] += 1
|
485
|
-
end
|
486
|
-
end # === def dom_id
|
277
|
+
fail ::ArgumentError, "Unknown args: #{args.inspect}"
|
278
|
+
end # === case
|
487
279
|
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
#
|
494
|
-
#
|
495
|
-
#
|
496
|
-
def selector_id
|
497
|
-
i = tag![:tag_index]
|
498
|
-
id_given = false
|
499
|
-
classes = []
|
500
|
-
|
501
|
-
while !id_given && i && i > -1
|
502
|
-
e = @tag_arr[i]
|
503
|
-
id = dom_id e
|
504
|
-
(id_given = true) if id
|
505
|
-
|
506
|
-
if e[:tag] == :body && !classes.empty?
|
507
|
-
# do nothing because
|
508
|
-
# we do not want 'body tag.class tag.class'
|
509
|
-
else
|
510
|
-
case
|
511
|
-
when id
|
512
|
-
classes << "##{id}"
|
513
|
-
else
|
514
|
-
classes << e[:tag]
|
515
|
-
end # === case
|
516
|
-
end # === if
|
517
|
-
|
518
|
-
i = e[:parent_index]
|
519
|
-
end
|
520
|
-
|
521
|
-
return 'body' if classes.empty?
|
522
|
-
classes.join SPACE
|
523
|
-
end
|
280
|
+
p = parent(tag)
|
281
|
+
return true if p && !name
|
282
|
+
return true if p && p[:tag_name] == name
|
283
|
+
return true if !p && name == :body
|
284
|
+
false
|
285
|
+
end # === def parent?
|
524
286
|
|
525
287
|
#
|
526
|
-
#
|
527
|
-
# css_id -> current css id of element.
|
528
|
-
# It uses the first class, if any, found.
|
529
|
-
# #id.class -> if #id and first class found.
|
530
|
-
# #id -> if class is missing and id given.
|
531
|
-
# #id tag.class -> if class given and ancestor has id.
|
532
|
-
# #id tag tag -> if no class given and ancestor has id.
|
533
|
-
# tag tag tag -> if no ancestor has class.
|
534
|
-
#
|
535
|
-
# css_id :my_class -> same as 'css_id()' except
|
536
|
-
# 'my_class' overrides :class attribute of current
|
537
|
-
# element.
|
288
|
+
# Ex:
|
538
289
|
#
|
290
|
+
# parent
|
291
|
+
# parent tag
|
539
292
|
#
|
540
|
-
def
|
541
|
-
|
542
|
-
|
293
|
+
def parent *args
|
294
|
+
case
|
295
|
+
when args.length == 0
|
296
|
+
tag = @tag
|
543
297
|
|
544
|
-
|
545
|
-
|
546
|
-
fail "Not in a tag." unless tag!
|
547
|
-
str_class = @css_id_override
|
548
|
-
when 1
|
549
|
-
str_class = args.first
|
298
|
+
when args.length == 1 && args.first.is_a?(::Hash)
|
299
|
+
tag = args.first
|
550
300
|
else
|
551
|
-
fail "Unknown args: #{args.inspect}"
|
552
|
-
end
|
553
|
-
|
554
|
-
i = tag![:tag_index]
|
555
|
-
id_given = false
|
556
|
-
classes = []
|
557
|
-
|
558
|
-
while !id_given && i && i > -1
|
559
|
-
e = @tag_arr[i]
|
560
|
-
id = dom_id e
|
561
|
-
first_class = e[:attrs][:class].first
|
562
|
-
|
563
|
-
if id
|
564
|
-
id_given = true
|
565
|
-
if str_class
|
566
|
-
classes.unshift(
|
567
|
-
str_class.is_a?(::Symbol) ?
|
568
|
-
"##{id}.#{str_class}" :
|
569
|
-
"##{id}#{str_class}"
|
570
|
-
)
|
571
|
-
else
|
572
|
-
classes.unshift "##{id}"
|
573
|
-
end
|
301
|
+
fail ::ArgumentError, "Unknown args: #{args.inspect}"
|
302
|
+
end # === case
|
574
303
|
|
575
|
-
|
576
|
-
if str_class
|
577
|
-
classes.unshift(
|
578
|
-
str_class.is_a?(::Symbol) ?
|
579
|
-
"#{e[:tag]}.#{str_class}" :
|
580
|
-
"#{e[:tag]}#{str_class}"
|
581
|
-
)
|
582
|
-
elsif first_class
|
583
|
-
classes.unshift "#{e[:tag]}.#{first_class}"
|
584
|
-
else
|
585
|
-
if e[:tag] != :body || (classes.empty?)
|
586
|
-
classes.unshift "#{e[:tag]}"
|
587
|
-
end
|
588
|
-
end # if first_class
|
589
|
-
|
590
|
-
end # if id
|
591
|
-
|
592
|
-
i = e[:parent_index]
|
593
|
-
break if i == @body[:tag_index] && !classes.empty?
|
594
|
-
end
|
595
|
-
|
596
|
-
classes.join SPACE
|
304
|
+
tag && tag[:parent]
|
597
305
|
end
|
598
306
|
|
599
|
-
|
600
|
-
|
601
|
-
|
307
|
+
def in_tag t
|
308
|
+
if t.is_a?(::Symbol)
|
309
|
+
in_tag(detect(t)) {
|
310
|
+
yield
|
311
|
+
}
|
312
|
+
return self
|
602
313
|
|
603
|
-
|
604
|
-
|
605
|
-
|
314
|
+
else # =============================
|
315
|
+
orig = @tag
|
316
|
+
@tag = t
|
317
|
+
yield
|
318
|
+
@tag = orig
|
319
|
+
nil
|
606
320
|
|
607
|
-
|
608
|
-
fail "not done"
|
321
|
+
end # === if t == :head
|
609
322
|
end
|
610
323
|
|
611
|
-
def
|
612
|
-
|
613
|
-
fail("Unknown args: #{args.first}") if args.size > 1
|
614
|
-
return false unless parent
|
324
|
+
def create name, opts = nil
|
325
|
+
if @tag && @tag[:tag_name] == :_
|
615
326
|
|
616
|
-
|
327
|
+
# Ex:
|
328
|
+
# _.id(:the_body).^(:loading)
|
329
|
+
# div {
|
330
|
+
# }
|
331
|
+
go_up if !@tag[:closed]
|
617
332
|
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
333
|
+
# Ex:
|
334
|
+
# _.^(:happy) {
|
335
|
+
# a { }
|
336
|
+
# }
|
337
|
+
fail "New tags not allowed here." if (@tag && @tag[:closed]) && !ancestor?(:group)
|
623
338
|
end
|
624
|
-
end
|
625
|
-
|
626
|
-
def parent
|
627
|
-
fail "Not in a tag." unless tag!
|
628
|
-
fail "No parent: #{tag![:tag].inspect}, #{tag![:tag_index]}" if !tag![:parent_index]
|
629
|
-
@tag_arr[tag![:parent_index]]
|
630
|
-
end
|
631
|
-
|
632
|
-
# =================================================================
|
633
|
-
# Tag (aka element)-related methods
|
634
|
-
# =================================================================
|
635
|
-
|
636
|
-
def tag!
|
637
|
-
return nil unless @current_tag_index.is_a?(::Numeric)
|
638
|
-
@tag_arr[@current_tag_index]
|
639
|
-
end
|
640
|
-
|
641
|
-
def tag? sym_tag
|
642
|
-
tag![:tag] == sym_tag
|
643
|
-
end
|
644
|
-
|
645
|
-
def tag sym_name
|
646
|
-
e = {
|
647
|
-
:type => :html,
|
648
|
-
:tag => sym_name,
|
649
|
-
:attrs => {:class=>[]},
|
650
|
-
:text => nil,
|
651
|
-
:childs => [],
|
652
|
-
:parent_index => @current_tag_index,
|
653
|
-
:is_closed => false,
|
654
|
-
:tag_index => @tag_arr.size,
|
655
|
-
:render? => @render_it
|
656
|
-
}
|
657
|
-
|
658
|
-
@tag_arr << e
|
659
|
-
@current_tag_index = e[:tag_index]
|
660
339
|
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
340
|
+
# === If:
|
341
|
+
# we are creating an HTML element
|
342
|
+
# within a group, then we either start
|
343
|
+
# a new group or stay here.
|
344
|
+
if name != :group && tag_or_ancestor?(:groups)
|
345
|
+
if tag?(:groups)
|
346
|
+
create :group
|
347
|
+
else
|
348
|
+
stay_or_go_up_to_if_exists(:group)
|
666
349
|
end
|
667
350
|
end
|
668
351
|
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
352
|
+
old = @tag
|
353
|
+
new = {:tag_name=>name}
|
354
|
+
|
355
|
+
# === Add to parent's children array:
|
356
|
+
if old
|
357
|
+
old[:children] ||= []
|
358
|
+
old[:children] << new
|
359
|
+
new[:parent] = old
|
360
|
+
else # === Example: :head, :body, etc.
|
361
|
+
@tags << new
|
673
362
|
end
|
674
|
-
end
|
675
363
|
|
676
|
-
|
677
|
-
orig = @current_tag_index
|
678
|
-
@current_tag_index = t[:tag_index]
|
679
|
-
yield
|
680
|
-
@current_tag_index = orig
|
681
|
-
nil
|
682
|
-
end
|
364
|
+
@tag = new
|
683
365
|
|
684
|
-
|
685
|
-
fail "No block allowed here: :/" if block_given?
|
686
|
-
close_tag
|
687
|
-
end
|
688
|
-
|
689
|
-
def close_tag
|
690
|
-
orig_tag = tag!
|
691
|
-
is_script = tag?(:script)
|
366
|
+
@tag.merge!(opts) if opts
|
692
367
|
|
693
368
|
if block_given?
|
694
|
-
|
695
|
-
results = yield
|
696
|
-
|
697
|
-
results = nil if is_script
|
698
|
-
|
699
|
-
# The :yield may have left some opened tags, :input, :br/
|
700
|
-
# So we make sure we are in the original tag/element
|
701
|
-
# when we want to make some final changes.
|
702
|
-
in_tag(orig_tag) {
|
703
|
-
if tag?(:form)
|
704
|
-
input(:hidden, :auth_token, :auth_token.to_mustache(:html))
|
705
|
-
end
|
706
|
-
|
707
|
-
if (results.is_a?(::Hash) && results[:type] && !results[:tag] && results[:type] != :string)
|
708
|
-
fail Invalid_Type, results[:type].inspect
|
709
|
-
end
|
710
|
-
|
711
|
-
if (results.is_a?(::Hash) && results[:type] == :string) || results.is_a?(::String) || results.is_a?(::Symbol)
|
712
|
-
tag![:text] = results
|
713
|
-
end
|
714
|
-
}
|
369
|
+
close { yield }
|
715
370
|
end
|
716
371
|
|
717
|
-
orig_tag[:is_closed] = true
|
718
|
-
@current_tag_index = orig_tag[:parent_index]
|
719
|
-
|
720
|
-
nil
|
721
|
-
end
|
722
|
-
|
723
|
-
# =================================================================
|
724
|
-
# CSS-related methods
|
725
|
-
# =================================================================
|
726
|
-
|
727
|
-
def style
|
728
|
-
orig = @render_it
|
729
|
-
@render_it = false
|
730
|
-
results = yield
|
731
|
-
@render_it = orig
|
732
|
-
results
|
733
|
-
end
|
734
|
-
|
735
|
-
def css_property name, val = nil
|
736
|
-
prop = {:name=>name, :value=>val, :parent=>parent? ? parent : nil}
|
737
|
-
|
738
|
-
id = css_id
|
739
|
-
@style[:css][id] ||= {}
|
740
|
-
|
741
|
-
@css_arr << prop
|
742
|
-
@style[:css][id][@css_arr.map { |c| c[:name] }.join('_').to_sym] = val
|
743
|
-
yield if block_given?
|
744
|
-
@css_arr.pop
|
745
|
-
end
|
746
|
-
|
747
|
-
Methods[:css][:pseudo].each { |name|
|
748
|
-
eval <<-EOF, nil, __FILE__, __LINE__ + 1
|
749
|
-
def _#{name}
|
750
|
-
orig = @css_id_override
|
751
|
-
@css_id_override = ':#{name}'.freeze
|
752
|
-
result = yield
|
753
|
-
@css_id_override = orig
|
754
|
-
result
|
755
|
-
end
|
756
|
-
EOF
|
757
|
-
}
|
758
|
-
|
759
|
-
# =================================================================
|
760
|
-
|
761
|
-
def page_title
|
762
|
-
@is_doc = true
|
763
|
-
in_tag(@head) {
|
764
|
-
tag(:title) { @page_title = yield }
|
765
|
-
}
|
766
372
|
self
|
767
|
-
end
|
373
|
+
end # === def create
|
768
374
|
|
769
|
-
def
|
375
|
+
def text str
|
770
376
|
fail "No block allowed." if block_given?
|
771
|
-
|
772
|
-
|
773
|
-
in_tag(@tag) { c = tag(:meta, *args) }
|
774
|
-
c
|
377
|
+
create(:text, :value=>str, :closed=>true)
|
378
|
+
go_up
|
775
379
|
end
|
776
380
|
|
777
|
-
def
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
clean_vals = vals.map { |raw_x|
|
782
|
-
x = case raw_x
|
783
|
-
when ::Symbol, ::String
|
784
|
-
Sanitize.html(raw_x.to_s)
|
785
|
-
when ::Array
|
786
|
-
to_clean_text :javascript, raw_x
|
787
|
-
when ::Numeric
|
788
|
-
x
|
789
|
-
else
|
790
|
-
fail "Unknown type for json: #{raw_x.inspect}"
|
791
|
-
end
|
792
|
-
}
|
793
|
-
|
794
|
-
when type == :to_json && vals.is_a?(::Array)
|
795
|
-
::Escape_Escape_Escape.json_encode(to_clean_text(:javascript, vals))
|
796
|
-
|
797
|
-
when type == :style_classes && vals.is_a?(::Hash)
|
798
|
-
h = vals
|
799
|
-
h.map { |raw_k,styles|
|
800
|
-
k = raw_k.to_s
|
801
|
-
|
802
|
-
<<-EOF
|
803
|
-
#{Sanitize.css_selector k} {
|
804
|
-
#{to_clean_text :styles, styles}
|
805
|
-
}
|
806
|
-
EOF
|
807
|
-
}.join.strip
|
808
|
-
|
809
|
-
when type == :styles && vals.is_a?(::Hash)
|
810
|
-
h = vals
|
811
|
-
h.map { |k,raw_v|
|
812
|
-
name = begin
|
813
|
-
clean_k = ::WWW_App::Sanitize.css_attr(k.to_s.gsub('_','-'))
|
814
|
-
fail("Invalid name for css property name: #{k.inspect}") if !clean_k || clean_k.empty?
|
815
|
-
clean_k
|
816
|
-
end
|
817
|
-
|
818
|
-
raw_v = raw_v.to_s
|
819
|
-
|
820
|
-
v = case
|
821
|
-
|
822
|
-
when name[IMAGE_AT_END]
|
823
|
-
case raw_v
|
824
|
-
when 'inherit', 'none'
|
825
|
-
raw_v
|
826
|
-
else
|
827
|
-
"url(#{Sanitize.href(raw_v)})"
|
828
|
-
end
|
829
|
-
|
830
|
-
when Methods[:css][:properties].include?(k)
|
831
|
-
Sanitize.css_value raw_v
|
832
|
-
|
833
|
-
else
|
834
|
-
fail "Invalid css attr: #{name.inspect}"
|
835
|
-
|
836
|
-
end # === case
|
837
|
-
|
838
|
-
%^#{name}: #{v};^
|
839
|
-
}.join("\n").strip
|
840
|
-
|
841
|
-
when type == :attrs && vals.is_a?(::Hash)
|
842
|
-
h = vals[:attrs]
|
843
|
-
tag = vals
|
844
|
-
final = h.map { |k,raw_v|
|
845
|
-
|
846
|
-
fail "Unknown attr: #{k.inspect}" if !ALLOWED_ATTRS.include?(k)
|
847
|
-
|
848
|
-
next if raw_v.is_a?(::Array) && raw_v.empty?
|
849
|
-
|
850
|
-
v = raw_v
|
851
|
-
|
852
|
-
attr_name = k.to_s.gsub(::WWW_App::INVALID_ATTR_CHARS, '_')
|
853
|
-
fail("Invalid name for html attr: #{k.inspect}") if !attr_name || attr_name.empty?
|
854
|
-
|
855
|
-
attr_val = case
|
856
|
-
when k == :href && tag[:tag] == :a
|
857
|
-
Sanitize.mustache :href, v
|
858
|
-
|
859
|
-
when k == :action || k == :src || k == :href
|
860
|
-
Sanitize.relative_href(v)
|
861
|
-
|
862
|
-
when k == :class
|
863
|
-
v.map { |n|
|
864
|
-
Sanitize.css_class_name(n)
|
865
|
-
}.join SPACE
|
866
|
-
|
867
|
-
when k == :id
|
868
|
-
Sanitize.html_id v.to_s
|
869
|
-
|
870
|
-
when ALLOWED_ATTRS[k]
|
871
|
-
Sanitize.html(v)
|
872
|
-
|
873
|
-
else
|
874
|
-
fail "Invalid attr: #{k.inspect}"
|
875
|
-
|
876
|
-
end # === case
|
877
|
-
|
878
|
-
%*#{attr_name}="#{attr_val}"*
|
879
|
-
|
880
|
-
}.compact.join SPACE
|
881
|
-
|
882
|
-
final.empty? ?
|
883
|
-
'' :
|
884
|
-
(" " << final)
|
885
|
-
|
886
|
-
when type == :html && vals.is_a?(::Array)
|
887
|
-
a = vals
|
888
|
-
a.map { |tag_index|
|
889
|
-
to_clean_text(:html, @tag_arr[tag_index])
|
890
|
-
}.join NEW_LINE
|
891
|
-
|
892
|
-
when type == :html && vals.is_a?(::Hash)
|
893
|
-
|
894
|
-
h = vals
|
895
|
-
|
896
|
-
fail("Unknown type: #{h.inspect}") if h[:type] != :html
|
897
|
-
|
898
|
-
if h[:tag] == :style
|
899
|
-
return <<-EOF
|
900
|
-
<style type="text/css">
|
901
|
-
#{to_clean_text :style_classes, h[:css]}
|
902
|
-
</style>
|
903
|
-
EOF
|
904
|
-
end
|
905
|
-
|
906
|
-
if h[:tag] == :script && h[:content] && !h[:content].empty?
|
907
|
-
return <<-EOF
|
908
|
-
<script type="text/css">
|
909
|
-
WWW_App.compile(
|
910
|
-
#{to_clean_text :to_json, h[:content]}
|
911
|
-
);
|
912
|
-
</script>
|
913
|
-
EOF
|
914
|
-
end
|
915
|
-
|
916
|
-
html = h[:childs].map { |tag_index|
|
917
|
-
to_clean_text(:html, @tag_arr[tag_index])
|
918
|
-
}.join(NEW_LINE).strip
|
919
|
-
|
920
|
-
return unless h[:render?]
|
921
|
-
|
922
|
-
if html.empty? && h[:text]
|
923
|
-
html = if h[:text].is_a?(::Symbol)
|
924
|
-
h[:text].to_mustache(:html)
|
925
|
-
else
|
926
|
-
if h[:text].is_a?(::Hash)
|
927
|
-
if h[:text][:escape] == false
|
928
|
-
h[:text][:value]
|
929
|
-
else
|
930
|
-
Sanitize.html(h[:text][:value].strip)
|
931
|
-
end
|
932
|
-
else
|
933
|
-
Sanitize.html(h[:text].strip)
|
934
|
-
end
|
935
|
-
end
|
936
|
-
end # === if html.empty?
|
937
|
-
|
938
|
-
(html = nil) if html.empty?
|
939
|
-
|
940
|
-
case
|
941
|
-
when h[:tag] == :render_if
|
942
|
-
key = h[:attrs][:key]
|
943
|
-
open = "{{# coll.#{key} }}"
|
944
|
-
close = "{{/ coll.#{key} }}"
|
945
|
-
|
946
|
-
when h[:tag] == :render_unless
|
947
|
-
key = h[:attrs][:key]
|
948
|
-
open = "{{^ coll.#{key} }}"
|
949
|
-
close = "{{/ coll.#{key} }}"
|
950
|
-
|
951
|
-
when Methods[:elements].include?(h[:tag])
|
952
|
-
open = "<#{h[:tag]}#{to_clean_text(:attrs, h)}"
|
953
|
-
if NO_END_TAGS.include?(h[:tag])
|
954
|
-
open += ' />'
|
955
|
-
close = nil
|
956
|
-
else
|
957
|
-
open += '>'
|
958
|
-
close = "</#{h[:tag]}>"
|
959
|
-
end
|
960
|
-
|
961
|
-
else
|
962
|
-
fail "Unknown html tag: #{h[:tag].inspect}"
|
963
|
-
|
964
|
-
end # === case h[:tag]
|
965
|
-
|
966
|
-
if h[:tag]
|
967
|
-
[open, html, close].compact.join
|
968
|
-
else
|
969
|
-
html
|
970
|
-
end
|
971
|
-
|
972
|
-
else
|
973
|
-
fail "Unknown vals: #{type.inspect}, #{vals.inspect}"
|
974
|
-
|
975
|
-
end # case
|
976
|
-
end # def to_clean_text
|
977
|
-
|
978
|
-
def in_html?
|
979
|
-
@state.last == :html
|
381
|
+
def raw_text str
|
382
|
+
fail "No block allowed." if block_given?
|
383
|
+
create(:text, :skip_escape=>true, :value=>str, :closed=>true)
|
384
|
+
go_up
|
980
385
|
end
|
981
386
|
|
982
|
-
def
|
983
|
-
@state.last == :create_html
|
984
|
-
end
|
387
|
+
def close
|
985
388
|
|
986
|
-
|
987
|
-
fail("No js event defined.") if @js.empty?
|
988
|
-
if args.empty?
|
989
|
-
@js.last
|
990
|
-
else
|
991
|
-
@js.last.concat args
|
992
|
-
end
|
993
|
-
end
|
389
|
+
group = find_nearest(:group)
|
994
390
|
|
995
|
-
|
996
|
-
|
391
|
+
if group
|
392
|
+
stay_or_go_up_to :group
|
393
|
+
final_parent = parent
|
997
394
|
|
998
|
-
|
999
|
-
|
395
|
+
# We set :groups=>true because
|
396
|
+
# we want tags created in the block to create their own
|
397
|
+
# group as a child element.
|
398
|
+
@tag[:groups] = true
|
1000
399
|
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
if @js.last.size == 2
|
1007
|
-
@js.pop
|
1008
|
-
@js.pop
|
400
|
+
@tag[:closed] = true
|
401
|
+
yield
|
402
|
+
@tag = final_parent
|
403
|
+
return self
|
1009
404
|
end
|
1010
405
|
|
1011
|
-
|
1012
|
-
end
|
406
|
+
@tag[:closed] = true
|
1013
407
|
|
1014
|
-
|
408
|
+
final_parent = parent
|
1015
409
|
|
1016
|
-
|
410
|
+
orig = @tag
|
1017
411
|
|
1018
|
-
|
1019
|
-
|
1020
|
-
# :head content might include a '!HEAD'
|
1021
|
-
# value.
|
1022
|
-
(page_title { 'Unknown Page Title' }) unless @page_title
|
1023
|
-
|
1024
|
-
Document_Template.
|
1025
|
-
sub('!BODY', to_clean_text(:html, @body)).
|
1026
|
-
sub('!HEAD', to_clean_text(:html, @head[:childs]))
|
1027
|
-
else
|
1028
|
-
to_clean_text(:html, @body[:childs])
|
1029
|
-
end
|
412
|
+
if block_given?
|
413
|
+
results = yield
|
1030
414
|
|
1031
|
-
|
415
|
+
# The :yield may have left some opened tags, :input, :br/
|
416
|
+
# So we make sure we are in the original tag/element
|
417
|
+
# when we want to make some final changes.
|
418
|
+
in_tag(orig) {
|
419
|
+
case
|
420
|
+
when tag?(:form)
|
421
|
+
input(:hidden, :auth_token, :auth_token.to_mustache(:html))
|
1032
422
|
|
1033
|
-
|
1034
|
-
|
423
|
+
when results.is_a?(::Symbol) && ancestor?(:script)
|
424
|
+
create :text, :skip_escape=>true, :value => results.to_mustache(:mustache, :html)
|
1035
425
|
|
426
|
+
when results.is_a?(::Symbol)
|
427
|
+
create :text, :skip_escape=>true, :value => results.to_mustache(:html)
|
1036
428
|
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
else
|
1042
|
-
super
|
429
|
+
when results.is_a?(::String)
|
430
|
+
text results
|
431
|
+
end
|
432
|
+
}
|
1043
433
|
end
|
1044
|
-
end
|
1045
434
|
|
1046
|
-
|
1047
|
-
js("add_class", [name])
|
1048
|
-
end
|
1049
|
-
|
1050
|
-
class Sanitize
|
435
|
+
@tag = final_parent
|
1051
436
|
|
1052
|
-
|
437
|
+
self
|
438
|
+
end # === close
|
1053
439
|
|
1054
|
-
|
440
|
+
public # =======================================================
|
1055
441
|
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
442
|
+
#
|
443
|
+
# Ex:
|
444
|
+
# div.id(:main) {
|
445
|
+
# style {
|
446
|
+
# div.__._ { .. }
|
447
|
+
# }
|
448
|
+
# }
|
449
|
+
#
|
450
|
+
# div {
|
451
|
+
# _.^(:sad) {
|
452
|
+
# color '#000'
|
453
|
+
# }
|
454
|
+
# }
|
455
|
+
def _
|
456
|
+
create :_
|
457
|
+
if block_given?
|
458
|
+
return(close { yield })
|
459
|
+
end
|
1066
460
|
|
1067
|
-
|
1068
|
-
|
1069
|
-
args.push(args.pop.to_s)
|
1070
|
-
end
|
1071
|
-
::Escape_Escape_Escape.send(name, *args)
|
1072
|
-
end
|
461
|
+
self
|
462
|
+
end # === def _
|
1073
463
|
|
1074
|
-
end # === class << self
|
1075
|
-
end # === class Sanitize
|
1076
464
|
|
1077
465
|
end # === class WWW_App ==========================================
|
1078
466
|
|
1079
|
-
__END__
|
1080
|
-
<!DOCTYPE html>
|
1081
|
-
<html lang="en">
|
1082
|
-
<head>
|
1083
|
-
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
1084
|
-
!HEAD
|
1085
|
-
</head>
|
1086
|
-
!BODY
|
1087
|
-
</html>
|