##// END OF EJS Templates
Merged r3282 to r3284 from trunk....
Jean-Philippe Lang -
r3173:9d82bff1a84f
parent child
Show More
@@ -1,43 +1,42
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 module JournalsHelper
18 module JournalsHelper
19 def render_notes(journal, options={})
19 def render_notes(journal, options={})
20 content = ''
20 content = ''
21 editable = journal.editable_by?(User.current)
21 editable = journal.editable_by?(User.current)
22 links = []
22 links = []
23 if !journal.notes.blank?
23 if !journal.notes.blank?
24 links << link_to_remote(image_tag('comment.png'),
24 links << link_to_remote(image_tag('comment.png'),
25 { :url => {:controller => 'issues', :action => 'reply', :id => journal.journalized, :journal_id => journal} },
25 { :url => {:controller => 'issues', :action => 'reply', :id => journal.journalized, :journal_id => journal} },
26 :title => l(:button_quote)) if options[:reply_links]
26 :title => l(:button_quote)) if options[:reply_links]
27 links << link_to_in_place_notes_editor(image_tag('edit.png'), "journal-#{journal.id}-notes",
27 links << link_to_in_place_notes_editor(image_tag('edit.png'), "journal-#{journal.id}-notes",
28 { :controller => 'journals', :action => 'edit', :id => journal },
28 { :controller => 'journals', :action => 'edit', :id => journal },
29 :title => l(:button_edit)) if editable
29 :title => l(:button_edit)) if editable
30 end
30 end
31 content << content_tag('div', links.join(' '), :class => 'contextual') unless links.empty?
31 content << content_tag('div', links.join(' '), :class => 'contextual') unless links.empty?
32 content << textilizable(journal, :notes)
32 content << textilizable(journal, :notes)
33 css_classes = "wiki"
33 css_classes = "wiki"
34 css_classes << " editable" if editable
34 css_classes << " editable" if editable
35 css_classes << " gravatar-margin" if Setting.gravatar_enabled?
36 content_tag('div', content, :id => "journal-#{journal.id}-notes", :class => css_classes)
35 content_tag('div', content, :id => "journal-#{journal.id}-notes", :class => css_classes)
37 end
36 end
38
37
39 def link_to_in_place_notes_editor(text, field_id, url, options={})
38 def link_to_in_place_notes_editor(text, field_id, url, options={})
40 onclick = "new Ajax.Request('#{url_for(url)}', {asynchronous:true, evalScripts:true, method:'get'}); return false;"
39 onclick = "new Ajax.Request('#{url_for(url)}', {asynchronous:true, evalScripts:true, method:'get'}); return false;"
41 link_to text, '#', options.merge(:onclick => onclick)
40 link_to text, '#', options.merge(:onclick => onclick)
42 end
41 end
43 end
42 end
@@ -1,559 +1,559
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 class QueryColumn
18 class QueryColumn
19 attr_accessor :name, :sortable, :groupable, :default_order
19 attr_accessor :name, :sortable, :groupable, :default_order
20 include Redmine::I18n
20 include Redmine::I18n
21
21
22 def initialize(name, options={})
22 def initialize(name, options={})
23 self.name = name
23 self.name = name
24 self.sortable = options[:sortable]
24 self.sortable = options[:sortable]
25 self.groupable = options[:groupable] || false
25 self.groupable = options[:groupable] || false
26 if groupable == true
26 if groupable == true
27 self.groupable = name.to_s
27 self.groupable = name.to_s
28 end
28 end
29 self.default_order = options[:default_order]
29 self.default_order = options[:default_order]
30 end
30 end
31
31
32 def caption
32 def caption
33 l("field_#{name}")
33 l("field_#{name}")
34 end
34 end
35
35
36 # Returns true if the column is sortable, otherwise false
36 # Returns true if the column is sortable, otherwise false
37 def sortable?
37 def sortable?
38 !sortable.nil?
38 !sortable.nil?
39 end
39 end
40
40
41 def value(issue)
41 def value(issue)
42 issue.send name
42 issue.send name
43 end
43 end
44 end
44 end
45
45
46 class QueryCustomFieldColumn < QueryColumn
46 class QueryCustomFieldColumn < QueryColumn
47
47
48 def initialize(custom_field)
48 def initialize(custom_field)
49 self.name = "cf_#{custom_field.id}".to_sym
49 self.name = "cf_#{custom_field.id}".to_sym
50 self.sortable = custom_field.order_statement || false
50 self.sortable = custom_field.order_statement || false
51 if %w(list date bool int).include?(custom_field.field_format)
51 if %w(list date bool int).include?(custom_field.field_format)
52 self.groupable = custom_field.order_statement
52 self.groupable = custom_field.order_statement
53 end
53 end
54 self.groupable ||= false
54 self.groupable ||= false
55 @cf = custom_field
55 @cf = custom_field
56 end
56 end
57
57
58 def caption
58 def caption
59 @cf.name
59 @cf.name
60 end
60 end
61
61
62 def custom_field
62 def custom_field
63 @cf
63 @cf
64 end
64 end
65
65
66 def value(issue)
66 def value(issue)
67 cv = issue.custom_values.detect {|v| v.custom_field_id == @cf.id}
67 cv = issue.custom_values.detect {|v| v.custom_field_id == @cf.id}
68 cv && @cf.cast_value(cv.value)
68 cv && @cf.cast_value(cv.value)
69 end
69 end
70 end
70 end
71
71
72 class Query < ActiveRecord::Base
72 class Query < ActiveRecord::Base
73 class StatementInvalid < ::ActiveRecord::StatementInvalid
73 class StatementInvalid < ::ActiveRecord::StatementInvalid
74 end
74 end
75
75
76 belongs_to :project
76 belongs_to :project
77 belongs_to :user
77 belongs_to :user
78 serialize :filters
78 serialize :filters
79 serialize :column_names
79 serialize :column_names
80 serialize :sort_criteria, Array
80 serialize :sort_criteria, Array
81
81
82 attr_protected :project_id, :user_id
82 attr_protected :project_id, :user_id
83
83
84 validates_presence_of :name, :on => :save
84 validates_presence_of :name, :on => :save
85 validates_length_of :name, :maximum => 255
85 validates_length_of :name, :maximum => 255
86
86
87 @@operators = { "=" => :label_equals,
87 @@operators = { "=" => :label_equals,
88 "!" => :label_not_equals,
88 "!" => :label_not_equals,
89 "o" => :label_open_issues,
89 "o" => :label_open_issues,
90 "c" => :label_closed_issues,
90 "c" => :label_closed_issues,
91 "!*" => :label_none,
91 "!*" => :label_none,
92 "*" => :label_all,
92 "*" => :label_all,
93 ">=" => :label_greater_or_equal,
93 ">=" => :label_greater_or_equal,
94 "<=" => :label_less_or_equal,
94 "<=" => :label_less_or_equal,
95 "<t+" => :label_in_less_than,
95 "<t+" => :label_in_less_than,
96 ">t+" => :label_in_more_than,
96 ">t+" => :label_in_more_than,
97 "t+" => :label_in,
97 "t+" => :label_in,
98 "t" => :label_today,
98 "t" => :label_today,
99 "w" => :label_this_week,
99 "w" => :label_this_week,
100 ">t-" => :label_less_than_ago,
100 ">t-" => :label_less_than_ago,
101 "<t-" => :label_more_than_ago,
101 "<t-" => :label_more_than_ago,
102 "t-" => :label_ago,
102 "t-" => :label_ago,
103 "~" => :label_contains,
103 "~" => :label_contains,
104 "!~" => :label_not_contains }
104 "!~" => :label_not_contains }
105
105
106 cattr_reader :operators
106 cattr_reader :operators
107
107
108 @@operators_by_filter_type = { :list => [ "=", "!" ],
108 @@operators_by_filter_type = { :list => [ "=", "!" ],
109 :list_status => [ "o", "=", "!", "c", "*" ],
109 :list_status => [ "o", "=", "!", "c", "*" ],
110 :list_optional => [ "=", "!", "!*", "*" ],
110 :list_optional => [ "=", "!", "!*", "*" ],
111 :list_subprojects => [ "*", "!*", "=" ],
111 :list_subprojects => [ "*", "!*", "=" ],
112 :date => [ "<t+", ">t+", "t+", "t", "w", ">t-", "<t-", "t-" ],
112 :date => [ "<t+", ">t+", "t+", "t", "w", ">t-", "<t-", "t-" ],
113 :date_past => [ ">t-", "<t-", "t-", "t", "w" ],
113 :date_past => [ ">t-", "<t-", "t-", "t", "w" ],
114 :string => [ "=", "~", "!", "!~" ],
114 :string => [ "=", "~", "!", "!~" ],
115 :text => [ "~", "!~" ],
115 :text => [ "~", "!~" ],
116 :integer => [ "=", ">=", "<=", "!*", "*" ] }
116 :integer => [ "=", ">=", "<=", "!*", "*" ] }
117
117
118 cattr_reader :operators_by_filter_type
118 cattr_reader :operators_by_filter_type
119
119
120 @@available_columns = [
120 @@available_columns = [
121 QueryColumn.new(:project, :sortable => "#{Project.table_name}.name", :groupable => true),
121 QueryColumn.new(:project, :sortable => "#{Project.table_name}.name", :groupable => true),
122 QueryColumn.new(:tracker, :sortable => "#{Tracker.table_name}.position", :groupable => true),
122 QueryColumn.new(:tracker, :sortable => "#{Tracker.table_name}.position", :groupable => true),
123 QueryColumn.new(:status, :sortable => "#{IssueStatus.table_name}.position", :groupable => true),
123 QueryColumn.new(:status, :sortable => "#{IssueStatus.table_name}.position", :groupable => true),
124 QueryColumn.new(:priority, :sortable => "#{IssuePriority.table_name}.position", :default_order => 'desc', :groupable => true),
124 QueryColumn.new(:priority, :sortable => "#{IssuePriority.table_name}.position", :default_order => 'desc', :groupable => true),
125 QueryColumn.new(:subject, :sortable => "#{Issue.table_name}.subject"),
125 QueryColumn.new(:subject, :sortable => "#{Issue.table_name}.subject"),
126 QueryColumn.new(:author),
126 QueryColumn.new(:author),
127 QueryColumn.new(:assigned_to, :sortable => ["#{User.table_name}.lastname", "#{User.table_name}.firstname", "#{User.table_name}.id"], :groupable => true),
127 QueryColumn.new(:assigned_to, :sortable => ["#{User.table_name}.lastname", "#{User.table_name}.firstname", "#{User.table_name}.id"], :groupable => true),
128 QueryColumn.new(:updated_on, :sortable => "#{Issue.table_name}.updated_on", :default_order => 'desc'),
128 QueryColumn.new(:updated_on, :sortable => "#{Issue.table_name}.updated_on", :default_order => 'desc'),
129 QueryColumn.new(:category, :sortable => "#{IssueCategory.table_name}.name", :groupable => true),
129 QueryColumn.new(:category, :sortable => "#{IssueCategory.table_name}.name", :groupable => true),
130 QueryColumn.new(:fixed_version, :sortable => ["#{Version.table_name}.effective_date", "#{Version.table_name}.name"], :default_order => 'desc', :groupable => true),
130 QueryColumn.new(:fixed_version, :sortable => ["#{Version.table_name}.effective_date", "#{Version.table_name}.name"], :default_order => 'desc', :groupable => true),
131 QueryColumn.new(:start_date, :sortable => "#{Issue.table_name}.start_date"),
131 QueryColumn.new(:start_date, :sortable => "#{Issue.table_name}.start_date"),
132 QueryColumn.new(:due_date, :sortable => "#{Issue.table_name}.due_date"),
132 QueryColumn.new(:due_date, :sortable => "#{Issue.table_name}.due_date"),
133 QueryColumn.new(:estimated_hours, :sortable => "#{Issue.table_name}.estimated_hours"),
133 QueryColumn.new(:estimated_hours, :sortable => "#{Issue.table_name}.estimated_hours"),
134 QueryColumn.new(:done_ratio, :sortable => "#{Issue.table_name}.done_ratio", :groupable => true),
134 QueryColumn.new(:done_ratio, :sortable => "#{Issue.table_name}.done_ratio", :groupable => true),
135 QueryColumn.new(:created_on, :sortable => "#{Issue.table_name}.created_on", :default_order => 'desc'),
135 QueryColumn.new(:created_on, :sortable => "#{Issue.table_name}.created_on", :default_order => 'desc'),
136 ]
136 ]
137 cattr_reader :available_columns
137 cattr_reader :available_columns
138
138
139 def initialize(attributes = nil)
139 def initialize(attributes = nil)
140 super attributes
140 super attributes
141 self.filters ||= { 'status_id' => {:operator => "o", :values => [""]} }
141 self.filters ||= { 'status_id' => {:operator => "o", :values => [""]} }
142 end
142 end
143
143
144 def after_initialize
144 def after_initialize
145 # Store the fact that project is nil (used in #editable_by?)
145 # Store the fact that project is nil (used in #editable_by?)
146 @is_for_all = project.nil?
146 @is_for_all = project.nil?
147 end
147 end
148
148
149 def validate
149 def validate
150 filters.each_key do |field|
150 filters.each_key do |field|
151 errors.add label_for(field), :blank unless
151 errors.add label_for(field), :blank unless
152 # filter requires one or more values
152 # filter requires one or more values
153 (values_for(field) and !values_for(field).first.blank?) or
153 (values_for(field) and !values_for(field).first.blank?) or
154 # filter doesn't require any value
154 # filter doesn't require any value
155 ["o", "c", "!*", "*", "t", "w"].include? operator_for(field)
155 ["o", "c", "!*", "*", "t", "w"].include? operator_for(field)
156 end if filters
156 end if filters
157 end
157 end
158
158
159 def editable_by?(user)
159 def editable_by?(user)
160 return false unless user
160 return false unless user
161 # Admin can edit them all and regular users can edit their private queries
161 # Admin can edit them all and regular users can edit their private queries
162 return true if user.admin? || (!is_public && self.user_id == user.id)
162 return true if user.admin? || (!is_public && self.user_id == user.id)
163 # Members can not edit public queries that are for all project (only admin is allowed to)
163 # Members can not edit public queries that are for all project (only admin is allowed to)
164 is_public && !@is_for_all && user.allowed_to?(:manage_public_queries, project)
164 is_public && !@is_for_all && user.allowed_to?(:manage_public_queries, project)
165 end
165 end
166
166
167 def available_filters
167 def available_filters
168 return @available_filters if @available_filters
168 return @available_filters if @available_filters
169
169
170 trackers = project.nil? ? Tracker.find(:all, :order => 'position') : project.rolled_up_trackers
170 trackers = project.nil? ? Tracker.find(:all, :order => 'position') : project.rolled_up_trackers
171
171
172 @available_filters = { "status_id" => { :type => :list_status, :order => 1, :values => IssueStatus.find(:all, :order => 'position').collect{|s| [s.name, s.id.to_s] } },
172 @available_filters = { "status_id" => { :type => :list_status, :order => 1, :values => IssueStatus.find(:all, :order => 'position').collect{|s| [s.name, s.id.to_s] } },
173 "tracker_id" => { :type => :list, :order => 2, :values => trackers.collect{|s| [s.name, s.id.to_s] } },
173 "tracker_id" => { :type => :list, :order => 2, :values => trackers.collect{|s| [s.name, s.id.to_s] } },
174 "priority_id" => { :type => :list, :order => 3, :values => IssuePriority.all.collect{|s| [s.name, s.id.to_s] } },
174 "priority_id" => { :type => :list, :order => 3, :values => IssuePriority.all.collect{|s| [s.name, s.id.to_s] } },
175 "subject" => { :type => :text, :order => 8 },
175 "subject" => { :type => :text, :order => 8 },
176 "created_on" => { :type => :date_past, :order => 9 },
176 "created_on" => { :type => :date_past, :order => 9 },
177 "updated_on" => { :type => :date_past, :order => 10 },
177 "updated_on" => { :type => :date_past, :order => 10 },
178 "start_date" => { :type => :date, :order => 11 },
178 "start_date" => { :type => :date, :order => 11 },
179 "due_date" => { :type => :date, :order => 12 },
179 "due_date" => { :type => :date, :order => 12 },
180 "estimated_hours" => { :type => :integer, :order => 13 },
180 "estimated_hours" => { :type => :integer, :order => 13 },
181 "done_ratio" => { :type => :integer, :order => 14 }}
181 "done_ratio" => { :type => :integer, :order => 14 }}
182
182
183 user_values = []
183 user_values = []
184 user_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged?
184 user_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged?
185 if project
185 if project
186 user_values += project.users.sort.collect{|s| [s.name, s.id.to_s] }
186 user_values += project.users.sort.collect{|s| [s.name, s.id.to_s] }
187 else
187 else
188 # members of the user's projects
188 # members of the user's projects
189 # OPTIMIZE: Is selecting from users per project (N+1)
189 # OPTIMIZE: Is selecting from users per project (N+1)
190 user_values += User.current.projects.collect(&:users).flatten.uniq.sort.collect{|s| [s.name, s.id.to_s] }
190 user_values += User.current.projects.collect(&:users).flatten.uniq.sort.collect{|s| [s.name, s.id.to_s] }
191 end
191 end
192 @available_filters["assigned_to_id"] = { :type => :list_optional, :order => 4, :values => user_values } unless user_values.empty?
192 @available_filters["assigned_to_id"] = { :type => :list_optional, :order => 4, :values => user_values } unless user_values.empty?
193 @available_filters["author_id"] = { :type => :list, :order => 5, :values => user_values } unless user_values.empty?
193 @available_filters["author_id"] = { :type => :list, :order => 5, :values => user_values } unless user_values.empty?
194
194
195 if User.current.logged?
195 if User.current.logged?
196 @available_filters["watcher_id"] = { :type => :list, :order => 15, :values => [["<< #{l(:label_me)} >>", "me"]] }
196 @available_filters["watcher_id"] = { :type => :list, :order => 15, :values => [["<< #{l(:label_me)} >>", "me"]] }
197 end
197 end
198
198
199 if project
199 if project
200 # project specific filters
200 # project specific filters
201 unless @project.issue_categories.empty?
201 unless @project.issue_categories.empty?
202 @available_filters["category_id"] = { :type => :list_optional, :order => 6, :values => @project.issue_categories.collect{|s| [s.name, s.id.to_s] } }
202 @available_filters["category_id"] = { :type => :list_optional, :order => 6, :values => @project.issue_categories.collect{|s| [s.name, s.id.to_s] } }
203 end
203 end
204 unless @project.shared_versions.empty?
204 unless @project.shared_versions.empty?
205 @available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => @project.shared_versions.sort.collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s] } }
205 @available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => @project.shared_versions.sort.collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s] } }
206 end
206 end
207 unless @project.descendants.active.empty?
207 unless @project.descendants.active.empty?
208 @available_filters["subproject_id"] = { :type => :list_subprojects, :order => 13, :values => @project.descendants.visible.collect{|s| [s.name, s.id.to_s] } }
208 @available_filters["subproject_id"] = { :type => :list_subprojects, :order => 13, :values => @project.descendants.visible.collect{|s| [s.name, s.id.to_s] } }
209 end
209 end
210 add_custom_fields_filters(@project.all_issue_custom_fields)
210 add_custom_fields_filters(@project.all_issue_custom_fields)
211 else
211 else
212 # global filters for cross project issue list
212 # global filters for cross project issue list
213 add_custom_fields_filters(IssueCustomField.find(:all, :conditions => {:is_filter => true, :is_for_all => true}))
213 add_custom_fields_filters(IssueCustomField.find(:all, :conditions => {:is_filter => true, :is_for_all => true}))
214 end
214 end
215 @available_filters
215 @available_filters
216 end
216 end
217
217
218 def add_filter(field, operator, values)
218 def add_filter(field, operator, values)
219 # values must be an array
219 # values must be an array
220 return unless values and values.is_a? Array # and !values.first.empty?
220 return unless values and values.is_a? Array # and !values.first.empty?
221 # check if field is defined as an available filter
221 # check if field is defined as an available filter
222 if available_filters.has_key? field
222 if available_filters.has_key? field
223 filter_options = available_filters[field]
223 filter_options = available_filters[field]
224 # check if operator is allowed for that filter
224 # check if operator is allowed for that filter
225 #if @@operators_by_filter_type[filter_options[:type]].include? operator
225 #if @@operators_by_filter_type[filter_options[:type]].include? operator
226 # allowed_values = values & ([""] + (filter_options[:values] || []).collect {|val| val[1]})
226 # allowed_values = values & ([""] + (filter_options[:values] || []).collect {|val| val[1]})
227 # filters[field] = {:operator => operator, :values => allowed_values } if (allowed_values.first and !allowed_values.first.empty?) or ["o", "c", "!*", "*", "t"].include? operator
227 # filters[field] = {:operator => operator, :values => allowed_values } if (allowed_values.first and !allowed_values.first.empty?) or ["o", "c", "!*", "*", "t"].include? operator
228 #end
228 #end
229 filters[field] = {:operator => operator, :values => values }
229 filters[field] = {:operator => operator, :values => values }
230 end
230 end
231 end
231 end
232
232
233 def add_short_filter(field, expression)
233 def add_short_filter(field, expression)
234 return unless expression
234 return unless expression
235 parms = expression.scan(/^(o|c|\!|\*)?(.*)$/).first
235 parms = expression.scan(/^(o|c|!\*|!|\*)?(.*)$/).first
236 add_filter field, (parms[0] || "="), [parms[1] || ""]
236 add_filter field, (parms[0] || "="), [parms[1] || ""]
237 end
237 end
238
238
239 def has_filter?(field)
239 def has_filter?(field)
240 filters and filters[field]
240 filters and filters[field]
241 end
241 end
242
242
243 def operator_for(field)
243 def operator_for(field)
244 has_filter?(field) ? filters[field][:operator] : nil
244 has_filter?(field) ? filters[field][:operator] : nil
245 end
245 end
246
246
247 def values_for(field)
247 def values_for(field)
248 has_filter?(field) ? filters[field][:values] : nil
248 has_filter?(field) ? filters[field][:values] : nil
249 end
249 end
250
250
251 def label_for(field)
251 def label_for(field)
252 label = available_filters[field][:name] if available_filters.has_key?(field)
252 label = available_filters[field][:name] if available_filters.has_key?(field)
253 label ||= field.gsub(/\_id$/, "")
253 label ||= field.gsub(/\_id$/, "")
254 end
254 end
255
255
256 def available_columns
256 def available_columns
257 return @available_columns if @available_columns
257 return @available_columns if @available_columns
258 @available_columns = Query.available_columns
258 @available_columns = Query.available_columns
259 @available_columns += (project ?
259 @available_columns += (project ?
260 project.all_issue_custom_fields :
260 project.all_issue_custom_fields :
261 IssueCustomField.find(:all)
261 IssueCustomField.find(:all)
262 ).collect {|cf| QueryCustomFieldColumn.new(cf) }
262 ).collect {|cf| QueryCustomFieldColumn.new(cf) }
263 end
263 end
264
264
265 # Returns an array of columns that can be used to group the results
265 # Returns an array of columns that can be used to group the results
266 def groupable_columns
266 def groupable_columns
267 available_columns.select {|c| c.groupable}
267 available_columns.select {|c| c.groupable}
268 end
268 end
269
269
270 def columns
270 def columns
271 if has_default_columns?
271 if has_default_columns?
272 available_columns.select do |c|
272 available_columns.select do |c|
273 # Adds the project column by default for cross-project lists
273 # Adds the project column by default for cross-project lists
274 Setting.issue_list_default_columns.include?(c.name.to_s) || (c.name == :project && project.nil?)
274 Setting.issue_list_default_columns.include?(c.name.to_s) || (c.name == :project && project.nil?)
275 end
275 end
276 else
276 else
277 # preserve the column_names order
277 # preserve the column_names order
278 column_names.collect {|name| available_columns.find {|col| col.name == name}}.compact
278 column_names.collect {|name| available_columns.find {|col| col.name == name}}.compact
279 end
279 end
280 end
280 end
281
281
282 def column_names=(names)
282 def column_names=(names)
283 if names
283 if names
284 names = names.select {|n| n.is_a?(Symbol) || !n.blank? }
284 names = names.select {|n| n.is_a?(Symbol) || !n.blank? }
285 names = names.collect {|n| n.is_a?(Symbol) ? n : n.to_sym }
285 names = names.collect {|n| n.is_a?(Symbol) ? n : n.to_sym }
286 # Set column_names to nil if default columns
286 # Set column_names to nil if default columns
287 if names.map(&:to_s) == Setting.issue_list_default_columns
287 if names.map(&:to_s) == Setting.issue_list_default_columns
288 names = nil
288 names = nil
289 end
289 end
290 end
290 end
291 write_attribute(:column_names, names)
291 write_attribute(:column_names, names)
292 end
292 end
293
293
294 def has_column?(column)
294 def has_column?(column)
295 column_names && column_names.include?(column.name)
295 column_names && column_names.include?(column.name)
296 end
296 end
297
297
298 def has_default_columns?
298 def has_default_columns?
299 column_names.nil? || column_names.empty?
299 column_names.nil? || column_names.empty?
300 end
300 end
301
301
302 def sort_criteria=(arg)
302 def sort_criteria=(arg)
303 c = []
303 c = []
304 if arg.is_a?(Hash)
304 if arg.is_a?(Hash)
305 arg = arg.keys.sort.collect {|k| arg[k]}
305 arg = arg.keys.sort.collect {|k| arg[k]}
306 end
306 end
307 c = arg.select {|k,o| !k.to_s.blank?}.slice(0,3).collect {|k,o| [k.to_s, o == 'desc' ? o : 'asc']}
307 c = arg.select {|k,o| !k.to_s.blank?}.slice(0,3).collect {|k,o| [k.to_s, o == 'desc' ? o : 'asc']}
308 write_attribute(:sort_criteria, c)
308 write_attribute(:sort_criteria, c)
309 end
309 end
310
310
311 def sort_criteria
311 def sort_criteria
312 read_attribute(:sort_criteria) || []
312 read_attribute(:sort_criteria) || []
313 end
313 end
314
314
315 def sort_criteria_key(arg)
315 def sort_criteria_key(arg)
316 sort_criteria && sort_criteria[arg] && sort_criteria[arg].first
316 sort_criteria && sort_criteria[arg] && sort_criteria[arg].first
317 end
317 end
318
318
319 def sort_criteria_order(arg)
319 def sort_criteria_order(arg)
320 sort_criteria && sort_criteria[arg] && sort_criteria[arg].last
320 sort_criteria && sort_criteria[arg] && sort_criteria[arg].last
321 end
321 end
322
322
323 # Returns the SQL sort order that should be prepended for grouping
323 # Returns the SQL sort order that should be prepended for grouping
324 def group_by_sort_order
324 def group_by_sort_order
325 if grouped? && (column = group_by_column)
325 if grouped? && (column = group_by_column)
326 column.sortable.is_a?(Array) ?
326 column.sortable.is_a?(Array) ?
327 column.sortable.collect {|s| "#{s} #{column.default_order}"}.join(',') :
327 column.sortable.collect {|s| "#{s} #{column.default_order}"}.join(',') :
328 "#{column.sortable} #{column.default_order}"
328 "#{column.sortable} #{column.default_order}"
329 end
329 end
330 end
330 end
331
331
332 # Returns true if the query is a grouped query
332 # Returns true if the query is a grouped query
333 def grouped?
333 def grouped?
334 !group_by.blank?
334 !group_by.blank?
335 end
335 end
336
336
337 def group_by_column
337 def group_by_column
338 groupable_columns.detect {|c| c.name.to_s == group_by}
338 groupable_columns.detect {|c| c.name.to_s == group_by}
339 end
339 end
340
340
341 def group_by_statement
341 def group_by_statement
342 group_by_column.groupable
342 group_by_column.groupable
343 end
343 end
344
344
345 def project_statement
345 def project_statement
346 project_clauses = []
346 project_clauses = []
347 if project && !@project.descendants.active.empty?
347 if project && !@project.descendants.active.empty?
348 ids = [project.id]
348 ids = [project.id]
349 if has_filter?("subproject_id")
349 if has_filter?("subproject_id")
350 case operator_for("subproject_id")
350 case operator_for("subproject_id")
351 when '='
351 when '='
352 # include the selected subprojects
352 # include the selected subprojects
353 ids += values_for("subproject_id").each(&:to_i)
353 ids += values_for("subproject_id").each(&:to_i)
354 when '!*'
354 when '!*'
355 # main project only
355 # main project only
356 else
356 else
357 # all subprojects
357 # all subprojects
358 ids += project.descendants.collect(&:id)
358 ids += project.descendants.collect(&:id)
359 end
359 end
360 elsif Setting.display_subprojects_issues?
360 elsif Setting.display_subprojects_issues?
361 ids += project.descendants.collect(&:id)
361 ids += project.descendants.collect(&:id)
362 end
362 end
363 project_clauses << "#{Project.table_name}.id IN (%s)" % ids.join(',')
363 project_clauses << "#{Project.table_name}.id IN (%s)" % ids.join(',')
364 elsif project
364 elsif project
365 project_clauses << "#{Project.table_name}.id = %d" % project.id
365 project_clauses << "#{Project.table_name}.id = %d" % project.id
366 end
366 end
367 project_clauses << Project.allowed_to_condition(User.current, :view_issues)
367 project_clauses << Project.allowed_to_condition(User.current, :view_issues)
368 project_clauses.join(' AND ')
368 project_clauses.join(' AND ')
369 end
369 end
370
370
371 def statement
371 def statement
372 # filters clauses
372 # filters clauses
373 filters_clauses = []
373 filters_clauses = []
374 filters.each_key do |field|
374 filters.each_key do |field|
375 next if field == "subproject_id"
375 next if field == "subproject_id"
376 v = values_for(field).clone
376 v = values_for(field).clone
377 next unless v and !v.empty?
377 next unless v and !v.empty?
378 operator = operator_for(field)
378 operator = operator_for(field)
379
379
380 # "me" value subsitution
380 # "me" value subsitution
381 if %w(assigned_to_id author_id watcher_id).include?(field)
381 if %w(assigned_to_id author_id watcher_id).include?(field)
382 v.push(User.current.logged? ? User.current.id.to_s : "0") if v.delete("me")
382 v.push(User.current.logged? ? User.current.id.to_s : "0") if v.delete("me")
383 end
383 end
384
384
385 sql = ''
385 sql = ''
386 if field =~ /^cf_(\d+)$/
386 if field =~ /^cf_(\d+)$/
387 # custom field
387 # custom field
388 db_table = CustomValue.table_name
388 db_table = CustomValue.table_name
389 db_field = 'value'
389 db_field = 'value'
390 is_custom_filter = true
390 is_custom_filter = true
391 sql << "#{Issue.table_name}.id IN (SELECT #{Issue.table_name}.id FROM #{Issue.table_name} LEFT OUTER JOIN #{db_table} ON #{db_table}.customized_type='Issue' AND #{db_table}.customized_id=#{Issue.table_name}.id AND #{db_table}.custom_field_id=#{$1} WHERE "
391 sql << "#{Issue.table_name}.id IN (SELECT #{Issue.table_name}.id FROM #{Issue.table_name} LEFT OUTER JOIN #{db_table} ON #{db_table}.customized_type='Issue' AND #{db_table}.customized_id=#{Issue.table_name}.id AND #{db_table}.custom_field_id=#{$1} WHERE "
392 sql << sql_for_field(field, operator, v, db_table, db_field, true) + ')'
392 sql << sql_for_field(field, operator, v, db_table, db_field, true) + ')'
393 elsif field == 'watcher_id'
393 elsif field == 'watcher_id'
394 db_table = Watcher.table_name
394 db_table = Watcher.table_name
395 db_field = 'user_id'
395 db_field = 'user_id'
396 sql << "#{Issue.table_name}.id #{ operator == '=' ? 'IN' : 'NOT IN' } (SELECT #{db_table}.watchable_id FROM #{db_table} WHERE #{db_table}.watchable_type='Issue' AND "
396 sql << "#{Issue.table_name}.id #{ operator == '=' ? 'IN' : 'NOT IN' } (SELECT #{db_table}.watchable_id FROM #{db_table} WHERE #{db_table}.watchable_type='Issue' AND "
397 sql << sql_for_field(field, '=', v, db_table, db_field) + ')'
397 sql << sql_for_field(field, '=', v, db_table, db_field) + ')'
398 else
398 else
399 # regular field
399 # regular field
400 db_table = Issue.table_name
400 db_table = Issue.table_name
401 db_field = field
401 db_field = field
402 sql << '(' + sql_for_field(field, operator, v, db_table, db_field) + ')'
402 sql << '(' + sql_for_field(field, operator, v, db_table, db_field) + ')'
403 end
403 end
404 filters_clauses << sql
404 filters_clauses << sql
405
405
406 end if filters and valid?
406 end if filters and valid?
407
407
408 (filters_clauses << project_statement).join(' AND ')
408 (filters_clauses << project_statement).join(' AND ')
409 end
409 end
410
410
411 # Returns the issue count
411 # Returns the issue count
412 def issue_count
412 def issue_count
413 Issue.count(:include => [:status, :project], :conditions => statement)
413 Issue.count(:include => [:status, :project], :conditions => statement)
414 rescue ::ActiveRecord::StatementInvalid => e
414 rescue ::ActiveRecord::StatementInvalid => e
415 raise StatementInvalid.new(e.message)
415 raise StatementInvalid.new(e.message)
416 end
416 end
417
417
418 # Returns the issue count by group or nil if query is not grouped
418 # Returns the issue count by group or nil if query is not grouped
419 def issue_count_by_group
419 def issue_count_by_group
420 r = nil
420 r = nil
421 if grouped?
421 if grouped?
422 begin
422 begin
423 # Rails will raise an (unexpected) RecordNotFound if there's only a nil group value
423 # Rails will raise an (unexpected) RecordNotFound if there's only a nil group value
424 r = Issue.count(:group => group_by_statement, :include => [:status, :project], :conditions => statement)
424 r = Issue.count(:group => group_by_statement, :include => [:status, :project], :conditions => statement)
425 rescue ActiveRecord::RecordNotFound
425 rescue ActiveRecord::RecordNotFound
426 r = {nil => issue_count}
426 r = {nil => issue_count}
427 end
427 end
428 c = group_by_column
428 c = group_by_column
429 if c.is_a?(QueryCustomFieldColumn)
429 if c.is_a?(QueryCustomFieldColumn)
430 r = r.keys.inject({}) {|h, k| h[c.custom_field.cast_value(k)] = r[k]; h}
430 r = r.keys.inject({}) {|h, k| h[c.custom_field.cast_value(k)] = r[k]; h}
431 end
431 end
432 end
432 end
433 r
433 r
434 rescue ::ActiveRecord::StatementInvalid => e
434 rescue ::ActiveRecord::StatementInvalid => e
435 raise StatementInvalid.new(e.message)
435 raise StatementInvalid.new(e.message)
436 end
436 end
437
437
438 # Returns the issues
438 # Returns the issues
439 # Valid options are :order, :offset, :limit, :include, :conditions
439 # Valid options are :order, :offset, :limit, :include, :conditions
440 def issues(options={})
440 def issues(options={})
441 order_option = [group_by_sort_order, options[:order]].reject {|s| s.blank?}.join(',')
441 order_option = [group_by_sort_order, options[:order]].reject {|s| s.blank?}.join(',')
442 order_option = nil if order_option.blank?
442 order_option = nil if order_option.blank?
443
443
444 Issue.find :all, :include => ([:status, :project] + (options[:include] || [])).uniq,
444 Issue.find :all, :include => ([:status, :project] + (options[:include] || [])).uniq,
445 :conditions => Query.merge_conditions(statement, options[:conditions]),
445 :conditions => Query.merge_conditions(statement, options[:conditions]),
446 :order => order_option,
446 :order => order_option,
447 :limit => options[:limit],
447 :limit => options[:limit],
448 :offset => options[:offset]
448 :offset => options[:offset]
449 rescue ::ActiveRecord::StatementInvalid => e
449 rescue ::ActiveRecord::StatementInvalid => e
450 raise StatementInvalid.new(e.message)
450 raise StatementInvalid.new(e.message)
451 end
451 end
452
452
453 # Returns the journals
453 # Returns the journals
454 # Valid options are :order, :offset, :limit
454 # Valid options are :order, :offset, :limit
455 def journals(options={})
455 def journals(options={})
456 Journal.find :all, :include => [:details, :user, {:issue => [:project, :author, :tracker, :status]}],
456 Journal.find :all, :include => [:details, :user, {:issue => [:project, :author, :tracker, :status]}],
457 :conditions => statement,
457 :conditions => statement,
458 :order => options[:order],
458 :order => options[:order],
459 :limit => options[:limit],
459 :limit => options[:limit],
460 :offset => options[:offset]
460 :offset => options[:offset]
461 rescue ::ActiveRecord::StatementInvalid => e
461 rescue ::ActiveRecord::StatementInvalid => e
462 raise StatementInvalid.new(e.message)
462 raise StatementInvalid.new(e.message)
463 end
463 end
464
464
465 # Returns the versions
465 # Returns the versions
466 # Valid options are :conditions
466 # Valid options are :conditions
467 def versions(options={})
467 def versions(options={})
468 Version.find :all, :include => :project,
468 Version.find :all, :include => :project,
469 :conditions => Query.merge_conditions(project_statement, options[:conditions])
469 :conditions => Query.merge_conditions(project_statement, options[:conditions])
470 rescue ::ActiveRecord::StatementInvalid => e
470 rescue ::ActiveRecord::StatementInvalid => e
471 raise StatementInvalid.new(e.message)
471 raise StatementInvalid.new(e.message)
472 end
472 end
473
473
474 private
474 private
475
475
476 # Helper method to generate the WHERE sql for a +field+, +operator+ and a +value+
476 # Helper method to generate the WHERE sql for a +field+, +operator+ and a +value+
477 def sql_for_field(field, operator, value, db_table, db_field, is_custom_filter=false)
477 def sql_for_field(field, operator, value, db_table, db_field, is_custom_filter=false)
478 sql = ''
478 sql = ''
479 case operator
479 case operator
480 when "="
480 when "="
481 sql = "#{db_table}.#{db_field} IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")"
481 sql = "#{db_table}.#{db_field} IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")"
482 when "!"
482 when "!"
483 sql = "(#{db_table}.#{db_field} IS NULL OR #{db_table}.#{db_field} NOT IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + "))"
483 sql = "(#{db_table}.#{db_field} IS NULL OR #{db_table}.#{db_field} NOT IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + "))"
484 when "!*"
484 when "!*"
485 sql = "#{db_table}.#{db_field} IS NULL"
485 sql = "#{db_table}.#{db_field} IS NULL"
486 sql << " OR #{db_table}.#{db_field} = ''" if is_custom_filter
486 sql << " OR #{db_table}.#{db_field} = ''" if is_custom_filter
487 when "*"
487 when "*"
488 sql = "#{db_table}.#{db_field} IS NOT NULL"
488 sql = "#{db_table}.#{db_field} IS NOT NULL"
489 sql << " AND #{db_table}.#{db_field} <> ''" if is_custom_filter
489 sql << " AND #{db_table}.#{db_field} <> ''" if is_custom_filter
490 when ">="
490 when ">="
491 sql = "#{db_table}.#{db_field} >= #{value.first.to_i}"
491 sql = "#{db_table}.#{db_field} >= #{value.first.to_i}"
492 when "<="
492 when "<="
493 sql = "#{db_table}.#{db_field} <= #{value.first.to_i}"
493 sql = "#{db_table}.#{db_field} <= #{value.first.to_i}"
494 when "o"
494 when "o"
495 sql = "#{IssueStatus.table_name}.is_closed=#{connection.quoted_false}" if field == "status_id"
495 sql = "#{IssueStatus.table_name}.is_closed=#{connection.quoted_false}" if field == "status_id"
496 when "c"
496 when "c"
497 sql = "#{IssueStatus.table_name}.is_closed=#{connection.quoted_true}" if field == "status_id"
497 sql = "#{IssueStatus.table_name}.is_closed=#{connection.quoted_true}" if field == "status_id"
498 when ">t-"
498 when ">t-"
499 sql = date_range_clause(db_table, db_field, - value.first.to_i, 0)
499 sql = date_range_clause(db_table, db_field, - value.first.to_i, 0)
500 when "<t-"
500 when "<t-"
501 sql = date_range_clause(db_table, db_field, nil, - value.first.to_i)
501 sql = date_range_clause(db_table, db_field, nil, - value.first.to_i)
502 when "t-"
502 when "t-"
503 sql = date_range_clause(db_table, db_field, - value.first.to_i, - value.first.to_i)
503 sql = date_range_clause(db_table, db_field, - value.first.to_i, - value.first.to_i)
504 when ">t+"
504 when ">t+"
505 sql = date_range_clause(db_table, db_field, value.first.to_i, nil)
505 sql = date_range_clause(db_table, db_field, value.first.to_i, nil)
506 when "<t+"
506 when "<t+"
507 sql = date_range_clause(db_table, db_field, 0, value.first.to_i)
507 sql = date_range_clause(db_table, db_field, 0, value.first.to_i)
508 when "t+"
508 when "t+"
509 sql = date_range_clause(db_table, db_field, value.first.to_i, value.first.to_i)
509 sql = date_range_clause(db_table, db_field, value.first.to_i, value.first.to_i)
510 when "t"
510 when "t"
511 sql = date_range_clause(db_table, db_field, 0, 0)
511 sql = date_range_clause(db_table, db_field, 0, 0)
512 when "w"
512 when "w"
513 from = l(:general_first_day_of_week) == '7' ?
513 from = l(:general_first_day_of_week) == '7' ?
514 # week starts on sunday
514 # week starts on sunday
515 ((Date.today.cwday == 7) ? Time.now.at_beginning_of_day : Time.now.at_beginning_of_week - 1.day) :
515 ((Date.today.cwday == 7) ? Time.now.at_beginning_of_day : Time.now.at_beginning_of_week - 1.day) :
516 # week starts on monday (Rails default)
516 # week starts on monday (Rails default)
517 Time.now.at_beginning_of_week
517 Time.now.at_beginning_of_week
518 sql = "#{db_table}.#{db_field} BETWEEN '%s' AND '%s'" % [connection.quoted_date(from), connection.quoted_date(from + 7.days)]
518 sql = "#{db_table}.#{db_field} BETWEEN '%s' AND '%s'" % [connection.quoted_date(from), connection.quoted_date(from + 7.days)]
519 when "~"
519 when "~"
520 sql = "LOWER(#{db_table}.#{db_field}) LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'"
520 sql = "LOWER(#{db_table}.#{db_field}) LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'"
521 when "!~"
521 when "!~"
522 sql = "LOWER(#{db_table}.#{db_field}) NOT LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'"
522 sql = "LOWER(#{db_table}.#{db_field}) NOT LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'"
523 end
523 end
524
524
525 return sql
525 return sql
526 end
526 end
527
527
528 def add_custom_fields_filters(custom_fields)
528 def add_custom_fields_filters(custom_fields)
529 @available_filters ||= {}
529 @available_filters ||= {}
530
530
531 custom_fields.select(&:is_filter?).each do |field|
531 custom_fields.select(&:is_filter?).each do |field|
532 case field.field_format
532 case field.field_format
533 when "text"
533 when "text"
534 options = { :type => :text, :order => 20 }
534 options = { :type => :text, :order => 20 }
535 when "list"
535 when "list"
536 options = { :type => :list_optional, :values => field.possible_values, :order => 20}
536 options = { :type => :list_optional, :values => field.possible_values, :order => 20}
537 when "date"
537 when "date"
538 options = { :type => :date, :order => 20 }
538 options = { :type => :date, :order => 20 }
539 when "bool"
539 when "bool"
540 options = { :type => :list, :values => [[l(:general_text_yes), "1"], [l(:general_text_no), "0"]], :order => 20 }
540 options = { :type => :list, :values => [[l(:general_text_yes), "1"], [l(:general_text_no), "0"]], :order => 20 }
541 else
541 else
542 options = { :type => :string, :order => 20 }
542 options = { :type => :string, :order => 20 }
543 end
543 end
544 @available_filters["cf_#{field.id}"] = options.merge({ :name => field.name })
544 @available_filters["cf_#{field.id}"] = options.merge({ :name => field.name })
545 end
545 end
546 end
546 end
547
547
548 # Returns a SQL clause for a date or datetime field.
548 # Returns a SQL clause for a date or datetime field.
549 def date_range_clause(table, field, from, to)
549 def date_range_clause(table, field, from, to)
550 s = []
550 s = []
551 if from
551 if from
552 s << ("#{table}.#{field} > '%s'" % [connection.quoted_date((Date.yesterday + from).to_time.end_of_day)])
552 s << ("#{table}.#{field} > '%s'" % [connection.quoted_date((Date.yesterday + from).to_time.end_of_day)])
553 end
553 end
554 if to
554 if to
555 s << ("#{table}.#{field} <= '%s'" % [connection.quoted_date((Date.today + to).to_time.end_of_day)])
555 s << ("#{table}.#{field} <= '%s'" % [connection.quoted_date((Date.today + to).to_time.end_of_day)])
556 end
556 end
557 s.join(' AND ')
557 s.join(' AND ')
558 end
558 end
559 end
559 end
@@ -1,34 +1,35
1 <div class="contextual">
1 <div class="contextual">
2 <%= link_to l(:label_auth_source_new), {:action => 'new'}, :class => 'icon icon-add' %>
2 <%= link_to l(:label_auth_source_new), {:action => 'new'}, :class => 'icon icon-add' %>
3 </div>
3 </div>
4
4
5 <h2><%=l(:label_auth_source_plural)%></h2>
5 <h2><%=l(:label_auth_source_plural)%></h2>
6
6
7 <table class="list">
7 <table class="list">
8 <thead><tr>
8 <thead><tr>
9 <th><%=l(:field_name)%></th>
9 <th><%=l(:field_name)%></th>
10 <th><%=l(:field_type)%></th>
10 <th><%=l(:field_type)%></th>
11 <th><%=l(:field_host)%></th>
11 <th><%=l(:field_host)%></th>
12 <th><%=l(:label_user_plural)%></th>
12 <th><%=l(:label_user_plural)%></th>
13 <th></th>
13 <th></th>
14 </tr></thead>
14 </tr></thead>
15 <tbody>
15 <tbody>
16 <% for source in @auth_sources %>
16 <% for source in @auth_sources %>
17 <tr class="<%= cycle("odd", "even") %>">
17 <tr class="<%= cycle("odd", "even") %>">
18 <td><%= link_to source.name, :action => 'edit', :id => source%></td>
18 <td><%= link_to source.name, :action => 'edit', :id => source%></td>
19 <td align="center"><%= source.auth_method_name %></td>
19 <td align="center"><%= source.auth_method_name %></td>
20 <td align="center"><%= source.host %></td>
20 <td align="center"><%= source.host %></td>
21 <td align="center"><%= source.users.count %></td>
21 <td align="center"><%= source.users.count %></td>
22 <td class="buttons">
22 <td class="buttons">
23 <%= link_to l(:button_test), :action => 'test_connection', :id => source %>
23 <%= link_to l(:button_test), :action => 'test_connection', :id => source %>
24 <%= link_to l(:button_delete), { :action => 'destroy', :id => source },
24 <%= link_to l(:button_delete), { :action => 'destroy', :id => source },
25 :method => :post,
25 :confirm => l(:text_are_you_sure),
26 :confirm => l(:text_are_you_sure),
26 :class => 'icon icon-del',
27 :class => 'icon icon-del',
27 :disabled => source.users.any? %>
28 :disabled => source.users.any? %>
28 </td>
29 </td>
29 </tr>
30 </tr>
30 <% end %>
31 <% end %>
31 </tbody>
32 </tbody>
32 </table>
33 </table>
33
34
34 <p class="pagination"><%= pagination_links_full @auth_source_pages %></p>
35 <p class="pagination"><%= pagination_links_full @auth_source_pages %></p>
@@ -1,16 +1,17
1 <% reply_links = authorize_for('issues', 'edit') -%>
1 <% reply_links = authorize_for('issues', 'edit') -%>
2 <% for journal in journals %>
2 <% for journal in journals %>
3 <div id="change-<%= journal.id %>" class="journal">
3 <div id="change-<%= journal.id %>" class="journal">
4 <h4><div style="float:right;"><%= link_to "##{journal.indice}", :anchor => "note-#{journal.indice}" %></div>
4 <h4><div style="float:right;"><%= link_to "##{journal.indice}", :anchor => "note-#{journal.indice}" %></div>
5 <%= avatar(journal.user, :size => "24") %>
5 <%= content_tag('a', '', :name => "note-#{journal.indice}")%>
6 <%= content_tag('a', '', :name => "note-#{journal.indice}")%>
6 <%= authoring journal.created_on, journal.user, :label => :label_updated_time_by %></h4>
7 <%= authoring journal.created_on, journal.user, :label => :label_updated_time_by %></h4>
7 <%= avatar(journal.user, :size => "32") %>
8
8 <ul>
9 <ul>
9 <% for detail in journal.details %>
10 <% for detail in journal.details %>
10 <li><%= show_detail(detail) %></li>
11 <li><%= show_detail(detail) %></li>
11 <% end %>
12 <% end %>
12 </ul>
13 </ul>
13 <%= render_notes(journal, :reply_links => reply_links) unless journal.notes.blank? %>
14 <%= render_notes(journal, :reply_links => reply_links) unless journal.notes.blank? %>
14 </div>
15 </div>
15 <%= call_hook(:view_issues_history_journal_bottom, { :journal => journal }) %>
16 <%= call_hook(:view_issues_history_journal_bottom, { :journal => journal }) %>
16 <% end %>
17 <% end %>
@@ -1,115 +1,115
1 <%= render :partial => 'action_menu' %>
1 <%= render :partial => 'action_menu' %>
2
2
3 <h2><%= @issue.tracker.name %> #<%= @issue.id %></h2>
3 <h2><%= @issue.tracker.name %> #<%= @issue.id %></h2>
4
4
5 <div class="<%= @issue.css_classes %> details">
5 <div class="<%= @issue.css_classes %> details">
6 <%= avatar(@issue.author, :size => "64") %>
6 <%= avatar(@issue.author, :size => "50") %>
7 <h3><%=h @issue.subject %></h3>
7 <h3><%=h @issue.subject %></h3>
8 <p class="author">
8 <p class="author">
9 <%= authoring @issue.created_on, @issue.author %>.
9 <%= authoring @issue.created_on, @issue.author %>.
10 <% if @issue.created_on != @issue.updated_on %>
10 <% if @issue.created_on != @issue.updated_on %>
11 <%= l(:label_updated_time, time_tag(@issue.updated_on)) %>.
11 <%= l(:label_updated_time, time_tag(@issue.updated_on)) %>.
12 <% end %>
12 <% end %>
13 </p>
13 </p>
14
14
15 <table class="attributes">
15 <table class="attributes">
16 <tr>
16 <tr>
17 <th class="status"><%=l(:field_status)%>:</th><td class="status"><%= @issue.status.name %></td>
17 <th class="status"><%=l(:field_status)%>:</th><td class="status"><%= @issue.status.name %></td>
18 <th class="start-date"><%=l(:field_start_date)%>:</th><td class="start-date"><%= format_date(@issue.start_date) %></td>
18 <th class="start-date"><%=l(:field_start_date)%>:</th><td class="start-date"><%= format_date(@issue.start_date) %></td>
19 </tr>
19 </tr>
20 <tr>
20 <tr>
21 <th class="priority"><%=l(:field_priority)%>:</th><td class="priority"><%= @issue.priority.name %></td>
21 <th class="priority"><%=l(:field_priority)%>:</th><td class="priority"><%= @issue.priority.name %></td>
22 <th class="due-date"><%=l(:field_due_date)%>:</th><td class="due-date"><%= format_date(@issue.due_date) %></td>
22 <th class="due-date"><%=l(:field_due_date)%>:</th><td class="due-date"><%= format_date(@issue.due_date) %></td>
23 </tr>
23 </tr>
24 <tr>
24 <tr>
25 <th class="assigned-to"><%=l(:field_assigned_to)%>:</th><td class="assigned-to"><%= avatar(@issue.assigned_to, :size => "14") %><%= @issue.assigned_to ? link_to_user(@issue.assigned_to) : "-" %></td>
25 <th class="assigned-to"><%=l(:field_assigned_to)%>:</th><td class="assigned-to"><%= avatar(@issue.assigned_to, :size => "14") %><%= @issue.assigned_to ? link_to_user(@issue.assigned_to) : "-" %></td>
26 <th class="progress"><%=l(:field_done_ratio)%>:</th><td class="progress"><%= progress_bar @issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%" %></td>
26 <th class="progress"><%=l(:field_done_ratio)%>:</th><td class="progress"><%= progress_bar @issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%" %></td>
27 </tr>
27 </tr>
28 <tr>
28 <tr>
29 <th class="category"><%=l(:field_category)%>:</th><td class="category"><%=h @issue.category ? @issue.category.name : "-" %></td>
29 <th class="category"><%=l(:field_category)%>:</th><td class="category"><%=h @issue.category ? @issue.category.name : "-" %></td>
30 <% if User.current.allowed_to?(:view_time_entries, @project) %>
30 <% if User.current.allowed_to?(:view_time_entries, @project) %>
31 <th class="spent-time"><%=l(:label_spent_time)%>:</th>
31 <th class="spent-time"><%=l(:label_spent_time)%>:</th>
32 <td class="spent-time"><%= @issue.spent_hours > 0 ? (link_to l_hours(@issue.spent_hours), {:controller => 'timelog', :action => 'details', :project_id => @project, :issue_id => @issue}) : "-" %></td>
32 <td class="spent-time"><%= @issue.spent_hours > 0 ? (link_to l_hours(@issue.spent_hours), {:controller => 'timelog', :action => 'details', :project_id => @project, :issue_id => @issue}) : "-" %></td>
33 <% end %>
33 <% end %>
34 </tr>
34 </tr>
35 <tr>
35 <tr>
36 <th class="fixed-version"><%=l(:field_fixed_version)%>:</th><td class="fixed-version"><%= @issue.fixed_version ? link_to_version(@issue.fixed_version) : "-" %></td>
36 <th class="fixed-version"><%=l(:field_fixed_version)%>:</th><td class="fixed-version"><%= @issue.fixed_version ? link_to_version(@issue.fixed_version) : "-" %></td>
37 <% if @issue.estimated_hours %>
37 <% if @issue.estimated_hours %>
38 <th class="estimated-hours"><%=l(:field_estimated_hours)%>:</th><td class="estimated-hours"><%= l_hours(@issue.estimated_hours) %></td>
38 <th class="estimated-hours"><%=l(:field_estimated_hours)%>:</th><td class="estimated-hours"><%= l_hours(@issue.estimated_hours) %></td>
39 <% end %>
39 <% end %>
40 </tr>
40 </tr>
41 <%= render_custom_fields_rows(@issue) %>
41 <%= render_custom_fields_rows(@issue) %>
42 <%= call_hook(:view_issues_show_details_bottom, :issue => @issue) %>
42 <%= call_hook(:view_issues_show_details_bottom, :issue => @issue) %>
43 </table>
43 </table>
44 <hr />
44 <hr />
45
45
46 <div class="contextual">
46 <div class="contextual">
47 <%= link_to_remote_if_authorized(l(:button_quote), { :url => {:action => 'reply', :id => @issue} }, :class => 'icon icon-comment') unless @issue.description.blank? %>
47 <%= link_to_remote_if_authorized(l(:button_quote), { :url => {:action => 'reply', :id => @issue} }, :class => 'icon icon-comment') unless @issue.description.blank? %>
48 </div>
48 </div>
49
49
50 <p><strong><%=l(:field_description)%></strong></p>
50 <p><strong><%=l(:field_description)%></strong></p>
51 <div class="wiki">
51 <div class="wiki">
52 <%= textilizable @issue, :description, :attachments => @issue.attachments %>
52 <%= textilizable @issue, :description, :attachments => @issue.attachments %>
53 </div>
53 </div>
54
54
55 <%= link_to_attachments @issue %>
55 <%= link_to_attachments @issue %>
56
56
57 <%= call_hook(:view_issues_show_description_bottom, :issue => @issue) %>
57 <%= call_hook(:view_issues_show_description_bottom, :issue => @issue) %>
58
58
59 <% if authorize_for('issue_relations', 'new') || @issue.relations.any? %>
59 <% if authorize_for('issue_relations', 'new') || @issue.relations.any? %>
60 <hr />
60 <hr />
61 <div id="relations">
61 <div id="relations">
62 <%= render :partial => 'relations' %>
62 <%= render :partial => 'relations' %>
63 </div>
63 </div>
64 <% end %>
64 <% end %>
65
65
66 <% if User.current.allowed_to?(:add_issue_watchers, @project) ||
66 <% if User.current.allowed_to?(:add_issue_watchers, @project) ||
67 (@issue.watchers.any? && User.current.allowed_to?(:view_issue_watchers, @project)) %>
67 (@issue.watchers.any? && User.current.allowed_to?(:view_issue_watchers, @project)) %>
68 <hr />
68 <hr />
69 <div id="watchers">
69 <div id="watchers">
70 <%= render :partial => 'watchers/watchers', :locals => {:watched => @issue} %>
70 <%= render :partial => 'watchers/watchers', :locals => {:watched => @issue} %>
71 </div>
71 </div>
72 <% end %>
72 <% end %>
73
73
74 </div>
74 </div>
75
75
76 <% if @changesets.any? && User.current.allowed_to?(:view_changesets, @project) %>
76 <% if @changesets.any? && User.current.allowed_to?(:view_changesets, @project) %>
77 <div id="issue-changesets">
77 <div id="issue-changesets">
78 <h3><%=l(:label_associated_revisions)%></h3>
78 <h3><%=l(:label_associated_revisions)%></h3>
79 <%= render :partial => 'changesets', :locals => { :changesets => @changesets} %>
79 <%= render :partial => 'changesets', :locals => { :changesets => @changesets} %>
80 </div>
80 </div>
81 <% end %>
81 <% end %>
82
82
83 <% if @journals.any? %>
83 <% if @journals.any? %>
84 <div id="history">
84 <div id="history">
85 <h3><%=l(:label_history)%></h3>
85 <h3><%=l(:label_history)%></h3>
86 <%= render :partial => 'history', :locals => { :journals => @journals } %>
86 <%= render :partial => 'history', :locals => { :journals => @journals } %>
87 </div>
87 </div>
88 <% end %>
88 <% end %>
89
89
90 <%= render :partial => 'action_menu', :locals => {:replace_watcher => 'watcher2' } %>
90 <%= render :partial => 'action_menu', :locals => {:replace_watcher => 'watcher2' } %>
91
91
92 <div style="clear: both;"></div>
92 <div style="clear: both;"></div>
93
93
94 <% if authorize_for('issues', 'edit') %>
94 <% if authorize_for('issues', 'edit') %>
95 <div id="update" style="display:none;">
95 <div id="update" style="display:none;">
96 <h3><%= l(:button_update) %></h3>
96 <h3><%= l(:button_update) %></h3>
97 <%= render :partial => 'edit' %>
97 <%= render :partial => 'edit' %>
98 </div>
98 </div>
99 <% end %>
99 <% end %>
100
100
101 <% other_formats_links do |f| %>
101 <% other_formats_links do |f| %>
102 <%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %>
102 <%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %>
103 <%= f.link_to 'PDF' %>
103 <%= f.link_to 'PDF' %>
104 <% end %>
104 <% end %>
105
105
106 <% html_title "#{@issue.tracker.name} ##{@issue.id}: #{@issue.subject}" %>
106 <% html_title "#{@issue.tracker.name} ##{@issue.id}: #{@issue.subject}" %>
107
107
108 <% content_for :sidebar do %>
108 <% content_for :sidebar do %>
109 <%= render :partial => 'issues/sidebar' %>
109 <%= render :partial => 'issues/sidebar' %>
110 <% end %>
110 <% end %>
111
111
112 <% content_for :header_tags do %>
112 <% content_for :header_tags do %>
113 <%= auto_discovery_link_tag(:atom, {:format => 'atom', :key => User.current.rss_key}, :title => "#{@issue.project} - #{@issue.tracker} ##{@issue.id}: #{@issue.subject}") %>
113 <%= auto_discovery_link_tag(:atom, {:format => 'atom', :key => User.current.rss_key}, :title => "#{@issue.project} - #{@issue.tracker} ##{@issue.id}: #{@issue.subject}") %>
114 <%= stylesheet_link_tag 'scm' %>
114 <%= stylesheet_link_tag 'scm' %>
115 <% end %>
115 <% end %>
@@ -1,64 +1,65
1 <%= breadcrumb link_to(l(:label_board_plural), {:controller => 'boards', :action => 'index', :project_id => @project}),
1 <%= breadcrumb link_to(l(:label_board_plural), {:controller => 'boards', :action => 'index', :project_id => @project}),
2 link_to(h(@board.name), {:controller => 'boards', :action => 'show', :project_id => @project, :id => @board}) %>
2 link_to(h(@board.name), {:controller => 'boards', :action => 'show', :project_id => @project, :id => @board}) %>
3
3
4 <div class="contextual">
4 <div class="contextual">
5 <%= watcher_tag(@topic, User.current) %>
5 <%= watcher_tag(@topic, User.current) %>
6 <%= link_to_remote_if_authorized l(:button_quote), { :url => {:action => 'quote', :id => @topic} }, :class => 'icon icon-comment' %>
6 <%= link_to_remote_if_authorized l(:button_quote), { :url => {:action => 'quote', :id => @topic} }, :class => 'icon icon-comment' %>
7 <%= link_to(l(:button_edit), {:action => 'edit', :id => @topic}, :class => 'icon icon-edit') if @message.editable_by?(User.current) %>
7 <%= link_to(l(:button_edit), {:action => 'edit', :id => @topic}, :class => 'icon icon-edit') if @message.editable_by?(User.current) %>
8 <%= link_to(l(:button_delete), {:action => 'destroy', :id => @topic}, :method => :post, :confirm => l(:text_are_you_sure), :class => 'icon icon-del') if @message.destroyable_by?(User.current) %>
8 <%= link_to(l(:button_delete), {:action => 'destroy', :id => @topic}, :method => :post, :confirm => l(:text_are_you_sure), :class => 'icon icon-del') if @message.destroyable_by?(User.current) %>
9 </div>
9 </div>
10
10
11 <h2><%=h @topic.subject %></h2>
11 <h2><%= avatar(@topic.author, :size => "24") %><%=h @topic.subject %></h2>
12
12
13 <div class="message">
13 <div class="message">
14 <p><span class="author"><%= authoring @topic.created_on, @topic.author %></span></p>
14 <p><span class="author"><%= authoring @topic.created_on, @topic.author %></span></p>
15 <div class="wiki">
15 <div class="wiki">
16 <%= textilizable(@topic.content, :attachments => @topic.attachments) %>
16 <%= textilizable(@topic.content, :attachments => @topic.attachments) %>
17 </div>
17 </div>
18 <%= link_to_attachments @topic, :author => false %>
18 <%= link_to_attachments @topic, :author => false %>
19 </div>
19 </div>
20 <br />
20 <br />
21
21
22 <% unless @replies.empty? %>
22 <% unless @replies.empty? %>
23 <h3 class="comments"><%= l(:label_reply_plural) %></h3>
23 <h3 class="comments"><%= l(:label_reply_plural) %></h3>
24 <% @replies.each do |message| %>
24 <% @replies.each do |message| %>
25 <div class="message reply" id="<%= "message-#{message.id}" %>">
25 <div class="message reply" id="<%= "message-#{message.id}" %>">
26 <div class="contextual">
26 <div class="contextual">
27 <%= link_to_remote_if_authorized image_tag('comment.png'), { :url => {:action => 'quote', :id => message} }, :title => l(:button_quote) %>
27 <%= link_to_remote_if_authorized image_tag('comment.png'), { :url => {:action => 'quote', :id => message} }, :title => l(:button_quote) %>
28 <%= link_to(image_tag('edit.png'), {:action => 'edit', :id => message}, :title => l(:button_edit)) if message.editable_by?(User.current) %>
28 <%= link_to(image_tag('edit.png'), {:action => 'edit', :id => message}, :title => l(:button_edit)) if message.editable_by?(User.current) %>
29 <%= link_to(image_tag('delete.png'), {:action => 'destroy', :id => message}, :method => :post, :confirm => l(:text_are_you_sure), :title => l(:button_delete)) if message.destroyable_by?(User.current) %>
29 <%= link_to(image_tag('delete.png'), {:action => 'destroy', :id => message}, :method => :post, :confirm => l(:text_are_you_sure), :title => l(:button_delete)) if message.destroyable_by?(User.current) %>
30 </div>
30 </div>
31 <h4>
31 <h4>
32 <%= avatar(message.author, :size => "24") %>
32 <%= link_to h(message.subject), { :controller => 'messages', :action => 'show', :board_id => @board, :id => @topic, :anchor => "message-#{message.id}" } %>
33 <%= link_to h(message.subject), { :controller => 'messages', :action => 'show', :board_id => @board, :id => @topic, :anchor => "message-#{message.id}" } %>
33 -
34 -
34 <%= authoring message.created_on, message.author %>
35 <%= authoring message.created_on, message.author %>
35 </h4>
36 </h4>
36 <div class="wiki"><%= textilizable message, :content, :attachments => message.attachments %></div>
37 <div class="wiki"><%= textilizable message, :content, :attachments => message.attachments %></div>
37 <%= link_to_attachments message, :author => false %>
38 <%= link_to_attachments message, :author => false %>
38 </div>
39 </div>
39 <% end %>
40 <% end %>
40 <% end %>
41 <% end %>
41
42
42 <% if !@topic.locked? && authorize_for('messages', 'reply') %>
43 <% if !@topic.locked? && authorize_for('messages', 'reply') %>
43 <p><%= toggle_link l(:button_reply), "reply", :focus => 'message_content' %></p>
44 <p><%= toggle_link l(:button_reply), "reply", :focus => 'message_content' %></p>
44 <div id="reply" style="display:none;">
45 <div id="reply" style="display:none;">
45 <% form_for :reply, @reply, :url => {:action => 'reply', :id => @topic}, :html => {:multipart => true, :id => 'message-form'} do |f| %>
46 <% form_for :reply, @reply, :url => {:action => 'reply', :id => @topic}, :html => {:multipart => true, :id => 'message-form'} do |f| %>
46 <%= render :partial => 'form', :locals => {:f => f, :replying => true} %>
47 <%= render :partial => 'form', :locals => {:f => f, :replying => true} %>
47 <%= submit_tag l(:button_submit) %>
48 <%= submit_tag l(:button_submit) %>
48 <%= link_to_remote l(:label_preview),
49 <%= link_to_remote l(:label_preview),
49 { :url => { :controller => 'messages', :action => 'preview', :board_id => @board },
50 { :url => { :controller => 'messages', :action => 'preview', :board_id => @board },
50 :method => 'post',
51 :method => 'post',
51 :update => 'preview',
52 :update => 'preview',
52 :with => "Form.serialize('message-form')",
53 :with => "Form.serialize('message-form')",
53 :complete => "Element.scrollTo('preview')"
54 :complete => "Element.scrollTo('preview')"
54 }, :accesskey => accesskey(:preview) %>
55 }, :accesskey => accesskey(:preview) %>
55 <% end %>
56 <% end %>
56 <div id="preview" class="wiki"></div>
57 <div id="preview" class="wiki"></div>
57 </div>
58 </div>
58 <% end %>
59 <% end %>
59
60
60 <% content_for :header_tags do %>
61 <% content_for :header_tags do %>
61 <%= stylesheet_link_tag 'scm' %>
62 <%= stylesheet_link_tag 'scm' %>
62 <% end %>
63 <% end %>
63
64
64 <% html_title h(@topic.subject) %>
65 <% html_title h(@topic.subject) %>
@@ -1,65 +1,65
1 <div class="contextual">
1 <div class="contextual">
2 <%= link_to_if_authorized l(:button_edit),
2 <%= link_to_if_authorized l(:button_edit),
3 {:controller => 'news', :action => 'edit', :id => @news},
3 {:controller => 'news', :action => 'edit', :id => @news},
4 :class => 'icon icon-edit',
4 :class => 'icon icon-edit',
5 :accesskey => accesskey(:edit),
5 :accesskey => accesskey(:edit),
6 :onclick => 'Element.show("edit-news"); return false;' %>
6 :onclick => 'Element.show("edit-news"); return false;' %>
7 <%= link_to_if_authorized l(:button_delete), {:controller => 'news', :action => 'destroy', :id => @news}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %>
7 <%= link_to_if_authorized l(:button_delete), {:controller => 'news', :action => 'destroy', :id => @news}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %>
8 </div>
8 </div>
9
9
10 <h2><%=h @news.title %></h2>
10 <h2><%= avatar(@news.author, :size => "24") %><%=h @news.title %></h2>
11
11
12 <% if authorize_for('news', 'edit') %>
12 <% if authorize_for('news', 'edit') %>
13 <div id="edit-news" style="display:none;">
13 <div id="edit-news" style="display:none;">
14 <% labelled_tabular_form_for :news, @news, :url => { :action => "edit", :id => @news },
14 <% labelled_tabular_form_for :news, @news, :url => { :action => "edit", :id => @news },
15 :html => { :id => 'news-form' } do |f| %>
15 :html => { :id => 'news-form' } do |f| %>
16 <%= render :partial => 'form', :locals => { :f => f } %>
16 <%= render :partial => 'form', :locals => { :f => f } %>
17 <%= submit_tag l(:button_save) %>
17 <%= submit_tag l(:button_save) %>
18 <%= link_to_remote l(:label_preview),
18 <%= link_to_remote l(:label_preview),
19 { :url => { :controller => 'news', :action => 'preview', :project_id => @project },
19 { :url => { :controller => 'news', :action => 'preview', :project_id => @project },
20 :method => 'post',
20 :method => 'post',
21 :update => 'preview',
21 :update => 'preview',
22 :with => "Form.serialize('news-form')"
22 :with => "Form.serialize('news-form')"
23 }, :accesskey => accesskey(:preview) %> |
23 }, :accesskey => accesskey(:preview) %> |
24 <%= link_to l(:button_cancel), "#", :onclick => 'Element.hide("edit-news"); return false;' %>
24 <%= link_to l(:button_cancel), "#", :onclick => 'Element.hide("edit-news"); return false;' %>
25 <% end %>
25 <% end %>
26 <div id="preview" class="wiki"></div>
26 <div id="preview" class="wiki"></div>
27 </div>
27 </div>
28 <% end %>
28 <% end %>
29
29
30 <p><em><% unless @news.summary.blank? %><%=h @news.summary %><br /><% end %>
30 <p><em><% unless @news.summary.blank? %><%=h @news.summary %><br /><% end %>
31 <span class="author"><%= authoring @news.created_on, @news.author %></span></em></p>
31 <span class="author"><%= authoring @news.created_on, @news.author %></span></em></p>
32 <div class="wiki">
32 <div class="wiki">
33 <%= textilizable(@news.description) %>
33 <%= textilizable(@news.description) %>
34 </div>
34 </div>
35 <br />
35 <br />
36
36
37 <div id="comments" style="margin-bottom:16px;">
37 <div id="comments" style="margin-bottom:16px;">
38 <h3 class="comments"><%= l(:label_comment_plural) %></h3>
38 <h3 class="comments"><%= l(:label_comment_plural) %></h3>
39 <% @comments.each do |comment| %>
39 <% @comments.each do |comment| %>
40 <% next if comment.new_record? %>
40 <% next if comment.new_record? %>
41 <div class="contextual">
41 <div class="contextual">
42 <%= link_to_if_authorized image_tag('delete.png'), {:controller => 'news', :action => 'destroy_comment', :id => @news, :comment_id => comment},
42 <%= link_to_if_authorized image_tag('delete.png'), {:controller => 'news', :action => 'destroy_comment', :id => @news, :comment_id => comment},
43 :confirm => l(:text_are_you_sure), :method => :post, :title => l(:button_delete) %>
43 :confirm => l(:text_are_you_sure), :method => :post, :title => l(:button_delete) %>
44 </div>
44 </div>
45 <h4><%= authoring comment.created_on, comment.author %></h4>
45 <h4><%= avatar(comment.author, :size => "24") %><%= authoring comment.created_on, comment.author %></h4>
46 <%= textilizable(comment.comments) %>
46 <%= textilizable(comment.comments) %>
47 <% end if @comments.any? %>
47 <% end if @comments.any? %>
48 </div>
48 </div>
49
49
50 <% if authorize_for 'news', 'add_comment' %>
50 <% if authorize_for 'news', 'add_comment' %>
51 <p><%= toggle_link l(:label_comment_add), "add_comment_form", :focus => "comment_comments" %></p>
51 <p><%= toggle_link l(:label_comment_add), "add_comment_form", :focus => "comment_comments" %></p>
52 <% form_tag({:action => 'add_comment', :id => @news}, :id => "add_comment_form", :style => "display:none;") do %>
52 <% form_tag({:action => 'add_comment', :id => @news}, :id => "add_comment_form", :style => "display:none;") do %>
53 <div class="box">
53 <div class="box">
54 <%= text_area 'comment', 'comments', :cols => 80, :rows => 15, :class => 'wiki-edit' %>
54 <%= text_area 'comment', 'comments', :cols => 80, :rows => 15, :class => 'wiki-edit' %>
55 <%= wikitoolbar_for 'comment_comments' %>
55 <%= wikitoolbar_for 'comment_comments' %>
56 </div>
56 </div>
57 <p><%= submit_tag l(:button_add) %></p>
57 <p><%= submit_tag l(:button_add) %></p>
58 <% end %>
58 <% end %>
59 <% end %>
59 <% end %>
60
60
61 <% html_title @news.title -%>
61 <% html_title @news.title -%>
62
62
63 <% content_for :header_tags do %>
63 <% content_for :header_tags do %>
64 <%= stylesheet_link_tag 'scm' %>
64 <%= stylesheet_link_tag 'scm' %>
65 <% end %>
65 <% end %>
@@ -1,48 +1,53
1 <% if @statuses.empty? or rows.empty? %>
1 <% if @statuses.empty? or rows.empty? %>
2 <p><i><%=l(:label_no_data)%></i></p>
2 <p><i><%=l(:label_no_data)%></i></p>
3 <% else %>
3 <% else %>
4 <% col_width = 70 / (@statuses.length+3) %>
4 <% col_width = 70 / (@statuses.length+3) %>
5 <table class="list">
5 <table class="list">
6 <thead><tr>
6 <thead><tr>
7 <th style="width:25%"></th>
7 <th style="width:25%"></th>
8 <% for status in @statuses %>
8 <% for status in @statuses %>
9 <th style="width:<%= col_width %>%"><%= status.name %></th>
9 <th style="width:<%= col_width %>%"><%= status.name %></th>
10 <% end %>
10 <% end %>
11 <th align="center" style="width:<%= col_width %>%"><strong><%=l(:label_open_issues_plural)%></strong></th>
11 <th align="center" style="width:<%= col_width %>%"><strong><%=l(:label_open_issues_plural)%></strong></th>
12 <th align="center" style="width:<%= col_width %>%"><strong><%=l(:label_closed_issues_plural)%></strong></th>
12 <th align="center" style="width:<%= col_width %>%"><strong><%=l(:label_closed_issues_plural)%></strong></th>
13 <th align="center" style="width:<%= col_width %>%"><strong><%=l(:label_total)%></strong></th>
13 <th align="center" style="width:<%= col_width %>%"><strong><%=l(:label_total)%></strong></th>
14 </tr></thead>
14 </tr></thead>
15 <tbody>
15 <tbody>
16 <% for row in rows %>
16 <% for row in rows %>
17 <tr class="<%= cycle("odd", "even") %>">
17 <tr class="<%= cycle("odd", "even") %>">
18 <td><%= link_to row.name, :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)),
18 <td><%= link_to row.name, :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)),
19 :set_filter => 1,
19 :set_filter => 1,
20 :subproject_id => '!*',
20 "#{field_name}" => row.id %></td>
21 "#{field_name}" => row.id %></td>
21 <% for status in @statuses %>
22 <% for status in @statuses %>
22 <td align="center"><%= aggregate_link data, { field_name => row.id, "status_id" => status.id },
23 <td align="center"><%= aggregate_link data, { field_name => row.id, "status_id" => status.id },
23 :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)),
24 :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)),
24 :set_filter => 1,
25 :set_filter => 1,
26 :subproject_id => '!*',
25 "status_id" => status.id,
27 "status_id" => status.id,
26 "#{field_name}" => row.id %></td>
28 "#{field_name}" => row.id %></td>
27 <% end %>
29 <% end %>
28 <td align="center"><%= aggregate_link data, { field_name => row.id, "closed" => 0 },
30 <td align="center"><%= aggregate_link data, { field_name => row.id, "closed" => 0 },
29 :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)),
31 :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)),
30 :set_filter => 1,
32 :set_filter => 1,
33 :subproject_id => '!*',
31 "#{field_name}" => row.id,
34 "#{field_name}" => row.id,
32 "status_id" => "o" %></td>
35 "status_id" => "o" %></td>
33 <td align="center"><%= aggregate_link data, { field_name => row.id, "closed" => 1 },
36 <td align="center"><%= aggregate_link data, { field_name => row.id, "closed" => 1 },
34 :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)),
37 :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)),
35 :set_filter => 1,
38 :set_filter => 1,
39 :subproject_id => '!*',
36 "#{field_name}" => row.id,
40 "#{field_name}" => row.id,
37 "status_id" => "c" %></td>
41 "status_id" => "c" %></td>
38 <td align="center"><%= aggregate_link data, { field_name => row.id },
42 <td align="center"><%= aggregate_link data, { field_name => row.id },
39 :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)),
43 :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)),
40 :set_filter => 1,
44 :set_filter => 1,
45 :subproject_id => '!*',
41 "#{field_name}" => row.id,
46 "#{field_name}" => row.id,
42 "status_id" => "*" %></td>
47 "status_id" => "*" %></td>
43 </tr>
48 </tr>
44 <% end %>
49 <% end %>
45 </tbody>
50 </tbody>
46 </table>
51 </table>
47 <% end
52 <% end
48 reset_cycle %> No newline at end of file
53 reset_cycle %>
@@ -1,37 +1,41
1 <% if @statuses.empty? or rows.empty? %>
1 <% if @statuses.empty? or rows.empty? %>
2 <p><i><%=l(:label_no_data)%></i></p>
2 <p><i><%=l(:label_no_data)%></i></p>
3 <% else %>
3 <% else %>
4 <table class="list">
4 <table class="list">
5 <thead><tr>
5 <thead><tr>
6 <th style="width:25%"></th>
6 <th style="width:25%"></th>
7 <th align="center" style="width:25%"><%=l(:label_open_issues_plural)%></th>
7 <th align="center" style="width:25%"><%=l(:label_open_issues_plural)%></th>
8 <th align="center" style="width:25%"><%=l(:label_closed_issues_plural)%></th>
8 <th align="center" style="width:25%"><%=l(:label_closed_issues_plural)%></th>
9 <th align="center" style="width:25%"><%=l(:label_total)%></th>
9 <th align="center" style="width:25%"><%=l(:label_total)%></th>
10 </tr></thead>
10 </tr></thead>
11 <tbody>
11 <tbody>
12 <% for row in rows %>
12 <% for row in rows %>
13 <tr class="<%= cycle("odd", "even") %>">
13 <tr class="<%= cycle("odd", "even") %>">
14 <td><%= link_to row.name, :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)),
14 <td><%= link_to row.name, :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)),
15 :set_filter => 1,
15 :set_filter => 1,
16 :subproject_id => '!*',
16 "#{field_name}" => row.id %></td>
17 "#{field_name}" => row.id %></td>
17 <td align="center"><%= aggregate_link data, { field_name => row.id, "closed" => 0 },
18 <td align="center"><%= aggregate_link data, { field_name => row.id, "closed" => 0 },
18 :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)),
19 :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)),
19 :set_filter => 1,
20 :set_filter => 1,
21 :subproject_id => '!*',
20 "#{field_name}" => row.id,
22 "#{field_name}" => row.id,
21 "status_id" => "o" %></td>
23 "status_id" => "o" %></td>
22 <td align="center"><%= aggregate_link data, { field_name => row.id, "closed" => 1 },
24 <td align="center"><%= aggregate_link data, { field_name => row.id, "closed" => 1 },
23 :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)),
25 :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)),
24 :set_filter => 1,
26 :set_filter => 1,
27 :subproject_id => '!*',
25 "#{field_name}" => row.id,
28 "#{field_name}" => row.id,
26 "status_id" => "c" %></td>
29 "status_id" => "c" %></td>
27 <td align="center"><%= aggregate_link data, { field_name => row.id },
30 <td align="center"><%= aggregate_link data, { field_name => row.id },
28 :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)),
31 :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)),
29 :set_filter => 1,
32 :set_filter => 1,
33 :subproject_id => '!*',
30 "#{field_name}" => row.id,
34 "#{field_name}" => row.id,
31 "status_id" => "*" %></td>
35 "status_id" => "*" %></td>
32 </tr>
36 </tr>
33 <% end %>
37 <% end %>
34 </tbody>
38 </tbody>
35 </table>
39 </table>
36 <% end
40 <% end
37 reset_cycle %> No newline at end of file
41 reset_cycle %>
@@ -1,70 +1,70
1 <div class="contextual">
1 <div class="contextual">
2 <%= link_to(l(:button_edit), {:controller => 'users', :action => 'edit', :id => @user}, :class => 'icon icon-edit') if User.current.admin? %>
2 <%= link_to(l(:button_edit), {:controller => 'users', :action => 'edit', :id => @user}, :class => 'icon icon-edit') if User.current.admin? %>
3 </div>
3 </div>
4
4
5 <h2><%= avatar @user %> <%=h @user.name %></h2>
5 <h2><%= avatar @user, :size => "50" %> <%=h @user.name %></h2>
6
6
7 <div class="splitcontentleft">
7 <div class="splitcontentleft">
8 <ul>
8 <ul>
9 <% unless @user.pref.hide_mail %>
9 <% unless @user.pref.hide_mail %>
10 <li><%=l(:field_mail)%>: <%= mail_to(h(@user.mail), nil, :encode => 'javascript') %></li>
10 <li><%=l(:field_mail)%>: <%= mail_to(h(@user.mail), nil, :encode => 'javascript') %></li>
11 <% end %>
11 <% end %>
12 <% for custom_value in @custom_values %>
12 <% for custom_value in @custom_values %>
13 <% if !custom_value.value.blank? %>
13 <% if !custom_value.value.blank? %>
14 <li><%=h custom_value.custom_field.name%>: <%=h show_value(custom_value) %></li>
14 <li><%=h custom_value.custom_field.name%>: <%=h show_value(custom_value) %></li>
15 <% end %>
15 <% end %>
16 <% end %>
16 <% end %>
17 <li><%=l(:label_registered_on)%>: <%= format_date(@user.created_on) %></li>
17 <li><%=l(:label_registered_on)%>: <%= format_date(@user.created_on) %></li>
18 <% unless @user.last_login_on.nil? %>
18 <% unless @user.last_login_on.nil? %>
19 <li><%=l(:field_last_login_on)%>: <%= format_date(@user.last_login_on) %></li>
19 <li><%=l(:field_last_login_on)%>: <%= format_date(@user.last_login_on) %></li>
20 <% end %>
20 <% end %>
21 </ul>
21 </ul>
22
22
23 <% unless @memberships.empty? %>
23 <% unless @memberships.empty? %>
24 <h3><%=l(:label_project_plural)%></h3>
24 <h3><%=l(:label_project_plural)%></h3>
25 <ul>
25 <ul>
26 <% for membership in @memberships %>
26 <% for membership in @memberships %>
27 <li><%= link_to(h(membership.project.name), :controller => 'projects', :action => 'show', :id => membership.project) %>
27 <li><%= link_to(h(membership.project.name), :controller => 'projects', :action => 'show', :id => membership.project) %>
28 (<%=h membership.roles.sort.collect(&:to_s).join(', ') %>, <%= format_date(membership.created_on) %>)</li>
28 (<%=h membership.roles.sort.collect(&:to_s).join(', ') %>, <%= format_date(membership.created_on) %>)</li>
29 <% end %>
29 <% end %>
30 </ul>
30 </ul>
31 <% end %>
31 <% end %>
32 <%= call_hook :view_account_left_bottom, :user => @user %>
32 <%= call_hook :view_account_left_bottom, :user => @user %>
33 </div>
33 </div>
34
34
35 <div class="splitcontentright">
35 <div class="splitcontentright">
36
36
37 <% unless @events_by_day.empty? %>
37 <% unless @events_by_day.empty? %>
38 <h3><%= link_to l(:label_activity), :controller => 'projects', :action => 'activity', :id => nil, :user_id => @user, :from => @events_by_day.keys.first %></h3>
38 <h3><%= link_to l(:label_activity), :controller => 'projects', :action => 'activity', :id => nil, :user_id => @user, :from => @events_by_day.keys.first %></h3>
39
39
40 <p>
40 <p>
41 <%=l(:label_reported_issues)%>: <%= Issue.count(:conditions => ["author_id=?", @user.id]) %>
41 <%=l(:label_reported_issues)%>: <%= Issue.count(:conditions => ["author_id=?", @user.id]) %>
42 </p>
42 </p>
43
43
44 <div id="activity">
44 <div id="activity">
45 <% @events_by_day.keys.sort.reverse.each do |day| %>
45 <% @events_by_day.keys.sort.reverse.each do |day| %>
46 <h4><%= format_activity_day(day) %></h4>
46 <h4><%= format_activity_day(day) %></h4>
47 <dl>
47 <dl>
48 <% @events_by_day[day].sort {|x,y| y.event_datetime <=> x.event_datetime }.each do |e| -%>
48 <% @events_by_day[day].sort {|x,y| y.event_datetime <=> x.event_datetime }.each do |e| -%>
49 <dt class="<%= e.event_type %>">
49 <dt class="<%= e.event_type %>">
50 <span class="time"><%= format_time(e.event_datetime, false) %></span>
50 <span class="time"><%= format_time(e.event_datetime, false) %></span>
51 <%= content_tag('span', h(e.project), :class => 'project') %>
51 <%= content_tag('span', h(e.project), :class => 'project') %>
52 <%= link_to format_activity_title(e.event_title), e.event_url %></dt>
52 <%= link_to format_activity_title(e.event_title), e.event_url %></dt>
53 <dd><span class="description"><%= format_activity_description(e.event_description) %></span></dd>
53 <dd><span class="description"><%= format_activity_description(e.event_description) %></span></dd>
54 <% end -%>
54 <% end -%>
55 </dl>
55 </dl>
56 <% end -%>
56 <% end -%>
57 </div>
57 </div>
58
58
59 <% other_formats_links do |f| %>
59 <% other_formats_links do |f| %>
60 <%= f.link_to 'Atom', :url => {:controller => 'projects', :action => 'activity', :id => nil, :user_id => @user, :key => User.current.rss_key} %>
60 <%= f.link_to 'Atom', :url => {:controller => 'projects', :action => 'activity', :id => nil, :user_id => @user, :key => User.current.rss_key} %>
61 <% end %>
61 <% end %>
62
62
63 <% content_for :header_tags do %>
63 <% content_for :header_tags do %>
64 <%= auto_discovery_link_tag(:atom, :controller => 'projects', :action => 'activity', :user_id => @user, :format => :atom, :key => User.current.rss_key) %>
64 <%= auto_discovery_link_tag(:atom, :controller => 'projects', :action => 'activity', :user_id => @user, :format => :atom, :key => User.current.rss_key) %>
65 <% end %>
65 <% end %>
66 <% end %>
66 <% end %>
67 <%= call_hook :view_account_right_bottom, :user => @user %>
67 <%= call_hook :view_account_right_bottom, :user => @user %>
68 </div>
68 </div>
69
69
70 <% html_title @user.name %>
70 <% html_title @user.name %>
@@ -1,848 +1,850
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; margin-right: 8px; font-weight: bold;}
21 #top-menu a {color: #fff; margin-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 #header h1 a.ancestor { font-size: 80%; }
28 #header h1 a.ancestor { font-size: 80%; }
29 #quick-search {float:right;}
29 #quick-search {float:right;}
30
30
31 #main-menu {position: absolute; bottom: 0px; left:6px; margin-right: -500px;}
31 #main-menu {position: absolute; bottom: 0px; left:6px; margin-right: -500px;}
32 #main-menu ul {margin: 0; padding: 0;}
32 #main-menu ul {margin: 0; padding: 0;}
33 #main-menu li {
33 #main-menu li {
34 float:left;
34 float:left;
35 list-style-type:none;
35 list-style-type:none;
36 margin: 0px 2px 0px 0px;
36 margin: 0px 2px 0px 0px;
37 padding: 0px 0px 0px 0px;
37 padding: 0px 0px 0px 0px;
38 white-space:nowrap;
38 white-space:nowrap;
39 }
39 }
40 #main-menu li a {
40 #main-menu li a {
41 display: block;
41 display: block;
42 color: #fff;
42 color: #fff;
43 text-decoration: none;
43 text-decoration: none;
44 font-weight: bold;
44 font-weight: bold;
45 margin: 0;
45 margin: 0;
46 padding: 4px 10px 4px 10px;
46 padding: 4px 10px 4px 10px;
47 }
47 }
48 #main-menu li a:hover {background:#759FCF; color:#fff;}
48 #main-menu li a:hover {background:#759FCF; color:#fff;}
49 #main-menu li a.selected, #main-menu li a.selected:hover {background:#fff; color:#555;}
49 #main-menu li a.selected, #main-menu li a.selected:hover {background:#fff; color:#555;}
50
50
51 #admin-menu ul {margin: 0; padding: 0;}
51 #admin-menu ul {margin: 0; padding: 0;}
52 #admin-menu li {margin: 0; padding: 0 0 12px 0; list-style-type:none;}
52 #admin-menu li {margin: 0; padding: 0 0 12px 0; list-style-type:none;}
53
53
54 #admin-menu a { background-position: 0% 40%; background-repeat: no-repeat; padding-left: 20px; padding-top: 2px; padding-bottom: 3px;}
54 #admin-menu a { background-position: 0% 40%; background-repeat: no-repeat; padding-left: 20px; padding-top: 2px; padding-bottom: 3px;}
55 #admin-menu a.projects { background-image: url(../images/projects.png); }
55 #admin-menu a.projects { background-image: url(../images/projects.png); }
56 #admin-menu a.users { background-image: url(../images/user.png); }
56 #admin-menu a.users { background-image: url(../images/user.png); }
57 #admin-menu a.groups { background-image: url(../images/group.png); }
57 #admin-menu a.groups { background-image: url(../images/group.png); }
58 #admin-menu a.roles { background-image: url(../images/database_key.png); }
58 #admin-menu a.roles { background-image: url(../images/database_key.png); }
59 #admin-menu a.trackers { background-image: url(../images/ticket.png); }
59 #admin-menu a.trackers { background-image: url(../images/ticket.png); }
60 #admin-menu a.issue_statuses { background-image: url(../images/ticket_edit.png); }
60 #admin-menu a.issue_statuses { background-image: url(../images/ticket_edit.png); }
61 #admin-menu a.workflows { background-image: url(../images/ticket_go.png); }
61 #admin-menu a.workflows { background-image: url(../images/ticket_go.png); }
62 #admin-menu a.custom_fields { background-image: url(../images/textfield.png); }
62 #admin-menu a.custom_fields { background-image: url(../images/textfield.png); }
63 #admin-menu a.enumerations { background-image: url(../images/text_list_bullets.png); }
63 #admin-menu a.enumerations { background-image: url(../images/text_list_bullets.png); }
64 #admin-menu a.settings { background-image: url(../images/changeset.png); }
64 #admin-menu a.settings { background-image: url(../images/changeset.png); }
65 #admin-menu a.plugins { background-image: url(../images/plugin.png); }
65 #admin-menu a.plugins { background-image: url(../images/plugin.png); }
66 #admin-menu a.info { background-image: url(../images/help.png); }
66 #admin-menu a.info { background-image: url(../images/help.png); }
67
67
68 #main {background-color:#EEEEEE;}
68 #main {background-color:#EEEEEE;}
69
69
70 #sidebar{ float: right; width: 17%; position: relative; z-index: 9; min-height: 600px; padding: 0; margin: 0;}
70 #sidebar{ float: right; width: 17%; position: relative; z-index: 9; min-height: 600px; padding: 0; margin: 0;}
71 * html #sidebar{ width: 17%; }
71 * html #sidebar{ width: 17%; }
72 #sidebar h3{ font-size: 14px; margin-top:14px; color: #666; }
72 #sidebar h3{ font-size: 14px; margin-top:14px; color: #666; }
73 #sidebar hr{ width: 100%; margin: 0 auto; height: 1px; background: #ccc; border: 0; }
73 #sidebar hr{ width: 100%; margin: 0 auto; height: 1px; background: #ccc; border: 0; }
74 * html #sidebar hr{ width: 95%; position: relative; left: -6px; color: #ccc; }
74 * html #sidebar hr{ width: 95%; position: relative; left: -6px; color: #ccc; }
75
75
76 #content { width: 80%; background-color: #fff; margin: 0px; border-right: 1px solid #ddd; padding: 6px 10px 10px 10px; z-index: 10; }
76 #content { width: 80%; background-color: #fff; margin: 0px; border-right: 1px solid #ddd; padding: 6px 10px 10px 10px; z-index: 10; }
77 * html #content{ width: 80%; padding-left: 0; margin-top: 0px; padding: 6px 10px 10px 10px;}
77 * html #content{ width: 80%; padding-left: 0; margin-top: 0px; padding: 6px 10px 10px 10px;}
78 html>body #content { min-height: 600px; overflow: auto; }
78 html>body #content { min-height: 600px; overflow: auto; }
79 * html body #content { height: 600px; } /* IE */
79 * html body #content { height: 600px; } /* IE */
80
80
81 #main.nosidebar #sidebar{ display: none; }
81 #main.nosidebar #sidebar{ display: none; }
82 #main.nosidebar #content{ width: auto; border-right: 0; }
82 #main.nosidebar #content{ width: auto; border-right: 0; }
83
83
84 #footer {clear: both; border-top: 1px solid #bbb; font-size: 0.9em; color: #aaa; padding: 5px; text-align:center; background:#fff;}
84 #footer {clear: both; border-top: 1px solid #bbb; font-size: 0.9em; color: #aaa; padding: 5px; text-align:center; background:#fff;}
85
85
86 #login-form table {margin-top:5em; padding:1em; margin-left: auto; margin-right: auto; border: 2px solid #FDBF3B; background-color:#FFEBC1; }
86 #login-form table {margin-top:5em; padding:1em; margin-left: auto; margin-right: auto; border: 2px solid #FDBF3B; background-color:#FFEBC1; }
87 #login-form table td {padding: 6px;}
87 #login-form table td {padding: 6px;}
88 #login-form label {font-weight: bold;}
88 #login-form label {font-weight: bold;}
89 #login-form input#username, #login-form input#password { width: 300px; }
89 #login-form input#username, #login-form input#password { width: 300px; }
90
90
91 input#openid_url { background: url(../images/openid-bg.gif) no-repeat; background-color: #fff; background-position: 0 50%; padding-left: 18px; }
91 input#openid_url { background: url(../images/openid-bg.gif) no-repeat; background-color: #fff; background-position: 0 50%; padding-left: 18px; }
92
92
93 .clear:after{ content: "."; display: block; height: 0; clear: both; visibility: hidden; }
93 .clear:after{ content: "."; display: block; height: 0; clear: both; visibility: hidden; }
94
94
95 /***** Links *****/
95 /***** Links *****/
96 a, a:link, a:visited{ color: #2A5685; text-decoration: none; }
96 a, a:link, a:visited{ color: #2A5685; text-decoration: none; }
97 a:hover, a:active{ color: #c61a1a; text-decoration: underline;}
97 a:hover, a:active{ color: #c61a1a; text-decoration: underline;}
98 a img{ border: 0; }
98 a img{ border: 0; }
99
99
100 a.issue.closed, a.issue.closed:link, a.issue.closed:visited { color: #999; text-decoration: line-through; }
100 a.issue.closed, a.issue.closed:link, a.issue.closed:visited { color: #999; text-decoration: line-through; }
101
101
102 /***** Tables *****/
102 /***** Tables *****/
103 table.list { border: 1px solid #e4e4e4; border-collapse: collapse; width: 100%; margin-bottom: 4px; }
103 table.list { border: 1px solid #e4e4e4; border-collapse: collapse; width: 100%; margin-bottom: 4px; }
104 table.list th { background-color:#EEEEEE; padding: 4px; white-space:nowrap; }
104 table.list th { background-color:#EEEEEE; padding: 4px; white-space:nowrap; }
105 table.list td { vertical-align: top; }
105 table.list td { vertical-align: top; }
106 table.list td.id { width: 2%; text-align: center;}
106 table.list td.id { width: 2%; text-align: center;}
107 table.list td.checkbox { width: 15px; padding: 0px;}
107 table.list td.checkbox { width: 15px; padding: 0px;}
108 table.list td.buttons { width: 15%; white-space:nowrap; text-align: right; }
108 table.list td.buttons { width: 15%; white-space:nowrap; text-align: right; }
109 table.list td.buttons a { padding-right: 0.6em; }
109 table.list td.buttons a { padding-right: 0.6em; }
110
110
111 tr.project td.name a { padding-left: 16px; white-space:nowrap; }
111 tr.project td.name a { padding-left: 16px; white-space:nowrap; }
112 tr.project.parent td.name a { background: url('../images/bullet_toggle_minus.png') no-repeat; }
112 tr.project.parent td.name a { background: url('../images/bullet_toggle_minus.png') no-repeat; }
113
113
114 tr.issue { text-align: center; white-space: nowrap; }
114 tr.issue { text-align: center; white-space: nowrap; }
115 tr.issue td.subject, tr.issue td.category, td.assigned_to { white-space: normal; }
115 tr.issue td.subject, tr.issue td.category, td.assigned_to { white-space: normal; }
116 tr.issue td.subject { text-align: left; }
116 tr.issue td.subject { text-align: left; }
117 tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;}
117 tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;}
118
118
119 tr.entry { border: 1px solid #f8f8f8; }
119 tr.entry { border: 1px solid #f8f8f8; }
120 tr.entry td { white-space: nowrap; }
120 tr.entry td { white-space: nowrap; }
121 tr.entry td.filename { width: 30%; }
121 tr.entry td.filename { width: 30%; }
122 tr.entry td.size { text-align: right; font-size: 90%; }
122 tr.entry td.size { text-align: right; font-size: 90%; }
123 tr.entry td.revision, tr.entry td.author { text-align: center; }
123 tr.entry td.revision, tr.entry td.author { text-align: center; }
124 tr.entry td.age { text-align: right; }
124 tr.entry td.age { text-align: right; }
125 tr.entry.file td.filename a { margin-left: 16px; }
125 tr.entry.file td.filename a { margin-left: 16px; }
126
126
127 tr span.expander {background-image: url(../images/bullet_toggle_plus.png); padding-left: 8px; margin-left: 0; cursor: pointer;}
127 tr span.expander {background-image: url(../images/bullet_toggle_plus.png); padding-left: 8px; margin-left: 0; cursor: pointer;}
128 tr.open span.expander {background-image: url(../images/bullet_toggle_minus.png);}
128 tr.open span.expander {background-image: url(../images/bullet_toggle_minus.png);}
129
129
130 tr.changeset td.author { text-align: center; width: 15%; }
130 tr.changeset td.author { text-align: center; width: 15%; }
131 tr.changeset td.committed_on { text-align: center; width: 15%; }
131 tr.changeset td.committed_on { text-align: center; width: 15%; }
132
132
133 table.files tr.file td { text-align: center; }
133 table.files tr.file td { text-align: center; }
134 table.files tr.file td.filename { text-align: left; padding-left: 24px; }
134 table.files tr.file td.filename { text-align: left; padding-left: 24px; }
135 table.files tr.file td.digest { font-size: 80%; }
135 table.files tr.file td.digest { font-size: 80%; }
136
136
137 table.members td.roles, table.memberships td.roles { width: 45%; }
137 table.members td.roles, table.memberships td.roles { width: 45%; }
138
138
139 tr.message { height: 2.6em; }
139 tr.message { height: 2.6em; }
140 tr.message td.last_message { font-size: 80%; }
140 tr.message td.last_message { font-size: 80%; }
141 tr.message.locked td.subject a { background-image: url(../images/locked.png); }
141 tr.message.locked td.subject a { background-image: url(../images/locked.png); }
142 tr.message.sticky td.subject a { background-image: url(../images/sticky.png); font-weight: bold; }
142 tr.message.sticky td.subject a { background-image: url(../images/sticky.png); font-weight: bold; }
143
143
144 tr.version.closed, tr.version.closed a { color: #999; }
144 tr.version.closed, tr.version.closed a { color: #999; }
145 tr.version td.name { padding-left: 20px; }
145 tr.version td.name { padding-left: 20px; }
146 tr.version.shared td.name { background: url(../images/link.png) no-repeat 0% 70%; }
146 tr.version.shared td.name { background: url(../images/link.png) no-repeat 0% 70%; }
147 tr.version td.date, tr.version td.status, tr.version td.sharing { text-align: center; }
147 tr.version td.date, tr.version td.status, tr.version td.sharing { text-align: center; }
148
148
149 tr.user td { width:13%; }
149 tr.user td { width:13%; }
150 tr.user td.email { width:18%; }
150 tr.user td.email { width:18%; }
151 tr.user td { white-space: nowrap; }
151 tr.user td { white-space: nowrap; }
152 tr.user.locked, tr.user.registered { color: #aaa; }
152 tr.user.locked, tr.user.registered { color: #aaa; }
153 tr.user.locked a, tr.user.registered a { color: #aaa; }
153 tr.user.locked a, tr.user.registered a { color: #aaa; }
154
154
155 tr.time-entry { text-align: center; white-space: nowrap; }
155 tr.time-entry { text-align: center; white-space: nowrap; }
156 tr.time-entry td.subject, tr.time-entry td.comments { text-align: left; white-space: normal; }
156 tr.time-entry td.subject, tr.time-entry td.comments { text-align: left; white-space: normal; }
157 td.hours { text-align: right; font-weight: bold; padding-right: 0.5em; }
157 td.hours { text-align: right; font-weight: bold; padding-right: 0.5em; }
158 td.hours .hours-dec { font-size: 0.9em; }
158 td.hours .hours-dec { font-size: 0.9em; }
159
159
160 table.plugins td { vertical-align: middle; }
160 table.plugins td { vertical-align: middle; }
161 table.plugins td.configure { text-align: right; padding-right: 1em; }
161 table.plugins td.configure { text-align: right; padding-right: 1em; }
162 table.plugins span.name { font-weight: bold; display: block; margin-bottom: 6px; }
162 table.plugins span.name { font-weight: bold; display: block; margin-bottom: 6px; }
163 table.plugins span.description { display: block; font-size: 0.9em; }
163 table.plugins span.description { display: block; font-size: 0.9em; }
164 table.plugins span.url { display: block; font-size: 0.9em; }
164 table.plugins span.url { display: block; font-size: 0.9em; }
165
165
166 table.list tbody tr.group td { padding: 0.8em 0 0.5em 0.3em; font-weight: bold; border-bottom: 1px solid #ccc; }
166 table.list tbody tr.group td { padding: 0.8em 0 0.5em 0.3em; font-weight: bold; border-bottom: 1px solid #ccc; }
167 table.list tbody tr.group span.count { color: #aaa; font-size: 80%; }
167 table.list tbody tr.group span.count { color: #aaa; font-size: 80%; }
168
168
169 table.list tbody tr:hover { background-color:#ffffdd; }
169 table.list tbody tr:hover { background-color:#ffffdd; }
170 table.list tbody tr.group:hover { background-color:inherit; }
170 table.list tbody tr.group:hover { background-color:inherit; }
171 table td {padding:2px;}
171 table td {padding:2px;}
172 table p {margin:0;}
172 table p {margin:0;}
173 .odd {background-color:#f6f7f8;}
173 .odd {background-color:#f6f7f8;}
174 .even {background-color: #fff;}
174 .even {background-color: #fff;}
175
175
176 a.sort { padding-right: 16px; background-position: 100% 50%; background-repeat: no-repeat; }
176 a.sort { padding-right: 16px; background-position: 100% 50%; background-repeat: no-repeat; }
177 a.sort.asc { background-image: url(../images/sort_asc.png); }
177 a.sort.asc { background-image: url(../images/sort_asc.png); }
178 a.sort.desc { background-image: url(../images/sort_desc.png); }
178 a.sort.desc { background-image: url(../images/sort_desc.png); }
179
179
180 table.attributes { width: 100% }
180 table.attributes { width: 100% }
181 table.attributes th { vertical-align: top; text-align: left; }
181 table.attributes th { vertical-align: top; text-align: left; }
182 table.attributes td { vertical-align: top; }
182 table.attributes td { vertical-align: top; }
183
183
184 table.boards a.board, h3.comments { background: url(../images/comment.png) no-repeat 0% 50%; padding-left: 20px; }
184 table.boards a.board, h3.comments { background: url(../images/comment.png) no-repeat 0% 50%; padding-left: 20px; }
185
185
186 td.center {text-align:center;}
186 td.center {text-align:center;}
187
187
188 h3.version { background: url(../images/package.png) no-repeat 0% 50%; padding-left: 20px; }
188 h3.version { background: url(../images/package.png) no-repeat 0% 50%; padding-left: 20px; }
189
189
190 div.issues h3 { background: url(../images/ticket.png) no-repeat 0% 50%; padding-left: 20px; }
190 div.issues h3 { background: url(../images/ticket.png) no-repeat 0% 50%; padding-left: 20px; }
191 div.members h3 { background: url(../images/group.png) no-repeat 0% 50%; padding-left: 20px; }
191 div.members h3 { background: url(../images/group.png) no-repeat 0% 50%; padding-left: 20px; }
192 div.news h3 { background: url(../images/news.png) no-repeat 0% 50%; padding-left: 20px; }
192 div.news h3 { background: url(../images/news.png) no-repeat 0% 50%; padding-left: 20px; }
193 div.projects h3 { background: url(../images/projects.png) no-repeat 0% 50%; padding-left: 20px; }
193 div.projects h3 { background: url(../images/projects.png) no-repeat 0% 50%; padding-left: 20px; }
194
194
195 .highlight { background-color: #FCFD8D;}
195 .highlight { background-color: #FCFD8D;}
196 .highlight.token-1 { background-color: #faa;}
196 .highlight.token-1 { background-color: #faa;}
197 .highlight.token-2 { background-color: #afa;}
197 .highlight.token-2 { background-color: #afa;}
198 .highlight.token-3 { background-color: #aaf;}
198 .highlight.token-3 { background-color: #aaf;}
199
199
200 .box{
200 .box{
201 padding:6px;
201 padding:6px;
202 margin-bottom: 10px;
202 margin-bottom: 10px;
203 background-color:#f6f6f6;
203 background-color:#f6f6f6;
204 color:#505050;
204 color:#505050;
205 line-height:1.5em;
205 line-height:1.5em;
206 border: 1px solid #e4e4e4;
206 border: 1px solid #e4e4e4;
207 }
207 }
208
208
209 div.square {
209 div.square {
210 border: 1px solid #999;
210 border: 1px solid #999;
211 float: left;
211 float: left;
212 margin: .3em .4em 0 .4em;
212 margin: .3em .4em 0 .4em;
213 overflow: hidden;
213 overflow: hidden;
214 width: .6em; height: .6em;
214 width: .6em; height: .6em;
215 }
215 }
216 .contextual {float:right; white-space: nowrap; line-height:1.4em;margin-top:5px; padding-left: 10px; font-size:0.9em;}
216 .contextual {float:right; white-space: nowrap; line-height:1.4em;margin-top:5px; padding-left: 10px; font-size:0.9em;}
217 .contextual input, .contextual select {font-size:0.9em;}
217 .contextual input, .contextual select {font-size:0.9em;}
218 .message .contextual { margin-top: 0; }
218 .message .contextual { margin-top: 0; }
219
219
220 .splitcontentleft{float:left; width:49%;}
220 .splitcontentleft{float:left; width:49%;}
221 .splitcontentright{float:right; width:49%;}
221 .splitcontentright{float:right; width:49%;}
222 form {display: inline;}
222 form {display: inline;}
223 input, select {vertical-align: middle; margin-top: 1px; margin-bottom: 1px;}
223 input, select {vertical-align: middle; margin-top: 1px; margin-bottom: 1px;}
224 fieldset {border: 1px solid #e4e4e4; margin:0;}
224 fieldset {border: 1px solid #e4e4e4; margin:0;}
225 legend {color: #484848;}
225 legend {color: #484848;}
226 hr { width: 100%; height: 1px; background: #ccc; border: 0;}
226 hr { width: 100%; height: 1px; background: #ccc; border: 0;}
227 blockquote { font-style: italic; border-left: 3px solid #e0e0e0; padding-left: 0.6em; margin-left: 2.4em;}
227 blockquote { font-style: italic; border-left: 3px solid #e0e0e0; padding-left: 0.6em; margin-left: 2.4em;}
228 blockquote blockquote { margin-left: 0;}
228 blockquote blockquote { margin-left: 0;}
229 acronym { border-bottom: 1px dotted; cursor: help; }
229 acronym { border-bottom: 1px dotted; cursor: help; }
230 textarea.wiki-edit { width: 99%; }
230 textarea.wiki-edit { width: 99%; }
231 li p {margin-top: 0;}
231 li p {margin-top: 0;}
232 div.issue {background:#ffffdd; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7;}
232 div.issue {background:#ffffdd; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7;}
233 p.breadcrumb { font-size: 0.9em; margin: 4px 0 4px 0;}
233 p.breadcrumb { font-size: 0.9em; margin: 4px 0 4px 0;}
234 p.subtitle { font-size: 0.9em; margin: -6px 0 12px 0; font-style: italic; }
234 p.subtitle { font-size: 0.9em; margin: -6px 0 12px 0; font-style: italic; }
235 p.footnote { font-size: 0.9em; margin-top: 0px; margin-bottom: 0px; }
235 p.footnote { font-size: 0.9em; margin-top: 0px; margin-bottom: 0px; }
236
236
237 fieldset.collapsible { border-width: 1px 0 0 0; font-size: 0.9em; }
237 fieldset.collapsible { border-width: 1px 0 0 0; font-size: 0.9em; }
238 fieldset.collapsible legend { padding-left: 16px; background: url(../images/arrow_expanded.png) no-repeat 0% 40%; cursor:pointer; }
238 fieldset.collapsible legend { padding-left: 16px; background: url(../images/arrow_expanded.png) no-repeat 0% 40%; cursor:pointer; }
239 fieldset.collapsible.collapsed legend { background-image: url(../images/arrow_collapsed.png); }
239 fieldset.collapsible.collapsed legend { background-image: url(../images/arrow_collapsed.png); }
240
240
241 fieldset#date-range p { margin: 2px 0 2px 0; }
241 fieldset#date-range p { margin: 2px 0 2px 0; }
242 fieldset#filters table { border-collapse: collapse; }
242 fieldset#filters table { border-collapse: collapse; }
243 fieldset#filters table td { padding: 0; vertical-align: middle; }
243 fieldset#filters table td { padding: 0; vertical-align: middle; }
244 fieldset#filters tr.filter { height: 2em; }
244 fieldset#filters tr.filter { height: 2em; }
245 fieldset#filters td.add-filter { text-align: right; vertical-align: top; }
245 fieldset#filters td.add-filter { text-align: right; vertical-align: top; }
246 .buttons { font-size: 0.9em; margin-bottom: 1.4em; margin-top: 1em; }
246 .buttons { font-size: 0.9em; margin-bottom: 1.4em; margin-top: 1em; }
247
247
248 div#issue-changesets {float:right; width:45%; margin-left: 1em; margin-bottom: 1em; background: #fff; padding-left: 1em; font-size: 90%;}
248 div#issue-changesets {float:right; width:45%; margin-left: 1em; margin-bottom: 1em; background: #fff; padding-left: 1em; font-size: 90%;}
249 div#issue-changesets .changeset { padding: 4px;}
249 div#issue-changesets .changeset { padding: 4px;}
250 div#issue-changesets .changeset { border-bottom: 1px solid #ddd; }
250 div#issue-changesets .changeset { border-bottom: 1px solid #ddd; }
251 div#issue-changesets p { margin-top: 0; margin-bottom: 1em;}
251 div#issue-changesets p { margin-top: 0; margin-bottom: 1em;}
252
252
253 div#activity dl, #search-results { margin-left: 2em; }
253 div#activity dl, #search-results { margin-left: 2em; }
254 div#activity dd, #search-results dd { margin-bottom: 1em; padding-left: 18px; font-size: 0.9em; }
254 div#activity dd, #search-results dd { margin-bottom: 1em; padding-left: 18px; font-size: 0.9em; }
255 div#activity dt, #search-results dt { margin-bottom: 0px; padding-left: 20px; line-height: 18px; background-position: 0 50%; background-repeat: no-repeat; }
255 div#activity dt, #search-results dt { margin-bottom: 0px; padding-left: 20px; line-height: 18px; background-position: 0 50%; background-repeat: no-repeat; }
256 div#activity dt.me .time { border-bottom: 1px solid #999; }
256 div#activity dt.me .time { border-bottom: 1px solid #999; }
257 div#activity dt .time { color: #777; font-size: 80%; }
257 div#activity dt .time { color: #777; font-size: 80%; }
258 div#activity dd .description, #search-results dd .description { font-style: italic; }
258 div#activity dd .description, #search-results dd .description { font-style: italic; }
259 div#activity span.project:after, #search-results span.project:after { content: " -"; }
259 div#activity span.project:after, #search-results span.project:after { content: " -"; }
260 div#activity dd span.description, #search-results dd span.description { display:block; color: #808080; }
260 div#activity dd span.description, #search-results dd span.description { display:block; color: #808080; }
261
261
262 #search-results dd { margin-bottom: 1em; padding-left: 20px; margin-left:0px; }
262 #search-results dd { margin-bottom: 1em; padding-left: 20px; margin-left:0px; }
263
263
264 div#search-results-counts {float:right;}
264 div#search-results-counts {float:right;}
265 div#search-results-counts ul { margin-top: 0.5em; }
265 div#search-results-counts ul { margin-top: 0.5em; }
266 div#search-results-counts li { list-style-type:none; float: left; margin-left: 1em; }
266 div#search-results-counts li { list-style-type:none; float: left; margin-left: 1em; }
267
267
268 dt.issue { background-image: url(../images/ticket.png); }
268 dt.issue { background-image: url(../images/ticket.png); }
269 dt.issue-edit { background-image: url(../images/ticket_edit.png); }
269 dt.issue-edit { background-image: url(../images/ticket_edit.png); }
270 dt.issue-closed { background-image: url(../images/ticket_checked.png); }
270 dt.issue-closed { background-image: url(../images/ticket_checked.png); }
271 dt.issue-note { background-image: url(../images/ticket_note.png); }
271 dt.issue-note { background-image: url(../images/ticket_note.png); }
272 dt.changeset { background-image: url(../images/changeset.png); }
272 dt.changeset { background-image: url(../images/changeset.png); }
273 dt.news { background-image: url(../images/news.png); }
273 dt.news { background-image: url(../images/news.png); }
274 dt.message { background-image: url(../images/message.png); }
274 dt.message { background-image: url(../images/message.png); }
275 dt.reply { background-image: url(../images/comments.png); }
275 dt.reply { background-image: url(../images/comments.png); }
276 dt.wiki-page { background-image: url(../images/wiki_edit.png); }
276 dt.wiki-page { background-image: url(../images/wiki_edit.png); }
277 dt.attachment { background-image: url(../images/attachment.png); }
277 dt.attachment { background-image: url(../images/attachment.png); }
278 dt.document { background-image: url(../images/document.png); }
278 dt.document { background-image: url(../images/document.png); }
279 dt.project { background-image: url(../images/projects.png); }
279 dt.project { background-image: url(../images/projects.png); }
280 dt.time-entry { background-image: url(../images/time.png); }
280 dt.time-entry { background-image: url(../images/time.png); }
281
281
282 #search-results dt.issue.closed { background-image: url(../images/ticket_checked.png); }
282 #search-results dt.issue.closed { background-image: url(../images/ticket_checked.png); }
283
283
284 div#roadmap fieldset.related-issues { margin-bottom: 1em; }
284 div#roadmap fieldset.related-issues { margin-bottom: 1em; }
285 div#roadmap fieldset.related-issues ul { margin-top: 0.3em; margin-bottom: 0.3em; }
285 div#roadmap fieldset.related-issues ul { margin-top: 0.3em; margin-bottom: 0.3em; }
286 div#roadmap .wiki h1:first-child { display: none; }
286 div#roadmap .wiki h1:first-child { display: none; }
287 div#roadmap .wiki h1 { font-size: 120%; }
287 div#roadmap .wiki h1 { font-size: 120%; }
288 div#roadmap .wiki h2 { font-size: 110%; }
288 div#roadmap .wiki h2 { font-size: 110%; }
289
289
290 div#version-summary { float:right; width:380px; margin-left: 16px; margin-bottom: 16px; background-color: #fff; }
290 div#version-summary { float:right; width:380px; margin-left: 16px; margin-bottom: 16px; background-color: #fff; }
291 div#version-summary fieldset { margin-bottom: 1em; }
291 div#version-summary fieldset { margin-bottom: 1em; }
292 div#version-summary .total-hours { text-align: right; }
292 div#version-summary .total-hours { text-align: right; }
293
293
294 table#time-report td.hours, table#time-report th.period, table#time-report th.total { text-align: right; padding-right: 0.5em; }
294 table#time-report td.hours, table#time-report th.period, table#time-report th.total { text-align: right; padding-right: 0.5em; }
295 table#time-report tbody tr { font-style: italic; color: #777; }
295 table#time-report tbody tr { font-style: italic; color: #777; }
296 table#time-report tbody tr.last-level { font-style: normal; color: #555; }
296 table#time-report tbody tr.last-level { font-style: normal; color: #555; }
297 table#time-report tbody tr.total { font-style: normal; font-weight: bold; color: #555; background-color:#EEEEEE; }
297 table#time-report tbody tr.total { font-style: normal; font-weight: bold; color: #555; background-color:#EEEEEE; }
298 table#time-report .hours-dec { font-size: 0.9em; }
298 table#time-report .hours-dec { font-size: 0.9em; }
299
299
300 form#issue-form .attributes { margin-bottom: 8px; }
300 form#issue-form .attributes { margin-bottom: 8px; }
301 form#issue-form .attributes p { padding-top: 1px; padding-bottom: 2px; }
301 form#issue-form .attributes p { padding-top: 1px; padding-bottom: 2px; }
302 form#issue-form .attributes select { min-width: 30%; }
302 form#issue-form .attributes select { min-width: 30%; }
303
303
304 ul.projects { margin: 0; padding-left: 1em; }
304 ul.projects { margin: 0; padding-left: 1em; }
305 ul.projects.root { margin: 0; padding: 0; }
305 ul.projects.root { margin: 0; padding: 0; }
306 ul.projects ul { border-left: 3px solid #e0e0e0; }
306 ul.projects ul { border-left: 3px solid #e0e0e0; }
307 ul.projects li { list-style-type:none; }
307 ul.projects li { list-style-type:none; }
308 ul.projects li.root { margin-bottom: 1em; }
308 ul.projects li.root { margin-bottom: 1em; }
309 ul.projects li.child { margin-top: 1em;}
309 ul.projects li.child { margin-top: 1em;}
310 ul.projects div.root a.project { font-family: "Trebuchet MS", Verdana, sans-serif; font-weight: bold; font-size: 16px; margin: 0 0 10px 0; }
310 ul.projects div.root a.project { font-family: "Trebuchet MS", Verdana, sans-serif; font-weight: bold; font-size: 16px; margin: 0 0 10px 0; }
311 .my-project { padding-left: 18px; background: url(../images/fav.png) no-repeat 0 50%; }
311 .my-project { padding-left: 18px; background: url(../images/fav.png) no-repeat 0 50%; }
312
312
313 #tracker_project_ids ul { margin: 0; padding-left: 1em; }
313 #tracker_project_ids ul { margin: 0; padding-left: 1em; }
314 #tracker_project_ids li { list-style-type:none; }
314 #tracker_project_ids li { list-style-type:none; }
315
315
316 ul.properties {padding:0; font-size: 0.9em; color: #777;}
316 ul.properties {padding:0; font-size: 0.9em; color: #777;}
317 ul.properties li {list-style-type:none;}
317 ul.properties li {list-style-type:none;}
318 ul.properties li span {font-style:italic;}
318 ul.properties li span {font-style:italic;}
319
319
320 .total-hours { font-size: 110%; font-weight: bold; }
320 .total-hours { font-size: 110%; font-weight: bold; }
321 .total-hours span.hours-int { font-size: 120%; }
321 .total-hours span.hours-int { font-size: 120%; }
322
322
323 .autoscroll {overflow-x: auto; padding:1px; margin-bottom: 1.2em;}
323 .autoscroll {overflow-x: auto; padding:1px; margin-bottom: 1.2em;}
324 #user_firstname, #user_lastname, #user_mail, #my_account_form select { width: 90%; }
324 #user_firstname, #user_lastname, #user_mail, #my_account_form select { width: 90%; }
325
325
326 #workflow_copy_form select { width: 200px; }
326 #workflow_copy_form select { width: 200px; }
327
327
328 .pagination {font-size: 90%}
328 .pagination {font-size: 90%}
329 p.pagination {margin-top:8px;}
329 p.pagination {margin-top:8px;}
330
330
331 /***** Tabular forms ******/
331 /***** Tabular forms ******/
332 .tabular p{
332 .tabular p{
333 margin: 0;
333 margin: 0;
334 padding: 5px 0 8px 0;
334 padding: 5px 0 8px 0;
335 padding-left: 180px; /*width of left column containing the label elements*/
335 padding-left: 180px; /*width of left column containing the label elements*/
336 height: 1%;
336 height: 1%;
337 clear:left;
337 clear:left;
338 }
338 }
339
339
340 html>body .tabular p {overflow:hidden;}
340 html>body .tabular p {overflow:hidden;}
341
341
342 .tabular label{
342 .tabular label{
343 font-weight: bold;
343 font-weight: bold;
344 float: left;
344 float: left;
345 text-align: right;
345 text-align: right;
346 margin-left: -180px; /*width of left column*/
346 margin-left: -180px; /*width of left column*/
347 width: 175px; /*width of labels. Should be smaller than left column to create some right
347 width: 175px; /*width of labels. Should be smaller than left column to create some right
348 margin*/
348 margin*/
349 }
349 }
350
350
351 .tabular label.floating{
351 .tabular label.floating{
352 font-weight: normal;
352 font-weight: normal;
353 margin-left: 0px;
353 margin-left: 0px;
354 text-align: left;
354 text-align: left;
355 width: 270px;
355 width: 270px;
356 }
356 }
357
357
358 .tabular label.block{
358 .tabular label.block{
359 font-weight: normal;
359 font-weight: normal;
360 margin-left: 0px !important;
360 margin-left: 0px !important;
361 text-align: left;
361 text-align: left;
362 float: none;
362 float: none;
363 display: block;
363 display: block;
364 width: auto;
364 width: auto;
365 }
365 }
366
366
367 input#time_entry_comments { width: 90%;}
367 input#time_entry_comments { width: 90%;}
368
368
369 #preview fieldset {margin-top: 1em; background: url(../images/draft.png)}
369 #preview fieldset {margin-top: 1em; background: url(../images/draft.png)}
370
370
371 .tabular.settings p{ padding-left: 300px; }
371 .tabular.settings p{ padding-left: 300px; }
372 .tabular.settings label{ margin-left: -300px; width: 295px; }
372 .tabular.settings label{ margin-left: -300px; width: 295px; }
373 .tabular.settings textarea { width: 99%; }
373 .tabular.settings textarea { width: 99%; }
374
374
375 fieldset.settings label { display: block; }
375 fieldset.settings label { display: block; }
376
376
377 .required {color: #bb0000;}
377 .required {color: #bb0000;}
378 .summary {font-style: italic;}
378 .summary {font-style: italic;}
379
379
380 #attachments_fields input[type=text] {margin-left: 8px; }
380 #attachments_fields input[type=text] {margin-left: 8px; }
381
381
382 div.attachments { margin-top: 12px; }
382 div.attachments { margin-top: 12px; }
383 div.attachments p { margin:4px 0 2px 0; }
383 div.attachments p { margin:4px 0 2px 0; }
384 div.attachments img { vertical-align: middle; }
384 div.attachments img { vertical-align: middle; }
385 div.attachments span.author { font-size: 0.9em; color: #888; }
385 div.attachments span.author { font-size: 0.9em; color: #888; }
386
386
387 p.other-formats { text-align: right; font-size:0.9em; color: #666; }
387 p.other-formats { text-align: right; font-size:0.9em; color: #666; }
388 .other-formats span + span:before { content: "| "; }
388 .other-formats span + span:before { content: "| "; }
389
389
390 a.atom { background: url(../images/feed.png) no-repeat 1px 50%; padding: 2px 0px 3px 16px; }
390 a.atom { background: url(../images/feed.png) no-repeat 1px 50%; padding: 2px 0px 3px 16px; }
391
391
392 /* Project members tab */
392 /* Project members tab */
393 div#tab-content-members .splitcontentleft, div#tab-content-memberships .splitcontentleft, div#tab-content-users .splitcontentleft { width: 64% }
393 div#tab-content-members .splitcontentleft, div#tab-content-memberships .splitcontentleft, div#tab-content-users .splitcontentleft { width: 64% }
394 div#tab-content-members .splitcontentright, div#tab-content-memberships .splitcontentright, div#tab-content-users .splitcontentright { width: 34% }
394 div#tab-content-members .splitcontentright, div#tab-content-memberships .splitcontentright, div#tab-content-users .splitcontentright { width: 34% }
395 div#tab-content-members fieldset, div#tab-content-memberships fieldset, div#tab-content-users fieldset { padding:1em; margin-bottom: 1em; }
395 div#tab-content-members fieldset, div#tab-content-memberships fieldset, div#tab-content-users fieldset { padding:1em; margin-bottom: 1em; }
396 div#tab-content-members fieldset legend, div#tab-content-memberships fieldset legend, div#tab-content-users fieldset legend { font-weight: bold; }
396 div#tab-content-members fieldset legend, div#tab-content-memberships fieldset legend, div#tab-content-users fieldset legend { font-weight: bold; }
397 div#tab-content-members fieldset label, div#tab-content-memberships fieldset label, div#tab-content-users fieldset label { display: block; }
397 div#tab-content-members fieldset label, div#tab-content-memberships fieldset label, div#tab-content-users fieldset label { display: block; }
398 div#tab-content-members fieldset div, div#tab-content-users fieldset div { max-height: 400px; overflow:auto; }
398 div#tab-content-members fieldset div, div#tab-content-users fieldset div { max-height: 400px; overflow:auto; }
399
399
400 table.members td.group { padding-left: 20px; background: url(../images/group.png) no-repeat 0% 50%; }
400 table.members td.group { padding-left: 20px; background: url(../images/group.png) no-repeat 0% 50%; }
401
401
402 * html div#tab-content-members fieldset div { height: 450px; }
402 * html div#tab-content-members fieldset div { height: 450px; }
403
403
404 /***** Flash & error messages ****/
404 /***** Flash & error messages ****/
405 #errorExplanation, div.flash, .nodata, .warning {
405 #errorExplanation, div.flash, .nodata, .warning {
406 padding: 4px 4px 4px 30px;
406 padding: 4px 4px 4px 30px;
407 margin-bottom: 12px;
407 margin-bottom: 12px;
408 font-size: 1.1em;
408 font-size: 1.1em;
409 border: 2px solid;
409 border: 2px solid;
410 }
410 }
411
411
412 div.flash {margin-top: 8px;}
412 div.flash {margin-top: 8px;}
413
413
414 div.flash.error, #errorExplanation {
414 div.flash.error, #errorExplanation {
415 background: url(../images/exclamation.png) 8px 50% no-repeat;
415 background: url(../images/exclamation.png) 8px 50% no-repeat;
416 background-color: #ffe3e3;
416 background-color: #ffe3e3;
417 border-color: #dd0000;
417 border-color: #dd0000;
418 color: #880000;
418 color: #880000;
419 }
419 }
420
420
421 div.flash.notice {
421 div.flash.notice {
422 background: url(../images/true.png) 8px 5px no-repeat;
422 background: url(../images/true.png) 8px 5px no-repeat;
423 background-color: #dfffdf;
423 background-color: #dfffdf;
424 border-color: #9fcf9f;
424 border-color: #9fcf9f;
425 color: #005f00;
425 color: #005f00;
426 }
426 }
427
427
428 div.flash.warning {
428 div.flash.warning {
429 background: url(../images/warning.png) 8px 5px no-repeat;
429 background: url(../images/warning.png) 8px 5px no-repeat;
430 background-color: #FFEBC1;
430 background-color: #FFEBC1;
431 border-color: #FDBF3B;
431 border-color: #FDBF3B;
432 color: #A6750C;
432 color: #A6750C;
433 text-align: left;
433 text-align: left;
434 }
434 }
435
435
436 .nodata, .warning {
436 .nodata, .warning {
437 text-align: center;
437 text-align: center;
438 background-color: #FFEBC1;
438 background-color: #FFEBC1;
439 border-color: #FDBF3B;
439 border-color: #FDBF3B;
440 color: #A6750C;
440 color: #A6750C;
441 }
441 }
442
442
443 #errorExplanation ul { font-size: 0.9em;}
443 #errorExplanation ul { font-size: 0.9em;}
444 #errorExplanation h2, #errorExplanation p { display: none; }
444 #errorExplanation h2, #errorExplanation p { display: none; }
445
445
446 /***** Ajax indicator ******/
446 /***** Ajax indicator ******/
447 #ajax-indicator {
447 #ajax-indicator {
448 position: absolute; /* fixed not supported by IE */
448 position: absolute; /* fixed not supported by IE */
449 background-color:#eee;
449 background-color:#eee;
450 border: 1px solid #bbb;
450 border: 1px solid #bbb;
451 top:35%;
451 top:35%;
452 left:40%;
452 left:40%;
453 width:20%;
453 width:20%;
454 font-weight:bold;
454 font-weight:bold;
455 text-align:center;
455 text-align:center;
456 padding:0.6em;
456 padding:0.6em;
457 z-index:100;
457 z-index:100;
458 filter:alpha(opacity=50);
458 filter:alpha(opacity=50);
459 opacity: 0.5;
459 opacity: 0.5;
460 }
460 }
461
461
462 html>body #ajax-indicator { position: fixed; }
462 html>body #ajax-indicator { position: fixed; }
463
463
464 #ajax-indicator span {
464 #ajax-indicator span {
465 background-position: 0% 40%;
465 background-position: 0% 40%;
466 background-repeat: no-repeat;
466 background-repeat: no-repeat;
467 background-image: url(../images/loading.gif);
467 background-image: url(../images/loading.gif);
468 padding-left: 26px;
468 padding-left: 26px;
469 vertical-align: bottom;
469 vertical-align: bottom;
470 }
470 }
471
471
472 /***** Calendar *****/
472 /***** Calendar *****/
473 table.cal {border-collapse: collapse; width: 100%; margin: 0px 0 6px 0;border: 1px solid #d7d7d7;}
473 table.cal {border-collapse: collapse; width: 100%; margin: 0px 0 6px 0;border: 1px solid #d7d7d7;}
474 table.cal thead th {width: 14%;}
474 table.cal thead th {width: 14%;}
475 table.cal tbody tr {height: 100px;}
475 table.cal tbody tr {height: 100px;}
476 table.cal th { background-color:#EEEEEE; padding: 4px; }
476 table.cal th { background-color:#EEEEEE; padding: 4px; }
477 table.cal td {border: 1px solid #d7d7d7; vertical-align: top; font-size: 0.9em;}
477 table.cal td {border: 1px solid #d7d7d7; vertical-align: top; font-size: 0.9em;}
478 table.cal td p.day-num {font-size: 1.1em; text-align:right;}
478 table.cal td p.day-num {font-size: 1.1em; text-align:right;}
479 table.cal td.odd p.day-num {color: #bbb;}
479 table.cal td.odd p.day-num {color: #bbb;}
480 table.cal td.today {background:#ffffdd;}
480 table.cal td.today {background:#ffffdd;}
481 table.cal td.today p.day-num {font-weight: bold;}
481 table.cal td.today p.day-num {font-weight: bold;}
482
482
483 /***** Tooltips ******/
483 /***** Tooltips ******/
484 .tooltip{position:relative;z-index:24;}
484 .tooltip{position:relative;z-index:24;}
485 .tooltip:hover{z-index:25;color:#000;}
485 .tooltip:hover{z-index:25;color:#000;}
486 .tooltip span.tip{display: none; text-align:left;}
486 .tooltip span.tip{display: none; text-align:left;}
487
487
488 div.tooltip:hover span.tip{
488 div.tooltip:hover span.tip{
489 display:block;
489 display:block;
490 position:absolute;
490 position:absolute;
491 top:12px; left:24px; width:270px;
491 top:12px; left:24px; width:270px;
492 border:1px solid #555;
492 border:1px solid #555;
493 background-color:#fff;
493 background-color:#fff;
494 padding: 4px;
494 padding: 4px;
495 font-size: 0.8em;
495 font-size: 0.8em;
496 color:#505050;
496 color:#505050;
497 }
497 }
498
498
499 /***** Progress bar *****/
499 /***** Progress bar *****/
500 table.progress {
500 table.progress {
501 border: 1px solid #D7D7D7;
501 border: 1px solid #D7D7D7;
502 border-collapse: collapse;
502 border-collapse: collapse;
503 border-spacing: 0pt;
503 border-spacing: 0pt;
504 empty-cells: show;
504 empty-cells: show;
505 text-align: center;
505 text-align: center;
506 float:left;
506 float:left;
507 margin: 1px 6px 1px 0px;
507 margin: 1px 6px 1px 0px;
508 }
508 }
509
509
510 table.progress td { height: 0.9em; }
510 table.progress td { height: 0.9em; }
511 table.progress td.closed { background: #BAE0BA none repeat scroll 0%; }
511 table.progress td.closed { background: #BAE0BA none repeat scroll 0%; }
512 table.progress td.done { background: #DEF0DE none repeat scroll 0%; }
512 table.progress td.done { background: #DEF0DE none repeat scroll 0%; }
513 table.progress td.open { background: #FFF none repeat scroll 0%; }
513 table.progress td.open { background: #FFF none repeat scroll 0%; }
514 p.pourcent {font-size: 80%;}
514 p.pourcent {font-size: 80%;}
515 p.progress-info {clear: left; font-style: italic; font-size: 80%;}
515 p.progress-info {clear: left; font-style: italic; font-size: 80%;}
516
516
517 /***** Tabs *****/
517 /***** Tabs *****/
518 #content .tabs {height: 2.6em; border-bottom: 1px solid #bbbbbb; margin-bottom:1.2em; position:relative; overflow:hidden;}
518 #content .tabs {height: 2.6em; border-bottom: 1px solid #bbbbbb; margin-bottom:1.2em; position:relative; overflow:hidden;}
519 #content .tabs ul {margin:0; position:absolute; bottom:-2px; padding-left:1em; width: 2000px;}
519 #content .tabs ul {margin:0; position:absolute; bottom:-2px; padding-left:1em; width: 2000px;}
520 #content .tabs>ul { bottom:-1px; } /* others */
520 #content .tabs>ul { bottom:-1px; } /* others */
521 #content .tabs ul li {
521 #content .tabs ul li {
522 float:left;
522 float:left;
523 list-style-type:none;
523 list-style-type:none;
524 white-space:nowrap;
524 white-space:nowrap;
525 margin-right:8px;
525 margin-right:8px;
526 background:#fff;
526 background:#fff;
527 }
527 }
528 #content .tabs ul li a{
528 #content .tabs ul li a{
529 display:block;
529 display:block;
530 font-size: 0.9em;
530 font-size: 0.9em;
531 text-decoration:none;
531 text-decoration:none;
532 line-height:1.3em;
532 line-height:1.3em;
533 padding:4px 6px 4px 6px;
533 padding:4px 6px 4px 6px;
534 border: 1px solid #ccc;
534 border: 1px solid #ccc;
535 border-bottom: 1px solid #bbbbbb;
535 border-bottom: 1px solid #bbbbbb;
536 background-color: #eeeeee;
536 background-color: #eeeeee;
537 color:#777;
537 color:#777;
538 font-weight:bold;
538 font-weight:bold;
539 }
539 }
540
540
541 #content .tabs ul li a:hover {
541 #content .tabs ul li a:hover {
542 background-color: #ffffdd;
542 background-color: #ffffdd;
543 text-decoration:none;
543 text-decoration:none;
544 }
544 }
545
545
546 #content .tabs ul li a.selected {
546 #content .tabs ul li a.selected {
547 background-color: #fff;
547 background-color: #fff;
548 border: 1px solid #bbbbbb;
548 border: 1px solid #bbbbbb;
549 border-bottom: 1px solid #fff;
549 border-bottom: 1px solid #fff;
550 }
550 }
551
551
552 #content .tabs ul li a.selected:hover {
552 #content .tabs ul li a.selected:hover {
553 background-color: #fff;
553 background-color: #fff;
554 }
554 }
555
555
556 div.tabs-buttons { position:absolute; right: 0; width: 48px; height: 24px; background: white; bottom: -1px; }
556 div.tabs-buttons { position:absolute; right: 0; width: 48px; height: 24px; background: white; bottom: -1px; }
557
557
558 button.tab-left, button.tab-right {
558 button.tab-left, button.tab-right {
559 font-size: 0.9em;
559 font-size: 0.9em;
560 cursor: pointer;
560 cursor: pointer;
561 height:24px;
561 height:24px;
562 border: 1px solid #ccc;
562 border: 1px solid #ccc;
563 border-bottom: 1px solid #bbbbbb;
563 border-bottom: 1px solid #bbbbbb;
564 position:absolute;
564 position:absolute;
565 padding:4px;
565 padding:4px;
566 width: 20px;
566 width: 20px;
567 }
567 }
568
568
569 button.tab-left {
569 button.tab-left {
570 right: 20px;
570 right: 20px;
571 bottom: 0;
571 bottom: 0;
572 background: #eeeeee url(../images/bullet_arrow_left.png) no-repeat 50% 50%;
572 background: #eeeeee url(../images/bullet_arrow_left.png) no-repeat 50% 50%;
573 }
573 }
574
574
575 button.tab-right {
575 button.tab-right {
576 right: 0;
576 right: 0;
577 bottom: 0;
577 bottom: 0;
578 background: #eeeeee url(../images/bullet_arrow_right.png) no-repeat 50% 50%;}
578 background: #eeeeee url(../images/bullet_arrow_right.png) no-repeat 50% 50%;}
579 }
579 }
580
580
581 /***** Auto-complete *****/
581 /***** Auto-complete *****/
582 div.autocomplete {
582 div.autocomplete {
583 position:absolute;
583 position:absolute;
584 width:250px;
584 width:250px;
585 background-color:white;
585 background-color:white;
586 margin:0;
586 margin:0;
587 padding:0;
587 padding:0;
588 }
588 }
589 div.autocomplete ul {
589 div.autocomplete ul {
590 list-style-type:none;
590 list-style-type:none;
591 margin:0;
591 margin:0;
592 padding:0;
592 padding:0;
593 }
593 }
594 div.autocomplete ul li.selected { background-color: #ffb;}
594 div.autocomplete ul li.selected { background-color: #ffb;}
595 div.autocomplete ul li {
595 div.autocomplete ul li {
596 list-style-type:none;
596 list-style-type:none;
597 display:block;
597 display:block;
598 margin:0;
598 margin:0;
599 padding:2px;
599 padding:2px;
600 cursor:pointer;
600 cursor:pointer;
601 font-size: 90%;
601 font-size: 90%;
602 border-bottom: 1px solid #ccc;
602 border-bottom: 1px solid #ccc;
603 border-left: 1px solid #ccc;
603 border-left: 1px solid #ccc;
604 border-right: 1px solid #ccc;
604 border-right: 1px solid #ccc;
605 }
605 }
606 div.autocomplete ul li span.informal {
606 div.autocomplete ul li span.informal {
607 font-size: 80%;
607 font-size: 80%;
608 color: #aaa;
608 color: #aaa;
609 }
609 }
610
610
611 /***** Diff *****/
611 /***** Diff *****/
612 .diff_out { background: #fcc; }
612 .diff_out { background: #fcc; }
613 .diff_in { background: #cfc; }
613 .diff_in { background: #cfc; }
614
614
615 /***** Wiki *****/
615 /***** Wiki *****/
616 div.wiki table {
616 div.wiki table {
617 border: 1px solid #505050;
617 border: 1px solid #505050;
618 border-collapse: collapse;
618 border-collapse: collapse;
619 margin-bottom: 1em;
619 margin-bottom: 1em;
620 }
620 }
621
621
622 div.wiki table, div.wiki td, div.wiki th {
622 div.wiki table, div.wiki td, div.wiki th {
623 border: 1px solid #bbb;
623 border: 1px solid #bbb;
624 padding: 4px;
624 padding: 4px;
625 }
625 }
626
626
627 div.wiki .external {
627 div.wiki .external {
628 background-position: 0% 60%;
628 background-position: 0% 60%;
629 background-repeat: no-repeat;
629 background-repeat: no-repeat;
630 padding-left: 12px;
630 padding-left: 12px;
631 background-image: url(../images/external.png);
631 background-image: url(../images/external.png);
632 }
632 }
633
633
634 div.wiki a.new {
634 div.wiki a.new {
635 color: #b73535;
635 color: #b73535;
636 }
636 }
637
637
638 div.wiki pre {
638 div.wiki pre {
639 margin: 1em 1em 1em 1.6em;
639 margin: 1em 1em 1em 1.6em;
640 padding: 2px;
640 padding: 2px;
641 background-color: #fafafa;
641 background-color: #fafafa;
642 border: 1px solid #dadada;
642 border: 1px solid #dadada;
643 width:95%;
643 width:95%;
644 overflow-x: auto;
644 overflow-x: auto;
645 }
645 }
646
646
647 div.wiki ul.toc {
647 div.wiki ul.toc {
648 background-color: #ffffdd;
648 background-color: #ffffdd;
649 border: 1px solid #e4e4e4;
649 border: 1px solid #e4e4e4;
650 padding: 4px;
650 padding: 4px;
651 line-height: 1.2em;
651 line-height: 1.2em;
652 margin-bottom: 12px;
652 margin-bottom: 12px;
653 margin-right: 12px;
653 margin-right: 12px;
654 margin-left: 0;
654 margin-left: 0;
655 display: table
655 display: table
656 }
656 }
657 * html div.wiki ul.toc { width: 50%; } /* IE6 doesn't autosize div */
657 * html div.wiki ul.toc { width: 50%; } /* IE6 doesn't autosize div */
658
658
659 div.wiki ul.toc.right { float: right; margin-left: 12px; margin-right: 0; width: auto; }
659 div.wiki ul.toc.right { float: right; margin-left: 12px; margin-right: 0; width: auto; }
660 div.wiki ul.toc.left { float: left; margin-right: 12px; margin-left: 0; width: auto; }
660 div.wiki ul.toc.left { float: left; margin-right: 12px; margin-left: 0; width: auto; }
661 div.wiki ul.toc li { list-style-type:none;}
661 div.wiki ul.toc li { list-style-type:none;}
662 div.wiki ul.toc li.heading2 { margin-left: 6px; }
662 div.wiki ul.toc li.heading2 { margin-left: 6px; }
663 div.wiki ul.toc li.heading3 { margin-left: 12px; font-size: 0.8em; }
663 div.wiki ul.toc li.heading3 { margin-left: 12px; font-size: 0.8em; }
664
664
665 div.wiki ul.toc a {
665 div.wiki ul.toc a {
666 font-size: 0.9em;
666 font-size: 0.9em;
667 font-weight: normal;
667 font-weight: normal;
668 text-decoration: none;
668 text-decoration: none;
669 color: #606060;
669 color: #606060;
670 }
670 }
671 div.wiki ul.toc a:hover { color: #c61a1a; text-decoration: underline;}
671 div.wiki ul.toc a:hover { color: #c61a1a; text-decoration: underline;}
672
672
673 a.wiki-anchor { display: none; margin-left: 6px; text-decoration: none; }
673 a.wiki-anchor { display: none; margin-left: 6px; text-decoration: none; }
674 a.wiki-anchor:hover { color: #aaa !important; text-decoration: none; }
674 a.wiki-anchor:hover { color: #aaa !important; text-decoration: none; }
675 h1:hover a.wiki-anchor, h2:hover a.wiki-anchor, h3:hover a.wiki-anchor { display: inline; color: #ddd; }
675 h1:hover a.wiki-anchor, h2:hover a.wiki-anchor, h3:hover a.wiki-anchor { display: inline; color: #ddd; }
676
676
677 /***** My page layout *****/
677 /***** My page layout *****/
678 .block-receiver {
678 .block-receiver {
679 border:1px dashed #c0c0c0;
679 border:1px dashed #c0c0c0;
680 margin-bottom: 20px;
680 margin-bottom: 20px;
681 padding: 15px 0 15px 0;
681 padding: 15px 0 15px 0;
682 }
682 }
683
683
684 .mypage-box {
684 .mypage-box {
685 margin:0 0 20px 0;
685 margin:0 0 20px 0;
686 color:#505050;
686 color:#505050;
687 line-height:1.5em;
687 line-height:1.5em;
688 }
688 }
689
689
690 .handle {
690 .handle {
691 cursor: move;
691 cursor: move;
692 }
692 }
693
693
694 a.close-icon {
694 a.close-icon {
695 display:block;
695 display:block;
696 margin-top:3px;
696 margin-top:3px;
697 overflow:hidden;
697 overflow:hidden;
698 width:12px;
698 width:12px;
699 height:12px;
699 height:12px;
700 background-repeat: no-repeat;
700 background-repeat: no-repeat;
701 cursor:pointer;
701 cursor:pointer;
702 background-image:url('../images/close.png');
702 background-image:url('../images/close.png');
703 }
703 }
704
704
705 a.close-icon:hover {
705 a.close-icon:hover {
706 background-image:url('../images/close_hl.png');
706 background-image:url('../images/close_hl.png');
707 }
707 }
708
708
709 /***** Gantt chart *****/
709 /***** Gantt chart *****/
710 .gantt_hdr {
710 .gantt_hdr {
711 position:absolute;
711 position:absolute;
712 top:0;
712 top:0;
713 height:16px;
713 height:16px;
714 border-top: 1px solid #c0c0c0;
714 border-top: 1px solid #c0c0c0;
715 border-bottom: 1px solid #c0c0c0;
715 border-bottom: 1px solid #c0c0c0;
716 border-right: 1px solid #c0c0c0;
716 border-right: 1px solid #c0c0c0;
717 text-align: center;
717 text-align: center;
718 overflow: hidden;
718 overflow: hidden;
719 }
719 }
720
720
721 .task {
721 .task {
722 position: absolute;
722 position: absolute;
723 height:8px;
723 height:8px;
724 font-size:0.8em;
724 font-size:0.8em;
725 color:#888;
725 color:#888;
726 padding:0;
726 padding:0;
727 margin:0;
727 margin:0;
728 line-height:0.8em;
728 line-height:0.8em;
729 }
729 }
730
730
731 .task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; }
731 .task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; }
732 .task_done { background:#66f url(../images/task_done.png); border: 1px solid #66f; }
732 .task_done { background:#66f url(../images/task_done.png); border: 1px solid #66f; }
733 .task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; }
733 .task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; }
734 .milestone { background-image:url(../images/milestone.png); background-repeat: no-repeat; border: 0; }
734 .milestone { background-image:url(../images/milestone.png); background-repeat: no-repeat; border: 0; }
735
735
736 /***** Icons *****/
736 /***** Icons *****/
737 .icon {
737 .icon {
738 background-position: 0% 50%;
738 background-position: 0% 50%;
739 background-repeat: no-repeat;
739 background-repeat: no-repeat;
740 padding-left: 20px;
740 padding-left: 20px;
741 padding-top: 2px;
741 padding-top: 2px;
742 padding-bottom: 3px;
742 padding-bottom: 3px;
743 }
743 }
744
744
745 .icon-add { background-image: url(../images/add.png); }
745 .icon-add { background-image: url(../images/add.png); }
746 .icon-edit { background-image: url(../images/edit.png); }
746 .icon-edit { background-image: url(../images/edit.png); }
747 .icon-copy { background-image: url(../images/copy.png); }
747 .icon-copy { background-image: url(../images/copy.png); }
748 .icon-duplicate { background-image: url(../images/duplicate.png); }
748 .icon-duplicate { background-image: url(../images/duplicate.png); }
749 .icon-del { background-image: url(../images/delete.png); }
749 .icon-del { background-image: url(../images/delete.png); }
750 .icon-move { background-image: url(../images/move.png); }
750 .icon-move { background-image: url(../images/move.png); }
751 .icon-save { background-image: url(../images/save.png); }
751 .icon-save { background-image: url(../images/save.png); }
752 .icon-cancel { background-image: url(../images/cancel.png); }
752 .icon-cancel { background-image: url(../images/cancel.png); }
753 .icon-multiple { background-image: url(../images/table_multiple.png); }
753 .icon-multiple { background-image: url(../images/table_multiple.png); }
754 .icon-folder { background-image: url(../images/folder.png); }
754 .icon-folder { background-image: url(../images/folder.png); }
755 .open .icon-folder { background-image: url(../images/folder_open.png); }
755 .open .icon-folder { background-image: url(../images/folder_open.png); }
756 .icon-package { background-image: url(../images/package.png); }
756 .icon-package { background-image: url(../images/package.png); }
757 .icon-home { background-image: url(../images/home.png); }
757 .icon-home { background-image: url(../images/home.png); }
758 .icon-user { background-image: url(../images/user.png); }
758 .icon-user { background-image: url(../images/user.png); }
759 .icon-projects { background-image: url(../images/projects.png); }
759 .icon-projects { background-image: url(../images/projects.png); }
760 .icon-help { background-image: url(../images/help.png); }
760 .icon-help { background-image: url(../images/help.png); }
761 .icon-attachment { background-image: url(../images/attachment.png); }
761 .icon-attachment { background-image: url(../images/attachment.png); }
762 .icon-history { background-image: url(../images/history.png); }
762 .icon-history { background-image: url(../images/history.png); }
763 .icon-time { background-image: url(../images/time.png); }
763 .icon-time { background-image: url(../images/time.png); }
764 .icon-time-add { background-image: url(../images/time_add.png); }
764 .icon-time-add { background-image: url(../images/time_add.png); }
765 .icon-stats { background-image: url(../images/stats.png); }
765 .icon-stats { background-image: url(../images/stats.png); }
766 .icon-warning { background-image: url(../images/warning.png); }
766 .icon-warning { background-image: url(../images/warning.png); }
767 .icon-fav { background-image: url(../images/fav.png); }
767 .icon-fav { background-image: url(../images/fav.png); }
768 .icon-fav-off { background-image: url(../images/fav_off.png); }
768 .icon-fav-off { background-image: url(../images/fav_off.png); }
769 .icon-reload { background-image: url(../images/reload.png); }
769 .icon-reload { background-image: url(../images/reload.png); }
770 .icon-lock { background-image: url(../images/locked.png); }
770 .icon-lock { background-image: url(../images/locked.png); }
771 .icon-unlock { background-image: url(../images/unlock.png); }
771 .icon-unlock { background-image: url(../images/unlock.png); }
772 .icon-checked { background-image: url(../images/true.png); }
772 .icon-checked { background-image: url(../images/true.png); }
773 .icon-details { background-image: url(../images/zoom_in.png); }
773 .icon-details { background-image: url(../images/zoom_in.png); }
774 .icon-report { background-image: url(../images/report.png); }
774 .icon-report { background-image: url(../images/report.png); }
775 .icon-comment { background-image: url(../images/comment.png); }
775 .icon-comment { background-image: url(../images/comment.png); }
776 .icon-summary { background-image: url(../images/lightning.png); }
776 .icon-summary { background-image: url(../images/lightning.png); }
777
777
778 .icon-file { background-image: url(../images/files/default.png); }
778 .icon-file { background-image: url(../images/files/default.png); }
779 .icon-file.text-plain { background-image: url(../images/files/text.png); }
779 .icon-file.text-plain { background-image: url(../images/files/text.png); }
780 .icon-file.text-x-c { background-image: url(../images/files/c.png); }
780 .icon-file.text-x-c { background-image: url(../images/files/c.png); }
781 .icon-file.text-x-csharp { background-image: url(../images/files/csharp.png); }
781 .icon-file.text-x-csharp { background-image: url(../images/files/csharp.png); }
782 .icon-file.text-x-php { background-image: url(../images/files/php.png); }
782 .icon-file.text-x-php { background-image: url(../images/files/php.png); }
783 .icon-file.text-x-ruby { background-image: url(../images/files/ruby.png); }
783 .icon-file.text-x-ruby { background-image: url(../images/files/ruby.png); }
784 .icon-file.text-xml { background-image: url(../images/files/xml.png); }
784 .icon-file.text-xml { background-image: url(../images/files/xml.png); }
785 .icon-file.image-gif { background-image: url(../images/files/image.png); }
785 .icon-file.image-gif { background-image: url(../images/files/image.png); }
786 .icon-file.image-jpeg { background-image: url(../images/files/image.png); }
786 .icon-file.image-jpeg { background-image: url(../images/files/image.png); }
787 .icon-file.image-png { background-image: url(../images/files/image.png); }
787 .icon-file.image-png { background-image: url(../images/files/image.png); }
788 .icon-file.image-tiff { background-image: url(../images/files/image.png); }
788 .icon-file.image-tiff { background-image: url(../images/files/image.png); }
789 .icon-file.application-pdf { background-image: url(../images/files/pdf.png); }
789 .icon-file.application-pdf { background-image: url(../images/files/pdf.png); }
790 .icon-file.application-zip { background-image: url(../images/files/zip.png); }
790 .icon-file.application-zip { background-image: url(../images/files/zip.png); }
791 .icon-file.application-x-gzip { background-image: url(../images/files/zip.png); }
791 .icon-file.application-x-gzip { background-image: url(../images/files/zip.png); }
792
792
793 img.gravatar {
793 img.gravatar {
794 padding: 2px;
794 padding: 2px;
795 border: solid 1px #d5d5d5;
795 border: solid 1px #d5d5d5;
796 background: #fff;
796 background: #fff;
797 }
797 }
798
798
799 div.issue img.gravatar {
799 div.issue img.gravatar {
800 float: right;
800 float: right;
801 margin: 0 0 0 1em;
801 margin: 0 0 0 1em;
802 padding: 5px;
802 padding: 5px;
803 }
803 }
804
804
805 div.issue table img.gravatar {
805 div.issue table img.gravatar {
806 height: 14px;
806 height: 14px;
807 width: 14px;
807 width: 14px;
808 padding: 2px;
808 padding: 2px;
809 float: left;
809 float: left;
810 margin: 0 0.5em 0 0;
810 margin: 0 0.5em 0 0;
811 }
811 }
812
812
813 #history img.gravatar {
813 h2 img.gravatar {
814 padding: 3px;
814 padding: 3px;
815 margin: 0 1.5em 1em 0;
815 margin: -2px 4px 0 0;
816 float: left;
817 }
818
819 h4 img.gravatar {
820 padding: 3px;
821 margin: -6px 4px 0 0;
816 float: left;
822 float: left;
817 }
823 }
818
824
819 td.username img.gravatar {
825 td.username img.gravatar {
820 float: left;
826 float: left;
821 margin: 0 1em 0 0;
827 margin: 0 1em 0 0;
822 }
828 }
823
829
824 #activity dt img.gravatar {
830 #activity dt img.gravatar {
825 float: left;
831 float: left;
826 margin: 0 1em 1em 0;
832 margin: 0 1em 1em 0;
827 }
833 }
828
834
829 #activity dt,
835 #activity dt,
830 .journal {
836 .journal {
831 clear: left;
837 clear: left;
832 }
838 }
833
839
834 .gravatar-margin {
835 margin-left: 40px;
836 }
837
838 h2 img { vertical-align:middle; }
840 h2 img { vertical-align:middle; }
839
841
840 .hascontextmenu { cursor: context-menu; }
842 .hascontextmenu { cursor: context-menu; }
841
843
842 /***** Media print specific styles *****/
844 /***** Media print specific styles *****/
843 @media print {
845 @media print {
844 #top-menu, #header, #main-menu, #sidebar, #footer, .contextual, .other-formats { display:none; }
846 #top-menu, #header, #main-menu, #sidebar, #footer, .contextual, .other-formats { display:none; }
845 #main { background: #fff; }
847 #main { background: #fff; }
846 #content { width: 99%; margin: 0; padding: 0; border: 0; background: #fff; overflow: visible !important;}
848 #content { width: 99%; margin: 0; padding: 0; border: 0; background: #fff; overflow: visible !important;}
847 #wiki_add_attachment { display:none; }
849 #wiki_add_attachment { display:none; }
848 }
850 }
General Comments 0
You need to be logged in to leave comments. Login now