nitro 0.30.0 → 0.31.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.
@@ -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