mullen-wee 2.2.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.
- data/README.rdoc +127 -0
- data/Rakefile +25 -0
- data/aWee.gemspec +26 -0
- data/examples/ObjectSpaceBrowser.rb +191 -0
- data/examples/ajax.rb +73 -0
- data/examples/apotomo-webhunter/main.rb +75 -0
- data/examples/apotomo-webhunter/public/images/bear_trap_charged.png +0 -0
- data/examples/apotomo-webhunter/public/images/bear_trap_snapped.png +0 -0
- data/examples/apotomo-webhunter/public/images/cheese.png +0 -0
- data/examples/apotomo-webhunter/public/images/dark_forest.jpg +0 -0
- data/examples/apotomo-webhunter/public/images/mouse.png +0 -0
- data/examples/apotomo-webhunter/public/javascripts/jquery-1.3.2.min.js +19 -0
- data/examples/apotomo-webhunter/public/javascripts/wee-jquery.js +19 -0
- data/examples/apotomo-webhunter/public/stylesheets/forest.css +33 -0
- data/examples/arc_challenge.rb +42 -0
- data/examples/arc_challenge2.rb +46 -0
- data/examples/cheese_task.rb +27 -0
- data/examples/continuations.rb +28 -0
- data/examples/demo.rb +135 -0
- data/examples/demo/calculator.rb +63 -0
- data/examples/demo/calendar.rb +333 -0
- data/examples/demo/counter.rb +38 -0
- data/examples/demo/editable_counter.rb +36 -0
- data/examples/demo/example.rb +142 -0
- data/examples/demo/file_upload.rb +19 -0
- data/examples/demo/messagebox.rb +15 -0
- data/examples/demo/radio.rb +33 -0
- data/examples/demo/window.rb +71 -0
- data/examples/hw.rb +11 -0
- data/examples/i18n/app.rb +16 -0
- data/examples/i18n/locale/de/app.po +25 -0
- data/examples/i18n/locale/en/app.po +25 -0
- data/examples/pager.rb +102 -0
- data/lib/wee.rb +109 -0
- data/lib/wee/application.rb +89 -0
- data/lib/wee/callback.rb +109 -0
- data/lib/wee/component.rb +363 -0
- data/lib/wee/decoration.rb +251 -0
- data/lib/wee/dialog.rb +171 -0
- data/lib/wee/external_resource.rb +39 -0
- data/lib/wee/html_brushes.rb +795 -0
- data/lib/wee/html_canvas.rb +254 -0
- data/lib/wee/html_document.rb +52 -0
- data/lib/wee/html_writer.rb +71 -0
- data/lib/wee/id_generator.rb +81 -0
- data/lib/wee/jquery.rb +11 -0
- data/lib/wee/jquery/jquery-1.3.2.min.js +19 -0
- data/lib/wee/jquery/wee-jquery.js +19 -0
- data/lib/wee/locale.rb +56 -0
- data/lib/wee/lru_cache.rb +91 -0
- data/lib/wee/presenter.rb +44 -0
- data/lib/wee/renderer.rb +72 -0
- data/lib/wee/request.rb +56 -0
- data/lib/wee/response.rb +68 -0
- data/lib/wee/rightjs.rb +11 -0
- data/lib/wee/rightjs/rightjs-1.5.2.min.js +9 -0
- data/lib/wee/rightjs/wee-rightjs.js +18 -0
- data/lib/wee/root_component.rb +45 -0
- data/lib/wee/session.rb +366 -0
- data/lib/wee/state.rb +102 -0
- data/lib/wee/task.rb +16 -0
- data/test/bm_render.rb +34 -0
- data/test/component_spec.rb +40 -0
- data/test/stress/plotter.rb +84 -0
- data/test/stress/stress_client.rb +51 -0
- data/test/stress/stress_local.rb +86 -0
- data/test/stress/stress_server.rb +83 -0
- data/test/test_component.rb +106 -0
- data/test/test_html_canvas.rb +25 -0
- data/test/test_html_writer.rb +32 -0
- data/test/test_lru_cache.rb +51 -0
- data/test/test_request.rb +42 -0
- 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('->').callback { @list2.push(*@selected1); @list1.replace(@list1-@selected1); @selected1.replace([]) }
|
104
|
+
r.submit_button.value('<-').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
|
data/examples/hw.rb
ADDED
@@ -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 ""
|
data/examples/pager.rb
ADDED
@@ -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
|