raw 0.49.0
Sign up to get free protection for your applications and to get access to all the features.
- data/doc/CONTRIBUTORS +106 -0
- data/doc/LICENSE +32 -0
- data/doc/coding_conventions.txt +11 -0
- data/lib/raw.rb +42 -0
- data/lib/raw/adapter.rb +113 -0
- data/lib/raw/adapter/cgi.rb +41 -0
- data/lib/raw/adapter/fastcgi.rb +48 -0
- data/lib/raw/adapter/mongrel.rb +146 -0
- data/lib/raw/adapter/script.rb +94 -0
- data/lib/raw/adapter/webrick.rb +144 -0
- data/lib/raw/adapter/webrick/vcr.rb +91 -0
- data/lib/raw/cgi.rb +323 -0
- data/lib/raw/cgi/cookie.rb +47 -0
- data/lib/raw/cgi/http.rb +62 -0
- data/lib/raw/compiler.rb +138 -0
- data/lib/raw/compiler/filter/cleanup.rb +21 -0
- data/lib/raw/compiler/filter/elements.rb +166 -0
- data/lib/raw/compiler/filter/elements/element.rb +210 -0
- data/lib/raw/compiler/filter/localization.rb +23 -0
- data/lib/raw/compiler/filter/markup.rb +32 -0
- data/lib/raw/compiler/filter/morph.rb +123 -0
- data/lib/raw/compiler/filter/morph/each.rb +34 -0
- data/lib/raw/compiler/filter/morph/for.rb +11 -0
- data/lib/raw/compiler/filter/morph/if.rb +26 -0
- data/lib/raw/compiler/filter/morph/selected_if.rb +43 -0
- data/lib/raw/compiler/filter/morph/standard.rb +55 -0
- data/lib/raw/compiler/filter/morph/times.rb +27 -0
- data/lib/raw/compiler/filter/script.rb +116 -0
- data/lib/raw/compiler/filter/squeeze.rb +16 -0
- data/lib/raw/compiler/filter/static_include.rb +74 -0
- data/lib/raw/compiler/filter/template.rb +121 -0
- data/lib/raw/compiler/reloader.rb +96 -0
- data/lib/raw/context.rb +154 -0
- data/lib/raw/context/flash.rb +157 -0
- data/lib/raw/context/global.rb +88 -0
- data/lib/raw/context/request.rb +338 -0
- data/lib/raw/context/response.rb +57 -0
- data/lib/raw/context/session.rb +198 -0
- data/lib/raw/context/session/drb.rb +11 -0
- data/lib/raw/context/session/file.rb +15 -0
- data/lib/raw/context/session/memcached.rb +13 -0
- data/lib/raw/context/session/memory.rb +12 -0
- data/lib/raw/context/session/og.rb +15 -0
- data/lib/raw/context/session/pstore.rb +13 -0
- data/lib/raw/control.rb +18 -0
- data/lib/raw/control/attribute.rb +91 -0
- data/lib/raw/control/attribute/checkbox.rb +25 -0
- data/lib/raw/control/attribute/datetime.rb +21 -0
- data/lib/raw/control/attribute/file.rb +20 -0
- data/lib/raw/control/attribute/fixnum.rb +26 -0
- data/lib/raw/control/attribute/float.rb +26 -0
- data/lib/raw/control/attribute/options.rb +38 -0
- data/lib/raw/control/attribute/password.rb +16 -0
- data/lib/raw/control/attribute/text.rb +16 -0
- data/lib/raw/control/attribute/textarea.rb +16 -0
- data/lib/raw/control/none.rb +16 -0
- data/lib/raw/control/relation.rb +59 -0
- data/lib/raw/control/relation/belongs_to.rb +0 -0
- data/lib/raw/control/relation/has_many.rb +97 -0
- data/lib/raw/control/relation/joins_many.rb +0 -0
- data/lib/raw/control/relation/many_to_many.rb +0 -0
- data/lib/raw/control/relation/refers_to.rb +29 -0
- data/lib/raw/controller.rb +37 -0
- data/lib/raw/controller/publishable.rb +160 -0
- data/lib/raw/dispatcher.rb +209 -0
- data/lib/raw/dispatcher/format.rb +108 -0
- data/lib/raw/dispatcher/format/atom.rb +31 -0
- data/lib/raw/dispatcher/format/css.rb +0 -0
- data/lib/raw/dispatcher/format/html.rb +42 -0
- data/lib/raw/dispatcher/format/json.rb +31 -0
- data/lib/raw/dispatcher/format/rss.rb +33 -0
- data/lib/raw/dispatcher/format/xoxo.rb +31 -0
- data/lib/raw/dispatcher/mounter.rb +60 -0
- data/lib/raw/dispatcher/router.rb +111 -0
- data/lib/raw/errors.rb +19 -0
- data/lib/raw/helper.rb +86 -0
- data/lib/raw/helper/benchmark.rb +23 -0
- data/lib/raw/helper/buffer.rb +60 -0
- data/lib/raw/helper/cookie.rb +32 -0
- data/lib/raw/helper/debug.rb +28 -0
- data/lib/raw/helper/default.rb +16 -0
- data/lib/raw/helper/feed.rb +451 -0
- data/lib/raw/helper/form.rb +284 -0
- data/lib/raw/helper/javascript.rb +59 -0
- data/lib/raw/helper/layout.rb +40 -0
- data/lib/raw/helper/navigation.rb +87 -0
- data/lib/raw/helper/pager.rb +305 -0
- data/lib/raw/helper/table.rb +247 -0
- data/lib/raw/helper/xhtml.rb +218 -0
- data/lib/raw/helper/xml.rb +125 -0
- data/lib/raw/mixin/magick.rb +35 -0
- data/lib/raw/mixin/sweeper.rb +71 -0
- data/lib/raw/mixin/thumbnails.rb +1 -0
- data/lib/raw/mixin/webfile.rb +165 -0
- data/lib/raw/render.rb +271 -0
- data/lib/raw/render/builder.rb +26 -0
- data/lib/raw/render/caching.rb +81 -0
- data/lib/raw/render/call.rb +43 -0
- data/lib/raw/render/send_file.rb +46 -0
- data/lib/raw/render/stream.rb +39 -0
- data/lib/raw/scaffold.rb +13 -0
- data/lib/raw/scaffold/controller.rb +25 -0
- data/lib/raw/scaffold/model.rb +157 -0
- data/lib/raw/test.rb +5 -0
- data/lib/raw/test/assertions.rb +169 -0
- data/lib/raw/test/context.rb +55 -0
- data/lib/raw/test/testcase.rb +79 -0
- data/lib/raw/util/attr.rb +128 -0
- data/lib/raw/util/encode_uri.rb +149 -0
- data/lib/raw/util/html_filter.rb +538 -0
- data/lib/raw/util/markup.rb +130 -0
- data/test/glue/tc_webfile.rb +1 -0
- data/test/nitro/CONFIG.rb +3 -0
- data/test/nitro/adapter/raw_post1.bin +9 -0
- data/test/nitro/adapter/tc_webrick.rb +16 -0
- data/test/nitro/cgi/tc_cookie.rb +14 -0
- data/test/nitro/cgi/tc_request.rb +61 -0
- data/test/nitro/compiler/tc_client_morpher.rb +47 -0
- data/test/nitro/compiler/tc_compiler.rb +25 -0
- data/test/nitro/dispatcher/tc_mounter.rb +47 -0
- data/test/nitro/helper/tc_feed.rb +135 -0
- data/test/nitro/helper/tc_navbar.rb +74 -0
- data/test/nitro/helper/tc_pager.rb +35 -0
- data/test/nitro/helper/tc_table.rb +68 -0
- data/test/nitro/helper/tc_xhtml.rb +19 -0
- data/test/nitro/tc_caching.rb +19 -0
- data/test/nitro/tc_cgi.rb +222 -0
- data/test/nitro/tc_context.rb +17 -0
- data/test/nitro/tc_controller.rb +103 -0
- data/test/nitro/tc_controller_aspect.rb +32 -0
- data/test/nitro/tc_controller_params.rb +885 -0
- data/test/nitro/tc_dispatcher.rb +109 -0
- data/test/nitro/tc_element.rb +85 -0
- data/test/nitro/tc_flash.rb +59 -0
- data/test/nitro/tc_helper.rb +47 -0
- data/test/nitro/tc_render.rb +119 -0
- data/test/nitro/tc_router.rb +61 -0
- data/test/nitro/tc_server.rb +35 -0
- data/test/nitro/tc_session.rb +66 -0
- data/test/nitro/tc_template.rb +71 -0
- data/test/nitro/util/tc_encode_url.rb +87 -0
- data/test/nitro/util/tc_markup.rb +31 -0
- data/test/public/blog/another/very_litle/index.xhtml +1 -0
- data/test/public/blog/inc1.xhtml +2 -0
- data/test/public/blog/inc2.xhtml +1 -0
- data/test/public/blog/list.xhtml +9 -0
- data/test/public/dummy_mailer/registration.xhtml +5 -0
- metadata +244 -0
@@ -0,0 +1,284 @@
|
|
1
|
+
require "glue/builder/xml"
|
2
|
+
|
3
|
+
require 'raw/control'
|
4
|
+
require 'raw/control/none'
|
5
|
+
|
6
|
+
require 'raw/control/attribute/fixnum'
|
7
|
+
require 'raw/control/attribute/float'
|
8
|
+
require 'raw/control/attribute/text'
|
9
|
+
require 'raw/control/attribute/password'
|
10
|
+
require 'raw/control/attribute/textarea'
|
11
|
+
require 'raw/control/attribute/checkbox'
|
12
|
+
require 'raw/control/attribute/options'
|
13
|
+
require 'raw/control/attribute/file'
|
14
|
+
|
15
|
+
require 'raw/control/relation/refers_to'
|
16
|
+
require 'raw/control/relation/has_many'
|
17
|
+
|
18
|
+
module Raw
|
19
|
+
|
20
|
+
module FormHelper
|
21
|
+
|
22
|
+
# A specialized Builder for dynamically building of forms.
|
23
|
+
# Provides extra support for forms backed by managed objects
|
24
|
+
# (entities).
|
25
|
+
#--
|
26
|
+
# TODO: allow multiple objects per form.
|
27
|
+
# TODO: use more generalized controls.
|
28
|
+
#++
|
29
|
+
|
30
|
+
class FormXmlBuilder < ::Glue::XmlBuilder
|
31
|
+
|
32
|
+
# Mappings of control names to controls.
|
33
|
+
|
34
|
+
setting :control_map, :doc => 'Mappings of control names to controls', :default => {
|
35
|
+
:fixnum => FixnumControl,
|
36
|
+
:integer => FixnumControl,
|
37
|
+
:float => FloatControl,
|
38
|
+
:true_class => CheckboxControl,
|
39
|
+
:boolean => CheckboxControl,
|
40
|
+
:checkbox => CheckboxControl,
|
41
|
+
:string => TextControl,
|
42
|
+
:password => PasswordControl,
|
43
|
+
:textarea => TextareaControl,
|
44
|
+
:file => FileControl,
|
45
|
+
:webfile => FileControl,
|
46
|
+
=begin
|
47
|
+
:array => ArrayControl,
|
48
|
+
=end
|
49
|
+
:options => OptionsControl,
|
50
|
+
:refers_to => RefersToControl,
|
51
|
+
:has_one => RefersToControl,
|
52
|
+
:belongs_to => RefersToControl,
|
53
|
+
:has_many => HasManyControl,
|
54
|
+
:many_to_many => HasManyControl,
|
55
|
+
:joins_many => HasManyControl
|
56
|
+
}
|
57
|
+
|
58
|
+
# Returns a control for the given objects attribute.
|
59
|
+
|
60
|
+
def self.control_for(obj, a, anno, options)
|
61
|
+
raise "Invalid attribute '#{a}' for object '#{obj}'" if anno.nil?
|
62
|
+
name = anno[:control] || anno[:class].to_s.demodulize.underscore.to_sym
|
63
|
+
control_class = self.control_map.fetch(name, NoneControl)
|
64
|
+
return control_class.new(obj, a, options)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Returns a control for the given objects relation.
|
68
|
+
|
69
|
+
def self.control_for_relation(obj, rel, options)
|
70
|
+
name = rel[:control] || rel.class.to_s.demodulize.underscore.to_sym
|
71
|
+
control_class = self.control_map.fetch(name, NoneControl)
|
72
|
+
return control_class.new(obj, rel, options)
|
73
|
+
end
|
74
|
+
|
75
|
+
def initialize(buffer = '', options = {})
|
76
|
+
super
|
77
|
+
@obj = options[:object]
|
78
|
+
@errors = options[:errors]
|
79
|
+
end
|
80
|
+
|
81
|
+
# Render a control+label for the given property of the form
|
82
|
+
# object.
|
83
|
+
|
84
|
+
def attribute(a, options = {})
|
85
|
+
if anno = @obj.class.ann(a)
|
86
|
+
control = self.class.control_for(@obj, a, anno, options)
|
87
|
+
print element(a, anno, control.render)
|
88
|
+
else
|
89
|
+
raise "Undefined attribute '#{a}' for class '#{@obj.class}'."
|
90
|
+
end
|
91
|
+
end
|
92
|
+
alias_method :attr, :attribute
|
93
|
+
|
94
|
+
# Render controls for all attributes of the form object.
|
95
|
+
# It only considers serializable attributes.
|
96
|
+
|
97
|
+
def all_attributes(options = {})
|
98
|
+
for a in @obj.class.serializable_attributes
|
99
|
+
prop = @obj.class.ann(a)
|
100
|
+
unless options[:all]
|
101
|
+
next if a == @obj.class.primary_key or prop[:control] == :none or prop[:relation] or [options[:exclude]].flatten.include?(a)
|
102
|
+
end
|
103
|
+
attribute a, options
|
104
|
+
end
|
105
|
+
end
|
106
|
+
alias_method :attributes, :all_attributes
|
107
|
+
alias_method :serializable_attributes, :all_attributes
|
108
|
+
|
109
|
+
# === Input
|
110
|
+
#
|
111
|
+
# * rel = The relation name as symbol, or the actual
|
112
|
+
# relation object.
|
113
|
+
#--
|
114
|
+
# FIXME: Fix the mismatch with the attributes.
|
115
|
+
#++
|
116
|
+
|
117
|
+
def relation(rel, options = {})
|
118
|
+
# If the relation name is passed, lookup the actual
|
119
|
+
# relation.
|
120
|
+
|
121
|
+
if rel.is_a? Symbol
|
122
|
+
rel = @obj.class.relation(rel)
|
123
|
+
end
|
124
|
+
|
125
|
+
control = self.class.control_for_relation(@obj, rel, options)
|
126
|
+
print element(rel[:symbol], rel, control.render)
|
127
|
+
end
|
128
|
+
alias_method :rel, :relation
|
129
|
+
|
130
|
+
# Render controls for all relations of the form object.
|
131
|
+
|
132
|
+
def all_relations(options = {})
|
133
|
+
for rel in @obj.class.relations
|
134
|
+
unless options[:all]
|
135
|
+
# Ignore polymorphic_marker relations.
|
136
|
+
#--
|
137
|
+
# gmosx: should revisit the handling of polymorphic
|
138
|
+
# relations, feels hacky.
|
139
|
+
#++
|
140
|
+
next if (rel[:control] == :none) or rel.polymorphic_marker?
|
141
|
+
end
|
142
|
+
relation rel, options
|
143
|
+
end
|
144
|
+
end
|
145
|
+
alias_method :relations, :all_relations
|
146
|
+
|
147
|
+
# Renders a control to select a file for upload.
|
148
|
+
|
149
|
+
def select_file(name, options = {})
|
150
|
+
print %|<input type="file" name="#{name}" />|
|
151
|
+
end
|
152
|
+
|
153
|
+
# If flash[:ERRORS] is filled with errors structured as
|
154
|
+
# name/message pairs the method creates a div containing them,
|
155
|
+
# otherwise it returns an empty string.
|
156
|
+
#
|
157
|
+
# So you can write code like
|
158
|
+
# #{form_errors}
|
159
|
+
# <form>... </form>
|
160
|
+
#
|
161
|
+
# and redirect the user to the form in case of errors, thus
|
162
|
+
# allowing him to see what was wrong.
|
163
|
+
|
164
|
+
def form_errors
|
165
|
+
res = ''
|
166
|
+
|
167
|
+
unless @errors.empty?
|
168
|
+
res << %{<div class="error">\n<ul>\n}
|
169
|
+
for err in @errors
|
170
|
+
if err.is_a? Array
|
171
|
+
res << "<li><strong>#{err[0].to_s.humanize}</strong>: #{err[1]}</li>\n"
|
172
|
+
else
|
173
|
+
res << "<li>#{err}</li>\n"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
res << %{</ul>\n</div>\n}
|
177
|
+
end
|
178
|
+
|
179
|
+
print(res)
|
180
|
+
end
|
181
|
+
|
182
|
+
private
|
183
|
+
|
184
|
+
# Emit a form element. Override this method to customize the
|
185
|
+
# rendering for your application needs.
|
186
|
+
|
187
|
+
def element(a, anno, html)
|
188
|
+
# TODO: give better form id!
|
189
|
+
%{
|
190
|
+
<p id="form_#{a}">
|
191
|
+
#{html}
|
192
|
+
</p>
|
193
|
+
}
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
197
|
+
|
198
|
+
private
|
199
|
+
|
200
|
+
# A sophisticated form generation helper method.
|
201
|
+
# If no block is provided, render all attributes.
|
202
|
+
#
|
203
|
+
# === Options
|
204
|
+
#
|
205
|
+
# * :object, :entity, :class = The object that acts as model
|
206
|
+
# for this form. If you pass a class an empty object is
|
207
|
+
# instantiated.
|
208
|
+
#
|
209
|
+
# * :action = The action of this form. The parameter is
|
210
|
+
# passed through the R operator (encode_uri) to support
|
211
|
+
# advanced uri transformation.
|
212
|
+
#
|
213
|
+
# * :errors = An optional collection of errors.
|
214
|
+
#
|
215
|
+
# === Example
|
216
|
+
#
|
217
|
+
# #{form(:object => @owner, :action => :save_profile) do |f|
|
218
|
+
# f.property :name, :editable => false
|
219
|
+
# f.property :password
|
220
|
+
# f.br
|
221
|
+
# f.submit 'Update'
|
222
|
+
# end}
|
223
|
+
|
224
|
+
def form(options = {}, &block)
|
225
|
+
obj = (options[:object] ||= options[:entity] || options[:class])
|
226
|
+
|
227
|
+
# If the passed obj is a Class instantiate an empty object
|
228
|
+
# of this class.
|
229
|
+
|
230
|
+
if obj.is_a? Class
|
231
|
+
obj = options[:object] = obj.allocate
|
232
|
+
end
|
233
|
+
|
234
|
+
# Convert virtual :multipart method to method="post",
|
235
|
+
# enctype="multipart/form-data"
|
236
|
+
|
237
|
+
if options[:method] == :multipart
|
238
|
+
options[:method] = 'POST'
|
239
|
+
options[:enctype] = 'multipart/form-data'
|
240
|
+
end
|
241
|
+
|
242
|
+
options[:errors] ||= []
|
243
|
+
|
244
|
+
if errors = flash[:ERRORS]
|
245
|
+
if errors.is_a? Array
|
246
|
+
options[:errors].concat(errors)
|
247
|
+
elsif errors.is_a? Glue::Validation::Errors
|
248
|
+
options[:errors].concat(errors.to_a)
|
249
|
+
else
|
250
|
+
options[:errors] << errors
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
if obj and errors = obj.errors
|
255
|
+
options[:errors].concat(errors.to_a)
|
256
|
+
end
|
257
|
+
|
258
|
+
b = FormXmlBuilder.new('', options)
|
259
|
+
|
260
|
+
b << '<form'
|
261
|
+
b << %| action="#{R options[:action]}"| if options[:action]
|
262
|
+
b << %| method="#{options[:method]}"| if options[:method]
|
263
|
+
b << %| accept-charset="#{options[:charset]}"| if options[:charset]
|
264
|
+
b << %| enctype="#{options[:enctype]}"| if options[:enctype]
|
265
|
+
b << '>'
|
266
|
+
|
267
|
+
b.hidden(:oid, obj.oid) if obj and obj.saved?
|
268
|
+
|
269
|
+
# If no block is provided, render all attributes.
|
270
|
+
|
271
|
+
if block_given?
|
272
|
+
yield b
|
273
|
+
else
|
274
|
+
b.all_attributes
|
275
|
+
end
|
276
|
+
|
277
|
+
b << '</form>'
|
278
|
+
|
279
|
+
return b
|
280
|
+
end
|
281
|
+
|
282
|
+
end
|
283
|
+
|
284
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require "facets/core/inflect"
|
2
|
+
|
3
|
+
module Raw
|
4
|
+
|
5
|
+
# Javascript code manager.
|
6
|
+
#--
|
7
|
+
# TODO: Add support for synthesizing compound Javascript files from
|
8
|
+
# multiple smaller files.
|
9
|
+
#++
|
10
|
+
|
11
|
+
module Javascript
|
12
|
+
|
13
|
+
# The javascript files to auto include.
|
14
|
+
|
15
|
+
setting :required_files, :default => [], :doc => "The javascript files to auto include"
|
16
|
+
|
17
|
+
# The root directory where javascript files reside.
|
18
|
+
|
19
|
+
setting :root_dir, :default => "public/js", :doc => "The root directory where javascript files reside"
|
20
|
+
|
21
|
+
def self.require(path)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
# Javascript utilities.
|
27
|
+
|
28
|
+
module JavascriptUtils
|
29
|
+
|
30
|
+
private
|
31
|
+
# Escape carrier returns and single and double quotes for JavaScript segments.
|
32
|
+
|
33
|
+
def escape_javascript(js)
|
34
|
+
(js || '').gsub(/\r\n|\n|\r/, "\\n").gsub(/["']/) { |m| "\\#{m}" }
|
35
|
+
end
|
36
|
+
alias_method :escape, :escape_javascript
|
37
|
+
|
38
|
+
# Converts a Ruby hash to a Javascript hash.
|
39
|
+
|
40
|
+
def hash_to_js(options)
|
41
|
+
'{' + options.map {|k, v| "#{k}:#{v}"}.join(', ') + '}'
|
42
|
+
end
|
43
|
+
|
44
|
+
# Converts the name of a javascript file to the actual
|
45
|
+
# filename. Override if you don't like the defaults.
|
46
|
+
|
47
|
+
def name_to_jsfile(name)
|
48
|
+
"/js/#{name}.js"
|
49
|
+
end
|
50
|
+
|
51
|
+
# Generate javascript confirm code for links.
|
52
|
+
|
53
|
+
def confirm(text = 'Are you sure?')
|
54
|
+
%|onclick="return confirm('#{text}')"|
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require "facets/core/inflect"
|
2
|
+
|
3
|
+
require "raw/element"
|
4
|
+
|
5
|
+
module Raw
|
6
|
+
|
7
|
+
# This helper uses Nitro's powerfull Elements mechanism to
|
8
|
+
# implement a simple Rails style Layout helper. Perhaps this
|
9
|
+
# may be useful for people coming over from Rails.
|
10
|
+
#
|
11
|
+
# WARNING: This is not enabled by default. You have to insert
|
12
|
+
# the LayoutCompiler before the ElementsCompiler for layout to
|
13
|
+
# work.
|
14
|
+
|
15
|
+
module LayoutHelper
|
16
|
+
|
17
|
+
def self.included(base)
|
18
|
+
base.module_eval do
|
19
|
+
# Enclose all templates of this controller with the
|
20
|
+
# given element.
|
21
|
+
|
22
|
+
def self.layout(name = nil)
|
23
|
+
klass = name.to_s.camelize
|
24
|
+
|
25
|
+
unless klass
|
26
|
+
if defined? 'Nitro::Element::Layout'
|
27
|
+
klass = Nitro::Element::Layout
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
if klass
|
32
|
+
ann :self, :layout => klass
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Raw
|
2
|
+
|
3
|
+
# A helper mixin for programmatically building Navigation Menus
|
4
|
+
# through easy to style XHTML.
|
5
|
+
# The code resulting from these methods is in line with that found in most examples at
|
6
|
+
# listamatic, thus you can use prebuilt CSS and Javascript to create horizontal or vertical menus.
|
7
|
+
# Basically it generates something like
|
8
|
+
# <div id="navcontainer">
|
9
|
+
# <ul id="navlist">
|
10
|
+
# <li id="active"> <a href="/foo" id="current"> Current Page </a></li>
|
11
|
+
# <li> <a href="/bar"> Other page </a> </li>
|
12
|
+
# </ul>
|
13
|
+
# </div>
|
14
|
+
#
|
15
|
+
# This helper takes care of setting of putting the special CSS
|
16
|
+
# identifiers for the current controller automatically.
|
17
|
+
# You could override menuitem_active_on(path)
|
18
|
+
# to change the behaviour that choose the active item,
|
19
|
+
# for example to keep the item "Wiki" active both for
|
20
|
+
# /wiki/pageone and /wiki/pagetwo
|
21
|
+
#
|
22
|
+
# Example of horizontal bar at listamatic:
|
23
|
+
# http://css.maxdesign.com.au/listamatic/horizontal26.htm
|
24
|
+
# Vertical example
|
25
|
+
# http://css.maxdesign.com.au/listamatic/vertical09.htm
|
26
|
+
#
|
27
|
+
# NOTE: No tests were made with Publishable objects which are not
|
28
|
+
# subclass of Nitro::Controller, but it _should_ work.
|
29
|
+
|
30
|
+
module NavigationHelper
|
31
|
+
|
32
|
+
TEMPLATE=<<Eof
|
33
|
+
<div id="navcontainer">
|
34
|
+
<ul id="navlist">
|
35
|
+
LIST
|
36
|
+
</ul>
|
37
|
+
</div>
|
38
|
+
Eof
|
39
|
+
|
40
|
+
# Takes a list of controllers and builds a menu
|
41
|
+
# using #mount_path as the uri and the controller name as text.
|
42
|
+
# An eventual "Controller" suffix will be stripped, so i.e. for controllers
|
43
|
+
# named +HomeController+, +Pages+, +FeedCtl+ it will use
|
44
|
+
# +Home+, +Page+, +FeedCtl+.
|
45
|
+
#
|
46
|
+
# For more finegrained control you can pass a block to this function, each
|
47
|
+
# controller will be passed to it and the result will be used as the text
|
48
|
+
# for the menu item.
|
49
|
+
#
|
50
|
+
#
|
51
|
+
# Otherwise you can specify pairs of path/text using #navigation_for_hash
|
52
|
+
|
53
|
+
def menu_for(*controllers) #:yields:
|
54
|
+
hash= {}
|
55
|
+
controllers.each do |c|
|
56
|
+
hash[c.mount_path] = block_given? ? yield(c) : c.name.gsub(/Controller/,'')
|
57
|
+
end
|
58
|
+
menu_from_hash(hash)
|
59
|
+
end
|
60
|
+
|
61
|
+
# The argument must be an hash of pairs {'path'=>'text for menu item'},
|
62
|
+
# no control will be applied on these values, they will be used directly.
|
63
|
+
# You can use the method like
|
64
|
+
# navigation_for_hash '/foo/bar'=>'Page One', '/foo/baz'=>'Page Two'
|
65
|
+
#
|
66
|
+
# The method takes care of setting the CSS values as expected.
|
67
|
+
#
|
68
|
+
# To avoid specifying everything the method #navigation_menu can be used.
|
69
|
+
|
70
|
+
def menu_from_hash(hash)
|
71
|
+
list=hash.map do |path,name|
|
72
|
+
if menuitem_active_on?(path)
|
73
|
+
%{<li id="active"><a href="#{path}" id="current"> #{name} </a></li>}
|
74
|
+
else
|
75
|
+
%{<li><a href="#{path}"> #{name} </a></li>}
|
76
|
+
end
|
77
|
+
end.join("\n")
|
78
|
+
TEMPLATE.gsub("LIST",list)
|
79
|
+
end
|
80
|
+
|
81
|
+
def menuitem_active_on?(path)
|
82
|
+
path == request.path
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|