##// END OF EJS Templates
Adds url and author_url plugin attributes (#2162)....
Jean-Philippe Lang -
r2039:5362a85f2bd7
parent child
Show More
@@ -1,17 +1,19
1 <h2><%= l(:label_plugins) %></h2>
1 <h2><%= l(:label_plugins) %></h2>
2
2
3 <% if @plugins.any? %>
3 <% if @plugins.any? %>
4 <table class="list">
4 <table class="list plugins">
5 <% @plugins.each do |plugin| %>
5 <% @plugins.each do |plugin| %>
6 <tr class="<%= cycle('odd', 'even') %>">
6 <tr class="<%= cycle('odd', 'even') %>">
7 <td><%=h plugin.name %></td>
7 <td><span class="name"><%=h plugin.name %></span>
8 <td><%=h plugin.description %></td>
8 <%= content_tag('span', h(plugin.description), :class => 'description') unless plugin.description.blank? %>
9 <td><%=h plugin.author %></td>
9 <%= content_tag('span', link_to(h(plugin.url), plugin.url), :class => 'url') unless plugin.url.blank? %>
10 <td><%=h plugin.version %></td>
10 </td>
11 <td><%= link_to(l(:button_configure), :controller => 'settings', :action => 'plugin', :id => plugin.id) if plugin.configurable? %></td>
11 <td class="author"><%= plugin.author_url.blank? ? h(plugin.author) : link_to(h(plugin.author), plugin.author_url) %></td>
12 <td class="version"><%=h plugin.version %></td>
13 <td class="configure"><%= link_to(l(:button_configure), :controller => 'settings', :action => 'plugin', :id => plugin.id) if plugin.configurable? %></td>
12 </tr>
14 </tr>
13 <% end %>
15 <% end %>
14 </table>
16 </table>
15 <% else %>
17 <% else %>
16 <p class="nodata"><%= l(:label_no_data) %></p>
18 <p class="nodata"><%= l(:label_no_data) %></p>
17 <% end %>
19 <% end %>
@@ -1,197 +1,197
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 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 #:nodoc:
18 module Redmine #:nodoc:
19
19
20 class PluginNotFound < StandardError; end
20 class PluginNotFound < StandardError; end
21
21
22 # Base class for Redmine plugins.
22 # Base class for Redmine plugins.
23 # Plugins are registered using the <tt>register</tt> class method that acts as the public constructor.
23 # Plugins are registered using the <tt>register</tt> class method that acts as the public constructor.
24 #
24 #
25 # Redmine::Plugin.register :example do
25 # Redmine::Plugin.register :example do
26 # name 'Example plugin'
26 # name 'Example plugin'
27 # author 'John Smith'
27 # author 'John Smith'
28 # description 'This is an example plugin for Redmine'
28 # description 'This is an example plugin for Redmine'
29 # version '0.0.1'
29 # version '0.0.1'
30 # settings :default => {'foo'=>'bar'}, :partial => 'settings/settings'
30 # settings :default => {'foo'=>'bar'}, :partial => 'settings/settings'
31 # end
31 # end
32 #
32 #
33 # === Plugin attributes
33 # === Plugin attributes
34 #
34 #
35 # +settings+ is an optional attribute that let the plugin be configurable.
35 # +settings+ is an optional attribute that let the plugin be configurable.
36 # It must be a hash with the following keys:
36 # It must be a hash with the following keys:
37 # * <tt>:default</tt>: default value for the plugin settings
37 # * <tt>:default</tt>: default value for the plugin settings
38 # * <tt>:partial</tt>: path of the configuration partial view, relative to the plugin <tt>app/views</tt> directory
38 # * <tt>:partial</tt>: path of the configuration partial view, relative to the plugin <tt>app/views</tt> directory
39 # Example:
39 # Example:
40 # settings :default => {'foo'=>'bar'}, :partial => 'settings/settings'
40 # settings :default => {'foo'=>'bar'}, :partial => 'settings/settings'
41 # In this example, the settings partial will be found here in the plugin directory: <tt>app/views/settings/_settings.rhtml</tt>.
41 # In this example, the settings partial will be found here in the plugin directory: <tt>app/views/settings/_settings.rhtml</tt>.
42 #
42 #
43 # When rendered, the plugin settings value is available as the local variable +settings+
43 # When rendered, the plugin settings value is available as the local variable +settings+
44 class Plugin
44 class Plugin
45 @registered_plugins = {}
45 @registered_plugins = {}
46 class << self
46 class << self
47 attr_reader :registered_plugins
47 attr_reader :registered_plugins
48 private :new
48 private :new
49
49
50 def def_field(*names)
50 def def_field(*names)
51 class_eval do
51 class_eval do
52 names.each do |name|
52 names.each do |name|
53 define_method(name) do |*args|
53 define_method(name) do |*args|
54 args.empty? ? instance_variable_get("@#{name}") : instance_variable_set("@#{name}", *args)
54 args.empty? ? instance_variable_get("@#{name}") : instance_variable_set("@#{name}", *args)
55 end
55 end
56 end
56 end
57 end
57 end
58 end
58 end
59 end
59 end
60 def_field :name, :description, :author, :version, :settings
60 def_field :name, :description, :url, :author, :author_url, :version, :settings
61 attr_reader :id
61 attr_reader :id
62
62
63 # Plugin constructor
63 # Plugin constructor
64 def self.register(id, &block)
64 def self.register(id, &block)
65 p = new(id)
65 p = new(id)
66 p.instance_eval(&block)
66 p.instance_eval(&block)
67 # Set a default name if it was not provided during registration
67 # Set a default name if it was not provided during registration
68 p.name(id.to_s.humanize) if p.name.nil?
68 p.name(id.to_s.humanize) if p.name.nil?
69 registered_plugins[id] = p
69 registered_plugins[id] = p
70 end
70 end
71
71
72 # Returns an array off all registered plugins
72 # Returns an array off all registered plugins
73 def self.all
73 def self.all
74 registered_plugins.values.sort
74 registered_plugins.values.sort
75 end
75 end
76
76
77 # Finds a plugin by its id
77 # Finds a plugin by its id
78 # Returns a PluginNotFound exception if the plugin doesn't exist
78 # Returns a PluginNotFound exception if the plugin doesn't exist
79 def self.find(id)
79 def self.find(id)
80 registered_plugins[id.to_sym] || raise(PluginNotFound)
80 registered_plugins[id.to_sym] || raise(PluginNotFound)
81 end
81 end
82
82
83 # Clears the registered plugins hash
83 # Clears the registered plugins hash
84 # It doesn't unload installed plugins
84 # It doesn't unload installed plugins
85 def self.clear
85 def self.clear
86 @registered_plugins = {}
86 @registered_plugins = {}
87 end
87 end
88
88
89 def initialize(id)
89 def initialize(id)
90 @id = id.to_sym
90 @id = id.to_sym
91 end
91 end
92
92
93 def <=>(plugin)
93 def <=>(plugin)
94 self.id.to_s <=> plugin.id.to_s
94 self.id.to_s <=> plugin.id.to_s
95 end
95 end
96
96
97 # Adds an item to the given +menu+.
97 # Adds an item to the given +menu+.
98 # The +id+ parameter (equals to the project id) is automatically added to the url.
98 # The +id+ parameter (equals to the project id) is automatically added to the url.
99 # menu :project_menu, :plugin_example, { :controller => 'example', :action => 'say_hello' }, :caption => 'Sample'
99 # menu :project_menu, :plugin_example, { :controller => 'example', :action => 'say_hello' }, :caption => 'Sample'
100 #
100 #
101 # +name+ parameter can be: :top_menu, :account_menu, :application_menu or :project_menu
101 # +name+ parameter can be: :top_menu, :account_menu, :application_menu or :project_menu
102 #
102 #
103 def menu(menu, item, url, options={})
103 def menu(menu, item, url, options={})
104 Redmine::MenuManager.map(menu).push(item, url, options)
104 Redmine::MenuManager.map(menu).push(item, url, options)
105 end
105 end
106 alias :add_menu_item :menu
106 alias :add_menu_item :menu
107
107
108 # Removes +item+ from the given +menu+.
108 # Removes +item+ from the given +menu+.
109 def delete_menu_item(menu, item)
109 def delete_menu_item(menu, item)
110 Redmine::MenuManager.map(menu).delete(item)
110 Redmine::MenuManager.map(menu).delete(item)
111 end
111 end
112
112
113 # Defines a permission called +name+ for the given +actions+.
113 # Defines a permission called +name+ for the given +actions+.
114 #
114 #
115 # The +actions+ argument is a hash with controllers as keys and actions as values (a single value or an array):
115 # The +actions+ argument is a hash with controllers as keys and actions as values (a single value or an array):
116 # permission :destroy_contacts, { :contacts => :destroy }
116 # permission :destroy_contacts, { :contacts => :destroy }
117 # permission :view_contacts, { :contacts => [:index, :show] }
117 # permission :view_contacts, { :contacts => [:index, :show] }
118 #
118 #
119 # The +options+ argument can be used to make the permission public (implicitly given to any user)
119 # The +options+ argument can be used to make the permission public (implicitly given to any user)
120 # or to restrict users the permission can be given to.
120 # or to restrict users the permission can be given to.
121 #
121 #
122 # Examples
122 # Examples
123 # # A permission that is implicitly given to any user
123 # # A permission that is implicitly given to any user
124 # # This permission won't appear on the Roles & Permissions setup screen
124 # # This permission won't appear on the Roles & Permissions setup screen
125 # permission :say_hello, { :example => :say_hello }, :public => true
125 # permission :say_hello, { :example => :say_hello }, :public => true
126 #
126 #
127 # # A permission that can be given to any user
127 # # A permission that can be given to any user
128 # permission :say_hello, { :example => :say_hello }
128 # permission :say_hello, { :example => :say_hello }
129 #
129 #
130 # # A permission that can be given to registered users only
130 # # A permission that can be given to registered users only
131 # permission :say_hello, { :example => :say_hello }, :require => loggedin
131 # permission :say_hello, { :example => :say_hello }, :require => loggedin
132 #
132 #
133 # # A permission that can be given to project members only
133 # # A permission that can be given to project members only
134 # permission :say_hello, { :example => :say_hello }, :require => member
134 # permission :say_hello, { :example => :say_hello }, :require => member
135 def permission(name, actions, options = {})
135 def permission(name, actions, options = {})
136 if @project_module
136 if @project_module
137 Redmine::AccessControl.map {|map| map.project_module(@project_module) {|map|map.permission(name, actions, options)}}
137 Redmine::AccessControl.map {|map| map.project_module(@project_module) {|map|map.permission(name, actions, options)}}
138 else
138 else
139 Redmine::AccessControl.map {|map| map.permission(name, actions, options)}
139 Redmine::AccessControl.map {|map| map.permission(name, actions, options)}
140 end
140 end
141 end
141 end
142
142
143 # Defines a project module, that can be enabled/disabled for each project.
143 # Defines a project module, that can be enabled/disabled for each project.
144 # Permissions defined inside +block+ will be bind to the module.
144 # Permissions defined inside +block+ will be bind to the module.
145 #
145 #
146 # project_module :things do
146 # project_module :things do
147 # permission :view_contacts, { :contacts => [:list, :show] }, :public => true
147 # permission :view_contacts, { :contacts => [:list, :show] }, :public => true
148 # permission :destroy_contacts, { :contacts => :destroy }
148 # permission :destroy_contacts, { :contacts => :destroy }
149 # end
149 # end
150 def project_module(name, &block)
150 def project_module(name, &block)
151 @project_module = name
151 @project_module = name
152 self.instance_eval(&block)
152 self.instance_eval(&block)
153 @project_module = nil
153 @project_module = nil
154 end
154 end
155
155
156 # Registers an activity provider.
156 # Registers an activity provider.
157 #
157 #
158 # Options:
158 # Options:
159 # * <tt>:class_name</tt> - one or more model(s) that provide these events (inferred from event_type by default)
159 # * <tt>:class_name</tt> - one or more model(s) that provide these events (inferred from event_type by default)
160 # * <tt>:default</tt> - setting this option to false will make the events not displayed by default
160 # * <tt>:default</tt> - setting this option to false will make the events not displayed by default
161 #
161 #
162 # A model can provide several activity event types.
162 # A model can provide several activity event types.
163 #
163 #
164 # Examples:
164 # Examples:
165 # register :news
165 # register :news
166 # register :scrums, :class_name => 'Meeting'
166 # register :scrums, :class_name => 'Meeting'
167 # register :issues, :class_name => ['Issue', 'Journal']
167 # register :issues, :class_name => ['Issue', 'Journal']
168 #
168 #
169 # Retrieving events:
169 # Retrieving events:
170 # Associated model(s) must implement the find_events class method.
170 # Associated model(s) must implement the find_events class method.
171 # ActiveRecord models can use acts_as_activity_provider as a way to implement this class method.
171 # ActiveRecord models can use acts_as_activity_provider as a way to implement this class method.
172 #
172 #
173 # The following call should return all the scrum events visible by current user that occured in the 5 last days:
173 # The following call should return all the scrum events visible by current user that occured in the 5 last days:
174 # Meeting.find_events('scrums', User.current, 5.days.ago, Date.today)
174 # Meeting.find_events('scrums', User.current, 5.days.ago, Date.today)
175 # Meeting.find_events('scrums', User.current, 5.days.ago, Date.today, :project => foo) # events for project foo only
175 # Meeting.find_events('scrums', User.current, 5.days.ago, Date.today, :project => foo) # events for project foo only
176 #
176 #
177 # Note that :view_scrums permission is required to view these events in the activity view.
177 # Note that :view_scrums permission is required to view these events in the activity view.
178 def activity_provider(*args)
178 def activity_provider(*args)
179 Redmine::Activity.register(*args)
179 Redmine::Activity.register(*args)
180 end
180 end
181
181
182 # Registers a wiki formatter.
182 # Registers a wiki formatter.
183 #
183 #
184 # Parameters:
184 # Parameters:
185 # * +name+ - human-readable name
185 # * +name+ - human-readable name
186 # * +formatter+ - formatter class, which should have an instance method +to_html+
186 # * +formatter+ - formatter class, which should have an instance method +to_html+
187 # * +helper+ - helper module, which will be included by wiki pages
187 # * +helper+ - helper module, which will be included by wiki pages
188 def wiki_format_provider(name, formatter, helper)
188 def wiki_format_provider(name, formatter, helper)
189 Redmine::WikiFormatting.register(name, formatter, helper)
189 Redmine::WikiFormatting.register(name, formatter, helper)
190 end
190 end
191
191
192 # Returns +true+ if the plugin can be configured.
192 # Returns +true+ if the plugin can be configured.
193 def configurable?
193 def configurable?
194 settings && settings.is_a?(Hash) && !settings[:partial].blank?
194 settings && settings.is_a?(Hash) && !settings[:partial].blank?
195 end
195 end
196 end
196 end
197 end
197 end
@@ -1,665 +1,671
1 body { font-family: Verdana, sans-serif; font-size: 12px; color:#484848; margin: 0; padding: 0; min-width: 900px; }
1 body { font-family: Verdana, sans-serif; font-size: 12px; color:#484848; margin: 0; padding: 0; min-width: 900px; }
2
2
3 h1, h2, h3, h4 { font-family: "Trebuchet MS", Verdana, sans-serif;}
3 h1, h2, h3, h4 { font-family: "Trebuchet MS", Verdana, sans-serif;}
4 h1 {margin:0; padding:0; font-size: 24px;}
4 h1 {margin:0; padding:0; font-size: 24px;}
5 h2, .wiki h1 {font-size: 20px;padding: 2px 10px 1px 0px;margin: 0 0 10px 0; border-bottom: 1px solid #bbbbbb; color: #444;}
5 h2, .wiki h1 {font-size: 20px;padding: 2px 10px 1px 0px;margin: 0 0 10px 0; border-bottom: 1px solid #bbbbbb; color: #444;}
6 h3, .wiki h2 {font-size: 16px;padding: 2px 10px 1px 0px;margin: 0 0 10px 0; border-bottom: 1px solid #bbbbbb; color: #444;}
6 h3, .wiki h2 {font-size: 16px;padding: 2px 10px 1px 0px;margin: 0 0 10px 0; border-bottom: 1px solid #bbbbbb; color: #444;}
7 h4, .wiki h3 {font-size: 13px;padding: 2px 10px 1px 0px;margin-bottom: 5px; border-bottom: 1px dotted #bbbbbb; color: #444;}
7 h4, .wiki h3 {font-size: 13px;padding: 2px 10px 1px 0px;margin-bottom: 5px; border-bottom: 1px dotted #bbbbbb; color: #444;}
8
8
9 /***** Layout *****/
9 /***** Layout *****/
10 #wrapper {background: white;}
10 #wrapper {background: white;}
11
11
12 #top-menu {background: #2C4056; color: #fff; height:1.8em; font-size: 0.8em; padding: 2px 2px 0px 6px;}
12 #top-menu {background: #2C4056; color: #fff; height:1.8em; font-size: 0.8em; padding: 2px 2px 0px 6px;}
13 #top-menu ul {margin: 0; padding: 0;}
13 #top-menu ul {margin: 0; padding: 0;}
14 #top-menu li {
14 #top-menu li {
15 float:left;
15 float:left;
16 list-style-type:none;
16 list-style-type:none;
17 margin: 0px 0px 0px 0px;
17 margin: 0px 0px 0px 0px;
18 padding: 0px 0px 0px 0px;
18 padding: 0px 0px 0px 0px;
19 white-space:nowrap;
19 white-space:nowrap;
20 }
20 }
21 #top-menu a {color: #fff; padding-right: 8px; font-weight: bold;}
21 #top-menu a {color: #fff; padding-right: 8px; font-weight: bold;}
22 #top-menu #loggedas { float: right; margin-right: 0.5em; color: #fff; }
22 #top-menu #loggedas { float: right; margin-right: 0.5em; color: #fff; }
23
23
24 #account {float:right;}
24 #account {float:right;}
25
25
26 #header {height:5.3em;margin:0;background-color:#507AAA;color:#f8f8f8; padding: 4px 8px 0px 6px; position:relative;}
26 #header {height:5.3em;margin:0;background-color:#507AAA;color:#f8f8f8; padding: 4px 8px 0px 6px; position:relative;}
27 #header a {color:#f8f8f8;}
27 #header a {color:#f8f8f8;}
28 #quick-search {float:right;}
28 #quick-search {float:right;}
29
29
30 #main-menu {position: absolute; bottom: 0px; left:6px; margin-right: -500px;}
30 #main-menu {position: absolute; bottom: 0px; left:6px; margin-right: -500px;}
31 #main-menu ul {margin: 0; padding: 0;}
31 #main-menu ul {margin: 0; padding: 0;}
32 #main-menu li {
32 #main-menu li {
33 float:left;
33 float:left;
34 list-style-type:none;
34 list-style-type:none;
35 margin: 0px 2px 0px 0px;
35 margin: 0px 2px 0px 0px;
36 padding: 0px 0px 0px 0px;
36 padding: 0px 0px 0px 0px;
37 white-space:nowrap;
37 white-space:nowrap;
38 }
38 }
39 #main-menu li a {
39 #main-menu li a {
40 display: block;
40 display: block;
41 color: #fff;
41 color: #fff;
42 text-decoration: none;
42 text-decoration: none;
43 font-weight: bold;
43 font-weight: bold;
44 margin: 0;
44 margin: 0;
45 padding: 4px 10px 4px 10px;
45 padding: 4px 10px 4px 10px;
46 }
46 }
47 #main-menu li a:hover {background:#759FCF; color:#fff;}
47 #main-menu li a:hover {background:#759FCF; color:#fff;}
48 #main-menu li a.selected, #main-menu li a.selected:hover {background:#fff; color:#555;}
48 #main-menu li a.selected, #main-menu li a.selected:hover {background:#fff; color:#555;}
49
49
50 #main {background-color:#EEEEEE;}
50 #main {background-color:#EEEEEE;}
51
51
52 #sidebar{ float: right; width: 17%; position: relative; z-index: 9; min-height: 600px; padding: 0; margin: 0;}
52 #sidebar{ float: right; width: 17%; position: relative; z-index: 9; min-height: 600px; padding: 0; margin: 0;}
53 * html #sidebar{ width: 17%; }
53 * html #sidebar{ width: 17%; }
54 #sidebar h3{ font-size: 14px; margin-top:14px; color: #666; }
54 #sidebar h3{ font-size: 14px; margin-top:14px; color: #666; }
55 #sidebar hr{ width: 100%; margin: 0 auto; height: 1px; background: #ccc; border: 0; }
55 #sidebar hr{ width: 100%; margin: 0 auto; height: 1px; background: #ccc; border: 0; }
56 * html #sidebar hr{ width: 95%; position: relative; left: -6px; color: #ccc; }
56 * html #sidebar hr{ width: 95%; position: relative; left: -6px; color: #ccc; }
57
57
58 #content { width: 80%; background-color: #fff; margin: 0px; border-right: 1px solid #ddd; padding: 6px 10px 10px 10px; z-index: 10; height:600px; min-height: 600px;}
58 #content { width: 80%; background-color: #fff; margin: 0px; border-right: 1px solid #ddd; padding: 6px 10px 10px 10px; z-index: 10; height:600px; min-height: 600px;}
59 * html #content{ width: 80%; padding-left: 0; margin-top: 0px; padding: 6px 10px 10px 10px;}
59 * html #content{ width: 80%; padding-left: 0; margin-top: 0px; padding: 6px 10px 10px 10px;}
60 html>body #content { height: auto; min-height: 600px; overflow: auto; }
60 html>body #content { height: auto; min-height: 600px; overflow: auto; }
61
61
62 #main.nosidebar #sidebar{ display: none; }
62 #main.nosidebar #sidebar{ display: none; }
63 #main.nosidebar #content{ width: auto; border-right: 0; }
63 #main.nosidebar #content{ width: auto; border-right: 0; }
64
64
65 #footer {clear: both; border-top: 1px solid #bbb; font-size: 0.9em; color: #aaa; padding: 5px; text-align:center; background:#fff;}
65 #footer {clear: both; border-top: 1px solid #bbb; font-size: 0.9em; color: #aaa; padding: 5px; text-align:center; background:#fff;}
66
66
67 #login-form table {margin-top:5em; padding:1em; margin-left: auto; margin-right: auto; border: 2px solid #FDBF3B; background-color:#FFEBC1; }
67 #login-form table {margin-top:5em; padding:1em; margin-left: auto; margin-right: auto; border: 2px solid #FDBF3B; background-color:#FFEBC1; }
68 #login-form table td {padding: 6px;}
68 #login-form table td {padding: 6px;}
69 #login-form label {font-weight: bold;}
69 #login-form label {font-weight: bold;}
70
70
71 .clear:after{ content: "."; display: block; height: 0; clear: both; visibility: hidden; }
71 .clear:after{ content: "."; display: block; height: 0; clear: both; visibility: hidden; }
72
72
73 /***** Links *****/
73 /***** Links *****/
74 a, a:link, a:visited{ color: #2A5685; text-decoration: none; }
74 a, a:link, a:visited{ color: #2A5685; text-decoration: none; }
75 a:hover, a:active{ color: #c61a1a; text-decoration: underline;}
75 a:hover, a:active{ color: #c61a1a; text-decoration: underline;}
76 a img{ border: 0; }
76 a img{ border: 0; }
77
77
78 a.issue.closed { text-decoration: line-through; }
78 a.issue.closed { text-decoration: line-through; }
79
79
80 /***** Tables *****/
80 /***** Tables *****/
81 table.list { border: 1px solid #e4e4e4; border-collapse: collapse; width: 100%; margin-bottom: 4px; }
81 table.list { border: 1px solid #e4e4e4; border-collapse: collapse; width: 100%; margin-bottom: 4px; }
82 table.list th { background-color:#EEEEEE; padding: 4px; white-space:nowrap; }
82 table.list th { background-color:#EEEEEE; padding: 4px; white-space:nowrap; }
83 table.list td { vertical-align: top; }
83 table.list td { vertical-align: top; }
84 table.list td.id { width: 2%; text-align: center;}
84 table.list td.id { width: 2%; text-align: center;}
85 table.list td.checkbox { width: 15px; padding: 0px;}
85 table.list td.checkbox { width: 15px; padding: 0px;}
86
86
87 tr.issue { text-align: center; white-space: nowrap; }
87 tr.issue { text-align: center; white-space: nowrap; }
88 tr.issue td.subject, tr.issue td.category, td.assigned_to { white-space: normal; }
88 tr.issue td.subject, tr.issue td.category, td.assigned_to { white-space: normal; }
89 tr.issue td.subject { text-align: left; }
89 tr.issue td.subject { text-align: left; }
90 tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;}
90 tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;}
91
91
92 tr.entry { border: 1px solid #f8f8f8; }
92 tr.entry { border: 1px solid #f8f8f8; }
93 tr.entry td { white-space: nowrap; }
93 tr.entry td { white-space: nowrap; }
94 tr.entry td.filename { width: 30%; }
94 tr.entry td.filename { width: 30%; }
95 tr.entry td.size { text-align: right; font-size: 90%; }
95 tr.entry td.size { text-align: right; font-size: 90%; }
96 tr.entry td.revision, tr.entry td.author { text-align: center; }
96 tr.entry td.revision, tr.entry td.author { text-align: center; }
97 tr.entry td.age { text-align: right; }
97 tr.entry td.age { text-align: right; }
98
98
99 tr.entry span.expander {background-image: url(../images/bullet_toggle_plus.png); padding-left: 8px; margin-left: 0; cursor: pointer;}
99 tr.entry span.expander {background-image: url(../images/bullet_toggle_plus.png); padding-left: 8px; margin-left: 0; cursor: pointer;}
100 tr.entry.open span.expander {background-image: url(../images/bullet_toggle_minus.png);}
100 tr.entry.open span.expander {background-image: url(../images/bullet_toggle_minus.png);}
101 tr.entry.file td.filename a { margin-left: 16px; }
101 tr.entry.file td.filename a { margin-left: 16px; }
102
102
103 tr.changeset td.author { text-align: center; width: 15%; }
103 tr.changeset td.author { text-align: center; width: 15%; }
104 tr.changeset td.committed_on { text-align: center; width: 15%; }
104 tr.changeset td.committed_on { text-align: center; width: 15%; }
105
105
106 tr.message { height: 2.6em; }
106 tr.message { height: 2.6em; }
107 tr.message td.last_message { font-size: 80%; }
107 tr.message td.last_message { font-size: 80%; }
108 tr.message.locked td.subject a { background-image: url(../images/locked.png); }
108 tr.message.locked td.subject a { background-image: url(../images/locked.png); }
109 tr.message.sticky td.subject a { background-image: url(../images/sticky.png); font-weight: bold; }
109 tr.message.sticky td.subject a { background-image: url(../images/sticky.png); font-weight: bold; }
110
110
111 tr.user td { width:13%; }
111 tr.user td { width:13%; }
112 tr.user td.email { width:18%; }
112 tr.user td.email { width:18%; }
113 tr.user td { white-space: nowrap; }
113 tr.user td { white-space: nowrap; }
114 tr.user.locked, tr.user.registered { color: #aaa; }
114 tr.user.locked, tr.user.registered { color: #aaa; }
115 tr.user.locked a, tr.user.registered a { color: #aaa; }
115 tr.user.locked a, tr.user.registered a { color: #aaa; }
116
116
117 tr.time-entry { text-align: center; white-space: nowrap; }
117 tr.time-entry { text-align: center; white-space: nowrap; }
118 tr.time-entry td.subject, tr.time-entry td.comments { text-align: left; white-space: normal; }
118 tr.time-entry td.subject, tr.time-entry td.comments { text-align: left; white-space: normal; }
119 td.hours { text-align: right; font-weight: bold; padding-right: 0.5em; }
119 td.hours { text-align: right; font-weight: bold; padding-right: 0.5em; }
120 td.hours .hours-dec { font-size: 0.9em; }
120 td.hours .hours-dec { font-size: 0.9em; }
121
121
122 table.plugins td { vertical-align: middle; }
123 table.plugins td.configure { text-align: right; padding-right: 1em; }
124 table.plugins span.name { font-weight: bold; display: block; margin-bottom: 6px; }
125 table.plugins span.description { display: block; font-size: 0.9em; }
126 table.plugins span.url { display: block; font-size: 0.9em; }
127
122 table.list tbody tr:hover { background-color:#ffffdd; }
128 table.list tbody tr:hover { background-color:#ffffdd; }
123 table td {padding:2px;}
129 table td {padding:2px;}
124 table p {margin:0;}
130 table p {margin:0;}
125 .odd {background-color:#f6f7f8;}
131 .odd {background-color:#f6f7f8;}
126 .even {background-color: #fff;}
132 .even {background-color: #fff;}
127
133
128 .highlight { background-color: #FCFD8D;}
134 .highlight { background-color: #FCFD8D;}
129 .highlight.token-1 { background-color: #faa;}
135 .highlight.token-1 { background-color: #faa;}
130 .highlight.token-2 { background-color: #afa;}
136 .highlight.token-2 { background-color: #afa;}
131 .highlight.token-3 { background-color: #aaf;}
137 .highlight.token-3 { background-color: #aaf;}
132
138
133 .box{
139 .box{
134 padding:6px;
140 padding:6px;
135 margin-bottom: 10px;
141 margin-bottom: 10px;
136 background-color:#f6f6f6;
142 background-color:#f6f6f6;
137 color:#505050;
143 color:#505050;
138 line-height:1.5em;
144 line-height:1.5em;
139 border: 1px solid #e4e4e4;
145 border: 1px solid #e4e4e4;
140 }
146 }
141
147
142 div.square {
148 div.square {
143 border: 1px solid #999;
149 border: 1px solid #999;
144 float: left;
150 float: left;
145 margin: .3em .4em 0 .4em;
151 margin: .3em .4em 0 .4em;
146 overflow: hidden;
152 overflow: hidden;
147 width: .6em; height: .6em;
153 width: .6em; height: .6em;
148 }
154 }
149 .contextual {float:right; white-space: nowrap; line-height:1.4em;margin-top:5px; padding-left: 10px; font-size:0.9em;}
155 .contextual {float:right; white-space: nowrap; line-height:1.4em;margin-top:5px; padding-left: 10px; font-size:0.9em;}
150 .contextual input {font-size:0.9em;}
156 .contextual input {font-size:0.9em;}
151
157
152 .splitcontentleft{float:left; width:49%;}
158 .splitcontentleft{float:left; width:49%;}
153 .splitcontentright{float:right; width:49%;}
159 .splitcontentright{float:right; width:49%;}
154 form {display: inline;}
160 form {display: inline;}
155 input, select {vertical-align: middle; margin-top: 1px; margin-bottom: 1px;}
161 input, select {vertical-align: middle; margin-top: 1px; margin-bottom: 1px;}
156 fieldset {border: 1px solid #e4e4e4; margin:0;}
162 fieldset {border: 1px solid #e4e4e4; margin:0;}
157 legend {color: #484848;}
163 legend {color: #484848;}
158 hr { width: 100%; height: 1px; background: #ccc; border: 0;}
164 hr { width: 100%; height: 1px; background: #ccc; border: 0;}
159 blockquote { font-style: italic; border-left: 3px solid #e0e0e0; padding-left: 0.6em; margin-left: 2.4em;}
165 blockquote { font-style: italic; border-left: 3px solid #e0e0e0; padding-left: 0.6em; margin-left: 2.4em;}
160 blockquote blockquote { margin-left: 0;}
166 blockquote blockquote { margin-left: 0;}
161 textarea.wiki-edit { width: 99%; }
167 textarea.wiki-edit { width: 99%; }
162 li p {margin-top: 0;}
168 li p {margin-top: 0;}
163 div.issue {background:#ffffdd; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7;}
169 div.issue {background:#ffffdd; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7;}
164 p.breadcrumb { font-size: 0.9em; margin: 4px 0 4px 0;}
170 p.breadcrumb { font-size: 0.9em; margin: 4px 0 4px 0;}
165 p.subtitle { font-size: 0.9em; margin: -6px 0 12px 0; font-style: italic; }
171 p.subtitle { font-size: 0.9em; margin: -6px 0 12px 0; font-style: italic; }
166 p.footnote { font-size: 0.9em; margin-top: 0px; margin-bottom: 0px; }
172 p.footnote { font-size: 0.9em; margin-top: 0px; margin-bottom: 0px; }
167
173
168 fieldset#filters, fieldset#date-range { padding: 0.7em; margin-bottom: 8px; }
174 fieldset#filters, fieldset#date-range { padding: 0.7em; margin-bottom: 8px; }
169 fieldset#filters p { margin: 1.2em 0 0.8em 2px; }
175 fieldset#filters p { margin: 1.2em 0 0.8em 2px; }
170 fieldset#filters table { border-collapse: collapse; }
176 fieldset#filters table { border-collapse: collapse; }
171 fieldset#filters table td { padding: 0; vertical-align: middle; }
177 fieldset#filters table td { padding: 0; vertical-align: middle; }
172 fieldset#filters tr.filter { height: 2em; }
178 fieldset#filters tr.filter { height: 2em; }
173 fieldset#filters td.add-filter { text-align: right; vertical-align: top; }
179 fieldset#filters td.add-filter { text-align: right; vertical-align: top; }
174 .buttons { font-size: 0.9em; }
180 .buttons { font-size: 0.9em; }
175
181
176 div#issue-changesets {float:right; width:45%; margin-left: 1em; margin-bottom: 1em; background: #fff; padding-left: 1em; font-size: 90%;}
182 div#issue-changesets {float:right; width:45%; margin-left: 1em; margin-bottom: 1em; background: #fff; padding-left: 1em; font-size: 90%;}
177 div#issue-changesets .changeset { padding: 4px;}
183 div#issue-changesets .changeset { padding: 4px;}
178 div#issue-changesets .changeset { border-bottom: 1px solid #ddd; }
184 div#issue-changesets .changeset { border-bottom: 1px solid #ddd; }
179 div#issue-changesets p { margin-top: 0; margin-bottom: 1em;}
185 div#issue-changesets p { margin-top: 0; margin-bottom: 1em;}
180
186
181 div#activity dl, #search-results { margin-left: 2em; }
187 div#activity dl, #search-results { margin-left: 2em; }
182 div#activity dd, #search-results dd { margin-bottom: 1em; padding-left: 18px; font-size: 0.9em; }
188 div#activity dd, #search-results dd { margin-bottom: 1em; padding-left: 18px; font-size: 0.9em; }
183 div#activity dt, #search-results dt { margin-bottom: 0px; padding-left: 20px; line-height: 18px; background-position: 0 50%; background-repeat: no-repeat; }
189 div#activity dt, #search-results dt { margin-bottom: 0px; padding-left: 20px; line-height: 18px; background-position: 0 50%; background-repeat: no-repeat; }
184 div#activity dt.me .time { border-bottom: 1px solid #999; }
190 div#activity dt.me .time { border-bottom: 1px solid #999; }
185 div#activity dt .time { color: #777; font-size: 80%; }
191 div#activity dt .time { color: #777; font-size: 80%; }
186 div#activity dd .description, #search-results dd .description { font-style: italic; }
192 div#activity dd .description, #search-results dd .description { font-style: italic; }
187 div#activity span.project:after, #search-results span.project:after { content: " -"; }
193 div#activity span.project:after, #search-results span.project:after { content: " -"; }
188 div#activity dd span.description, #search-results dd span.description { display:block; }
194 div#activity dd span.description, #search-results dd span.description { display:block; }
189
195
190 #search-results dd { margin-bottom: 1em; padding-left: 20px; margin-left:0px; }
196 #search-results dd { margin-bottom: 1em; padding-left: 20px; margin-left:0px; }
191 div#search-results-counts {float:right;}
197 div#search-results-counts {float:right;}
192 div#search-results-counts ul { margin-top: 0.5em; }
198 div#search-results-counts ul { margin-top: 0.5em; }
193 div#search-results-counts li { list-style-type:none; float: left; margin-left: 1em; }
199 div#search-results-counts li { list-style-type:none; float: left; margin-left: 1em; }
194
200
195 dt.issue { background-image: url(../images/ticket.png); }
201 dt.issue { background-image: url(../images/ticket.png); }
196 dt.issue-edit { background-image: url(../images/ticket_edit.png); }
202 dt.issue-edit { background-image: url(../images/ticket_edit.png); }
197 dt.issue-closed { background-image: url(../images/ticket_checked.png); }
203 dt.issue-closed { background-image: url(../images/ticket_checked.png); }
198 dt.issue-note { background-image: url(../images/ticket_note.png); }
204 dt.issue-note { background-image: url(../images/ticket_note.png); }
199 dt.changeset { background-image: url(../images/changeset.png); }
205 dt.changeset { background-image: url(../images/changeset.png); }
200 dt.news { background-image: url(../images/news.png); }
206 dt.news { background-image: url(../images/news.png); }
201 dt.message { background-image: url(../images/message.png); }
207 dt.message { background-image: url(../images/message.png); }
202 dt.reply { background-image: url(../images/comments.png); }
208 dt.reply { background-image: url(../images/comments.png); }
203 dt.wiki-page { background-image: url(../images/wiki_edit.png); }
209 dt.wiki-page { background-image: url(../images/wiki_edit.png); }
204 dt.attachment { background-image: url(../images/attachment.png); }
210 dt.attachment { background-image: url(../images/attachment.png); }
205 dt.document { background-image: url(../images/document.png); }
211 dt.document { background-image: url(../images/document.png); }
206 dt.project { background-image: url(../images/projects.png); }
212 dt.project { background-image: url(../images/projects.png); }
207
213
208 div#roadmap fieldset.related-issues { margin-bottom: 1em; }
214 div#roadmap fieldset.related-issues { margin-bottom: 1em; }
209 div#roadmap fieldset.related-issues ul { margin-top: 0.3em; margin-bottom: 0.3em; }
215 div#roadmap fieldset.related-issues ul { margin-top: 0.3em; margin-bottom: 0.3em; }
210 div#roadmap .wiki h1:first-child { display: none; }
216 div#roadmap .wiki h1:first-child { display: none; }
211 div#roadmap .wiki h1 { font-size: 120%; }
217 div#roadmap .wiki h1 { font-size: 120%; }
212 div#roadmap .wiki h2 { font-size: 110%; }
218 div#roadmap .wiki h2 { font-size: 110%; }
213
219
214 div#version-summary { float:right; width:380px; margin-left: 16px; margin-bottom: 16px; background-color: #fff; }
220 div#version-summary { float:right; width:380px; margin-left: 16px; margin-bottom: 16px; background-color: #fff; }
215 div#version-summary fieldset { margin-bottom: 1em; }
221 div#version-summary fieldset { margin-bottom: 1em; }
216 div#version-summary .total-hours { text-align: right; }
222 div#version-summary .total-hours { text-align: right; }
217
223
218 table#time-report td.hours, table#time-report th.period, table#time-report th.total { text-align: right; padding-right: 0.5em; }
224 table#time-report td.hours, table#time-report th.period, table#time-report th.total { text-align: right; padding-right: 0.5em; }
219 table#time-report tbody tr { font-style: italic; color: #777; }
225 table#time-report tbody tr { font-style: italic; color: #777; }
220 table#time-report tbody tr.last-level { font-style: normal; color: #555; }
226 table#time-report tbody tr.last-level { font-style: normal; color: #555; }
221 table#time-report tbody tr.total { font-style: normal; font-weight: bold; color: #555; background-color:#EEEEEE; }
227 table#time-report tbody tr.total { font-style: normal; font-weight: bold; color: #555; background-color:#EEEEEE; }
222 table#time-report .hours-dec { font-size: 0.9em; }
228 table#time-report .hours-dec { font-size: 0.9em; }
223
229
224 ul.properties {padding:0; font-size: 0.9em; color: #777;}
230 ul.properties {padding:0; font-size: 0.9em; color: #777;}
225 ul.properties li {list-style-type:none;}
231 ul.properties li {list-style-type:none;}
226 ul.properties li span {font-style:italic;}
232 ul.properties li span {font-style:italic;}
227
233
228 .total-hours { font-size: 110%; font-weight: bold; }
234 .total-hours { font-size: 110%; font-weight: bold; }
229 .total-hours span.hours-int { font-size: 120%; }
235 .total-hours span.hours-int { font-size: 120%; }
230
236
231 .autoscroll {overflow-x: auto; padding:1px; margin-bottom: 1.2em;}
237 .autoscroll {overflow-x: auto; padding:1px; margin-bottom: 1.2em;}
232 #user_firstname, #user_lastname, #user_mail, #my_account_form select { width: 90%; }
238 #user_firstname, #user_lastname, #user_mail, #my_account_form select { width: 90%; }
233
239
234 .pagination {font-size: 90%}
240 .pagination {font-size: 90%}
235 p.pagination {margin-top:8px;}
241 p.pagination {margin-top:8px;}
236
242
237 /***** Tabular forms ******/
243 /***** Tabular forms ******/
238 .tabular p{
244 .tabular p{
239 margin: 0;
245 margin: 0;
240 padding: 5px 0 8px 0;
246 padding: 5px 0 8px 0;
241 padding-left: 180px; /*width of left column containing the label elements*/
247 padding-left: 180px; /*width of left column containing the label elements*/
242 height: 1%;
248 height: 1%;
243 clear:left;
249 clear:left;
244 }
250 }
245
251
246 html>body .tabular p {overflow:hidden;}
252 html>body .tabular p {overflow:hidden;}
247
253
248 .tabular label{
254 .tabular label{
249 font-weight: bold;
255 font-weight: bold;
250 float: left;
256 float: left;
251 text-align: right;
257 text-align: right;
252 margin-left: -180px; /*width of left column*/
258 margin-left: -180px; /*width of left column*/
253 width: 175px; /*width of labels. Should be smaller than left column to create some right
259 width: 175px; /*width of labels. Should be smaller than left column to create some right
254 margin*/
260 margin*/
255 }
261 }
256
262
257 .tabular label.floating{
263 .tabular label.floating{
258 font-weight: normal;
264 font-weight: normal;
259 margin-left: 0px;
265 margin-left: 0px;
260 text-align: left;
266 text-align: left;
261 width: 270px;
267 width: 270px;
262 }
268 }
263
269
264 input#time_entry_comments { width: 90%;}
270 input#time_entry_comments { width: 90%;}
265
271
266 #preview fieldset {margin-top: 1em; background: url(../images/draft.png)}
272 #preview fieldset {margin-top: 1em; background: url(../images/draft.png)}
267
273
268 .tabular.settings p{ padding-left: 300px; }
274 .tabular.settings p{ padding-left: 300px; }
269 .tabular.settings label{ margin-left: -300px; width: 295px; }
275 .tabular.settings label{ margin-left: -300px; width: 295px; }
270
276
271 .required {color: #bb0000;}
277 .required {color: #bb0000;}
272 .summary {font-style: italic;}
278 .summary {font-style: italic;}
273
279
274 #attachments_fields input[type=text] {margin-left: 8px; }
280 #attachments_fields input[type=text] {margin-left: 8px; }
275
281
276 div.attachments { margin-top: 12px; }
282 div.attachments { margin-top: 12px; }
277 div.attachments p { margin:4px 0 2px 0; }
283 div.attachments p { margin:4px 0 2px 0; }
278 div.attachments img { vertical-align: middle; }
284 div.attachments img { vertical-align: middle; }
279 div.attachments span.author { font-size: 0.9em; color: #888; }
285 div.attachments span.author { font-size: 0.9em; color: #888; }
280
286
281 p.other-formats { text-align: right; font-size:0.9em; color: #666; }
287 p.other-formats { text-align: right; font-size:0.9em; color: #666; }
282 .other-formats span + span:before { content: "| "; }
288 .other-formats span + span:before { content: "| "; }
283
289
284 a.feed { background: url(../images/feed.png) no-repeat 1px 50%; padding: 2px 0px 3px 16px; }
290 a.feed { background: url(../images/feed.png) no-repeat 1px 50%; padding: 2px 0px 3px 16px; }
285
291
286 /***** Flash & error messages ****/
292 /***** Flash & error messages ****/
287 #errorExplanation, div.flash, .nodata, .warning {
293 #errorExplanation, div.flash, .nodata, .warning {
288 padding: 4px 4px 4px 30px;
294 padding: 4px 4px 4px 30px;
289 margin-bottom: 12px;
295 margin-bottom: 12px;
290 font-size: 1.1em;
296 font-size: 1.1em;
291 border: 2px solid;
297 border: 2px solid;
292 }
298 }
293
299
294 div.flash {margin-top: 8px;}
300 div.flash {margin-top: 8px;}
295
301
296 div.flash.error, #errorExplanation {
302 div.flash.error, #errorExplanation {
297 background: url(../images/false.png) 8px 5px no-repeat;
303 background: url(../images/false.png) 8px 5px no-repeat;
298 background-color: #ffe3e3;
304 background-color: #ffe3e3;
299 border-color: #dd0000;
305 border-color: #dd0000;
300 color: #550000;
306 color: #550000;
301 }
307 }
302
308
303 div.flash.notice {
309 div.flash.notice {
304 background: url(../images/true.png) 8px 5px no-repeat;
310 background: url(../images/true.png) 8px 5px no-repeat;
305 background-color: #dfffdf;
311 background-color: #dfffdf;
306 border-color: #9fcf9f;
312 border-color: #9fcf9f;
307 color: #005f00;
313 color: #005f00;
308 }
314 }
309
315
310 .nodata, .warning {
316 .nodata, .warning {
311 text-align: center;
317 text-align: center;
312 background-color: #FFEBC1;
318 background-color: #FFEBC1;
313 border-color: #FDBF3B;
319 border-color: #FDBF3B;
314 color: #A6750C;
320 color: #A6750C;
315 }
321 }
316
322
317 #errorExplanation ul { font-size: 0.9em;}
323 #errorExplanation ul { font-size: 0.9em;}
318
324
319 /***** Ajax indicator ******/
325 /***** Ajax indicator ******/
320 #ajax-indicator {
326 #ajax-indicator {
321 position: absolute; /* fixed not supported by IE */
327 position: absolute; /* fixed not supported by IE */
322 background-color:#eee;
328 background-color:#eee;
323 border: 1px solid #bbb;
329 border: 1px solid #bbb;
324 top:35%;
330 top:35%;
325 left:40%;
331 left:40%;
326 width:20%;
332 width:20%;
327 font-weight:bold;
333 font-weight:bold;
328 text-align:center;
334 text-align:center;
329 padding:0.6em;
335 padding:0.6em;
330 z-index:100;
336 z-index:100;
331 filter:alpha(opacity=50);
337 filter:alpha(opacity=50);
332 opacity: 0.5;
338 opacity: 0.5;
333 }
339 }
334
340
335 html>body #ajax-indicator { position: fixed; }
341 html>body #ajax-indicator { position: fixed; }
336
342
337 #ajax-indicator span {
343 #ajax-indicator span {
338 background-position: 0% 40%;
344 background-position: 0% 40%;
339 background-repeat: no-repeat;
345 background-repeat: no-repeat;
340 background-image: url(../images/loading.gif);
346 background-image: url(../images/loading.gif);
341 padding-left: 26px;
347 padding-left: 26px;
342 vertical-align: bottom;
348 vertical-align: bottom;
343 }
349 }
344
350
345 /***** Calendar *****/
351 /***** Calendar *****/
346 table.cal {border-collapse: collapse; width: 100%; margin: 0px 0 6px 0;border: 1px solid #d7d7d7;}
352 table.cal {border-collapse: collapse; width: 100%; margin: 0px 0 6px 0;border: 1px solid #d7d7d7;}
347 table.cal thead th {width: 14%;}
353 table.cal thead th {width: 14%;}
348 table.cal tbody tr {height: 100px;}
354 table.cal tbody tr {height: 100px;}
349 table.cal th { background-color:#EEEEEE; padding: 4px; }
355 table.cal th { background-color:#EEEEEE; padding: 4px; }
350 table.cal td {border: 1px solid #d7d7d7; vertical-align: top; font-size: 0.9em;}
356 table.cal td {border: 1px solid #d7d7d7; vertical-align: top; font-size: 0.9em;}
351 table.cal td p.day-num {font-size: 1.1em; text-align:right;}
357 table.cal td p.day-num {font-size: 1.1em; text-align:right;}
352 table.cal td.odd p.day-num {color: #bbb;}
358 table.cal td.odd p.day-num {color: #bbb;}
353 table.cal td.today {background:#ffffdd;}
359 table.cal td.today {background:#ffffdd;}
354 table.cal td.today p.day-num {font-weight: bold;}
360 table.cal td.today p.day-num {font-weight: bold;}
355
361
356 /***** Tooltips ******/
362 /***** Tooltips ******/
357 .tooltip{position:relative;z-index:24;}
363 .tooltip{position:relative;z-index:24;}
358 .tooltip:hover{z-index:25;color:#000;}
364 .tooltip:hover{z-index:25;color:#000;}
359 .tooltip span.tip{display: none; text-align:left;}
365 .tooltip span.tip{display: none; text-align:left;}
360
366
361 div.tooltip:hover span.tip{
367 div.tooltip:hover span.tip{
362 display:block;
368 display:block;
363 position:absolute;
369 position:absolute;
364 top:12px; left:24px; width:270px;
370 top:12px; left:24px; width:270px;
365 border:1px solid #555;
371 border:1px solid #555;
366 background-color:#fff;
372 background-color:#fff;
367 padding: 4px;
373 padding: 4px;
368 font-size: 0.8em;
374 font-size: 0.8em;
369 color:#505050;
375 color:#505050;
370 }
376 }
371
377
372 /***** Progress bar *****/
378 /***** Progress bar *****/
373 table.progress {
379 table.progress {
374 border: 1px solid #D7D7D7;
380 border: 1px solid #D7D7D7;
375 border-collapse: collapse;
381 border-collapse: collapse;
376 border-spacing: 0pt;
382 border-spacing: 0pt;
377 empty-cells: show;
383 empty-cells: show;
378 text-align: center;
384 text-align: center;
379 float:left;
385 float:left;
380 margin: 1px 6px 1px 0px;
386 margin: 1px 6px 1px 0px;
381 }
387 }
382
388
383 table.progress td { height: 0.9em; }
389 table.progress td { height: 0.9em; }
384 table.progress td.closed { background: #BAE0BA none repeat scroll 0%; }
390 table.progress td.closed { background: #BAE0BA none repeat scroll 0%; }
385 table.progress td.done { background: #DEF0DE none repeat scroll 0%; }
391 table.progress td.done { background: #DEF0DE none repeat scroll 0%; }
386 table.progress td.open { background: #FFF none repeat scroll 0%; }
392 table.progress td.open { background: #FFF none repeat scroll 0%; }
387 p.pourcent {font-size: 80%;}
393 p.pourcent {font-size: 80%;}
388 p.progress-info {clear: left; font-style: italic; font-size: 80%;}
394 p.progress-info {clear: left; font-style: italic; font-size: 80%;}
389
395
390 /***** Tabs *****/
396 /***** Tabs *****/
391 #content .tabs {height: 2.6em; border-bottom: 1px solid #bbbbbb; margin-bottom:1.2em; position:relative;}
397 #content .tabs {height: 2.6em; border-bottom: 1px solid #bbbbbb; margin-bottom:1.2em; position:relative;}
392 #content .tabs ul {margin:0; position:absolute; bottom:-2px; padding-left:1em;}
398 #content .tabs ul {margin:0; position:absolute; bottom:-2px; padding-left:1em;}
393 #content .tabs>ul { bottom:-1px; } /* others */
399 #content .tabs>ul { bottom:-1px; } /* others */
394 #content .tabs ul li {
400 #content .tabs ul li {
395 float:left;
401 float:left;
396 list-style-type:none;
402 list-style-type:none;
397 white-space:nowrap;
403 white-space:nowrap;
398 margin-right:8px;
404 margin-right:8px;
399 background:#fff;
405 background:#fff;
400 }
406 }
401 #content .tabs ul li a{
407 #content .tabs ul li a{
402 display:block;
408 display:block;
403 font-size: 0.9em;
409 font-size: 0.9em;
404 text-decoration:none;
410 text-decoration:none;
405 line-height:1.3em;
411 line-height:1.3em;
406 padding:4px 6px 4px 6px;
412 padding:4px 6px 4px 6px;
407 border: 1px solid #ccc;
413 border: 1px solid #ccc;
408 border-bottom: 1px solid #bbbbbb;
414 border-bottom: 1px solid #bbbbbb;
409 background-color: #eeeeee;
415 background-color: #eeeeee;
410 color:#777;
416 color:#777;
411 font-weight:bold;
417 font-weight:bold;
412 }
418 }
413
419
414 #content .tabs ul li a:hover {
420 #content .tabs ul li a:hover {
415 background-color: #ffffdd;
421 background-color: #ffffdd;
416 text-decoration:none;
422 text-decoration:none;
417 }
423 }
418
424
419 #content .tabs ul li a.selected {
425 #content .tabs ul li a.selected {
420 background-color: #fff;
426 background-color: #fff;
421 border: 1px solid #bbbbbb;
427 border: 1px solid #bbbbbb;
422 border-bottom: 1px solid #fff;
428 border-bottom: 1px solid #fff;
423 }
429 }
424
430
425 #content .tabs ul li a.selected:hover {
431 #content .tabs ul li a.selected:hover {
426 background-color: #fff;
432 background-color: #fff;
427 }
433 }
428
434
429 /***** Diff *****/
435 /***** Diff *****/
430 .diff_out { background: #fcc; }
436 .diff_out { background: #fcc; }
431 .diff_in { background: #cfc; }
437 .diff_in { background: #cfc; }
432
438
433 /***** Wiki *****/
439 /***** Wiki *****/
434 div.wiki table {
440 div.wiki table {
435 border: 1px solid #505050;
441 border: 1px solid #505050;
436 border-collapse: collapse;
442 border-collapse: collapse;
437 margin-bottom: 1em;
443 margin-bottom: 1em;
438 }
444 }
439
445
440 div.wiki table, div.wiki td, div.wiki th {
446 div.wiki table, div.wiki td, div.wiki th {
441 border: 1px solid #bbb;
447 border: 1px solid #bbb;
442 padding: 4px;
448 padding: 4px;
443 }
449 }
444
450
445 div.wiki .external {
451 div.wiki .external {
446 background-position: 0% 60%;
452 background-position: 0% 60%;
447 background-repeat: no-repeat;
453 background-repeat: no-repeat;
448 padding-left: 12px;
454 padding-left: 12px;
449 background-image: url(../images/external.png);
455 background-image: url(../images/external.png);
450 }
456 }
451
457
452 div.wiki a.new {
458 div.wiki a.new {
453 color: #b73535;
459 color: #b73535;
454 }
460 }
455
461
456 div.wiki pre {
462 div.wiki pre {
457 margin: 1em 1em 1em 1.6em;
463 margin: 1em 1em 1em 1.6em;
458 padding: 2px;
464 padding: 2px;
459 background-color: #fafafa;
465 background-color: #fafafa;
460 border: 1px solid #dadada;
466 border: 1px solid #dadada;
461 width:95%;
467 width:95%;
462 overflow-x: auto;
468 overflow-x: auto;
463 }
469 }
464
470
465 div.wiki ul.toc {
471 div.wiki ul.toc {
466 background-color: #ffffdd;
472 background-color: #ffffdd;
467 border: 1px solid #e4e4e4;
473 border: 1px solid #e4e4e4;
468 padding: 4px;
474 padding: 4px;
469 line-height: 1.2em;
475 line-height: 1.2em;
470 margin-bottom: 12px;
476 margin-bottom: 12px;
471 margin-right: 12px;
477 margin-right: 12px;
472 margin-left: 0;
478 margin-left: 0;
473 display: table
479 display: table
474 }
480 }
475 * html div.wiki ul.toc { width: 50%; } /* IE6 doesn't autosize div */
481 * html div.wiki ul.toc { width: 50%; } /* IE6 doesn't autosize div */
476
482
477 div.wiki ul.toc.right { float: right; margin-left: 12px; margin-right: 0; width: auto; }
483 div.wiki ul.toc.right { float: right; margin-left: 12px; margin-right: 0; width: auto; }
478 div.wiki ul.toc.left { float: left; margin-right: 12px; margin-left: 0; width: auto; }
484 div.wiki ul.toc.left { float: left; margin-right: 12px; margin-left: 0; width: auto; }
479 div.wiki ul.toc li { list-style-type:none;}
485 div.wiki ul.toc li { list-style-type:none;}
480 div.wiki ul.toc li.heading2 { margin-left: 6px; }
486 div.wiki ul.toc li.heading2 { margin-left: 6px; }
481 div.wiki ul.toc li.heading3 { margin-left: 12px; font-size: 0.8em; }
487 div.wiki ul.toc li.heading3 { margin-left: 12px; font-size: 0.8em; }
482
488
483 div.wiki ul.toc a {
489 div.wiki ul.toc a {
484 font-size: 0.9em;
490 font-size: 0.9em;
485 font-weight: normal;
491 font-weight: normal;
486 text-decoration: none;
492 text-decoration: none;
487 color: #606060;
493 color: #606060;
488 }
494 }
489 div.wiki ul.toc a:hover { color: #c61a1a; text-decoration: underline;}
495 div.wiki ul.toc a:hover { color: #c61a1a; text-decoration: underline;}
490
496
491 a.wiki-anchor { display: none; margin-left: 6px; text-decoration: none; }
497 a.wiki-anchor { display: none; margin-left: 6px; text-decoration: none; }
492 a.wiki-anchor:hover { color: #aaa !important; text-decoration: none; }
498 a.wiki-anchor:hover { color: #aaa !important; text-decoration: none; }
493 h1:hover a.wiki-anchor, h2:hover a.wiki-anchor, h3:hover a.wiki-anchor { display: inline; color: #ddd; }
499 h1:hover a.wiki-anchor, h2:hover a.wiki-anchor, h3:hover a.wiki-anchor { display: inline; color: #ddd; }
494
500
495 /***** My page layout *****/
501 /***** My page layout *****/
496 .block-receiver {
502 .block-receiver {
497 border:1px dashed #c0c0c0;
503 border:1px dashed #c0c0c0;
498 margin-bottom: 20px;
504 margin-bottom: 20px;
499 padding: 15px 0 15px 0;
505 padding: 15px 0 15px 0;
500 }
506 }
501
507
502 .mypage-box {
508 .mypage-box {
503 margin:0 0 20px 0;
509 margin:0 0 20px 0;
504 color:#505050;
510 color:#505050;
505 line-height:1.5em;
511 line-height:1.5em;
506 }
512 }
507
513
508 .handle {
514 .handle {
509 cursor: move;
515 cursor: move;
510 }
516 }
511
517
512 a.close-icon {
518 a.close-icon {
513 display:block;
519 display:block;
514 margin-top:3px;
520 margin-top:3px;
515 overflow:hidden;
521 overflow:hidden;
516 width:12px;
522 width:12px;
517 height:12px;
523 height:12px;
518 background-repeat: no-repeat;
524 background-repeat: no-repeat;
519 cursor:pointer;
525 cursor:pointer;
520 background-image:url('../images/close.png');
526 background-image:url('../images/close.png');
521 }
527 }
522
528
523 a.close-icon:hover {
529 a.close-icon:hover {
524 background-image:url('../images/close_hl.png');
530 background-image:url('../images/close_hl.png');
525 }
531 }
526
532
527 /***** Gantt chart *****/
533 /***** Gantt chart *****/
528 .gantt_hdr {
534 .gantt_hdr {
529 position:absolute;
535 position:absolute;
530 top:0;
536 top:0;
531 height:16px;
537 height:16px;
532 border-top: 1px solid #c0c0c0;
538 border-top: 1px solid #c0c0c0;
533 border-bottom: 1px solid #c0c0c0;
539 border-bottom: 1px solid #c0c0c0;
534 border-right: 1px solid #c0c0c0;
540 border-right: 1px solid #c0c0c0;
535 text-align: center;
541 text-align: center;
536 overflow: hidden;
542 overflow: hidden;
537 }
543 }
538
544
539 .task {
545 .task {
540 position: absolute;
546 position: absolute;
541 height:8px;
547 height:8px;
542 font-size:0.8em;
548 font-size:0.8em;
543 color:#888;
549 color:#888;
544 padding:0;
550 padding:0;
545 margin:0;
551 margin:0;
546 line-height:0.8em;
552 line-height:0.8em;
547 }
553 }
548
554
549 .task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; }
555 .task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; }
550 .task_done { background:#66f url(../images/task_done.png); border: 1px solid #66f; }
556 .task_done { background:#66f url(../images/task_done.png); border: 1px solid #66f; }
551 .task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; }
557 .task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; }
552 .milestone { background-image:url(../images/milestone.png); background-repeat: no-repeat; border: 0; }
558 .milestone { background-image:url(../images/milestone.png); background-repeat: no-repeat; border: 0; }
553
559
554 /***** Icons *****/
560 /***** Icons *****/
555 .icon {
561 .icon {
556 background-position: 0% 40%;
562 background-position: 0% 40%;
557 background-repeat: no-repeat;
563 background-repeat: no-repeat;
558 padding-left: 20px;
564 padding-left: 20px;
559 padding-top: 2px;
565 padding-top: 2px;
560 padding-bottom: 3px;
566 padding-bottom: 3px;
561 }
567 }
562
568
563 .icon22 {
569 .icon22 {
564 background-position: 0% 40%;
570 background-position: 0% 40%;
565 background-repeat: no-repeat;
571 background-repeat: no-repeat;
566 padding-left: 26px;
572 padding-left: 26px;
567 line-height: 22px;
573 line-height: 22px;
568 vertical-align: middle;
574 vertical-align: middle;
569 }
575 }
570
576
571 .icon-add { background-image: url(../images/add.png); }
577 .icon-add { background-image: url(../images/add.png); }
572 .icon-edit { background-image: url(../images/edit.png); }
578 .icon-edit { background-image: url(../images/edit.png); }
573 .icon-copy { background-image: url(../images/copy.png); }
579 .icon-copy { background-image: url(../images/copy.png); }
574 .icon-del { background-image: url(../images/delete.png); }
580 .icon-del { background-image: url(../images/delete.png); }
575 .icon-move { background-image: url(../images/move.png); }
581 .icon-move { background-image: url(../images/move.png); }
576 .icon-save { background-image: url(../images/save.png); }
582 .icon-save { background-image: url(../images/save.png); }
577 .icon-cancel { background-image: url(../images/cancel.png); }
583 .icon-cancel { background-image: url(../images/cancel.png); }
578 .icon-file { background-image: url(../images/file.png); }
584 .icon-file { background-image: url(../images/file.png); }
579 .icon-folder { background-image: url(../images/folder.png); }
585 .icon-folder { background-image: url(../images/folder.png); }
580 .open .icon-folder { background-image: url(../images/folder_open.png); }
586 .open .icon-folder { background-image: url(../images/folder_open.png); }
581 .icon-package { background-image: url(../images/package.png); }
587 .icon-package { background-image: url(../images/package.png); }
582 .icon-home { background-image: url(../images/home.png); }
588 .icon-home { background-image: url(../images/home.png); }
583 .icon-user { background-image: url(../images/user.png); }
589 .icon-user { background-image: url(../images/user.png); }
584 .icon-mypage { background-image: url(../images/user_page.png); }
590 .icon-mypage { background-image: url(../images/user_page.png); }
585 .icon-admin { background-image: url(../images/admin.png); }
591 .icon-admin { background-image: url(../images/admin.png); }
586 .icon-projects { background-image: url(../images/projects.png); }
592 .icon-projects { background-image: url(../images/projects.png); }
587 .icon-help { background-image: url(../images/help.png); }
593 .icon-help { background-image: url(../images/help.png); }
588 .icon-attachment { background-image: url(../images/attachment.png); }
594 .icon-attachment { background-image: url(../images/attachment.png); }
589 .icon-index { background-image: url(../images/index.png); }
595 .icon-index { background-image: url(../images/index.png); }
590 .icon-history { background-image: url(../images/history.png); }
596 .icon-history { background-image: url(../images/history.png); }
591 .icon-time { background-image: url(../images/time.png); }
597 .icon-time { background-image: url(../images/time.png); }
592 .icon-stats { background-image: url(../images/stats.png); }
598 .icon-stats { background-image: url(../images/stats.png); }
593 .icon-warning { background-image: url(../images/warning.png); }
599 .icon-warning { background-image: url(../images/warning.png); }
594 .icon-fav { background-image: url(../images/fav.png); }
600 .icon-fav { background-image: url(../images/fav.png); }
595 .icon-fav-off { background-image: url(../images/fav_off.png); }
601 .icon-fav-off { background-image: url(../images/fav_off.png); }
596 .icon-reload { background-image: url(../images/reload.png); }
602 .icon-reload { background-image: url(../images/reload.png); }
597 .icon-lock { background-image: url(../images/locked.png); }
603 .icon-lock { background-image: url(../images/locked.png); }
598 .icon-unlock { background-image: url(../images/unlock.png); }
604 .icon-unlock { background-image: url(../images/unlock.png); }
599 .icon-checked { background-image: url(../images/true.png); }
605 .icon-checked { background-image: url(../images/true.png); }
600 .icon-details { background-image: url(../images/zoom_in.png); }
606 .icon-details { background-image: url(../images/zoom_in.png); }
601 .icon-report { background-image: url(../images/report.png); }
607 .icon-report { background-image: url(../images/report.png); }
602 .icon-comment { background-image: url(../images/comment.png); }
608 .icon-comment { background-image: url(../images/comment.png); }
603
609
604 .icon22-projects { background-image: url(../images/22x22/projects.png); }
610 .icon22-projects { background-image: url(../images/22x22/projects.png); }
605 .icon22-users { background-image: url(../images/22x22/users.png); }
611 .icon22-users { background-image: url(../images/22x22/users.png); }
606 .icon22-tracker { background-image: url(../images/22x22/tracker.png); }
612 .icon22-tracker { background-image: url(../images/22x22/tracker.png); }
607 .icon22-role { background-image: url(../images/22x22/role.png); }
613 .icon22-role { background-image: url(../images/22x22/role.png); }
608 .icon22-workflow { background-image: url(../images/22x22/workflow.png); }
614 .icon22-workflow { background-image: url(../images/22x22/workflow.png); }
609 .icon22-options { background-image: url(../images/22x22/options.png); }
615 .icon22-options { background-image: url(../images/22x22/options.png); }
610 .icon22-notifications { background-image: url(../images/22x22/notifications.png); }
616 .icon22-notifications { background-image: url(../images/22x22/notifications.png); }
611 .icon22-authent { background-image: url(../images/22x22/authent.png); }
617 .icon22-authent { background-image: url(../images/22x22/authent.png); }
612 .icon22-info { background-image: url(../images/22x22/info.png); }
618 .icon22-info { background-image: url(../images/22x22/info.png); }
613 .icon22-comment { background-image: url(../images/22x22/comment.png); }
619 .icon22-comment { background-image: url(../images/22x22/comment.png); }
614 .icon22-package { background-image: url(../images/22x22/package.png); }
620 .icon22-package { background-image: url(../images/22x22/package.png); }
615 .icon22-settings { background-image: url(../images/22x22/settings.png); }
621 .icon22-settings { background-image: url(../images/22x22/settings.png); }
616 .icon22-plugin { background-image: url(../images/22x22/plugin.png); }
622 .icon22-plugin { background-image: url(../images/22x22/plugin.png); }
617
623
618 img.gravatar {
624 img.gravatar {
619 padding: 2px;
625 padding: 2px;
620 border: solid 1px #d5d5d5;
626 border: solid 1px #d5d5d5;
621 background: #fff;
627 background: #fff;
622 }
628 }
623
629
624 div.issue img.gravatar {
630 div.issue img.gravatar {
625 float: right;
631 float: right;
626 margin: 0 0 0 1em;
632 margin: 0 0 0 1em;
627 padding: 5px;
633 padding: 5px;
628 }
634 }
629
635
630 div.issue table img.gravatar {
636 div.issue table img.gravatar {
631 height: 14px;
637 height: 14px;
632 width: 14px;
638 width: 14px;
633 padding: 2px;
639 padding: 2px;
634 float: left;
640 float: left;
635 margin: 0 0.5em 0 0;
641 margin: 0 0.5em 0 0;
636 }
642 }
637
643
638 #history img.gravatar {
644 #history img.gravatar {
639 padding: 3px;
645 padding: 3px;
640 margin: 0 1.5em 1em 0;
646 margin: 0 1.5em 1em 0;
641 float: left;
647 float: left;
642 }
648 }
643
649
644 td.username img.gravatar {
650 td.username img.gravatar {
645 float: left;
651 float: left;
646 margin: 0 1em 0 0;
652 margin: 0 1em 0 0;
647 }
653 }
648
654
649 #activity dt img.gravatar {
655 #activity dt img.gravatar {
650 float: left;
656 float: left;
651 margin: 0 1em 1em 0;
657 margin: 0 1em 1em 0;
652 }
658 }
653
659
654 #activity dt,
660 #activity dt,
655 .journal {
661 .journal {
656 clear: left;
662 clear: left;
657 }
663 }
658
664
659
665
660 /***** Media print specific styles *****/
666 /***** Media print specific styles *****/
661 @media print {
667 @media print {
662 #top-menu, #header, #main-menu, #sidebar, #footer, .contextual, .other-formats { display:none; }
668 #top-menu, #header, #main-menu, #sidebar, #footer, .contextual, .other-formats { display:none; }
663 #main { background: #fff; }
669 #main { background: #fff; }
664 #content { width: 99%; margin: 0; padding: 0; border: 0; background: #fff; }
670 #content { width: 99%; margin: 0; padding: 0; border: 0; background: #fff; }
665 }
671 }
@@ -1,124 +1,124
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 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 require File.dirname(__FILE__) + '/../test_helper'
18 require File.dirname(__FILE__) + '/../test_helper'
19 require 'admin_controller'
19 require 'admin_controller'
20
20
21 # Re-raise errors caught by the controller.
21 # Re-raise errors caught by the controller.
22 class AdminController; def rescue_action(e) raise e end; end
22 class AdminController; def rescue_action(e) raise e end; end
23
23
24 class AdminControllerTest < Test::Unit::TestCase
24 class AdminControllerTest < Test::Unit::TestCase
25 fixtures :projects, :users, :roles
25 fixtures :projects, :users, :roles
26
26
27 def setup
27 def setup
28 @controller = AdminController.new
28 @controller = AdminController.new
29 @request = ActionController::TestRequest.new
29 @request = ActionController::TestRequest.new
30 @response = ActionController::TestResponse.new
30 @response = ActionController::TestResponse.new
31 User.current = nil
31 User.current = nil
32 @request.session[:user_id] = 1 # admin
32 @request.session[:user_id] = 1 # admin
33 end
33 end
34
34
35 def test_index
35 def test_index
36 get :index
36 get :index
37 assert_no_tag :tag => 'div',
37 assert_no_tag :tag => 'div',
38 :attributes => { :class => /nodata/ }
38 :attributes => { :class => /nodata/ }
39 end
39 end
40
40
41 def test_index_with_no_configuration_data
41 def test_index_with_no_configuration_data
42 delete_configuration_data
42 delete_configuration_data
43 get :index
43 get :index
44 assert_tag :tag => 'div',
44 assert_tag :tag => 'div',
45 :attributes => { :class => /nodata/ }
45 :attributes => { :class => /nodata/ }
46 end
46 end
47
47
48 def test_projects
48 def test_projects
49 get :projects
49 get :projects
50 assert_response :success
50 assert_response :success
51 assert_template 'projects'
51 assert_template 'projects'
52 assert_not_nil assigns(:projects)
52 assert_not_nil assigns(:projects)
53 # active projects only
53 # active projects only
54 assert_nil assigns(:projects).detect {|u| !u.active?}
54 assert_nil assigns(:projects).detect {|u| !u.active?}
55 end
55 end
56
56
57 def test_projects_with_name_filter
57 def test_projects_with_name_filter
58 get :projects, :name => 'store', :status => ''
58 get :projects, :name => 'store', :status => ''
59 assert_response :success
59 assert_response :success
60 assert_template 'projects'
60 assert_template 'projects'
61 projects = assigns(:projects)
61 projects = assigns(:projects)
62 assert_not_nil projects
62 assert_not_nil projects
63 assert_equal 1, projects.size
63 assert_equal 1, projects.size
64 assert_equal 'OnlineStore', projects.first.name
64 assert_equal 'OnlineStore', projects.first.name
65 end
65 end
66
66
67 def test_load_default_configuration_data
67 def test_load_default_configuration_data
68 delete_configuration_data
68 delete_configuration_data
69 post :default_configuration, :lang => 'fr'
69 post :default_configuration, :lang => 'fr'
70 assert IssueStatus.find_by_name('Nouveau')
70 assert IssueStatus.find_by_name('Nouveau')
71 end
71 end
72
72
73 def test_test_email
73 def test_test_email
74 get :test_email
74 get :test_email
75 assert_redirected_to 'settings/edit'
75 assert_redirected_to 'settings/edit'
76 mail = ActionMailer::Base.deliveries.last
76 mail = ActionMailer::Base.deliveries.last
77 assert_kind_of TMail::Mail, mail
77 assert_kind_of TMail::Mail, mail
78 user = User.find(1)
78 user = User.find(1)
79 assert_equal [user.mail], mail.bcc
79 assert_equal [user.mail], mail.bcc
80 end
80 end
81
81
82 def test_no_plugins
82 def test_no_plugins
83 Redmine::Plugin.clear
83 Redmine::Plugin.clear
84
84
85 get :plugins
85 get :plugins
86 assert_response :success
86 assert_response :success
87 assert_template 'plugins'
87 assert_template 'plugins'
88 end
88 end
89
89
90 def test_plugins
90 def test_plugins
91 # Register a few plugins
91 # Register a few plugins
92 Redmine::Plugin.register :foo do
92 Redmine::Plugin.register :foo do
93 name 'Foo plugin'
93 name 'Foo plugin'
94 author 'John Smith'
94 author 'John Smith'
95 description 'This is a test plugin'
95 description 'This is a test plugin'
96 version '0.0.1'
96 version '0.0.1'
97 settings :default => {'sample_setting' => 'value', 'foo'=>'bar'}, :partial => 'foo/settings'
97 settings :default => {'sample_setting' => 'value', 'foo'=>'bar'}, :partial => 'foo/settings'
98 end
98 end
99 Redmine::Plugin.register :bar do
99 Redmine::Plugin.register :bar do
100 end
100 end
101
101
102 get :plugins
102 get :plugins
103 assert_response :success
103 assert_response :success
104 assert_template 'plugins'
104 assert_template 'plugins'
105
105
106 assert_tag :td, :content => 'Foo plugin'
106 assert_tag :td, :child => { :tag => 'span', :content => 'Foo plugin' }
107 assert_tag :td, :content => 'Bar'
107 assert_tag :td, :child => { :tag => 'span', :content => 'Bar' }
108 end
108 end
109
109
110 def test_info
110 def test_info
111 get :info
111 get :info
112 assert_response :success
112 assert_response :success
113 assert_template 'info'
113 assert_template 'info'
114 end
114 end
115
115
116 private
116 private
117
117
118 def delete_configuration_data
118 def delete_configuration_data
119 Role.delete_all('builtin = 0')
119 Role.delete_all('builtin = 0')
120 Tracker.delete_all
120 Tracker.delete_all
121 IssueStatus.delete_all
121 IssueStatus.delete_all
122 Enumeration.delete_all
122 Enumeration.delete_all
123 end
123 end
124 end
124 end
@@ -1,51 +1,55
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2008 Jean-Philippe Lang
2 # Copyright (C) 2006-2008 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 require File.dirname(__FILE__) + '/../../../test_helper'
18 require File.dirname(__FILE__) + '/../../../test_helper'
19
19
20 class Redmine::PluginTest < Test::Unit::TestCase
20 class Redmine::PluginTest < Test::Unit::TestCase
21
21
22 def setup
22 def setup
23 @klass = Redmine::Plugin
23 @klass = Redmine::Plugin
24 # In case some real plugins are installed
24 # In case some real plugins are installed
25 @klass.clear
25 @klass.clear
26 end
26 end
27
27
28 def teardown
28 def teardown
29 @klass.clear
29 @klass.clear
30 end
30 end
31
31
32 def test_register
32 def test_register
33 @klass.register :foo do
33 @klass.register :foo do
34 name 'Foo plugin'
34 name 'Foo plugin'
35 url 'http://example.net/plugins/foo'
35 author 'John Smith'
36 author 'John Smith'
37 author_url 'http://example.net/jsmith'
36 description 'This is a test plugin'
38 description 'This is a test plugin'
37 version '0.0.1'
39 version '0.0.1'
38 settings :default => {'sample_setting' => 'value', 'foo'=>'bar'}, :partial => 'foo/settings'
40 settings :default => {'sample_setting' => 'value', 'foo'=>'bar'}, :partial => 'foo/settings'
39 end
41 end
40
42
41 assert_equal 1, @klass.all.size
43 assert_equal 1, @klass.all.size
42
44
43 plugin = @klass.find('foo')
45 plugin = @klass.find('foo')
44 assert plugin.is_a?(Redmine::Plugin)
46 assert plugin.is_a?(Redmine::Plugin)
45 assert_equal :foo, plugin.id
47 assert_equal :foo, plugin.id
46 assert_equal 'Foo plugin', plugin.name
48 assert_equal 'Foo plugin', plugin.name
49 assert_equal 'http://example.net/plugins/foo', plugin.url
47 assert_equal 'John Smith', plugin.author
50 assert_equal 'John Smith', plugin.author
51 assert_equal 'http://example.net/jsmith', plugin.author_url
48 assert_equal 'This is a test plugin', plugin.description
52 assert_equal 'This is a test plugin', plugin.description
49 assert_equal '0.0.1', plugin.version
53 assert_equal '0.0.1', plugin.version
50 end
54 end
51 end
55 end
General Comments 0
You need to be logged in to leave comments. Login now