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