nitro 0.30.0 → 0.31.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -24,6 +24,10 @@ class Pager
24
24
 
25
25
  setting :key, :default => '_page', :doc => 'The request key'
26
26
 
27
+ # The nav link titles
28
+
29
+ setting :link_titles, :default => {:first => 'First', :previous => 'Previous', :last => 'Last', :next => 'Next'}, :doc => "Titles of pager links"
30
+
27
31
  # The current page.
28
32
 
29
33
  attr_accessor :page
@@ -40,10 +44,10 @@ class Pager
40
44
 
41
45
  attr_accessor :total_count
42
46
 
43
- def initialize(request, per_page, total_count, key = Pager.key)
47
+ def initialize(request, per_page, total_count, key = Pager.key, link_titles = Pager.link_titles)
44
48
  raise 'per_page should be > 0' unless per_page > 0
45
49
 
46
- @request, @key = request, key
50
+ @request, @key, @link_titles = request, key, link_titles
47
51
  @page = request.query.fetch(key, 1).to_i
48
52
  @per_page = per_page
49
53
  set_count(total_count)
@@ -55,6 +59,10 @@ class Pager
55
59
  @page_count = (@total_count.to_f / @per_page).ceil
56
60
  end
57
61
 
62
+ def has_pages?
63
+ return @page_count > 1
64
+ end
65
+
58
66
  # Return the first page index.
59
67
 
60
68
  def first_page
@@ -188,17 +196,18 @@ class Pager
188
196
  def navigation
189
197
  nav = ""
190
198
 
199
+ return nav unless has_pages?
191
200
  unless first_page?
192
201
  nav << %{
193
- <div class="first"><a href="#{first_page_href}">First</a></div>
194
- <div class="previous"><a href="#{previous_page_href}">Previous</a></div>
202
+ <div class="first"><a href="#{first_page_href}">#{CGI.escapeHTML(@link_titles[:first])}</a></div>
203
+ <div class="previous"><a href="#{previous_page_href}">#{CGI.escapeHTML(@link_titles[:previous])}</a></div>
195
204
  }
196
205
  end
197
206
 
198
207
  unless last_page?
199
208
  nav << %{
200
- <div class="last"><a href="#{last_page_href}">Last</a></div>
201
- <div class="next"><a href="#{next_page_href}">Next</a></div>
209
+ <div class="last"><a href="#{last_page_href}">#{CGI.escapeHTML(@link_titles[:last])}</a></div>
210
+ <div class="next"><a href="#{next_page_href}">#{CGI.escapeHTML(@link_titles[:next])}</a></div>
202
211
  }
203
212
  end
204
213
 
@@ -270,24 +279,24 @@ private
270
279
  def paginate(items, options = {})
271
280
  per_page = options.delete(:per_page) || Pager.per_page
272
281
  pager_key = options.delete(:pager_key) || Pager.key
273
-
282
+ pager_link_titles = Pager.link_titles.merge(options.delete(:pager_link_titles) || Pager.link_titles)
274
283
  case items
275
284
  when Array
276
285
  items = items.dup
277
- pager = Pager.new(request, per_page, items.size, pager_key)
286
+ pager = Pager.new(request, per_page, items.size, pager_key, pager_link_titles)
278
287
  items = items.slice(pager.offset, pager.per_page) || []
279
288
  return items, pager
280
289
 
281
290
  when Og::Collection
282
291
  collection = items
283
- pager = Pager.new(request, per_page, collection.count, pager_key)
292
+ pager = Pager.new(request, per_page, collection.count, pager_key, pager_link_titles)
284
293
  options.update(pager.limit)
285
294
  items = collection.reload(options)
286
295
  return items, pager
287
296
 
288
297
  when Class
289
298
  klass = items
290
- pager = Pager.new(request, per_page, klass.count(options), pager_key)
299
+ pager = Pager.new(request, per_page, klass.count(options), pager_key, pager_link_titles)
291
300
  options.update(pager.limit)
292
301
  items = klass.all(options)
293
302
  return items, pager
@@ -111,7 +111,7 @@ module TableHelper
111
111
  str << '>'
112
112
 
113
113
  for value in row
114
- str << %|<td>#{value}</td>|
114
+ str << %|<td>#{process(value)}</td>|
115
115
  end
116
116
 
117
117
  str << '</tr>'
@@ -131,7 +131,7 @@ module TableHelper
131
131
  str << '>'
132
132
 
133
133
  for value in row
