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/CSS.rb
ADDED
@@ -0,0 +1,310 @@
|
|
1
|
+
|
2
|
+
class WWW_App
|
3
|
+
|
4
|
+
module CSS
|
5
|
+
COMMA = ", ".freeze
|
6
|
+
|
7
|
+
AT_RULES = [ 'font-face', 'media' ]
|
8
|
+
|
9
|
+
# === From:
|
10
|
+
# https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes
|
11
|
+
PSEUDO = %w[
|
12
|
+
active checked default dir() disabled
|
13
|
+
empty enabled
|
14
|
+
first first-child first-of-type fullscreen focus
|
15
|
+
hover
|
16
|
+
indeterminate in-range invalid
|
17
|
+
lang() last-child last-of-type left link
|
18
|
+
not() nth-child() nth-last-child() nth-last-of-type() nth-of-type()
|
19
|
+
only-child only-of-type optional out-of-range
|
20
|
+
read-only read-write required right root
|
21
|
+
scope
|
22
|
+
target
|
23
|
+
valid visited
|
24
|
+
].select { |name| name[/\A[a-z0-9\-]+\Z/] }.map { |name| name.gsub('-', '_').to_sym }
|
25
|
+
|
26
|
+
# From: Sanitize::Config::RELAXED[:css][:properties]
|
27
|
+
PROPERTIES = %w[
|
28
|
+
background bottom font_variant_position quotes
|
29
|
+
background_attachment box_decoration_break font_weight resize
|
30
|
+
background_clip box_shadow height right
|
31
|
+
background_color box_sizing hyphens tab_size
|
32
|
+
background_image clear icon table_layout
|
33
|
+
background_origin clip image_orientation text_align
|
34
|
+
background_position clip_path image_rendering text_align_last
|
35
|
+
background_repeat color image_resolution text_combine_horizontal
|
36
|
+
background_size column_count ime_mode text_decoration
|
37
|
+
border column_fill justify_content text_decoration_color
|
38
|
+
border_bottom column_gap left text_decoration_line
|
39
|
+
border_bottom_color column_rule letter_spacing text_decoration_style
|
40
|
+
border_bottom_left_radius column_rule_color line_height text_indent
|
41
|
+
border_bottom_right_radius column_rule_style list_style text_orientation
|
42
|
+
border_bottom_style column_rule_width list_style_image text_overflow
|
43
|
+
border_bottom_width column_span list_style_position text_rendering
|
44
|
+
border_collapse column_width list_style_type text_shadow
|
45
|
+
border_color columns margin text_size_adjust
|
46
|
+
border_image counter_increment margin_bottom text_transform
|
47
|
+
border_image_outset counter_reset margin_left text_underline_position
|
48
|
+
border_image_repeat cursor margin_right top
|
49
|
+
border_image_slice direction margin_top touch_action
|
50
|
+
border_image_source display marks transform
|
51
|
+
border_image_width empty_cells mask transform_origin
|
52
|
+
border_left filter mask_type transform_style
|
53
|
+
border_left_color float max_height transition
|
54
|
+
border_left_style font max_width transition_delay
|
55
|
+
border_left_width font_family min_height transition_duration
|
56
|
+
border_radius font_feature_settings min_width transition_property
|
57
|
+
border_right font_kerning opacity transition_timing_function
|
58
|
+
border_right_color font_language_override order unicode_bidi
|
59
|
+
border_right_style font_size orphans unicode_range
|
60
|
+
border_right_width font_size_adjust overflow vertical_align
|
61
|
+
border_spacing font_stretch overflow_wrap visibility
|
62
|
+
border_style font_style overflow_x white_space
|
63
|
+
border_top font_synthesis overflow_y widows
|
64
|
+
border_top_color font_variant padding width
|
65
|
+
border_top_left_radius font_variant_alternates padding_bottom word_break
|
66
|
+
border_top_right_radius font_variant_caps padding_left word_spacing
|
67
|
+
border_top_style font_variant_east_asian padding_right word_wrap
|
68
|
+
border_top_width font_variant_ligatures padding_top z_index
|
69
|
+
border_width font_variant_numeric position
|
70
|
+
].map(&:to_sym)
|
71
|
+
|
72
|
+
PROPERTIES.each { |name|
|
73
|
+
eval <<-EOF, nil, __FILE__, __LINE__ + 1
|
74
|
+
def #{name} *args
|
75
|
+
alter_css_property(:#{name}, *args)
|
76
|
+
block_given? ?
|
77
|
+
close { yield } :
|
78
|
+
self
|
79
|
+
end
|
80
|
+
EOF
|
81
|
+
}
|
82
|
+
|
83
|
+
PSEUDO.each { |name|
|
84
|
+
eval <<-EOF, nil, __FILE__, __LINE__ + 1
|
85
|
+
def _#{name} *args
|
86
|
+
pseudo :#{name}, *args
|
87
|
+
block_given? ?
|
88
|
+
close { yield } :
|
89
|
+
self
|
90
|
+
end
|
91
|
+
EOF
|
92
|
+
}
|
93
|
+
|
94
|
+
#
|
95
|
+
# Ex:
|
96
|
+
# style {
|
97
|
+
# div.^(:bad).__.div {
|
98
|
+
# }
|
99
|
+
#
|
100
|
+
def __
|
101
|
+
fail "Can only be used inside :style tag" unless ancestor?(:style)
|
102
|
+
|
103
|
+
if !@tag || (@tag[:tag_name] == :group || @tag[:tag_name] == :groups)
|
104
|
+
fail "Can only be used after an HTML element is created: #{@tag[:tag_name].inspect}"
|
105
|
+
end
|
106
|
+
|
107
|
+
@tag[:__] = true
|
108
|
+
go_up
|
109
|
+
self
|
110
|
+
end
|
111
|
+
|
112
|
+
#
|
113
|
+
# Example:
|
114
|
+
# style {
|
115
|
+
# a._link / a._hover {
|
116
|
+
# ...
|
117
|
+
# }
|
118
|
+
# }
|
119
|
+
#
|
120
|
+
# link.href('/file')./
|
121
|
+
#
|
122
|
+
def / *args
|
123
|
+
fail "No block allowed here." if block_given?
|
124
|
+
|
125
|
+
case args.size
|
126
|
+
when 0
|
127
|
+
close
|
128
|
+
when 1
|
129
|
+
self
|
130
|
+
else
|
131
|
+
fail ::ArgumentError, "Unknown args: #{args.inspect[0,50]}"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
#
|
136
|
+
# Example:
|
137
|
+
# css_selector
|
138
|
+
# css_selector tag
|
139
|
+
# css_selector :full || :tag || :ancestor
|
140
|
+
# css_selector tag, :full || :tag || :ancestor
|
141
|
+
#
|
142
|
+
def css_selector *args
|
143
|
+
tag = @tag
|
144
|
+
type = :full
|
145
|
+
args.each { |a|
|
146
|
+
case
|
147
|
+
when a.is_a?(Symbol)
|
148
|
+
type = a
|
149
|
+
else
|
150
|
+
tag = a
|
151
|
+
end
|
152
|
+
}
|
153
|
+
|
154
|
+
metaphor = (de_ref(tag) || {}.freeze)
|
155
|
+
|
156
|
+
final = case
|
157
|
+
|
158
|
+
when type == :full && tag?(metaphor, :group)
|
159
|
+
css = metaphor[:children].inject([]) { |memo, c|
|
160
|
+
if !(tag?(c, :group)) && !c[:__parent]
|
161
|
+
memo << css_selector(c, :full)
|
162
|
+
end
|
163
|
+
memo
|
164
|
+
}
|
165
|
+
|
166
|
+
if css
|
167
|
+
css.join COMMA
|
168
|
+
else
|
169
|
+
nil
|
170
|
+
end
|
171
|
+
|
172
|
+
when tag?(metaphor, :style)
|
173
|
+
p = metaphor[:parent]
|
174
|
+
if p
|
175
|
+
css_selector p, type
|
176
|
+
end
|
177
|
+
|
178
|
+
when type == :full && parent?(metaphor, :group)
|
179
|
+
grand_parent = metaphor[:parent][:parent]
|
180
|
+
grand_css = grand_parent && css_selector(grand_parent, :full)
|
181
|
+
use_grand = !(metaphor[:__] && metaphor[:__children].detect { |e| tag?(e, :_) })
|
182
|
+
|
183
|
+
if grand_css && use_grand
|
184
|
+
grand_css.split(COMMA).map { |css|
|
185
|
+
css << SPACE << css_selector(metaphor, :tag)
|
186
|
+
}.join COMMA
|
187
|
+
else
|
188
|
+
css_selector metaphor, :tag
|
189
|
+
end
|
190
|
+
|
191
|
+
when type == :tag
|
192
|
+
id = metaphor[:id]
|
193
|
+
name = if id
|
194
|
+
'#' << Clean.html_id(id).to_s
|
195
|
+
else
|
196
|
+
metaphor[:tag_name].to_s
|
197
|
+
end
|
198
|
+
|
199
|
+
if metaphor[:class]
|
200
|
+
name << '.'.freeze
|
201
|
+
name.<<(
|
202
|
+
metaphor[:class].map { |name|
|
203
|
+
Clean.css_class_name(name.to_s)
|
204
|
+
}.join('.'.freeze)
|
205
|
+
)
|
206
|
+
end
|
207
|
+
|
208
|
+
if metaphor[:pseudo]
|
209
|
+
name << ":#{metaphor[:pseudo]}"
|
210
|
+
end
|
211
|
+
|
212
|
+
if tag[:__]
|
213
|
+
name << SPACE << tag[:__children].map { |c|
|
214
|
+
css_selector(c, :tag)
|
215
|
+
}.join(SPACE)
|
216
|
+
end
|
217
|
+
|
218
|
+
name = if name.empty?
|
219
|
+
nil
|
220
|
+
else
|
221
|
+
name
|
222
|
+
end
|
223
|
+
|
224
|
+
when type == :ancestor
|
225
|
+
if metaphor[:id]
|
226
|
+
nil
|
227
|
+
else
|
228
|
+
selectors = []
|
229
|
+
p = metaphor[:parent]
|
230
|
+
while p
|
231
|
+
selectors.unshift(css_selector(p, :tag)) unless [:style, :group].freeze.include?(p[:tag_name])
|
232
|
+
p = p[:id] ? nil : p[:parent]
|
233
|
+
end # === while
|
234
|
+
|
235
|
+
selectors.compact.join(SPACE)
|
236
|
+
end
|
237
|
+
|
238
|
+
else
|
239
|
+
[css_selector(metaphor, :ancestor), css_selector(metaphor, :tag)].compact.join SPACE
|
240
|
+
end
|
241
|
+
|
242
|
+
return nil if !final || final.empty?
|
243
|
+
final.gsub(' _!:'.freeze, ':'.freeze)
|
244
|
+
end
|
245
|
+
|
246
|
+
private # ==================================
|
247
|
+
|
248
|
+
def pseudo name
|
249
|
+
origin = @tag
|
250
|
+
case
|
251
|
+
|
252
|
+
when tag?(:style)
|
253
|
+
#
|
254
|
+
# WHEN:
|
255
|
+
#
|
256
|
+
# style {
|
257
|
+
# _link {
|
258
|
+
#
|
259
|
+
create :group
|
260
|
+
create :_
|
261
|
+
|
262
|
+
when ancestor?(:groups) && @tag[:closed]
|
263
|
+
#
|
264
|
+
# WHEN:
|
265
|
+
#
|
266
|
+
# style {
|
267
|
+
# div { ... }
|
268
|
+
# _link { ... }
|
269
|
+
#
|
270
|
+
create :group
|
271
|
+
create :_!
|
272
|
+
|
273
|
+
when (tag?(:_) || tag?(:_!)) && @tag[:pseudo]
|
274
|
+
# WHEN:
|
275
|
+
# style {
|
276
|
+
# _link / _visited
|
277
|
+
tag_name = @tag[:tag_name]
|
278
|
+
go_up
|
279
|
+
create tag_name
|
280
|
+
|
281
|
+
when @tag[:pseudo] && !@tag[:closed]
|
282
|
+
puts @tag
|
283
|
+
# Ex:
|
284
|
+
# a._link._visited { ... }
|
285
|
+
fail "Applying two pseudos at the same element: #{@tag[:pseudo].inspect} #{name.inspect}"
|
286
|
+
|
287
|
+
end # === case
|
288
|
+
|
289
|
+
@tag[:pseudo] = name
|
290
|
+
block_given? ?
|
291
|
+
close { yield } :
|
292
|
+
self
|
293
|
+
end
|
294
|
+
|
295
|
+
def alter_css_property name, *args
|
296
|
+
if !@tag
|
297
|
+
self._
|
298
|
+
end
|
299
|
+
@tag[:css] ||= {}
|
300
|
+
@tag[:css][name] = args.size == 1 ? args.first : args
|
301
|
+
self
|
302
|
+
end
|
303
|
+
|
304
|
+
def style
|
305
|
+
create :style, :type=>'text/css', :groups=>true
|
306
|
+
close { yield }
|
307
|
+
end
|
308
|
+
|
309
|
+
end # === module CSS ==============
|
310
|
+
end # === class WWW_App =============
|
data/lib/www_app/HTML.rb
ADDED
@@ -0,0 +1,219 @@
|
|
1
|
+
|
2
|
+
class WWW_App
|
3
|
+
module HTML
|
4
|
+
|
5
|
+
SELF_CLOSING_TAGS = [:br, :input, :link, :meta, :hr, :img]
|
6
|
+
NO_NEW_LINES = [:p, :code, :span].freeze
|
7
|
+
|
8
|
+
TAGS = %w[
|
9
|
+
title
|
10
|
+
body div span
|
11
|
+
|
12
|
+
img
|
13
|
+
b em i strong u a
|
14
|
+
abbr blockquote cite
|
15
|
+
br cite code
|
16
|
+
ul ol li p pre q
|
17
|
+
sup sub
|
18
|
+
form input button
|
19
|
+
|
20
|
+
link
|
21
|
+
|
22
|
+
script
|
23
|
+
].map(&:to_sym)
|
24
|
+
|
25
|
+
TAGS_TO_ATTRIBUTES = {
|
26
|
+
:all => [:id, :class],
|
27
|
+
:a => [:href, :rel],
|
28
|
+
:form => [:action, :method, :accept_charset],
|
29
|
+
:input => [:type, :name, :value],
|
30
|
+
:style => [:type],
|
31
|
+
:script => [:type, :src, :language],
|
32
|
+
:link => [:rel, :type, :sizes, :href, :title],
|
33
|
+
:meta => [:name, :http_equiv, :property, :content, :charset],
|
34
|
+
:img => [:src], # :width, :height will be used by CSS only.
|
35
|
+
:html => [:lang]
|
36
|
+
}
|
37
|
+
|
38
|
+
ATTRIBUTES_TO_TAGS = TAGS_TO_ATTRIBUTES.inject({}) { |memo, (tag, attrs)|
|
39
|
+
attrs.each { |a|
|
40
|
+
memo[a] ||= []
|
41
|
+
memo[a] << tag
|
42
|
+
}
|
43
|
+
memo
|
44
|
+
}
|
45
|
+
|
46
|
+
ATTRIBUTES = ATTRIBUTES_TO_TAGS.keys
|
47
|
+
|
48
|
+
ATTRIBUTES_TO_TAGS.each { |name, tags|
|
49
|
+
eval <<-EOF, nil, __FILE__, __LINE__ + 1
|
50
|
+
def #{name} val
|
51
|
+
alter_attribute :#{name}, val
|
52
|
+
block_given? ?
|
53
|
+
close { yield } :
|
54
|
+
self
|
55
|
+
end
|
56
|
+
EOF
|
57
|
+
}
|
58
|
+
|
59
|
+
TAGS.each { |name|
|
60
|
+
eval <<-EOF, nil, __FILE__, __LINE__ + 1
|
61
|
+
def #{name}
|
62
|
+
create(:#{name})
|
63
|
+
block_given? ?
|
64
|
+
close { yield } :
|
65
|
+
self
|
66
|
+
end
|
67
|
+
EOF
|
68
|
+
}
|
69
|
+
|
70
|
+
def alter_attribute name, val
|
71
|
+
allowed = @tag &&
|
72
|
+
ATTRIBUTES_TO_TAGS[name] &&
|
73
|
+
ATTRIBUTES_TO_TAGS[name].include?(@tag[:tag_name])
|
74
|
+
|
75
|
+
fail "#{name.inspect} not allowed to be set here." unless allowed
|
76
|
+
|
77
|
+
@tag[name] = val
|
78
|
+
|
79
|
+
block_given? ?
|
80
|
+
close { yield } :
|
81
|
+
self
|
82
|
+
end
|
83
|
+
|
84
|
+
def meta *args
|
85
|
+
fail "No block allowed." if block_given?
|
86
|
+
fail "Not allowed here." if parent
|
87
|
+
create(:meta, *args)
|
88
|
+
end
|
89
|
+
|
90
|
+
def title
|
91
|
+
fail ":title not allowed here" if parent
|
92
|
+
create :title do
|
93
|
+
yield
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def id new_id
|
98
|
+
if !@tag
|
99
|
+
fail "No HTML tag found. Try using _.id(#{new_id.inspect})"
|
100
|
+
end
|
101
|
+
|
102
|
+
if !ancestor?(:group)
|
103
|
+
old_id = @tag[:id]
|
104
|
+
if old_id && old_id != new_id
|
105
|
+
fail("Id already set: #{old_id} new: #{new_id}")
|
106
|
+
end
|
107
|
+
|
108
|
+
if @html_ids[new_id]
|
109
|
+
fail(HTML_ID_Duplicate, "Id already used: #{new_id.inspect}, tag index: #{@html_ids[new_id]}")
|
110
|
+
end
|
111
|
+
@html_ids[ new_id ] = new_id
|
112
|
+
end
|
113
|
+
|
114
|
+
@tag[:id] = new_id
|
115
|
+
|
116
|
+
if block_given?
|
117
|
+
close { yield }
|
118
|
+
else
|
119
|
+
self
|
120
|
+
end
|
121
|
+
end # === def id
|
122
|
+
|
123
|
+
def is_fragment?
|
124
|
+
!is_doc?
|
125
|
+
end
|
126
|
+
|
127
|
+
def is_doc?
|
128
|
+
@is_doc ||= begin
|
129
|
+
found = false
|
130
|
+
tags = @tags.dup
|
131
|
+
while !found && !tags.empty?
|
132
|
+
t = tags.shift
|
133
|
+
found = begin
|
134
|
+
(t[:tag_name] == :body && (t[:id] || t[:css]) ) ||
|
135
|
+
t[:tag_name] == :style ||
|
136
|
+
t[:tag_name] == :script ||
|
137
|
+
t[:tag_name] == :meta ||
|
138
|
+
t[:css] ||
|
139
|
+
(t[:tag_name] == :title && t[:parent] && t[:parent][:tag_name] == :body)
|
140
|
+
end
|
141
|
+
if !found && t[:children]
|
142
|
+
tags = t[:children].concat(tags)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
found
|
147
|
+
end
|
148
|
+
end # === def is_doc?
|
149
|
+
|
150
|
+
def lang name
|
151
|
+
fail "Tag has to be placed tomost of the page." if parent
|
152
|
+
fail "Block not allowed here." if block_given?
|
153
|
+
create :html_tag_attr do
|
154
|
+
@tag[:lang] = name.to_s.downcase.gsub(/[^a-z0-9\_\-]+/, ''.freeze)
|
155
|
+
@tag[:lang] = 'en' if @tag[:lang].empty?
|
156
|
+
end
|
157
|
+
|
158
|
+
self
|
159
|
+
end
|
160
|
+
|
161
|
+
#
|
162
|
+
# Example:
|
163
|
+
# div.^(:alert, :red_hot) { 'my content' }
|
164
|
+
#
|
165
|
+
def ^ *names
|
166
|
+
@tag[:class] ||= []
|
167
|
+
@tag[:class].concat(names)
|
168
|
+
|
169
|
+
if block_given?
|
170
|
+
close { yield }
|
171
|
+
else
|
172
|
+
self
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def render_if name
|
177
|
+
fail ::ArgumentError, "Not a symbol: #{name.inspect}" unless name.is_a?(Symbol)
|
178
|
+
raw_text %^{{#coll.#{name}}}^
|
179
|
+
yield
|
180
|
+
raw_text %^{{/coll.#{name}}}^
|
181
|
+
nil
|
182
|
+
end
|
183
|
+
|
184
|
+
def render_unless name
|
185
|
+
fail ::ArgumentError, "Not a symbol: #{name.inspect}" unless name.is_a?(Symbol)
|
186
|
+
raw_text %!{{^coll.#{name}}}!
|
187
|
+
yield
|
188
|
+
raw_text %!{{/coll.#{name}}}!
|
189
|
+
nil
|
190
|
+
end
|
191
|
+
|
192
|
+
def input *args
|
193
|
+
case
|
194
|
+
when args.size === 3
|
195
|
+
create(:input, :type=>args[0].to_s, :name=>args[1].to_s, :value=>args[2], :closed=>true)
|
196
|
+
go_up
|
197
|
+
else
|
198
|
+
super
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def script src = nil
|
203
|
+
|
204
|
+
if src.is_a?(String) && src['.js'.freeze]
|
205
|
+
return create(:script, :src=>src) { }
|
206
|
+
end
|
207
|
+
|
208
|
+
attrs = {
|
209
|
+
:type => src || "text/mustache"
|
210
|
+
}
|
211
|
+
|
212
|
+
create :script, attrs
|
213
|
+
close { yield } if block_given?
|
214
|
+
self
|
215
|
+
end
|
216
|
+
|
217
|
+
end # === module HTML
|
218
|
+
end # === class WWW_App
|
219
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
|
2
|
+
class WWW_App
|
3
|
+
module JavaScript
|
4
|
+
|
5
|
+
class DSL < BasicObject
|
6
|
+
|
7
|
+
include ::Kernel
|
8
|
+
|
9
|
+
def initialize &blok
|
10
|
+
@js = []
|
11
|
+
instance_eval &blok
|
12
|
+
end
|
13
|
+
|
14
|
+
%w[ add_class ].each { |name|
|
15
|
+
eval <<-EOF, nil, __FILE__, __LINE__ + 1
|
16
|
+
def #{name} *args
|
17
|
+
run_method :#{name}, args
|
18
|
+
end
|
19
|
+
EOF
|
20
|
+
}
|
21
|
+
def run_method name, args
|
22
|
+
self << name
|
23
|
+
self << args
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
def raw_code
|
28
|
+
@js
|
29
|
+
end
|
30
|
+
|
31
|
+
def concat arr
|
32
|
+
@js.concat(arr)
|
33
|
+
end
|
34
|
+
|
35
|
+
def << *args
|
36
|
+
@js.<<(*args)
|
37
|
+
end
|
38
|
+
|
39
|
+
def capture &blok
|
40
|
+
orig = @js
|
41
|
+
new = []
|
42
|
+
@js = new
|
43
|
+
instance_eval &blok
|
44
|
+
@js = orig
|
45
|
+
new
|
46
|
+
end
|
47
|
+
|
48
|
+
end # === class DSL
|
49
|
+
|
50
|
+
end # === module JavaScript
|
51
|
+
end # === class WWW_App
|