raw 0.49.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. data/doc/CONTRIBUTORS +106 -0
  2. data/doc/LICENSE +32 -0
  3. data/doc/coding_conventions.txt +11 -0
  4. data/lib/raw.rb +42 -0
  5. data/lib/raw/adapter.rb +113 -0
  6. data/lib/raw/adapter/cgi.rb +41 -0
  7. data/lib/raw/adapter/fastcgi.rb +48 -0
  8. data/lib/raw/adapter/mongrel.rb +146 -0
  9. data/lib/raw/adapter/script.rb +94 -0
  10. data/lib/raw/adapter/webrick.rb +144 -0
  11. data/lib/raw/adapter/webrick/vcr.rb +91 -0
  12. data/lib/raw/cgi.rb +323 -0
  13. data/lib/raw/cgi/cookie.rb +47 -0
  14. data/lib/raw/cgi/http.rb +62 -0
  15. data/lib/raw/compiler.rb +138 -0
  16. data/lib/raw/compiler/filter/cleanup.rb +21 -0
  17. data/lib/raw/compiler/filter/elements.rb +166 -0
  18. data/lib/raw/compiler/filter/elements/element.rb +210 -0
  19. data/lib/raw/compiler/filter/localization.rb +23 -0
  20. data/lib/raw/compiler/filter/markup.rb +32 -0
  21. data/lib/raw/compiler/filter/morph.rb +123 -0
  22. data/lib/raw/compiler/filter/morph/each.rb +34 -0
  23. data/lib/raw/compiler/filter/morph/for.rb +11 -0
  24. data/lib/raw/compiler/filter/morph/if.rb +26 -0
  25. data/lib/raw/compiler/filter/morph/selected_if.rb +43 -0
  26. data/lib/raw/compiler/filter/morph/standard.rb +55 -0
  27. data/lib/raw/compiler/filter/morph/times.rb +27 -0
  28. data/lib/raw/compiler/filter/script.rb +116 -0
  29. data/lib/raw/compiler/filter/squeeze.rb +16 -0
  30. data/lib/raw/compiler/filter/static_include.rb +74 -0
  31. data/lib/raw/compiler/filter/template.rb +121 -0
  32. data/lib/raw/compiler/reloader.rb +96 -0
  33. data/lib/raw/context.rb +154 -0
  34. data/lib/raw/context/flash.rb +157 -0
  35. data/lib/raw/context/global.rb +88 -0
  36. data/lib/raw/context/request.rb +338 -0
  37. data/lib/raw/context/response.rb +57 -0
  38. data/lib/raw/context/session.rb +198 -0
  39. data/lib/raw/context/session/drb.rb +11 -0
  40. data/lib/raw/context/session/file.rb +15 -0
  41. data/lib/raw/context/session/memcached.rb +13 -0
  42. data/lib/raw/context/session/memory.rb +12 -0
  43. data/lib/raw/context/session/og.rb +15 -0
  44. data/lib/raw/context/session/pstore.rb +13 -0
  45. data/lib/raw/control.rb +18 -0
  46. data/lib/raw/control/attribute.rb +91 -0
  47. data/lib/raw/control/attribute/checkbox.rb +25 -0
  48. data/lib/raw/control/attribute/datetime.rb +21 -0
  49. data/lib/raw/control/attribute/file.rb +20 -0
  50. data/lib/raw/control/attribute/fixnum.rb +26 -0
  51. data/lib/raw/control/attribute/float.rb +26 -0
  52. data/lib/raw/control/attribute/options.rb +38 -0
  53. data/lib/raw/control/attribute/password.rb +16 -0
  54. data/lib/raw/control/attribute/text.rb +16 -0
  55. data/lib/raw/control/attribute/textarea.rb +16 -0
  56. data/lib/raw/control/none.rb +16 -0
  57. data/lib/raw/control/relation.rb +59 -0
  58. data/lib/raw/control/relation/belongs_to.rb +0 -0
  59. data/lib/raw/control/relation/has_many.rb +97 -0
  60. data/lib/raw/control/relation/joins_many.rb +0 -0
  61. data/lib/raw/control/relation/many_to_many.rb +0 -0
  62. data/lib/raw/control/relation/refers_to.rb +29 -0
  63. data/lib/raw/controller.rb +37 -0
  64. data/lib/raw/controller/publishable.rb +160 -0
  65. data/lib/raw/dispatcher.rb +209 -0
  66. data/lib/raw/dispatcher/format.rb +108 -0
  67. data/lib/raw/dispatcher/format/atom.rb +31 -0
  68. data/lib/raw/dispatcher/format/css.rb +0 -0
  69. data/lib/raw/dispatcher/format/html.rb +42 -0
  70. data/lib/raw/dispatcher/format/json.rb +31 -0
  71. data/lib/raw/dispatcher/format/rss.rb +33 -0
  72. data/lib/raw/dispatcher/format/xoxo.rb +31 -0
  73. data/lib/raw/dispatcher/mounter.rb +60 -0
  74. data/lib/raw/dispatcher/router.rb +111 -0
  75. data/lib/raw/errors.rb +19 -0
  76. data/lib/raw/helper.rb +86 -0
  77. data/lib/raw/helper/benchmark.rb +23 -0
  78. data/lib/raw/helper/buffer.rb +60 -0
  79. data/lib/raw/helper/cookie.rb +32 -0
  80. data/lib/raw/helper/debug.rb +28 -0
  81. data/lib/raw/helper/default.rb +16 -0
  82. data/lib/raw/helper/feed.rb +451 -0
  83. data/lib/raw/helper/form.rb +284 -0
  84. data/lib/raw/helper/javascript.rb +59 -0
  85. data/lib/raw/helper/layout.rb +40 -0
  86. data/lib/raw/helper/navigation.rb +87 -0
  87. data/lib/raw/helper/pager.rb +305 -0
  88. data/lib/raw/helper/table.rb +247 -0
  89. data/lib/raw/helper/xhtml.rb +218 -0
  90. data/lib/raw/helper/xml.rb +125 -0
  91. data/lib/raw/mixin/magick.rb +35 -0
  92. data/lib/raw/mixin/sweeper.rb +71 -0
  93. data/lib/raw/mixin/thumbnails.rb +1 -0
  94. data/lib/raw/mixin/webfile.rb +165 -0
  95. data/lib/raw/render.rb +271 -0
  96. data/lib/raw/render/builder.rb +26 -0
  97. data/lib/raw/render/caching.rb +81 -0
  98. data/lib/raw/render/call.rb +43 -0
  99. data/lib/raw/render/send_file.rb +46 -0
  100. data/lib/raw/render/stream.rb +39 -0
  101. data/lib/raw/scaffold.rb +13 -0
  102. data/lib/raw/scaffold/controller.rb +25 -0
  103. data/lib/raw/scaffold/model.rb +157 -0
  104. data/lib/raw/test.rb +5 -0
  105. data/lib/raw/test/assertions.rb +169 -0
  106. data/lib/raw/test/context.rb +55 -0
  107. data/lib/raw/test/testcase.rb +79 -0
  108. data/lib/raw/util/attr.rb +128 -0
  109. data/lib/raw/util/encode_uri.rb +149 -0
  110. data/lib/raw/util/html_filter.rb +538 -0
  111. data/lib/raw/util/markup.rb +130 -0
  112. data/test/glue/tc_webfile.rb +1 -0
  113. data/test/nitro/CONFIG.rb +3 -0
  114. data/test/nitro/adapter/raw_post1.bin +9 -0
  115. data/test/nitro/adapter/tc_webrick.rb +16 -0
  116. data/test/nitro/cgi/tc_cookie.rb +14 -0
  117. data/test/nitro/cgi/tc_request.rb +61 -0
  118. data/test/nitro/compiler/tc_client_morpher.rb +47 -0
  119. data/test/nitro/compiler/tc_compiler.rb +25 -0
  120. data/test/nitro/dispatcher/tc_mounter.rb +47 -0
  121. data/test/nitro/helper/tc_feed.rb +135 -0
  122. data/test/nitro/helper/tc_navbar.rb +74 -0
  123. data/test/nitro/helper/tc_pager.rb +35 -0
  124. data/test/nitro/helper/tc_table.rb +68 -0
  125. data/test/nitro/helper/tc_xhtml.rb +19 -0
  126. data/test/nitro/tc_caching.rb +19 -0
  127. data/test/nitro/tc_cgi.rb +222 -0
  128. data/test/nitro/tc_context.rb +17 -0
  129. data/test/nitro/tc_controller.rb +103 -0
  130. data/test/nitro/tc_controller_aspect.rb +32 -0
  131. data/test/nitro/tc_controller_params.rb +885 -0
  132. data/test/nitro/tc_dispatcher.rb +109 -0
  133. data/test/nitro/tc_element.rb +85 -0
  134. data/test/nitro/tc_flash.rb +59 -0
  135. data/test/nitro/tc_helper.rb +47 -0
  136. data/test/nitro/tc_render.rb +119 -0
  137. data/test/nitro/tc_router.rb +61 -0
  138. data/test/nitro/tc_server.rb +35 -0
  139. data/test/nitro/tc_session.rb +66 -0
  140. data/test/nitro/tc_template.rb +71 -0
  141. data/test/nitro/util/tc_encode_url.rb +87 -0
  142. data/test/nitro/util/tc_markup.rb +31 -0
  143. data/test/public/blog/another/very_litle/index.xhtml +1 -0
  144. data/test/public/blog/inc1.xhtml +2 -0
  145. data/test/public/blog/inc2.xhtml +1 -0
  146. data/test/public/blog/list.xhtml +9 -0
  147. data/test/public/dummy_mailer/registration.xhtml +5 -0
  148. metadata +244 -0
