nitro 0.22.0 → 0.23.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/CHANGELOG +109 -1250
- data/INSTALL +3 -2
- data/README +5 -4
- data/Rakefile +1 -1
- data/bin/nitrogen +1 -1
- data/doc/AUTHORS +20 -6
- data/doc/CHANGELOG.3 +1314 -0
- data/doc/RELEASES +90 -0
- data/lib/nitro.rb +6 -17
- data/lib/nitro/adapter/cgi.rb +11 -0
- data/lib/nitro/adapter/webrick.rb +7 -1
- data/lib/nitro/caching/stores.rb +4 -6
- data/lib/nitro/compiler.rb +1 -1
- data/lib/nitro/compiler/errors.rb +1 -1
- data/lib/nitro/context.rb +11 -4
- data/lib/nitro/controller.rb +0 -3
- data/lib/nitro/cookie.rb +4 -3
- data/lib/nitro/dispatcher.rb +7 -1
- data/lib/nitro/dispatcher/nice.rb +6 -1
- data/lib/nitro/element.rb +2 -2
- data/lib/nitro/mixin/benchmark.rb +16 -0
- data/lib/nitro/mixin/form.rb +171 -55
- data/lib/nitro/mixin/rss.rb +1 -1
- data/lib/nitro/mixin/xhtml.rb +91 -4
- data/lib/nitro/render.rb +25 -6
- data/lib/nitro/request.rb +13 -3
- data/lib/nitro/scaffold.rb +91 -68
- data/lib/nitro/scaffold/relations.rb +54 -0
- data/lib/nitro/server.rb +8 -5
- data/lib/nitro/server/runner.rb +4 -3
- data/lib/nitro/service.rb +3 -1
- data/lib/nitro/service/xmlrpc.rb +1 -1
- data/lib/nitro/session.rb +69 -51
- data/lib/nitro/session/drb.rb +5 -7
- data/lib/nitro/session/drbserver.rb +4 -6
- data/lib/nitro/session/memory.rb +4 -6
- data/lib/part/admin.rb +6 -0
- data/lib/part/admin/controller.rb +24 -0
- data/lib/part/admin/skin.rb +21 -0
- data/lib/part/admin/template/index.xhtml +9 -0
- data/proto/public/js/cookies.js +122 -0
- data/proto/public/scaffold/edit.xhtml +4 -0
- data/proto/public/scaffold/form.xhtml +7 -0
- data/proto/public/scaffold/list.xhtml +15 -0
- data/proto/public/scaffold/new.xhtml +4 -0
- data/proto/public/scaffold/view.xhtml +0 -0
- data/proto/script/benchmark +19 -0
- data/test/nitro/adapter/tc_cgi.rb +32 -2
- data/test/nitro/mixin/tc_xhtml.rb +6 -0
- data/test/nitro/tc_dispatcher.rb +0 -17
- data/test/nitro/tc_render.rb +58 -0
- data/test/nitro/tc_server.rb +2 -0
- data/test/nitro/tc_session.rb +16 -0
- metadata +104 -85
data/doc/RELEASES
CHANGED
@@ -1,3 +1,93 @@
|
|
1
|
+
== Version 0.23.0
|
2
|
+
|
3
|
+
The summer vacations are over and there is a brand new Nitro
|
4
|
+
release. There is a preview of the new Scaffolder (also handles
|
5
|
+
Og relations), support for Tagging (folksonomy), lots of small
|
6
|
+
features and improvements and many bug fixes. Additionally, the
|
7
|
+
code has been restructured to utilize the excellent Nano and Mega
|
8
|
+
support libraries.
|
9
|
+
|
10
|
+
Most notable additions:
|
11
|
+
|
12
|
+
* Scaffolding reloaded. The scaffolding infrastructure is
|
13
|
+
reimplemented to generate more flexible code. The automatically
|
14
|
+
generated forms allow for visualization and editing of
|
15
|
+
Og relations such as HasMany and BelongsTo.
|
16
|
+
|
17
|
+
For example when rendering a BelongsTo relation all possible
|
18
|
+
parents are presented with a select element. When rendering a
|
19
|
+
HasMany relation a list of all children is presented.
|
20
|
+
|
21
|
+
Moreover, an experimental admin component is provided. Just add the
|
22
|
+
line:
|
23
|
+
|
24
|
+
require 'part/admin'
|
25
|
+
|
26
|
+
and surf
|
27
|
+
|
28
|
+
http://www.mysite.com/admin
|
29
|
+
|
30
|
+
To enter a simple administration screen.
|
31
|
+
|
32
|
+
WARNING: This feature is considered a preview and will be
|
33
|
+
improved in a future version.
|
34
|
+
|
35
|
+
* Major cleanup in the Glue subproject. Some files are moved
|
36
|
+
to the nano/mega project. Nano/Mega is now used throughout
|
37
|
+
Nitro and really makes development so much easier.
|
38
|
+
|
39
|
+
* Introduced Og Taggable mixin. It was never easier to add
|
40
|
+
tagging to your application.
|
41
|
+
|
42
|
+
class Article
|
43
|
+
include Og::Taggable
|
44
|
+
..
|
45
|
+
end
|
46
|
+
|
47
|
+
article.tag('navel', 'gmosx', 'nitro')
|
48
|
+
article.tags
|
49
|
+
article.tag_names
|
50
|
+
Article.find_with_tags('navel', 'gmosx')
|
51
|
+
Article.find_with_any_tag('name', 'gmosx')
|
52
|
+
|
53
|
+
t = Article::Tag.find_by_name('ruby')
|
54
|
+
t.articles
|
55
|
+
t.articles.count
|
56
|
+
|
57
|
+
For an example usage of this Mixin, consult the Spark sources.
|
58
|
+
|
59
|
+
* Added support for relative and absolute URLs in redirects
|
60
|
+
and renders. This feature simplifies the creation of reusable
|
61
|
+
components.
|
62
|
+
|
63
|
+
* Support for assigning compound objects from the request. Here
|
64
|
+
is an example:
|
65
|
+
|
66
|
+
class Article
|
67
|
+
property :title, String
|
68
|
+
property :body, String
|
69
|
+
end
|
70
|
+
|
71
|
+
<form>
|
72
|
+
<input type="text" name="article.title" />
|
73
|
+
<input type="text" name="article.body" />
|
74
|
+
</form>
|
75
|
+
|
76
|
+
article = request.assign('article')
|
77
|
+
|
78
|
+
Alternatively you can use the article[title] article[body]
|
79
|
+
notation.
|
80
|
+
|
81
|
+
* Added simple Benchmarking mixin.
|
82
|
+
|
83
|
+
* Added support for 'evolving' a single Og managed class. Useful
|
84
|
+
when you are in development mode and change your schema.
|
85
|
+
|
86
|
+
* Added support for session garbage collection.
|
87
|
+
|
88
|
+
* Many many small bug fixes in Og and Nitro.
|
89
|
+
|
90
|
+
|
1
91
|
== Version 0.22.0
|
2
92
|
|
3
93
|
A snapshot of the latest developments. Many requested features
|
data/lib/nitro.rb
CHANGED
@@ -1,21 +1,12 @@
|
|
1
1
|
# = Nitro
|
2
2
|
#
|
3
|
-
# Nitro is an efficient, yet simple engine for developing
|
4
|
-
# professional Web Applications using Ruby and Javascript.
|
5
|
-
# Nitro provides a robust infrastructure for scalable
|
6
|
-
# applications that can be distributed over a server
|
7
|
-
# cluster. However, Nitro can also power simple web
|
8
|
-
# applications for deployment on intranets or desktops.
|
9
|
-
#
|
10
|
-
# Nitro integrates the powerful Og Object-Relational mapping
|
11
|
-
# library.
|
12
|
-
#
|
13
|
-
# Copyright (c) 2004-2005, George Moschovitis (http://www.gmosx.com)
|
14
3
|
# Copyright (c) 2004-2005, Navel Ltd (http://www.navel.gr)
|
4
|
+
# Copyright (c) 2004-2005, George Moschovitis (http://www.gmosx.com)
|
15
5
|
#
|
16
|
-
# Nitro is copyrighted free software
|
17
|
-
# George Moschovitis (mailto:gm@navel.gr)
|
18
|
-
# standard BSD Licence. For details
|
6
|
+
# Nitro (http://www.nitrohq.com) is copyrighted free software
|
7
|
+
# created and maintained by George Moschovitis (mailto:gm@navel.gr)
|
8
|
+
# and released under the standard BSD Licence. For details
|
9
|
+
# consult the file doc/LICENCE.
|
19
10
|
|
20
11
|
require 'glue'
|
21
12
|
require 'glue/logger'
|
@@ -25,7 +16,7 @@ module Nitro
|
|
25
16
|
|
26
17
|
# The version.
|
27
18
|
|
28
|
-
Version = '0.
|
19
|
+
Version = '0.23.0'
|
29
20
|
|
30
21
|
# Library path.
|
31
22
|
|
@@ -75,5 +66,3 @@ module Nitro
|
|
75
66
|
end
|
76
67
|
|
77
68
|
end
|
78
|
-
|
79
|
-
# * George Moschovitis <gm@navel.gr>
|
data/lib/nitro/adapter/cgi.rb
CHANGED
@@ -103,6 +103,9 @@ class CgiUtils
|
|
103
103
|
#
|
104
104
|
# Parameters in the form xxx[] are converted
|
105
105
|
# to arrays.
|
106
|
+
#
|
107
|
+
# Use the field.attr or field[attr] notation to pass
|
108
|
+
# compound objects.
|
106
109
|
|
107
110
|
def self.parse_query_string(query_string)
|
108
111
|
params = {}
|
@@ -117,12 +120,20 @@ class CgiUtils
|
|
117
120
|
val = CGI.unescape(val) unless val.nil?
|
118
121
|
|
119
122
|
if key =~ /(.*)\[\]$/
|
123
|
+
# Multiple values, for example a checkbox collection.
|
124
|
+
# Stored as an array.
|
120
125
|
if params.has_key?($1)
|
121
126
|
params[$1] << val
|
122
127
|
else
|
123
128
|
params[$1] = [val]
|
124
129
|
end
|
130
|
+
elsif key =~ /(.*)\[(.*)\]$/ or key =~ /(.*)\.(.*)$/
|
131
|
+
# A compound object with attributes.
|
132
|
+
# Stored as a Hash.
|
133
|
+
params[$1] ||= {}
|
134
|
+
params[$1][$2] = val
|
125
135
|
else
|
136
|
+
# Standard single valued parameter.
|
126
137
|
params[key] = val.nil? ? nil : val
|
127
138
|
end
|
128
139
|
end
|
@@ -26,7 +26,11 @@ class Webrick
|
|
26
26
|
else
|
27
27
|
wblog = STDERR
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
|
+
webrick_options = server.options.dup
|
31
|
+
require 'webrick/https' if webrick_options[:SSLEnable]
|
32
|
+
|
33
|
+
webrick_options.update(
|
30
34
|
:BindAddress => server.address,
|
31
35
|
:Port => server.port,
|
32
36
|
:DocumentRoot => server.public_root,
|
@@ -35,6 +39,7 @@ class Webrick
|
|
35
39
|
[wblog, WEBrick::AccessLog::REFERER_LOG_FORMAT]
|
36
40
|
]
|
37
41
|
)
|
42
|
+
@webrick = WEBrick::HTTPServer.new(webrick_options)
|
38
43
|
|
39
44
|
trap('INT') { @webrick.shutdown }
|
40
45
|
|
@@ -159,3 +164,4 @@ end
|
|
159
164
|
end
|
160
165
|
|
161
166
|
# * George Moschovitis <gm@navel.gr>
|
167
|
+
# * Guillaume Pierronnet <guillaume.pierronnet@laposte.net>
|
data/lib/nitro/caching/stores.rb
CHANGED
@@ -1,10 +1,6 @@
|
|
1
|
-
# * George Moschovitis <gm@navel.gr>
|
2
|
-
# (c) 2004-2005 Navel, all rights reserved.
|
3
|
-
# $Id: stores.rb 182 2005-07-22 10:07:50Z gmosx $
|
4
|
-
|
5
1
|
require 'fileutils'
|
6
2
|
|
7
|
-
require '
|
3
|
+
require 'mega/synchash'
|
8
4
|
|
9
5
|
module Nitro
|
10
6
|
|
@@ -14,7 +10,7 @@ module Caching
|
|
14
10
|
|
15
11
|
# Cached fragments are stored in memory.
|
16
12
|
|
17
|
-
class MemoryStore <
|
13
|
+
class MemoryStore < SyncHash
|
18
14
|
|
19
15
|
def read(name, options = {})
|
20
16
|
self[name]
|
@@ -82,3 +78,5 @@ module Caching
|
|
82
78
|
end
|
83
79
|
|
84
80
|
end
|
81
|
+
|
82
|
+
# * George Moschovitis <gm@navel.gr>
|
data/lib/nitro/compiler.rb
CHANGED
data/lib/nitro/context.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'nano/object/assign_with'
|
2
|
+
|
1
3
|
require 'nitro/request'
|
2
4
|
require 'nitro/response'
|
3
5
|
require 'nitro/render'
|
@@ -79,23 +81,28 @@ class Context
|
|
79
81
|
EXCLUDED_PARAMETERS = %w{ oid name }
|
80
82
|
|
81
83
|
def fill(obj, name = nil)
|
82
|
-
#
|
84
|
+
# If an class is passed create an instance.
|
83
85
|
obj = obj.new if obj.is_a?(Class)
|
84
86
|
|
85
87
|
@params.each do |param, val|
|
86
88
|
begin
|
87
89
|
# gmosx: DO NOT escape by default !!!
|
88
90
|
if not EXCLUDED_PARAMETERS.include?(param)
|
89
|
-
|
91
|
+
if val.is_a? Hash
|
92
|
+
obj.send("__force_hash_#{param}", val)
|
93
|
+
else
|
94
|
+
obj.send("__force_#{param}", val)
|
95
|
+
end
|
90
96
|
end
|
91
|
-
rescue NameError
|
97
|
+
rescue NameError => ex
|
92
98
|
next
|
93
99
|
end
|
94
100
|
end
|
95
|
-
|
101
|
+
|
96
102
|
return obj
|
97
103
|
end
|
98
104
|
alias_method :populate, :fill
|
105
|
+
alias_method :assign, :fill
|
99
106
|
end
|
100
107
|
|
101
108
|
end
|
data/lib/nitro/controller.rb
CHANGED
data/lib/nitro/cookie.rb
CHANGED
@@ -8,13 +8,14 @@ class Cookie
|
|
8
8
|
attr_accessor :domain, :path, :secure
|
9
9
|
attr_accessor :comment, :max_age
|
10
10
|
|
11
|
-
|
11
|
+
def initialize(name = nil, value = nil, expires = nil)
|
12
12
|
@name = name
|
13
13
|
@value = value
|
14
|
+
self.expires = expires
|
14
15
|
@version = 0 # Netscape Cookie
|
15
16
|
@path = '/' # gmosx: KEEP this!
|
16
|
-
@domain = @secure = @comment = @max_age =
|
17
|
-
@
|
17
|
+
@domain = @secure = @comment = @max_age = nil
|
18
|
+
@comment_url = @discard = @port = nil
|
18
19
|
end
|
19
20
|
|
20
21
|
def expires=(t)
|
data/lib/nitro/dispatcher.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'nano/object/singleton_class'
|
2
2
|
|
3
3
|
require 'nitro/controller'
|
4
4
|
require 'nitro/routing'
|
@@ -86,6 +86,12 @@ class Dispatcher
|
|
86
86
|
end
|
87
87
|
|
88
88
|
auto_mixin(c)
|
89
|
+
|
90
|
+
# Perform mount-time initialization of the controller.
|
91
|
+
|
92
|
+
if c.respond_to? :mounted
|
93
|
+
c.mounted
|
94
|
+
end
|
89
95
|
|
90
96
|
# Try to setup a template_root if none is defined:
|
91
97
|
|
@@ -8,6 +8,9 @@ class Dispatcher
|
|
8
8
|
|
9
9
|
# An alternative dispatching algorithm that handles
|
10
10
|
# implicit nice urls. Subdirectories are not supported.
|
11
|
+
#
|
12
|
+
# Returns the dispatcher class, the action name and the
|
13
|
+
# base url. For the root path, the base url is nil.
|
11
14
|
|
12
15
|
def dispatch(path, context)
|
13
16
|
path = route(path, context)
|
@@ -18,7 +21,7 @@ class Dispatcher
|
|
18
21
|
if klass = controller_class_for("/#{parts.first}")
|
19
22
|
base = "/#{parts.shift}"
|
20
23
|
else
|
21
|
-
base =
|
24
|
+
base = nil
|
22
25
|
klass = controller_class_for(ROOT)
|
23
26
|
end
|
24
27
|
|
@@ -30,6 +33,8 @@ class Dispatcher
|
|
30
33
|
context.headers['QUERY_STRING'] = "#{parts.join(';')};#{context.headers['QUERY_STRING']}"
|
31
34
|
end
|
32
35
|
|
36
|
+
base = nil if base == ROOT
|
37
|
+
|
33
38
|
return klass, "#{action}_action", base
|
34
39
|
end
|
35
40
|
end
|
data/lib/nitro/element.rb
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'benchmark'
|
2
|
+
|
3
|
+
module Nitro
|
4
|
+
|
5
|
+
module BenchmarkMixin
|
6
|
+
|
7
|
+
def benchmark(message = 'Benchmarking')
|
8
|
+
real = Benchmark.realtime { yield }
|
9
|
+
Logger.info "#{message}: time = #{'%.5f' % real} ms."
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
# * George Moschovitis <gm@navel.gr>
|
data/lib/nitro/mixin/form.rb
CHANGED
@@ -1,88 +1,204 @@
|
|
1
|
-
require '
|
1
|
+
require 'nano/inflect'
|
2
2
|
|
3
3
|
module Nitro
|
4
4
|
|
5
5
|
# A collection of useful helpers for creating and manipulating
|
6
6
|
# Forms.
|
7
|
+
#--
|
8
|
+
# FIXME: cleanup this file, move stuff to scaffold, allow
|
9
|
+
# overrides.
|
10
|
+
#++
|
7
11
|
|
8
12
|
module FormMixin
|
9
13
|
|
10
|
-
|
11
|
-
|
14
|
+
def self.included(base)
|
15
|
+
base.send :include, XhtmlMixin
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
# Render a standard form for the given Object. The object
|
21
|
+
# should include attribute metadata.
|
22
|
+
#--
|
23
|
+
# TODO: get info, for example localization mode from session,
|
24
|
+
# if this module is mixed in a Render.
|
25
|
+
#++
|
26
|
+
|
27
|
+
def form_for(obj, options = {})
|
28
|
+
method = options.fetch(:method, 'post')
|
29
|
+
action = options.fetch(:action, "save_#{obj.class.name.underscore}")
|
30
|
+
submit = options.fetch(:submit, 'Save')
|
31
|
+
|
32
|
+
action = "#{@base}/#{action}" unless action =~ /\//
|
33
|
+
|
34
|
+
str = %{<form action="#{action}" method="post">}
|
35
|
+
if obj.oid
|
36
|
+
str << %{
|
37
|
+
<input type="hidden" name="oid" value="#{obj.oid}" />}
|
38
|
+
end
|
39
|
+
str << %{
|
40
|
+
#{tags_for(obj, options)}
|
41
|
+
<br />
|
42
|
+
<input type="submit" value="#{submit}" /> or <a href="#@base/#{Scaffolding.class_to_list(obj.class)}">Cancel</a>
|
43
|
+
</form>
|
44
|
+
}
|
45
|
+
return str
|
46
|
+
end
|
47
|
+
|
48
|
+
# Render a standard form tags for the given Object. The object
|
49
|
+
# should include attribute metadata.
|
50
|
+
#
|
12
51
|
# If show_all is false then apply field filtering.
|
13
52
|
#
|
53
|
+
# For extra flexibility and to keep semantics this helper
|
54
|
+
# emits a <dl> structure. You can use CSS to style the
|
55
|
+
# list to fit your overal design.
|
56
|
+
#
|
14
57
|
# Example:
|
15
58
|
#
|
16
59
|
# <p>
|
17
60
|
# <form name="test">
|
18
|
-
# #{
|
61
|
+
# #{tags_for entry}
|
19
62
|
# </form>
|
20
63
|
# </p>
|
21
|
-
#--
|
22
|
-
# TODO: get info, for example localization mode from session,
|
23
|
-
# if this module is mixed in a Render.
|
24
|
-
#++
|
25
64
|
|
26
|
-
def
|
27
|
-
str =
|
65
|
+
def tags_for(obj, options = {})
|
66
|
+
str = prologue()
|
28
67
|
|
29
68
|
for p in obj.class.properties
|
30
|
-
unless
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
<input type="text" id="#{p.symbol}" name="#{p.symbol}" value="#{obj.send(p.symbol)}" />
|
40
|
-
</dd>
|
41
|
-
}
|
42
|
-
elsif p.klass.ancestors.include?(String)
|
43
|
-
str << %{
|
44
|
-
<dt><label for="#{p.symbol}">#{p.symbol}</label></dt>
|
45
|
-
<dd>
|
46
|
-
}
|
47
|
-
val = obj.send(p.symbol)
|
48
|
-
if :textarea == p.meta[:ui]
|
49
|
-
str << %{
|
50
|
-
<textarea id="#{p.symbol}" name="#{p.symbol}">#{val}</textarea>
|
51
|
-
}
|
69
|
+
next if :oid == p.symbol unless options[:all]
|
70
|
+
ancestors = p.klass.ancestors
|
71
|
+
if ancestors.include?(Numeric)
|
72
|
+
unless p.meta[:relation]
|
73
|
+
str << field_tag(obj, p, options)
|
74
|
+
end
|
75
|
+
elsif ancestors.include?(String)
|
76
|
+
if p.metadata[:editor] == :textarea
|
77
|
+
str << textarea_tag(obj, p, options)
|
52
78
|
else
|
53
|
-
str <<
|
54
|
-
<input type="text" id="#{p.symbol}" name="#{p.symbol}" value="#{val}" />
|
55
|
-
}
|
79
|
+
str << field_tag(obj, p, options)
|
56
80
|
end
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
81
|
+
elsif ancestors.include?(TrueClass)
|
82
|
+
str << checkbox_tag(obj, p, options)
|
83
|
+
elsif ancestors.include?(Time)
|
84
|
+
str << datetime_tag(obj, p, options)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
for rel in obj.class.relations
|
89
|
+
case rel
|
90
|
+
when Og::BelongsTo
|
91
|
+
str << belongs_to_tag(obj, rel, options)
|
92
|
+
when Og::HasMany
|
93
|
+
str << has_many_tag(obj, rel, options)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
str << epilogue()
|
98
|
+
|
99
|
+
return str
|
100
|
+
end
|
101
|
+
|
102
|
+
def belongs_to_tag(obj, rel, options)
|
103
|
+
entities = rel.target_class.all
|
104
|
+
labels = entities.map { |e| e.to_s }
|
105
|
+
values = entities.map { |e| e.oid }
|
106
|
+
element(
|
107
|
+
label(rel.name),
|
108
|
+
%{
|
109
|
+
<select id="#{rel.name}" name="#{rel.name}">
|
110
|
+
#{options(:labels => labels, :values => values, :selected => 1)}
|
111
|
+
</select>
|
112
|
+
}
|
113
|
+
)
|
114
|
+
end
|
115
|
+
|
116
|
+
def has_many_tag(obj, rel, options)
|
117
|
+
entities = obj.send(rel.target_plural_name) if obj.saved?
|
118
|
+
unless entities.empty?
|
119
|
+
str = entities.inject('') do |acc, e|
|
120
|
+
acc << "<tr><td>#{e.to_edit_link(@base)}</td></tr>"
|
121
|
+
end
|
122
|
+
str = "<table>#{str}</table>"
|
123
|
+
else
|
124
|
+
str = 'No entities found.<br /><br />'
|
125
|
+
end
|
126
|
+
element(
|
127
|
+
label(rel.name) + ' <a href="#">Add</a>',
|
128
|
+
%{
|
129
|
+
#{str}
|
130
|
+
}
|
131
|
+
)
|
132
|
+
end
|
133
|
+
|
134
|
+
def field_tag(obj, p, options)
|
135
|
+
%{
|
136
|
+
<dt>#{label(p.symbol)}</dt>
|
63
137
|
<dd>
|
64
|
-
<input type="
|
138
|
+
<input type="text" id="#{p.symbol}" name="#{p.symbol}" value="#{obj.send(p.symbol)}" style="width: 250px" />
|
65
139
|
</dd>
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
140
|
+
}
|
141
|
+
end
|
142
|
+
|
143
|
+
def textarea_tag(obj, p, options)
|
144
|
+
%{
|
145
|
+
<dt>#{label(p.symbol)}</dt>
|
70
146
|
<dd>
|
71
|
-
<
|
147
|
+
<textarea id="#{p.symbol}" name="#{p.symbol}">#{obj.send(p.symbol)}</textarea>
|
72
148
|
</dd>
|
73
|
-
|
74
|
-
|
75
|
-
end
|
149
|
+
}
|
150
|
+
end
|
76
151
|
|
77
|
-
|
78
|
-
|
152
|
+
def checkbox_tag(obj, p, options)
|
153
|
+
%{
|
154
|
+
<dt>
|
155
|
+
<input type="checkbox" id="#{p.symbol}" name="#{p.symbol}" />
|
156
|
+
#{label(p.symbol)}
|
157
|
+
</dt>
|
158
|
+
<dd>#{}</dd>
|
159
|
+
}
|
160
|
+
end
|
79
161
|
|
80
|
-
|
162
|
+
def datetime_tag(obj, p, options)
|
163
|
+
element(
|
164
|
+
label(p.symbol),
|
165
|
+
datetime_select(obj.send(p.symbol), :name => p.symbol.to_s)
|
166
|
+
)
|
167
|
+
end
|
168
|
+
|
169
|
+
def label(sym)
|
170
|
+
%|<label for="#{sym}">#{sym.to_s.humanize}</label>|
|
171
|
+
end
|
172
|
+
|
173
|
+
# :section: Relations.
|
174
|
+
|
175
|
+
|
176
|
+
# :section: General formating methods. Override to customize.
|
177
|
+
|
178
|
+
# Emit form prologue.
|
179
|
+
|
180
|
+
def prologue
|
181
|
+
'<dl>'
|
182
|
+
end
|
183
|
+
|
184
|
+
# Emit form epilogue.
|
185
|
+
|
186
|
+
def epilogue
|
187
|
+
'</dl>'
|
81
188
|
end
|
82
|
-
alias_method :build_form, :form_for
|
83
189
|
|
190
|
+
# Emit a form element.
|
191
|
+
|
192
|
+
def element(label, element)
|
193
|
+
%{
|
194
|
+
<dt>#{label}</dt>
|
195
|
+
<dd>
|
196
|
+
#{element}
|
197
|
+
</dd>
|
198
|
+
}
|
199
|
+
end
|
84
200
|
end
|
85
201
|
|
86
202
|
end
|
87
203
|
|
88
|
-
# * George Moschovitis
|
204
|
+
# * George Moschovitis <gm@navel.gr>
|