##// END OF EJS Templates
Use controller instead of instance variable....
Jean-Philippe Lang -
r7776:a756103b10ec
parent child
Show More
@@ -1,449 +1,449
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require 'tree' # gem install rubytree
18 require 'tree' # gem install rubytree
19
19
20 # Monkey patch the TreeNode to add on a few more methods :nodoc:
20 # Monkey patch the TreeNode to add on a few more methods :nodoc:
21 module TreeNodePatch
21 module TreeNodePatch
22 def self.included(base)
22 def self.included(base)
23 base.class_eval do
23 base.class_eval do
24 attr_reader :last_items_count
24 attr_reader :last_items_count
25
25
26 alias :old_initilize :initialize
26 alias :old_initilize :initialize
27 def initialize(name, content = nil)
27 def initialize(name, content = nil)
28 old_initilize(name, content)
28 old_initilize(name, content)
29 @childrenHash ||= {}
29 @childrenHash ||= {}
30 @last_items_count = 0
30 @last_items_count = 0
31 extend(InstanceMethods)
31 extend(InstanceMethods)
32 end
32 end
33 end
33 end
34 end
34 end
35
35
36 module InstanceMethods
36 module InstanceMethods
37 # Adds the specified child node to the receiver node. The child node's
37 # Adds the specified child node to the receiver node. The child node's
38 # parent is set to be the receiver. The child is added as the first child in
38 # parent is set to be the receiver. The child is added as the first child in
39 # the current list of children for the receiver node.
39 # the current list of children for the receiver node.
40 def prepend(child)
40 def prepend(child)
41 raise "Child already added" if @childrenHash.has_key?(child.name)
41 raise "Child already added" if @childrenHash.has_key?(child.name)
42
42
43 @childrenHash[child.name] = child
43 @childrenHash[child.name] = child
44 @children = [child] + @children
44 @children = [child] + @children
45 child.parent = self
45 child.parent = self
46 return child
46 return child
47
47
48 end
48 end
49
49
50 # Adds the specified child node to the receiver node. The child node's
50 # Adds the specified child node to the receiver node. The child node's
51 # parent is set to be the receiver. The child is added at the position
51 # parent is set to be the receiver. The child is added at the position
52 # into the current list of children for the receiver node.
52 # into the current list of children for the receiver node.
53 def add_at(child, position)
53 def add_at(child, position)
54 raise "Child already added" if @childrenHash.has_key?(child.name)
54 raise "Child already added" if @childrenHash.has_key?(child.name)
55
55
56 @childrenHash[child.name] = child
56 @childrenHash[child.name] = child
57 @children = @children.insert(position, child)
57 @children = @children.insert(position, child)
58 child.parent = self
58 child.parent = self
59 return child
59 return child
60
60
61 end
61 end
62
62
63 def add_last(child)
63 def add_last(child)
64 raise "Child already added" if @childrenHash.has_key?(child.name)
64 raise "Child already added" if @childrenHash.has_key?(child.name)
65
65
66 @childrenHash[child.name] = child
66 @childrenHash[child.name] = child
67 @children << child
67 @children << child
68 @last_items_count += 1
68 @last_items_count += 1
69 child.parent = self
69 child.parent = self
70 return child
70 return child
71
71
72 end
72 end
73
73
74 # Adds the specified child node to the receiver node. The child node's
74 # Adds the specified child node to the receiver node. The child node's
75 # parent is set to be the receiver. The child is added as the last child in
75 # parent is set to be the receiver. The child is added as the last child in
76 # the current list of children for the receiver node.
76 # the current list of children for the receiver node.
77 def add(child)
77 def add(child)
78 raise "Child already added" if @childrenHash.has_key?(child.name)
78 raise "Child already added" if @childrenHash.has_key?(child.name)
79
79
80 @childrenHash[child.name] = child
80 @childrenHash[child.name] = child
81 position = @children.size - @last_items_count
81 position = @children.size - @last_items_count
82 @children.insert(position, child)
82 @children.insert(position, child)
83 child.parent = self
83 child.parent = self
84 return child
84 return child
85
85
86 end
86 end
87
87
88 # Wrapp remove! making sure to decrement the last_items counter if
88 # Wrapp remove! making sure to decrement the last_items counter if
89 # the removed child was a last item
89 # the removed child was a last item
90 def remove!(child)
90 def remove!(child)
91 @last_items_count -= +1 if child && child.last
91 @last_items_count -= +1 if child && child.last
92 super
92 super
93 end
93 end
94
94
95
95
96 # Will return the position (zero-based) of the current child in
96 # Will return the position (zero-based) of the current child in
97 # it's parent
97 # it's parent
98 def position
98 def position
99 self.parent.children.index(self)
99 self.parent.children.index(self)
100 end
100 end
101 end
101 end
102 end
102 end
103 Tree::TreeNode.send(:include, TreeNodePatch)
103 Tree::TreeNode.send(:include, TreeNodePatch)
104
104
105 module Redmine
105 module Redmine
106 module MenuManager
106 module MenuManager
107 class MenuError < StandardError #:nodoc:
107 class MenuError < StandardError #:nodoc:
108 end
108 end
109
109
110 module MenuController
110 module MenuController
111 def self.included(base)
111 def self.included(base)
112 base.extend(ClassMethods)
112 base.extend(ClassMethods)
113 end
113 end
114
114
115 module ClassMethods
115 module ClassMethods
116 @@menu_items = Hash.new {|hash, key| hash[key] = {:default => key, :actions => {}}}
116 @@menu_items = Hash.new {|hash, key| hash[key] = {:default => key, :actions => {}}}
117 mattr_accessor :menu_items
117 mattr_accessor :menu_items
118
118
119 # Set the menu item name for a controller or specific actions
119 # Set the menu item name for a controller or specific actions
120 # Examples:
120 # Examples:
121 # * menu_item :tickets # => sets the menu name to :tickets for the whole controller
121 # * menu_item :tickets # => sets the menu name to :tickets for the whole controller
122 # * menu_item :tickets, :only => :list # => sets the menu name to :tickets for the 'list' action only
122 # * menu_item :tickets, :only => :list # => sets the menu name to :tickets for the 'list' action only
123 # * menu_item :tickets, :only => [:list, :show] # => sets the menu name to :tickets for 2 actions only
123 # * menu_item :tickets, :only => [:list, :show] # => sets the menu name to :tickets for 2 actions only
124 #
124 #
125 # The default menu item name for a controller is controller_name by default
125 # The default menu item name for a controller is controller_name by default
126 # Eg. the default menu item name for ProjectsController is :projects
126 # Eg. the default menu item name for ProjectsController is :projects
127 def menu_item(id, options = {})
127 def menu_item(id, options = {})
128 if actions = options[:only]
128 if actions = options[:only]
129 actions = [] << actions unless actions.is_a?(Array)
129 actions = [] << actions unless actions.is_a?(Array)
130 actions.each {|a| menu_items[controller_name.to_sym][:actions][a.to_sym] = id}
130 actions.each {|a| menu_items[controller_name.to_sym][:actions][a.to_sym] = id}
131 else
131 else
132 menu_items[controller_name.to_sym][:default] = id
132 menu_items[controller_name.to_sym][:default] = id
133 end
133 end
134 end
134 end
135 end
135 end
136
136
137 def menu_items
137 def menu_items
138 self.class.menu_items
138 self.class.menu_items
139 end
139 end
140
140
141 # Returns the menu item name according to the current action
141 # Returns the menu item name according to the current action
142 def current_menu_item
142 def current_menu_item
143 @current_menu_item ||= menu_items[controller_name.to_sym][:actions][action_name.to_sym] ||
143 @current_menu_item ||= menu_items[controller_name.to_sym][:actions][action_name.to_sym] ||
144 menu_items[controller_name.to_sym][:default]
144 menu_items[controller_name.to_sym][:default]
145 end
145 end
146
146
147 # Redirects user to the menu item of the given project
147 # Redirects user to the menu item of the given project
148 # Returns false if user is not authorized
148 # Returns false if user is not authorized
149 def redirect_to_project_menu_item(project, name)
149 def redirect_to_project_menu_item(project, name)
150 item = Redmine::MenuManager.items(:project_menu).detect {|i| i.name.to_s == name.to_s}
150 item = Redmine::MenuManager.items(:project_menu).detect {|i| i.name.to_s == name.to_s}
151 if item && User.current.allowed_to?(item.url, project) && (item.condition.nil? || item.condition.call(project))
151 if item && User.current.allowed_to?(item.url, project) && (item.condition.nil? || item.condition.call(project))
152 redirect_to({item.param => project}.merge(item.url))
152 redirect_to({item.param => project}.merge(item.url))
153 return true
153 return true
154 end
154 end
155 false
155 false
156 end
156 end
157 end
157 end
158
158
159 module MenuHelper
159 module MenuHelper
160 # Returns the current menu item name
160 # Returns the current menu item name
161 def current_menu_item
161 def current_menu_item
162 @controller.current_menu_item
162 controller.current_menu_item
163 end
163 end
164
164
165 # Renders the application main menu
165 # Renders the application main menu
166 def render_main_menu(project)
166 def render_main_menu(project)
167 render_menu((project && !project.new_record?) ? :project_menu : :application_menu, project)
167 render_menu((project && !project.new_record?) ? :project_menu : :application_menu, project)
168 end
168 end
169
169
170 def display_main_menu?(project)
170 def display_main_menu?(project)
171 menu_name = project && !project.new_record? ? :project_menu : :application_menu
171 menu_name = project && !project.new_record? ? :project_menu : :application_menu
172 Redmine::MenuManager.items(menu_name).size > 1 # 1 element is the root
172 Redmine::MenuManager.items(menu_name).size > 1 # 1 element is the root
173 end
173 end
174
174
175 def render_menu(menu, project=nil)
175 def render_menu(menu, project=nil)
176 links = []
176 links = []
177 menu_items_for(menu, project) do |node|
177 menu_items_for(menu, project) do |node|
178 links << render_menu_node(node, project)
178 links << render_menu_node(node, project)
179 end
179 end
180 links.empty? ? nil : content_tag('ul', links.join("\n").html_safe)
180 links.empty? ? nil : content_tag('ul', links.join("\n").html_safe)
181 end
181 end
182
182
183 def render_menu_node(node, project=nil)
183 def render_menu_node(node, project=nil)
184 if node.hasChildren? || !node.child_menus.nil?
184 if node.hasChildren? || !node.child_menus.nil?
185 return render_menu_node_with_children(node, project)
185 return render_menu_node_with_children(node, project)
186 else
186 else
187 caption, url, selected = extract_node_details(node, project)
187 caption, url, selected = extract_node_details(node, project)
188 return content_tag('li',
188 return content_tag('li',
189 render_single_menu_node(node, caption, url, selected))
189 render_single_menu_node(node, caption, url, selected))
190 end
190 end
191 end
191 end
192
192
193 def render_menu_node_with_children(node, project=nil)
193 def render_menu_node_with_children(node, project=nil)
194 caption, url, selected = extract_node_details(node, project)
194 caption, url, selected = extract_node_details(node, project)
195
195
196 html = [].tap do |html|
196 html = [].tap do |html|
197 html << '<li>'
197 html << '<li>'
198 # Parent
198 # Parent
199 html << render_single_menu_node(node, caption, url, selected)
199 html << render_single_menu_node(node, caption, url, selected)
200
200
201 # Standard children
201 # Standard children
202 standard_children_list = "".tap do |child_html|
202 standard_children_list = "".tap do |child_html|
203 node.children.each do |child|
203 node.children.each do |child|
204 child_html << render_menu_node(child, project)
204 child_html << render_menu_node(child, project)
205 end
205 end
206 end
206 end
207
207
208 html << content_tag(:ul, standard_children_list, :class => 'menu-children') unless standard_children_list.empty?
208 html << content_tag(:ul, standard_children_list, :class => 'menu-children') unless standard_children_list.empty?
209
209
210 # Unattached children
210 # Unattached children
211 unattached_children_list = render_unattached_children_menu(node, project)
211 unattached_children_list = render_unattached_children_menu(node, project)
212 html << content_tag(:ul, unattached_children_list, :class => 'menu-children unattached') unless unattached_children_list.blank?
212 html << content_tag(:ul, unattached_children_list, :class => 'menu-children unattached') unless unattached_children_list.blank?
213
213
214 html << '</li>'
214 html << '</li>'
215 end
215 end
216 return html.join("\n")
216 return html.join("\n")
217 end
217 end
218
218
219 # Returns a list of unattached children menu items
219 # Returns a list of unattached children menu items
220 def render_unattached_children_menu(node, project)
220 def render_unattached_children_menu(node, project)
221 return nil unless node.child_menus
221 return nil unless node.child_menus
222
222
223 "".tap do |child_html|
223 "".tap do |child_html|
224 unattached_children = node.child_menus.call(project)
224 unattached_children = node.child_menus.call(project)
225 # Tree nodes support #each so we need to do object detection
225 # Tree nodes support #each so we need to do object detection
226 if unattached_children.is_a? Array
226 if unattached_children.is_a? Array
227 unattached_children.each do |child|
227 unattached_children.each do |child|
228 child_html << content_tag(:li, render_unattached_menu_item(child, project))
228 child_html << content_tag(:li, render_unattached_menu_item(child, project))
229 end
229 end
230 else
230 else
231 raise MenuError, ":child_menus must be an array of MenuItems"
231 raise MenuError, ":child_menus must be an array of MenuItems"
232 end
232 end
233 end
233 end
234 end
234 end
235
235
236 def render_single_menu_node(item, caption, url, selected)
236 def render_single_menu_node(item, caption, url, selected)
237 link_to(h(caption), url, item.html_options(:selected => selected))
237 link_to(h(caption), url, item.html_options(:selected => selected))
238 end
238 end
239
239
240 def render_unattached_menu_item(menu_item, project)
240 def render_unattached_menu_item(menu_item, project)
241 raise MenuError, ":child_menus must be an array of MenuItems" unless menu_item.is_a? MenuItem
241 raise MenuError, ":child_menus must be an array of MenuItems" unless menu_item.is_a? MenuItem
242
242
243 if User.current.allowed_to?(menu_item.url, project)
243 if User.current.allowed_to?(menu_item.url, project)
244 link_to(h(menu_item.caption),
244 link_to(h(menu_item.caption),
245 menu_item.url,
245 menu_item.url,
246 menu_item.html_options)
246 menu_item.html_options)
247 end
247 end
248 end
248 end
249
249
250 def menu_items_for(menu, project=nil)
250 def menu_items_for(menu, project=nil)
251 items = []
251 items = []
252 Redmine::MenuManager.items(menu).root.children.each do |node|
252 Redmine::MenuManager.items(menu).root.children.each do |node|
253 if allowed_node?(node, User.current, project)
253 if allowed_node?(node, User.current, project)
254 if block_given?
254 if block_given?
255 yield node
255 yield node
256 else
256 else
257 items << node # TODO: not used?
257 items << node # TODO: not used?
258 end
258 end
259 end
259 end
260 end
260 end
261 return block_given? ? nil : items
261 return block_given? ? nil : items
262 end
262 end
263
263
264 def extract_node_details(node, project=nil)
264 def extract_node_details(node, project=nil)
265 item = node
265 item = node
266 url = case item.url
266 url = case item.url
267 when Hash
267 when Hash
268 project.nil? ? item.url : {item.param => project}.merge(item.url)
268 project.nil? ? item.url : {item.param => project}.merge(item.url)
269 when Symbol
269 when Symbol
270 send(item.url)
270 send(item.url)
271 else
271 else
272 item.url
272 item.url
273 end
273 end
274 caption = item.caption(project)
274 caption = item.caption(project)
275 return [caption, url, (current_menu_item == item.name)]
275 return [caption, url, (current_menu_item == item.name)]
276 end
276 end
277
277
278 # Checks if a user is allowed to access the menu item by:
278 # Checks if a user is allowed to access the menu item by:
279 #
279 #
280 # * Checking the conditions of the item
280 # * Checking the conditions of the item
281 # * Checking the url target (project only)
281 # * Checking the url target (project only)
282 def allowed_node?(node, user, project)
282 def allowed_node?(node, user, project)
283 if node.condition && !node.condition.call(project)
283 if node.condition && !node.condition.call(project)
284 # Condition that doesn't pass
284 # Condition that doesn't pass
285 return false
285 return false
286 end
286 end
287
287
288 if project
288 if project
289 return user && user.allowed_to?(node.url, project)
289 return user && user.allowed_to?(node.url, project)
290 else
290 else
291 # outside a project, all menu items allowed
291 # outside a project, all menu items allowed
292 return true
292 return true
293 end
293 end
294 end
294 end
295 end
295 end
296
296
297 class << self
297 class << self
298 def map(menu_name)
298 def map(menu_name)
299 @items ||= {}
299 @items ||= {}
300 mapper = Mapper.new(menu_name.to_sym, @items)
300 mapper = Mapper.new(menu_name.to_sym, @items)
301 if block_given?
301 if block_given?
302 yield mapper
302 yield mapper
303 else
303 else
304 mapper
304 mapper
305 end
305 end
306 end
306 end
307
307
308 def items(menu_name)
308 def items(menu_name)
309 @items[menu_name.to_sym] || Tree::TreeNode.new(:root, {})
309 @items[menu_name.to_sym] || Tree::TreeNode.new(:root, {})
310 end
310 end
311 end
311 end
312
312
313 class Mapper
313 class Mapper
314 def initialize(menu, items)
314 def initialize(menu, items)
315 items[menu] ||= Tree::TreeNode.new(:root, {})
315 items[menu] ||= Tree::TreeNode.new(:root, {})
316 @menu = menu
316 @menu = menu
317 @menu_items = items[menu]
317 @menu_items = items[menu]
318 end
318 end
319
319
320 @@last_items_count = Hash.new {|h,k| h[k] = 0}
320 @@last_items_count = Hash.new {|h,k| h[k] = 0}
321
321
322 # Adds an item at the end of the menu. Available options:
322 # Adds an item at the end of the menu. Available options:
323 # * param: the parameter name that is used for the project id (default is :id)
323 # * param: the parameter name that is used for the project id (default is :id)
324 # * if: a Proc that is called before rendering the item, the item is displayed only if it returns true
324 # * if: a Proc that is called before rendering the item, the item is displayed only if it returns true
325 # * caption that can be:
325 # * caption that can be:
326 # * a localized string Symbol
326 # * a localized string Symbol
327 # * a String
327 # * a String
328 # * a Proc that can take the project as argument
328 # * a Proc that can take the project as argument
329 # * before, after: specify where the menu item should be inserted (eg. :after => :activity)
329 # * before, after: specify where the menu item should be inserted (eg. :after => :activity)
330 # * parent: menu item will be added as a child of another named menu (eg. :parent => :issues)
330 # * parent: menu item will be added as a child of another named menu (eg. :parent => :issues)
331 # * children: a Proc that is called before rendering the item. The Proc should return an array of MenuItems, which will be added as children to this item.
331 # * children: a Proc that is called before rendering the item. The Proc should return an array of MenuItems, which will be added as children to this item.
332 # eg. :children => Proc.new {|project| [Redmine::MenuManager::MenuItem.new(...)] }
332 # eg. :children => Proc.new {|project| [Redmine::MenuManager::MenuItem.new(...)] }
333 # * last: menu item will stay at the end (eg. :last => true)
333 # * last: menu item will stay at the end (eg. :last => true)
334 # * html_options: a hash of html options that are passed to link_to
334 # * html_options: a hash of html options that are passed to link_to
335 def push(name, url, options={})
335 def push(name, url, options={})
336 options = options.dup
336 options = options.dup
337
337
338 if options[:parent]
338 if options[:parent]
339 subtree = self.find(options[:parent])
339 subtree = self.find(options[:parent])
340 if subtree
340 if subtree
341 target_root = subtree
341 target_root = subtree
342 else
342 else
343 target_root = @menu_items.root
343 target_root = @menu_items.root
344 end
344 end
345
345
346 else
346 else
347 target_root = @menu_items.root
347 target_root = @menu_items.root
348 end
348 end
349
349
350 # menu item position
350 # menu item position
351 if first = options.delete(:first)
351 if first = options.delete(:first)
352 target_root.prepend(MenuItem.new(name, url, options))
352 target_root.prepend(MenuItem.new(name, url, options))
353 elsif before = options.delete(:before)
353 elsif before = options.delete(:before)
354
354
355 if exists?(before)
355 if exists?(before)
356 target_root.add_at(MenuItem.new(name, url, options), position_of(before))
356 target_root.add_at(MenuItem.new(name, url, options), position_of(before))
357 else
357 else
358 target_root.add(MenuItem.new(name, url, options))
358 target_root.add(MenuItem.new(name, url, options))
359 end
359 end
360
360
361 elsif after = options.delete(:after)
361 elsif after = options.delete(:after)
362
362
363 if exists?(after)
363 if exists?(after)
364 target_root.add_at(MenuItem.new(name, url, options), position_of(after) + 1)
364 target_root.add_at(MenuItem.new(name, url, options), position_of(after) + 1)
365 else
365 else
366 target_root.add(MenuItem.new(name, url, options))
366 target_root.add(MenuItem.new(name, url, options))
367 end
367 end
368
368
369 elsif options[:last] # don't delete, needs to be stored
369 elsif options[:last] # don't delete, needs to be stored
370 target_root.add_last(MenuItem.new(name, url, options))
370 target_root.add_last(MenuItem.new(name, url, options))
371 else
371 else
372 target_root.add(MenuItem.new(name, url, options))
372 target_root.add(MenuItem.new(name, url, options))
373 end
373 end
374 end
374 end
375
375
376 # Removes a menu item
376 # Removes a menu item
377 def delete(name)
377 def delete(name)
378 if found = self.find(name)
378 if found = self.find(name)
379 @menu_items.remove!(found)
379 @menu_items.remove!(found)
380 end
380 end
381 end
381 end
382
382
383 # Checks if a menu item exists
383 # Checks if a menu item exists
384 def exists?(name)
384 def exists?(name)
385 @menu_items.any? {|node| node.name == name}
385 @menu_items.any? {|node| node.name == name}
386 end
386 end
387
387
388 def find(name)
388 def find(name)
389 @menu_items.find {|node| node.name == name}
389 @menu_items.find {|node| node.name == name}
390 end
390 end
391
391
392 def position_of(name)
392 def position_of(name)
393 @menu_items.each do |node|
393 @menu_items.each do |node|
394 if node.name == name
394 if node.name == name
395 return node.position
395 return node.position
396 end
396 end
397 end
397 end
398 end
398 end
399 end
399 end
400
400
401 class MenuItem < Tree::TreeNode
401 class MenuItem < Tree::TreeNode
402 include Redmine::I18n
402 include Redmine::I18n
403 attr_reader :name, :url, :param, :condition, :parent, :child_menus, :last
403 attr_reader :name, :url, :param, :condition, :parent, :child_menus, :last
404
404
405 def initialize(name, url, options)
405 def initialize(name, url, options)
406 raise ArgumentError, "Invalid option :if for menu item '#{name}'" if options[:if] && !options[:if].respond_to?(:call)
406 raise ArgumentError, "Invalid option :if for menu item '#{name}'" if options[:if] && !options[:if].respond_to?(:call)
407 raise ArgumentError, "Invalid option :html for menu item '#{name}'" if options[:html] && !options[:html].is_a?(Hash)
407 raise ArgumentError, "Invalid option :html for menu item '#{name}'" if options[:html] && !options[:html].is_a?(Hash)
408 raise ArgumentError, "Cannot set the :parent to be the same as this item" if options[:parent] == name.to_sym
408 raise ArgumentError, "Cannot set the :parent to be the same as this item" if options[:parent] == name.to_sym
409 raise ArgumentError, "Invalid option :children for menu item '#{name}'" if options[:children] && !options[:children].respond_to?(:call)
409 raise ArgumentError, "Invalid option :children for menu item '#{name}'" if options[:children] && !options[:children].respond_to?(:call)
410 @name = name
410 @name = name
411 @url = url
411 @url = url
412 @condition = options[:if]
412 @condition = options[:if]
413 @param = options[:param] || :id
413 @param = options[:param] || :id
414 @caption = options[:caption]
414 @caption = options[:caption]
415 @html_options = options[:html] || {}
415 @html_options = options[:html] || {}
416 # Adds a unique class to each menu item based on its name
416 # Adds a unique class to each menu item based on its name
417 @html_options[:class] = [@html_options[:class], @name.to_s.dasherize].compact.join(' ')
417 @html_options[:class] = [@html_options[:class], @name.to_s.dasherize].compact.join(' ')
418 @parent = options[:parent]
418 @parent = options[:parent]
419 @child_menus = options[:children]
419 @child_menus = options[:children]
420 @last = options[:last] || false
420 @last = options[:last] || false
421 super @name.to_sym
421 super @name.to_sym
422 end
422 end
423
423
424 def caption(project=nil)
424 def caption(project=nil)
425 if @caption.is_a?(Proc)
425 if @caption.is_a?(Proc)
426 c = @caption.call(project).to_s
426 c = @caption.call(project).to_s
427 c = @name.to_s.humanize if c.blank?
427 c = @name.to_s.humanize if c.blank?
428 c
428 c
429 else
429 else
430 if @caption.nil?
430 if @caption.nil?
431 l_or_humanize(name, :prefix => 'label_')
431 l_or_humanize(name, :prefix => 'label_')
432 else
432 else
433 @caption.is_a?(Symbol) ? l(@caption) : @caption
433 @caption.is_a?(Symbol) ? l(@caption) : @caption
434 end
434 end
435 end
435 end
436 end
436 end
437
437
438 def html_options(options={})
438 def html_options(options={})
439 if options[:selected]
439 if options[:selected]
440 o = @html_options.dup
440 o = @html_options.dup
441 o[:class] += ' selected'
441 o[:class] += ' selected'
442 o
442 o
443 else
443 else
444 @html_options
444 @html_options
445 end
445 end
446 end
446 end
447 end
447 end
448 end
448 end
449 end
449 end
General Comments 0
You need to be logged in to leave comments. Login now