mullen-wee 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. data/README.rdoc +127 -0
  2. data/Rakefile +25 -0
  3. data/aWee.gemspec +26 -0
  4. data/examples/ObjectSpaceBrowser.rb +191 -0
  5. data/examples/ajax.rb +73 -0
  6. data/examples/apotomo-webhunter/main.rb +75 -0
  7. data/examples/apotomo-webhunter/public/images/bear_trap_charged.png +0 -0
  8. data/examples/apotomo-webhunter/public/images/bear_trap_snapped.png +0 -0
  9. data/examples/apotomo-webhunter/public/images/cheese.png +0 -0
  10. data/examples/apotomo-webhunter/public/images/dark_forest.jpg +0 -0
  11. data/examples/apotomo-webhunter/public/images/mouse.png +0 -0
  12. data/examples/apotomo-webhunter/public/javascripts/jquery-1.3.2.min.js +19 -0
  13. data/examples/apotomo-webhunter/public/javascripts/wee-jquery.js +19 -0
  14. data/examples/apotomo-webhunter/public/stylesheets/forest.css +33 -0
  15. data/examples/arc_challenge.rb +42 -0
  16. data/examples/arc_challenge2.rb +46 -0
  17. data/examples/cheese_task.rb +27 -0
  18. data/examples/continuations.rb +28 -0
  19. data/examples/demo.rb +135 -0
  20. data/examples/demo/calculator.rb +63 -0
  21. data/examples/demo/calendar.rb +333 -0
  22. data/examples/demo/counter.rb +38 -0
  23. data/examples/demo/editable_counter.rb +36 -0
  24. data/examples/demo/example.rb +142 -0
  25. data/examples/demo/file_upload.rb +19 -0
  26. data/examples/demo/messagebox.rb +15 -0
  27. data/examples/demo/radio.rb +33 -0
  28. data/examples/demo/window.rb +71 -0
  29. data/examples/hw.rb +11 -0
  30. data/examples/i18n/app.rb +16 -0
  31. data/examples/i18n/locale/de/app.po +25 -0
  32. data/examples/i18n/locale/en/app.po +25 -0
  33. data/examples/pager.rb +102 -0
  34. data/lib/wee.rb +109 -0
  35. data/lib/wee/application.rb +89 -0
  36. data/lib/wee/callback.rb +109 -0
  37. data/lib/wee/component.rb +363 -0
  38. data/lib/wee/decoration.rb +251 -0
  39. data/lib/wee/dialog.rb +171 -0
  40. data/lib/wee/external_resource.rb +39 -0
  41. data/lib/wee/html_brushes.rb +795 -0
  42. data/lib/wee/html_canvas.rb +254 -0
  43. data/lib/wee/html_document.rb +52 -0
  44. data/lib/wee/html_writer.rb +71 -0
  45. data/lib/wee/id_generator.rb +81 -0
  46. data/lib/wee/jquery.rb +11 -0
  47. data/lib/wee/jquery/jquery-1.3.2.min.js +19 -0
  48. data/lib/wee/jquery/wee-jquery.js +19 -0
  49. data/lib/wee/locale.rb +56 -0
  50. data/lib/wee/lru_cache.rb +91 -0
  51. data/lib/wee/presenter.rb +44 -0
  52. data/lib/wee/renderer.rb +72 -0
  53. data/lib/wee/request.rb +56 -0
  54. data/lib/wee/response.rb +68 -0
  55. data/lib/wee/rightjs.rb +11 -0
  56. data/lib/wee/rightjs/rightjs-1.5.2.min.js +9 -0
  57. data/lib/wee/rightjs/wee-rightjs.js +18 -0
  58. data/lib/wee/root_component.rb +45 -0
  59. data/lib/wee/session.rb +366 -0
  60. data/lib/wee/state.rb +102 -0
  61. data/lib/wee/task.rb +16 -0
  62. data/test/bm_render.rb +34 -0
  63. data/test/component_spec.rb +40 -0
  64. data/test/stress/plotter.rb +84 -0
  65. data/test/stress/stress_client.rb +51 -0
  66. data/test/stress/stress_local.rb +86 -0
  67. data/test/stress/stress_server.rb +83 -0
  68. data/test/test_component.rb +106 -0
  69. data/test/test_html_canvas.rb +25 -0
  70. data/test/test_html_writer.rb +32 -0
  71. data/test/test_lru_cache.rb +51 -0
  72. data/test/test_request.rb +42 -0
  73. metadata +185 -0
