diff options
author | Eric Davis <edavis@littlestreamsoftware.com> | 2009-11-25 05:36:50 +0000 |
---|---|---|
committer | Eric Davis <edavis@littlestreamsoftware.com> | 2009-11-25 05:36:50 +0000 |
commit | b0999e3764f0554d40d243f273f23fe53e164066 (patch) | |
tree | 6ad211b83516bf9db17d7bf84af8794875a760e9 /lib | |
parent | 1f06cf889990d9640f7160c4969ed074fb68a7ca (diff) | |
download | redmine-b0999e3764f0554d40d243f273f23fe53e164066.tar.gz redmine-b0999e3764f0554d40d243f273f23fe53e164066.zip |
Add support for unattached menus (generated dynamically)
A MenuItem can define a :child_menus option with a Proc. When the menus
are rendered, the Proc will be run and the resulting MenuItems will be
added to the page as child menus
#4250
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@3091 e93f8b46-1217-0410-a6f0-8f06a7374b81
Diffstat (limited to 'lib')
-rw-r--r-- | lib/redmine/menu_manager.rb | 73 |
1 files changed, 61 insertions, 12 deletions
diff --git a/lib/redmine/menu_manager.rb b/lib/redmine/menu_manager.rb index debcdd143..320d4a655 100644 --- a/lib/redmine/menu_manager.rb +++ b/lib/redmine/menu_manager.rb @@ -95,6 +95,9 @@ Tree::TreeNode.send(:include, TreeNodePatch) module Redmine module MenuManager + class MenuError < StandardError #:nodoc: + end + module MenuController def self.included(base) base.extend(ClassMethods) @@ -164,27 +167,71 @@ module Redmine end def render_menu_node(node, project=nil) + if node.hasChildren? || !node.child_menus.nil? + return render_menu_node_with_children(node, project) + else + caption, url, selected = extract_node_details(node, project) + return content_tag('li', + render_single_menu_node(node, caption, url, selected)) + end + end + + def render_menu_node_with_children(node, project=nil) caption, url, selected = extract_node_details(node, project) - if node.hasChildren? - html = [] + + html = returning [] do |html| html << '<li>' - html << render_single_menu_node(node, caption, url, selected) # parent - html << ' <ul>' - node.children.each do |child| - html << render_menu_node(child, project) + # Parent + html << render_single_menu_node(node, caption, url, selected) + + # Standard children + standard_children_list = returning "" do |child_html| + node.children.each do |child| + child_html << render_menu_node(child, project) + end end - html << ' </ul>' + + html << content_tag(:ul, standard_children_list, :class => 'menu-children') unless standard_children_list.empty? + + # Unattached children + unattached_children_list = render_unattached_children_menu(node, project) + html << content_tag(:ul, unattached_children_list, :class => 'menu-children unattached') unless unattached_children_list.blank? + html << '</li>' - return html.join("\n") - else - return content_tag('li', - render_single_menu_node(node, caption, url, selected)) + end + return html.join("\n") + end + + # Returns a list of unattached children menu items + def render_unattached_children_menu(node, project) + return nil unless node.child_menus + + returning "" do |child_html| + unattached_children = node.child_menus.call(project) + # Tree nodes support #each so we need to do object detection + if unattached_children.is_a? Array + unattached_children.each do |child| + child_html << content_tag(:li, render_unattached_menu_item(child, project)) + end + else + raise MenuError, ":child_menus must be an array of MenuItems" + end end end def render_single_menu_node(item, caption, url, selected) link_to(h(caption), url, item.html_options(:selected => selected)) end + + def render_unattached_menu_item(menu_item, project) + raise MenuError, ":child_menus must be an array of MenuItems" unless menu_item.is_a? MenuItem + + if User.current.allowed_to?(menu_item.url, project) + link_to(h(menu_item.caption), + menu_item.url, + menu_item.html_options) + end + end def menu_items_for(menu, project=nil) items = [] @@ -336,12 +383,13 @@ module Redmine class MenuItem < Tree::TreeNode include Redmine::I18n - attr_reader :name, :url, :param, :condition, :parent_menu + attr_reader :name, :url, :param, :condition, :parent_menu, :child_menus def initialize(name, url, options) raise ArgumentError, "Invalid option :if for menu item '#{name}'" if options[:if] && !options[:if].respond_to?(:call) raise ArgumentError, "Invalid option :html for menu item '#{name}'" if options[:html] && !options[:html].is_a?(Hash) raise ArgumentError, "Cannot set the :parent_menu to be the same as this item" if options[:parent_menu] == name.to_sym + raise ArgumentError, "Invalid option :child_menus for menu item '#{name}'" if options[:child_menus] && !options[:child_menus].respond_to?(:call) @name = name @url = url @condition = options[:if] @@ -351,6 +399,7 @@ module Redmine # Adds a unique class to each menu item based on its name @html_options[:class] = [@html_options[:class], @name.to_s.dasherize].compact.join(' ') @parent_menu = options[:parent_menu] + @child_menus = options[:child_menus] super @name.to_sym end |