nitro 0.19.0 → 0.20.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +187 -0
- data/INSTALL +5 -0
- data/README +11 -5
- data/doc/AUTHORS +11 -1
- data/doc/RELEASES +217 -0
- data/doc/tutorial.txt +1 -2
- data/lib/nitro.rb +9 -6
- data/lib/nitro/adapter/webrick.rb +13 -2
- data/lib/nitro/builder/form.rb +11 -9
- data/lib/nitro/builder/rss.rb +2 -2
- data/lib/nitro/builder/xhtml.rb +15 -0
- data/lib/nitro/caching.rb +15 -10
- data/lib/nitro/conf.rb +0 -5
- data/lib/nitro/controller.rb +118 -81
- data/lib/nitro/cookie.rb +6 -6
- data/lib/nitro/dispatcher.rb +62 -18
- data/lib/nitro/element.rb +4 -1
- data/lib/nitro/element/java_script.rb +15 -0
- data/lib/nitro/localization.rb +3 -4
- data/lib/nitro/markup.rb +4 -4
- data/lib/nitro/mixin/debug.rb +30 -0
- data/lib/nitro/mixin/helper.rb +14 -0
- data/lib/nitro/mixin/javascript.rb +137 -0
- data/lib/nitro/{ui → mixin}/pager.rb +110 -82
- data/lib/nitro/render.rb +20 -8
- data/lib/nitro/request.rb +6 -0
- data/lib/nitro/routing.rb +6 -5
- data/lib/nitro/runner.rb +21 -9
- data/lib/nitro/server.rb +95 -0
- data/lib/nitro/service.rb +0 -1
- data/lib/nitro/session.rb +4 -5
- data/lib/nitro/shaders.rb +2 -2
- data/lib/nitro/template.rb +1 -1
- data/lib/nitro/testing/assertions.rb +2 -4
- data/lib/nitro/testing/context.rb +4 -6
- data/proto/public/js/behaviour.js +254 -0
- data/proto/public/js/controls.js +446 -0
- data/proto/public/js/dragdrop.js +537 -0
- data/proto/public/js/effects.js +612 -0
- data/proto/public/js/prototype.js +644 -370
- data/proto/public/settings.xhtml +64 -0
- data/test/nitro/adapter/tc_cgi.rb +2 -2
- data/test/nitro/builder/tc_rss.rb +1 -1
- data/test/nitro/mixin/tc_pager.rb +35 -0
- data/test/nitro/tc_controller.rb +1 -1
- data/test/nitro/tc_cookie.rb +14 -0
- data/test/nitro/tc_dispatcher.rb +11 -6
- data/test/nitro/tc_server.rb +35 -0
- metadata +20 -15
- data/lib/nitro/builder/atom.rb +0 -74
- data/lib/nitro/part.rb +0 -22
- data/lib/nitro/simple.rb +0 -11
- data/lib/nitro/ui/popup.rb +0 -41
- data/lib/nitro/ui/tabs.rb +0 -25
- data/lib/nitro/uri.rb +0 -193
- data/test/nitro/builder/tc_atom.rb +0 -24
- data/test/nitro/tc_uri.rb +0 -97
- data/test/nitro/ui/tc_pager.rb +0 -49
@@ -1,78 +1,58 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
# $Id: pager.rb 1 2005-04-11 11:04:30Z gmosx $
|
1
|
+
require 'glue/uri'
|
2
|
+
require 'glue/configuration'
|
4
3
|
|
5
|
-
|
6
|
-
|
7
|
-
module Nitro; module UI
|
4
|
+
module Nitro
|
8
5
|
|
9
6
|
# Displays a collection of entitities in multiple pages.
|
10
7
|
#
|
11
8
|
# === Design
|
12
9
|
#
|
13
|
-
#
|
10
|
+
# This pager is carefully designed for scaleability. It stores
|
14
11
|
# only the items for one page. The name parameter is needed, multiple
|
15
12
|
# pagers can coexist in a single page. Unlike older pagers this
|
16
|
-
# pager leverages the SQL LIMIT option to optimize database
|
17
|
-
#
|
18
|
-
|
19
|
-
|
20
|
-
#
|
21
|
-
# @entries = BlogEntry.all("ORDER BY oid #{@pager.sql_limit}")
|
22
|
-
# @pager.set(BlogEntry.count)
|
23
|
-
#
|
24
|
-
# default navigation (customize with css):
|
25
|
-
# <div class="pager">#{@pager.navigation}</div>
|
26
|
-
#
|
27
|
-
# custom navigation:
|
28
|
-
#
|
29
|
-
# <table cellspacing="0" width="100%" border="1">
|
30
|
-
# <tr>
|
31
|
-
# <td width="64"><x:pager-prev>Previous</x:pager-prev></td>
|
32
|
-
# <td width="100%"></td>
|
33
|
-
# <td width="64"><x:pager-next>Next</x:pager-next></td>
|
34
|
-
# </tr>
|
35
|
-
# </table>
|
36
|
-
#--
|
37
|
-
# INVESTIGATE:
|
38
|
-
# mysql> SELECT SQL_CALC_FOUND_ROWS * FROM tbl_name
|
39
|
-
# -> WHERE id > 100 LIMIT 10;
|
40
|
-
# mysql> SELECT FOUND_ROWS();
|
41
|
-
#++
|
42
|
-
|
43
|
-
class Pager < Array
|
44
|
-
|
45
|
-
attr_accessor :name, :idx, :page, :page_count
|
46
|
-
|
47
|
-
# Total count of items
|
48
|
-
attr_accessor :total_count
|
13
|
+
# pager leverages the SQL LIMIT option to optimize database
|
14
|
+
# interaction.
|
15
|
+
|
16
|
+
class Pager
|
17
|
+
# Items per page.
|
49
18
|
|
50
|
-
|
51
|
-
attr_accessor :page_items
|
19
|
+
setting :per_page, :default => 10, :doc => 'Items per page'
|
52
20
|
|
53
|
-
#
|
54
|
-
attr_accessor :request
|
21
|
+
# The request key.
|
55
22
|
|
56
|
-
|
57
|
-
|
23
|
+
setting :key, :default => '_page', :doc => 'The request key'
|
24
|
+
|
25
|
+
# The current page.
|
26
|
+
|
27
|
+
attr_accessor :page
|
28
|
+
|
29
|
+
# Items per page.
|
30
|
+
|
31
|
+
attr_accessor :per_page
|
58
32
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
33
|
+
# The total number of pages.
|
34
|
+
|
35
|
+
attr_accessor :page_count
|
36
|
+
|
37
|
+
# Total count of items.
|
38
|
+
|
39
|
+
attr_accessor :total_count
|
63
40
|
|
64
|
-
|
65
|
-
|
66
|
-
# gmosx, FIXME: not exactly what i want!
|
67
|
-
items.slice!(@start_idx, @items_per_page)
|
68
|
-
end
|
69
|
-
end
|
41
|
+
def initialize(request, per_page, total_count, key = Pager.key)
|
42
|
+
raise 'per_page should be > 0' unless per_page > 0
|
70
43
|
|
71
|
-
|
44
|
+
@request, @key = request, key
|
45
|
+
@page = request.query.fetch(key, 1).to_i
|
46
|
+
@per_page = per_page
|
47
|
+
set_count(total_count)
|
48
|
+
@start_idx = (@page - 1) * per_page
|
49
|
+
end
|
50
|
+
|
51
|
+
def set_count(total_count)
|
72
52
|
@total_count = total_count
|
73
|
-
@page_count = (@total_count.to_f
|
53
|
+
@page_count = (@total_count.to_f / @per_page).ceil
|
74
54
|
end
|
75
|
-
|
55
|
+
|
76
56
|
def first_page
|
77
57
|
return 1
|
78
58
|
end
|
@@ -135,10 +115,33 @@ class Pager < Array
|
|
135
115
|
|
136
116
|
return (s..e)
|
137
117
|
end
|
118
|
+
|
119
|
+
# To be used with Og queries.
|
120
|
+
|
121
|
+
def limit
|
122
|
+
{ :limit => @per_page, :offset => @start_idx }
|
123
|
+
end
|
124
|
+
|
125
|
+
def offset
|
126
|
+
@start_idx
|
127
|
+
end
|
128
|
+
|
129
|
+
# Create an appropriate SQL limit clause.
|
130
|
+
# Returns postgres/mysql compatible limit.
|
138
131
|
|
139
|
-
|
140
|
-
|
132
|
+
def to_sql
|
133
|
+
if @start_idx > 0
|
134
|
+
return "LIMIT #{@per_page} OFFSET #{@start_idx}"
|
135
|
+
else
|
136
|
+
# gmosx: perhaps this is optimized ? naaaaaah...
|
137
|
+
return "LIMIT #{@per_page}"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# Override this method in your application if needed.
|
142
|
+
#--
|
141
143
|
# TODO: better markup.
|
144
|
+
#++
|
142
145
|
|
143
146
|
def navigation
|
144
147
|
nav = ""
|
@@ -175,32 +178,57 @@ class Pager < Array
|
|
175
178
|
|
176
179
|
return nav
|
177
180
|
end
|
181
|
+
alias_method :links, :navigation
|
182
|
+
|
183
|
+
private
|
178
184
|
|
179
|
-
# Create an appropriate SQL limit clause.
|
180
|
-
# Returns postgres/mysql compatible limit.
|
181
|
-
|
182
|
-
def sql_limit
|
183
|
-
if @start_idx > 0
|
184
|
-
return "LIMIT #{@items_per_page} OFFSET #{@start_idx}"
|
185
|
-
else
|
186
|
-
# gmosx: perhaps this is optimized ? naaaaaah...
|
187
|
-
return "LIMIT #{@items_per_page}"
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
# Returns the current offset. The offset is zero-based.
|
192
|
-
|
193
|
-
def offset
|
194
|
-
(@page-1) * @items_per_page
|
195
|
-
end
|
196
|
-
|
197
185
|
# Generate the target URI.
|
198
|
-
|
186
|
+
|
199
187
|
def target_uri(page)
|
200
|
-
params = {
|
188
|
+
params = { @key => page }
|
201
189
|
return UriUtils.update_query_string(@request.uri.to_s, params)
|
202
190
|
end
|
203
191
|
|
204
192
|
end
|
205
193
|
|
206
|
-
|
194
|
+
# Pager related helper methods.
|
195
|
+
|
196
|
+
module PagerMixin
|
197
|
+
|
198
|
+
private
|
199
|
+
|
200
|
+
# Helper method that generates a collection of items and the
|
201
|
+
# asorted pager object.
|
202
|
+
#
|
203
|
+
# === Example
|
204
|
+
#
|
205
|
+
# entries, pager = paginate(Article, :condition => 'title LIKE %Ab%', :per_page => 10)
|
206
|
+
#
|
207
|
+
# <ul>
|
208
|
+
# <?r for entry in entries ?>
|
209
|
+
# <li>#{entry.to_link}</li>
|
210
|
+
# <?r end ?>
|
211
|
+
# </ul>
|
212
|
+
# #{pager.links}
|
213
|
+
|
214
|
+
def paginate(klass_or_array, options = {})
|
215
|
+
per_page = options.delete(:per_page) || Pager.per_page
|
216
|
+
|
217
|
+
if klass_or_array.is_a? Array
|
218
|
+
items = klass_or_array.dup
|
219
|
+
pager = Pager.new(request, per_page, items.size, key = Pager.key)
|
220
|
+
items = items.slice(pager.offset, pager.per_page)
|
221
|
+
return items, pager
|
222
|
+
else
|
223
|
+
pager = Pager.new(request, per_page, klass_or_array.count(options), key = Pager.key)
|
224
|
+
options.update(pager.limit)
|
225
|
+
items = klass_or_array.all(options)
|
226
|
+
return items, pager
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
end
|
231
|
+
|
232
|
+
end
|
233
|
+
|
234
|
+
# * George Moschovitis <gm@navel.gr>
|
data/lib/nitro/render.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
require 'sync'
|
2
2
|
|
3
|
+
require 'facet/string/blank%3F'
|
4
|
+
|
3
5
|
require 'glue/attribute'
|
4
6
|
require 'glue/misc'
|
5
7
|
require 'glue/object'
|
8
|
+
require 'glue/settings'
|
6
9
|
|
7
10
|
require 'nitro/shaders'
|
8
11
|
require 'nitro/buffering'
|
@@ -27,12 +30,12 @@ module Rendering
|
|
27
30
|
@@sync = Sync.new
|
28
31
|
|
29
32
|
# The default template root
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
+
|
34
|
+
setting :default_template_root, :default => 'public', :doc => 'The default template root'
|
35
|
+
|
33
36
|
# The default template name (no extension).
|
34
37
|
|
35
|
-
|
38
|
+
setting :default_template, :default => 'index', :doc => 'The default template name (no extension).'
|
36
39
|
|
37
40
|
# The shader used for transforming templates.
|
38
41
|
# The default shader is very simple, here is a
|
@@ -48,11 +51,12 @@ module Rendering
|
|
48
51
|
# </tt>
|
49
52
|
|
50
53
|
mattr_accessor :shader; @@shader = RubyShader.new
|
54
|
+
# setting :shader, :default => RubyShader.new, :doc => 'The shader used for transforming templates'
|
51
55
|
|
52
56
|
# If set to :full, reloads all controllers. Useful in
|
53
57
|
# development.
|
54
58
|
|
55
|
-
|
59
|
+
setting :reload, :default => false, :doc => 'If set to :full reloads everything, useful in development'
|
56
60
|
|
57
61
|
# Given the action try find the matching template.
|
58
62
|
# Can search for xhtml or xml templates.
|
@@ -133,15 +137,17 @@ module Rendering
|
|
133
137
|
|
134
138
|
param_count = klass.instance_method(action.intern).arity
|
135
139
|
|
140
|
+
# gmosx, FIXME: REIMPLEMENT THIS!!!!
|
141
|
+
|
136
142
|
if param_count > 0
|
137
143
|
code << %{
|
144
|
+
params = []
|
138
145
|
qs = context.query_string.split(/[&;]/)
|
139
146
|
|
140
|
-
params = []
|
141
147
|
#{param_count}.times do |i|
|
142
148
|
params << qs.shift.split(/=/).last
|
143
149
|
end
|
144
|
-
|
150
|
+
|
145
151
|
unless :stop == #{action}(*params)
|
146
152
|
}
|
147
153
|
else
|
@@ -272,7 +278,11 @@ module Render
|
|
272
278
|
# The name of the currently executing action.
|
273
279
|
|
274
280
|
attr_accessor :action_name
|
275
|
-
|
281
|
+
|
282
|
+
# The name of the current controller.
|
283
|
+
|
284
|
+
attr_accessor :controller_name
|
285
|
+
|
276
286
|
# Initialize the render.
|
277
287
|
#
|
278
288
|
# [+context+]
|
@@ -280,6 +290,7 @@ module Render
|
|
280
290
|
|
281
291
|
def initialize(context, base = nil)
|
282
292
|
@request = @response = @context = context
|
293
|
+
@controller_name = base
|
283
294
|
@out = context.out
|
284
295
|
end
|
285
296
|
|
@@ -324,6 +335,7 @@ private
|
|
324
335
|
def redirect(url, status = 303)
|
325
336
|
url = url.to_s
|
326
337
|
url = "#{@context.host_url}/#{url.gsub(/^\//, '')}" unless url =~ /http/
|
338
|
+
|
327
339
|
@context.status = status
|
328
340
|
@context.out = "<html><a href=\"#{url}\">#{url}</a>.</html>\n"
|
329
341
|
@context.response_headers['location'] = url
|
data/lib/nitro/request.rb
CHANGED
data/lib/nitro/routing.rb
CHANGED
@@ -1,10 +1,8 @@
|
|
1
|
-
# * George Moschovitis <gm@navel.gr>
|
2
|
-
# (c) 2004-2005 Navel, all rights reserved.
|
3
|
-
# $Id: routing.rb 1 2005-04-11 11:04:30Z gmosx $
|
4
|
-
|
5
1
|
module Nitro
|
6
2
|
|
7
|
-
# Router mixin.
|
3
|
+
# Router mixin. Typically used to generate 'nice' urls.
|
4
|
+
# Nice urls are considered (?) more Search Engine
|
5
|
+
# friendly.
|
8
6
|
|
9
7
|
module Router
|
10
8
|
|
@@ -31,3 +29,6 @@ module Router
|
|
31
29
|
end
|
32
30
|
|
33
31
|
end
|
32
|
+
|
33
|
+
# * George Moschovitis <gm@navel.gr>
|
34
|
+
|
data/lib/nitro/runner.rb
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
require 'optparse'
|
4
4
|
|
5
5
|
require 'glue/misc'
|
6
|
+
require 'glue/configuration'
|
7
|
+
|
6
8
|
require 'nitro/conf'
|
7
9
|
|
8
10
|
module Nitro
|
@@ -135,7 +137,8 @@ class Runner
|
|
135
137
|
end
|
136
138
|
ENV['NITRO_INVOKE'] = 'irb'
|
137
139
|
conf_file = File.basename(caller.last.split(':').first)
|
138
|
-
exec "#{irb_name} -r #{conf_file} -r irb/completion --noinspect"
|
140
|
+
# exec "#{irb_name} -r #{conf_file} -r irb/completion --noinspect"
|
141
|
+
exec "#{irb_name} -r #{conf_file} --noinspect"
|
139
142
|
exit
|
140
143
|
end
|
141
144
|
|
@@ -170,20 +173,19 @@ class Runner
|
|
170
173
|
# using the passed configuration parameters.
|
171
174
|
|
172
175
|
def run(conf)
|
173
|
-
|
174
176
|
if conf.is_a?(Hash)
|
175
177
|
conf = Conf.new(conf)
|
176
178
|
end
|
177
179
|
|
178
180
|
case @mode
|
179
|
-
|
180
|
-
|
181
|
+
when :debug
|
182
|
+
setup_debug(conf)
|
181
183
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
184
|
+
when :stage
|
185
|
+
setup_stage(conf)
|
186
|
+
|
187
|
+
when :live
|
188
|
+
setup_live(conf)
|
187
189
|
end
|
188
190
|
|
189
191
|
if 'fcgi_proc' == ENV['NITRO_INVOKE']
|
@@ -330,6 +332,16 @@ def self.run(conf = nil)
|
|
330
332
|
runner.run(conf)
|
331
333
|
end
|
332
334
|
|
335
|
+
#--
|
336
|
+
# Experimental.
|
337
|
+
#++
|
338
|
+
|
339
|
+
def self.start(controller)
|
340
|
+
# require 'glue/autoreload'
|
341
|
+
# autoreload(3)
|
342
|
+
Server.run(controller)
|
343
|
+
end
|
344
|
+
|
333
345
|
end
|
334
346
|
|
335
347
|
# * George Moschovitis <gm@navel.gr>
|
data/lib/nitro/server.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'glue/autoreload'
|
2
|
+
require 'nitro/adapter/webrick'
|
3
|
+
|
4
|
+
module Nitro
|
5
|
+
|
6
|
+
class Server
|
7
|
+
|
8
|
+
# :nodoc: all
|
9
|
+
# A Helper class used for CherryPy-style publishing.
|
10
|
+
|
11
|
+
class Mounter
|
12
|
+
def initialize(parent, base = '')
|
13
|
+
@parent, @base = parent, base
|
14
|
+
end
|
15
|
+
|
16
|
+
def method_missing(sym, *args)
|
17
|
+
sym = sym.to_s
|
18
|
+
if sym =~ /=$/
|
19
|
+
@parent.map["#@base/#{sym.gsub(/=/, '')}"] = args.first
|
20
|
+
else
|
21
|
+
Mounter.new(@parent, "#@base/#{sym}")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# The server listening address.
|
27
|
+
#--
|
28
|
+
# 0.0.0.0 may be a better default?
|
29
|
+
#++
|
30
|
+
|
31
|
+
setting :address, :default => '127.0.0.1', :doc => 'The server listening address'
|
32
|
+
|
33
|
+
# The server listening port.
|
34
|
+
|
35
|
+
setting :port, :default => 9999, :doc => 'The server listening port'
|
36
|
+
|
37
|
+
# The map.
|
38
|
+
|
39
|
+
setting :map, :default => { '/' => SimpleController }, :doc => 'The server map'
|
40
|
+
|
41
|
+
# The name of the application.
|
42
|
+
|
43
|
+
attr_accessor :name
|
44
|
+
|
45
|
+
# The sitemap. Defines how controller objects are published.
|
46
|
+
|
47
|
+
attr_accessor :map
|
48
|
+
|
49
|
+
def initialize(name = 'Nitro')
|
50
|
+
@name = name
|
51
|
+
@map = self.class.map.dup
|
52
|
+
end
|
53
|
+
|
54
|
+
# Start the server.
|
55
|
+
|
56
|
+
def start(controller = nil)
|
57
|
+
self.map['/'] = controller if controller
|
58
|
+
|
59
|
+
$DBG = true
|
60
|
+
autoreload(3)
|
61
|
+
Rendering.reload = :full
|
62
|
+
|
63
|
+
dispatcher = Dispatcher.new
|
64
|
+
dispatcher.publish(self.map)
|
65
|
+
conf = {
|
66
|
+
:dispatcher => dispatcher
|
67
|
+
}
|
68
|
+
|
69
|
+
Webrick.start(Conf.new(conf))
|
70
|
+
end
|
71
|
+
|
72
|
+
def root=(controller)
|
73
|
+
@map['/'] = controller
|
74
|
+
end
|
75
|
+
|
76
|
+
def root
|
77
|
+
Mounter.new(self)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Helper method.
|
81
|
+
|
82
|
+
def self.run(controller = nil)
|
83
|
+
server = Server.new
|
84
|
+
server.start(controller)
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
# Alias for the Server class.
|
92
|
+
|
93
|
+
App = Nitro::Server unless Object.const_defined?(:App)
|
94
|
+
|
95
|
+
# * George Moschovitis <gm@navel.gr>
|