@@ -0,0 +1,38 @@
1
+ class Counter < Wee::Component
2
+ attr_accessor :count
3
+
4
+ def initialize(initial_count=0)
5
+ @count = initial_count
6
+ add_decoration Wee::StyleDecoration.new(self)
7
+ end
8
+
9
+ def state(s) super
10
+ s.add_ivar(self, :@count)
11
+ end
12
+
13
+ def dec
14
+ @count -= 1
15
+ end
16
+
17
+ def inc
18
+ @count += 1
19
+ end
20
+
21
+ def style
22
+ ".wee-Counter a { border: 1px dotted blue; margin: 2px; }"
23
+ end
24
+
25
+ def render(r)
26
+ r.div.oid.css_class('wee-Counter').with {
27
+ r.anchor.callback_method(:dec).with("--")
28
+ r.space
29
+ render_count(r)
30
+ r.space
31
+ r.anchor.callback_method(:inc).with("++")
32
+ }
33
+ end
34
+
35
+ def render_count(r)
36
+ r.text @count.to_s
37
+ end
38
+ end
@@ -0,0 +1,36 @@
1
+ # NEEDS: FormDecoration
2
+
3
+ require 'demo/counter'
4
+
5
+ class EditableCounter < Counter
6
+
7
+ def initialize(initial_count=0)
8
+ super
9
+ @show_edit_field = false
10
+ end
11
+
12
+ def state(s)
13
+ super
14
+ s.add_ivar(self, :@show_edit_field, @show_edit_field)
15
+ end
16
+
17
+ def render_count(r)
18
+ if @show_edit_field
19
+ r.text_input.value(@count).size(6).callback {|val| self.count = val}
20
+ r.submit_button.value('S').callback { submit }
21
+ else
22
+ r.anchor.callback { submit }.with(@count)
23
+ end
24
+ end
25
+
26
+ def submit
27
+ if @count.to_s !~ /^\d+$/
28
+ call Wee::MessageBox.new("You entered an invalid counter! Please try again!")
29
+ @count = 0
30
+ else
31
+ @show_edit_field = !@show_edit_field
32
+ end
33
+ @count = @count.to_i
34
+ end
35
+
36
+ end
@@ -0,0 +1,142 @@
1
+ $LOAD_PATH.unshift "../lib"
2
+ require 'rubygems'
3
+ require 'wee'
4
+
5
+ require 'demo/window'
6
+ require 'demo/editable_counter'
7
+ require 'demo/messagebox'
8
+
9
+ class RegexpValidatedInput < Wee::Component
10
+
11
+ def initialize(init_value, regexp)
12
+ super()
13
+ @regexp = regexp
14
+ self.value = init_value
15
+ @error = false
16
+ end
17
+
18
+ def state(s)
19
+ super
20
+ s.add(self)
21
+ end
22
+
23
+ def value
24
+ @value
25
+ end
26
+
27
+ def value=(new_value)
28
+ raise unless new_value =~ @regexp
29
+ @input = @value = new_value
30
+ end
31
+
32
+ def render(r)
33
+ r.form do
34
+ r.text_input.value(@input).callback {|val| self.input = val }
35
+ r.text %(<div style="color: red">Invalid input</div>) if @error
36
+ end
37
+ end
38
+
39
+ def input
40
+ @input
41
+ end
42
+
43
+ def input=(str)
44
+ @input = str
45
+
46
+ if @input =~ @regexp
47
+ @value = str
48
+ @error = false
49
+ else
50
+ @error = true
51
+ end
52
+ end
53
+
54
+ end
55
+
56
+ class MainPage < Wee::Component
57
+ def initialize
58
+ super()
59
+ @counters = (1..10).map {|i|
60
+ Window.new {|w|
61
+ w.title = "Cnt #{ i }"
62
+ w.pos_x = "200px"
63
+ w.pos_y = "#{i*50}px"
64
+ w << EditableCounter.new(i)
65
+ }
66
+ }
67
+
68
+ @val_inp = RegexpValidatedInput.new('Michael Neumann', /^\w+\s+\w+$/)
69
+
70
+ @arr = []
71
+ @text = ""
72
+
73
+ @list1 = (0..9).to_a
74
+ @selected1 = []
75
+ @list2 = []
76
+ @selected2 = []
77
+ end
78
+
79
+ def children
80
+ [@val_inp, *@counters]
81
+ end
82
+
83
+ def state(s)
84
+ super
85
+ s.add(@counters)
86
+ state_decoration(s)
87
+ s.add(@arr)
88
+ s.add(@text)
89
+
90
+ s.add(@list1)
91
+ s.add(@selected1)
92
+ s.add(@list2)
93
+ s.add(@selected2)
94
+ end
95
+
96
+ attr_accessor :text
97
+
98
+ def render(r)
99
+ r.page.title("Counter Test").with do
100
+
101
+ r.form do
102
+ r.select_list(@list1).size(10).multiple.selected(@selected1).callback {|choosen| @selected1.replace(choosen)}
103
+ r.submit_button.value('-&gt;').callback { @list2.push(*@selected1); @list1.replace(@list1-@selected1); @selected1.replace([]) }
104
+ r.submit_button.value('&lt;-').callback { @list1.push(*@selected2); @list2.replace(@list2-@selected2); @selected2.replace([]) }
105
+ r.select_list(@list2).size(10).multiple.selected(@selected2).callback {|choosen| @selected2.replace(choosen)}
106
+ end
107
+
108
+ r.form do
109
+
110
+ @counters.each { |cnt|
111
+ r.render(cnt)
112
+ }
113
+
114
+ r.render(@val_inp)
115
+
116
+ @arr.each do |a|
117
+ r.text(a)
118
+ r.break
119
+ end
120
+
121
+ end
122
+
123
+ r.form do
124
+ r.text_input.value(@text).callback{|val| @text = val}
125
+ r.submit_button.callback{add}.value('add')
126
+ end
127
+
128
+ end
129
+ end
130
+
131
+ def add
132
+ call Wee::MessageBox.new("Do you really want to add '" + @text + "'?") do |res|
133
+ if res
134
+ call Wee::MessageBox.new("Do you really really really want to add '" + @text + "'?") do |res2|
135
+ @arr << @text if res2
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
141
+
142
+ Wee.run(MainPage) if __FILE__ == $0
@@ -0,0 +1,19 @@
1
+ class FileUploadTest < Wee::Component
2
+ def render(r)
3
+ r.file_upload.callback {|f| call Uploaded.new(f[:tempfile]) }
4
+ r.break
5
+ r.submit_button.name('Upload')
6
+ end
7
+
8
+ class Uploaded < Wee::Component
9
+ def initialize(file)
10
+ super()
11
+ @file = file
12
+ end
13
+
14
+ def render(r)
15
+ r.pre { r.encode_text @file.read }
16
+ r.anchor.callback_method(:answer).with('back')
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ class Wee::MessageBox < Wee::Component
2
+ def initialize(text)
3
+ super()
4
+ @text = text
5
+ end
6
+
7
+ def render(r)
8
+ r.bold(@text)
9
+ r.form do
10
+ r.submit_button.value('OK').callback { answer true }
11
+ r.space
12
+ r.submit_button.value('Cancel').callback { answer false }
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,33 @@
1
+ class RadioTest < Wee::Component
2
+ def render(r)
3
+ grp1 = r.new_radio_group
4
+ grp2 = r.new_radio_group
5
+
6
+ r.paragraph
7
+ r.text "Group1"
8
+ r.text " (your choice: #{@g1})" if @g1
9
+ r.break
10
+
11
+ r.text "R1: "
12
+ r.radio_button.group(grp1).checked(@g1.nil? || @g1 == 'R1').callback { @g1 = 'R1' }
13
+ r.break
14
+
15
+ r.text "R2: "
16
+ r.radio_button.group(grp1).checked(@g1 == 'R2').callback { @g1 = 'R2' }
17
+
18
+ r.paragraph
19
+ r.text "Group2"
20
+ r.text " (your choice: #{@g2})" if @g2
21
+ r.break
22
+
23
+ r.text "R1: "
24
+ r.radio_button.group(grp2).checked(@g2.nil? || @g2 == 'R1').callback { @g2 = 'R1' }
25
+ r.break
26
+
27
+ r.text "R2: "
28
+ r.radio_button.group(grp2).checked(@g2 == 'R2').callback { @g2 = 'R2' }
29
+
30
+ r.paragraph
31
+ r.submit_button.value('Submit')
32
+ end
33
+ end
@@ -0,0 +1,71 @@
1
+ class Window < Wee::Component
2
+
3
+ attr_accessor :title, :pos_x, :pos_y
4
+
5
+ def initialize(&block)
6
+ super()
7
+ @status = :normal
8
+ @pos_x, @pos_y = "0px", "0px"
9
+ @children = []
10
+ block.call(self) if block
11
+ end
12
+
13
+ def <<(c)
14
+ @children << c
15
+ end
16
+
17
+ def children() @children end
18
+
19
+ def state(s)
20
+ super
21
+ s.add_ivar(self, :@status, @status)
22
+ end
23
+
24
+ def process_callbacks(callbacks)
25
+ return if @status == :closed
26
+ super
27
+ end
28
+
29
+ def render(r)
30
+ return if @status == :closed
31
+
32
+ r.table.cellspacing(0).style("border:solid 1px grey; position: absolute; left: #{@pos_x}; top: #{@pos_y};").with do
33
+ r.table_row.style("background-color: lightblue; width: 100%").with do
34
+ r.table_data.style("text-align: left; width: 66%").with(@title)
35
+ r.table_data.style("text-align: right").with do
36
+ if @status == :minimized
37
+ r.anchor.callback{maximize}.with("^")
38
+ else
39
+ r.anchor.callback{minimize}.with("_")
40
+ end
41
+ r.space
42
+ r.anchor.callback{close}.with("x")
43
+ end
44
+ end
45
+ r.table_row do
46
+ r.table_data.colspan(2).with do
47
+ if @status == :normal
48
+ for child in self.children do
49
+ r.render(child)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ public
58
+
59
+ def minimize
60
+ @status = :minimized
61
+ end
62
+
63
+ def maximize
64
+ @status = :normal
65
+ end
66
+
67
+ def close
68
+ @status = :closed
69
+ end
70
+
71
+ end
@@ -0,0 +1,11 @@
1
+ $LOAD_PATH.unshift "../lib"
2
+ require 'rubygems' if RUBY_VERSION < "1.9"
3
+ require 'wee'
4
+
5
+ class HelloWorld < Wee::RootComponent
6
+ def render(r)
7
+ r.h1 "Hello World from Wee!"
8
+ end
9
+ end
10
+
11
+ Wee.run(HelloWorld) if __FILE__ == $0
@@ -0,0 +1,16 @@
1
+ $LOAD_PATH.unshift "../../lib"
2
+ require 'rubygems'
3
+ require 'wee'
4
+ require 'wee/locale'
5
+
6
+ class HelloWorld < Wee::RootComponent
7
+ def render(r)
8
+ r.h1 _("Hello World!")
9
+ r.select_list(%w(en de)).selected(session.locale).labels(["English", "Deutsch"]).callback {|lang| session.locale = lang}
10
+ r.submit_button.value(_("Set"))
11
+ end
12
+ end
13
+
14
+ Wee::Application.load_locale("app", %w(en de), "en", :path => "locale", :type => :po)
15
+
16
+ HelloWorld.run if __FILE__ == $0
@@ -0,0 +1,25 @@
1
+ # SOME DESCRIPTIVE TITLE.
2
+ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3
+ # This file is distributed under the same license as the PACKAGE package.
4
+ # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5
+ #
6
+ #, fuzzy
7
+ msgid ""
8
+ msgstr ""
9
+ "Project-Id-Version: PACKAGE VERSION\n"
10
+ "POT-Creation-Date: 2010-01-05 00:27+0100\n"
11
+ "PO-Revision-Date: 2010-01-05 00:27+0100\n"
12
+ "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13
+ "Language-Team: LANGUAGE <LL@li.org>\n"
14
+ "MIME-Version: 1.0\n"
15
+ "Content-Type: text/plain; charset=UTF-8\n"
16
+ "Content-Transfer-Encoding: 8bit\n"
17
+ "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
18
+
19
+ #: app.rb:8
20
+ msgid "Hello World!"
21
+ msgstr "Hallo Welt!"
22
+
23
+ #: app.rb:10
24
+ msgid "Set"
25
+ msgstr "Einstellen"
@@ -0,0 +1,25 @@
1
+ # SOME DESCRIPTIVE TITLE.
2
+ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3
+ # This file is distributed under the same license as the PACKAGE package.
4
+ # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5
+ #
6
+ #, fuzzy
7
+ msgid ""
8
+ msgstr ""
9
+ "Project-Id-Version: PACKAGE VERSION\n"
10
+ "POT-Creation-Date: 2010-01-05 00:27+0100\n"
11
+ "PO-Revision-Date: 2010-01-05 00:27+0100\n"
12
+ "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13
+ "Language-Team: LANGUAGE <LL@li.org>\n"
14
+ "MIME-Version: 1.0\n"
15
+ "Content-Type: text/plain; charset=UTF-8\n"
16
+ "Content-Transfer-Encoding: 8bit\n"
17
+ "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
18
+
19
+ #: app.rb:8
20
+ msgid "Hello World!"
21
+ msgstr ""
22
+
23
+ #: app.rb:10
24
+ msgid "Set"
25
+ msgstr ""
@@ -0,0 +1,102 @@
1
+ class Pager < Wee::Component
2
+ attr_accessor :num_entries, :entries_per_page
3
+ attr_reader :current_page
4
+
5
+ def initialize(num_entries=0)
6
+ super()
7
+ @num_entries = num_entries
8
+ @current_page = 0
9
+ @entries_per_page = 20
10
+ yield self if block_given?
11
+ end
12
+
13
+ # Returns the number of pages
14
+
15
+ def num_pages
16
+ n, rest = @num_entries.divmod(@entries_per_page)
17
+ if rest > 0 then n + 1 else n end
18
+ end
19
+
20
+ # Returns the index of the first entry on the current page
21
+
22
+ def current_start_index
23
+ @current_page * @entries_per_page
24
+ end
25
+
26
+ # Returns the index of the last page
27
+
28
+ def last_page_index
29
+ num_pages() - 1
30
+ end
31
+
32
+ # Go to first page
33
+
34
+ def first
35
+ goto(0)
36
+ end
37
+
38
+ # Go to last page
39
+
40
+ def last
41
+ goto(last_page_index())
42
+ end
43
+
44
+ # Go to previous page
45
+
46
+ def prev
47
+ goto(@current_page - 1)
48
+ end
49
+
50
+ # Go to next page
51
+
52
+ def next
53
+ goto(@current_page + 1)
54
+ end
55
+
56
+ # Go to page with index +page+
57
+ # Note that page-indices start with zero!
58
+
59
+ def goto(page)
60
+ @current_page = page
61
+ validate
62
+ end
63
+
64
+ def render(r)
65
+ return if num_pages() <= 0
66
+ render_arrow(r, :first, "<<", "Go to first page"); r.space(2)
67
+ render_arrow(r, :prev, "<", "Go to previous page"); r.space(2)
68
+ render_index(r); r.space(2)
69
+ render_arrow(r, :next, ">", "Go to next page"); r.space(2)
70
+ render_arrow(r, :last, ">>", "Go to last page")
71
+ end
72
+
73
+ private
74
+
75
+ def render_arrow(r, sym, text, tooltip=text)
76
+ r.anchor.callback_method(sym).tooltip(tooltip).with { r.encode_text(text) }
77
+ end
78
+
79
+ def render_index(r)
80
+ last = last_page_index()
81
+ (0 .. last).each do |i|
82
+ if i == @current_page
83
+ render_page_num(r, i, true)
84
+ else
85
+ render_page_num(r, i, false)
86
+ end
87
+ r.space if i < last
88
+ end
89
+ end
90
+
91
+ def render_page_num(r, num, current)
92
+ if current
93
+ r.bold(num+1)
94
+ else
95
+ r.anchor.callback{ goto(num) }.with(num+1)
96
+ end
97
+ end
98
+
99
+ def validate
100
+ @current_page = [[0, @current_page].max, last_page_index()].min
101
+ end
102
+ end