##// END OF EJS Templates
Support for named route in project menu and a new :permission option (#6426)....
Jean-Philippe Lang -
r13383:64fea07affaf
parent child
Show More
@@ -1,440 +1,454
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2014 Jean-Philippe Lang
2 # Copyright (C) 2006-2014 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 module Redmine
18 module Redmine
19 module MenuManager
19 module MenuManager
20 class MenuError < StandardError #:nodoc:
20 class MenuError < StandardError #:nodoc:
21 end
21 end
22
22
23 module MenuController
23 module MenuController
24 def self.included(base)
24 def self.included(base)
25 base.extend(ClassMethods)
25 base.extend(ClassMethods)
26 end
26 end
27
27
28 module ClassMethods
28 module ClassMethods
29 @@menu_items = Hash.new {|hash, key| hash[key] = {:default => key, :actions => {}}}
29 @@menu_items = Hash.new {|hash, key| hash[key] = {:default => key, :actions => {}}}
30 mattr_accessor :menu_items
30 mattr_accessor :menu_items
31
31
32 # Set the menu item name for a controller or specific actions
32 # Set the menu item name for a controller or specific actions
33 # Examples:
33 # Examples:
34 # * menu_item :tickets # => sets the menu name to :tickets for the whole controller
34 # * menu_item :tickets # => sets the menu name to :tickets for the whole controller
35 # * menu_item :tickets, :only => :list # => sets the menu name to :tickets for the 'list' action only
35 # * menu_item :tickets, :only => :list # => sets the menu name to :tickets for the 'list' action only
36 # * menu_item :tickets, :only => [:list, :show] # => sets the menu name to :tickets for 2 actions only
36 # * menu_item :tickets, :only => [:list, :show] # => sets the menu name to :tickets for 2 actions only
37 #
37 #
38 # The default menu item name for a controller is controller_name by default
38 # The default menu item name for a controller is controller_name by default
39 # Eg. the default menu item name for ProjectsController is :projects
39 # Eg. the default menu item name for ProjectsController is :projects
40 def menu_item(id, options = {})
40 def menu_item(id, options = {})
41 if actions = options[:only]
41 if actions = options[:only]
42 actions = [] << actions unless actions.is_a?(Array)
42 actions = [] << actions unless actions.is_a?(Array)
43 actions.each {|a| menu_items[controller_name.to_sym][:actions][a.to_sym] = id}
43 actions.each {|a| menu_items[controller_name.to_sym][:actions][a.to_sym] = id}
44 else
44 else
45 menu_items[controller_name.to_sym][:default] = id
45 menu_items[controller_name.to_sym][:default] = id
46 end
46 end
47 end
47 end
48 end
48 end
49
49
50 def menu_items
50 def menu_items
51 self.class.menu_items
51 self.class.menu_items
52 end
52 end
53
53
54 # Returns the menu item name according to the current action
54 # Returns the menu item name according to the current action
55 def current_menu_item
55 def current_menu_item
56 @current_menu_item ||= menu_items[controller_name.to_sym][:actions][action_name.to_sym] ||
56 @current_menu_item ||= menu_items[controller_name.to_sym][:actions][action_name.to_sym] ||
57 menu_items[controller_name.to_sym][:default]
57 menu_items[controller_name.to_sym][:default]
58 end
58 end
59
59
60 # Redirects user to the menu item of the given project
60 # Redirects user to the menu item of the given project
61 # Returns false if user is not authorized
61 # Returns false if user is not authorized
62 def redirect_to_project_menu_item(project, name)
62 def redirect_to_project_menu_item(project, name)
63 item = Redmine::MenuManager.items(:project_menu).detect {|i| i.name.to_s == name.to_s}
63 item = Redmine::MenuManager.items(:project_menu).detect {|i| i.name.to_s == name.to_s}
64 if item && item.allowed?(User.current, project)
64 if item && item.allowed?(User.current, project)
65 redirect_to({item.param => project}.merge(item.url))
65 redirect_to({item.param => project}.merge(item.url))
66 return true
66 return true
67 end
67 end
68 false
68 false
69 end
69 end
70 end
70 end
71
71
72 module MenuHelper
72 module MenuHelper
73 # Returns the current menu item name
73 # Returns the current menu item name
74 def current_menu_item
74 def current_menu_item
75 controller.current_menu_item
75 controller.current_menu_item
76 end
76 end
77
77
78 # Renders the application main menu
78 # Renders the application main menu
79 def render_main_menu(project)
79 def render_main_menu(project)
80 render_menu((project && !project.new_record?) ? :project_menu : :application_menu, project)
80 render_menu((project && !project.new_record?) ? :project_menu : :application_menu, project)
81 end
81 end
82
82
83 def display_main_menu?(project)
83 def display_main_menu?(project)
84 menu_name = project && !project.new_record? ? :project_menu : :application_menu
84 menu_name = project && !project.new_record? ? :project_menu : :application_menu
85 Redmine::MenuManager.items(menu_name).children.present?
85 Redmine::MenuManager.items(menu_name).children.present?
86 end
86 end
87
87
88 def render_menu(menu, project=nil)
88 def render_menu(menu, project=nil)
89 links = []
89 links = []
90 menu_items_for(menu, project) do |node|
90 menu_items_for(menu, project) do |node|
91 links << render_menu_node(node, project)
91 links << render_menu_node(node, project)
92 end
92 end
93 links.empty? ? nil : content_tag('ul', links.join("\n").html_safe)
93 links.empty? ? nil : content_tag('ul', links.join("\n").html_safe)
94 end
94 end
95
95
96 def render_menu_node(node, project=nil)
96 def render_menu_node(node, project=nil)
97 if node.children.present? || !node.child_menus.nil?
97 if node.children.present? || !node.child_menus.nil?
98 return render_menu_node_with_children(node, project)
98 return render_menu_node_with_children(node, project)
99 else
99 else
100 caption, url, selected = extract_node_details(node, project)
100 caption, url, selected = extract_node_details(node, project)
101 return content_tag('li',
101 return content_tag('li',
102 render_single_menu_node(node, caption, url, selected))
102 render_single_menu_node(node, caption, url, selected))
103 end
103 end
104 end
104 end
105
105
106 def render_menu_node_with_children(node, project=nil)
106 def render_menu_node_with_children(node, project=nil)
107 caption, url, selected = extract_node_details(node, project)
107 caption, url, selected = extract_node_details(node, project)
108
108
109 html = [].tap do |html|
109 html = [].tap do |html|
110 html << '<li>'
110 html << '<li>'
111 # Parent
111 # Parent
112 html << render_single_menu_node(node, caption, url, selected)
112 html << render_single_menu_node(node, caption, url, selected)
113
113
114 # Standard children
114 # Standard children
115 standard_children_list = "".html_safe.tap do |child_html|
115 standard_children_list = "".html_safe.tap do |child_html|
116 node.children.each do |child|
116 node.children.each do |child|
117 child_html << render_menu_node(child, project)
117 child_html << render_menu_node(child, project)
118 end
118 end
119 end
119 end
120
120
121 html << content_tag(:ul, standard_children_list, :class => 'menu-children') unless standard_children_list.empty?
121 html << content_tag(:ul, standard_children_list, :class => 'menu-children') unless standard_children_list.empty?
122
122
123 # Unattached children
123 # Unattached children
124 unattached_children_list = render_unattached_children_menu(node, project)
124 unattached_children_list = render_unattached_children_menu(node, project)
125 html << content_tag(:ul, unattached_children_list, :class => 'menu-children unattached') unless unattached_children_list.blank?
125 html << content_tag(:ul, unattached_children_list, :class => 'menu-children unattached') unless unattached_children_list.blank?
126
126
127 html << '</li>'
127 html << '</li>'
128 end
128 end
129 return html.join("\n").html_safe
129 return html.join("\n").html_safe
130 end
130 end
131
131
132 # Returns a list of unattached children menu items
132 # Returns a list of unattached children menu items
133 def render_unattached_children_menu(node, project)
133 def render_unattached_children_menu(node, project)
134 return nil unless node.child_menus
134 return nil unless node.child_menus
135
135
136 "".html_safe.tap do |child_html|
136 "".html_safe.tap do |child_html|
137 unattached_children = node.child_menus.call(project)
137 unattached_children = node.child_menus.call(project)
138 # Tree nodes support #each so we need to do object detection
138 # Tree nodes support #each so we need to do object detection
139 if unattached_children.is_a? Array
139 if unattached_children.is_a? Array
140 unattached_children.each do |child|
140 unattached_children.each do |child|
141 child_html << content_tag(:li, render_unattached_menu_item(child, project))
141 child_html << content_tag(:li, render_unattached_menu_item(child, project))
142 end
142 end
143 else
143 else
144 raise MenuError, ":child_menus must be an array of MenuItems"
144 raise MenuError, ":child_menus must be an array of MenuItems"
145 end
145 end
146 end
146 end
147 end
147 end
148
148
149 def render_single_menu_node(item, caption, url, selected)
149 def render_single_menu_node(item, caption, url, selected)
150 link_to(h(caption), url, item.html_options(:selected => selected))
150 link_to(h(caption), url, item.html_options(:selected => selected))
151 end
151 end
152
152
153 def render_unattached_menu_item(menu_item, project)
153 def render_unattached_menu_item(menu_item, project)
154 raise MenuError, ":child_menus must be an array of MenuItems" unless menu_item.is_a? MenuItem
154 raise MenuError, ":child_menus must be an array of MenuItems" unless menu_item.is_a? MenuItem
155
155
156 if menu_item.allowed?(User.current, project)
156 if menu_item.allowed?(User.current, project)
157 link_to(menu_item.caption, menu_item.url, menu_item.html_options)
157 link_to(menu_item.caption, menu_item.url, menu_item.html_options)
158 end
158 end
159 end
159 end
160
160
161 def menu_items_for(menu, project=nil)
161 def menu_items_for(menu, project=nil)
162 items = []
162 items = []
163 Redmine::MenuManager.items(menu).root.children.each do |node|
163 Redmine::MenuManager.items(menu).root.children.each do |node|
164 if node.allowed?(User.current, project)
164 if node.allowed?(User.current, project)
165 if block_given?
165 if block_given?
166 yield node
166 yield node
167 else
167 else
168 items << node # TODO: not used?
168 items << node # TODO: not used?
169 end
169 end
170 end
170 end
171 end
171 end
172 return block_given? ? nil : items
172 return block_given? ? nil : items
173 end
173 end
174
174
175 def extract_node_details(node, project=nil)
175 def extract_node_details(node, project=nil)
176 item = node
176 item = node
177 url = case item.url
177 url = case item.url
178 when Hash
178 when Hash
179 project.nil? ? item.url : {item.param => project}.merge(item.url)
179 project.nil? ? item.url : {item.param => project}.merge(item.url)
180 when Symbol
180 when Symbol
181 send(item.url)
181 if project
182 send(item.url, project)
183 else
184 send(item.url)
185 end
182 else
186 else
183 item.url
187 item.url
184 end
188 end
185 caption = item.caption(project)
189 caption = item.caption(project)
186 return [caption, url, (current_menu_item == item.name)]
190 return [caption, url, (current_menu_item == item.name)]
187 end
191 end
188
192
189 # See MenuItem#allowed?
193 # See MenuItem#allowed?
190 def allowed_node?(node, user, project)
194 def allowed_node?(node, user, project)
191 node.allowed?(user, project)
195 node.allowed?(user, project)
192 end
196 end
193 end
197 end
194
198
195 class << self
199 class << self
196 def map(menu_name)
200 def map(menu_name)
197 @items ||= {}
201 @items ||= {}
198 mapper = Mapper.new(menu_name.to_sym, @items)
202 mapper = Mapper.new(menu_name.to_sym, @items)
199 if block_given?
203 if block_given?
200 yield mapper
204 yield mapper
201 else
205 else
202 mapper
206 mapper
203 end
207 end
204 end
208 end
205
209
206 def items(menu_name)
210 def items(menu_name)
207 @items[menu_name.to_sym] || MenuNode.new(:root, {})
211 @items[menu_name.to_sym] || MenuNode.new(:root, {})
208 end
212 end
209 end
213 end
210
214
211 class Mapper
215 class Mapper
212 attr_reader :menu, :menu_items
216 attr_reader :menu, :menu_items
213
217
214 def initialize(menu, items)
218 def initialize(menu, items)
215 items[menu] ||= MenuNode.new(:root, {})
219 items[menu] ||= MenuNode.new(:root, {})
216 @menu = menu
220 @menu = menu
217 @menu_items = items[menu]
221 @menu_items = items[menu]
218 end
222 end
219
223
220 # Adds an item at the end of the menu. Available options:
224 # Adds an item at the end of the menu. Available options:
221 # * param: the parameter name that is used for the project id (default is :id)
225 # * param: the parameter name that is used for the project id (default is :id)
222 # * if: a Proc that is called before rendering the item, the item is displayed only if it returns true
226 # * if: a Proc that is called before rendering the item, the item is displayed only if it returns true
223 # * caption that can be:
227 # * caption that can be:
224 # * a localized string Symbol
228 # * a localized string Symbol
225 # * a String
229 # * a String
226 # * a Proc that can take the project as argument
230 # * a Proc that can take the project as argument
227 # * before, after: specify where the menu item should be inserted (eg. :after => :activity)
231 # * before, after: specify where the menu item should be inserted (eg. :after => :activity)
228 # * parent: menu item will be added as a child of another named menu (eg. :parent => :issues)
232 # * parent: menu item will be added as a child of another named menu (eg. :parent => :issues)
229 # * 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.
233 # * 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.
230 # eg. :children => Proc.new {|project| [Redmine::MenuManager::MenuItem.new(...)] }
234 # eg. :children => Proc.new {|project| [Redmine::MenuManager::MenuItem.new(...)] }
231 # * last: menu item will stay at the end (eg. :last => true)
235 # * last: menu item will stay at the end (eg. :last => true)
232 # * html_options: a hash of html options that are passed to link_to
236 # * html_options: a hash of html options that are passed to link_to
233 def push(name, url, options={})
237 def push(name, url, options={})
234 options = options.dup
238 options = options.dup
235
239
236 if options[:parent]
240 if options[:parent]
237 subtree = self.find(options[:parent])
241 subtree = self.find(options[:parent])
238 if subtree
242 if subtree
239 target_root = subtree
243 target_root = subtree
240 else
244 else
241 target_root = @menu_items.root
245 target_root = @menu_items.root
242 end
246 end
243
247
244 else
248 else
245 target_root = @menu_items.root
249 target_root = @menu_items.root
246 end
250 end
247
251
248 # menu item position
252 # menu item position
249 if first = options.delete(:first)
253 if first = options.delete(:first)
250 target_root.prepend(MenuItem.new(name, url, options))
254 target_root.prepend(MenuItem.new(name, url, options))
251 elsif before = options.delete(:before)
255 elsif before = options.delete(:before)
252
256
253 if exists?(before)
257 if exists?(before)
254 target_root.add_at(MenuItem.new(name, url, options), position_of(before))
258 target_root.add_at(MenuItem.new(name, url, options), position_of(before))
255 else
259 else
256 target_root.add(MenuItem.new(name, url, options))
260 target_root.add(MenuItem.new(name, url, options))
257 end
261 end
258
262
259 elsif after = options.delete(:after)
263 elsif after = options.delete(:after)
260
264
261 if exists?(after)
265 if exists?(after)
262 target_root.add_at(MenuItem.new(name, url, options), position_of(after) + 1)
266 target_root.add_at(MenuItem.new(name, url, options), position_of(after) + 1)
263 else
267 else
264 target_root.add(MenuItem.new(name, url, options))
268 target_root.add(MenuItem.new(name, url, options))
265 end
269 end
266
270
267 elsif options[:last] # don't delete, needs to be stored
271 elsif options[:last] # don't delete, needs to be stored
268 target_root.add_last(MenuItem.new(name, url, options))
272 target_root.add_last(MenuItem.new(name, url, options))
269 else
273 else
270 target_root.add(MenuItem.new(name, url, options))
274 target_root.add(MenuItem.new(name, url, options))
271 end
275 end
272 end
276 end
273
277
274 # Removes a menu item
278 # Removes a menu item
275 def delete(name)
279 def delete(name)
276 if found = self.find(name)
280 if found = self.find(name)
277 @menu_items.remove!(found)
281 @menu_items.remove!(found)
278 end
282 end
279 end
283 end
280
284
281 # Checks if a menu item exists
285 # Checks if a menu item exists
282 def exists?(name)
286 def exists?(name)
283 @menu_items.any? {|node| node.name == name}
287 @menu_items.any? {|node| node.name == name}
284 end
288 end
285
289
286 def find(name)
290 def find(name)
287 @menu_items.find {|node| node.name == name}
291 @menu_items.find {|node| node.name == name}
288 end
292 end
289
293
290 def position_of(name)
294 def position_of(name)
291 @menu_items.each do |node|
295 @menu_items.each do |node|
292 if node.name == name
296 if node.name == name
293 return node.position
297 return node.position
294 end
298 end
295 end
299 end
296 end
300 end
297 end
301 end
298
302
299 class MenuNode
303 class MenuNode
300 include Enumerable
304 include Enumerable
301 attr_accessor :parent
305 attr_accessor :parent
302 attr_reader :last_items_count, :name
306 attr_reader :last_items_count, :name
303
307
304 def initialize(name, content = nil)
308 def initialize(name, content = nil)
305 @name = name
309 @name = name
306 @children = []
310 @children = []
307 @last_items_count = 0
311 @last_items_count = 0
308 end
312 end
309
313
310 def children
314 def children
311 if block_given?
315 if block_given?
312 @children.each {|child| yield child}
316 @children.each {|child| yield child}
313 else
317 else
314 @children
318 @children
315 end
319 end
316 end
320 end
317
321
318 # Returns the number of descendants + 1
322 # Returns the number of descendants + 1
319 def size
323 def size
320 @children.inject(1) {|sum, node| sum + node.size}
324 @children.inject(1) {|sum, node| sum + node.size}
321 end
325 end
322
326
323 def each &block
327 def each &block
324 yield self
328 yield self
325 children { |child| child.each(&block) }
329 children { |child| child.each(&block) }
326 end
330 end
327
331
328 # Adds a child at first position
332 # Adds a child at first position
329 def prepend(child)
333 def prepend(child)
330 add_at(child, 0)
334 add_at(child, 0)
331 end
335 end
332
336
333 # Adds a child at given position
337 # Adds a child at given position
334 def add_at(child, position)
338 def add_at(child, position)
335 raise "Child already added" if find {|node| node.name == child.name}
339 raise "Child already added" if find {|node| node.name == child.name}
336
340
337 @children = @children.insert(position, child)
341 @children = @children.insert(position, child)
338 child.parent = self
342 child.parent = self
339 child
343 child
340 end
344 end
341
345
342 # Adds a child as last child
346 # Adds a child as last child
343 def add_last(child)
347 def add_last(child)
344 add_at(child, -1)
348 add_at(child, -1)
345 @last_items_count += 1
349 @last_items_count += 1
346 child
350 child
347 end
351 end
348
352
349 # Adds a child
353 # Adds a child
350 def add(child)
354 def add(child)
351 position = @children.size - @last_items_count
355 position = @children.size - @last_items_count
352 add_at(child, position)
356 add_at(child, position)
353 end
357 end
354 alias :<< :add
358 alias :<< :add
355
359
356 # Removes a child
360 # Removes a child
357 def remove!(child)
361 def remove!(child)
358 @children.delete(child)
362 @children.delete(child)
359 @last_items_count -= +1 if child && child.last
363 @last_items_count -= +1 if child && child.last
360 child.parent = nil
364 child.parent = nil
361 child
365 child
362 end
366 end
363
367
364 # Returns the position for this node in it's parent
368 # Returns the position for this node in it's parent
365 def position
369 def position
366 self.parent.children.index(self)
370 self.parent.children.index(self)
367 end
371 end
368
372
369 # Returns the root for this node
373 # Returns the root for this node
370 def root
374 def root
371 root = self
375 root = self
372 root = root.parent while root.parent
376 root = root.parent while root.parent
373 root
377 root
374 end
378 end
375 end
379 end
376
380
377 class MenuItem < MenuNode
381 class MenuItem < MenuNode
378 include Redmine::I18n
382 include Redmine::I18n
379 attr_reader :name, :url, :param, :condition, :parent, :child_menus, :last
383 attr_reader :name, :url, :param, :condition, :parent, :child_menus, :last, :permission
380
384
381 def initialize(name, url, options)
385 def initialize(name, url, options={})
382 raise ArgumentError, "Invalid option :if for menu item '#{name}'" if options[:if] && !options[:if].respond_to?(:call)
386 raise ArgumentError, "Invalid option :if for menu item '#{name}'" if options[:if] && !options[:if].respond_to?(:call)
383 raise ArgumentError, "Invalid option :html for menu item '#{name}'" if options[:html] && !options[:html].is_a?(Hash)
387 raise ArgumentError, "Invalid option :html for menu item '#{name}'" if options[:html] && !options[:html].is_a?(Hash)
384 raise ArgumentError, "Cannot set the :parent to be the same as this item" if options[:parent] == name.to_sym
388 raise ArgumentError, "Cannot set the :parent to be the same as this item" if options[:parent] == name.to_sym
385 raise ArgumentError, "Invalid option :children for menu item '#{name}'" if options[:children] && !options[:children].respond_to?(:call)
389 raise ArgumentError, "Invalid option :children for menu item '#{name}'" if options[:children] && !options[:children].respond_to?(:call)
386 @name = name
390 @name = name
387 @url = url
391 @url = url
388 @condition = options[:if]
392 @condition = options[:if]
393 @permission = options[:permission]
394 @permission ||= false if options.key?(:permission)
389 @param = options[:param] || :id
395 @param = options[:param] || :id
390 @caption = options[:caption]
396 @caption = options[:caption]
391 @html_options = options[:html] || {}
397 @html_options = options[:html] || {}
392 # Adds a unique class to each menu item based on its name
398 # Adds a unique class to each menu item based on its name
393 @html_options[:class] = [@html_options[:class], @name.to_s.dasherize].compact.join(' ')
399 @html_options[:class] = [@html_options[:class], @name.to_s.dasherize].compact.join(' ')
394 @parent = options[:parent]
400 @parent = options[:parent]
395 @child_menus = options[:children]
401 @child_menus = options[:children]
396 @last = options[:last] || false
402 @last = options[:last] || false
397 super @name.to_sym
403 super @name.to_sym
398 end
404 end
399
405
400 def caption(project=nil)
406 def caption(project=nil)
401 if @caption.is_a?(Proc)
407 if @caption.is_a?(Proc)
402 c = @caption.call(project).to_s
408 c = @caption.call(project).to_s
403 c = @name.to_s.humanize if c.blank?
409 c = @name.to_s.humanize if c.blank?
404 c
410 c
405 else
411 else
406 if @caption.nil?
412 if @caption.nil?
407 l_or_humanize(name, :prefix => 'label_')
413 l_or_humanize(name, :prefix => 'label_')
408 else
414 else
409 @caption.is_a?(Symbol) ? l(@caption) : @caption
415 @caption.is_a?(Symbol) ? l(@caption) : @caption
410 end
416 end
411 end
417 end
412 end
418 end
413
419
414 def html_options(options={})
420 def html_options(options={})
415 if options[:selected]
421 if options[:selected]
416 o = @html_options.dup
422 o = @html_options.dup
417 o[:class] += ' selected'
423 o[:class] += ' selected'
418 o
424 o
419 else
425 else
420 @html_options
426 @html_options
421 end
427 end
422 end
428 end
423
429
424 # Checks if a user is allowed to access the menu item by:
430 # Checks if a user is allowed to access the menu item by:
425 #
431 #
426 # * Checking the url target (project only)
432 # * Checking the permission or the url target (project only)
427 # * Checking the conditions of the item
433 # * Checking the conditions of the item
428 def allowed?(user, project)
434 def allowed?(user, project)
429 if url.is_a?(Hash) && project && user && !user.allowed_to?(url, project)
435 if user && project
430 return false
436 if permission
437 unless user.allowed_to?(permission, project)
438 return false
439 end
440 elsif permission.nil? && url.is_a?(Hash)
441 unless user.allowed_to?(url, project)
442 return false
443 end
444 end
431 end
445 end
432 if condition && !condition.call(project)
446 if condition && !condition.call(project)
433 # Condition that doesn't pass
447 # Condition that doesn't pass
434 return false
448 return false
435 end
449 end
436 return true
450 return true
437 end
451 end
438 end
452 end
439 end
453 end
440 end
454 end
@@ -1,233 +1,260
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2014 Jean-Philippe Lang
2 # Copyright (C) 2006-2014 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 File.expand_path('../../../../../test_helper', __FILE__)
18 require File.expand_path('../../../../../test_helper', __FILE__)
19
19
20 class Redmine::MenuManager::MenuHelperTest < ActionView::TestCase
20 class Redmine::MenuManager::MenuHelperTest < ActionView::TestCase
21
21
22 include Redmine::MenuManager::MenuHelper
22 include Redmine::MenuManager::MenuHelper
23 include ERB::Util
23 include ERB::Util
24 fixtures :users, :members, :projects, :enabled_modules, :roles, :member_roles
24 fixtures :users, :members, :projects, :enabled_modules, :roles, :member_roles
25
25
26 def setup
26 def setup
27 setup_with_controller
27 setup_with_controller
28 # Stub the current menu item in the controller
28 # Stub the current menu item in the controller
29 def current_menu_item
29 def current_menu_item
30 :index
30 :index
31 end
31 end
32 end
32 end
33
33
34 def test_render_single_menu_node
34 def test_render_single_menu_node
35 node = Redmine::MenuManager::MenuItem.new(:testing, '/test', { })
35 node = Redmine::MenuManager::MenuItem.new(:testing, '/test', { })
36 @output_buffer = render_single_menu_node(node, 'This is a test', node.url, false)
36 @output_buffer = render_single_menu_node(node, 'This is a test', node.url, false)
37
37
38 assert_select("a.testing", "This is a test")
38 assert_select("a.testing", "This is a test")
39 end
39 end
40
40
41 def test_render_menu_node
41 def test_render_menu_node
42 single_node = Redmine::MenuManager::MenuItem.new(:single_node, '/test', { })
42 single_node = Redmine::MenuManager::MenuItem.new(:single_node, '/test', { })
43 @output_buffer = render_menu_node(single_node, nil)
43 @output_buffer = render_menu_node(single_node, nil)
44
44
45 assert_select("li") do
45 assert_select("li") do
46 assert_select("a.single-node", "Single node")
46 assert_select("a.single-node", "Single node")
47 end
47 end
48 end
48 end
49
49
50 def test_render_menu_node_with_symbol_as_url
51 node = Redmine::MenuManager::MenuItem.new(:testing, :issues_path)
52 @output_buffer = render_menu_node(node, nil)
53
54 assert_select "a[href=/issues]", "Testing"
55 end
56
57 def test_render_menu_node_with_symbol_as_url_and_project
58 node = Redmine::MenuManager::MenuItem.new(:testing, :project_issues_path)
59 @output_buffer = render_menu_node(node, Project.find(1))
60
61 assert_select "a[href=/projects/ecookbook/issues]", "Testing"
62 end
63
50 def test_render_menu_node_with_nested_items
64 def test_render_menu_node_with_nested_items
51 parent_node = Redmine::MenuManager::MenuItem.new(:parent_node, '/test', { })
65 parent_node = Redmine::MenuManager::MenuItem.new(:parent_node, '/test', { })
52 parent_node << Redmine::MenuManager::MenuItem.new(:child_one_node, '/test', { })
66 parent_node << Redmine::MenuManager::MenuItem.new(:child_one_node, '/test', { })
53 parent_node << Redmine::MenuManager::MenuItem.new(:child_two_node, '/test', { })
67 parent_node << Redmine::MenuManager::MenuItem.new(:child_two_node, '/test', { })
54 parent_node <<
68 parent_node <<
55 Redmine::MenuManager::MenuItem.new(:child_three_node, '/test', { }) <<
69 Redmine::MenuManager::MenuItem.new(:child_three_node, '/test', { }) <<
56 Redmine::MenuManager::MenuItem.new(:child_three_inner_node, '/test', { })
70 Redmine::MenuManager::MenuItem.new(:child_three_inner_node, '/test', { })
57
71
58 @output_buffer = render_menu_node(parent_node, nil)
72 @output_buffer = render_menu_node(parent_node, nil)
59
73
60 assert_select("li") do
74 assert_select("li") do
61 assert_select("a.parent-node", "Parent node")
75 assert_select("a.parent-node", "Parent node")
62 assert_select("ul") do
76 assert_select("ul") do
63 assert_select("li a.child-one-node", "Child one node")
77 assert_select("li a.child-one-node", "Child one node")
64 assert_select("li a.child-two-node", "Child two node")
78 assert_select("li a.child-two-node", "Child two node")
65 assert_select("li") do
79 assert_select("li") do
66 assert_select("a.child-three-node", "Child three node")
80 assert_select("a.child-three-node", "Child three node")
67 assert_select("ul") do
81 assert_select("ul") do
68 assert_select("li a.child-three-inner-node", "Child three inner node")
82 assert_select("li a.child-three-inner-node", "Child three inner node")
69 end
83 end
70 end
84 end
71 end
85 end
72 end
86 end
73
87
74 end
88 end
75
89
76 def test_render_menu_node_with_children
90 def test_render_menu_node_with_children
77 User.current = User.find(2)
91 User.current = User.find(2)
78
92
79 parent_node = Redmine::MenuManager::MenuItem.new(:parent_node,
93 parent_node = Redmine::MenuManager::MenuItem.new(:parent_node,
80 '/test',
94 '/test',
81 {
95 {
82 :children => Proc.new {|p|
96 :children => Proc.new {|p|
83 children = []
97 children = []
84 3.times do |time|
98 3.times do |time|
85 children << Redmine::MenuManager::MenuItem.new("test_child_#{time}",
99 children << Redmine::MenuManager::MenuItem.new("test_child_#{time}",
86 {:controller => 'issues', :action => 'index'},
100 {:controller => 'issues', :action => 'index'},
87 {})
101 {})
88 end
102 end
89 children
103 children
90 }
104 }
91 })
105 })
92 @output_buffer = render_menu_node(parent_node, Project.find(1))
106 @output_buffer = render_menu_node(parent_node, Project.find(1))
93
107
94 assert_select("li") do
108 assert_select("li") do
95 assert_select("a.parent-node", "Parent node")
109 assert_select("a.parent-node", "Parent node")
96 assert_select("ul") do
110 assert_select("ul") do
97 assert_select("li a.test-child-0", "Test child 0")
111 assert_select("li a.test-child-0", "Test child 0")
98 assert_select("li a.test-child-1", "Test child 1")
112 assert_select("li a.test-child-1", "Test child 1")
99 assert_select("li a.test-child-2", "Test child 2")
113 assert_select("li a.test-child-2", "Test child 2")
100 end
114 end
101 end
115 end
102 end
116 end
103
117
104 def test_render_menu_node_with_nested_items_and_children
118 def test_render_menu_node_with_nested_items_and_children
105 User.current = User.find(2)
119 User.current = User.find(2)
106
120
107 parent_node = Redmine::MenuManager::MenuItem.new(:parent_node,
121 parent_node = Redmine::MenuManager::MenuItem.new(:parent_node,
108 '/test',
122 '/test',
109 {
123 {
110 :children => Proc.new {|p|
124 :children => Proc.new {|p|
111 children = []
125 children = []
112 3.times do |time|
126 3.times do |time|
113 children << Redmine::MenuManager::MenuItem.new("test_child_#{time}", {:controller => 'issues', :action => 'index'}, {})
127 children << Redmine::MenuManager::MenuItem.new("test_child_#{time}", {:controller => 'issues', :action => 'index'}, {})
114 end
128 end
115 children
129 children
116 }
130 }
117 })
131 })
118
132
119 parent_node << Redmine::MenuManager::MenuItem.new(:child_node,
133 parent_node << Redmine::MenuManager::MenuItem.new(:child_node,
120 '/test',
134 '/test',
121 {
135 {
122 :children => Proc.new {|p|
136 :children => Proc.new {|p|
123 children = []
137 children = []
124 6.times do |time|
138 6.times do |time|
125 children << Redmine::MenuManager::MenuItem.new("test_dynamic_child_#{time}", {:controller => 'issues', :action => 'index'}, {})
139 children << Redmine::MenuManager::MenuItem.new("test_dynamic_child_#{time}", {:controller => 'issues', :action => 'index'}, {})
126 end
140 end
127 children
141 children
128 }
142 }
129 })
143 })
130
144
131 @output_buffer = render_menu_node(parent_node, Project.find(1))
145 @output_buffer = render_menu_node(parent_node, Project.find(1))
132
146
133 assert_select("li") do
147 assert_select("li") do
134 assert_select("a.parent-node", "Parent node")
148 assert_select("a.parent-node", "Parent node")
135 assert_select("ul") do
149 assert_select("ul") do
136 assert_select("li a.child-node", "Child node")
150 assert_select("li a.child-node", "Child node")
137 assert_select("ul") do
151 assert_select("ul") do
138 assert_select("li a.test-dynamic-child-0", "Test dynamic child 0")
152 assert_select("li a.test-dynamic-child-0", "Test dynamic child 0")
139 assert_select("li a.test-dynamic-child-1", "Test dynamic child 1")
153 assert_select("li a.test-dynamic-child-1", "Test dynamic child 1")
140 assert_select("li a.test-dynamic-child-2", "Test dynamic child 2")
154 assert_select("li a.test-dynamic-child-2", "Test dynamic child 2")
141 assert_select("li a.test-dynamic-child-3", "Test dynamic child 3")
155 assert_select("li a.test-dynamic-child-3", "Test dynamic child 3")
142 assert_select("li a.test-dynamic-child-4", "Test dynamic child 4")
156 assert_select("li a.test-dynamic-child-4", "Test dynamic child 4")
143 assert_select("li a.test-dynamic-child-5", "Test dynamic child 5")
157 assert_select("li a.test-dynamic-child-5", "Test dynamic child 5")
144 end
158 end
145 assert_select("li a.test-child-0", "Test child 0")
159 assert_select("li a.test-child-0", "Test child 0")
146 assert_select("li a.test-child-1", "Test child 1")
160 assert_select("li a.test-child-1", "Test child 1")
147 assert_select("li a.test-child-2", "Test child 2")
161 assert_select("li a.test-child-2", "Test child 2")
148 end
162 end
149 end
163 end
150 end
164 end
151
165
152 def test_render_menu_node_with_children_without_an_array
166 def test_render_menu_node_with_children_without_an_array
153 parent_node = Redmine::MenuManager::MenuItem.new(:parent_node,
167 parent_node = Redmine::MenuManager::MenuItem.new(:parent_node,
154 '/test',
168 '/test',
155 {
169 {
156 :children => Proc.new {|p| Redmine::MenuManager::MenuItem.new("test_child", "/testing", {})}
170 :children => Proc.new {|p| Redmine::MenuManager::MenuItem.new("test_child", "/testing", {})}
157 })
171 })
158
172
159 assert_raises Redmine::MenuManager::MenuError, ":children must be an array of MenuItems" do
173 assert_raises Redmine::MenuManager::MenuError, ":children must be an array of MenuItems" do
160 @output_buffer = render_menu_node(parent_node, Project.find(1))
174 @output_buffer = render_menu_node(parent_node, Project.find(1))
161 end
175 end
162 end
176 end
163
177
164 def test_render_menu_node_with_incorrect_children
178 def test_render_menu_node_with_incorrect_children
165 parent_node = Redmine::MenuManager::MenuItem.new(:parent_node,
179 parent_node = Redmine::MenuManager::MenuItem.new(:parent_node,
166 '/test',
180 '/test',
167 {
181 {
168 :children => Proc.new {|p| ["a string"] }
182 :children => Proc.new {|p| ["a string"] }
169 })
183 })
170
184
171 assert_raises Redmine::MenuManager::MenuError, ":children must be an array of MenuItems" do
185 assert_raises Redmine::MenuManager::MenuError, ":children must be an array of MenuItems" do
172 @output_buffer = render_menu_node(parent_node, Project.find(1))
186 @output_buffer = render_menu_node(parent_node, Project.find(1))
173 end
187 end
174
188
175 end
189 end
176
190
177 def test_menu_items_for_should_yield_all_items_if_passed_a_block
191 def test_menu_items_for_should_yield_all_items_if_passed_a_block
178 menu_name = :test_menu_items_for_should_yield_all_items_if_passed_a_block
192 menu_name = :test_menu_items_for_should_yield_all_items_if_passed_a_block
179 Redmine::MenuManager.map menu_name do |menu|
193 Redmine::MenuManager.map menu_name do |menu|
180 menu.push(:a_menu, '/', { })
194 menu.push(:a_menu, '/', { })
181 menu.push(:a_menu_2, '/', { })
195 menu.push(:a_menu_2, '/', { })
182 menu.push(:a_menu_3, '/', { })
196 menu.push(:a_menu_3, '/', { })
183 end
197 end
184
198
185 items_yielded = []
199 items_yielded = []
186 menu_items_for(menu_name) do |item|
200 menu_items_for(menu_name) do |item|
187 items_yielded << item
201 items_yielded << item
188 end
202 end
189
203
190 assert_equal 3, items_yielded.size
204 assert_equal 3, items_yielded.size
191 end
205 end
192
206
193 def test_menu_items_for_should_return_all_items
207 def test_menu_items_for_should_return_all_items
194 menu_name = :test_menu_items_for_should_return_all_items
208 menu_name = :test_menu_items_for_should_return_all_items
195 Redmine::MenuManager.map menu_name do |menu|
209 Redmine::MenuManager.map menu_name do |menu|
196 menu.push(:a_menu, '/', { })
210 menu.push(:a_menu, '/', { })
197 menu.push(:a_menu_2, '/', { })
211 menu.push(:a_menu_2, '/', { })
198 menu.push(:a_menu_3, '/', { })
212 menu.push(:a_menu_3, '/', { })
199 end
213 end
200
214
201 items = menu_items_for(menu_name)
215 items = menu_items_for(menu_name)
202 assert_equal 3, items.size
216 assert_equal 3, items.size
203 end
217 end
204
218
205 def test_menu_items_for_should_skip_unallowed_items_on_a_project
219 def test_menu_items_for_should_skip_unallowed_items_on_a_project
206 menu_name = :test_menu_items_for_should_skip_unallowed_items_on_a_project
220 menu_name = :test_menu_items_for_should_skip_unallowed_items_on_a_project
207 Redmine::MenuManager.map menu_name do |menu|
221 Redmine::MenuManager.map menu_name do |menu|
208 menu.push(:a_menu, {:controller => 'issues', :action => 'index' }, { })
222 menu.push(:a_menu, {:controller => 'issues', :action => 'index' }, { })
209 menu.push(:a_menu_2, {:controller => 'issues', :action => 'index' }, { })
223 menu.push(:a_menu_2, {:controller => 'issues', :action => 'index' }, { })
210 menu.push(:unallowed, {:controller => 'issues', :action => 'unallowed' }, { })
224 menu.push(:unallowed, {:controller => 'issues', :action => 'unallowed' }, { })
211 end
225 end
212
226
213 User.current = User.find(2)
227 User.current = User.find(2)
214
228
215 items = menu_items_for(menu_name, Project.find(1))
229 items = menu_items_for(menu_name, Project.find(1))
216 assert_equal 2, items.size
230 assert_equal 2, items.size
217 end
231 end
218
232
233 def test_menu_items_for_should_skip_items_that_fail_the_permission
234 menu_name = :test_menu_items_for_should_skip_items_that_fail_the_permission
235 Redmine::MenuManager.map menu_name do |menu|
236 menu.push(:a_menu, :project_issues_path)
237 menu.push(:unallowed, :project_issues_path, :permission => :unallowed)
238 end
239
240 User.current = User.find(2)
241
242 items = menu_items_for(menu_name, Project.find(1))
243 assert_equal 1, items.size
244 end
245
219 def test_menu_items_for_should_skip_items_that_fail_the_conditions
246 def test_menu_items_for_should_skip_items_that_fail_the_conditions
220 menu_name = :test_menu_items_for_should_skip_items_that_fail_the_conditions
247 menu_name = :test_menu_items_for_should_skip_items_that_fail_the_conditions
221 Redmine::MenuManager.map menu_name do |menu|
248 Redmine::MenuManager.map menu_name do |menu|
222 menu.push(:a_menu, {:controller => 'issues', :action => 'index' }, { })
249 menu.push(:a_menu, {:controller => 'issues', :action => 'index' }, { })
223 menu.push(:unallowed,
250 menu.push(:unallowed,
224 {:controller => 'issues', :action => 'index' },
251 {:controller => 'issues', :action => 'index' },
225 { :if => Proc.new { false }})
252 { :if => Proc.new { false }})
226 end
253 end
227
254
228 User.current = User.find(2)
255 User.current = User.find(2)
229
256
230 items = menu_items_for(menu_name, Project.find(1))
257 items = menu_items_for(menu_name, Project.find(1))
231 assert_equal 1, items.size
258 assert_equal 1, items.size
232 end
259 end
233 end
260 end
@@ -1,114 +1,108
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2009 Jean-Philippe Lang
2 # Copyright (C) 2006-2009 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 File.expand_path('../../../../../test_helper', __FILE__)
18 require File.expand_path('../../../../../test_helper', __FILE__)
19
19
20 module RedmineMenuTestHelper
20 module RedmineMenuTestHelper
21 # Helpers
21 # Helpers
22 def get_menu_item(menu_name, item_name)
22 def get_menu_item(menu_name, item_name)
23 Redmine::MenuManager.items(menu_name).find {|item| item.name == item_name.to_sym}
23 Redmine::MenuManager.items(menu_name).find {|item| item.name == item_name.to_sym}
24 end
24 end
25 end
25 end
26
26
27 class Redmine::MenuManager::MenuItemTest < ActiveSupport::TestCase
27 class Redmine::MenuManager::MenuItemTest < ActiveSupport::TestCase
28 include RedmineMenuTestHelper
28 include RedmineMenuTestHelper
29
29
30 Redmine::MenuManager.map :test_menu do |menu|
30 Redmine::MenuManager.map :test_menu do |menu|
31 menu.push(:parent, '/test', { })
31 menu.push(:parent, '/test', { })
32 menu.push(:child_menu, '/test', { :parent => :parent})
32 menu.push(:child_menu, '/test', { :parent => :parent})
33 menu.push(:child2_menu, '/test', { :parent => :parent})
33 menu.push(:child2_menu, '/test', { :parent => :parent})
34 end
34 end
35
35
36 # context new menu item
36 # context new menu item
37 def test_new_menu_item_should_require_a_name
37 def test_new_menu_item_should_require_a_name
38 assert_raises ArgumentError do
38 assert_raises ArgumentError do
39 Redmine::MenuManager::MenuItem.new
39 Redmine::MenuManager::MenuItem.new
40 end
40 end
41 end
41 end
42
42
43 def test_new_menu_item_should_require_an_url
43 def test_new_menu_item_should_require_an_url
44 assert_raises ArgumentError do
44 assert_raises ArgumentError do
45 Redmine::MenuManager::MenuItem.new(:test_missing_url)
45 Redmine::MenuManager::MenuItem.new(:test_missing_url)
46 end
46 end
47 end
47 end
48
48
49 def test_new_menu_item_should_require_the_options
50 assert_raises ArgumentError do
51 Redmine::MenuManager::MenuItem.new(:test_missing_options, '/test')
52 end
53 end
54
55 def test_new_menu_item_with_all_required_parameters
49 def test_new_menu_item_with_all_required_parameters
56 assert Redmine::MenuManager::MenuItem.new(:test_good_menu, '/test', {})
50 assert Redmine::MenuManager::MenuItem.new(:test_good_menu, '/test', {})
57 end
51 end
58
52
59 def test_new_menu_item_should_require_a_proc_to_use_for_the_if_condition
53 def test_new_menu_item_should_require_a_proc_to_use_for_the_if_condition
60 assert_raises ArgumentError do
54 assert_raises ArgumentError do
61 Redmine::MenuManager::MenuItem.new(:test_error, '/test',
55 Redmine::MenuManager::MenuItem.new(:test_error, '/test',
62 {
56 {
63 :if => ['not_a_proc']
57 :if => ['not_a_proc']
64 })
58 })
65 end
59 end
66
60
67 assert Redmine::MenuManager::MenuItem.new(:test_good_if, '/test',
61 assert Redmine::MenuManager::MenuItem.new(:test_good_if, '/test',
68 {
62 {
69 :if => Proc.new{}
63 :if => Proc.new{}
70 })
64 })
71 end
65 end
72
66
73 def test_new_menu_item_should_allow_a_hash_for_extra_html_options
67 def test_new_menu_item_should_allow_a_hash_for_extra_html_options
74 assert_raises ArgumentError do
68 assert_raises ArgumentError do
75 Redmine::MenuManager::MenuItem.new(:test_error, '/test',
69 Redmine::MenuManager::MenuItem.new(:test_error, '/test',
76 {
70 {
77 :html => ['not_a_hash']
71 :html => ['not_a_hash']
78 })
72 })
79 end
73 end
80
74
81 assert Redmine::MenuManager::MenuItem.new(:test_good_html, '/test',
75 assert Redmine::MenuManager::MenuItem.new(:test_good_html, '/test',
82 {
76 {
83 :html => { :onclick => 'doSomething'}
77 :html => { :onclick => 'doSomething'}
84 })
78 })
85 end
79 end
86
80
87 def test_new_menu_item_should_require_a_proc_to_use_the_children_option
81 def test_new_menu_item_should_require_a_proc_to_use_the_children_option
88 assert_raises ArgumentError do
82 assert_raises ArgumentError do
89 Redmine::MenuManager::MenuItem.new(:test_error, '/test',
83 Redmine::MenuManager::MenuItem.new(:test_error, '/test',
90 {
84 {
91 :children => ['not_a_proc']
85 :children => ['not_a_proc']
92 })
86 })
93 end
87 end
94
88
95 assert Redmine::MenuManager::MenuItem.new(:test_good_children, '/test',
89 assert Redmine::MenuManager::MenuItem.new(:test_good_children, '/test',
96 {
90 {
97 :children => Proc.new{}
91 :children => Proc.new{}
98 })
92 })
99 end
93 end
100
94
101 def test_new_should_not_allow_setting_the_parent_item_to_the_current_item
95 def test_new_should_not_allow_setting_the_parent_item_to_the_current_item
102 assert_raises ArgumentError do
96 assert_raises ArgumentError do
103 Redmine::MenuManager::MenuItem.new(:test_error, '/test', { :parent => :test_error })
97 Redmine::MenuManager::MenuItem.new(:test_error, '/test', { :parent => :test_error })
104 end
98 end
105 end
99 end
106
100
107 def test_has_children
101 def test_has_children
108 parent_item = get_menu_item(:test_menu, :parent)
102 parent_item = get_menu_item(:test_menu, :parent)
109 assert parent_item.children.present?
103 assert parent_item.children.present?
110 assert_equal 2, parent_item.children.size
104 assert_equal 2, parent_item.children.size
111 assert_equal get_menu_item(:test_menu, :child_menu), parent_item.children[0]
105 assert_equal get_menu_item(:test_menu, :child_menu), parent_item.children[0]
112 assert_equal get_menu_item(:test_menu, :child2_menu), parent_item.children[1]
106 assert_equal get_menu_item(:test_menu, :child2_menu), parent_item.children[1]
113 end
107 end
114 end
108 end
General Comments 0
You need to be logged in to leave comments. Login now