##// END OF EJS Templates
Required file lib/redmine/hook.rb is patching autoloaded ApplicationHelper (#20508)....
Jean-Philippe Lang -
r14128:5626ee94ed8a
parent child
Show More
@@ -1,175 +1,175
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
2 # Copyright (C) 2006-2015 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 Hook
19 module Hook
20 @@listener_classes = []
20 @@listener_classes = []
21 @@listeners = nil
21 @@listeners = nil
22 @@hook_listeners = {}
22 @@hook_listeners = {}
23
23
24 class << self
24 class << self
25 # Adds a listener class.
25 # Adds a listener class.
26 # Automatically called when a class inherits from Redmine::Hook::Listener.
26 # Automatically called when a class inherits from Redmine::Hook::Listener.
27 def add_listener(klass)
27 def add_listener(klass)
28 raise "Hooks must include Singleton module." unless klass.included_modules.include?(Singleton)
28 raise "Hooks must include Singleton module." unless klass.included_modules.include?(Singleton)
29 @@listener_classes << klass
29 @@listener_classes << klass
30 clear_listeners_instances
30 clear_listeners_instances
31 end
31 end
32
32
33 # Returns all the listener instances.
33 # Returns all the listener instances.
34 def listeners
34 def listeners
35 @@listeners ||= @@listener_classes.collect {|listener| listener.instance}
35 @@listeners ||= @@listener_classes.collect {|listener| listener.instance}
36 end
36 end
37
37
38 # Returns the listener instances for the given hook.
38 # Returns the listener instances for the given hook.
39 def hook_listeners(hook)
39 def hook_listeners(hook)
40 @@hook_listeners[hook] ||= listeners.select {|listener| listener.respond_to?(hook)}
40 @@hook_listeners[hook] ||= listeners.select {|listener| listener.respond_to?(hook)}
41 end
41 end
42
42
43 # Clears all the listeners.
43 # Clears all the listeners.
44 def clear_listeners
44 def clear_listeners
45 @@listener_classes = []
45 @@listener_classes = []
46 clear_listeners_instances
46 clear_listeners_instances
47 end
47 end
48
48
49 # Clears all the listeners instances.
49 # Clears all the listeners instances.
50 def clear_listeners_instances
50 def clear_listeners_instances
51 @@listeners = nil
51 @@listeners = nil
52 @@hook_listeners = {}
52 @@hook_listeners = {}
53 end
53 end
54
54
55 # Calls a hook.
55 # Calls a hook.
56 # Returns the listeners response.
56 # Returns the listeners response.
57 def call_hook(hook, context={})
57 def call_hook(hook, context={})
58 [].tap do |response|
58 [].tap do |response|
59 hls = hook_listeners(hook)
59 hls = hook_listeners(hook)
60 if hls.any?
60 if hls.any?
61 hls.each {|listener| response << listener.send(hook, context)}
61 hls.each {|listener| response << listener.send(hook, context)}
62 end
62 end
63 end
63 end
64 end
64 end
65 end
65 end
66
66
67 # Base class for hook listeners.
67 # Base class for hook listeners.
68 class Listener
68 class Listener
69 include Singleton
69 include Singleton
70 include Redmine::I18n
70 include Redmine::I18n
71
71
72 # Registers the listener
72 # Registers the listener
73 def self.inherited(child)
73 def self.inherited(child)
74 Redmine::Hook.add_listener(child)
74 Redmine::Hook.add_listener(child)
75 super
75 super
76 end
76 end
77
77
78 end
78 end
79
79
80 # Listener class used for views hooks.
80 # Listener class used for views hooks.
81 # Listeners that inherit this class will include various helpers by default.
81 # Listeners that inherit this class will include various helpers by default.
82 class ViewListener < Listener
82 class ViewListener < Listener
83 include ERB::Util
83 include ERB::Util
84 include ActionView::Helpers::TagHelper
84 include ActionView::Helpers::TagHelper
85 include ActionView::Helpers::FormHelper
85 include ActionView::Helpers::FormHelper
86 include ActionView::Helpers::FormTagHelper
86 include ActionView::Helpers::FormTagHelper
87 include ActionView::Helpers::FormOptionsHelper
87 include ActionView::Helpers::FormOptionsHelper
88 include ActionView::Helpers::JavaScriptHelper
88 include ActionView::Helpers::JavaScriptHelper
89 include ActionView::Helpers::NumberHelper
89 include ActionView::Helpers::NumberHelper
90 include ActionView::Helpers::UrlHelper
90 include ActionView::Helpers::UrlHelper
91 include ActionView::Helpers::AssetTagHelper
91 include ActionView::Helpers::AssetTagHelper
92 include ActionView::Helpers::TextHelper
92 include ActionView::Helpers::TextHelper
93 include Rails.application.routes.url_helpers
93 include Rails.application.routes.url_helpers
94 include ApplicationHelper
94 include ApplicationHelper
95
95
96 # Default to creating links using only the path. Subclasses can
96 # Default to creating links using only the path. Subclasses can
97 # change this default as needed
97 # change this default as needed
98 def self.default_url_options
98 def self.default_url_options
99 {:only_path => true, :script_name => Redmine::Utils.relative_url_root}
99 {:only_path => true, :script_name => Redmine::Utils.relative_url_root}
100 end
100 end
101
101
102 # Helper method to directly render using the context,
102 # Helper method to directly render using the context,
103 # render_options must be valid #render options.
103 # render_options must be valid #render options.
104 #
104 #
105 # class MyHook < Redmine::Hook::ViewListener
105 # class MyHook < Redmine::Hook::ViewListener
106 # render_on :view_issues_show_details_bottom, :partial => "show_more_data"
106 # render_on :view_issues_show_details_bottom, :partial => "show_more_data"
107 # end
107 # end
108 #
108 #
109 # class MultipleHook < Redmine::Hook::ViewListener
109 # class MultipleHook < Redmine::Hook::ViewListener
110 # render_on :view_issues_show_details_bottom,
110 # render_on :view_issues_show_details_bottom,
111 # {:partial => "show_more_data"},
111 # {:partial => "show_more_data"},
112 # {:partial => "show_even_more_data"}
112 # {:partial => "show_even_more_data"}
113 # end
113 # end
114 #
114 #
115 def self.render_on(hook, *render_options)
115 def self.render_on(hook, *render_options)
116 define_method hook do |context|
116 define_method hook do |context|
117 render_options.map do |options|
117 render_options.map do |options|
118 if context[:hook_caller].respond_to?(:render)
118 if context[:hook_caller].respond_to?(:render)
119 context[:hook_caller].send(:render, {:locals => context}.merge(options))
119 context[:hook_caller].send(:render, {:locals => context}.merge(options))
120 elsif context[:controller].is_a?(ActionController::Base)
120 elsif context[:controller].is_a?(ActionController::Base)
121 context[:controller].send(:render_to_string, {:locals => context}.merge(options))
121 context[:controller].send(:render_to_string, {:locals => context}.merge(options))
122 else
122 else
123 raise "Cannot render #{self.name} hook from #{context[:hook_caller].class.name}"
123 raise "Cannot render #{self.name} hook from #{context[:hook_caller].class.name}"
124 end
124 end
125 end
125 end
126 end
126 end
127 end
127 end
128
128
129 def controller
129 def controller
130 nil
130 nil
131 end
131 end
132
132
133 def config
133 def config
134 ActionController::Base.config
134 ActionController::Base.config
135 end
135 end
136 end
136 end
137
137
138 # Helper module included in ApplicationHelper and ActionController so that
138 # Helper module included in ApplicationHelper and ActionController so that
139 # hooks can be called in views like this:
139 # hooks can be called in views like this:
140 #
140 #
141 # <%= call_hook(:some_hook) %>
141 # <%= call_hook(:some_hook) %>
142 # <%= call_hook(:another_hook, :foo => 'bar') %>
142 # <%= call_hook(:another_hook, :foo => 'bar') %>
143 #
143 #
144 # Or in controllers like:
144 # Or in controllers like:
145 # call_hook(:some_hook)
145 # call_hook(:some_hook)
146 # call_hook(:another_hook, :foo => 'bar')
146 # call_hook(:another_hook, :foo => 'bar')
147 #
147 #
148 # Hooks added to views will be concatenated into a string. Hooks added to
148 # Hooks added to views will be concatenated into a string. Hooks added to
149 # controllers will return an array of results.
149 # controllers will return an array of results.
150 #
150 #
151 # Several objects are automatically added to the call context:
151 # Several objects are automatically added to the call context:
152 #
152 #
153 # * project => current project
153 # * project => current project
154 # * request => Request instance
154 # * request => Request instance
155 # * controller => current Controller instance
155 # * controller => current Controller instance
156 # * hook_caller => object that called the hook
156 # * hook_caller => object that called the hook
157 #
157 #
158 module Helper
158 module Helper
159 def call_hook(hook, context={})
159 def call_hook(hook, context={})
160 if is_a?(ActionController::Base)
160 if is_a?(ActionController::Base)
161 default_context = {:controller => self, :project => @project, :request => request, :hook_caller => self}
161 default_context = {:controller => self, :project => @project, :request => request, :hook_caller => self}
162 Redmine::Hook.call_hook(hook, default_context.merge(context))
162 Redmine::Hook.call_hook(hook, default_context.merge(context))
163 else
163 else
164 default_context = { :project => @project, :hook_caller => self }
164 default_context = { :project => @project, :hook_caller => self }
165 default_context[:controller] = controller if respond_to?(:controller)
165 default_context[:controller] = controller if respond_to?(:controller)
166 default_context[:request] = request if respond_to?(:request)
166 default_context[:request] = request if respond_to?(:request)
167 Redmine::Hook.call_hook(hook, default_context.merge(context)).join(' ').html_safe
167 Redmine::Hook.call_hook(hook, default_context.merge(context)).join(' ').html_safe
168 end
168 end
169 end
169 end
170 end
170 end
171 end
171 end
172 end
172 end
173
173
174 ApplicationHelper.send(:include, Redmine::Hook::Helper)
174 ActionView::Base.send(:include, Redmine::Hook::Helper)
175 ActionController::Base.send(:include, Redmine::Hook::Helper)
175 ActionController::Base.send(:include, Redmine::Hook::Helper)
General Comments 0
You need to be logged in to leave comments. Login now