@@ -0,0 +1,305 @@
1
+ require 'facets/more/settings'
2
+
3
+ require 'og/collection'
4
+
5
+ module Raw
6
+
7
+ # Displays a collection of entitities in multiple pages.
8
+ #
9
+ # === Design
10
+ #
11
+ # This pager is carefully designed for scaleability. It stores
12
+ # only the items for one page. The key parameter is needed,
13
+ # multiple pagers can coexist in a single page. The pager
14
+ # leverages the SQL LIMIT option to optimize database
15
+ # interaction.
16
+
17
+ class Pager
18
+ # Items per page.
19
+
20
+ setting :per_page, :default => 10, :doc => 'Items per page'
21
+
22
+ # The request key.
23
+
24
+ setting :key, :default => '_page', :doc => 'The request key'
25
+
26
+ # The current page.
27
+
28
+ attr_accessor :page
29
+
30
+ # Items per page.
31
+
32
+ attr_accessor :per_page
33
+
34
+ # The total number of pages.
35
+
36
+ attr_accessor :page_count
37
+
38
+ # Total count of items.
39
+
40
+ attr_accessor :total_count
41
+
42
+ def initialize(request, per_page, total_count, key = Pager.key)
43
+ raise 'per_page should be > 0' unless per_page > 0
44
+
45
+ @request, @key = request, key
46
+ @page = (request.query[key] || 1).to_i
47
+ @per_page = per_page
48
+ set_count(total_count)
49
+ @start_idx = (@page - 1) * per_page
50
+ end
51
+
52
+ def set_count(total_count)
53
+ @total_count = total_count
54
+ @page_count = (@total_count.to_f / @per_page).ceil
55
+ end
56
+
57
+ # Return the first page index.
58
+
59
+ def first_page
60
+ return 1
61
+ end
62
+
63
+ # Is the first page displayed?
64
+
65
+ def first_page?
66
+ @page == 1
67
+ end
68
+
69
+ # Return the last page index.
70
+
71
+ def last_page
72
+ return @page_count
73
+ end
74
+
75
+ # Is the last page displayed?
76
+
77
+ def last_page?
78
+ @page == @page_count
79
+ end
80
+
81
+ # Return the index of the previous page.
82
+
83
+ def previous_page
84
+ return [@page - 1, 1].max()
85
+ end
86
+
87
+ # Return the index of the next page.
88
+
89
+ def next_page
90
+ return [@page + 1, @page_count].min()
91
+ end
92
+
93
+ # A set of helpers to create links to common pages.
94
+
95
+ for target in [:first, :last, :previous, :next]
96
+ eval %{
97
+ def link_#{target}_page
98
+ target_uri(#{target}_page)
99
+ end
100
+ alias_method :#{target}_page_uri, :link_#{target}_page
101
+ alias_method :#{target}_page_href, :link_#{target}_page
102
+ }
103
+ end
104
+
105
+ # Iterator
106
+
107
+ def each(&block)
108
+ @page_items.each(&block)
109
+ end
110
+
111
+ # Iterator
112
+ # Returns 1-based index.
113
+
114
+ def each_with_index
115
+ idx = @start_idx
116
+ for item in @page_items
117
+ yield(idx + 1, item)
118
+ idx += 1
119
+ end
120
+ end
121
+
122
+ # Is the pager empty, ie has one page only?
123
+
124
+ def empty?
125
+ return @page_count < 1
126
+ end
127
+
128
+ # The items count.
129
+
130
+ def size
131
+ return @total_count
132
+ end
133
+
134
+ # Returns the range of the current page.
135
+
136
+ def page_range
137
+ s = @idx
138
+ e = [@idx + @items_per_page - 1, all_total_count].min
139
+
140
+ return [s, e]
141
+ end
142
+
143
+ # Override if needed.
144
+
145
+ def nav_range
146
+ # effective range = 10 pages.
147
+ s = [@page - 5, 1].max()
148
+ e = [@page + 9, @page_count].min()
149
+
150
+ d = 9 - (e - s)
151
+ e += d if d < 0
152
+
153
+ return (s..e)
154
+ end
155
+
156
+ # To be used with Og queries.
157
+
158
+ def limit
159
+ if @start_idx > 0
160
+ { :limit => @per_page, :offset => @start_idx }
161
+ else
162
+ { :limit => @per_page }
163
+ end
164
+ end
165
+
166
+ def offset
167
+ @start_idx
168
+ end
169
+
170
+ # Create an appropriate SQL limit clause.
171
+ # Returns postgres/mysql compatible limit.
172
+
173
+ def to_sql
174
+ if @start_idx > 0
175
+ return "LIMIT #{@per_page} OFFSET #{@start_idx}"
176
+ else
177
+ # gmosx: perhaps this is optimized ? naaaaaah...
178
+ return "LIMIT #{@per_page}"
179
+ end
180
+ end
181
+
182
+ # Override this method in your application if needed.
183
+ #--
184
+ # TODO: better markup.
185
+ #++
186
+
187
+ def navigation
188
+ nav = ""
189
+
190
+ unless first_page?
191
+ nav << %{
192
+ <div class="first"><a href="#{first_page_href}">First</a></div>
193
+ <div class="previous"><a href="#{previous_page_href}">Previous</a></div>
194
+ }
195
+ end
196
+
197
+ unless last_page?
198
+ nav << %{
199
+ <div class="last"><a href="#{last_page_href}">Last</a></div>
200
+ <div class="next"><a href="#{next_page_href}">Next</a></div>
201
+ }
202
+ end
203
+
204
+ nav << %{<ul>}
205
+
206
+ for i in nav_range()
207
+ if i == @page
208
+ nav << %{
209
+ <li class="active">#{i}</li>
210
+ }
211
+ else
212
+ nav << %{
213
+ <li><a href="#{target_uri(i)}">#{i}</a></li>
214
+ }
215
+ end
216
+ end
217
+
218
+ nav << %{</ul>}
219
+
220
+ return nav
221
+ end
222
+ alias_method :links, :navigation
223
+
224
+ def navigation_needed?
225
+ @page_count > 1
226
+ end
227
+ alias_method :navigation?, :navigation_needed?
228
+
229
+ private
230
+
231
+ # Generate the target URI.
232
+
233
+ def target_uri(page)
234
+ uri = @request.uri.to_s
235
+
236
+ if uri =~ /[?;]#{@key}=(\d*)/
237
+ return uri.gsub(/([?;]#{@key}=)\d*/) { |m| "#$1#{page}" }
238
+ elsif uri =~ /\?/
239
+ return "#{uri};#{@key}=#{page}"
240
+ else
241
+ return "#{uri}?#{@key}=#{page}"
242
+ end
243
+ end
244
+
245
+ end
246
+
247
+ # Pager related helper methods.
248
+
249
+ module PagerHelper
250
+
251
+ private
252
+
253
+ # Helper method that generates a collection of items and the
254
+ # associated pager object.
255
+ #
256
+ # === Example
257
+ #
258
+ # entries, pager = paginate(Article, :condition => 'title LIKE %Ab%', :per_page => 10)
259
+ #
260
+ # or
261
+ #
262
+ # items = [ 'item1', 'item2', ... ]
263
+ # entries, pager = paginate(items, :per_page => 10)
264
+ #
265
+ # or
266
+ #
267
+ # entries, pager = paginate(article.comments, :per_page => 10)
268
+ #
269
+ # <ul>
270
+ # <?r for entry in entries ?>
271
+ # <li>#{entry.to_link}</li>
272
+ # <?r end ?>
273
+ # </ul>
274
+ # #{pager.links}
275
+
276
+ def paginate(items, options = {})
277
+ per_page = options.delete(:per_page) || options[:limit] || Pager.per_page
278
+ pager_key = options.delete(:pager_key) || Pager.key
279
+
280
+ case items
281
+ when Array
282
+ items = items.dup
283
+ pager = Pager.new(request, per_page, items.size, pager_key)
284
+ items = items.slice(pager.offset, pager.per_page) || []
285
+ return items, pager
286
+
287
+ when Og::Collection
288
+ collection = items
289
+ pager = Pager.new(request, per_page, collection.count, pager_key)
290
+ options.update(pager.limit)
291
+ items = collection.reload(options)
292
+ return items, pager
293
+
294
+ when Class
295
+ klass = items
296
+ pager = Pager.new(request, per_page, klass.count(options), pager_key)
297
+ options.update(pager.limit)
298
+ items = klass.all(options)
299
+ return items, pager
300
+ end
301
+ end
302
+
303
+ end
304
+
305
+ end
@@ -0,0 +1,247 @@
1
+ require "facets/more/settings"
2
+
3
+ require "glue/uri"
4
+
5
+ module Raw
6
+
7
+ # The TableBuilder is a helper class that automates the creation
8
+ # of tables from collections of objects. The resulting html
9
+ # can be styled using css.
10
+ #
11
+ # === Example
12
+ #
13
+ # <?r
14
+ # users = User.all.map { |u| [u.name, u.first_name, u.last_name, u.email] }
15
+ # headers = ['Username', 'First name', 'Last name', 'Email']
16
+ # ?>
17
+ #
18
+ # <div class="custom-table-class">
19
+ # #{table :values => users, :headers => header}
20
+ # </div>
21
+ #
22
+ #
23
+ # === Extended Example
24
+ #
25
+ # <?r
26
+ # users = User.all.map { |u| [u.name, u.first_name, u.last_name, u.email] }
27
+ # headers = ['Username', 'First name', 'Last name', 'Email']
28
+ # order_opts = { :right => true, # right align the order controls
29
+ # :values => [nil, 'first_name', 'last_name'], # column names from DB
30
+ # :asc_pic => "/images/asc.png",
31
+ # :desc_pic => "/images/desc.png" }
32
+ # ?>
33
+ #
34
+ # <div class="custom-table-class">
35
+ # #{table :values => users, :headers => header,
36
+ # :order => order_opts, :alternating_rows => true }
37
+ # </div>
38
+ #
39
+ #--
40
+ # TODO: legend, verbose... ?
41
+ # TODO, gmosx: Remove crappy, bloatware additions.
42
+ #++
43
+
44
+ module TableHelper
45
+
46
+ # The order by key.
47
+
48
+ setting :order_by_key, :default => '_order_by', :doc => 'The order key'
49
+
50
+ # The order by key.
51
+
52
+ setting :order_direction_key, :default => '_order_direction', :doc => 'The order direction key'
53
+
54
+ # [+options+]
55
+ # A hash of options.
56
+ #
57
+ # :id = id of the component.
58
+ # :class = class of the component
59
+ # :headers = an array of the header values
60
+ # :values = an array of arrays.
61
+ # :order = options hash (:left, :right, :asc_pic, :desc_pic, :values)
62
+ # :alternating_rows = alternating rows, use css to color row_even / row_odd
63
+ # :footers = an array of tfooter values
64
+
65
+ def table(options)
66
+ str = '<table'
67
+ str << %| id="#{options[:id]}"| if options[:id]
68
+ str << %| class="#{options[:class]}"| if options[:class]
69
+ str << '>'
70
+
71
+ str << table_rows(options)
72
+
73
+ str << '</table>'
74
+ end
75
+ alias_method :build_table, :table
76
+
77
+ # [+options+]
78
+ # A hash of options.
79
+ #
80
+ # :headers = an array of the header values
81
+ # :values = an array of arrays.
82
+ # :order = options hash (:left, :right, :asc_pic, :desc_pic, :values)
83
+ # :alternating_rows = alternating rows, use css to color row_even / row_odd
84
+ # :footers = an array of tfooter values
85
+
86
+ def table_rows(options)
87
+ # also accept :items, :rows
88
+ options[:values] = options[:values] || options[:items] || options[:rows]
89
+
90
+ str = ''
91
+ str << table_header(options) if options[:headers]
92
+ str << table_footer(options) if options[:footers]
93
+
94
+ items = options[:values]
95
+
96
+ row_state = 'odd' if options[:alternating_rows]
97
+
98
+ # when items is an array of arrays of arrays (meaning, several
99
+ # arrays deviding the table into several table parts (tbodys))
100
+
101
+ if create_tbody?(options)
102
+ for body in items
103
+ str << '<tbody>'
104
+
105
+ for row in body
106
+ str << '<tr'
107
+
108
+ if options[:alternating_rows]
109
+ str << %| class="row_#{row_state}"|
110
+ row_state = (row_state == "odd" ? "even" : "odd")
111
+ end
112
+
113
+ str << '>'
114
+
115
+ for value in row
116
+ str << %|<td>#{value}</td>|
117
+ end
118
+
119
+ str << '</tr>'
120
+ end
121
+
122
+ str << '</tbody>'
123
+ end
124
+ else
125
+ for row in items
126
+ str << '<tr'
127
+
128
+ if options[:alternating_rows]
129
+ str << %| class="row_#{row_state}"|
130
+ row_state = (row_state == "odd" ? "even" : "odd")
131
+ end
132
+
133
+ str << '>'
134
+
135
+ for value in row
136
+ str << %|<td>#{value}</td>|
137
+ end
138
+
139
+ str << '</tr>'
140
+ end
141
+ end
142
+
143
+ return str
144
+ end
145
+
146
+ private
147
+
148
+ # [+options+]
149
+ # A hash of options.
150
+ #
151
+ # :id = id of the component.
152
+ # :headers = an array of the header values
153
+ # :values = an array of arrays.
154
+ # :order = options hash (:left, :right, :asc_pic, :desc_pic, :values)
155
+ # :alternating_rows = alternating rows, use css to color row_even / row_odd
156
+ # :footers = an array of tfooter values
157
+
158
+ def table_header(options)
159
+ str = ''
160
+ str << '<thead>' if create_tbody?(options) || options[:footers]
161
+ str << '<tr>'
162
+
163
+ options[:headers].each_with_index do |header, index|
164
+ if (options[:order] && options[:order][:values] &&
165
+ options[:order][:values][index])
166
+ order_by = options[:order][:values][index]
167
+
168
+ asc_val = if options[:order][:asc_pic]
169
+ %|<img src="#{options[:order][:asc_pic]}" alt="asc" />|
170
+ else
171
+ '^'
172
+ end
173
+ desc_val = if options[:order][:desc_pic]
174
+ %|<img src="#{options[:order][:desc_pic]}" alt="desc" />|
175
+ else
176
+ 'v'
177
+ end
178
+
179
+ order_asc = "<a href='#{target_uri(order_by, 'ASC')}'>#{asc_val}</a>"
180
+ order_desc = "<a href='#{target_uri(order_by, 'DESC')}'>#{desc_val}</a>"
181
+
182
+ str << '<th><table width="100%" cellspacing="0" cellpadding="0"><tr>'
183
+
184
+ if options[:order][:left] || !options[:order][:right]
185
+ str << "<th>#{order_asc}<br />#{order_desc}</th>"
186
+ end
187
+
188
+ str << %|<th>#{header}</th>|
189
+
190
+ if options[:order][:right]
191
+ str << "<th>#{order_asc}<br />#{order_desc}</th>"
192
+ end
193
+
194
+ str << '</tr></table></th>'
195
+ else
196
+ str << %|<th>#{header}</th>|
197
+ end
198
+ end
199
+
200
+ str << '</tr>'
201
+ str << '</thead>' if create_tbody?(options) || options[:footers]
202
+
203
+ return str
204
+ end
205
+
206
+ # [+options+]
207
+ # A hash of options.
208
+ #
209
+ # :id = id of the component.
210
+ # :headers = an array of the header values
211
+ # :values = an array of arrays.
212
+ # :order = options hash (:left, :right, :asc_pic, :desc_pic, :values)
213
+ # :alternating_rows = alternating rows, use css to color row_even / row_odd
214
+ # :footers = an array of tfooter values
215
+
216
+ def table_footer(options)
217
+ str = '<tfoot><tr>'
218
+
219
+ for footer in options[:footers]
220
+ str << %|<td>#{footer}</td>|
221
+ end
222
+
223
+ str << '</tr></tfoot>'
224
+
225
+ return str
226
+ end
227
+
228
+ # Generate the target URI.
229
+
230
+ def target_uri(order_by, direction)
231
+ params = { TableHelper.order_by_key => order_by,
232
+ TableHelper.order_direction_key => direction }
233
+
234
+ return Glue::UriUtils.update_query_string(request.uri.to_s, params)
235
+ end
236
+
237
+ #--
238
+ # gmosx: Arrgh!! dangerous method, who added this?
239
+ #++
240
+
241
+ def create_tbody?(options)
242
+ options[:values][0][0].respond_to?(:to_ary)
243
+ end
244
+
245
+ end
246
+
247
+ end