www_app 1.3.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|