134
- str << %|<td>#{value}</td>|
134
+ str << %|<td>#{process(value)}</td>|
135
135
  end
136
136
 
137
137
  str << '</tr>'
@@ -159,6 +159,7 @@ module TableHelper
159
159
  str << '<tr>'
160
160
 
161
161
  options[:headers].each_with_index do |header, index|
162
+ header = process(header)
162
163
  if (options[:order] && options[:order][:values] &&
163
164
  options[:order][:values][index])
164
165
  order_by = options[:order][:values][index]
@@ -233,7 +234,31 @@ module TableHelper
233
234
  end
234
235
 
235
236
  def create_tbody?(options)
236
- options[:values][0][0].respond_to?(:to_ary)
237
+ options[:values][0].respond_to?(:to_ary) && options[:values][0][0].respond_to?(:to_ary)
238
+ end
239
+
240
+ # A simple hack to allow Localization-processing in the table-helper
241
+ # overwrite this method to make this happen
242
+ # Now you can just pass [[somestring]] to the tablehelper and it will
243
+ # be localized like the rest of the page.
244
+ # ATM it's only kicking in when the @lc is set.
245
+ #
246
+ # Example for the method:
247
+ # module Nitro
248
+ # module TableHelper
249
+ # def process(value)
250
+ # val = value.to_s.gsub(/\[\[(.*?)\]\]/){ @lc[$1] }
251
+ # return val == "" ? value : val
252
+ # end
253
+ # end
254
+ # end
255
+
256
+ def process(value)
257
+ if @lc
258
+ val = value.to_s.gsub(/\[\[(.*?)\]\]/){ @lc[$1] }
259
+ return val == "" ? value : val
260
+ end
261
+ return value
237
262
  end
238
263
 
239
264
  end
@@ -13,7 +13,7 @@ module XhtmlHelper
13
13
  elsif obj.respond_to? :to_href
14
14
  href = obj.to_href
15
15
  else
16
- href = "#{obj.class.name.pluralize.undescore}/#{obj.oid}"
16
+ href = "#{obj.class.name.pluralize.underscore}/#{obj.oid}"
17
17
  end
18
18
 
19
19
  if base
@@ -63,7 +63,8 @@ module XhtmlHelper
63
63
 
64
64
  values = options[:values] || options[:labels_values] || (0...labels.size).to_a
65
65
 
66
- selected = (options[:selected] || -1).to_i
66
+ selected = options[:selected]
67
+ selected = selected.to_s if selected
67
68
 
68
69
  labels.each_with_index do |label, idx|
69
70
  value = values[idx]
@@ -75,7 +76,7 @@ module XhtmlHelper
75
76
  end
76
77
  style = %{ style="#{style}"}
77
78
  end
78
- if value == selected
79
+ if value.to_s == selected
79
80
  str << %|<option value="#{value}" selected="selected"#{style}>#{label}</option>|
80
81
  else
81
82
  str << %|<option value="#{value}"#{style}>#{label}</option>|
data/lib/nitro/part.rb CHANGED
@@ -3,12 +3,67 @@ module Nitro
3
3
  # A part is a module of reusable functionality encapsulated as
4
4
  # a mini site/app. You can require (include) multiple parts in
5
5
  # your application. A part is in essence a high level component.
