##// END OF EJS Templates
Roadmap: more accurate completion percentage calculation (done ratio of open issues is now taken into account)....
Jean-Philippe Lang -
r895:9ad79612fed4
parent child
Show More
@@ -1,386 +1,397
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 module ApplicationHelper
19 19 include Redmine::WikiFormatting::Macros::Definitions
20 20
21 21 def current_role
22 22 @current_role ||= User.current.role_for_project(@project)
23 23 end
24 24
25 25 # Return true if user is authorized for controller/action, otherwise false
26 26 def authorize_for(controller, action)
27 27 User.current.allowed_to?({:controller => controller, :action => action}, @project)
28 28 end
29 29
30 30 # Display a link if user is authorized
31 31 def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference)
32 32 link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller] || params[:controller], options[:action])
33 33 end
34 34
35 35 # Display a link to user's account page
36 36 def link_to_user(user)
37 37 link_to user.name, :controller => 'account', :action => 'show', :id => user
38 38 end
39 39
40 40 def link_to_issue(issue)
41 41 link_to "#{issue.tracker.name} ##{issue.id}", :controller => "issues", :action => "show", :id => issue
42 42 end
43 43
44 44 def toggle_link(name, id, options={})
45 45 onclick = "Element.toggle('#{id}'); "
46 46 onclick << (options[:focus] ? "Form.Element.focus('#{options[:focus]}'); " : "this.blur(); ")
47 47 onclick << "return false;"
48 48 link_to(name, "#", :onclick => onclick)
49 49 end
50 50
51 51 def show_and_goto_link(name, id, options={})
52 52 onclick = "Element.show('#{id}'); "
53 53 onclick << (options[:focus] ? "Form.Element.focus('#{options[:focus]}'); " : "this.blur(); ")
54 54 onclick << "location.href='##{id}-anchor'; "
55 55 onclick << "return false;"
56 56 link_to(name, "#", options.merge(:onclick => onclick))
57 57 end
58 58
59 59 def image_to_function(name, function, html_options = {})
60 60 html_options.symbolize_keys!
61 61 tag(:input, html_options.merge({
62 62 :type => "image", :src => image_path(name),
63 63 :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};"
64 64 }))
65 65 end
66 66
67 67 def prompt_to_remote(name, text, param, url, html_options = {})
68 68 html_options[:onclick] = "promptToRemote('#{text}', '#{param}', '#{url_for(url)}'); return false;"
69 69 link_to name, {}, html_options
70 70 end
71 71
72 72 def format_date(date)
73 73 return nil unless date
74 74 # "Setting.date_format.size < 2" is a temporary fix (content of date_format setting changed)
75 75 @date_format ||= (Setting.date_format.blank? || Setting.date_format.size < 2 ? l(:general_fmt_date) : Setting.date_format)
76 76 date.strftime(@date_format)
77 77 end
78 78
79 79 def format_time(time, include_date = true)
80 80 return nil unless time
81 81 time = time.to_time if time.is_a?(String)
82 82 @date_format ||= (Setting.date_format.blank? || Setting.date_format.size < 2 ? l(:general_fmt_date) : Setting.date_format)
83 83 @time_format ||= (Setting.time_format.blank? ? l(:general_fmt_time) : Setting.time_format)
84 84 include_date ? time.strftime("#{@date_format} #{@time_format}") : time.strftime(@time_format)
85 85 end
86 86
87 87 def authoring(created, author)
88 88 time_tag = content_tag('acronym', distance_of_time_in_words(Time.now, created), :title => format_time(created))
89 89 l(:label_added_time_by, author.name, time_tag)
90 90 end
91 91
92 92 def day_name(day)
93 93 l(:general_day_names).split(',')[day-1]
94 94 end
95 95
96 96 def month_name(month)
97 97 l(:actionview_datehelper_select_month_names).split(',')[month-1]
98 98 end
99 99
100 100 def pagination_links_full(paginator, options={}, html_options={})
101 101 page_param = options.delete(:page_param) || :page
102 102
103 103 html = ''
104 104 html << link_to_remote(('&#171; ' + l(:label_previous)),
105 105 {:update => "content", :url => options.merge(page_param => paginator.current.previous)},
106 106 {:href => url_for(:params => options.merge(page_param => paginator.current.previous))}) + ' ' if paginator.current.previous
107 107
108 108 html << (pagination_links_each(paginator, options) do |n|
109 109 link_to_remote(n.to_s,
110 110 {:url => {:params => options.merge(page_param => n)}, :update => 'content'},
111 111 {:href => url_for(:params => options.merge(page_param => n))})
112 112 end || '')
113 113
114 114 html << ' ' + link_to_remote((l(:label_next) + ' &#187;'),
115 115 {:update => "content", :url => options.merge(page_param => paginator.current.next)},
116 116 {:href => url_for(:params => options.merge(page_param => paginator.current.next))}) if paginator.current.next
117 117 html
118 118 end
119 119
120 120 def set_html_title(text)
121 121 @html_header_title = text
122 122 end
123 123
124 124 def html_title
125 125 title = []
126 126 title << @project.name if @project
127 127 title << @html_header_title
128 128 title << Setting.app_title
129 129 title.compact.join(' - ')
130 130 end
131 131
132 132 ACCESSKEYS = {:edit => 'e',
133 133 :preview => 'r',
134 134 :quick_search => 'f',
135 135 :search => '4',
136 136 }.freeze unless const_defined?(:ACCESSKEYS)
137 137
138 138 def accesskey(s)
139 139 ACCESSKEYS[s]
140 140 end
141 141
142 142 # Formats text according to system settings.
143 143 # 2 ways to call this method:
144 144 # * with a String: textilizable(text, options)
145 145 # * with an object and one of its attribute: textilizable(issue, :description, options)
146 146 def textilizable(*args)
147 147 options = args.last.is_a?(Hash) ? args.pop : {}
148 148 case args.size
149 149 when 1
150 150 obj = nil
151 151 text = args.shift || ''
152 152 when 2
153 153 obj = args.shift
154 154 text = obj.send(args.shift)
155 155 else
156 156 raise ArgumentError, 'invalid arguments to textilizable'
157 157 end
158 158
159 159 # when using an image link, try to use an attachment, if possible
160 160 attachments = options[:attachments]
161 161 if attachments
162 162 text = text.gsub(/!([<>=]*)(\S+\.(gif|jpg|jpeg|png))!/) do |m|
163 163 align = $1
164 164 filename = $2
165 165 rf = Regexp.new(filename, Regexp::IGNORECASE)
166 166 # search for the picture in attachments
167 167 if found = attachments.detect { |att| att.filename =~ rf }
168 168 image_url = url_for :controller => 'attachments', :action => 'download', :id => found.id
169 169 "!#{align}#{image_url}!"
170 170 else
171 171 "!#{align}#{filename}!"
172 172 end
173 173 end
174 174 end
175 175
176 176 text = (Setting.text_formatting == 'textile') ?
177 177 Redmine::WikiFormatting.to_html(text) { |macro, args| exec_macro(macro, obj, args) } :
178 178 simple_format(auto_link(h(text)))
179 179
180 180 # different methods for formatting wiki links
181 181 case options[:wiki_links]
182 182 when :local
183 183 # used for local links to html files
184 184 format_wiki_link = Proc.new {|project, title| "#{title}.html" }
185 185 when :anchor
186 186 # used for single-file wiki export
187 187 format_wiki_link = Proc.new {|project, title| "##{title}" }
188 188 else
189 189 format_wiki_link = Proc.new {|project, title| url_for :controller => 'wiki', :action => 'index', :id => project, :page => title }
190 190 end
191 191
192 192 project = options[:project] || @project
193 193
194 194 # turn wiki links into html links
195 195 # example:
196 196 # [[mypage]]
197 197 # [[mypage|mytext]]
198 198 # wiki links can refer other project wikis, using project name or identifier:
199 199 # [[project:]] -> wiki starting page
200 200 # [[project:|mytext]]
201 201 # [[project:mypage]]
202 202 # [[project:mypage|mytext]]
203 203 text = text.gsub(/\[\[([^\]\|]+)(\|([^\]\|]+))?\]\]/) do |m|
204 204 link_project = project
205 205 page = $1
206 206 title = $3
207 207 if page =~ /^([^\:]+)\:(.*)$/
208 208 link_project = Project.find_by_name($1) || Project.find_by_identifier($1)
209 209 page = title || $2
210 210 title = $1 if page.blank?
211 211 end
212 212
213 213 if link_project && link_project.wiki
214 214 # check if page exists
215 215 wiki_page = link_project.wiki.find_page(page)
216 216 link_to((title || page), format_wiki_link.call(link_project, Wiki.titleize(page)),
217 217 :class => ('wiki-page' + (wiki_page ? '' : ' new')))
218 218 else
219 219 # project or wiki doesn't exist
220 220 title || page
221 221 end
222 222 end
223 223
224 224 # turn issue and revision ids into links
225 225 # example:
226 226 # #52 -> <a href="/issues/show/52">#52</a>
227 227 # r52 -> <a href="/repositories/revision/6?rev=52">r52</a> (project.id is 6)
228 228 text = text.gsub(%r{([\s,-^])(#|r)(\d+)(?=[[:punct:]]|\s|<|$)}) do |m|
229 229 leading, otype, oid = $1, $2, $3
230 230 link = nil
231 231 if otype == 'r'
232 232 if project && (changeset = project.changesets.find_by_revision(oid))
233 233 link = link_to("r#{oid}", {:controller => 'repositories', :action => 'revision', :id => project.id, :rev => oid}, :class => 'changeset',
234 234 :title => truncate(changeset.comments, 100))
235 235 end
236 236 else
237 237 if issue = Issue.find_by_id(oid.to_i, :include => [:project, :status], :conditions => Project.visible_by(User.current))
238 238 link = link_to("##{oid}", {:controller => 'issues', :action => 'show', :id => oid}, :class => 'issue',
239 239 :title => "#{truncate(issue.subject, 100)} (#{issue.status.name})")
240 240 link = content_tag('del', link) if issue.closed?
241 241 end
242 242 end
243 243 leading + (link || "#{otype}#{oid}")
244 244 end
245 245
246 246 text
247 247 end
248 248
249 249 # Same as Rails' simple_format helper without using paragraphs
250 250 def simple_format_without_paragraph(text)
251 251 text.to_s.
252 252 gsub(/\r\n?/, "\n"). # \r\n and \r -> \n
253 253 gsub(/\n\n+/, "<br /><br />"). # 2+ newline -> 2 br
254 254 gsub(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br
255 255 end
256 256
257 257 def error_messages_for(object_name, options = {})
258 258 options = options.symbolize_keys
259 259 object = instance_variable_get("@#{object_name}")
260 260 if object && !object.errors.empty?
261 261 # build full_messages here with controller current language
262 262 full_messages = []
263 263 object.errors.each do |attr, msg|
264 264 next if msg.nil?
265 265 msg = msg.first if msg.is_a? Array
266 266 if attr == "base"
267 267 full_messages << l(msg)
268 268 else
269 269 full_messages << "&#171; " + (l_has_string?("field_" + attr) ? l("field_" + attr) : object.class.human_attribute_name(attr)) + " &#187; " + l(msg) unless attr == "custom_values"
270 270 end
271 271 end
272 272 # retrieve custom values error messages
273 273 if object.errors[:custom_values]
274 274 object.custom_values.each do |v|
275 275 v.errors.each do |attr, msg|
276 276 next if msg.nil?
277 277 msg = msg.first if msg.is_a? Array
278 278 full_messages << "&#171; " + v.custom_field.name + " &#187; " + l(msg)
279 279 end
280 280 end
281 281 end
282 282 content_tag("div",
283 283 content_tag(
284 284 options[:header_tag] || "span", lwr(:gui_validation_error, full_messages.length) + ":"
285 285 ) +
286 286 content_tag("ul", full_messages.collect { |msg| content_tag("li", msg) }),
287 287 "id" => options[:id] || "errorExplanation", "class" => options[:class] || "errorExplanation"
288 288 )
289 289 else
290 290 ""
291 291 end
292 292 end
293 293
294 294 def lang_options_for_select(blank=true)
295 295 (blank ? [["(auto)", ""]] : []) +
296 296 GLoc.valid_languages.collect{|lang| [ ll(lang.to_s, :general_lang_name), lang.to_s]}.sort{|x,y| x.first <=> y.first }
297 297 end
298 298
299 299 def label_tag_for(name, option_tags = nil, options = {})
300 300 label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "")
301 301 content_tag("label", label_text)
302 302 end
303 303
304 304 def labelled_tabular_form_for(name, object, options, &proc)
305 305 options[:html] ||= {}
306 306 options[:html].store :class, "tabular"
307 307 form_for(name, object, options.merge({ :builder => TabularFormBuilder, :lang => current_language}), &proc)
308 308 end
309 309
310 310 def check_all_links(form_name)
311 311 link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") +
312 312 " | " +
313 313 link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)")
314 314 end
315 315
316 def progress_bar(pct, options={})
317 width = options[:width] || '100px;'
318 legend = options[:legend] || ''
319 content_tag('table',
320 content_tag('tr',
321 (pct > 0 ? content_tag('td', '', :width => "#{pct.floor}%;", :class => 'closed') : '') +
322 (pct < 100 ? content_tag('td', '', :width => "#{100-pct.floor}%;", :class => 'open') : '')
323 ), :class => 'progress', :style => "width: #{width};") +
324 content_tag('p', legend, :class => 'pourcent')
325 end
326
316 327 def context_menu_link(name, url, options={})
317 328 options[:class] ||= ''
318 329 if options.delete(:selected)
319 330 options[:class] << ' icon-checked disabled'
320 331 options[:disabled] = true
321 332 end
322 333 if options.delete(:disabled)
323 334 options.delete(:method)
324 335 options.delete(:confirm)
325 336 options.delete(:onclick)
326 337 options[:class] << ' disabled'
327 338 url = '#'
328 339 end
329 340 link_to name, url, options
330 341 end
331 342
332 343 def calendar_for(field_id)
333 344 image_tag("calendar.png", {:id => "#{field_id}_trigger",:class => "calendar-trigger"}) +
334 345 javascript_tag("Calendar.setup({inputField : '#{field_id}', ifFormat : '%Y-%m-%d', button : '#{field_id}_trigger' });")
335 346 end
336 347
337 348 def wikitoolbar_for(field_id)
338 349 return '' unless Setting.text_formatting == 'textile'
339 350 javascript_include_tag('jstoolbar') + javascript_tag("var toolbar = new jsToolBar($('#{field_id}')); toolbar.draw();")
340 351 end
341 352
342 353 def content_for(name, content = nil, &block)
343 354 @has_content ||= {}
344 355 @has_content[name] = true
345 356 super(name, content, &block)
346 357 end
347 358
348 359 def has_content?(name)
349 360 (@has_content && @has_content[name]) || false
350 361 end
351 362 end
352 363
353 364 class TabularFormBuilder < ActionView::Helpers::FormBuilder
354 365 include GLoc
355 366
356 367 def initialize(object_name, object, template, options, proc)
357 368 set_language_if_valid options.delete(:lang)
358 369 @object_name, @object, @template, @options, @proc = object_name, object, template, options, proc
359 370 end
360 371
361 372 (field_helpers - %w(radio_button hidden_field) + %w(date_select)).each do |selector|
362 373 src = <<-END_SRC
363 374 def #{selector}(field, options = {})
364 375 return super if options.delete :no_label
365 376 label_text = l(options[:label]) if options[:label]
366 377 label_text ||= l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym)
367 378 label_text << @template.content_tag("span", " *", :class => "required") if options.delete(:required)
368 379 label = @template.content_tag("label", label_text,
369 380 :class => (@object && @object.errors[field] ? "error" : nil),
370 381 :for => (@object_name.to_s + "_" + field.to_s))
371 382 label + super
372 383 end
373 384 END_SRC
374 385 class_eval src, __FILE__, __LINE__
375 386 end
376 387
377 388 def select(field, choices, options = {}, html_options = {})
378 389 label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "")
379 390 label = @template.content_tag("label", label_text,
380 391 :class => (@object && @object.errors[field] ? "error" : nil),
381 392 :for => (@object_name.to_s + "_" + field.to_s))
382 393 label + super
383 394 end
384 395
385 396 end
386 397
@@ -1,46 +1,51
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 module QueriesHelper
19 19
20 20 def operators_for_select(filter_type)
21 21 Query.operators_by_filter_type[filter_type].collect {|o| [l(Query.operators[o]), o]}
22 22 end
23 23
24 24 def column_header(column)
25 25 column.sortable ? sort_header_tag(column.sortable, :caption => column.caption) : content_tag('th', column.caption)
26 26 end
27 27
28 28 def column_content(column, issue)
29 29 if column.is_a?(QueryCustomFieldColumn)
30 30 cv = issue.custom_values.detect {|v| v.custom_field_id == column.custom_field.id}
31 31 show_value(cv)
32 32 else
33 33 value = issue.send(column.name)
34 34 if value.is_a?(Date)
35 35 format_date(value)
36 36 elsif value.is_a?(Time)
37 37 format_time(value)
38 elsif column.name == :subject
38 else
39 case column.name
40 when :subject
39 41 ((@project.nil? || @project != issue.project) ? "#{issue.project.name} - " : '') +
40 42 link_to(h(value), :controller => 'issues', :action => 'show', :id => issue)
41 else
42 h(value)
43 when :done_ratio
44 progress_bar(value, :width => '80px')
45 else
46 h(value)
47 end
43 48 end
44 49 end
45 50 end
46 51 end
@@ -1,78 +1,88
1 1 # redMine - project management software
2 2 # Copyright (C) 2006 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class Version < ActiveRecord::Base
19 19 before_destroy :check_integrity
20 20 belongs_to :project
21 21 has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id'
22 22 has_many :attachments, :as => :container, :dependent => :destroy
23 23
24 24 validates_presence_of :name
25 25 validates_uniqueness_of :name, :scope => [:project_id]
26 26 validates_length_of :name, :maximum => 30
27 27 validates_format_of :effective_date, :with => /^\d{4}-\d{2}-\d{2}$/, :message => :activerecord_error_not_a_date, :allow_nil => true
28 28
29 29 def start_date
30 30 effective_date
31 31 end
32 32
33 33 def due_date
34 34 effective_date
35 35 end
36 36
37 37 # Returns true if the version is completed: due date reached and no open issues
38 38 def completed?
39 39 effective_date && (effective_date <= Date.today) && (open_issues_count == 0)
40 40 end
41 41
42 def completed_pourcent
43 if fixed_issues.count == 0
44 0
45 elsif open_issues_count == 0
46 100
47 else
48 (closed_issues_count * 100 + Issue.sum('done_ratio', :include => 'status', :conditions => ["fixed_version_id = ? AND is_closed = ?", id, false]).to_f) / fixed_issues.count
49 end
50 end
51
42 52 # Returns true if the version is overdue: due date reached and some open issues
43 53 def overdue?
44 54 effective_date && (effective_date < Date.today) && (open_issues_count > 0)
45 55 end
46 56
47 57 def open_issues_count
48 58 @open_issues_count ||= Issue.count(:all, :conditions => ["fixed_version_id = ? AND is_closed = ?", self.id, false], :include => :status)
49 59 end
50 60
51 61 def closed_issues_count
52 62 @closed_issues_count ||= Issue.count(:all, :conditions => ["fixed_version_id = ? AND is_closed = ?", self.id, true], :include => :status)
53 63 end
54 64
55 65 def wiki_page
56 66 if project.wiki && !wiki_page_title.blank?
57 67 @wiki_page ||= project.wiki.find_page(wiki_page_title)
58 68 end
59 69 @wiki_page
60 70 end
61 71
62 72 def to_s; name end
63 73
64 74 # Versions are sorted by effective_date
65 75 # Those with no effective_date are at the end, sorted by name
66 76 def <=>(version)
67 77 if self.effective_date
68 78 version.effective_date ? (self.effective_date <=> version.effective_date) : -1
69 79 else
70 80 version.effective_date ? 1 : (self.name <=> version.name)
71 81 end
72 82 end
73 83
74 84 private
75 85 def check_integrity
76 86 raise "Can't delete version" if self.fixed_issues.find(:first)
77 87 end
78 88 end
@@ -1,123 +1,123
1 1 <div class="contextual">
2 2 <%= show_and_goto_link(l(:label_add_note), 'add-note', :class => 'icon icon-note') if authorize_for('issues', 'add_note') %>
3 3 <%= link_to_if_authorized l(:button_edit), {:controller => 'issues', :action => 'edit', :id => @issue}, :class => 'icon icon-edit', :accesskey => accesskey(:edit) %>
4 4 <%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'edit', :issue_id => @issue}, :class => 'icon icon-time' %>
5 5 <%= watcher_tag(@issue, User.current) %>
6 6 <%= link_to_if_authorized l(:button_copy), {:controller => 'projects', :action => 'add_issue', :id => @project, :copy_from => @issue }, :class => 'icon icon-copy' %>
7 7 <%= link_to_if_authorized l(:button_move), {:controller => 'projects', :action => 'move_issues', :id => @project, "issue_ids[]" => @issue.id }, :class => 'icon icon-move' %>
8 8 <%= link_to_if_authorized l(:button_delete), {:controller => 'issues', :action => 'destroy', :id => @issue}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %>
9 9 </div>
10 10
11 11 <h2><%= @issue.tracker.name %> #<%= @issue.id %></h2>
12 12
13 13 <div class="issue">
14 14 <h3><%=h @issue.subject %></h3>
15 15 <p class="author">
16 16 <%= authoring @issue.created_on, @issue.author %>.
17 17 <%= l(:label_updated_time, distance_of_time_in_words(Time.now, @issue.updated_on)) if @issue.created_on != @issue.updated_on %>.
18 18 </p>
19 19
20 20 <table width="100%">
21 21 <tr>
22 22 <td style="width:15%"><b><%=l(:field_status)%> :</b></td><td style="width:35%"><%= @issue.status.name %></td>
23 23 <td style="width:15%"><b><%=l(:field_start_date)%> :</b></td><td style="width:35%"><%= format_date(@issue.start_date) %></td>
24 24 </tr>
25 25 <tr>
26 26 <td><b><%=l(:field_priority)%> :</b></td><td><%= @issue.priority.name %></td>
27 27 <td><b><%=l(:field_due_date)%> :</b></td><td><%= format_date(@issue.due_date) %></td>
28 28 </tr>
29 29 <tr>
30 30 <td><b><%=l(:field_assigned_to)%> :</b></td><td><%= @issue.assigned_to ? link_to_user(@issue.assigned_to) : "-" %></td>
31 <td><b><%=l(:field_done_ratio)%> :</b></td><td><%= @issue.done_ratio %> %</td>
31 <td><b><%=l(:field_done_ratio)%> :</b></td><td><%= progress_bar @issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%" %></td>
32 32 </tr>
33 33 <tr>
34 34 <td><b><%=l(:field_category)%> :</b></td><td><%=h @issue.category ? @issue.category.name : "-" %></td>
35 35 <% if User.current.allowed_to?(:view_time_entries, @project) %>
36 36 <td><b><%=l(:label_spent_time)%> :</b></td>
37 37 <td><%= @issue.spent_hours > 0 ? (link_to lwr(:label_f_hour, @issue.spent_hours), {:controller => 'timelog', :action => 'details', :issue_id => @issue}, :class => 'icon icon-time') : "-" %></td>
38 38 <% end %>
39 39 </tr>
40 40 <tr>
41 41 <td><b><%=l(:field_fixed_version)%> :</b></td><td><%= @issue.fixed_version ? link_to_version(@issue.fixed_version) : "-" %></td>
42 42 <% if @issue.estimated_hours %>
43 43 <td><b><%=l(:field_estimated_hours)%> :</b></td><td><%= lwr(:label_f_hour, @issue.estimated_hours) %></td>
44 44 <% end %>
45 45 </tr>
46 46 <tr>
47 47 <% n = 0
48 48 for custom_value in @custom_values %>
49 49 <td valign="top"><b><%= custom_value.custom_field.name %> :</b></td><td valign="top"><%= simple_format(h(show_value(custom_value))) %></td>
50 50 <% n = n + 1
51 51 if (n > 1)
52 52 n = 0 %>
53 53 </tr><tr>
54 54 <%end
55 55 end %>
56 56 </tr>
57 57 </table>
58 58 <hr />
59 59
60 60 <% if @issue.changesets.any? %>
61 61 <div style="float:right;">
62 62 <em><%= l(:label_revision_plural) %>: <%= @issue.changesets.collect{|changeset| link_to(changeset.revision, :controller => 'repositories', :action => 'revision', :id => @project, :rev => changeset.revision)}.join(", ") %></em>
63 63 </div>
64 64 <% end %>
65 65
66 66 <p><strong><%=l(:field_description)%></strong></p>
67 67 <%= textilizable @issue, :description, :attachments => @issue.attachments %>
68 68
69 69 <% if @issue.attachments.any? %>
70 70 <%= link_to_attachments @issue.attachments, :delete_url => (authorize_for('issues', 'destroy_attachment') ? {:controller => 'issues', :action => 'destroy_attachment', :id => @issue} : nil) %>
71 71 <% end %>
72 72
73 73 <% if authorize_for('issue_relations', 'new') || @issue.relations.any? %>
74 74 <hr />
75 75 <div id="relations">
76 76 <%= render :partial => 'relations' %>
77 77 </div>
78 78 <% end %>
79 79
80 80 </div>
81 81
82 82 <% if authorize_for('issues', 'change_status') and @status_options and !@status_options.empty? %>
83 83 <% form_tag({:controller => 'issues', :action => 'change_status', :id => @issue}) do %>
84 84 <p><%=l(:label_change_status)%> :
85 85 <select name="new_status_id">
86 86 <%= options_from_collection_for_select @status_options, "id", "name" %>
87 87 </select>
88 88 <%= submit_tag l(:button_change) %></p>
89 89 <% end %>
90 90 <% end %>
91 91
92 92 <% if @journals.any? %>
93 93 <div id="history">
94 94 <h3><%=l(:label_history)%></h3>
95 95 <%= render :partial => 'history', :locals => { :journals => @journals } %>
96 96 </div>
97 97 <% end %>
98 98
99 99 <% if authorize_for('issues', 'add_note') %>
100 100 <a name="add-note-anchor"></a>
101 101 <div id="add-note" class="box" style="display:none;">
102 102 <h3><%= l(:label_add_note) %></h3>
103 103 <% form_tag({:controller => 'issues', :action => 'add_note', :id => @issue}, :class => "tabular", :multipart => true) do %>
104 104 <p><label for="notes"><%=l(:field_notes)%></label>
105 105 <%= text_area_tag 'notes', '', :cols => 60, :rows => 10, :class => 'wiki-edit' %></p>
106 106 <%= wikitoolbar_for 'notes' %>
107 107 <%= render :partial => 'attachments/form' %>
108 108 <%= submit_tag l(:button_add) %>
109 109 <%= toggle_link l(:button_cancel), 'add-note' %>
110 110 <% end %>
111 111 </div>
112 112 <% end %>
113 113
114 114 <div class="contextual">
115 115 <%= l(:label_export_to) %><%= link_to 'PDF', {:format => 'pdf'}, :class => 'icon icon-pdf' %>
116 116 </div>
117 117 &nbsp;
118 118
119 119 <% set_html_title "#{@issue.tracker.name} ##{@issue.id}: #{@issue.subject}" %>
120 120
121 121 <% content_for :sidebar do %>
122 122 <%= render :partial => 'issues/sidebar' %>
123 123 <% end %>
@@ -1,73 +1,68
1 1 <h2><%=l(:label_roadmap)%></h2>
2 2
3 3 <% if @versions.empty? %>
4 4 <p class="nodata"><%= l(:label_no_data) %></p>
5 5 <% end %>
6 6
7 7 <% @versions.each do |version| %>
8 8 <a name="<%= version.name %>"><h3 class="icon22 icon22-package"><%= version.name %></h3></a>
9 9 <% if version.completed? %>
10 10 <p><%= format_date(version.effective_date) %></p>
11 11 <% elsif version.overdue? %>
12 12 <p><strong><%= l(:label_roadmap_overdue, distance_of_time_in_words(Time.now, version.effective_date)) %> (<%= format_date(version.effective_date) %>)</strong></p>
13 13 <% elsif version.effective_date %>
14 14 <p><strong><%=l(:label_roadmap_due_in)%> <%= distance_of_time_in_words Time.now, version.effective_date %> (<%= format_date(version.effective_date) %>)</strong></p>
15 15 <% end %>
16 16 <p><%=h version.description %></p>
17 <% issues = version.fixed_issues.find(:all,
18 :include => [:status, :tracker],
19 :conditions => ["tracker_id in (#{@selected_tracker_ids.join(',')})"],
20 :order => "#{Tracker.table_name}.position") unless @selected_tracker_ids.empty?
21 issues ||= []
22
23 total = issues.size
24 complete = issues.inject(0) {|c,i| i.status.is_closed? ? c + 1 : c }
25 percentComplete = total == 0 ? 100 : (100.0 / total * complete).floor
26 percentIncomplete = 100 - percentComplete
27 %>
28 <table class="progress">
29 <tr>
30 <% if percentComplete > 0 %>
31 <td class="closed" style="width: <%= percentComplete %>%"></td>
32 <% end; if percentIncomplete > 0 %>
33 <td class="open" style="width: <%= percentIncomplete %>%"></td>
34 <% end %>
35 </tr>
36 </table>
37 <em><%= link_to(complete, :controller => 'issues', :action => 'index', :project_id => @project, :status_id => 'c', :fixed_version_id => version, :set_filter => 1) %> <%= lwr(:label_closed_issues, complete) %> (<%= percentComplete %>%) &#160;
38 <%= link_to((total - complete), :controller => 'issues', :action => 'index', :project_id => @project, :status_id => 'o', :fixed_version_id => version, :set_filter => 1) %> <%= lwr(:label_open_issues, total - complete)%> (<%= percentIncomplete %>%)</em>
39 <br />
40 <br />
41 <%= render(:partial => "wiki/content", :locals => {:content => version.wiki_page.content}) if version.wiki_page %>
42 <ul>
43 <% if total == 0 %>
44 <li><%=l(:label_roadmap_no_issues)%></li>
45 <% else %>
46 <% issues.each do |issue| %>
47 <li>
48 <%= link = link_to_issue(issue)
49 issue.status.is_closed? ? content_tag("del", link) : link %>: <%=h issue.subject %>
50 <%= content_tag "em", "(#{l(:label_closed_issues)})" if issue.status.is_closed? %>
51 </li>
52 <% end %>
53 <% end %>
54 </ul>
17
18 <% if version.fixed_issues.count > 0 %>
19 <%= progress_bar(version.completed_pourcent, :width => '40em', :legend => ('%0.0f%' % version.completed_pourcent)) %>
20 <p class="progress-info">
21 <%= link_to(version.closed_issues_count, :controller => 'issues', :action => 'index', :project_id => @project, :status_id => 'c', :fixed_version_id => version, :set_filter => 1) %>
22 <%= lwr(:label_closed_issues, version.closed_issues_count) %>
23 (<%= '%0.0f' % (version.closed_issues_count.to_f / version.fixed_issues.count * 100) %>%)
24 &#160;
25 <%= link_to(version.open_issues_count, :controller => 'issues', :action => 'index', :project_id => @project, :status_id => 'o', :fixed_version_id => version, :set_filter => 1) %>
26 <%= lwr(:label_open_issues, version.open_issues_count)%>
27 (<%= '%0.0f' % (version.open_issues_count.to_f / version.fixed_issues.count * 100) %>%)
28 </p>
29 <%= render(:partial => "wiki/content", :locals => {:content => version.wiki_page.content}) if version.wiki_page %>
30 <% issues = version.fixed_issues.find(:all,
31 :include => [:status, :tracker],
32 :conditions => ["tracker_id in (#{@selected_tracker_ids.join(',')})"],
33 :order => "#{Tracker.table_name}.position") unless @selected_tracker_ids.empty?
34 issues ||= []
35 %>
36 <ul>
37 <% if issues.size > 0 %>
38 <% issues.each do |issue| %>
39 <li>
40 <%= link = link_to_issue(issue)
41 issue.status.is_closed? ? content_tag("del", link) : link %>: <%=h issue.subject %>
42 <%= content_tag "em", "(#{l(:label_closed_issues)})" if issue.status.is_closed? %>
43 </li>
44 <% end %>
45 <% end %>
46 </ul>
47 <% else %>
48 <p><em><%= l(:label_roadmap_no_issues) %></em></p>
49 <% end %>
55 50 <% end %>
56 51
57 52 <% content_for :sidebar do %>
58 53 <% form_tag do %>
59 54 <h3><%= l(:label_roadmap) %></h3>
60 55 <% @trackers.each do |tracker| %>
61 56 <label><%= check_box_tag "tracker_ids[]", tracker.id, (@selected_tracker_ids.include? tracker.id.to_s) %>
62 57 <%= tracker.name %></label><br />
63 58 <% end %>
64 59 <br />
65 60 <label for="completed"><%= check_box_tag "completed", 1, params[:completed] %> <%= l(:label_show_completed_versions) %>
66 61 <p><%= submit_tag l(:button_apply), :class => 'button-small' %></p>
67 62 <% end %>
68 63
69 64 <h3><%= l(:label_version_plural) %></h3>
70 65 <% @versions.each do |version| %>
71 66 <%= link_to version.name, :anchor => version.name %><br />
72 67 <% end %>
73 68 <% end %>
@@ -1,479 +1,482
1 1 body { font-family: Verdana, sans-serif; font-size: 12px; color:#484848; margin: 0; padding: 0; min-width: 900px; }
2 2
3 3 h1, h2, h3, h4 { font-family: "Trebuchet MS", Verdana, sans-serif;}
4 4 h1 {margin:0; padding:0; font-size: 24px;}
5 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 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 7 h4, .wiki h3 {font-size: 12px;padding: 2px 10px 1px 0px;margin-bottom: 5px; border-bottom: 1px dotted #bbbbbb; color: #444;}
8 8
9 9 /***** Layout *****/
10 10 #top-menu {background: #2C4056;color: #fff;height:1.5em; padding: 2px 6px 0px 6px;}
11 11 #top-menu a {color: #fff; padding-right: 4px;}
12 12 #account {float:right;}
13 13
14 14 #header {height:5.3em;margin:0;background-color:#507AAA;color:#f8f8f8; padding: 4px 8px 0px 6px; position:relative;}
15 15 #header a {color:#f8f8f8;}
16 16 #quick-search {float:right;}
17 17
18 18 #main-menu {position: absolute; bottom: 0px; left:6px;}
19 19 #main-menu ul {margin: 0; padding: 0;}
20 20 #main-menu li {
21 21 float:left;
22 22 list-style-type:none;
23 23 margin: 0px 10px 0px 0px;
24 24 padding: 0px 0px 0px 0px;
25 25 white-space:nowrap;
26 26 }
27 27 #main-menu li a {
28 28 display: block;
29 29 color: #fff;
30 30 text-decoration: none;
31 31 margin: 0;
32 32 padding: 4px 4px 4px 4px;
33 33 background: #2C4056;
34 34 }
35 35 #main-menu li a:hover {background:#759FCF;}
36 36
37 37 #main {background: url(../images/mainbg.png) repeat-x; background-color:#EEEEEE;}
38 38
39 39 #sidebar{ float: right; width: 17%; position: relative; z-index: 9; min-height: 600px; padding: 0; margin: 0;}
40 40 * html #sidebar{ width: 17%; }
41 41 #sidebar h3{ font-size: 14px; margin-top:14px; color: #666; }
42 42 #sidebar hr{ width: 100%; margin: 0 auto; height: 1px; background: #ccc; border: 0; }
43 43 * html #sidebar hr{ width: 95%; position: relative; left: -6px; color: #ccc; }
44 44
45 45 #content { width: 80%; background: url(../images/contentbg.png) repeat-x; background-color: #fff; margin: 0px; border-right: 1px solid #ddd; padding: 6px 10px 10px 10px; z-index: 10; height:600px; min-height: 600px;}
46 46 * html #content{ width: 80%; padding-left: 0; margin-top: 0px; padding: 6px 10px 10px 10px;}
47 47 html>body #content {
48 48 height: auto;
49 49 min-height: 600px;
50 50 }
51 51
52 52 #main.nosidebar #sidebar{ display: none; }
53 53 #main.nosidebar #content{ width: auto; border-right: 0; }
54 54
55 55 #footer {clear: both; border-top: 1px solid #bbb; font-size: 0.9em; color: #aaa; padding: 5px; text-align:center; background:#fff;}
56 56
57 57 #login-form table {margin-top:5em; padding:1em; margin-left: auto; margin-right: auto; border: 2px solid #FDBF3B; background-color:#FFEBC1; }
58 58 #login-form table td {padding: 6px;}
59 59 #login-form label {font-weight: bold;}
60 60
61 61 .clear:after{ content: "."; display: block; height: 0; clear: both; visibility: hidden; }
62 62
63 63 /***** Links *****/
64 64 a, a:link, a:visited{ color: #2A5685; text-decoration: none; }
65 65 a:hover, a:active{ color: #c61a1a; text-decoration: underline;}
66 66 a img{ border: 0; }
67 67
68 68 /***** Tables *****/
69 69 table.list { border: 1px solid #e4e4e4; border-collapse: collapse; width: 100%; margin-bottom: 4px; }
70 70 table.list th { background-color:#EEEEEE; padding: 4px; white-space:nowrap; }
71 71 table.list td { overflow: hidden; text-overflow: ellipsis; vertical-align: top;}
72 72 table.list td.id { width: 2%; text-align: center;}
73 73 table.list td.checkbox { width: 15px; padding: 0px;}
74 74
75 75 tr.issue { text-align: center; white-space: nowrap; }
76 76 tr.issue td.subject, tr.issue td.category { white-space: normal; }
77 77 tr.issue td.subject { text-align: left; }
78 tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;}
78 79
79 80 table.list tbody tr:hover { background-color:#ffffdd; }
80 81 table td {padding:2px;}
81 82 table p {margin:0;}
82 83 .odd {background-color:#f6f7f8;}
83 84 .even {background-color: #fff;}
84 85
85 86 .highlight { background-color: #FCFD8D;}
86 87 .highlight.token-1 { background-color: #faa;}
87 88 .highlight.token-2 { background-color: #afa;}
88 89 .highlight.token-3 { background-color: #aaf;}
89 90
90 91 .box{
91 92 padding:6px;
92 93 margin-bottom: 10px;
93 94 background-color:#f6f6f6;
94 95 color:#505050;
95 96 line-height:1.5em;
96 97 border: 1px solid #e4e4e4;
97 98 }
98 99
99 100 div.square {
100 101 border: 1px solid #999;
101 102 float: left;
102 103 margin: .3em .4em 0 .4em;
103 104 overflow: hidden;
104 105 width: .6em; height: .6em;
105 106 }
106 107
107 108 .contextual {float:right; white-space: nowrap; line-height:1.4em;margin-top:5px;font-size:0.9em;}
108 109 .splitcontentleft{float:left; width:49%;}
109 110 .splitcontentright{float:right; width:49%;}
110 111 form {display: inline;}
111 112 input, select {vertical-align: middle; margin-top: 1px; margin-bottom: 1px;}
112 113 fieldset {border: 1px solid #e4e4e4; margin:0;}
113 114 legend {color: #484848;}
114 115 hr { width: 100%; height: 1px; background: #ccc; border: 0;}
115 116 textarea.wiki-edit { width: 99%; }
116 117 li p {margin-top: 0;}
117 118 div.issue {background:#ffffdd; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7;}
118 119 .autoscroll {overflow-x: auto; padding:1px; width:100%;}
119 120 #user_firstname, #user_lastname, #user_mail, #notification_option { width: 90%; }
120 121
121 122 /***** Tabular forms ******/
122 123 .tabular p{
123 124 margin: 0;
124 125 padding: 5px 0 8px 0;
125 126 padding-left: 180px; /*width of left column containing the label elements*/
126 127 height: 1%;
127 128 clear:left;
128 129 }
129 130
130 131 .tabular label{
131 132 font-weight: bold;
132 133 float: left;
133 134 text-align: right;
134 135 margin-left: -180px; /*width of left column*/
135 136 width: 175px; /*width of labels. Should be smaller than left column to create some right
136 137 margin*/
137 138 }
138 139
139 140 .tabular label.floating{
140 141 font-weight: normal;
141 142 margin-left: 0px;
142 143 text-align: left;
143 144 width: 200px;
144 145 }
145 146
146 147 #preview fieldset {margin-top: 1em; background: url(../images/draft.png)}
147 148
148 149 #settings .tabular p{ padding-left: 300px; }
149 150 #settings .tabular label{ margin-left: -300px; width: 295px; }
150 151
151 152 .required {color: #bb0000;}
152 153 .summary {font-style: italic;}
153 154
154 155 div.attachments p { margin:4px 0 2px 0; }
155 156
156 157 /***** Flash & error messages ****/
157 158 #errorExplanation, div.flash, .nodata {
158 159 padding: 4px 4px 4px 30px;
159 160 margin-bottom: 12px;
160 161 font-size: 1.1em;
161 162 border: 2px solid;
162 163 }
163 164
164 165 div.flash {margin-top: 8px;}
165 166
166 167 div.flash.error, #errorExplanation {
167 168 background: url(../images/false.png) 8px 5px no-repeat;
168 169 background-color: #ffe3e3;
169 170 border-color: #dd0000;
170 171 color: #550000;
171 172 }
172 173
173 174 div.flash.notice {
174 175 background: url(../images/true.png) 8px 5px no-repeat;
175 176 background-color: #dfffdf;
176 177 border-color: #9fcf9f;
177 178 color: #005f00;
178 179 }
179 180
180 181 .nodata {
181 182 text-align: center;
182 183 background-color: #FFEBC1;
183 184 border-color: #FDBF3B;
184 185 color: #A6750C;
185 186 }
186 187
187 188 #errorExplanation ul { font-size: 0.9em;}
188 189
189 190 /***** Ajax indicator ******/
190 191 #ajax-indicator {
191 192 position: absolute; /* fixed not supported by IE */
192 193 background-color:#eee;
193 194 border: 1px solid #bbb;
194 195 top:35%;
195 196 left:40%;
196 197 width:20%;
197 198 font-weight:bold;
198 199 text-align:center;
199 200 padding:0.6em;
200 201 z-index:100;
201 202 filter:alpha(opacity=50);
202 203 -moz-opacity:0.5;
203 204 opacity: 0.5;
204 205 -khtml-opacity: 0.5;
205 206 }
206 207
207 208 html>body #ajax-indicator { position: fixed; }
208 209
209 210 #ajax-indicator span {
210 211 background-position: 0% 40%;
211 212 background-repeat: no-repeat;
212 213 background-image: url(../images/loading.gif);
213 214 padding-left: 26px;
214 215 vertical-align: bottom;
215 216 }
216 217
217 218 /***** Calendar *****/
218 219 table.cal {border-collapse: collapse; width: 100%; margin: 8px 0 6px 0;border: 1px solid #d7d7d7;}
219 220 table.cal thead th {width: 14%;}
220 221 table.cal tbody tr {height: 100px;}
221 222 table.cal th { background-color:#EEEEEE; padding: 4px; }
222 223 table.cal td {border: 1px solid #d7d7d7; vertical-align: top; font-size: 0.9em;}
223 224 table.cal td p.day-num {font-size: 1.1em; text-align:right;}
224 225 table.cal td.odd p.day-num {color: #bbb;}
225 226 table.cal td.today {background:#ffffdd;}
226 227 table.cal td.today p.day-num {font-weight: bold;}
227 228
228 229 /***** Tooltips ******/
229 230 .tooltip{position:relative;z-index:24;}
230 231 .tooltip:hover{z-index:25;color:#000;}
231 232 .tooltip span.tip{display: none; text-align:left;}
232 233
233 234 div.tooltip:hover span.tip{
234 235 display:block;
235 236 position:absolute;
236 237 top:12px; left:24px; width:270px;
237 238 border:1px solid #555;
238 239 background-color:#fff;
239 240 padding: 4px;
240 241 font-size: 0.8em;
241 242 color:#505050;
242 243 }
243 244
244 245 /***** Progress bar *****/
245 .progress {
246 table.progress {
246 247 border: 1px solid #D7D7D7;
247 248 border-collapse: collapse;
248 249 border-spacing: 0pt;
249 250 empty-cells: show;
250 padding: 3px;
251 width: 40em;
252 251 text-align: center;
252 float:left;
253 margin: 1px 6px 1px 0px;
253 254 }
254 255
255 .progress td { height: 1em; }
256 .progress .closed { background: #BAE0BA none repeat scroll 0%; }
257 .progress .open { background: #FFF none repeat scroll 0%; }
256 table.progress td { height: 0.9em; }
257 table.progress td.closed { background: #BAE0BA none repeat scroll 0%; }
258 table.progress td.open { background: #FFF none repeat scroll 0%; }
259 p.pourcent {font-size: 80%;}
260 p.progress-info {clear: left; font-style: italic; font-size: 80%;}
258 261
259 262 /***** Tabs *****/
260 263 #content .tabs{height: 2.6em;}
261 264 #content .tabs ul{margin:0;}
262 265 #content .tabs ul li{
263 266 float:left;
264 267 list-style-type:none;
265 268 white-space:nowrap;
266 269 margin-right:8px;
267 270 background:#fff;
268 271 }
269 272 #content .tabs ul li a{
270 273 display:block;
271 274 font-size: 0.9em;
272 275 text-decoration:none;
273 276 line-height:1em;
274 277 padding:4px;
275 278 border: 1px solid #c0c0c0;
276 279 }
277 280
278 281 #content .tabs ul li a.selected, #content .tabs ul li a:hover{
279 282 background-color: #507AAA;
280 283 border: 1px solid #507AAA;
281 284 color: #fff;
282 285 text-decoration:none;
283 286 }
284 287
285 288 /***** Diff *****/
286 289 .diff_out { background: #fcc; }
287 290 .diff_in { background: #cfc; }
288 291
289 292 /***** Wiki *****/
290 293 div.wiki table {
291 294 border: 1px solid #505050;
292 295 border-collapse: collapse;
293 296 }
294 297
295 298 div.wiki table, div.wiki td, div.wiki th {
296 299 border: 1px solid #bbb;
297 300 padding: 4px;
298 301 }
299 302
300 303 div.wiki .external {
301 304 background-position: 0% 60%;
302 305 background-repeat: no-repeat;
303 306 padding-left: 12px;
304 307 background-image: url(../images/external.png);
305 308 }
306 309
307 310 div.wiki a.new {
308 311 color: #b73535;
309 312 }
310 313
311 314 div.wiki pre {
312 315 margin: 1em 1em 1em 1.6em;
313 316 padding: 2px;
314 317 background-color: #fafafa;
315 318 border: 1px solid #dadada;
316 319 width:95%;
317 320 overflow-x: auto;
318 321 }
319 322
320 323 div.wiki div.toc {
321 324 background-color: #ffffdd;
322 325 border: 1px solid #e4e4e4;
323 326 padding: 4px;
324 327 line-height: 1.2em;
325 328 margin-bottom: 12px;
326 329 margin-right: 12px;
327 330 display: table
328 331 }
329 332 * html div.wiki div.toc { width: 50%; } /* IE6 doesn't autosize div */
330 333
331 334 div.wiki div.toc.right { float: right; margin-left: 12px; margin-right: 0; width: auto; }
332 335 div.wiki div.toc.left { float: left; margin-right: 12px; margin-left: 0; width: auto; }
333 336
334 337 div.wiki div.toc a {
335 338 display: block;
336 339 font-size: 0.9em;
337 340 font-weight: normal;
338 341 text-decoration: none;
339 342 color: #606060;
340 343 }
341 344 div.wiki div.toc a:hover { color: #c61a1a; text-decoration: underline;}
342 345
343 346 div.wiki div.toc a.heading2 { margin-left: 6px; }
344 347 div.wiki div.toc a.heading3 { margin-left: 12px; font-size: 0.8em; }
345 348
346 349 /***** My page layout *****/
347 350 .block-receiver {
348 351 border:1px dashed #c0c0c0;
349 352 margin-bottom: 20px;
350 353 padding: 15px 0 15px 0;
351 354 }
352 355
353 356 .mypage-box {
354 357 margin:0 0 20px 0;
355 358 color:#505050;
356 359 line-height:1.5em;
357 360 }
358 361
359 362 .handle {
360 363 cursor: move;
361 364 }
362 365
363 366 a.close-icon {
364 367 display:block;
365 368 margin-top:3px;
366 369 overflow:hidden;
367 370 width:12px;
368 371 height:12px;
369 372 background-repeat: no-repeat;
370 373 cursor:pointer;
371 374 background-image:url('../images/close.png');
372 375 }
373 376
374 377 a.close-icon:hover {
375 378 background-image:url('../images/close_hl.png');
376 379 }
377 380
378 381 /***** Gantt chart *****/
379 382 .gantt_hdr {
380 383 position:absolute;
381 384 top:0;
382 385 height:16px;
383 386 border-top: 1px solid #c0c0c0;
384 387 border-bottom: 1px solid #c0c0c0;
385 388 border-right: 1px solid #c0c0c0;
386 389 text-align: center;
387 390 overflow: hidden;
388 391 }
389 392
390 393 .task {
391 394 position: absolute;
392 395 height:8px;
393 396 font-size:0.8em;
394 397 color:#888;
395 398 padding:0;
396 399 margin:0;
397 400 line-height:0.8em;
398 401 }
399 402
400 403 .task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; }
401 404 .task_done { background:#66f url(../images/task_done.png); border: 1px solid #66f; }
402 405 .task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; }
403 406 .milestone { background-image:url(../images/milestone.png); background-repeat: no-repeat; border: 0; }
404 407
405 408 /***** Icons *****/
406 409 .icon {
407 410 background-position: 0% 40%;
408 411 background-repeat: no-repeat;
409 412 padding-left: 20px;
410 413 padding-top: 2px;
411 414 padding-bottom: 3px;
412 415 }
413 416
414 417 .icon22 {
415 418 background-position: 0% 40%;
416 419 background-repeat: no-repeat;
417 420 padding-left: 26px;
418 421 line-height: 22px;
419 422 vertical-align: middle;
420 423 }
421 424
422 425 .icon-add { background-image: url(../images/add.png); }
423 426 .icon-edit { background-image: url(../images/edit.png); }
424 427 .icon-copy { background-image: url(../images/copy.png); }
425 428 .icon-del { background-image: url(../images/delete.png); }
426 429 .icon-move { background-image: url(../images/move.png); }
427 430 .icon-save { background-image: url(../images/save.png); }
428 431 .icon-cancel { background-image: url(../images/cancel.png); }
429 432 .icon-pdf { background-image: url(../images/pdf.png); }
430 433 .icon-csv { background-image: url(../images/csv.png); }
431 434 .icon-html { background-image: url(../images/html.png); }
432 435 .icon-image { background-image: url(../images/image.png); }
433 436 .icon-txt { background-image: url(../images/txt.png); }
434 437 .icon-file { background-image: url(../images/file.png); }
435 438 .icon-folder { background-image: url(../images/folder.png); }
436 439 .open .icon-folder { background-image: url(../images/folder_open.png); }
437 440 .icon-package { background-image: url(../images/package.png); }
438 441 .icon-home { background-image: url(../images/home.png); }
439 442 .icon-user { background-image: url(../images/user.png); }
440 443 .icon-mypage { background-image: url(../images/user_page.png); }
441 444 .icon-admin { background-image: url(../images/admin.png); }
442 445 .icon-projects { background-image: url(../images/projects.png); }
443 446 .icon-logout { background-image: url(../images/logout.png); }
444 447 .icon-help { background-image: url(../images/help.png); }
445 448 .icon-attachment { background-image: url(../images/attachment.png); }
446 449 .icon-index { background-image: url(../images/index.png); }
447 450 .icon-history { background-image: url(../images/history.png); }
448 451 .icon-feed { background-image: url(../images/feed.png); }
449 452 .icon-time { background-image: url(../images/time.png); }
450 453 .icon-stats { background-image: url(../images/stats.png); }
451 454 .icon-warning { background-image: url(../images/warning.png); }
452 455 .icon-fav { background-image: url(../images/fav.png); }
453 456 .icon-fav-off { background-image: url(../images/fav_off.png); }
454 457 .icon-reload { background-image: url(../images/reload.png); }
455 458 .icon-lock { background-image: url(../images/locked.png); }
456 459 .icon-unlock { background-image: url(../images/unlock.png); }
457 460 .icon-note { background-image: url(../images/note.png); }
458 461 .icon-checked { background-image: url(../images/true.png); }
459 462
460 463 .icon22-projects { background-image: url(../images/22x22/projects.png); }
461 464 .icon22-users { background-image: url(../images/22x22/users.png); }
462 465 .icon22-tracker { background-image: url(../images/22x22/tracker.png); }
463 466 .icon22-role { background-image: url(../images/22x22/role.png); }
464 467 .icon22-workflow { background-image: url(../images/22x22/workflow.png); }
465 468 .icon22-options { background-image: url(../images/22x22/options.png); }
466 469 .icon22-notifications { background-image: url(../images/22x22/notifications.png); }
467 470 .icon22-authent { background-image: url(../images/22x22/authent.png); }
468 471 .icon22-info { background-image: url(../images/22x22/info.png); }
469 472 .icon22-comment { background-image: url(../images/22x22/comment.png); }
470 473 .icon22-package { background-image: url(../images/22x22/package.png); }
471 474 .icon22-settings { background-image: url(../images/22x22/settings.png); }
472 475 .icon22-plugin { background-image: url(../images/22x22/plugin.png); }
473 476
474 477 /***** Media print specific styles *****/
475 478 @media print {
476 479 #top-menu, #header, #main-menu, #sidebar, #footer, .contextual { display:none; }
477 480 #main { background: #fff; }
478 481 #content { width: 99%; margin: 0; padding: 0; border: 0; background: #fff; }
479 482 }
@@ -1,52 +1,52
1 #context-menu { position: absolute; }
1 #context-menu { position: absolute; z-index: 10;}
2 2
3 3 #context-menu ul, #context-menu li, #context-menu a {
4 4 display:block;
5 5 margin:0;
6 6 padding:0;
7 7 border:0;
8 8 }
9 9
10 10 #context-menu ul {
11 11 width:150px;
12 12 border-top:1px solid #ddd;
13 13 border-left:1px solid #ddd;
14 14 border-bottom:1px solid #777;
15 15 border-right:1px solid #777;
16 16 background:white;
17 17 list-style:none;
18 18 }
19 19
20 20 #context-menu li {
21 21 position:relative;
22 22 padding:1px;
23 23 z-index:9;
24 24 }
25 25 #context-menu li.folder ul {
26 26 position:absolute;
27 27 left:128px; /* IE */
28 28 top:-2px;
29 29 }
30 30 #context-menu li.folder>ul { left:148px; }
31 31
32 32 #context-menu a {
33 33 border:1px solid white;
34 34 text-decoration:none;
35 35 background-repeat: no-repeat;
36 36 background-position: 1px 50%;
37 37 padding: 2px 0px 2px 20px;
38 38 width:100%; /* IE */
39 39 }
40 40 #context-menu li>a { width:auto; } /* others */
41 41 #context-menu a.disabled, #context-menu a.disabled:hover {color: #ccc;}
42 42 #context-menu li a.submenu { background:url("../images/sub.gif") right no-repeat; }
43 43 #context-menu a:hover { border-color:gray; background-color:#eee; color:#2A5685; }
44 44 #context-menu li.folder a:hover { background-color:#eee; }
45 45 #context-menu li.folder:hover { z-index:10; }
46 46 #context-menu ul ul, #context-menu li:hover ul ul { display:none; }
47 47 #context-menu li:hover ul, #context-menu li:hover li:hover ul { display:block; }
48 48
49 49 /* selected element */
50 50 .context-menu-selection { background-color:#507AAA !important; color:#f8f8f8 !important; }
51 51 .context-menu-selection a, .context-menu-selection a:hover { color:#f8f8f8 !important; }
52 52 .context-menu-selection:hover { background-color:#507AAA !important; color:#f8f8f8 !important; }
General Comments 0
You need to be logged in to leave comments. Login now