From b8e8678e924db478d64346d8d2dbbbde6316a7a8 Mon Sep 17 00:00:00 2001 From: Stephan Eckardt Date: Fri, 25 Nov 2011 14:52:33 +0100 Subject: [PATCH] [#731] Changes the MenuManager to be more dynamic --- lib/redmine/menu_manager.rb | 22 +++++++++++----- lib/redmine/menu_manager/mapper.rb | 18 +++++++++++++ lib/redmine/plugin.rb | 12 ++++++--- .../lib/redmine/menu_manager_test.rb | 26 +++++++++++++++++++ 4 files changed, 67 insertions(+), 11 deletions(-) diff --git a/lib/redmine/menu_manager.rb b/lib/redmine/menu_manager.rb index 5948ba6588..b17a063603 100644 --- a/lib/redmine/menu_manager.rb +++ b/lib/redmine/menu_manager.rb @@ -13,17 +13,25 @@ #++ module Redmine::MenuManager - def self.map(menu_name) - @items ||= {} - mapper = Mapper.new(menu_name.to_sym, @items) - if block_given? - yield mapper + def self.map(menu_name, &menu_builder) + @menu_builder_queues ||= {} + current_queue = @menu_builder_queues[menu_name.to_sym] ||= [] + + if menu_builder + current_queue.push menu_builder else - mapper + MapDeferrer.new current_queue end end def self.items(menu_name) - @items[menu_name.to_sym] || Redmine::MenuManager::TreeNode.new(:root, {}) + items = {} + + mapper = Mapper.new(menu_name.to_sym, items) + @menu_builder_queues[menu_name.to_sym].each do |menu_builder| + menu_builder.call(mapper) + end + + items[menu_name.to_sym] || Redmine::MenuManager::TreeNode.new(:root, {}) end end diff --git a/lib/redmine/menu_manager/mapper.rb b/lib/redmine/menu_manager/mapper.rb index 6a9451f165..d1aceb2112 100644 --- a/lib/redmine/menu_manager/mapper.rb +++ b/lib/redmine/menu_manager/mapper.rb @@ -99,3 +99,21 @@ class Redmine::MenuManager::Mapper end end end + +class Redmine::MenuManager::MapDeferrer + def initialize(menu_builder_queue) + @menu_builder_queue = menu_builder_queue + end + + def defer(method, *args) + ActiveSupport::Deprecation.warn "Calling #{method.to_s} and accessing the the menu object from outside of the block attached to the map method is deprecated and will be removed in ChiliProject 3.0. Please access the menu object from within the attached block instead. Please also note the differences between the APIs.", caller.drop(1) + menu_builder = proc{ |menu_mapper| menu_mapper.send(method, *args) } + @menu_builder_queue.push(menu_builder) + end + + [:push, :delete, :exists?, :find, :position_of].each do |method| + define_method method do |*args| + defer(method, *args) + end + end +end \ No newline at end of file diff --git a/lib/redmine/plugin.rb b/lib/redmine/plugin.rb index 3053d5d79a..3842b594df 100644 --- a/lib/redmine/plugin.rb +++ b/lib/redmine/plugin.rb @@ -252,14 +252,18 @@ module Redmine #:nodoc: # # +name+ parameter can be: :top_menu, :account_menu, :application_menu or :project_menu # - def menu(menu, item, url, options={}) - Redmine::MenuManager.map(menu).push(item, url, options) + def menu(menu_name, item, url, options={}) + Redmine::MenuManager.map(menu_name) do |menu| + menu.push(item, url, options) + end end alias :add_menu_item :menu # Removes +item+ from the given +menu+. - def delete_menu_item(menu, item) - Redmine::MenuManager.map(menu).delete(item) + def delete_menu_item(menu_name, item) + Redmine::MenuManager.map(menu_name) do |menu| + menu.delete(item) + end end # Defines a permission called +name+ for the given +actions+. diff --git a/test/integration/lib/redmine/menu_manager_test.rb b/test/integration/lib/redmine/menu_manager_test.rb index a60ef3cc65..2c8d8d2e9f 100644 --- a/test/integration/lib/redmine/menu_manager_test.rb +++ b/test/integration/lib/redmine/menu_manager_test.rb @@ -63,4 +63,30 @@ class MenuManagerTest < ActionController::IntegrationTest end end end + + def test_dynamic_menu + list = [] + Redmine::MenuManager.map :some_menu do |menu| + list.each do |item| + menu.push item[:name], item[:url], item[:options] + end + end + + base_size = Redmine::MenuManager.items(:some_menu).size + list.push({ :name => :foo, :url => {:controller => 'projects', :action => 'show'}, :options => {:caption => 'Foo'}}) + assert_equal base_size + 1, Redmine::MenuManager.items(:some_menu).size + list.push({ :name => :bar, :url => {:controller => 'projects', :action => 'show'}, :options => {:caption => 'Bar'}}) + assert_equal base_size + 2, Redmine::MenuManager.items(:some_menu).size + list.push({ :name => :hello, :url => {:controller => 'projects', :action => 'show'}, :options => {:caption => 'Hello'}}) + assert_equal base_size + 3, Redmine::MenuManager.items(:some_menu).size + list.pop + assert_equal base_size + 2, Redmine::MenuManager.items(:some_menu).size + end + + def test_dynamic_menu_map_deferred + assert_no_difference 'Redmine::MenuManager.items(:some_menu).size' do + Redmine::MenuManager.map(:some_other_menu).push :baz, {:controller => 'projects', :action => 'show'}, :caption => 'Baz' + Redmine::MenuManager.map(:some_other_menu).delete :baz + end + end end