6
-
6
+ #
7
+ # The directory structure of a part mirrors the structure
8
+ # of a typicall web application. By conventions we put the
9
+ # main directories of parts in a root directory called 'part'.
10
+ #
11
+ # Let's demonstrate the above with an example. Two parts are
12
+ # defined here. A user management part (users) and a CMS
13
+ # (content). A typical dir structure goes like this ($ is a
14
+ # directory in the load path, this means you can put parts in
15
+ # multiple places as long as the are in the load path):
16
+ #
17
+ # $/part # parts will be stored here.
18
+ #
19
+ # $/part/users.rb # helper file used to 'require' the part.
20
+ # $/part/users/public/
21
+ # $/part/users/controller.rb
22
+ # $/part/users/controller/xml.rb
23
+ # $/part/users/model/user.rb
24
+ # $/part/users/model/acl.rb
25
+ # $/part/users/template/login.xhtml
26
+ # $/part/users/template/form.xinc
27
+ # $/part/users/run.rb # starts an 'example' application for this part.
28
+ #
29
+ # $/part/content.rb
30
+ # $/part/content/controller.rb
31
+ # $/part/content/model.rb
32
+ # ...
33
+ #
34
+ # Given this direcotry structure you can 'require' a part
35
+ # like this:
36
+ #
37
+ # require 'part/users'
38
+ # require 'part/content'
39
+ #
40
+ # The helper files (for example the file part/users.rb) typically
41
+ # require the part files needed by default.
42
+ #
43
+ # The 'example' application start files (for example part/users/run.rb)
44
+ # are optional. If present, they start a small application that
45
+ # demonstrates the usage of the part. In the example app, the main
46
+ # part controller is mounted at the root ('/'). Typically, in
47
+ # your own applications, you will mount the controller as needed,
48
+ # (for example: 'users' => UsersController,
49
+ # 'blog' => 'ContentController')
50
+ #
51
+ # The files that reside in the public directory are typically
52
+ # copied by a code generator to your application public dir.
53
+ #
54
+ # Part controllers setup the template root stack to lookup
55
+ # templates in their local template dir (for example part/users/template)
56
+ # if a template is not found in the applications normal template
57
+ # root. In essence, by requiring a part a target application,
58
+ # 'inherits' its templates. If you want to customize (override)
59
+ # one template, just place a template with the same name in the
60
+ # respective directory in the application template root.
61
+
7
62
  class Part
8
63
 
9
64
  # Require (include) a part in the current application.
10
65
 
11
- def self.require(name)
66
+ def self.require name
12
67
  Logger.debug "Requiring part '#{name}'." if $DBG
13
68
  Kernel.require 'part/' + name + '/run.rb'
14
69
  end
data/lib/nitro/render.rb CHANGED
@@ -4,7 +4,6 @@ require 'stringio'
4
4
 
5
5
  require 'facet/string/blank'
6
6
 
7
- require 'glue/attribute'
8
7
  require 'glue/settings'
9
8
  require 'glue/template'
10
9
  require 'glue/builder/xml'
@@ -16,24 +15,32 @@ require 'nitro/helper/buffer'
16
15
 
17
16
  module Nitro
18
17
 
18
+ #--
19
19
  # Raise or Throw this exception to stop the current action.
20
- # Typically called to skip the template.
20
+ # Typically called to skip the template. This is considerered
21
+ # a low level tactic. Prefer to use the exit method.
22
+ #++
21
23
 
22
- class ActionExit < Exception; end
24
+ class ActionExit < Exception # :nodoc: all
25
+ end
23
26
 
27
+ #--
24
28
  # Raise or Throw this exception to stop rendering altogether.
25
29
  # Typically called by redirects.
30
+ #++
26
31
 
27
- class RenderExit < Exception; end
32
+ class RenderExit < Exception # :nodoc: all
33
+ end
28
34
 
35
+ #--
29
36
  # The output buffer. The output of a contoller action is
30
37
  # accumulated in this buffer before sending this to the client
31
38
  # as a HTTP Response.
32
- #--
39
+ #
33
40
  # TODO: Implement a FAST string (maybe in C)
34
41
  #++
35
42
 
36
- class OutputBuffer < String
43
+ class OutputBuffer < String # :nodoc: all
37
44
  end
38
45
 
39
46
  # The rendering mixin. This module is typically included in
@@ -81,12 +88,9 @@ module Render
81
88
 
82
89
  attr_accessor :base
83
90
 
84
- # The name of the current controller.
85
- #--
86
- # gmosx: Needed for WEE. Will be deprecated.
87
- #++
91
+ # The current controller class.
88
92
 
89
- attr_accessor :controller_name
93
+ attr_accessor :controller
90
94
 
91
95
  # Initialize the render.
92
96
  #
@@ -94,9 +98,8 @@ module Render
94
98
  # A parent render/controller acts as the context.
95
99
 
96
100
  def initialize(context, base = nil)
97
- @rendering_context = 0
98
101
  @request = @response = @context = context
99
- @controller_name = @base = base
102
+ @base = base
100
103
  @out = context.out
101
104
  end
102
105
 
@@ -114,21 +117,23 @@ module Render
114
117
 
115
118
  Logger.debug "Rendering '#{path}'." if $DBG
116
119
 
117
- klass, action, base = @context.dispatcher.dispatch(path, @context)
120
+ @controller, action, base = @context.dispatcher.dispatch(path, @context)
118
121
 
119
- # FIXME:
120
- @context.content_type = klass.instance_variable_get('@content_type') || 'text/html'
122
+ raise 'No controller for action' unless @controller
121
123
 
