;]
[askyou.git] / lib / redmine / hook.rb
blob7f4b6e07e74ad1251e8e4037257db1a6fd360690
1 # Redmine - project management software
2 # Copyright (C) 2006-2008  Jean-Philippe Lang
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
8
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13
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
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 module Redmine
19   module Hook
20     include ActionController::UrlWriter
22     @@listener_classes = []
23     @@listeners = nil
24     @@hook_listeners = {}
25     
26     class << self
27       # Adds a listener class.
28       # Automatically called when a class inherits from Redmine::Hook::Listener.
29       def add_listener(klass)
30         raise "Hooks must include Singleton module." unless klass.included_modules.include?(Singleton)
31         @@listener_classes << klass
32         clear_listeners_instances
33       end
34       
35       # Returns all the listerners instances.
36       def listeners
37         @@listeners ||= @@listener_classes.collect {|listener| listener.instance}
38       end
40       # Returns the listeners instances for the given hook.
41       def hook_listeners(hook)
42         @@hook_listeners[hook] ||= listeners.select {|listener| listener.respond_to?(hook)}
43       end
44       
45       # Clears all the listeners.
46       def clear_listeners
47         @@listener_classes = []
48         clear_listeners_instances
49       end
50       
51       # Clears all the listeners instances.
52       def clear_listeners_instances
53         @@listeners = nil
54         @@hook_listeners = {}
55       end
56       
57       # Calls a hook.
58       # Returns the listeners response.
59       def call_hook(hook, context={})
60         returning [] do |response|
61           hls = hook_listeners(hook)
62           if hls.any?
63             hls.each {|listener| response << listener.send(hook, context)}
64           end
65         end
66       end
67     end
69     # Base class for hook listeners.
70     class Listener
71       include Singleton
72       include Redmine::I18n
74       # Registers the listener
75       def self.inherited(child)
76         Redmine::Hook.add_listener(child)
77         super
78       end
80     end
82     # Listener class used for views hooks.
83     # Listeners that inherit this class will include various helpers by default.
84     class ViewListener < Listener
85       include ERB::Util
86       include ActionView::Helpers::TagHelper
87       include ActionView::Helpers::FormHelper
88       include ActionView::Helpers::FormTagHelper
89       include ActionView::Helpers::FormOptionsHelper
90       include ActionView::Helpers::JavaScriptHelper
91       include ActionView::Helpers::PrototypeHelper
92       include ActionView::Helpers::NumberHelper
93       include ActionView::Helpers::UrlHelper
94       include ActionView::Helpers::AssetTagHelper
95       include ActionView::Helpers::TextHelper
96       include ActionController::UrlWriter
97       include ApplicationHelper
99       # Default to creating links using only the path.  Subclasses can
100       # change this default as needed
101       def self.default_url_options
102         {:only_path => true }
103       end
104       
105       # Helper method to directly render a partial using the context:
106       # 
107       #   class MyHook < Redmine::Hook::ViewListener
108       #     render_on :view_issues_show_details_bottom, :partial => "show_more_data" 
109       #   end
110       #
111       def self.render_on(hook, options={})
112         define_method hook do |context|
113           context[:controller].send(:render_to_string, {:locals => context}.merge(options))
114         end
115       end
116     end
118     # Helper module included in ApplicationHelper and ActionControllerso that
119     # hooks can be called in views like this:
120     # 
121     #   <%= call_hook(:some_hook) %>
122     #   <%= call_hook(:another_hook, :foo => 'bar' %>
123     # 
124     # Or in controllers like:
125     #   call_hook(:some_hook)
126     #   call_hook(:another_hook, :foo => 'bar'
127     # 
128     # Hooks added to views will be concatenated into a string.  Hooks added to
129     # controllers will return an array of results.
130     #
131     # Several objects are automatically added to the call context:
132     # 
133     # * project => current project
134     # * request => Request instance
135     # * controller => current Controller instance
136     # 
137     module Helper
138       def call_hook(hook, context={})
139         if is_a?(ActionController::Base)
140           default_context = {:controller => self, :project => @project, :request => request}
141           Redmine::Hook.call_hook(hook, default_context.merge(context))
142         else
143           default_context = {:controller => controller, :project => @project, :request => request}
144           Redmine::Hook.call_hook(hook, default_context.merge(context)).join(' ')
145         end        
146       end
147     end
148   end
151 ApplicationHelper.send(:include, Redmine::Hook::Helper)
152 ActionController::Base.send(:include, Redmine::Hook::Helper)