Project

General

Profile

Patch #4250 » 0002-Add-support-for-unattached-menus-generated-dynamical.patch

Eric Davis, 2009-11-20 00:02

View differences:

lib/redmine/menu_manager.rb
95 95

  
96 96
module Redmine
97 97
  module MenuManager
98
    class MenuError < StandardError #:nodoc:
99
    end
100
    
98 101
    module MenuController
99 102
      def self.included(base)
100 103
        base.extend(ClassMethods)
......
164 167
      end
165 168

  
166 169
      def render_menu_node(node, project=nil)
170
        if node.hasChildren? || !node.child_menus.nil?
171
          return render_menu_node_with_children(node, project)
172
        else
173
          caption, url, selected = extract_node_details(node, project)
174
          return content_tag('li',
175
                               render_single_menu_node(node, caption, url, selected))
176
        end
177
      end
178

  
179
      def render_menu_node_with_children(node, project=nil)
167 180
        caption, url, selected = extract_node_details(node, project)
168
        if node.hasChildren?
169
          html = []
181

  
182
        html = returning [] do |html|
170 183
          html << '<li>'
171
          html << render_single_menu_node(node, caption, url, selected) # parent
172
          html << '  <ul>'
173
          node.children.each do |child|
174
            html << render_menu_node(child, project)
184
          # Parent
185
          html << render_single_menu_node(node, caption, url, selected)
186

  
187
          # Standard children
188
          standard_children_list = returning "" do |child_html|
189
            node.children.each do |child|
190
              child_html << render_menu_node(child, project)
191
            end
175 192
          end
176
          html << '  </ul>'
193

  
194
          html << content_tag(:ul, standard_children_list, :class => 'menu-children') unless standard_children_list.empty?
195

  
196
          # Unattached children
197
          unattached_children_list = render_unattached_children_menu(node, project)
198
          html << content_tag(:ul, unattached_children_list, :class => 'menu-children unattached') unless unattached_children_list.blank?
199

  
177 200
          html << '</li>'
178
          return html.join("\n")
179
        else
180
          return content_tag('li',
181
                               render_single_menu_node(node, caption, url, selected))
201
        end
202
        return html.join("\n")
203
      end
204

  
205
      # Returns a list of unattached children menu items
206
      def render_unattached_children_menu(node, project)
207
        return nil unless node.child_menus
208

  
209
        returning "" do |child_html|
210
          unattached_children = node.child_menus.call(project)
211
          # Tree nodes support #each so we need to do object detection
212
          if unattached_children.is_a? Array
213
            unattached_children.each do |child|
214
              child_html << content_tag(:li, render_unattached_menu_item(child, project)) 
215
            end
216
          else
217
            raise MenuError, ":child_menus must be an array of MenuItems"
218
          end
182 219
        end
183 220
      end
184 221

  
185 222
      def render_single_menu_node(item, caption, url, selected)
186 223
        link_to(h(caption), url, item.html_options(:selected => selected))
187 224
      end
225

  
226
      def render_unattached_menu_item(menu_item, project)
227
        raise MenuError, ":child_menus must be an array of MenuItems" unless menu_item.is_a? MenuItem
228

  
229
        if User.current.allowed_to?(menu_item.url, project)
230
          link_to(h(menu_item.caption),
231
                  menu_item.url,
232
                  menu_item.html_options)
233
        end
234
      end
188 235
      
189 236
      def menu_items_for(menu, project=nil)
190 237
        items = []
......
336 383
    
337 384
    class MenuItem < Tree::TreeNode
338 385
      include Redmine::I18n
339
      attr_reader :name, :url, :param, :condition, :parent_menu
386
      attr_reader :name, :url, :param, :condition, :parent_menu, :child_menus
340 387
      
341 388
      def initialize(name, url, options)
342 389
        raise ArgumentError, "Invalid option :if for menu item '#{name}'" if options[:if] && !options[:if].respond_to?(:call)
343 390
        raise ArgumentError, "Invalid option :html for menu item '#{name}'" if options[:html] && !options[:html].is_a?(Hash)
344 391
        raise ArgumentError, "Cannot set the :parent_menu to be the same as this item" if options[:parent_menu] == name.to_sym
392
        raise ArgumentError, "Invalid option :child_menus for menu item '#{name}'" if options[:child_menus] && !options[:child_menus].respond_to?(:call)
345 393
        @name = name
346 394
        @url = url
347 395
        @condition = options[:if]
......
351 399
        # Adds a unique class to each menu item based on its name
352 400
        @html_options[:class] = [@html_options[:class], @name.to_s.dasherize].compact.join(' ')
353 401
        @parent_menu = options[:parent_menu]
402
        @child_menus = options[:child_menus]
354 403
        super @name.to_sym
355 404
      end
356 405
      
test/unit/lib/redmine/menu_manager/menu_helper_test.rb
101 101
    
102 102
  end
103 103

  
104
  def test_render_menu_node_with_child_menus
105
    User.current = User.find(2)
106
    
107
    parent_node = Redmine::MenuManager::MenuItem.new(:parent_node,
108
                                                     '/test',
109
                                                     {
110
                                                       :child_menus => Proc.new {|p|
111
                                                         child_menus = []
112
                                                         3.times do |time|
113
                                                           child_menus << Redmine::MenuManager::MenuItem.new("test_child_#{time}",
114
                                                                                                             {:controller => 'issues', :action => 'index'},
115
                                                                                                             {})
116
                                                         end
117
                                                         child_menus
118
                                                       }
119
                                                     })
