wee 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/wee/holder.rb ADDED
@@ -0,0 +1,14 @@
1
+ class Wee::ValueHolder
2
+ attr_accessor :value
3
+
4
+ def initialize(value=nil)
5
+ @value = value
6
+ end
7
+ end
8
+
9
+ class Wee::StateHolder < Wee::ValueHolder
10
+ def initialize(value)
11
+ super
12
+ Wee::Session.current.state_registry << self
13
+ end
14
+ end
@@ -0,0 +1,379 @@
1
+ module Wee
2
+
3
+ class Canvas
4
+ def initialize
5
+ @parent_brush = nil
6
+ @current_brush = nil
7
+ end
8
+
9
+ def set_brush(brush)
10
+ # tell previous brush to finish
11
+ @current_brush.close if @current_brush
12
+
13
+ brush.parent = @parent_brush
14
+ brush.canvas = self
15
+ @current_brush = brush
16
+
17
+ return brush
18
+ end
19
+
20
+ def nest(&block)
21
+ @parent_brush = @current_brush
22
+ @current_brush = nil
23
+ block.call
24
+ @current_brush.close if @current_brush
25
+ @parent_brush = @parent_brush.parent
26
+ end
27
+ end
28
+
29
+ class HtmlCanvas < Canvas
30
+ attr_reader :context # the current Wee::RenderingContext
31
+ attr_reader :document
32
+ attr_accessor :current_component
33
+
34
+ def initialize(rendering_context)
35
+ @context = rendering_context
36
+ @document = rendering_context.document
37
+ end
38
+
39
+ def table(*args, &block)
40
+ handle(Brush::TableTag.new, *args, &block)
41
+ end
42
+
43
+ def table_row(*args, &block)
44
+ handle(Brush::TableRowTag.new, *args, &block)
45
+ end
46
+
47
+ def table_data(*args, &block)
48
+ handle(Brush::TableDataTag.new, *args, &block)
49
+ end
50
+
51
+ def table_header(*args, &block)
52
+ handle(Brush::TableHeaderTag.new, *args, &block)
53
+ end
54
+
55
+ def form(*args, &block)
56
+ handle(Brush::FormTag.new, *args, &block)
57
+ end
58
+
59
+ def input(*args, &block)
60
+ handle(Brush::InputTag.new, *args, &block)
61
+ end
62
+
63
+ def text_input(*args, &block)
64
+ handle(Brush::TextInputTag.new, *args, &block)
65
+ end
66
+
67
+ def submit_button(*args, &block)
68
+ handle(Brush::SubmitButtonTag.new, *args, &block)
69
+ end
70
+
71
+ def page(*args, &block)
72
+ handle(Brush::Page.new, *args, &block)
73
+ end
74
+
75
+ def anchor(*args, &block)
76
+ handle(Brush::AnchorTag.new, *args, &block)
77
+ end
78
+
79
+ def space(n=1)
80
+ set_brush(Brush::GenericTextBrush.new("&nbsp;"*n))
81
+ end
82
+
83
+ def break
84
+ set_brush(Brush::GenericTagBrush.new("br"))
85
+ end
86
+
87
+ def image
88
+ set_brush(Brush::GenericTagBrush.new("img"))
89
+ end
90
+
91
+ def text(str)
92
+ set_brush(Brush::GenericTextBrush.new(str))
93
+ end
94
+ alias << text
95
+
96
+ def render(obj)
97
+ obj.render_on(self)
98
+ nil
99
+ end
100
+
101
+ private
102
+
103
+ def handle(brush, *args, &block)
104
+ set_brush(brush)
105
+ if not args.empty? or block
106
+ brush.with(*args, &block)
107
+ else
108
+ brush
109
+ end
110
+ end
111
+ end
112
+
113
+ class Brush
114
+ attr_accessor :parent, :canvas
115
+
116
+ def with(*args, &block)
117
+ raise "either args or block, but not both" if block and not args.empty?
118
+
119
+ @canvas.nest(&block) if block
120
+ @closed = true
121
+ end
122
+
123
+ def close
124
+ with unless @closed
125
+ end
126
+ end
127
+
128
+ class Brush::GenericTextBrush < Brush
129
+ def initialize(text)
130
+ @text = text
131
+ end
132
+
133
+ def with
134
+ doc = @canvas.document
135
+ doc << @text
136
+ super
137
+ nil
138
+ end
139
+ end
140
+
141
+ class Brush::GenericTagBrush < Brush
142
+ def initialize(tag)
143
+ @tag = tag
144
+ @attributes = Hash.new
145
+ end
146
+
147
+ def id(x)
148
+ @attributes["id"] = x
149
+ self
150
+ end
151
+
152
+ def method_missing(m, arg)
153
+ @attributes[m.to_s] = arg.to_s
154
+ self
155
+ end
156
+
157
+ def with(text=nil, &block)
158
+ doc = @canvas.document
159
+ doc.start_tag(@tag, @attributes)
160
+ if text
161
+ doc.text(text)
162
+ super(text, &block)
163
+ else
164
+ super(&block)
165
+ end
166
+ doc.end_tag(@tag)
167
+ nil
168
+ end
169
+ end
170
+
171
+ class Brush::TableTag < Brush::GenericTagBrush
172
+ def initialize
173
+ super('table')
174
+ end
175
+ end
176
+
177
+ class Brush::TableRowTag < Brush::GenericTagBrush
178
+ def initialize
179
+ super('tr')
180
+ end
181
+
182
+ def align_top
183
+ @attributes['align'] = 'top'
184
+ self
185
+ end
186
+
187
+ def columns(*cols)
188
+ with {
189
+ cols.each {|col| @canvas.table_data(col) }
190
+ }
191
+ end
192
+
193
+ def headings(*headers)
194
+ with {
195
+ headers.each {|head| @canvas.table_heading(head) }
196
+ }
197
+ end
198
+
199
+ def spanning_column(str, colspan)
200
+ with {
201
+ @canvas.table_data.col_span(colspan).with(str)
202
+ }
203
+ end
204
+
205
+ def spacer
206
+ with {
207
+ @canvas.table_data { @canvas.space }
208
+ }
209
+ end
210
+ end
211
+
212
+
213
+ class Brush::InputTag < Brush::GenericTagBrush
214
+ def initialize
215
+ super('input')
216
+ end
217
+
218
+ %w(type name value size maxlength checked src).each do |meth|
219
+ eval %[
220
+ def #{ meth }(arg)
221
+ @attributes['#{ meth }'] = arg
222
+ self
223
+ end
224
+ ]
225
+ end
226
+
227
+ def with
228
+ super
229
+ end
230
+ end
231
+
232
+ class Brush::TextInputTag < Brush::InputTag
233
+ def initialize
234
+ super
235
+ type('text')
236
+ end
237
+
238
+ def attr(attr_name)
239
+ assign(attr_name.to_s + "=")
240
+ value(@canvas.current_component.send(attr_name))
241
+ self
242
+ end
243
+
244
+ def assign(act, obj=nil)
245
+ ctx = @canvas.context.context
246
+ obj ||= @canvas.current_component
247
+
248
+ name(ctx.handler_registry.handler_id_for_input(obj, act))
249
+ end
250
+ end
251
+
252
+ class Brush::SubmitButtonTag < Brush::InputTag
253
+ def initialize
254
+ super
255
+ type('submit')
256
+ end
257
+
258
+ # TODO: action for another object
259
+ def action(act, *args)
260
+ ctx = @canvas.context.context
261
+ obj = @canvas.current_component
262
+
263
+ name(ctx.handler_registry.handler_id_for_action(Wee::ActionHandler[obj, act, *args]))
264
+ end
265
+ end
266
+
267
+ class Brush::TableDataTag < Brush::GenericTagBrush
268
+ def initialize
269
+ super('td')
270
+ end
271
+
272
+ def align_top
273
+ @attributes['align'] = 'top'
274
+ self
275
+ end
276
+ end
277
+
278
+ class Brush::TableHeaderTag < Brush::GenericTagBrush
279
+ def initialize
280
+ super('th')
281
+ end
282
+ end
283
+
284
+ module Brush::ActionMixin
285
+ # TODO: action for another object
286
+ def action(act, *args)
287
+ ctx = @canvas.context.context
288
+ obj = @canvas.current_component
289
+ href = ctx.application.gen_handler_url(ctx.session_id, ctx.page_id,
290
+ act ? ctx.handler_registry.handler_id_for_action(Wee::ActionHandler[obj, act, *args]) : '')
291
+ __action(href)
292
+ end
293
+ end
294
+
295
+ class Brush::FormTag < Brush::GenericTagBrush
296
+ include Brush::ActionMixin
297
+
298
+ def initialize
299
+ super('form')
300
+ @attributes['method'] = 'POST'
301
+ end
302
+
303
+ def __action(href)
304
+ @attributes['action'] = href
305
+ self
306
+ end
307
+
308
+ def with(*args, &block)
309
+ action(nil) unless @attributes.has_key?('action')
310
+ super
311
+ end
312
+ end
313
+
314
+ class Brush::AnchorTag < Brush::GenericTagBrush
315
+ include Brush::ActionMixin
316
+
317
+ def initialize
318
+ super('a')
319
+ end
320
+
321
+ def url(href)
322
+ @attributes['href'] = href
323
+ self
324
+ end
325
+
326
+ alias __action url
327
+ end
328
+
329
+
330
+ class Brush::Page < Brush
331
+ def title(str)
332
+ @title = str
333
+ self
334
+ end
335
+
336
+ def with(text=nil, &block)
337
+ doc = @canvas.document
338
+ doc.start_tag("html")
339
+
340
+ if @title
341
+ doc.start_tag("head")
342
+ doc.start_tag("title")
343
+ doc.text(@title)
344
+ doc.end_tag("title")
345
+ doc.end_tag("head")
346
+ end
347
+
348
+ doc.start_tag("body")
349
+
350
+ if text
351
+ doc.text(text)
352
+ super(text, &block)
353
+ else
354
+ super(&block)
355
+ end
356
+
357
+ doc.end_tag("body")
358
+ doc.end_tag("html")
359
+ nil
360
+ end
361
+ end
362
+
363
+ end # module Wee
364
+
365
+ if __FILE__ == $0
366
+ require 'html_writer'
367
+
368
+ doc = Wee::HtmlWriter.new('')
369
+ c = Wee::HtmlCanvas.new(nil, doc)
370
+ c.form.url("foo").with {
371
+ c.table {
372
+ c.table_row.id("myrow").with {
373
+ c.table_data.align_top.with("Hello world")
374
+ }
375
+ }
376
+ c.space
377
+ }
378
+ puts doc.port
379
+ end
@@ -0,0 +1,63 @@
1
+ class Wee::HtmlWriter
2
+ attr_accessor :port
3
+
4
+ def initialize(port)
5
+ @port = port
6
+ @open_start_tag = false
7
+ @tag_stack = []
8
+ end
9
+
10
+ def start_tag(tag, attributes={})
11
+ @port << ">" if @open_start_tag
12
+ @open_start_tag = true
13
+ @tag_stack.push(tag)
14
+
15
+ @port << "<#{ tag }"
16
+ attributes.each {|k, v| @port << %[ #{ k }="#{ v }"] }
17
+
18
+ self
19
+ end
20
+
21
+ def end_tag(tag)
22
+ raise "unbalanced html" if @tag_stack.pop != tag
23
+
24
+ if @open_start_tag
25
+ @port << "/>"
26
+ @open_start_tag = false
27
+ else
28
+ @port << "</#{ tag }>"
29
+ end
30
+
31
+ self
32
+ end
33
+
34
+ def text(str)
35
+ if @open_start_tag
36
+ @port << ">"
37
+ @open_start_tag = false
38
+ end
39
+ @port << str.to_s
40
+
41
+ self
42
+ end
43
+ alias << text
44
+
45
+ def valid?
46
+ @tag_stack.empty?
47
+ end
48
+
49
+ end
50
+
51
+ if __FILE__ == $0
52
+ doc = ''
53
+ w = Wee::HtmlWriter.new(doc)
54
+
55
+ w.start_tag('html')
56
+
57
+ w.start_tag('blah')
58
+ w.end_tag('blah')
59
+
60
+ w.end_tag('html')
61
+ p w.valid?
62
+ p doc
63
+ end