122
- raise 'No controller for action' unless klass
124
+ # FIXME:
125
+ @context.content_type = @controller.instance_variable_get('@content_type') || 'text/html'
123
126
 
124
127
  @context.level += 1
125
-
126
- if self.class == klass
128
+ old_controller = Controller.replace_current(@controller)
129
+
130
+ if self.class == @controller
127
131
  self.send(action)
128
132
  else
129
- klass.new(@context, base).send(action)
133
+ @controller.new(@context, base).send(action)
130
134
  end
131
135
 
136
+ Controller.replace_current(old_controller)
132
137
  @context.level -= 1
133
138
 
134
139
  rescue NoActionError => e1
@@ -142,6 +147,7 @@ module Render
142
147
  rescue Exception, StandardError => e3
143
148
  # More fault tolerant, only flags the erroneous box with
144
149
  # error not the full page.
150
+
145
151
  log_error(e3, path)
146
152
  print '(error)'
147
153
  end
@@ -149,13 +155,21 @@ module Render
149
155
  private
150
156
 
151
157
  # Helper method to exit the current action, typically used
152
- # to skip the template.
158
+ # to skip the template rendering.
159
+ #
160
+ # === Example
161
+ #
162
+ # def my_action
163
+ # ...
164
+ # exit unless user.admin?
165
+ # end
153
166
 
154
167
  def exit
155
168
  raise ActionExit.new
156
169
  end
157
170
 
158
- # Flush the IO object if we are in streaming mode.
171
+ # Flush the IO object (OutputBuffer) if we are in streaming
172
+ # mode.
159
173
 
160
174
  def flush
161
175
  @out.flush if @out.is_a?(IO)
@@ -168,9 +182,34 @@ private
168
182
  # If the url starts with '/' it is considered absolute, else
169
183
  # the url is considered relative to the current controller and
170
184
  # the controller base is prepended.
185
+ #
186
+ # The parameters are passed to the R operator (encode_url)
187
+ # to actually build the url. So the following forms (among
188
+ # others) are allowed:
189
+ #
190
+ # redirect 'home/login'
191
+ # redirect ForaController, :post, :title, 'The title'
192
+ # redirect :welcome
193
+ # redirect article # => article.to_href
194
+ #
195
+ # You can also pass optional hash parameters at the end,
196
+ # for example:
197
+ #
198
+ # redirect :welcome, :status => 307
199
+ #
200
+ # The default redirect status is 303.
171
201
 
172
- def redirect(url, status = 303)
173
- url = url.to_s
202
+ def redirect(*args)
203
+ if args.last.is_a? Hash
204
+ status = args.last.fetch(:status, 303)
205
+ else
206
+ status = 303
207
+ end
208
+
209
+ url = encode_url(*args)
210
+
211
+ # gmosx, THINK: this may be unnecessary!
212
+
174
213
  unless url =~ /^http/
175
214
  url = "#@base/#{url}" unless url =~ /^\//
176
215
  url = "#{@context.host_url}/#{url.gsub(/^\//, '')}"
@@ -187,7 +226,7 @@ private
187
226
  # Redirect to the referer.
188
227
 
189
228
  def redirect_referer(postfix = nil, status = 303)
190
- redirect("#{@context.referer}#{postfix}", status)
229
+ redirect "#{@context.referer}#{postfix}", :status => status
191
230
  end
192
231
  alias_method :redirect_to_referer, :redirect_referer
193
232
  alias_method :redirect_referrer, :redirect_referer
@@ -196,7 +235,7 @@ private
196
235
  # Redirect to home.
197
236
 
198
237
  def redirect_home(status = 303)
199
- redirect('/', status)
238
+ redirect '/', :status => status
200
239
  end
201
240
  alias_method :redirect_to_home, :redirect_home
202
241
 
@@ -209,10 +248,10 @@ private
209
248
  # === Example
210
249
  #
211
250
  # caller:
212
- # color, type = call('utils/select_color')
251
+ # color, type = call 'utils/select_color'
213
252
  #
214
253
  # target:
215
- # answer(color, type)
254
+ # answer color, type
216
255
  #--
217
256
  # FIXME: dont use yet, you have to encode the branch to
218
257
  # make this safe for use.
data/lib/nitro/router.rb CHANGED
@@ -94,6 +94,7 @@ module Router
94
94
 
95
95
  return url
96
96
  end
97
+
97
98
  return false
98
99
  end
99
100