##// END OF EJS Templates
Menus items:...
Jean-Philippe Lang -
r1158:792b7f30e32e
parent child
Show More
@@ -1,25 +1,25
1 1 # Redmine sample plugin
2 2 require 'redmine'
3 3
4 4 RAILS_DEFAULT_LOGGER.info 'Starting Example plugin for RedMine'
5 5
6 6 Redmine::Plugin.register :sample_plugin do
7 7 name 'Example plugin'
8 8 author 'Author name'
9 9 description 'This is a sample plugin for Redmine'
10 10 version '0.0.1'
11 11 settings :default => {'sample_setting' => 'value', 'foo'=>'bar'}, :partial => 'settings/settings'
12 12
13 13 # This plugin adds a project module
14 14 # It can be enabled/disabled at project level (Project settings -> Modules)
15 15 project_module :example_module do
16 16 # A public action
17 17 permission :example_say_hello, {:example => [:say_hello]}, :public => true
18 18 # This permission has to be explicitly given
19 19 # It will be listed on the permissions screen
20 20 permission :example_say_goodbye, {:example => [:say_goodbye]}
21 21 end
22 22
23 23 # A new item is added to the project menu
24 menu :project_menu, :label_plugin_example, :controller => 'example', :action => 'say_hello'
24 menu :project_menu, :sample_plugin, { :controller => 'example', :action => 'say_hello' }, :caption => 'Sample'
25 25 end
@@ -1,139 +1,144
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 module Redmine
19 19 module MenuManager
20 20 module MenuController
21 21 def self.included(base)
22 22 base.extend(ClassMethods)
23 23 end
24 24
25 25 module ClassMethods
26 26 @@menu_items = Hash.new {|hash, key| hash[key] = {:default => key, :actions => {}}}
27 27 mattr_accessor :menu_items
28 28
29 29 # Set the menu item name for a controller or specific actions
30 30 # Examples:
31 31 # * menu_item :tickets # => sets the menu name to :tickets for the whole controller
32 32 # * menu_item :tickets, :only => :list # => sets the menu name to :tickets for the 'list' action only
33 33 # * menu_item :tickets, :only => [:list, :show] # => sets the menu name to :tickets for 2 actions only
34 34 #
35 35 # The default menu item name for a controller is controller_name by default
36 36 # Eg. the default menu item name for ProjectsController is :projects
37 37 def menu_item(id, options = {})
38 38 if actions = options[:only]
39 39 actions = [] << actions unless actions.is_a?(Array)
40 40 actions.each {|a| menu_items[controller_name.to_sym][:actions][a.to_sym] = id}
41 41 else
42 42 menu_items[controller_name.to_sym][:default] = id
43 43 end
44 44 end
45 45 end
46 46
47 47 def menu_items
48 48 self.class.menu_items
49 49 end
50 50
51 51 # Returns the menu item name according to the current action
52 52 def current_menu_item
53 53 menu_items[controller_name.to_sym][:actions][action_name.to_sym] ||
54 54 menu_items[controller_name.to_sym][:default]
55 55 end
56 56 end
57 57
58 58 module MenuHelper
59 59 # Returns the current menu item name
60 60 def current_menu_item
61 61 @controller.current_menu_item
62 62 end
63 63
64 64 # Renders the application main menu
65 65 def render_main_menu(project)
66 66 render_menu((project && !project.new_record?) ? :project_menu : :application_menu, project)
67 67 end
68 68
69 69 def render_menu(menu, project=nil)
70 70 links = []
71 71 Redmine::MenuManager.allowed_items(menu, User.current, project).each do |item|
72 72 unless item.condition && !item.condition.call(project)
73 73 url = case item.url
74 74 when Hash
75 75 project.nil? ? item.url : {item.param => project}.merge(item.url)
76 76 when Symbol
77 77 send(item.url)
78 78 else
79 79 item.url
80 80 end
81 81 #url = (project && item.url.is_a?(Hash)) ? {item.param => project}.merge(item.url) : (item.url.is_a?(Symbol) ? send(item.url) : item.url)
82 82 links << content_tag('li',
83 83 link_to(l(item.caption), url, (current_menu_item == item.name ? item.html_options.merge(:class => 'selected') : item.html_options)))
84 84 end
85 85 end
86 86 links.empty? ? nil : content_tag('ul', links.join("\n"))
87 87 end
88 88 end
89 89
90 90 class << self
91 91 def map(menu_name)
92 92 mapper = Mapper.new
93 93 yield mapper
94 94 @items ||= {}
95 95 @items[menu_name.to_sym] ||= []
96 96 @items[menu_name.to_sym] += mapper.items
97 97 end
98 98
99 99 def items(menu_name)
100 100 @items[menu_name.to_sym] || []
101 101 end
102 102
103 103 def allowed_items(menu_name, user, project)
104 104 project ? items(menu_name).select {|item| user && user.allowed_to?(item.url, project)} : items(menu_name)
105 105 end
106 106 end
107 107
108 108 class Mapper
109 109 # Adds an item at the end of the menu. Available options:
110 110 # * param: the parameter name that is used for the project id (default is :id)
111 111 # * if: a proc that is called before rendering the item, the item is displayed only if it returns true
112 112 # * caption: the localized string key that is used as the item label
113 113 # * html_options: a hash of html options that are passed to link_to
114 114 def push(name, url, options={})
115 115 items << MenuItem.new(name, url, options)
116 116 end
117 117
118 118 def items
119 119 @items ||= []
120 120 end
121 121 end
122 122
123 123 class MenuItem
124 124 include GLoc
125 attr_reader :name, :url, :param, :condition, :caption, :html_options
125 attr_reader :name, :url, :param, :condition, :html_options
126 126
127 127 def initialize(name, url, options)
128 128 raise "Invalid option :if for menu item '#{name}'" if options[:if] && !options[:if].respond_to?(:call)
129 129 raise "Invalid option :html for menu item '#{name}'" if options[:html] && !options[:html].is_a?(Hash)
130 130 @name = name
131 131 @url = url
132 132 @condition = options[:if]
133 133 @param = options[:param] || :id
134 @caption = options[:caption] || (l_has_string?("label_#{name}".to_sym) ? "label_#{name}".to_sym : name.to_s.humanize)
134 @caption_key = options[:caption]
135 135 @html_options = options[:html] || {}
136 136 end
137
138 def caption
139 # check if localized string exists on first render (after GLoc strings are loaded)
140 @caption ||= (@caption_key || (l_has_string?("label_#{@name}".to_sym) ? "label_#{@name}".to_sym : @name.to_s.humanize))
141 end
137 142 end
138 143 end
139 144 end
@@ -1,124 +1,125
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 module Redmine #:nodoc:
19 19
20 20 # Base class for Redmine plugins.
21 21 # Plugins are registered using the <tt>register</tt> class method that acts as the public constructor.
22 22 #
23 23 # Redmine::Plugin.register :example do
24 24 # name 'Example plugin'
25 25 # author 'John Smith'
26 26 # description 'This is an example plugin for Redmine'
27 27 # version '0.0.1'
28 28 # settings :default => {'foo'=>'bar'}, :partial => 'settings/settings'
29 29 # end
30 30 #
31 31 # === Plugin attributes
32 32 #
33 33 # +settings+ is an optional attribute that let the plugin be configurable.
34 34 # It must be a hash with the following keys:
35 35 # * <tt>:default</tt>: default value for the plugin settings
36 36 # * <tt>:partial</tt>: path of the configuration partial view, relative to the plugin <tt>app/views</tt> directory
37 37 # Example:
38 38 # settings :default => {'foo'=>'bar'}, :partial => 'settings/settings'
39 39 # In this example, the settings partial will be found here in the plugin directory: <tt>app/views/settings/_settings.rhtml</tt>.
40 40 #
41 41 # When rendered, the plugin settings value is available as the local variable +settings+
42 42 class Plugin
43 43 @registered_plugins = {}
44 44 class << self
45 45 attr_reader :registered_plugins
46 46 private :new
47 47
48 48 def def_field(*names)
49 49 class_eval do
50 50 names.each do |name|
51 51 define_method(name) do |*args|
52 52 args.empty? ? instance_variable_get("@#{name}") : instance_variable_set("@#{name}", *args)
53 53 end
54 54 end
55 55 end
56 56 end
57 57 end
58 58 def_field :name, :description, :author, :version, :settings
59 59
60 60 # Plugin constructor
61 61 def self.register(name, &block)
62 62 p = new
63 63 p.instance_eval(&block)
64 64 Plugin.registered_plugins[name] = p
65 65 end
66 66
67 67 # Adds an item to the given +menu+.
68 68 # The +id+ parameter (equals to the project id) is automatically added to the url.
69 # menu :project_menu, :label_plugin_example, :controller => 'example', :action => 'say_hello'
69 # menu :project_menu, :plugin_example, { :controller => 'example', :action => 'say_hello' }, :caption => 'Sample'
70 70 #
71 # Currently, only the project menu can be extended. Thus, the +name+ parameter must be +:project_menu+
72 def menu(name, label, url)
73 Redmine::MenuManager.map(name) {|menu| menu.push label, url}
71 # +name+ parameter can be: :top_menu, :account_menu, :application_menu or :project_menu
72 #
73 def menu(name, item, url, options={})
74 Redmine::MenuManager.map(name) {|menu| menu.push item, url, options}
74 75 end
75 76
76 77 # Defines a permission called +name+ for the given +actions+.
77 78 #
78 79 # The +actions+ argument is a hash with controllers as keys and actions as values (a single value or an array):
79 80 # permission :destroy_contacts, { :contacts => :destroy }
80 81 # permission :view_contacts, { :contacts => [:index, :show] }
81 82 #
82 83 # The +options+ argument can be used to make the permission public (implicitly given to any user)
83 84 # or to restrict users the permission can be given to.
84 85 #
85 86 # Examples
86 87 # # A permission that is implicitly given to any user
87 88 # # This permission won't appear on the Roles & Permissions setup screen
88 89 # permission :say_hello, { :example => :say_hello }, :public => true
89 90 #
90 91 # # A permission that can be given to any user
91 92 # permission :say_hello, { :example => :say_hello }
92 93 #
93 94 # # A permission that can be given to registered users only
94 95 # permission :say_hello, { :example => :say_hello }, :require => loggedin
95 96 #
96 97 # # A permission that can be given to project members only
97 98 # permission :say_hello, { :example => :say_hello }, :require => member
98 99 def permission(name, actions, options = {})
99 100 if @project_module
100 101 Redmine::AccessControl.map {|map| map.project_module(@project_module) {|map|map.permission(name, actions, options)}}
101 102 else
102 103 Redmine::AccessControl.map {|map| map.permission(name, actions, options)}
103 104 end
104 105 end
105 106
106 107 # Defines a project module, that can be enabled/disabled for each project.
107 108 # Permissions defined inside +block+ will be bind to the module.
108 109 #
109 110 # project_module :things do
110 111 # permission :view_contacts, { :contacts => [:list, :show] }, :public => true
111 112 # permission :destroy_contacts, { :contacts => :destroy }
112 113 # end
113 114 def project_module(name, &block)
114 115 @project_module = name
115 116 self.instance_eval(&block)
116 117 @project_module = nil
117 118 end
118 119
119 120 # Returns +true+ if the plugin can be configured.
120 121 def configurable?
121 122 settings && settings.is_a?(Hash) && !settings[:partial].blank?
122 123 end
123 124 end
124 125 end
General Comments 0
You need to be logged in to leave comments. Login now