120
    @response.body = render_menu_node(parent_node, Project.find(1))
121

  
122
    assert_select("li") do
123
      assert_select("a.parent-node", "Parent node")
124
      assert_select("ul") do
125
        assert_select("li a.test-child-0", "Test child 0")
126
        assert_select("li a.test-child-1", "Test child 1")
127
        assert_select("li a.test-child-2", "Test child 2")
128
      end
129
    end
130
  end
131

  
132
  def test_render_menu_node_with_nested_items_and_child_menus
133
    User.current = User.find(2)
134

  
135
    parent_node = Redmine::MenuManager::MenuItem.new(:parent_node,
136
                                                     '/test',
137
                                                     {
138
                                                       :child_menus => Proc.new {|p|
139
                                                         child_menus = []
140
                                                         3.times do |time|
141
                                                           child_menus << Redmine::MenuManager::MenuItem.new("test_child_#{time}", {:controller => 'issues', :action => 'index'}, {})
142
                                                         end
143
                                                         child_menus
144
                                                       }
145
                                                     })
146

  
147
    parent_node << Redmine::MenuManager::MenuItem.new(:child_node,
148
                                                     '/test',
149
                                                     {
150
                                                       :child_menus => Proc.new {|p|
151
                                                         child_menus = []
152
                                                         6.times do |time|
153
                                                            child_menus << Redmine::MenuManager::MenuItem.new("test_dynamic_child_#{time}", {:controller => 'issues', :action => 'index'}, {})
154
                                                         end
155
                                                         child_menus
156
                                                       }
157
                                                     })
158

  
159
    @response.body = render_menu_node(parent_node, Project.find(1))
160

  
161
    assert_select("li") do
162
      assert_select("a.parent-node", "Parent node")
163
      assert_select("ul") do
164
        assert_select("li a.child-node", "Child node")
165
        assert_select("ul") do
166
          assert_select("li a.test-dynamic-child-0", "Test dynamic child 0")
167
          assert_select("li a.test-dynamic-child-1", "Test dynamic child 1")
168
          assert_select("li a.test-dynamic-child-2", "Test dynamic child 2")
169
          assert_select("li a.test-dynamic-child-3", "Test dynamic child 3")
170
          assert_select("li a.test-dynamic-child-4", "Test dynamic child 4")
171
          assert_select("li a.test-dynamic-child-5", "Test dynamic child 5")
172
        end
173
        assert_select("li a.test-child-0", "Test child 0")
174
        assert_select("li a.test-child-1", "Test child 1")
175
        assert_select("li a.test-child-2", "Test child 2")
176
      end
177
    end
178
  end
179

  
180
  def test_render_menu_node_with_child_menus_without_an_array
181
    parent_node = Redmine::MenuManager::MenuItem.new(:parent_node,
182
                                                     '/test',
183
                                                     {
184
                                                       :child_menus => Proc.new {|p| Redmine::MenuManager::MenuItem.new("test_child", "/testing", {})}
185
                                                     })
186

  
187
    assert_raises Redmine::MenuManager::MenuError, ":child_menus must be an array of MenuItems" do
188
      @response.body = render_menu_node(parent_node, Project.find(1))
189
    end
190
  end
191
    
192
  def test_render_menu_node_with_incorrect_child_menus
193
    parent_node = Redmine::MenuManager::MenuItem.new(:parent_node,
194
                                                     '/test',
195
                                                     {
196
                                                       :child_menus => Proc.new {|p| ["a string"] }
197
                                                     })
198

  
199
    assert_raises Redmine::MenuManager::MenuError, ":child_menus must be an array of MenuItems" do
200
      @response.body = render_menu_node(parent_node, Project.find(1))
201
    end
202

  
203
  end
204

  
104 205
  def test_menu_items_for_should_yield_all_items_if_passed_a_block
105 206
    menu_name = :test_menu_items_for_should_yield_all_items_if_passed_a_block
106 207
    Redmine::MenuManager.map menu_name do |menu|
test/unit/lib/redmine/menu_manager/menu_item_test.rb
92 92
                                              })
93 93
  end
94 94

  
95
  def test_new_menu_item_should_require_a_proc_to_use_the_child_menus_option
96
    assert_raises ArgumentError do
97
      Redmine::MenuManager::MenuItem.new(:test_error, '/test',
98
                                         {
99
                                           :child_menus => ['not_a_proc']
100
                                         })
101
    end
102

  
103
    assert Redmine::MenuManager::MenuItem.new(:test_good_child_menus, '/test',
104
                                              {
105
                                                :child_menus => Proc.new{}
106
                                              })
107
  end
108

  
95 109
  def test_new_should_not_allow_setting_the_parent_menu_item_to_the_current_item
96 110
    assert_raises ArgumentError do
97 111
      Redmine::MenuManager::MenuItem.new(:test_error, '/test', { :parent_menu => :test_error })
test/unit/lib/redmine/menu_manager_test.rb
25 25
  context "MenuManager#items" do
26 26
    should "be tested"
27 27
  end
28

  
29
  should "be tested" do
30
    assert true
31
  end
28 32
end
(2-2/3)