nitro 0.29.0 → 0.30.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 +410 -0
- data/ProjectInfo +36 -44
- data/README +5 -5
- data/doc/AUTHORS +6 -0
- data/doc/RELEASES +159 -2
- data/lib/glue/sweeper.rb +2 -2
- data/lib/glue/webfile.rb +14 -1
- data/lib/nitro.rb +6 -9
- data/lib/nitro/adapter/mongrel.rb +36 -43
- data/lib/nitro/adapter/scgi.rb +1 -1
- data/lib/nitro/adapter/webrick.rb +96 -24
- data/lib/nitro/caching/actions.rb +2 -1
- data/lib/nitro/caching/fragments.rb +1 -8
- data/lib/nitro/caching/output.rb +14 -4
- data/lib/nitro/cgi.rb +19 -21
- data/lib/nitro/cgi/cookie.rb +5 -1
- data/lib/nitro/cgi/request.rb +20 -4
- data/lib/nitro/compiler.rb +74 -28
- data/lib/nitro/compiler/cleanup.rb +1 -1
- data/lib/nitro/compiler/elements.rb +1 -2
- data/lib/nitro/compiler/localization.rb +1 -1
- data/lib/nitro/compiler/markup.rb +1 -1
- data/lib/nitro/compiler/script.rb +52 -44
- data/lib/nitro/compiler/squeeze.rb +4 -3
- data/lib/nitro/compiler/xslt.rb +7 -6
- data/lib/nitro/context.rb +39 -20
- data/lib/nitro/controller.rb +24 -5
- data/lib/nitro/dispatcher.rb +13 -5
- data/lib/nitro/global.rb +63 -0
- data/lib/nitro/helper/feed.rb +432 -0
- data/lib/nitro/helper/form.rb +11 -3
- data/lib/nitro/helper/form/builder.rb +140 -0
- data/lib/nitro/helper/form/controls.rb +2 -1
- data/lib/nitro/helper/javascript.rb +6 -0
- data/lib/nitro/helper/javascript/morphing.rb +13 -6
- data/lib/nitro/helper/xhtml.rb +42 -6
- data/lib/nitro/helper/xml.rb +3 -0
- data/lib/nitro/part.rb +2 -2
- data/lib/nitro/render.rb +7 -2
- data/lib/nitro/router.rb +57 -16
- data/lib/nitro/scaffolding.rb +29 -20
- data/lib/nitro/server.rb +4 -10
- data/lib/nitro/server/drb.rb +1 -1
- data/lib/nitro/server/runner.rb +10 -0
- data/lib/nitro/session.rb +31 -12
- data/lib/nitro/session/drb.rb +13 -1
- data/lib/nitro/session/file.rb +1 -1
- data/lib/nitro/session/memcached.rb +1 -1
- data/lib/nitro/session/memory.rb +1 -1
- data/lib/nitro/session/og.rb +1 -1
- data/lib/nitro/test/testcase.rb +3 -0
- data/proto/public/error.xhtml +5 -5
- data/proto/public/js/controls.js +2 -2
- data/proto/public/js/dragdrop.js +320 -79
- data/proto/public/js/effects.js +200 -152
- data/proto/public/js/prototype.js +284 -63
- data/proto/public/js/scriptaculous.js +7 -5
- data/proto/public/js/unittest.js +11 -0
- data/proto/public/scaffold/advanced_search.xhtml +30 -0
- data/proto/public/scaffold/list.xhtml +8 -1
- data/proto/public/scaffold/search.xhtml +2 -1
- data/proto/script/scgi_service +1 -1
- data/src/part/admin/controller.rb +1 -1
- data/src/part/admin/skin.rb +1 -1
- data/test/nitro/CONFIG.rb +3 -0
- data/test/nitro/adapter/tc_webrick.rb +1 -1
- data/test/nitro/cgi/tc_cookie.rb +1 -1
- data/test/nitro/cgi/tc_request.rb +5 -5
- data/test/nitro/compiler/tc_client_morpher.rb +47 -0
- data/test/nitro/compiler/tc_compiler.rb +2 -0
- data/test/nitro/helper/tc_feed.rb +138 -0
- data/test/nitro/helper/tc_pager.rb +1 -1
- data/test/nitro/helper/tc_rss.rb +1 -1
- data/test/nitro/helper/tc_table.rb +1 -1
- data/test/nitro/helper/tc_xhtml.rb +1 -1
- data/test/nitro/tc_caching.rb +1 -1
- data/test/nitro/tc_cgi.rb +1 -1
- data/test/nitro/tc_context.rb +1 -1
- data/test/nitro/tc_controller.rb +31 -3
- data/test/nitro/tc_controller_aspect.rb +1 -1
- data/test/nitro/tc_dispatcher.rb +1 -1
- data/test/nitro/tc_element.rb +1 -1
- data/test/nitro/tc_flash.rb +1 -1
- data/test/nitro/tc_helper.rb +1 -1
- data/test/nitro/tc_render.rb +6 -6
- data/test/nitro/tc_router.rb +8 -4
- data/test/nitro/tc_server.rb +1 -3
- data/test/nitro/tc_session.rb +1 -3
- metadata +107 -104
- data/Rakefile +0 -232
- data/lib/nitro/adapter/acgi.rb +0 -237
- data/proto/public/Makefile.acgi +0 -40
- data/proto/public/acgi.c +0 -138
@@ -0,0 +1,432 @@
|
|
1
|
+
require 'rss/maker'
|
2
|
+
require 'glue/markup'
|
3
|
+
require 'rexml/document'
|
4
|
+
require 'time'
|
5
|
+
require 'uri'
|
6
|
+
|
7
|
+
require 'facet/string/first_char'
|
8
|
+
|
9
|
+
module Nitro
|
10
|
+
|
11
|
+
# A helper that provides Feed related methods.
|
12
|
+
#
|
13
|
+
# To include this helper into your controller,
|
14
|
+
# add the following at the beginning of your controller:
|
15
|
+
#
|
16
|
+
# helper :feed
|
17
|
+
#
|
18
|
+
# Then define actions that set an appropriate content_type and use build_(rss|atom|opml)
|
19
|
+
# to generate your desired feed. See below for details.
|
20
|
+
#
|
21
|
+
# == RSS 0.91, 1.0 and 2.0
|
22
|
+
#
|
23
|
+
# response.content_type = "application/rss+xml"
|
24
|
+
# build_rss(og_objects,
|
25
|
+
# :version => "0.9",
|
26
|
+
# :base => context.host_url, # + object.to_href results in an item-link
|
27
|
+
# :link => context.host_url+"/feed", # link to this feed
|
28
|
+
# :title => "Feed Title",
|
29
|
+
# :description => "What this feed is about",
|
30
|
+
# :search_title => "Search Form Here",
|
31
|
+
# :search_description => "Search description",
|
32
|
+
# :search_input_name => "search_field",
|
33
|
+
# :search_form_action => "http://url/to/search_action"
|
34
|
+
# )
|
35
|
+
#
|
36
|
+
# For RSS 1.0 or RSS 2.0 just change :version (defaults to '0.91'),
|
37
|
+
# possible :version options are "0.9", "0.91", "1.0" and "2.0"
|
38
|
+
#
|
39
|
+
# * for RSS 0.9 :language is required (or defaults to 'en')
|
40
|
+
# * for all RSS versions :title, :link and/or :base, :description are required
|
41
|
+
#
|
42
|
+
# <b>individual objects have to respond to at least:</b>
|
43
|
+
#
|
44
|
+
# * 1.0/0.9/2.0 require @title
|
45
|
+
# * 1.0/0.9 require @to_href
|
46
|
+
# * 2.0 requires @body
|
47
|
+
#
|
48
|
+
# if it doesn't, no item is created
|
49
|
+
#
|
50
|
+
# * @update_time, @create_time or @date is used for item.date
|
51
|
+
# * so if Og's "is Timestamped" is being used, it'll be @update_time
|
52
|
+
# * @author[:name] can optionally be used for item.author
|
53
|
+
#
|
54
|
+
# == Atom 1.0
|
55
|
+
#
|
56
|
+
# response.content_type = "application/atom+xml"
|
57
|
+
# build_atom(og_objects,
|
58
|
+
# :title => "Feed Title",
|
59
|
+
# :base => context.host_url, # + object.to_href results in an item-link
|
60
|
+
# :link => context.host_url+"/atomfeed",
|
61
|
+
# :id => "your_unique_id", # :base is being used unless :id specified (:base is recommended)
|
62
|
+
# :author_name => "Takeo",
|
63
|
+
# :author_email => "email@example.com",
|
64
|
+
# :author_link => "http://uri.to/authors/home",
|
65
|
+
# )
|
66
|
+
#
|
67
|
+
# <b>individual objects have to respond to at least:</b>
|
68
|
+
#
|
69
|
+
# * @title
|
70
|
+
# * @to_href
|
71
|
+
# * @update_time/@create_time/@date (at least one of them)
|
72
|
+
#
|
73
|
+
# if it doesn't, no entry is created
|
74
|
+
#
|
75
|
+
# optional:
|
76
|
+
#
|
77
|
+
# * @body (taken as summary (256 chars))
|
78
|
+
# * @full_content
|
79
|
+
# * use Og's "is Timestamped", so both @update_time and @create_time can be used
|
80
|
+
# * @author[:name]
|
81
|
+
# * @author[:link]
|
82
|
+
# * @author[:email] # be careful, you don't want to publish your users email address to spammers
|
83
|
+
#
|
84
|
+
#
|
85
|
+
# == OPML 1.0 feed lists
|
86
|
+
#
|
87
|
+
# Fabian: Eew, who invented OPML? Who needs it? Implementing it in a very rough way anyway though.
|
88
|
+
# takes a Hash of Feeds and optional options
|
89
|
+
#
|
90
|
+
# response.content_type = "application/opml+xml"
|
91
|
+
# build_opml(
|
92
|
+
# {
|
93
|
+
# "http://oxyliquit.de/feed" => "rss",
|
94
|
+
# "http://oxyliquit.de/feed/questions" => "rss",
|
95
|
+
# "http://oxyliquit.de/feed/tips" => "rss",
|
96
|
+
# "http://oxyliquit.de/feed/tutorials" => "rss"
|
97
|
+
# },
|
98
|
+
# :title => "My feeds"
|
99
|
+
# )
|
100
|
+
|
101
|
+
module FeedHelper
|
102
|
+
include Glue::Markup
|
103
|
+
|
104
|
+
# RSS 0.91, 1.0, 2.0 feeds.
|
105
|
+
|
106
|
+
def build_rss(objects, options = {})
|
107
|
+
|
108
|
+
# default options
|
109
|
+
options = {
|
110
|
+
:title => 'Syndication',
|
111
|
+
:description => 'Syndication',
|
112
|
+
:version => '0.9',
|
113
|
+
:language => 'en', # required by 0.9
|
114
|
+
}.update(options)
|
115
|
+
|
116
|
+
raise "Option ':version' contains a wrong version!" unless %w(0.9 0.91 1.0 2.0).include?(options[:version])
|
117
|
+
|
118
|
+
options[:base] ||= options[:link]
|
119
|
+
raise "Option ':base' cannot be omitted!" unless options[:base]
|
120
|
+
|
121
|
+
# build rss
|
122
|
+
rss = RSS::Maker.make(options[:version]) do |maker|
|
123
|
+
maker.channel.title = options[:title]
|
124
|
+
maker.channel.description = options[:description]
|
125
|
+
if options[:link]
|
126
|
+
maker.channel.link = options[:link]
|
127
|
+
else
|
128
|
+
maker.channel.link = options[:base] #FIXME: not sure
|
129
|
+
end
|
130
|
+
case options[:version]
|
131
|
+
when '0.9', '0.91'
|
132
|
+
maker.channel.language = options[:language]
|
133
|
+
when '1.0'
|
134
|
+
if options[:link]
|
135
|
+
maker.channel.about = options[:link]
|
136
|
+
else
|
137
|
+
raise "Option ':link' is required for RSS 1.0"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
maker.channel.generator = "Nitro " + Nitro::Version.to_s
|
141
|
+
|
142
|
+
maker.items.do_sort = true
|
143
|
+
|
144
|
+
# items for each object
|
145
|
+
# * 1.0/0.9/2.0 require @title
|
146
|
+
# * 1.0/0.9 require @link
|
147
|
+
# * 2.0 requires @description
|
148
|
+
objects.each do |o|
|
149
|
+
|
150
|
+
# new Item
|
151
|
+
item = maker.items.new_item
|
152
|
+
|
153
|
+
# Link
|
154
|
+
item.link = "#{options[:base]}/#{o.to_href}" if o.respond_to?(:to_href)
|
155
|
+
item.guid.content = "#{options[:base]}/#{o.to_href}" if options[:version] == '2.0' && o.respond_to?(:to_href)
|
156
|
+
|
157
|
+
# Title
|
158
|
+
item.title = o.title if o.respond_to?(:title)
|
159
|
+
|
160
|
+
# Description
|
161
|
+
if o.respond_to? :body and body = o.body
|
162
|
+
#TODO: think about whether markup should always be done
|
163
|
+
# and whether 256 chars should be a fixed limit
|
164
|
+
#item.description = markup(body.first_char(256))
|
165
|
+
# markup disabled, feedvalidator.org says "description should not contain HTML"
|
166
|
+
# so removing everything that looks like a tag
|
167
|
+
item.description = body.first_char(256).gsub!(/<[^>]+>/, ' ')
|
168
|
+
end
|
169
|
+
|
170
|
+
# Date (item.date asks for a Time object, so don't .to_s !)
|
171
|
+
if o.respond_to?(:update_time)
|
172
|
+
item.date = o.update_time
|
173
|
+
elsif o.respond_to?(:create_time)
|
174
|
+
item.date = o.create_time
|
175
|
+
elsif o.respond_to?(:date)
|
176
|
+
item.date = o.date
|
177
|
+
end
|
178
|
+
|
179
|
+
# Author
|
180
|
+
if o.respond_to?(:author)
|
181
|
+
if o.author[:name]
|
182
|
+
item.author = o.author[:name]
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
end if objects.size > 0 # objects/items
|
187
|
+
|
188
|
+
# search form
|
189
|
+
maker.textinput.title = options[:search_title] if options[:search_title]
|
190
|
+
maker.textinput.description = options[:search_description] if options[:search_description]
|
191
|
+
maker.textinput.name = options[:search_input_name] if options[:search_input_name]
|
192
|
+
maker.textinput.link = options[:search_form_action] if options[:search_form_action]
|
193
|
+
end
|
194
|
+
|
195
|
+
return rss.to_s
|
196
|
+
end # rss
|
197
|
+
alias_method :rss, :build_rss
|
198
|
+
|
199
|
+
|
200
|
+
# Atom 1.0 feeds.
|
201
|
+
|
202
|
+
def build_atom(objects, options = {})
|
203
|
+
|
204
|
+
# default options
|
205
|
+
options = {
|
206
|
+
:title => 'Syndication',
|
207
|
+
}.update(options)
|
208
|
+
|
209
|
+
raise "first param must be a collection of objects!" unless objects.respond_to?(:to_ary)
|
210
|
+
raise "your object(s) have to respond to :update_time, :create_time or :date" unless objects[0].respond_to?(:update_time) or objects[0].respond_to?(:create_time) or objects[0].respond_to?(:date)
|
211
|
+
raise "Option ':base' cannot be omitted!" unless options[:base]
|
212
|
+
|
213
|
+
# new XML Document for Atom
|
214
|
+
atom = REXML::Document.new
|
215
|
+
atom << REXML::XMLDecl.new("1.0", "utf-8")
|
216
|
+
|
217
|
+
# Root element <feed />
|
218
|
+
feed = REXML::Element.new("feed").add_namespace("http://www.w3.org/2005/Atom")
|
219
|
+
|
220
|
+
# Required feed elements
|
221
|
+
|
222
|
+
# id: Identifies the feed using a universally unique and permanent URI.
|
223
|
+
iduri = URI.parse(options[:id] || options[:base]).normalize.to_s
|
224
|
+
id = REXML::Element.new("id").add_text(iduri)
|
225
|
+
feed << id
|
226
|
+
|
227
|
+
# title: Contains a human readable title for the feed.
|
228
|
+
title = REXML::Element.new("title").add_text(options[:title])
|
229
|
+
feed << title
|
230
|
+
|
231
|
+
# updated: Indicates the last time the feed was modified in a significant way.
|
232
|
+
latest = Time.at(0) # a while back
|
233
|
+
objects.each do |o|
|
234
|
+
if o.respond_to?(:update_time)
|
235
|
+
latest = o.update_time if o.update_time > latest
|
236
|
+
elsif o.respond_to?(:create_time)
|
237
|
+
latest = o.create_time if o.create_time > latest
|
238
|
+
elsif o.respond_to?(:date)
|
239
|
+
latest = o.date if o.date > latest
|
240
|
+
end
|
241
|
+
end
|
242
|
+
updated = REXML::Element.new("updated").add_text(latest.iso8601)
|
243
|
+
feed << updated
|
244
|
+
|
245
|
+
# Recommended feed elements
|
246
|
+
|
247
|
+
# link: A feed should contain a link back to the feed itself.
|
248
|
+
if options[:link]
|
249
|
+
link = REXML::Element.new("link")
|
250
|
+
link.add_attributes({ "rel" => "self", "href" => options[:link] })
|
251
|
+
feed << link
|
252
|
+
end
|
253
|
+
|
254
|
+
# author: Names one author of the feed.
|
255
|
+
if options[:author_name] # name is required for author
|
256
|
+
author = REXML::Element.new("author")
|
257
|
+
author_name = REXML::Element.new("name").add_text(options[:author_name])
|
258
|
+
author << author_name
|
259
|
+
if options[:author_email]
|
260
|
+
author_email = REXML::Element.new("email").add_text(options[:author_email])
|
261
|
+
author << author_email
|
262
|
+
end
|
263
|
+
if options[:author_link]
|
264
|
+
author_link = REXML::Element.new("uri").add_text(options[:author_link])
|
265
|
+
author << author_link
|
266
|
+
end
|
267
|
+
feed << author
|
268
|
+
end
|
269
|
+
|
270
|
+
# Optional feed elements
|
271
|
+
|
272
|
+
# category:
|
273
|
+
# contributor:
|
274
|
+
# generator: Identifies the software used to generate the feed.
|
275
|
+
generator = REXML::Element.new("generator")
|
276
|
+
generator.add_attributes({ "uri" => "http://www.nitroproject.org", "version" => Nitro::Version })
|
277
|
+
generator.add_text("Nitro")
|
278
|
+
feed << generator
|
279
|
+
# icon
|
280
|
+
# logo
|
281
|
+
# rights
|
282
|
+
# subtitle
|
283
|
+
|
284
|
+
# Entries
|
285
|
+
objects.each do |o|
|
286
|
+
|
287
|
+
# new Entry (called "item" in RSS)
|
288
|
+
unless o.respond_to?(:to_href) and o.respond_to?(:title)
|
289
|
+
next
|
290
|
+
end
|
291
|
+
entry = REXML::Element.new("entry")
|
292
|
+
|
293
|
+
# Required entry elements
|
294
|
+
|
295
|
+
# id
|
296
|
+
if o.respond_to?(:to_href)
|
297
|
+
id = REXML::Element.new("id").add_text("#{options[:base]}/#{o.to_href}")
|
298
|
+
entry << id
|
299
|
+
end
|
300
|
+
|
301
|
+
# title
|
302
|
+
if o.respond_to?(:title)
|
303
|
+
title = REXML::Element.new("title").add_text(o.title)
|
304
|
+
entry << title
|
305
|
+
end
|
306
|
+
|
307
|
+
# updated
|
308
|
+
updated = Time.at(0) # a while back
|
309
|
+
if o.respond_to?(:update_time)
|
310
|
+
updated = o.update_time
|
311
|
+
elsif o.respond_to?(:create_time)
|
312
|
+
updated = o.create_time
|
313
|
+
elsif o.respond_to?(:date)
|
314
|
+
updated = o.date
|
315
|
+
end
|
316
|
+
entry << REXML::Element.new("updated").add_text(updated.iso8601)
|
317
|
+
|
318
|
+
# Recommended entry elements
|
319
|
+
|
320
|
+
# author
|
321
|
+
if o.respond_to?(:author)
|
322
|
+
if o.author[:name] # name is required for author
|
323
|
+
author = REXML::Element.new("author")
|
324
|
+
author_name = REXML::Element.new("name").add_text(o.author[:name])
|
325
|
+
author << author_name
|
326
|
+
if o.author[:email]
|
327
|
+
author_email = REXML::Element.new("email").add_text(o.author[:email])
|
328
|
+
author << author_email
|
329
|
+
end
|
330
|
+
if o.author[:link]
|
331
|
+
author_link = REXML::Element.new("uri").add_text(o.author[:link])
|
332
|
+
author << author_link
|
333
|
+
end
|
334
|
+
entry << author
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
# summary
|
339
|
+
if o.respond_to?(:body)
|
340
|
+
summary = REXML::Element.new("summary")
|
341
|
+
#TODO: think about whether 256 chars should be a fixed limit
|
342
|
+
summary.add_text(o.body.first_char(256).gsub(/<[^>]+>/, ' '))
|
343
|
+
entry << summary
|
344
|
+
end
|
345
|
+
|
346
|
+
# content
|
347
|
+
# may have the type text, html or xhtml
|
348
|
+
if o.respond_to?(:full_content)
|
349
|
+
content = REXML::Element.new("content")
|
350
|
+
#TODO: think about whether markup should always be done
|
351
|
+
content.add_text(markup(o.full_content))
|
352
|
+
entry << content
|
353
|
+
end
|
354
|
+
|
355
|
+
# link: An entry must contain an alternate link if there is no content element.
|
356
|
+
if o.respond_to?(:to_href)
|
357
|
+
link = REXML::Element.new("link")
|
358
|
+
link.add_attributes({ "rel" => "alternate", "href" => "#{options[:base]}/#{o.to_href}" })
|
359
|
+
entry << link
|
360
|
+
end
|
361
|
+
|
362
|
+
# Optional entry elements
|
363
|
+
|
364
|
+
# category
|
365
|
+
# could be used for Tags maybe?
|
366
|
+
# contributor
|
367
|
+
# published
|
368
|
+
if o.respond_to?(:create_time)
|
369
|
+
published = REXML::Element.new("published")
|
370
|
+
published.add_text(o.create_time.iso8601)
|
371
|
+
entry << published
|
372
|
+
end
|
373
|
+
# source
|
374
|
+
# rights
|
375
|
+
|
376
|
+
# don't forget to add the entry to the feed
|
377
|
+
feed << entry
|
378
|
+
|
379
|
+
end if objects.size > 0 # objects/entries
|
380
|
+
|
381
|
+
atom << feed
|
382
|
+
|
383
|
+
return atom.to_s
|
384
|
+
end # atom
|
385
|
+
alias_method :atom, :build_atom
|
386
|
+
|
387
|
+
# OPML 1.0 feed lists
|
388
|
+
# Fabian: eww, who invented OPML? Who needs it? Implementing
|
389
|
+
# it in a very rough way anyway though. Takes a Hash of
|
390
|
+
# Feeds and optional options.
|
391
|
+
|
392
|
+
def build_opml(feedhash, options = {})
|
393
|
+
|
394
|
+
# new XML Document for OPML
|
395
|
+
opml = REXML::Document.new
|
396
|
+
opml << REXML::XMLDecl.new("1.0", "utf-8")
|
397
|
+
|
398
|
+
# Root element <opml />
|
399
|
+
opml = REXML::Element.new("opml")
|
400
|
+
opml.add_attribute("version", "1.0")
|
401
|
+
|
402
|
+
# head
|
403
|
+
head = REXML::Element.new("head")
|
404
|
+
# title
|
405
|
+
if options[:title]
|
406
|
+
title = REXML::Element.new("title").add_text(options[:title])
|
407
|
+
head << title
|
408
|
+
end
|
409
|
+
# dateCreated
|
410
|
+
# dateModified
|
411
|
+
# ownerName
|
412
|
+
# ownerEmail
|
413
|
+
opml << head
|
414
|
+
|
415
|
+
# body
|
416
|
+
body = REXML::Element.new("body")
|
417
|
+
feedhash.each do |url, type|
|
418
|
+
outline = REXML::Element.new("outline")
|
419
|
+
outline.add_attributes({ "type" => type, "xmlUrl" => url })
|
420
|
+
body << outline
|
421
|
+
end
|
422
|
+
opml << body
|
423
|
+
|
424
|
+
return opml.to_s
|
425
|
+
end # opml
|
426
|
+
alias_method :opml, :build_opml
|
427
|
+
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
# * Fabian Buch <fabian@fabian-buch.de>
|
432
|
+
# * George Moschovitis <gm@navel.gr>
|
data/lib/nitro/helper/form.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'facet/inflect'
|
2
2
|
|
3
3
|
require 'nitro/helper/form/controls'
|
4
|
+
require 'nitro/helper/form/builder'
|
4
5
|
|
5
6
|
module Nitro
|
6
7
|
|
@@ -86,9 +87,13 @@ module FormHelper
|
|
86
87
|
end
|
87
88
|
end
|
88
89
|
|
89
|
-
|
90
|
+
if action == :self
|
91
|
+
str << %{<form method="post"#{enctype_attribute}>}
|
92
|
+
else
|
93
|
+
action = "#{@base}/#{action}" unless action =~ /\//
|
94
|
+
str << %{<form action="#{action}" method="post"#{enctype_attribute}>}
|
95
|
+
end
|
90
96
|
|
91
|
-
str << %{<form action="#{action}" method="post"#{enctype_attribute}>}
|
92
97
|
str << %{<input type="hidden" name="oid" value="#{obj.oid}" />} if obj.oid
|
93
98
|
str << controls_for(obj, options)
|
94
99
|
str << %{<input type="submit" value="#{submit}" />}
|
@@ -104,7 +109,10 @@ module FormHelper
|
|
104
109
|
str = FormBuilder.prologue
|
105
110
|
|
106
111
|
controls_for_properties(str, obj, options)
|
107
|
-
|
112
|
+
|
113
|
+
unless options[:no_relations]
|
114
|
+
controls_for_relations(str, obj, options)
|
115
|
+
end
|
108
116
|
|
109
117
|
str << FormBuilder.epilogue
|
110
118
|
|