##// END OF EJS Templates
Always show "Jump to project" drop-down (#24833)....
Jean-Philippe Lang -
r15817:df18ece50437
parent child
Show More
@@ -1,1448 +1,1446
1 # encoding: utf-8
1 # encoding: utf-8
2 #
2 #
3 # Redmine - project management software
3 # Redmine - project management software
4 # Copyright (C) 2006-2016 Jean-Philippe Lang
4 # Copyright (C) 2006-2016 Jean-Philippe Lang
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
9 # of the License, or (at your option) any later version.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
19
20 require 'forwardable'
20 require 'forwardable'
21 require 'cgi'
21 require 'cgi'
22
22
23 module ApplicationHelper
23 module ApplicationHelper
24 include Redmine::WikiFormatting::Macros::Definitions
24 include Redmine::WikiFormatting::Macros::Definitions
25 include Redmine::I18n
25 include Redmine::I18n
26 include GravatarHelper::PublicMethods
26 include GravatarHelper::PublicMethods
27 include Redmine::Pagination::Helper
27 include Redmine::Pagination::Helper
28 include Redmine::SudoMode::Helper
28 include Redmine::SudoMode::Helper
29 include Redmine::Themes::Helper
29 include Redmine::Themes::Helper
30 include Redmine::Hook::Helper
30 include Redmine::Hook::Helper
31 include Redmine::Helpers::URL
31 include Redmine::Helpers::URL
32
32
33 extend Forwardable
33 extend Forwardable
34 def_delegators :wiki_helper, :wikitoolbar_for, :heads_for_wiki_formatter
34 def_delegators :wiki_helper, :wikitoolbar_for, :heads_for_wiki_formatter
35
35
36 # Return true if user is authorized for controller/action, otherwise false
36 # Return true if user is authorized for controller/action, otherwise false
37 def authorize_for(controller, action)
37 def authorize_for(controller, action)
38 User.current.allowed_to?({:controller => controller, :action => action}, @project)
38 User.current.allowed_to?({:controller => controller, :action => action}, @project)
39 end
39 end
40
40
41 # Display a link if user is authorized
41 # Display a link if user is authorized
42 #
42 #
43 # @param [String] name Anchor text (passed to link_to)
43 # @param [String] name Anchor text (passed to link_to)
44 # @param [Hash] options Hash params. This will checked by authorize_for to see if the user is authorized
44 # @param [Hash] options Hash params. This will checked by authorize_for to see if the user is authorized
45 # @param [optional, Hash] html_options Options passed to link_to
45 # @param [optional, Hash] html_options Options passed to link_to
46 # @param [optional, Hash] parameters_for_method_reference Extra parameters for link_to
46 # @param [optional, Hash] parameters_for_method_reference Extra parameters for link_to
47 def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference)
47 def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference)
48 link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller] || params[:controller], options[:action])
48 link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller] || params[:controller], options[:action])
49 end
49 end
50
50
51 # Displays a link to user's account page if active
51 # Displays a link to user's account page if active
52 def link_to_user(user, options={})
52 def link_to_user(user, options={})
53 if user.is_a?(User)
53 if user.is_a?(User)
54 name = h(user.name(options[:format]))
54 name = h(user.name(options[:format]))
55 if user.active? || (User.current.admin? && user.logged?)
55 if user.active? || (User.current.admin? && user.logged?)
56 link_to name, user_path(user), :class => user.css_classes
56 link_to name, user_path(user), :class => user.css_classes
57 else
57 else
58 name
58 name
59 end
59 end
60 else
60 else
61 h(user.to_s)
61 h(user.to_s)
62 end
62 end
63 end
63 end
64
64
65 # Displays a link to +issue+ with its subject.
65 # Displays a link to +issue+ with its subject.
66 # Examples:
66 # Examples:
67 #
67 #
68 # link_to_issue(issue) # => Defect #6: This is the subject
68 # link_to_issue(issue) # => Defect #6: This is the subject
69 # link_to_issue(issue, :truncate => 6) # => Defect #6: This i...
69 # link_to_issue(issue, :truncate => 6) # => Defect #6: This i...
70 # link_to_issue(issue, :subject => false) # => Defect #6
70 # link_to_issue(issue, :subject => false) # => Defect #6
71 # link_to_issue(issue, :project => true) # => Foo - Defect #6
71 # link_to_issue(issue, :project => true) # => Foo - Defect #6
72 # link_to_issue(issue, :subject => false, :tracker => false) # => #6
72 # link_to_issue(issue, :subject => false, :tracker => false) # => #6
73 #
73 #
74 def link_to_issue(issue, options={})
74 def link_to_issue(issue, options={})
75 title = nil
75 title = nil
76 subject = nil
76 subject = nil
77 text = options[:tracker] == false ? "##{issue.id}" : "#{issue.tracker} ##{issue.id}"
77 text = options[:tracker] == false ? "##{issue.id}" : "#{issue.tracker} ##{issue.id}"
78 if options[:subject] == false
78 if options[:subject] == false
79 title = issue.subject.truncate(60)
79 title = issue.subject.truncate(60)
80 else
80 else
81 subject = issue.subject
81 subject = issue.subject
82 if truncate_length = options[:truncate]
82 if truncate_length = options[:truncate]
83 subject = subject.truncate(truncate_length)
83 subject = subject.truncate(truncate_length)
84 end
84 end
85 end
85 end
86 only_path = options[:only_path].nil? ? true : options[:only_path]
86 only_path = options[:only_path].nil? ? true : options[:only_path]
87 s = link_to(text, issue_url(issue, :only_path => only_path),
87 s = link_to(text, issue_url(issue, :only_path => only_path),
88 :class => issue.css_classes, :title => title)
88 :class => issue.css_classes, :title => title)
89 s << h(": #{subject}") if subject
89 s << h(": #{subject}") if subject
90 s = h("#{issue.project} - ") + s if options[:project]
90 s = h("#{issue.project} - ") + s if options[:project]
91 s
91 s
92 end
92 end
93
93
94 # Generates a link to an attachment.
94 # Generates a link to an attachment.
95 # Options:
95 # Options:
96 # * :text - Link text (default to attachment filename)
96 # * :text - Link text (default to attachment filename)
97 # * :download - Force download (default: false)
97 # * :download - Force download (default: false)
98 def link_to_attachment(attachment, options={})
98 def link_to_attachment(attachment, options={})
99 text = options.delete(:text) || attachment.filename
99 text = options.delete(:text) || attachment.filename
100 route_method = options.delete(:download) ? :download_named_attachment_url : :named_attachment_url
100 route_method = options.delete(:download) ? :download_named_attachment_url : :named_attachment_url
101 html_options = options.slice!(:only_path)
101 html_options = options.slice!(:only_path)
102 options[:only_path] = true unless options.key?(:only_path)
102 options[:only_path] = true unless options.key?(:only_path)
103 url = send(route_method, attachment, attachment.filename, options)
103 url = send(route_method, attachment, attachment.filename, options)
104 link_to text, url, html_options
104 link_to text, url, html_options
105 end
105 end
106
106
107 # Generates a link to a SCM revision
107 # Generates a link to a SCM revision
108 # Options:
108 # Options:
109 # * :text - Link text (default to the formatted revision)
109 # * :text - Link text (default to the formatted revision)
110 def link_to_revision(revision, repository, options={})
110 def link_to_revision(revision, repository, options={})
111 if repository.is_a?(Project)
111 if repository.is_a?(Project)
112 repository = repository.repository
112 repository = repository.repository
113 end
113 end
114 text = options.delete(:text) || format_revision(revision)
114 text = options.delete(:text) || format_revision(revision)
115 rev = revision.respond_to?(:identifier) ? revision.identifier : revision
115 rev = revision.respond_to?(:identifier) ? revision.identifier : revision
116 link_to(
116 link_to(
117 h(text),
117 h(text),
118 {:controller => 'repositories', :action => 'revision', :id => repository.project, :repository_id => repository.identifier_param, :rev => rev},
118 {:controller => 'repositories', :action => 'revision', :id => repository.project, :repository_id => repository.identifier_param, :rev => rev},
119 :title => l(:label_revision_id, format_revision(revision)),
119 :title => l(:label_revision_id, format_revision(revision)),
120 :accesskey => options[:accesskey]
120 :accesskey => options[:accesskey]
121 )
121 )
122 end
122 end
123
123
124 # Generates a link to a message
124 # Generates a link to a message
125 def link_to_message(message, options={}, html_options = nil)
125 def link_to_message(message, options={}, html_options = nil)
126 link_to(
126 link_to(
127 message.subject.truncate(60),
127 message.subject.truncate(60),
128 board_message_url(message.board_id, message.parent_id || message.id, {
128 board_message_url(message.board_id, message.parent_id || message.id, {
129 :r => (message.parent_id && message.id),
129 :r => (message.parent_id && message.id),
130 :anchor => (message.parent_id ? "message-#{message.id}" : nil),
130 :anchor => (message.parent_id ? "message-#{message.id}" : nil),
131 :only_path => true
131 :only_path => true
132 }.merge(options)),
132 }.merge(options)),
133 html_options
133 html_options
134 )
134 )
135 end
135 end
136
136
137 # Generates a link to a project if active
137 # Generates a link to a project if active
138 # Examples:
138 # Examples:
139 #
139 #
140 # link_to_project(project) # => link to the specified project overview
140 # link_to_project(project) # => link to the specified project overview
141 # link_to_project(project, {:only_path => false}, :class => "project") # => 3rd arg adds html options
141 # link_to_project(project, {:only_path => false}, :class => "project") # => 3rd arg adds html options
142 # link_to_project(project, {}, :class => "project") # => html options with default url (project overview)
142 # link_to_project(project, {}, :class => "project") # => html options with default url (project overview)
143 #
143 #
144 def link_to_project(project, options={}, html_options = nil)
144 def link_to_project(project, options={}, html_options = nil)
145 if project.archived?
145 if project.archived?
146 h(project.name)
146 h(project.name)
147 else
147 else
148 link_to project.name,
148 link_to project.name,
149 project_url(project, {:only_path => true}.merge(options)),
149 project_url(project, {:only_path => true}.merge(options)),
150 html_options
150 html_options
151 end
151 end
152 end
152 end
153
153
154 # Generates a link to a project settings if active
154 # Generates a link to a project settings if active
155 def link_to_project_settings(project, options={}, html_options=nil)
155 def link_to_project_settings(project, options={}, html_options=nil)
156 if project.active?
156 if project.active?
157 link_to project.name, settings_project_path(project, options), html_options
157 link_to project.name, settings_project_path(project, options), html_options
158 elsif project.archived?
158 elsif project.archived?
159 h(project.name)
159 h(project.name)
160 else
160 else
161 link_to project.name, project_path(project, options), html_options
161 link_to project.name, project_path(project, options), html_options
162 end
162 end
163 end
163 end
164
164
165 # Generates a link to a version
165 # Generates a link to a version
166 def link_to_version(version, options = {})
166 def link_to_version(version, options = {})
167 return '' unless version && version.is_a?(Version)
167 return '' unless version && version.is_a?(Version)
168 options = {:title => format_date(version.effective_date)}.merge(options)
168 options = {:title => format_date(version.effective_date)}.merge(options)
169 link_to_if version.visible?, format_version_name(version), version_path(version), options
169 link_to_if version.visible?, format_version_name(version), version_path(version), options
170 end
170 end
171
171
172 # Helper that formats object for html or text rendering
172 # Helper that formats object for html or text rendering
173 def format_object(object, html=true, &block)
173 def format_object(object, html=true, &block)
174 if block_given?
174 if block_given?
175 object = yield object
175 object = yield object
176 end
176 end
177 case object.class.name
177 case object.class.name
178 when 'Array'
178 when 'Array'
179 object.map {|o| format_object(o, html)}.join(', ').html_safe
179 object.map {|o| format_object(o, html)}.join(', ').html_safe
180 when 'Time'
180 when 'Time'
181 format_time(object)
181 format_time(object)
182 when 'Date'
182 when 'Date'
183 format_date(object)
183 format_date(object)
184 when 'Fixnum'
184 when 'Fixnum'
185 object.to_s
185 object.to_s
186 when 'Float'
186 when 'Float'
187 sprintf "%.2f", object
187 sprintf "%.2f", object
188 when 'User'
188 when 'User'
189 html ? link_to_user(object) : object.to_s
189 html ? link_to_user(object) : object.to_s
190 when 'Project'
190 when 'Project'
191 html ? link_to_project(object) : object.to_s
191 html ? link_to_project(object) : object.to_s
192 when 'Version'
192 when 'Version'
193 html ? link_to_version(object) : object.to_s
193 html ? link_to_version(object) : object.to_s
194 when 'TrueClass'
194 when 'TrueClass'
195 l(:general_text_Yes)
195 l(:general_text_Yes)
196 when 'FalseClass'
196 when 'FalseClass'
197 l(:general_text_No)
197 l(:general_text_No)
198 when 'Issue'
198 when 'Issue'
199 object.visible? && html ? link_to_issue(object) : "##{object.id}"
199 object.visible? && html ? link_to_issue(object) : "##{object.id}"
200 when 'Attachment'
200 when 'Attachment'
201 html ? link_to_attachment(object, :download => true) : object.filename
201 html ? link_to_attachment(object, :download => true) : object.filename
202 when 'CustomValue', 'CustomFieldValue'
202 when 'CustomValue', 'CustomFieldValue'
203 if object.custom_field
203 if object.custom_field
204 f = object.custom_field.format.formatted_custom_value(self, object, html)
204 f = object.custom_field.format.formatted_custom_value(self, object, html)
205 if f.nil? || f.is_a?(String)
205 if f.nil? || f.is_a?(String)
206 f
206 f
207 else
207 else
208 format_object(f, html, &block)
208 format_object(f, html, &block)
209 end
209 end
210 else
210 else
211 object.value.to_s
211 object.value.to_s
212 end
212 end
213 else
213 else
214 html ? h(object) : object.to_s
214 html ? h(object) : object.to_s
215 end
215 end
216 end
216 end
217
217
218 def wiki_page_path(page, options={})
218 def wiki_page_path(page, options={})
219 url_for({:controller => 'wiki', :action => 'show', :project_id => page.project, :id => page.title}.merge(options))
219 url_for({:controller => 'wiki', :action => 'show', :project_id => page.project, :id => page.title}.merge(options))
220 end
220 end
221
221
222 def thumbnail_tag(attachment)
222 def thumbnail_tag(attachment)
223 link_to image_tag(thumbnail_path(attachment)),
223 link_to image_tag(thumbnail_path(attachment)),
224 named_attachment_path(attachment, attachment.filename),
224 named_attachment_path(attachment, attachment.filename),
225 :title => attachment.filename
225 :title => attachment.filename
226 end
226 end
227
227
228 def toggle_link(name, id, options={})
228 def toggle_link(name, id, options={})
229 onclick = "$('##{id}').toggle(); "
229 onclick = "$('##{id}').toggle(); "
230 onclick << (options[:focus] ? "$('##{options[:focus]}').focus(); " : "this.blur(); ")
230 onclick << (options[:focus] ? "$('##{options[:focus]}').focus(); " : "this.blur(); ")
231 onclick << "return false;"
231 onclick << "return false;"
232 link_to(name, "#", :onclick => onclick)
232 link_to(name, "#", :onclick => onclick)
233 end
233 end
234
234
235 # Used to format item titles on the activity view
235 # Used to format item titles on the activity view
236 def format_activity_title(text)
236 def format_activity_title(text)
237 text
237 text
238 end
238 end
239
239
240 def format_activity_day(date)
240 def format_activity_day(date)
241 date == User.current.today ? l(:label_today).titleize : format_date(date)
241 date == User.current.today ? l(:label_today).titleize : format_date(date)
242 end
242 end
243
243
244 def format_activity_description(text)
244 def format_activity_description(text)
245 h(text.to_s.truncate(120).gsub(%r{[\r\n]*<(pre|code)>.*$}m, '...')
245 h(text.to_s.truncate(120).gsub(%r{[\r\n]*<(pre|code)>.*$}m, '...')
246 ).gsub(/[\r\n]+/, "<br />").html_safe
246 ).gsub(/[\r\n]+/, "<br />").html_safe
247 end
247 end
248
248
249 def format_version_name(version)
249 def format_version_name(version)
250 if version.project == @project
250 if version.project == @project
251 h(version)
251 h(version)
252 else
252 else
253 h("#{version.project} - #{version}")
253 h("#{version.project} - #{version}")
254 end
254 end
255 end
255 end
256
256
257 def format_changeset_comments(changeset, options={})
257 def format_changeset_comments(changeset, options={})
258 method = options[:short] ? :short_comments : :comments
258 method = options[:short] ? :short_comments : :comments
259 textilizable changeset, method, :formatting => Setting.commit_logs_formatting?
259 textilizable changeset, method, :formatting => Setting.commit_logs_formatting?
260 end
260 end
261
261
262 def due_date_distance_in_words(date)
262 def due_date_distance_in_words(date)
263 if date
263 if date
264 l((date < User.current.today ? :label_roadmap_overdue : :label_roadmap_due_in), distance_of_date_in_words(User.current.today, date))
264 l((date < User.current.today ? :label_roadmap_overdue : :label_roadmap_due_in), distance_of_date_in_words(User.current.today, date))
265 end
265 end
266 end
266 end
267
267
268 # Renders a tree of projects as a nested set of unordered lists
268 # Renders a tree of projects as a nested set of unordered lists
269 # The given collection may be a subset of the whole project tree
269 # The given collection may be a subset of the whole project tree
270 # (eg. some intermediate nodes are private and can not be seen)
270 # (eg. some intermediate nodes are private and can not be seen)
271 def render_project_nested_lists(projects, &block)
271 def render_project_nested_lists(projects, &block)
272 s = ''
272 s = ''
273 if projects.any?
273 if projects.any?
274 ancestors = []
274 ancestors = []
275 original_project = @project
275 original_project = @project
276 projects.sort_by(&:lft).each do |project|
276 projects.sort_by(&:lft).each do |project|
277 # set the project environment to please macros.
277 # set the project environment to please macros.
278 @project = project
278 @project = project
279 if (ancestors.empty? || project.is_descendant_of?(ancestors.last))
279 if (ancestors.empty? || project.is_descendant_of?(ancestors.last))
280 s << "<ul class='projects #{ ancestors.empty? ? 'root' : nil}'>\n"
280 s << "<ul class='projects #{ ancestors.empty? ? 'root' : nil}'>\n"
281 else
281 else
282 ancestors.pop
282 ancestors.pop
283 s << "</li>"
283 s << "</li>"
284 while (ancestors.any? && !project.is_descendant_of?(ancestors.last))
284 while (ancestors.any? && !project.is_descendant_of?(ancestors.last))
285 ancestors.pop
285 ancestors.pop
286 s << "</ul></li>\n"
286 s << "</ul></li>\n"
287 end
287 end
288 end
288 end
289 classes = (ancestors.empty? ? 'root' : 'child')
289 classes = (ancestors.empty? ? 'root' : 'child')
290 s << "<li class='#{classes}'><div class='#{classes}'>"
290 s << "<li class='#{classes}'><div class='#{classes}'>"
291 s << h(block_given? ? capture(project, &block) : project.name)
291 s << h(block_given? ? capture(project, &block) : project.name)
292 s << "</div>\n"
292 s << "</div>\n"
293 ancestors << project
293 ancestors << project
294 end
294 end
295 s << ("</li></ul>\n" * ancestors.size)
295 s << ("</li></ul>\n" * ancestors.size)
296 @project = original_project
296 @project = original_project
297 end
297 end
298 s.html_safe
298 s.html_safe
299 end
299 end
300
300
301 def render_page_hierarchy(pages, node=nil, options={})
301 def render_page_hierarchy(pages, node=nil, options={})
302 content = ''
302 content = ''
303 if pages[node]
303 if pages[node]
304 content << "<ul class=\"pages-hierarchy\">\n"
304 content << "<ul class=\"pages-hierarchy\">\n"
305 pages[node].each do |page|
305 pages[node].each do |page|
306 content << "<li>"
306 content << "<li>"
307 content << link_to(h(page.pretty_title), {:controller => 'wiki', :action => 'show', :project_id => page.project, :id => page.title, :version => nil},
307 content << link_to(h(page.pretty_title), {:controller => 'wiki', :action => 'show', :project_id => page.project, :id => page.title, :version => nil},
308 :title => (options[:timestamp] && page.updated_on ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil))
308 :title => (options[:timestamp] && page.updated_on ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil))
309 content << "\n" + render_page_hierarchy(pages, page.id, options) if pages[page.id]
309 content << "\n" + render_page_hierarchy(pages, page.id, options) if pages[page.id]
310 content << "</li>\n"
310 content << "</li>\n"
311 end
311 end
312 content << "</ul>\n"
312 content << "</ul>\n"
313 end
313 end
314 content.html_safe
314 content.html_safe
315 end
315 end
316
316
317 # Renders flash messages
317 # Renders flash messages
318 def render_flash_messages
318 def render_flash_messages
319 s = ''
319 s = ''
320 flash.each do |k,v|
320 flash.each do |k,v|
321 s << content_tag('div', v.html_safe, :class => "flash #{k}", :id => "flash_#{k}")
321 s << content_tag('div', v.html_safe, :class => "flash #{k}", :id => "flash_#{k}")
322 end
322 end
323 s.html_safe
323 s.html_safe
324 end
324 end
325
325
326 # Renders tabs and their content
326 # Renders tabs and their content
327 def render_tabs(tabs, selected=params[:tab])
327 def render_tabs(tabs, selected=params[:tab])
328 if tabs.any?
328 if tabs.any?
329 unless tabs.detect {|tab| tab[:name] == selected}
329 unless tabs.detect {|tab| tab[:name] == selected}
330 selected = nil
330 selected = nil
331 end
331 end
332 selected ||= tabs.first[:name]
332 selected ||= tabs.first[:name]
333 render :partial => 'common/tabs', :locals => {:tabs => tabs, :selected_tab => selected}
333 render :partial => 'common/tabs', :locals => {:tabs => tabs, :selected_tab => selected}
334 else
334 else
335 content_tag 'p', l(:label_no_data), :class => "nodata"
335 content_tag 'p', l(:label_no_data), :class => "nodata"
336 end
336 end
337 end
337 end
338
338
339 # Returns an array of projects that are displayed in the quick-jump box
339 # Returns an array of projects that are displayed in the quick-jump box
340 def projects_for_jump_box(user=User.current)
340 def projects_for_jump_box(user=User.current)
341 if user.logged?
341 if user.logged?
342 user.projects.active.select(:id, :name, :identifier, :lft, :rgt).to_a
342 user.projects.active.select(:id, :name, :identifier, :lft, :rgt).to_a
343 else
343 else
344 []
344 []
345 end
345 end
346 end
346 end
347
347
348 def render_projects_for_jump_box(projects, selected=nil)
348 def render_projects_for_jump_box(projects, selected=nil)
349 s = ''.html_safe
349 s = ''.html_safe
350 project_tree(projects) do |project, level|
350 project_tree(projects) do |project, level|
351 padding = level * 16
351 padding = level * 16
352 text = content_tag('span', project.name, :style => "padding-left:#{padding}px;")
352 text = content_tag('span', project.name, :style => "padding-left:#{padding}px;")
353 s << link_to(text, project_path(project, :jump => current_menu_item), :title => project.name, :class => (project == selected ? 'selected' : nil))
353 s << link_to(text, project_path(project, :jump => current_menu_item), :title => project.name, :class => (project == selected ? 'selected' : nil))
354 end
354 end
355 s
355 s
356 end
356 end
357
357
358 # Renders the project quick-jump box
358 # Renders the project quick-jump box
359 def render_project_jump_box
359 def render_project_jump_box
360 projects = projects_for_jump_box(User.current)
360 projects = projects_for_jump_box(User.current)
361 if projects.any?
361 text = @project.try(:name) || l(:label_jump_to_a_project)
362 text = @project.try(:name) || l(:label_jump_to_a_project)
362 trigger = content_tag('span', text, :class => 'drdn-trigger')
363 trigger = content_tag('span', text, :class => 'drdn-trigger')
363 q = text_field_tag('q', '', :id => 'projects-quick-search', :class => 'autocomplete', :data => {:automcomplete_url => projects_path(:format => 'js')})
364 q = text_field_tag('q', '', :id => 'projects-quick-search', :class => 'autocomplete', :data => {:automcomplete_url => projects_path(:format => 'js')})
364 all = link_to(l(:label_project_all), projects_path(:jump => current_menu_item), :class => (@project.nil? && controller.class.main_menu ? 'selected' : nil))
365 all = link_to(l(:label_project_all), projects_path(:jump => current_menu_item), :class => (@project.nil? && controller.class.main_menu ? 'selected' : nil))
365 content = content_tag('div',
366 content = content_tag('div',
366 content_tag('div', q, :class => 'quick-search') +
367 content_tag('div', q, :class => 'quick-search') +
367 content_tag('div', render_projects_for_jump_box(projects, @project), :class => 'drdn-items projects selection') +
368 content_tag('div', render_projects_for_jump_box(projects, @project), :class => 'drdn-items projects selection') +
368 content_tag('div', all, :class => 'drdn-items all-projects selection'),
369 content_tag('div', all, :class => 'drdn-items all-projects selection'),
369 :class => 'drdn-content'
370 :class => 'drdn-content'
370 )
371 )
371
372
372 content_tag('span', trigger + content, :id => "project-jump", :class => "drdn")
373 content_tag('span', trigger + content, :id => "project-jump", :class => "drdn")
374 end
375 end
373 end
376
374
377 def project_tree_options_for_select(projects, options = {})
375 def project_tree_options_for_select(projects, options = {})
378 s = ''.html_safe
376 s = ''.html_safe
379 if blank_text = options[:include_blank]
377 if blank_text = options[:include_blank]
380 if blank_text == true
378 if blank_text == true
381 blank_text = '&nbsp;'.html_safe
379 blank_text = '&nbsp;'.html_safe
382 end
380 end
383 s << content_tag('option', blank_text, :value => '')
381 s << content_tag('option', blank_text, :value => '')
384 end
382 end
385 project_tree(projects) do |project, level|
383 project_tree(projects) do |project, level|
386 name_prefix = (level > 0 ? '&nbsp;' * 2 * level + '&#187; ' : '').html_safe
384 name_prefix = (level > 0 ? '&nbsp;' * 2 * level + '&#187; ' : '').html_safe
387 tag_options = {:value => project.id}
385 tag_options = {:value => project.id}
388 if project == options[:selected] || (options[:selected].respond_to?(:include?) && options[:selected].include?(project))
386 if project == options[:selected] || (options[:selected].respond_to?(:include?) && options[:selected].include?(project))
389 tag_options[:selected] = 'selected'
387 tag_options[:selected] = 'selected'
390 else
388 else
391 tag_options[:selected] = nil
389 tag_options[:selected] = nil
392 end
390 end
393 tag_options.merge!(yield(project)) if block_given?
391 tag_options.merge!(yield(project)) if block_given?
394 s << content_tag('option', name_prefix + h(project), tag_options)
392 s << content_tag('option', name_prefix + h(project), tag_options)
395 end
393 end
396 s.html_safe
394 s.html_safe
397 end
395 end
398
396
399 # Yields the given block for each project with its level in the tree
397 # Yields the given block for each project with its level in the tree
400 #
398 #
401 # Wrapper for Project#project_tree
399 # Wrapper for Project#project_tree
402 def project_tree(projects, options={}, &block)
400 def project_tree(projects, options={}, &block)
403 Project.project_tree(projects, options, &block)
401 Project.project_tree(projects, options, &block)
404 end
402 end
405
403
406 def principals_check_box_tags(name, principals)
404 def principals_check_box_tags(name, principals)
407 s = ''
405 s = ''
408 principals.each do |principal|
406 principals.each do |principal|
409 s << "<label>#{ check_box_tag name, principal.id, false, :id => nil } #{h principal}</label>\n"
407 s << "<label>#{ check_box_tag name, principal.id, false, :id => nil } #{h principal}</label>\n"
410 end
408 end
411 s.html_safe
409 s.html_safe
412 end
410 end
413
411
414 # Returns a string for users/groups option tags
412 # Returns a string for users/groups option tags
415 def principals_options_for_select(collection, selected=nil)
413 def principals_options_for_select(collection, selected=nil)
416 s = ''
414 s = ''
417 if collection.include?(User.current)
415 if collection.include?(User.current)
418 s << content_tag('option', "<< #{l(:label_me)} >>", :value => User.current.id)
416 s << content_tag('option', "<< #{l(:label_me)} >>", :value => User.current.id)
419 end
417 end
420 groups = ''
418 groups = ''
421 collection.sort.each do |element|
419 collection.sort.each do |element|
422 selected_attribute = ' selected="selected"' if option_value_selected?(element, selected) || element.id.to_s == selected
420 selected_attribute = ' selected="selected"' if option_value_selected?(element, selected) || element.id.to_s == selected
423 (element.is_a?(Group) ? groups : s) << %(<option value="#{element.id}"#{selected_attribute}>#{h element.name}</option>)
421 (element.is_a?(Group) ? groups : s) << %(<option value="#{element.id}"#{selected_attribute}>#{h element.name}</option>)
424 end
422 end
425 unless groups.empty?
423 unless groups.empty?
426 s << %(<optgroup label="#{h(l(:label_group_plural))}">#{groups}</optgroup>)
424 s << %(<optgroup label="#{h(l(:label_group_plural))}">#{groups}</optgroup>)
427 end
425 end
428 s.html_safe
426 s.html_safe
429 end
427 end
430
428
431 def option_tag(name, text, value, selected=nil, options={})
429 def option_tag(name, text, value, selected=nil, options={})
432 content_tag 'option', value, options.merge(:value => value, :selected => (value == selected))
430 content_tag 'option', value, options.merge(:value => value, :selected => (value == selected))
433 end
431 end
434
432
435 def truncate_single_line_raw(string, length)
433 def truncate_single_line_raw(string, length)
436 string.to_s.truncate(length).gsub(%r{[\r\n]+}m, ' ')
434 string.to_s.truncate(length).gsub(%r{[\r\n]+}m, ' ')
437 end
435 end
438
436
439 # Truncates at line break after 250 characters or options[:length]
437 # Truncates at line break after 250 characters or options[:length]
440 def truncate_lines(string, options={})
438 def truncate_lines(string, options={})
441 length = options[:length] || 250
439 length = options[:length] || 250
442 if string.to_s =~ /\A(.{#{length}}.*?)$/m
440 if string.to_s =~ /\A(.{#{length}}.*?)$/m
443 "#{$1}..."
441 "#{$1}..."
444 else
442 else
445 string
443 string
446 end
444 end
447 end
445 end
448
446
449 def anchor(text)
447 def anchor(text)
450 text.to_s.gsub(' ', '_')
448 text.to_s.gsub(' ', '_')
451 end
449 end
452
450
453 def html_hours(text)
451 def html_hours(text)
454 text.gsub(%r{(\d+)([\.:])(\d+)}, '<span class="hours hours-int">\1</span><span class="hours hours-dec">\2\3</span>').html_safe
452 text.gsub(%r{(\d+)([\.:])(\d+)}, '<span class="hours hours-int">\1</span><span class="hours hours-dec">\2\3</span>').html_safe
455 end
453 end
456
454
457 def authoring(created, author, options={})
455 def authoring(created, author, options={})
458 l(options[:label] || :label_added_time_by, :author => link_to_user(author), :age => time_tag(created)).html_safe
456 l(options[:label] || :label_added_time_by, :author => link_to_user(author), :age => time_tag(created)).html_safe
459 end
457 end
460
458
461 def time_tag(time)
459 def time_tag(time)
462 text = distance_of_time_in_words(Time.now, time)
460 text = distance_of_time_in_words(Time.now, time)
463 if @project
461 if @project
464 link_to(text, project_activity_path(@project, :from => User.current.time_to_date(time)), :title => format_time(time))
462 link_to(text, project_activity_path(@project, :from => User.current.time_to_date(time)), :title => format_time(time))
465 else
463 else
466 content_tag('abbr', text, :title => format_time(time))
464 content_tag('abbr', text, :title => format_time(time))
467 end
465 end
468 end
466 end
469
467
470 def syntax_highlight_lines(name, content)
468 def syntax_highlight_lines(name, content)
471 syntax_highlight(name, content).each_line.to_a
469 syntax_highlight(name, content).each_line.to_a
472 end
470 end
473
471
474 def syntax_highlight(name, content)
472 def syntax_highlight(name, content)
475 Redmine::SyntaxHighlighting.highlight_by_filename(content, name)
473 Redmine::SyntaxHighlighting.highlight_by_filename(content, name)
476 end
474 end
477
475
478 def to_path_param(path)
476 def to_path_param(path)
479 str = path.to_s.split(%r{[/\\]}).select{|p| !p.blank?}.join("/")
477 str = path.to_s.split(%r{[/\\]}).select{|p| !p.blank?}.join("/")
480 str.blank? ? nil : str
478 str.blank? ? nil : str
481 end
479 end
482
480
483 def reorder_links(name, url, method = :post)
481 def reorder_links(name, url, method = :post)
484 # TODO: remove associated styles from application.css too
482 # TODO: remove associated styles from application.css too
485 ActiveSupport::Deprecation.warn "Application#reorder_links will be removed in Redmine 4."
483 ActiveSupport::Deprecation.warn "Application#reorder_links will be removed in Redmine 4."
486
484
487 link_to(l(:label_sort_highest),
485 link_to(l(:label_sort_highest),
488 url.merge({"#{name}[move_to]" => 'highest'}), :method => method,
486 url.merge({"#{name}[move_to]" => 'highest'}), :method => method,
489 :title => l(:label_sort_highest), :class => 'icon-only icon-move-top') +
487 :title => l(:label_sort_highest), :class => 'icon-only icon-move-top') +
490 link_to(l(:label_sort_higher),
488 link_to(l(:label_sort_higher),
491 url.merge({"#{name}[move_to]" => 'higher'}), :method => method,
489 url.merge({"#{name}[move_to]" => 'higher'}), :method => method,
492 :title => l(:label_sort_higher), :class => 'icon-only icon-move-up') +
490 :title => l(:label_sort_higher), :class => 'icon-only icon-move-up') +
493 link_to(l(:label_sort_lower),
491 link_to(l(:label_sort_lower),
494 url.merge({"#{name}[move_to]" => 'lower'}), :method => method,
492 url.merge({"#{name}[move_to]" => 'lower'}), :method => method,
495 :title => l(:label_sort_lower), :class => 'icon-only icon-move-down') +
493 :title => l(:label_sort_lower), :class => 'icon-only icon-move-down') +
496 link_to(l(:label_sort_lowest),
494 link_to(l(:label_sort_lowest),
497 url.merge({"#{name}[move_to]" => 'lowest'}), :method => method,
495 url.merge({"#{name}[move_to]" => 'lowest'}), :method => method,
498 :title => l(:label_sort_lowest), :class => 'icon-only icon-move-bottom')
496 :title => l(:label_sort_lowest), :class => 'icon-only icon-move-bottom')
499 end
497 end
500
498
501 def reorder_handle(object, options={})
499 def reorder_handle(object, options={})
502 data = {
500 data = {
503 :reorder_url => options[:url] || url_for(object),
501 :reorder_url => options[:url] || url_for(object),
504 :reorder_param => options[:param] || object.class.name.underscore
502 :reorder_param => options[:param] || object.class.name.underscore
505 }
503 }
506 content_tag('span', '',
504 content_tag('span', '',
507 :class => "sort-handle",
505 :class => "sort-handle",
508 :data => data,
506 :data => data,
509 :title => l(:button_sort))
507 :title => l(:button_sort))
510 end
508 end
511
509
512 def breadcrumb(*args)
510 def breadcrumb(*args)
513 elements = args.flatten
511 elements = args.flatten
514 elements.any? ? content_tag('p', (args.join(" \xc2\xbb ") + " \xc2\xbb ").html_safe, :class => 'breadcrumb') : nil
512 elements.any? ? content_tag('p', (args.join(" \xc2\xbb ") + " \xc2\xbb ").html_safe, :class => 'breadcrumb') : nil
515 end
513 end
516
514
517 def other_formats_links(&block)
515 def other_formats_links(&block)
518 concat('<p class="other-formats">'.html_safe + l(:label_export_to))
516 concat('<p class="other-formats">'.html_safe + l(:label_export_to))
519 yield Redmine::Views::OtherFormatsBuilder.new(self)
517 yield Redmine::Views::OtherFormatsBuilder.new(self)
520 concat('</p>'.html_safe)
518 concat('</p>'.html_safe)
521 end
519 end
522
520
523 def page_header_title
521 def page_header_title
524 if @project.nil? || @project.new_record?
522 if @project.nil? || @project.new_record?
525 h(Setting.app_title)
523 h(Setting.app_title)
526 else
524 else
527 b = []
525 b = []
528 ancestors = (@project.root? ? [] : @project.ancestors.visible.to_a)
526 ancestors = (@project.root? ? [] : @project.ancestors.visible.to_a)
529 if ancestors.any?
527 if ancestors.any?
530 root = ancestors.shift
528 root = ancestors.shift
531 b << link_to_project(root, {:jump => current_menu_item}, :class => 'root')
529 b << link_to_project(root, {:jump => current_menu_item}, :class => 'root')
532 if ancestors.size > 2
530 if ancestors.size > 2
533 b << "\xe2\x80\xa6"
531 b << "\xe2\x80\xa6"
534 ancestors = ancestors[-2, 2]
532 ancestors = ancestors[-2, 2]
535 end
533 end
536 b += ancestors.collect {|p| link_to_project(p, {:jump => current_menu_item}, :class => 'ancestor') }
534 b += ancestors.collect {|p| link_to_project(p, {:jump => current_menu_item}, :class => 'ancestor') }
537 end
535 end
538 b << content_tag(:span, h(@project), class: 'current-project')
536 b << content_tag(:span, h(@project), class: 'current-project')
539 if b.size > 1
537 if b.size > 1
540 separator = content_tag(:span, ' &raquo; '.html_safe, class: 'separator')
538 separator = content_tag(:span, ' &raquo; '.html_safe, class: 'separator')
541 path = safe_join(b[0..-2], separator) + separator
539 path = safe_join(b[0..-2], separator) + separator
542 b = [content_tag(:span, path.html_safe, class: 'breadcrumbs'), b[-1]]
540 b = [content_tag(:span, path.html_safe, class: 'breadcrumbs'), b[-1]]
543 end
541 end
544 safe_join b
542 safe_join b
545 end
543 end
546 end
544 end
547
545
548 # Returns a h2 tag and sets the html title with the given arguments
546 # Returns a h2 tag and sets the html title with the given arguments
549 def title(*args)
547 def title(*args)
550 strings = args.map do |arg|
548 strings = args.map do |arg|
551 if arg.is_a?(Array) && arg.size >= 2
549 if arg.is_a?(Array) && arg.size >= 2
552 link_to(*arg)
550 link_to(*arg)
553 else
551 else
554 h(arg.to_s)
552 h(arg.to_s)
555 end
553 end
556 end
554 end
557 html_title args.reverse.map {|s| (s.is_a?(Array) ? s.first : s).to_s}
555 html_title args.reverse.map {|s| (s.is_a?(Array) ? s.first : s).to_s}
558 content_tag('h2', strings.join(' &#187; ').html_safe)
556 content_tag('h2', strings.join(' &#187; ').html_safe)
559 end
557 end
560
558
561 # Sets the html title
559 # Sets the html title
562 # Returns the html title when called without arguments
560 # Returns the html title when called without arguments
563 # Current project name and app_title and automatically appended
561 # Current project name and app_title and automatically appended
564 # Exemples:
562 # Exemples:
565 # html_title 'Foo', 'Bar'
563 # html_title 'Foo', 'Bar'
566 # html_title # => 'Foo - Bar - My Project - Redmine'
564 # html_title # => 'Foo - Bar - My Project - Redmine'
567 def html_title(*args)
565 def html_title(*args)
568 if args.empty?
566 if args.empty?
569 title = @html_title || []
567 title = @html_title || []
570 title << @project.name if @project
568 title << @project.name if @project
571 title << Setting.app_title unless Setting.app_title == title.last
569 title << Setting.app_title unless Setting.app_title == title.last
572 title.reject(&:blank?).join(' - ')
570 title.reject(&:blank?).join(' - ')
573 else
571 else
574 @html_title ||= []
572 @html_title ||= []
575 @html_title += args
573 @html_title += args
576 end
574 end
577 end
575 end
578
576
579 # Returns the theme, controller name, and action as css classes for the
577 # Returns the theme, controller name, and action as css classes for the
580 # HTML body.
578 # HTML body.
581 def body_css_classes
579 def body_css_classes
582 css = []
580 css = []
583 if theme = Redmine::Themes.theme(Setting.ui_theme)
581 if theme = Redmine::Themes.theme(Setting.ui_theme)
584 css << 'theme-' + theme.name
582 css << 'theme-' + theme.name
585 end
583 end
586
584
587 css << 'project-' + @project.identifier if @project && @project.identifier.present?
585 css << 'project-' + @project.identifier if @project && @project.identifier.present?
588 css << 'controller-' + controller_name
586 css << 'controller-' + controller_name
589 css << 'action-' + action_name
587 css << 'action-' + action_name
590 if UserPreference::TEXTAREA_FONT_OPTIONS.include?(User.current.pref.textarea_font)
588 if UserPreference::TEXTAREA_FONT_OPTIONS.include?(User.current.pref.textarea_font)
591 css << "textarea-#{User.current.pref.textarea_font}"
589 css << "textarea-#{User.current.pref.textarea_font}"
592 end
590 end
593 css.join(' ')
591 css.join(' ')
594 end
592 end
595
593
596 def accesskey(s)
594 def accesskey(s)
597 @used_accesskeys ||= []
595 @used_accesskeys ||= []
598 key = Redmine::AccessKeys.key_for(s)
596 key = Redmine::AccessKeys.key_for(s)
599 return nil if @used_accesskeys.include?(key)
597 return nil if @used_accesskeys.include?(key)
600 @used_accesskeys << key
598 @used_accesskeys << key
601 key
599 key
602 end
600 end
603
601
604 # Formats text according to system settings.
602 # Formats text according to system settings.
605 # 2 ways to call this method:
603 # 2 ways to call this method:
606 # * with a String: textilizable(text, options)
604 # * with a String: textilizable(text, options)
607 # * with an object and one of its attribute: textilizable(issue, :description, options)
605 # * with an object and one of its attribute: textilizable(issue, :description, options)
608 def textilizable(*args)
606 def textilizable(*args)
609 options = args.last.is_a?(Hash) ? args.pop : {}
607 options = args.last.is_a?(Hash) ? args.pop : {}
610 case args.size
608 case args.size
611 when 1
609 when 1
612 obj = options[:object]
610 obj = options[:object]
613 text = args.shift
611 text = args.shift
614 when 2
612 when 2
615 obj = args.shift
613 obj = args.shift
616 attr = args.shift
614 attr = args.shift
617 text = obj.send(attr).to_s
615 text = obj.send(attr).to_s
618 else
616 else
619 raise ArgumentError, 'invalid arguments to textilizable'
617 raise ArgumentError, 'invalid arguments to textilizable'
620 end
618 end
621 return '' if text.blank?
619 return '' if text.blank?
622 project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil)
620 project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil)
623 @only_path = only_path = options.delete(:only_path) == false ? false : true
621 @only_path = only_path = options.delete(:only_path) == false ? false : true
624
622
625 text = text.dup
623 text = text.dup
626 macros = catch_macros(text)
624 macros = catch_macros(text)
627
625
628 if options[:formatting] == false
626 if options[:formatting] == false
629 text = h(text)
627 text = h(text)
630 else
628 else
631 formatting = options[:formatting] || Setting.text_formatting
629 formatting = options[:formatting] || Setting.text_formatting
632 text = Redmine::WikiFormatting.to_html(formatting, text, :object => obj, :attribute => attr)
630 text = Redmine::WikiFormatting.to_html(formatting, text, :object => obj, :attribute => attr)
633 end
631 end
634
632
635 @parsed_headings = []
633 @parsed_headings = []
636 @heading_anchors = {}
634 @heading_anchors = {}
637 @current_section = 0 if options[:edit_section_links]
635 @current_section = 0 if options[:edit_section_links]
638
636
639 parse_sections(text, project, obj, attr, only_path, options)
637 parse_sections(text, project, obj, attr, only_path, options)
640 text = parse_non_pre_blocks(text, obj, macros) do |text|
638 text = parse_non_pre_blocks(text, obj, macros) do |text|
641 [:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links].each do |method_name|
639 [:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links].each do |method_name|
642 send method_name, text, project, obj, attr, only_path, options
640 send method_name, text, project, obj, attr, only_path, options
643 end
641 end
644 end
642 end
645 parse_headings(text, project, obj, attr, only_path, options)
643 parse_headings(text, project, obj, attr, only_path, options)
646
644
647 if @parsed_headings.any?
645 if @parsed_headings.any?
648 replace_toc(text, @parsed_headings)
646 replace_toc(text, @parsed_headings)
649 end
647 end
650
648
651 text.html_safe
649 text.html_safe
652 end
650 end
653
651
654 def parse_non_pre_blocks(text, obj, macros)
652 def parse_non_pre_blocks(text, obj, macros)
655 s = StringScanner.new(text)
653 s = StringScanner.new(text)
656 tags = []
654 tags = []
657 parsed = ''
655 parsed = ''
658 while !s.eos?
656 while !s.eos?
659 s.scan(/(.*?)(<(\/)?(pre|code)(.*?)>|\z)/im)
657 s.scan(/(.*?)(<(\/)?(pre|code)(.*?)>|\z)/im)
660 text, full_tag, closing, tag = s[1], s[2], s[3], s[4]
658 text, full_tag, closing, tag = s[1], s[2], s[3], s[4]
661 if tags.empty?
659 if tags.empty?
662 yield text
660 yield text
663 inject_macros(text, obj, macros) if macros.any?
661 inject_macros(text, obj, macros) if macros.any?
664 else
662 else
665 inject_macros(text, obj, macros, false) if macros.any?
663 inject_macros(text, obj, macros, false) if macros.any?
666 end
664 end
667 parsed << text
665 parsed << text
668 if tag
666 if tag
669 if closing
667 if closing
670 if tags.last && tags.last.casecmp(tag) == 0
668 if tags.last && tags.last.casecmp(tag) == 0
671 tags.pop
669 tags.pop
672 end
670 end
673 else
671 else
674 tags << tag.downcase
672 tags << tag.downcase
675 end
673 end
676 parsed << full_tag
674 parsed << full_tag
677 end
675 end
678 end
676 end
679 # Close any non closing tags
677 # Close any non closing tags
680 while tag = tags.pop
678 while tag = tags.pop
681 parsed << "</#{tag}>"
679 parsed << "</#{tag}>"
682 end
680 end
683 parsed
681 parsed
684 end
682 end
685
683
686 def parse_inline_attachments(text, project, obj, attr, only_path, options)
684 def parse_inline_attachments(text, project, obj, attr, only_path, options)
687 return if options[:inline_attachments] == false
685 return if options[:inline_attachments] == false
688
686
689 # when using an image link, try to use an attachment, if possible
687 # when using an image link, try to use an attachment, if possible
690 attachments = options[:attachments] || []
688 attachments = options[:attachments] || []
691 attachments += obj.attachments if obj.respond_to?(:attachments)
689 attachments += obj.attachments if obj.respond_to?(:attachments)
692 if attachments.present?
690 if attachments.present?
693 text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpe|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m|
691 text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpe|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m|
694 filename, ext, alt, alttext = $1.downcase, $2, $3, $4
692 filename, ext, alt, alttext = $1.downcase, $2, $3, $4
695 # search for the picture in attachments
693 # search for the picture in attachments
696 if found = Attachment.latest_attach(attachments, CGI.unescape(filename))
694 if found = Attachment.latest_attach(attachments, CGI.unescape(filename))
697 image_url = download_named_attachment_url(found, found.filename, :only_path => only_path)
695 image_url = download_named_attachment_url(found, found.filename, :only_path => only_path)
698 desc = found.description.to_s.gsub('"', '')
696 desc = found.description.to_s.gsub('"', '')
699 if !desc.blank? && alttext.blank?
697 if !desc.blank? && alttext.blank?
700 alt = " title=\"#{desc}\" alt=\"#{desc}\""
698 alt = " title=\"#{desc}\" alt=\"#{desc}\""
701 end
699 end
702 "src=\"#{image_url}\"#{alt}"
700 "src=\"#{image_url}\"#{alt}"
703 else
701 else
704 m
702 m
705 end
703 end
706 end
704 end
707 end
705 end
708 end
706 end
709
707
710 # Wiki links
708 # Wiki links
711 #
709 #
712 # Examples:
710 # Examples:
713 # [[mypage]]
711 # [[mypage]]
714 # [[mypage|mytext]]
712 # [[mypage|mytext]]
715 # wiki links can refer other project wikis, using project name or identifier:
713 # wiki links can refer other project wikis, using project name or identifier:
716 # [[project:]] -> wiki starting page
714 # [[project:]] -> wiki starting page
717 # [[project:|mytext]]
715 # [[project:|mytext]]
718 # [[project:mypage]]
716 # [[project:mypage]]
719 # [[project:mypage|mytext]]
717 # [[project:mypage|mytext]]
720 def parse_wiki_links(text, project, obj, attr, only_path, options)
718 def parse_wiki_links(text, project, obj, attr, only_path, options)
721 text.gsub!(/(!)?(\[\[([^\]\n\|]+)(\|([^\]\n\|]+))?\]\])/) do |m|
719 text.gsub!(/(!)?(\[\[([^\]\n\|]+)(\|([^\]\n\|]+))?\]\])/) do |m|
722 link_project = project
720 link_project = project
723 esc, all, page, title = $1, $2, $3, $5
721 esc, all, page, title = $1, $2, $3, $5
724 if esc.nil?
722 if esc.nil?
725 if page =~ /^([^\:]+)\:(.*)$/
723 if page =~ /^([^\:]+)\:(.*)$/
726 identifier, page = $1, $2
724 identifier, page = $1, $2
727 link_project = Project.find_by_identifier(identifier) || Project.find_by_name(identifier)
725 link_project = Project.find_by_identifier(identifier) || Project.find_by_name(identifier)
728 title ||= identifier if page.blank?
726 title ||= identifier if page.blank?
729 end
727 end
730
728
731 if link_project && link_project.wiki
729 if link_project && link_project.wiki
732 # extract anchor
730 # extract anchor
733 anchor = nil
731 anchor = nil
734 if page =~ /^(.+?)\#(.+)$/
732 if page =~ /^(.+?)\#(.+)$/
735 page, anchor = $1, $2
733 page, anchor = $1, $2
736 end
734 end
737 anchor = sanitize_anchor_name(anchor) if anchor.present?
735 anchor = sanitize_anchor_name(anchor) if anchor.present?
738 # check if page exists
736 # check if page exists
739 wiki_page = link_project.wiki.find_page(page)
737 wiki_page = link_project.wiki.find_page(page)
740 url = if anchor.present? && wiki_page.present? && (obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version)) && obj.page == wiki_page
738 url = if anchor.present? && wiki_page.present? && (obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version)) && obj.page == wiki_page
741 "##{anchor}"
739 "##{anchor}"
742 else
740 else
743 case options[:wiki_links]
741 case options[:wiki_links]
744 when :local; "#{page.present? ? Wiki.titleize(page) : ''}.html" + (anchor.present? ? "##{anchor}" : '')
742 when :local; "#{page.present? ? Wiki.titleize(page) : ''}.html" + (anchor.present? ? "##{anchor}" : '')
745 when :anchor; "##{page.present? ? Wiki.titleize(page) : title}" + (anchor.present? ? "_#{anchor}" : '') # used for single-file wiki export
743 when :anchor; "##{page.present? ? Wiki.titleize(page) : title}" + (anchor.present? ? "_#{anchor}" : '') # used for single-file wiki export
746 else
744 else
747 wiki_page_id = page.present? ? Wiki.titleize(page) : nil
745 wiki_page_id = page.present? ? Wiki.titleize(page) : nil
748 parent = wiki_page.nil? && obj.is_a?(WikiContent) && obj.page && project == link_project ? obj.page.title : nil
746 parent = wiki_page.nil? && obj.is_a?(WikiContent) && obj.page && project == link_project ? obj.page.title : nil
749 url_for(:only_path => only_path, :controller => 'wiki', :action => 'show', :project_id => link_project,
747 url_for(:only_path => only_path, :controller => 'wiki', :action => 'show', :project_id => link_project,
750 :id => wiki_page_id, :version => nil, :anchor => anchor, :parent => parent)
748 :id => wiki_page_id, :version => nil, :anchor => anchor, :parent => parent)
751 end
749 end
752 end
750 end
753 link_to(title.present? ? title.html_safe : h(page), url, :class => ('wiki-page' + (wiki_page ? '' : ' new')))
751 link_to(title.present? ? title.html_safe : h(page), url, :class => ('wiki-page' + (wiki_page ? '' : ' new')))
754 else
752 else
755 # project or wiki doesn't exist
753 # project or wiki doesn't exist
756 all
754 all
757 end
755 end
758 else
756 else
759 all
757 all
760 end
758 end
761 end
759 end
762 end
760 end
763
761
764 # Redmine links
762 # Redmine links
765 #
763 #
766 # Examples:
764 # Examples:
767 # Issues:
765 # Issues:
768 # #52 -> Link to issue #52
766 # #52 -> Link to issue #52
769 # Changesets:
767 # Changesets:
770 # r52 -> Link to revision 52
768 # r52 -> Link to revision 52
771 # commit:a85130f -> Link to scmid starting with a85130f
769 # commit:a85130f -> Link to scmid starting with a85130f
772 # Documents:
770 # Documents:
773 # document#17 -> Link to document with id 17
771 # document#17 -> Link to document with id 17
774 # document:Greetings -> Link to the document with title "Greetings"
772 # document:Greetings -> Link to the document with title "Greetings"
775 # document:"Some document" -> Link to the document with title "Some document"
773 # document:"Some document" -> Link to the document with title "Some document"
776 # Versions:
774 # Versions:
777 # version#3 -> Link to version with id 3
775 # version#3 -> Link to version with id 3
778 # version:1.0.0 -> Link to version named "1.0.0"
776 # version:1.0.0 -> Link to version named "1.0.0"
779 # version:"1.0 beta 2" -> Link to version named "1.0 beta 2"
777 # version:"1.0 beta 2" -> Link to version named "1.0 beta 2"
780 # Attachments:
778 # Attachments:
781 # attachment:file.zip -> Link to the attachment of the current object named file.zip
779 # attachment:file.zip -> Link to the attachment of the current object named file.zip
782 # Source files:
780 # Source files:
783 # source:some/file -> Link to the file located at /some/file in the project's repository
781 # source:some/file -> Link to the file located at /some/file in the project's repository
784 # source:some/file@52 -> Link to the file's revision 52
782 # source:some/file@52 -> Link to the file's revision 52
785 # source:some/file#L120 -> Link to line 120 of the file
783 # source:some/file#L120 -> Link to line 120 of the file
786 # source:some/file@52#L120 -> Link to line 120 of the file's revision 52
784 # source:some/file@52#L120 -> Link to line 120 of the file's revision 52
787 # export:some/file -> Force the download of the file
785 # export:some/file -> Force the download of the file
788 # Forum messages:
786 # Forum messages:
789 # message#1218 -> Link to message with id 1218
787 # message#1218 -> Link to message with id 1218
790 # Projects:
788 # Projects:
791 # project:someproject -> Link to project named "someproject"
789 # project:someproject -> Link to project named "someproject"
792 # project#3 -> Link to project with id 3
790 # project#3 -> Link to project with id 3
793 #
791 #
794 # Links can refer other objects from other projects, using project identifier:
792 # Links can refer other objects from other projects, using project identifier:
795 # identifier:r52
793 # identifier:r52
796 # identifier:document:"Some document"
794 # identifier:document:"Some document"
797 # identifier:version:1.0.0
795 # identifier:version:1.0.0
798 # identifier:source:some/file
796 # identifier:source:some/file
799 def parse_redmine_links(text, default_project, obj, attr, only_path, options)
797 def parse_redmine_links(text, default_project, obj, attr, only_path, options)
800 text.gsub!(LINKS_RE) do |_|
798 text.gsub!(LINKS_RE) do |_|
801 tag_content = $~[:tag_content]
799 tag_content = $~[:tag_content]
802 leading = $~[:leading]
800 leading = $~[:leading]
803 esc = $~[:esc]
801 esc = $~[:esc]
804 project_prefix = $~[:project_prefix]
802 project_prefix = $~[:project_prefix]
805 project_identifier = $~[:project_identifier]
803 project_identifier = $~[:project_identifier]
806 prefix = $~[:prefix]
804 prefix = $~[:prefix]
807 repo_prefix = $~[:repo_prefix]
805 repo_prefix = $~[:repo_prefix]
808 repo_identifier = $~[:repo_identifier]
806 repo_identifier = $~[:repo_identifier]
809 sep = $~[:sep1] || $~[:sep2] || $~[:sep3]
807 sep = $~[:sep1] || $~[:sep2] || $~[:sep3]
810 identifier = $~[:identifier1] || $~[:identifier2]
808 identifier = $~[:identifier1] || $~[:identifier2]
811 comment_suffix = $~[:comment_suffix]
809 comment_suffix = $~[:comment_suffix]
812 comment_id = $~[:comment_id]
810 comment_id = $~[:comment_id]
813
811
814 if tag_content
812 if tag_content
815 $&
813 $&
816 else
814 else
817 link = nil
815 link = nil
818 project = default_project
816 project = default_project
819 if project_identifier
817 if project_identifier
820 project = Project.visible.find_by_identifier(project_identifier)
818 project = Project.visible.find_by_identifier(project_identifier)
821 end
819 end
822 if esc.nil?
820 if esc.nil?
823 if prefix.nil? && sep == 'r'
821 if prefix.nil? && sep == 'r'
824 if project
822 if project
825 repository = nil
823 repository = nil
826 if repo_identifier
824 if repo_identifier
827 repository = project.repositories.detect {|repo| repo.identifier == repo_identifier}
825 repository = project.repositories.detect {|repo| repo.identifier == repo_identifier}
828 else
826 else
829 repository = project.repository
827 repository = project.repository
830 end
828 end
831 # project.changesets.visible raises an SQL error because of a double join on repositories
829 # project.changesets.visible raises an SQL error because of a double join on repositories
832 if repository &&
830 if repository &&
833 (changeset = Changeset.visible.
831 (changeset = Changeset.visible.
834 find_by_repository_id_and_revision(repository.id, identifier))
832 find_by_repository_id_and_revision(repository.id, identifier))
835 link = link_to(h("#{project_prefix}#{repo_prefix}r#{identifier}"),
833 link = link_to(h("#{project_prefix}#{repo_prefix}r#{identifier}"),
836 {:only_path => only_path, :controller => 'repositories',
834 {:only_path => only_path, :controller => 'repositories',
837 :action => 'revision', :id => project,
835 :action => 'revision', :id => project,
838 :repository_id => repository.identifier_param,
836 :repository_id => repository.identifier_param,
839 :rev => changeset.revision},
837 :rev => changeset.revision},
840 :class => 'changeset',
838 :class => 'changeset',
841 :title => truncate_single_line_raw(changeset.comments, 100))
839 :title => truncate_single_line_raw(changeset.comments, 100))
842 end
840 end
843 end
841 end
844 elsif sep == '#'
842 elsif sep == '#'
845 oid = identifier.to_i
843 oid = identifier.to_i
846 case prefix
844 case prefix
847 when nil
845 when nil
848 if oid.to_s == identifier &&
846 if oid.to_s == identifier &&
849 issue = Issue.visible.find_by_id(oid)
847 issue = Issue.visible.find_by_id(oid)
850 anchor = comment_id ? "note-#{comment_id}" : nil
848 anchor = comment_id ? "note-#{comment_id}" : nil
851 link = link_to("##{oid}#{comment_suffix}",
849 link = link_to("##{oid}#{comment_suffix}",
852 issue_url(issue, :only_path => only_path, :anchor => anchor),
850 issue_url(issue, :only_path => only_path, :anchor => anchor),
853 :class => issue.css_classes,
851 :class => issue.css_classes,
854 :title => "#{issue.tracker.name}: #{issue.subject.truncate(100)} (#{issue.status.name})")
852 :title => "#{issue.tracker.name}: #{issue.subject.truncate(100)} (#{issue.status.name})")
855 end
853 end
856 when 'document'
854 when 'document'
857 if document = Document.visible.find_by_id(oid)
855 if document = Document.visible.find_by_id(oid)
858 link = link_to(document.title, document_url(document, :only_path => only_path), :class => 'document')
856 link = link_to(document.title, document_url(document, :only_path => only_path), :class => 'document')
859 end
857 end
860 when 'version'
858 when 'version'
861 if version = Version.visible.find_by_id(oid)
859 if version = Version.visible.find_by_id(oid)
862 link = link_to(version.name, version_url(version, :only_path => only_path), :class => 'version')
860 link = link_to(version.name, version_url(version, :only_path => only_path), :class => 'version')
863 end
861 end
864 when 'message'
862 when 'message'
865 if message = Message.visible.find_by_id(oid)
863 if message = Message.visible.find_by_id(oid)
866 link = link_to_message(message, {:only_path => only_path}, :class => 'message')
864 link = link_to_message(message, {:only_path => only_path}, :class => 'message')
867 end
865 end
868 when 'forum'
866 when 'forum'
869 if board = Board.visible.find_by_id(oid)
867 if board = Board.visible.find_by_id(oid)
870 link = link_to(board.name, project_board_url(board.project, board, :only_path => only_path), :class => 'board')
868 link = link_to(board.name, project_board_url(board.project, board, :only_path => only_path), :class => 'board')
871 end
869 end
872 when 'news'
870 when 'news'
873 if news = News.visible.find_by_id(oid)
871 if news = News.visible.find_by_id(oid)
874 link = link_to(news.title, news_url(news, :only_path => only_path), :class => 'news')
872 link = link_to(news.title, news_url(news, :only_path => only_path), :class => 'news')
875 end
873 end
876 when 'project'
874 when 'project'
877 if p = Project.visible.find_by_id(oid)
875 if p = Project.visible.find_by_id(oid)
878 link = link_to_project(p, {:only_path => only_path}, :class => 'project')
876 link = link_to_project(p, {:only_path => only_path}, :class => 'project')
879 end
877 end
880 end
878 end
881 elsif sep == ':'
879 elsif sep == ':'
882 # removes the double quotes if any
880 # removes the double quotes if any
883 name = identifier.gsub(%r{^"(.*)"$}, "\\1")
881 name = identifier.gsub(%r{^"(.*)"$}, "\\1")
884 name = CGI.unescapeHTML(name)
882 name = CGI.unescapeHTML(name)
885 case prefix
883 case prefix
886 when 'document'
884 when 'document'
887 if project && document = project.documents.visible.find_by_title(name)
885 if project && document = project.documents.visible.find_by_title(name)
888 link = link_to(document.title, document_url(document, :only_path => only_path), :class => 'document')
886 link = link_to(document.title, document_url(document, :only_path => only_path), :class => 'document')
889 end
887 end
890 when 'version'
888 when 'version'
891 if project && version = project.versions.visible.find_by_name(name)
889 if project && version = project.versions.visible.find_by_name(name)
892 link = link_to(version.name, version_url(version, :only_path => only_path), :class => 'version')
890 link = link_to(version.name, version_url(version, :only_path => only_path), :class => 'version')
893 end
891 end
894 when 'forum'
892 when 'forum'
895 if project && board = project.boards.visible.find_by_name(name)
893 if project && board = project.boards.visible.find_by_name(name)
896 link = link_to(board.name, project_board_url(board.project, board, :only_path => only_path), :class => 'board')
894 link = link_to(board.name, project_board_url(board.project, board, :only_path => only_path), :class => 'board')
897 end
895 end
898 when 'news'
896 when 'news'
899 if project && news = project.news.visible.find_by_title(name)
897 if project && news = project.news.visible.find_by_title(name)
900 link = link_to(news.title, news_url(news, :only_path => only_path), :class => 'news')
898 link = link_to(news.title, news_url(news, :only_path => only_path), :class => 'news')
901 end
899 end
902 when 'commit', 'source', 'export'
900 when 'commit', 'source', 'export'
903 if project
901 if project
904 repository = nil
902 repository = nil
905 if name =~ %r{^(([a-z0-9\-_]+)\|)(.+)$}
903 if name =~ %r{^(([a-z0-9\-_]+)\|)(.+)$}
906 repo_prefix, repo_identifier, name = $1, $2, $3
904 repo_prefix, repo_identifier, name = $1, $2, $3
907 repository = project.repositories.detect {|repo| repo.identifier == repo_identifier}
905 repository = project.repositories.detect {|repo| repo.identifier == repo_identifier}
908 else
906 else
909 repository = project.repository
907 repository = project.repository
910 end
908 end
911 if prefix == 'commit'
909 if prefix == 'commit'
912 if repository && (changeset = Changeset.visible.where("repository_id = ? AND scmid LIKE ?", repository.id, "#{name}%").first)
910 if repository && (changeset = Changeset.visible.where("repository_id = ? AND scmid LIKE ?", repository.id, "#{name}%").first)
913 link = link_to h("#{project_prefix}#{repo_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :repository_id => repository.identifier_param, :rev => changeset.identifier},
911 link = link_to h("#{project_prefix}#{repo_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :repository_id => repository.identifier_param, :rev => changeset.identifier},
914 :class => 'changeset',
912 :class => 'changeset',
915 :title => truncate_single_line_raw(changeset.comments, 100)
913 :title => truncate_single_line_raw(changeset.comments, 100)
916 end
914 end
917 else
915 else
918 if repository && User.current.allowed_to?(:browse_repository, project)
916 if repository && User.current.allowed_to?(:browse_repository, project)
919 name =~ %r{^[/\\]*(.*?)(@([^/\\@]+?))?(#(L\d+))?$}
917 name =~ %r{^[/\\]*(.*?)(@([^/\\@]+?))?(#(L\d+))?$}
920 path, rev, anchor = $1, $3, $5
918 path, rev, anchor = $1, $3, $5
921 link = link_to h("#{project_prefix}#{prefix}:#{repo_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => (prefix == 'export' ? 'raw' : 'entry'), :id => project, :repository_id => repository.identifier_param,
919 link = link_to h("#{project_prefix}#{prefix}:#{repo_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => (prefix == 'export' ? 'raw' : 'entry'), :id => project, :repository_id => repository.identifier_param,
922 :path => to_path_param(path),
920 :path => to_path_param(path),
923 :rev => rev,
921 :rev => rev,
924 :anchor => anchor},
922 :anchor => anchor},
925 :class => (prefix == 'export' ? 'source download' : 'source')
923 :class => (prefix == 'export' ? 'source download' : 'source')
926 end
924 end
927 end
925 end
928 repo_prefix = nil
926 repo_prefix = nil
929 end
927 end
930 when 'attachment'
928 when 'attachment'
931 attachments = options[:attachments] || []
929 attachments = options[:attachments] || []
932 attachments += obj.attachments if obj.respond_to?(:attachments)
930 attachments += obj.attachments if obj.respond_to?(:attachments)
933 if attachments && attachment = Attachment.latest_attach(attachments, name)
931 if attachments && attachment = Attachment.latest_attach(attachments, name)
934 link = link_to_attachment(attachment, :only_path => only_path, :download => true, :class => 'attachment')
932 link = link_to_attachment(attachment, :only_path => only_path, :download => true, :class => 'attachment')
935 end
933 end
936 when 'project'
934 when 'project'
937 if p = Project.visible.where("identifier = :s OR LOWER(name) = :s", :s => name.downcase).first
935 if p = Project.visible.where("identifier = :s OR LOWER(name) = :s", :s => name.downcase).first
938 link = link_to_project(p, {:only_path => only_path}, :class => 'project')
936 link = link_to_project(p, {:only_path => only_path}, :class => 'project')
939 end
937 end
940 end
938 end
941 end
939 end
942 end
940 end
943 (leading + (link || "#{project_prefix}#{prefix}#{repo_prefix}#{sep}#{identifier}#{comment_suffix}"))
941 (leading + (link || "#{project_prefix}#{prefix}#{repo_prefix}#{sep}#{identifier}#{comment_suffix}"))
944 end
942 end
945 end
943 end
946 end
944 end
947
945
948 LINKS_RE =
946 LINKS_RE =
949 %r{
947 %r{
950 <a( [^>]+?)?>(?<tag_content>.*?)</a>|
948 <a( [^>]+?)?>(?<tag_content>.*?)</a>|
951 (?<leading>[\s\(,\-\[\>]|^)
949 (?<leading>[\s\(,\-\[\>]|^)
952 (?<esc>!)?
950 (?<esc>!)?
953 (?<project_prefix>(?<project_identifier>[a-z0-9\-_]+):)?
951 (?<project_prefix>(?<project_identifier>[a-z0-9\-_]+):)?
954 (?<prefix>attachment|document|version|forum|news|message|project|commit|source|export)?
952 (?<prefix>attachment|document|version|forum|news|message|project|commit|source|export)?
955 (
953 (
956 (
954 (
957 (?<sep1>\#)|
955 (?<sep1>\#)|
958 (
956 (
959 (?<repo_prefix>(?<repo_identifier>[a-z0-9\-_]+)\|)?
957 (?<repo_prefix>(?<repo_identifier>[a-z0-9\-_]+)\|)?
960 (?<sep2>r)
958 (?<sep2>r)
961 )
959 )
962 )
960 )
963 (
961 (
964 (?<identifier1>\d+)
962 (?<identifier1>\d+)
965 (?<comment_suffix>
963 (?<comment_suffix>
966 (\#note)?
964 (\#note)?
967 -(?<comment_id>\d+)
965 -(?<comment_id>\d+)
968 )?
966 )?
969 )|
967 )|
970 (?<sep3>:)
968 (?<sep3>:)
971 (?<identifier2>[^"\s<>][^\s<>]*?|"[^"]+?")
969 (?<identifier2>[^"\s<>][^\s<>]*?|"[^"]+?")
972 )
970 )
973 (?=
971 (?=
974 (?=[[:punct:]][^A-Za-z0-9_/])|
972 (?=[[:punct:]][^A-Za-z0-9_/])|
975 ,|
973 ,|
976 \s|
974 \s|
977 \]|
975 \]|
978 <|
976 <|
979 $)
977 $)
980 }x
978 }x
981 HEADING_RE = /(<h(\d)( [^>]+)?>(.+?)<\/h(\d)>)/i unless const_defined?(:HEADING_RE)
979 HEADING_RE = /(<h(\d)( [^>]+)?>(.+?)<\/h(\d)>)/i unless const_defined?(:HEADING_RE)
982
980
983 def parse_sections(text, project, obj, attr, only_path, options)
981 def parse_sections(text, project, obj, attr, only_path, options)
984 return unless options[:edit_section_links]
982 return unless options[:edit_section_links]
985 text.gsub!(HEADING_RE) do
983 text.gsub!(HEADING_RE) do
986 heading, level = $1, $2
984 heading, level = $1, $2
987 @current_section += 1
985 @current_section += 1
988 if @current_section > 1
986 if @current_section > 1
989 content_tag('div',
987 content_tag('div',
990 link_to(l(:button_edit_section), options[:edit_section_links].merge(:section => @current_section),
988 link_to(l(:button_edit_section), options[:edit_section_links].merge(:section => @current_section),
991 :class => 'icon-only icon-edit'),
989 :class => 'icon-only icon-edit'),
992 :class => "contextual heading-#{level}",
990 :class => "contextual heading-#{level}",
993 :title => l(:button_edit_section),
991 :title => l(:button_edit_section),
994 :id => "section-#{@current_section}") + heading.html_safe
992 :id => "section-#{@current_section}") + heading.html_safe
995 else
993 else
996 heading
994 heading
997 end
995 end
998 end
996 end
999 end
997 end
1000
998
1001 # Headings and TOC
999 # Headings and TOC
1002 # Adds ids and links to headings unless options[:headings] is set to false
1000 # Adds ids and links to headings unless options[:headings] is set to false
1003 def parse_headings(text, project, obj, attr, only_path, options)
1001 def parse_headings(text, project, obj, attr, only_path, options)
1004 return if options[:headings] == false
1002 return if options[:headings] == false
1005
1003
1006 text.gsub!(HEADING_RE) do
1004 text.gsub!(HEADING_RE) do
1007 level, attrs, content = $2.to_i, $3, $4
1005 level, attrs, content = $2.to_i, $3, $4
1008 item = strip_tags(content).strip
1006 item = strip_tags(content).strip
1009 anchor = sanitize_anchor_name(item)
1007 anchor = sanitize_anchor_name(item)
1010 # used for single-file wiki export
1008 # used for single-file wiki export
1011 anchor = "#{obj.page.title}_#{anchor}" if options[:wiki_links] == :anchor && (obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version))
1009 anchor = "#{obj.page.title}_#{anchor}" if options[:wiki_links] == :anchor && (obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version))
1012 @heading_anchors[anchor] ||= 0
1010 @heading_anchors[anchor] ||= 0
1013 idx = (@heading_anchors[anchor] += 1)
1011 idx = (@heading_anchors[anchor] += 1)
1014 if idx > 1
1012 if idx > 1
1015 anchor = "#{anchor}-#{idx}"
1013 anchor = "#{anchor}-#{idx}"
1016 end
1014 end
1017 @parsed_headings << [level, anchor, item]
1015 @parsed_headings << [level, anchor, item]
1018 "<a name=\"#{anchor}\"></a>\n<h#{level} #{attrs}>#{content}<a href=\"##{anchor}\" class=\"wiki-anchor\">&para;</a></h#{level}>"
1016 "<a name=\"#{anchor}\"></a>\n<h#{level} #{attrs}>#{content}<a href=\"##{anchor}\" class=\"wiki-anchor\">&para;</a></h#{level}>"
1019 end
1017 end
1020 end
1018 end
1021
1019
1022 MACROS_RE = /(
1020 MACROS_RE = /(
1023 (!)? # escaping
1021 (!)? # escaping
1024 (
1022 (
1025 \{\{ # opening tag
1023 \{\{ # opening tag
1026 ([\w]+) # macro name
1024 ([\w]+) # macro name
1027 (\(([^\n\r]*?)\))? # optional arguments
1025 (\(([^\n\r]*?)\))? # optional arguments
1028 ([\n\r].*?[\n\r])? # optional block of text
1026 ([\n\r].*?[\n\r])? # optional block of text
1029 \}\} # closing tag
1027 \}\} # closing tag
1030 )
1028 )
1031 )/mx unless const_defined?(:MACROS_RE)
1029 )/mx unless const_defined?(:MACROS_RE)
1032
1030
1033 MACRO_SUB_RE = /(
1031 MACRO_SUB_RE = /(
1034 \{\{
1032 \{\{
1035 macro\((\d+)\)
1033 macro\((\d+)\)
1036 \}\}
1034 \}\}
1037 )/x unless const_defined?(:MACRO_SUB_RE)
1035 )/x unless const_defined?(:MACRO_SUB_RE)
1038
1036
1039 # Extracts macros from text
1037 # Extracts macros from text
1040 def catch_macros(text)
1038 def catch_macros(text)
1041 macros = {}
1039 macros = {}
1042 text.gsub!(MACROS_RE) do
1040 text.gsub!(MACROS_RE) do
1043 all, macro = $1, $4.downcase
1041 all, macro = $1, $4.downcase
1044 if macro_exists?(macro) || all =~ MACRO_SUB_RE
1042 if macro_exists?(macro) || all =~ MACRO_SUB_RE
1045 index = macros.size
1043 index = macros.size
1046 macros[index] = all
1044 macros[index] = all
1047 "{{macro(#{index})}}"
1045 "{{macro(#{index})}}"
1048 else
1046 else
1049 all
1047 all
1050 end
1048 end
1051 end
1049 end
1052 macros
1050 macros
1053 end
1051 end
1054
1052
1055 # Executes and replaces macros in text
1053 # Executes and replaces macros in text
1056 def inject_macros(text, obj, macros, execute=true)
1054 def inject_macros(text, obj, macros, execute=true)
1057 text.gsub!(MACRO_SUB_RE) do
1055 text.gsub!(MACRO_SUB_RE) do
1058 all, index = $1, $2.to_i
1056 all, index = $1, $2.to_i
1059 orig = macros.delete(index)
1057 orig = macros.delete(index)
1060 if execute && orig && orig =~ MACROS_RE
1058 if execute && orig && orig =~ MACROS_RE
1061 esc, all, macro, args, block = $2, $3, $4.downcase, $6.to_s, $7.try(:strip)
1059 esc, all, macro, args, block = $2, $3, $4.downcase, $6.to_s, $7.try(:strip)
1062 if esc.nil?
1060 if esc.nil?
1063 h(exec_macro(macro, obj, args, block) || all)
1061 h(exec_macro(macro, obj, args, block) || all)
1064 else
1062 else
1065 h(all)
1063 h(all)
1066 end
1064 end
1067 elsif orig
1065 elsif orig
1068 h(orig)
1066 h(orig)
1069 else
1067 else
1070 h(all)
1068 h(all)
1071 end
1069 end
1072 end
1070 end
1073 end
1071 end
1074
1072
1075 TOC_RE = /<p>\{\{((<|&lt;)|(>|&gt;))?toc\}\}<\/p>/i unless const_defined?(:TOC_RE)
1073 TOC_RE = /<p>\{\{((<|&lt;)|(>|&gt;))?toc\}\}<\/p>/i unless const_defined?(:TOC_RE)
1076
1074
1077 # Renders the TOC with given headings
1075 # Renders the TOC with given headings
1078 def replace_toc(text, headings)
1076 def replace_toc(text, headings)
1079 text.gsub!(TOC_RE) do
1077 text.gsub!(TOC_RE) do
1080 left_align, right_align = $2, $3
1078 left_align, right_align = $2, $3
1081 # Keep only the 4 first levels
1079 # Keep only the 4 first levels
1082 headings = headings.select{|level, anchor, item| level <= 4}
1080 headings = headings.select{|level, anchor, item| level <= 4}
1083 if headings.empty?
1081 if headings.empty?
1084 ''
1082 ''
1085 else
1083 else
1086 div_class = 'toc'
1084 div_class = 'toc'
1087 div_class << ' right' if right_align
1085 div_class << ' right' if right_align
1088 div_class << ' left' if left_align
1086 div_class << ' left' if left_align
1089 out = "<ul class=\"#{div_class}\"><li><strong>#{l :label_table_of_contents}</strong></li><li>"
1087 out = "<ul class=\"#{div_class}\"><li><strong>#{l :label_table_of_contents}</strong></li><li>"
1090 root = headings.map(&:first).min
1088 root = headings.map(&:first).min
1091 current = root
1089 current = root
1092 started = false
1090 started = false
1093 headings.each do |level, anchor, item|
1091 headings.each do |level, anchor, item|
1094 if level > current
1092 if level > current
1095 out << '<ul><li>' * (level - current)
1093 out << '<ul><li>' * (level - current)
1096 elsif level < current
1094 elsif level < current
1097 out << "</li></ul>\n" * (current - level) + "</li><li>"
1095 out << "</li></ul>\n" * (current - level) + "</li><li>"
1098 elsif started
1096 elsif started
1099 out << '</li><li>'
1097 out << '</li><li>'
1100 end
1098 end
1101 out << "<a href=\"##{anchor}\">#{item}</a>"
1099 out << "<a href=\"##{anchor}\">#{item}</a>"
1102 current = level
1100 current = level
1103 started = true
1101 started = true
1104 end
1102 end
1105 out << '</li></ul>' * (current - root)
1103 out << '</li></ul>' * (current - root)
1106 out << '</li></ul>'
1104 out << '</li></ul>'
1107 end
1105 end
1108 end
1106 end
1109 end
1107 end
1110
1108
1111 # Same as Rails' simple_format helper without using paragraphs
1109 # Same as Rails' simple_format helper without using paragraphs
1112 def simple_format_without_paragraph(text)
1110 def simple_format_without_paragraph(text)
1113 text.to_s.
1111 text.to_s.
1114 gsub(/\r\n?/, "\n"). # \r\n and \r -> \n
1112 gsub(/\r\n?/, "\n"). # \r\n and \r -> \n
1115 gsub(/\n\n+/, "<br /><br />"). # 2+ newline -> 2 br
1113 gsub(/\n\n+/, "<br /><br />"). # 2+ newline -> 2 br
1116 gsub(/([^\n]\n)(?=[^\n])/, '\1<br />'). # 1 newline -> br
1114 gsub(/([^\n]\n)(?=[^\n])/, '\1<br />'). # 1 newline -> br
1117 html_safe
1115 html_safe
1118 end
1116 end
1119
1117
1120 def lang_options_for_select(blank=true)
1118 def lang_options_for_select(blank=true)
1121 (blank ? [["(auto)", ""]] : []) + languages_options
1119 (blank ? [["(auto)", ""]] : []) + languages_options
1122 end
1120 end
1123
1121
1124 def labelled_form_for(*args, &proc)
1122 def labelled_form_for(*args, &proc)
1125 args << {} unless args.last.is_a?(Hash)
1123 args << {} unless args.last.is_a?(Hash)
1126 options = args.last
1124 options = args.last
1127 if args.first.is_a?(Symbol)
1125 if args.first.is_a?(Symbol)
1128 options.merge!(:as => args.shift)
1126 options.merge!(:as => args.shift)
1129 end
1127 end
1130 options.merge!({:builder => Redmine::Views::LabelledFormBuilder})
1128 options.merge!({:builder => Redmine::Views::LabelledFormBuilder})
1131 form_for(*args, &proc)
1129 form_for(*args, &proc)
1132 end
1130 end
1133
1131
1134 def labelled_fields_for(*args, &proc)
1132 def labelled_fields_for(*args, &proc)
1135 args << {} unless args.last.is_a?(Hash)
1133 args << {} unless args.last.is_a?(Hash)
1136 options = args.last
1134 options = args.last
1137 options.merge!({:builder => Redmine::Views::LabelledFormBuilder})
1135 options.merge!({:builder => Redmine::Views::LabelledFormBuilder})
1138 fields_for(*args, &proc)
1136 fields_for(*args, &proc)
1139 end
1137 end
1140
1138
1141 # Render the error messages for the given objects
1139 # Render the error messages for the given objects
1142 def error_messages_for(*objects)
1140 def error_messages_for(*objects)
1143 objects = objects.map {|o| o.is_a?(String) ? instance_variable_get("@#{o}") : o}.compact
1141 objects = objects.map {|o| o.is_a?(String) ? instance_variable_get("@#{o}") : o}.compact
1144 errors = objects.map {|o| o.errors.full_messages}.flatten
1142 errors = objects.map {|o| o.errors.full_messages}.flatten
1145 render_error_messages(errors)
1143 render_error_messages(errors)
1146 end
1144 end
1147
1145
1148 # Renders a list of error messages
1146 # Renders a list of error messages
1149 def render_error_messages(errors)
1147 def render_error_messages(errors)
1150 html = ""
1148 html = ""
1151 if errors.present?
1149 if errors.present?
1152 html << "<div id='errorExplanation'><ul>\n"
1150 html << "<div id='errorExplanation'><ul>\n"
1153 errors.each do |error|
1151 errors.each do |error|
1154 html << "<li>#{h error}</li>\n"
1152 html << "<li>#{h error}</li>\n"
1155 end
1153 end
1156 html << "</ul></div>\n"
1154 html << "</ul></div>\n"
1157 end
1155 end
1158 html.html_safe
1156 html.html_safe
1159 end
1157 end
1160
1158
1161 def delete_link(url, options={})
1159 def delete_link(url, options={})
1162 options = {
1160 options = {
1163 :method => :delete,
1161 :method => :delete,
1164 :data => {:confirm => l(:text_are_you_sure)},
1162 :data => {:confirm => l(:text_are_you_sure)},
1165 :class => 'icon icon-del'
1163 :class => 'icon icon-del'
1166 }.merge(options)
1164 }.merge(options)
1167
1165
1168 link_to l(:button_delete), url, options
1166 link_to l(:button_delete), url, options
1169 end
1167 end
1170
1168
1171 def preview_link(url, form, target='preview', options={})
1169 def preview_link(url, form, target='preview', options={})
1172 content_tag 'a', l(:label_preview), {
1170 content_tag 'a', l(:label_preview), {
1173 :href => "#",
1171 :href => "#",
1174 :onclick => %|submitPreview("#{escape_javascript url_for(url)}", "#{escape_javascript form}", "#{escape_javascript target}"); return false;|,
1172 :onclick => %|submitPreview("#{escape_javascript url_for(url)}", "#{escape_javascript form}", "#{escape_javascript target}"); return false;|,
1175 :accesskey => accesskey(:preview)
1173 :accesskey => accesskey(:preview)
1176 }.merge(options)
1174 }.merge(options)
1177 end
1175 end
1178
1176
1179 def link_to_function(name, function, html_options={})
1177 def link_to_function(name, function, html_options={})
1180 content_tag(:a, name, {:href => '#', :onclick => "#{function}; return false;"}.merge(html_options))
1178 content_tag(:a, name, {:href => '#', :onclick => "#{function}; return false;"}.merge(html_options))
1181 end
1179 end
1182
1180
1183 # Helper to render JSON in views
1181 # Helper to render JSON in views
1184 def raw_json(arg)
1182 def raw_json(arg)
1185 arg.to_json.to_s.gsub('/', '\/').html_safe
1183 arg.to_json.to_s.gsub('/', '\/').html_safe
1186 end
1184 end
1187
1185
1188 def back_url
1186 def back_url
1189 url = params[:back_url]
1187 url = params[:back_url]
1190 if url.nil? && referer = request.env['HTTP_REFERER']
1188 if url.nil? && referer = request.env['HTTP_REFERER']
1191 url = CGI.unescape(referer.to_s)
1189 url = CGI.unescape(referer.to_s)
1192 # URLs that contains the utf8=[checkmark] parameter added by Rails are
1190 # URLs that contains the utf8=[checkmark] parameter added by Rails are
1193 # parsed as invalid by URI.parse so the redirect to the back URL would
1191 # parsed as invalid by URI.parse so the redirect to the back URL would
1194 # not be accepted (ApplicationController#validate_back_url would return
1192 # not be accepted (ApplicationController#validate_back_url would return
1195 # false)
1193 # false)
1196 url.gsub!(/(\?|&)utf8=\u2713&?/, '\1')
1194 url.gsub!(/(\?|&)utf8=\u2713&?/, '\1')
1197 end
1195 end
1198 url
1196 url
1199 end
1197 end
1200
1198
1201 def back_url_hidden_field_tag
1199 def back_url_hidden_field_tag
1202 url = back_url
1200 url = back_url
1203 hidden_field_tag('back_url', url, :id => nil) unless url.blank?
1201 hidden_field_tag('back_url', url, :id => nil) unless url.blank?
1204 end
1202 end
1205
1203
1206 def check_all_links(form_name)
1204 def check_all_links(form_name)
1207 link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") +
1205 link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") +
1208 " | ".html_safe +
1206 " | ".html_safe +
1209 link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)")
1207 link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)")
1210 end
1208 end
1211
1209
1212 def toggle_checkboxes_link(selector)
1210 def toggle_checkboxes_link(selector)
1213 link_to_function '',
1211 link_to_function '',
1214 "toggleCheckboxesBySelector('#{selector}')",
1212 "toggleCheckboxesBySelector('#{selector}')",
1215 :title => "#{l(:button_check_all)} / #{l(:button_uncheck_all)}",
1213 :title => "#{l(:button_check_all)} / #{l(:button_uncheck_all)}",
1216 :class => 'toggle-checkboxes'
1214 :class => 'toggle-checkboxes'
1217 end
1215 end
1218
1216
1219 def progress_bar(pcts, options={})
1217 def progress_bar(pcts, options={})
1220 pcts = [pcts, pcts] unless pcts.is_a?(Array)
1218 pcts = [pcts, pcts] unless pcts.is_a?(Array)
1221 pcts = pcts.collect(&:round)
1219 pcts = pcts.collect(&:round)
1222 pcts[1] = pcts[1] - pcts[0]
1220 pcts[1] = pcts[1] - pcts[0]
1223 pcts << (100 - pcts[1] - pcts[0])
1221 pcts << (100 - pcts[1] - pcts[0])
1224 titles = options[:titles].to_a
1222 titles = options[:titles].to_a
1225 titles[0] = "#{pcts[0]}%" if titles[0].blank?
1223 titles[0] = "#{pcts[0]}%" if titles[0].blank?
1226 legend = options[:legend] || ''
1224 legend = options[:legend] || ''
1227 content_tag('table',
1225 content_tag('table',
1228 content_tag('tr',
1226 content_tag('tr',
1229 (pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0]}%;", :class => 'closed', :title => titles[0]) : ''.html_safe) +
1227 (pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0]}%;", :class => 'closed', :title => titles[0]) : ''.html_safe) +
1230 (pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1]}%;", :class => 'done', :title => titles[1]) : ''.html_safe) +
1228 (pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1]}%;", :class => 'done', :title => titles[1]) : ''.html_safe) +
1231 (pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2]}%;", :class => 'todo', :title => titles[2]) : ''.html_safe)
1229 (pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2]}%;", :class => 'todo', :title => titles[2]) : ''.html_safe)
1232 ), :class => "progress progress-#{pcts[0]}").html_safe +
1230 ), :class => "progress progress-#{pcts[0]}").html_safe +
1233 content_tag('p', legend, :class => 'percent').html_safe
1231 content_tag('p', legend, :class => 'percent').html_safe
1234 end
1232 end
1235
1233
1236 def checked_image(checked=true)
1234 def checked_image(checked=true)
1237 if checked
1235 if checked
1238 @checked_image_tag ||= content_tag(:span, nil, :class => 'icon-only icon-checked')
1236 @checked_image_tag ||= content_tag(:span, nil, :class => 'icon-only icon-checked')
1239 end
1237 end
1240 end
1238 end
1241
1239
1242 def context_menu
1240 def context_menu
1243 unless @context_menu_included
1241 unless @context_menu_included
1244 content_for :header_tags do
1242 content_for :header_tags do
1245 javascript_include_tag('context_menu') +
1243 javascript_include_tag('context_menu') +
1246 stylesheet_link_tag('context_menu')
1244 stylesheet_link_tag('context_menu')
1247 end
1245 end
1248 if l(:direction) == 'rtl'
1246 if l(:direction) == 'rtl'
1249 content_for :header_tags do
1247 content_for :header_tags do
1250 stylesheet_link_tag('context_menu_rtl')
1248 stylesheet_link_tag('context_menu_rtl')
1251 end
1249 end
1252 end
1250 end
1253 @context_menu_included = true
1251 @context_menu_included = true
1254 end
1252 end
1255 nil
1253 nil
1256 end
1254 end
1257
1255
1258 def calendar_for(field_id)
1256 def calendar_for(field_id)
1259 include_calendar_headers_tags
1257 include_calendar_headers_tags
1260 javascript_tag("$(function() { $('##{field_id}').addClass('date').datepickerFallback(datepickerOptions); });")
1258 javascript_tag("$(function() { $('##{field_id}').addClass('date').datepickerFallback(datepickerOptions); });")
1261 end
1259 end
1262
1260
1263 def include_calendar_headers_tags
1261 def include_calendar_headers_tags
1264 unless @calendar_headers_tags_included
1262 unless @calendar_headers_tags_included
1265 tags = ''.html_safe
1263 tags = ''.html_safe
1266 @calendar_headers_tags_included = true
1264 @calendar_headers_tags_included = true
1267 content_for :header_tags do
1265 content_for :header_tags do
1268 start_of_week = Setting.start_of_week
1266 start_of_week = Setting.start_of_week
1269 start_of_week = l(:general_first_day_of_week, :default => '1') if start_of_week.blank?
1267 start_of_week = l(:general_first_day_of_week, :default => '1') if start_of_week.blank?
1270 # Redmine uses 1..7 (monday..sunday) in settings and locales
1268 # Redmine uses 1..7 (monday..sunday) in settings and locales
1271 # JQuery uses 0..6 (sunday..saturday), 7 needs to be changed to 0
1269 # JQuery uses 0..6 (sunday..saturday), 7 needs to be changed to 0
1272 start_of_week = start_of_week.to_i % 7
1270 start_of_week = start_of_week.to_i % 7
1273 tags << javascript_tag(
1271 tags << javascript_tag(
1274 "var datepickerOptions={dateFormat: 'yy-mm-dd', firstDay: #{start_of_week}, " +
1272 "var datepickerOptions={dateFormat: 'yy-mm-dd', firstDay: #{start_of_week}, " +
1275 "showOn: 'button', buttonImageOnly: true, buttonImage: '" +
1273 "showOn: 'button', buttonImageOnly: true, buttonImage: '" +
1276 path_to_image('/images/calendar.png') +
1274 path_to_image('/images/calendar.png') +
1277 "', showButtonPanel: true, showWeek: true, showOtherMonths: true, " +
1275 "', showButtonPanel: true, showWeek: true, showOtherMonths: true, " +
1278 "selectOtherMonths: true, changeMonth: true, changeYear: true, " +
1276 "selectOtherMonths: true, changeMonth: true, changeYear: true, " +
1279 "beforeShow: beforeShowDatePicker};")
1277 "beforeShow: beforeShowDatePicker};")
1280 jquery_locale = l('jquery.locale', :default => current_language.to_s)
1278 jquery_locale = l('jquery.locale', :default => current_language.to_s)
1281 unless jquery_locale == 'en'
1279 unless jquery_locale == 'en'
1282 tags << javascript_include_tag("i18n/datepicker-#{jquery_locale}.js")
1280 tags << javascript_include_tag("i18n/datepicker-#{jquery_locale}.js")
1283 end
1281 end
1284 tags
1282 tags
1285 end
1283 end
1286 end
1284 end
1287 end
1285 end
1288
1286
1289 # Overrides Rails' stylesheet_link_tag with themes and plugins support.
1287 # Overrides Rails' stylesheet_link_tag with themes and plugins support.
1290 # Examples:
1288 # Examples:
1291 # stylesheet_link_tag('styles') # => picks styles.css from the current theme or defaults
1289 # stylesheet_link_tag('styles') # => picks styles.css from the current theme or defaults
1292 # stylesheet_link_tag('styles', :plugin => 'foo) # => picks styles.css from plugin's assets
1290 # stylesheet_link_tag('styles', :plugin => 'foo) # => picks styles.css from plugin's assets
1293 #
1291 #
1294 def stylesheet_link_tag(*sources)
1292 def stylesheet_link_tag(*sources)
1295 options = sources.last.is_a?(Hash) ? sources.pop : {}
1293 options = sources.last.is_a?(Hash) ? sources.pop : {}
1296 plugin = options.delete(:plugin)
1294 plugin = options.delete(:plugin)
1297 sources = sources.map do |source|
1295 sources = sources.map do |source|
1298 if plugin
1296 if plugin
1299 "/plugin_assets/#{plugin}/stylesheets/#{source}"
1297 "/plugin_assets/#{plugin}/stylesheets/#{source}"
1300 elsif current_theme && current_theme.stylesheets.include?(source)
1298 elsif current_theme && current_theme.stylesheets.include?(source)
1301 current_theme.stylesheet_path(source)
1299 current_theme.stylesheet_path(source)
1302 else
1300 else
1303 source
1301 source
1304 end
1302 end
1305 end
1303 end
1306 super *sources, options
1304 super *sources, options
1307 end
1305 end
1308
1306
1309 # Overrides Rails' image_tag with themes and plugins support.
1307 # Overrides Rails' image_tag with themes and plugins support.
1310 # Examples:
1308 # Examples:
1311 # image_tag('image.png') # => picks image.png from the current theme or defaults
1309 # image_tag('image.png') # => picks image.png from the current theme or defaults
1312 # image_tag('image.png', :plugin => 'foo) # => picks image.png from plugin's assets
1310 # image_tag('image.png', :plugin => 'foo) # => picks image.png from plugin's assets
1313 #
1311 #
1314 def image_tag(source, options={})
1312 def image_tag(source, options={})
1315 if plugin = options.delete(:plugin)
1313 if plugin = options.delete(:plugin)
1316 source = "/plugin_assets/#{plugin}/images/#{source}"
1314 source = "/plugin_assets/#{plugin}/images/#{source}"
1317 elsif current_theme && current_theme.images.include?(source)
1315 elsif current_theme && current_theme.images.include?(source)
1318 source = current_theme.image_path(source)
1316 source = current_theme.image_path(source)
1319 end
1317 end
1320 super source, options
1318 super source, options
1321 end
1319 end
1322
1320
1323 # Overrides Rails' javascript_include_tag with plugins support
1321 # Overrides Rails' javascript_include_tag with plugins support
1324 # Examples:
1322 # Examples:
1325 # javascript_include_tag('scripts') # => picks scripts.js from defaults
1323 # javascript_include_tag('scripts') # => picks scripts.js from defaults
1326 # javascript_include_tag('scripts', :plugin => 'foo) # => picks scripts.js from plugin's assets
1324 # javascript_include_tag('scripts', :plugin => 'foo) # => picks scripts.js from plugin's assets
1327 #
1325 #
1328 def javascript_include_tag(*sources)
1326 def javascript_include_tag(*sources)
1329 options = sources.last.is_a?(Hash) ? sources.pop : {}
1327 options = sources.last.is_a?(Hash) ? sources.pop : {}
1330 if plugin = options.delete(:plugin)
1328 if plugin = options.delete(:plugin)
1331 sources = sources.map do |source|
1329 sources = sources.map do |source|
1332 if plugin
1330 if plugin
1333 "/plugin_assets/#{plugin}/javascripts/#{source}"
1331 "/plugin_assets/#{plugin}/javascripts/#{source}"
1334 else
1332 else
1335 source
1333 source
1336 end
1334 end
1337 end
1335 end
1338 end
1336 end
1339 super *sources, options
1337 super *sources, options
1340 end
1338 end
1341
1339
1342 def sidebar_content?
1340 def sidebar_content?
1343 content_for?(:sidebar) || view_layouts_base_sidebar_hook_response.present?
1341 content_for?(:sidebar) || view_layouts_base_sidebar_hook_response.present?
1344 end
1342 end
1345
1343
1346 def view_layouts_base_sidebar_hook_response
1344 def view_layouts_base_sidebar_hook_response
1347 @view_layouts_base_sidebar_hook_response ||= call_hook(:view_layouts_base_sidebar)
1345 @view_layouts_base_sidebar_hook_response ||= call_hook(:view_layouts_base_sidebar)
1348 end
1346 end
1349
1347
1350 def email_delivery_enabled?
1348 def email_delivery_enabled?
1351 !!ActionMailer::Base.perform_deliveries
1349 !!ActionMailer::Base.perform_deliveries
1352 end
1350 end
1353
1351
1354 # Returns the avatar image tag for the given +user+ if avatars are enabled
1352 # Returns the avatar image tag for the given +user+ if avatars are enabled
1355 # +user+ can be a User or a string that will be scanned for an email address (eg. 'joe <joe@foo.bar>')
1353 # +user+ can be a User or a string that will be scanned for an email address (eg. 'joe <joe@foo.bar>')
1356 def avatar(user, options = { })
1354 def avatar(user, options = { })
1357 if Setting.gravatar_enabled?
1355 if Setting.gravatar_enabled?
1358 options.merge!(:default => Setting.gravatar_default)
1356 options.merge!(:default => Setting.gravatar_default)
1359 email = nil
1357 email = nil
1360 if user.respond_to?(:mail)
1358 if user.respond_to?(:mail)
1361 email = user.mail
1359 email = user.mail
1362 elsif user.to_s =~ %r{<(.+?)>}
1360 elsif user.to_s =~ %r{<(.+?)>}
1363 email = $1
1361 email = $1
1364 end
1362 end
1365 return gravatar(email.to_s.downcase, options) unless email.blank? rescue nil
1363 return gravatar(email.to_s.downcase, options) unless email.blank? rescue nil
1366 else
1364 else
1367 ''
1365 ''
1368 end
1366 end
1369 end
1367 end
1370
1368
1371 # Returns a link to edit user's avatar if avatars are enabled
1369 # Returns a link to edit user's avatar if avatars are enabled
1372 def avatar_edit_link(user, options={})
1370 def avatar_edit_link(user, options={})
1373 if Setting.gravatar_enabled?
1371 if Setting.gravatar_enabled?
1374 url = "https://gravatar.com"
1372 url = "https://gravatar.com"
1375 link_to avatar(user, {:title => l(:button_edit)}.merge(options)), url, :target => '_blank'
1373 link_to avatar(user, {:title => l(:button_edit)}.merge(options)), url, :target => '_blank'
1376 end
1374 end
1377 end
1375 end
1378
1376
1379 def sanitize_anchor_name(anchor)
1377 def sanitize_anchor_name(anchor)
1380 anchor.gsub(%r{[^\s\-\p{Word}]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
1378 anchor.gsub(%r{[^\s\-\p{Word}]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
1381 end
1379 end
1382
1380
1383 # Returns the javascript tags that are included in the html layout head
1381 # Returns the javascript tags that are included in the html layout head
1384 def javascript_heads
1382 def javascript_heads
1385 tags = javascript_include_tag('jquery-1.11.1-ui-1.11.0-ujs-3.1.4', 'application', 'responsive')
1383 tags = javascript_include_tag('jquery-1.11.1-ui-1.11.0-ujs-3.1.4', 'application', 'responsive')
1386 unless User.current.pref.warn_on_leaving_unsaved == '0'
1384 unless User.current.pref.warn_on_leaving_unsaved == '0'
1387 tags << "\n".html_safe + javascript_tag("$(window).load(function(){ warnLeavingUnsaved('#{escape_javascript l(:text_warn_on_leaving_unsaved)}'); });")
1385 tags << "\n".html_safe + javascript_tag("$(window).load(function(){ warnLeavingUnsaved('#{escape_javascript l(:text_warn_on_leaving_unsaved)}'); });")
1388 end
1386 end
1389 tags
1387 tags
1390 end
1388 end
1391
1389
1392 def favicon
1390 def favicon
1393 "<link rel='shortcut icon' href='#{favicon_path}' />".html_safe
1391 "<link rel='shortcut icon' href='#{favicon_path}' />".html_safe
1394 end
1392 end
1395
1393
1396 # Returns the path to the favicon
1394 # Returns the path to the favicon
1397 def favicon_path
1395 def favicon_path
1398 icon = (current_theme && current_theme.favicon?) ? current_theme.favicon_path : '/favicon.ico'
1396 icon = (current_theme && current_theme.favicon?) ? current_theme.favicon_path : '/favicon.ico'
1399 image_path(icon)
1397 image_path(icon)
1400 end
1398 end
1401
1399
1402 # Returns the full URL to the favicon
1400 # Returns the full URL to the favicon
1403 def favicon_url
1401 def favicon_url
1404 # TODO: use #image_url introduced in Rails4
1402 # TODO: use #image_url introduced in Rails4
1405 path = favicon_path
1403 path = favicon_path
1406 base = url_for(:controller => 'welcome', :action => 'index', :only_path => false)
1404 base = url_for(:controller => 'welcome', :action => 'index', :only_path => false)
1407 base.sub(%r{/+$},'') + '/' + path.sub(%r{^/+},'')
1405 base.sub(%r{/+$},'') + '/' + path.sub(%r{^/+},'')
1408 end
1406 end
1409
1407
1410 def robot_exclusion_tag
1408 def robot_exclusion_tag
1411 '<meta name="robots" content="noindex,follow,noarchive" />'.html_safe
1409 '<meta name="robots" content="noindex,follow,noarchive" />'.html_safe
1412 end
1410 end
1413
1411
1414 # Returns true if arg is expected in the API response
1412 # Returns true if arg is expected in the API response
1415 def include_in_api_response?(arg)
1413 def include_in_api_response?(arg)
1416 unless @included_in_api_response
1414 unless @included_in_api_response
1417 param = params[:include]
1415 param = params[:include]
1418 @included_in_api_response = param.is_a?(Array) ? param.collect(&:to_s) : param.to_s.split(',')
1416 @included_in_api_response = param.is_a?(Array) ? param.collect(&:to_s) : param.to_s.split(',')
1419 @included_in_api_response.collect!(&:strip)
1417 @included_in_api_response.collect!(&:strip)
1420 end
1418 end
1421 @included_in_api_response.include?(arg.to_s)
1419 @included_in_api_response.include?(arg.to_s)
1422 end
1420 end
1423
1421
1424 # Returns options or nil if nometa param or X-Redmine-Nometa header
1422 # Returns options or nil if nometa param or X-Redmine-Nometa header
1425 # was set in the request
1423 # was set in the request
1426 def api_meta(options)
1424 def api_meta(options)
1427 if params[:nometa].present? || request.headers['X-Redmine-Nometa']
1425 if params[:nometa].present? || request.headers['X-Redmine-Nometa']
1428 # compatibility mode for activeresource clients that raise
1426 # compatibility mode for activeresource clients that raise
1429 # an error when deserializing an array with attributes
1427 # an error when deserializing an array with attributes
1430 nil
1428 nil
1431 else
1429 else
1432 options
1430 options
1433 end
1431 end
1434 end
1432 end
1435
1433
1436 def generate_csv(&block)
1434 def generate_csv(&block)
1437 decimal_separator = l(:general_csv_decimal_separator)
1435 decimal_separator = l(:general_csv_decimal_separator)
1438 encoding = l(:general_csv_encoding)
1436 encoding = l(:general_csv_encoding)
1439 end
1437 end
1440
1438
1441 private
1439 private
1442
1440
1443 def wiki_helper
1441 def wiki_helper
1444 helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting)
1442 helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting)
1445 extend helper
1443 extend helper
1446 return self
1444 return self
1447 end
1445 end
1448 end
1446 end
@@ -1,1459 +1,1462
1 html {overflow-y:scroll;}
1 html {overflow-y:scroll;}
2 body { font-family: Verdana, sans-serif; font-size: 12px; color:#333; margin: 0; padding: 0; min-width: 900px; }
2 body { font-family: Verdana, sans-serif; font-size: 12px; color:#333; margin: 0; padding: 0; min-width: 900px; }
3
3
4 h1, h2, h3, h4 {font-family: "Trebuchet MS", Verdana, sans-serif;padding: 2px 10px 1px 0px;margin: 0 0 10px 0;}
4 h1, h2, h3, h4 {font-family: "Trebuchet MS", Verdana, sans-serif;padding: 2px 10px 1px 0px;margin: 0 0 10px 0;}
5 #content h1, h2, h3, h4 {color: #555;}
5 #content h1, h2, h3, h4 {color: #555;}
6 h2, .wiki h1 {font-size: 20px;}
6 h2, .wiki h1 {font-size: 20px;}
7 h3, .wiki h2 {font-size: 16px;}
7 h3, .wiki h2 {font-size: 16px;}
8 h4, .wiki h3 {font-size: 13px;}
8 h4, .wiki h3 {font-size: 13px;}
9 h4 {border-bottom: 1px dotted #bbb;}
9 h4 {border-bottom: 1px dotted #bbb;}
10 pre, code {font-family: Consolas, Menlo, "Liberation Mono", Courier, monospace;}
10 pre, code {font-family: Consolas, Menlo, "Liberation Mono", Courier, monospace;}
11
11
12 /***** Layout *****/
12 /***** Layout *****/
13 #wrapper {background: white;overflow: hidden;}
13 #wrapper {background: white;overflow: hidden;}
14
14
15 #top-menu {background: #3E5B76; color: #fff; height:1.8em; font-size: 0.8em; padding: 2px 2px 0px 6px;}
15 #top-menu {background: #3E5B76; color: #fff; height:1.8em; font-size: 0.8em; padding: 2px 2px 0px 6px;}
16 #top-menu ul {margin: 0; padding: 0;}
16 #top-menu ul {margin: 0; padding: 0;}
17 #top-menu li {
17 #top-menu li {
18 float:left;
18 float:left;
19 list-style-type:none;
19 list-style-type:none;
20 margin: 0px 0px 0px 0px;
20 margin: 0px 0px 0px 0px;
21 padding: 0px 0px 0px 0px;
21 padding: 0px 0px 0px 0px;
22 white-space:nowrap;
22 white-space:nowrap;
23 }
23 }
24 #top-menu a {color: #fff; margin-right: 8px; font-weight: bold;}
24 #top-menu a {color: #fff; margin-right: 8px; font-weight: bold;}
25 #top-menu #loggedas { float: right; margin-right: 0.5em; color: #fff; }
25 #top-menu #loggedas { float: right; margin-right: 0.5em; color: #fff; }
26
26
27 #account {float:right;}
27 #account {float:right;}
28
28
29 #header {min-height:5.3em;margin:0;background-color:#628DB6;color:#f8f8f8; padding: 4px 8px 20px 6px; position:relative;}
29 #header {min-height:5.3em;margin:0;background-color:#628DB6;color:#f8f8f8; padding: 4px 8px 20px 6px; position:relative;}
30 #header a {color:#f8f8f8;}
30 #header a {color:#f8f8f8;}
31 #header h1 { overflow: hidden; text-overflow: ellipsis; white-space: nowrap;}
31 #header h1 { overflow: hidden; text-overflow: ellipsis; white-space: nowrap;}
32 #header h1 .breadcrumbs { display:block; font-size: .5em; font-weight: normal; }
32 #header h1 .breadcrumbs { display:block; font-size: .5em; font-weight: normal; }
33
33
34 #quick-search {float:right;}
34 #quick-search {float:right;}
35 #quick-search #q {width:130px; height:24px; box-sizing:border-box; vertical-align:middle; border:1px solid #ccc; border-radius:3px;}
35 #quick-search #q {width:130px; height:24px; box-sizing:border-box; vertical-align:middle; border:1px solid #ccc; border-radius:3px;}
36
36
37 #main-menu {position: absolute; bottom: 0px; left:6px; margin-right: -500px; width: 100%;}
37 #main-menu {position: absolute; bottom: 0px; left:6px; margin-right: -500px; width: 100%;}
38 #main-menu ul {margin: 0; padding: 0; width: 100%; white-space: nowrap;}
38 #main-menu ul {margin: 0; padding: 0; width: 100%; white-space: nowrap;}
39 #main-menu li {
39 #main-menu li {
40 float:none;
40 float:none;
41 list-style-type:none;
41 list-style-type:none;
42 margin: 0px 2px 0px 0px;
42 margin: 0px 2px 0px 0px;
43 padding: 0px 0px 0px 0px;
43 padding: 0px 0px 0px 0px;
44 white-space:nowrap;
44 white-space:nowrap;
45 display:inline-block;
45 display:inline-block;
46 }
46 }
47 #main-menu li a {
47 #main-menu li a {
48 display: block;
48 display: block;
49 color: #fff;
49 color: #fff;
50 text-decoration: none;
50 text-decoration: none;
51 font-weight: bold;
51 font-weight: bold;
52 margin: 0;
52 margin: 0;
53 padding: 4px 10px 4px 10px;
53 padding: 4px 10px 4px 10px;
54 }
54 }
55 #main-menu li a:hover {background:#759FCF; color:#fff;}
55 #main-menu li a:hover {background:#759FCF; color:#fff;}
56 #main-menu li:hover ul.menu-children, #main-menu li ul.menu-children.visible {display: block;}
56 #main-menu li:hover ul.menu-children, #main-menu li ul.menu-children.visible {display: block;}
57 #main-menu li a.selected, #main-menu li a.selected:hover {background:#fff; color:#555;}
57 #main-menu li a.selected, #main-menu li a.selected:hover {background:#fff; color:#555;}
58 #main-menu li a.new-object { background-color:#759FCF; }
58 #main-menu li a.new-object { background-color:#759FCF; }
59
59
60 #main-menu .menu-children {
60 #main-menu .menu-children {
61 display: none;
61 display: none;
62 position:absolute;
62 position:absolute;
63 width: inherit;
63 width: inherit;
64 z-index:45;
64 z-index:45;
65 background-color:#fff;
65 background-color:#fff;
66 border-right: 1px solid #759FCF;
66 border-right: 1px solid #759FCF;
67 border-bottom: 1px solid #759FCF;
67 border-bottom: 1px solid #759FCF;
68 border-left: 1px solid #759FCF;
68 border-left: 1px solid #759FCF;
69 }
69 }
70 #main-menu .menu-children li {float:left; clear:both; width:100%;}
70 #main-menu .menu-children li {float:left; clear:both; width:100%;}
71 #main-menu .menu-children li a {color: #555; background-color:#fff; font-weight:normal;}
71 #main-menu .menu-children li a {color: #555; background-color:#fff; font-weight:normal;}
72 #main-menu .menu-children li a:hover {color: #fff; background-color: #759FCF;}
72 #main-menu .menu-children li a:hover {color: #fff; background-color: #759FCF;}
73
73
74 #main-menu .tabs-buttons {
74 #main-menu .tabs-buttons {
75 right: 6px;
75 right: 6px;
76 background-color: transparent;
76 background-color: transparent;
77 border-bottom-color: transparent;
77 border-bottom-color: transparent;
78 }
78 }
79
79
80 #admin-menu ul {margin: 0; padding: 0;}
80 #admin-menu ul {margin: 0; padding: 0;}
81 #admin-menu li {margin: 0; padding: 0 0 6px 0; list-style-type:none;}
81 #admin-menu li {margin: 0; padding: 0 0 6px 0; list-style-type:none;}
82
82
83 #main {background-color:#EEEEEE;}
83 #main {background-color:#EEEEEE;}
84
84
85 #sidebar{ float: right; width: 22%; position: relative; z-index: 9; padding: 0; margin: 0;}
85 #sidebar{ float: right; width: 22%; position: relative; z-index: 9; padding: 0; margin: 0;}
86 * html #sidebar{ width: 22%; }
86 * html #sidebar{ width: 22%; }
87 #sidebar h3{ font-size: 14px; margin-top:14px; color: #666; }
87 #sidebar h3{ font-size: 14px; margin-top:14px; color: #666; }
88 #sidebar hr{ width: 100%; margin: 0 auto; height: 1px; background: #ccc; border: 0; }
88 #sidebar hr{ width: 100%; margin: 0 auto; height: 1px; background: #ccc; border: 0; }
89 * html #sidebar hr{ width: 95%; position: relative; left: -6px; color: #ccc; }
89 * html #sidebar hr{ width: 95%; position: relative; left: -6px; color: #ccc; }
90 #sidebar .contextual { margin-right: 1em; }
90 #sidebar .contextual { margin-right: 1em; }
91 #sidebar ul, ul.flat {margin: 0; padding: 0;}
91 #sidebar ul, ul.flat {margin: 0; padding: 0;}
92 #sidebar ul li, ul.flat li {list-style-type:none;margin: 0px 2px 0px 0px; padding: 0px 0px 0px 0px;}
92 #sidebar ul li, ul.flat li {list-style-type:none;margin: 0px 2px 0px 0px; padding: 0px 0px 0px 0px;}
93 #sidebar div.wiki ul {margin:inherit; padding-left:40px;}
93 #sidebar div.wiki ul {margin:inherit; padding-left:40px;}
94 #sidebar div.wiki ul li {list-style-type:inherit;}
94 #sidebar div.wiki ul li {list-style-type:inherit;}
95
95
96 #content { width: 75%; background-color: #fff; margin: 0px; border-right: 1px solid #ddd; padding: 6px 10px 10px 10px; z-index: 10; }
96 #content { width: 75%; background-color: #fff; margin: 0px; border-right: 1px solid #ddd; padding: 6px 10px 10px 10px; z-index: 10; }
97 * html #content{ width: 75%; padding-left: 0; margin-top: 0px; padding: 6px 10px 10px 10px;}
97 * html #content{ width: 75%; padding-left: 0; margin-top: 0px; padding: 6px 10px 10px 10px;}
98 html>body #content { min-height: 600px; }
98 html>body #content { min-height: 600px; }
99 * html body #content { height: 600px; } /* IE */
99 * html body #content { height: 600px; } /* IE */
100
100
101 #main.nosidebar #sidebar{ display: none; }
101 #main.nosidebar #sidebar{ display: none; }
102 #main.nosidebar #content{ width: auto; border-right: 0; }
102 #main.nosidebar #content{ width: auto; border-right: 0; }
103
103
104 #footer {clear: both; border-top: 1px solid #bbb; font-size: 0.9em; color: #aaa; padding: 5px; text-align:center; background:#fff;}
104 #footer {clear: both; border-top: 1px solid #bbb; font-size: 0.9em; color: #aaa; padding: 5px; text-align:center; background:#fff;}
105
105
106 #login-form {margin:5em auto 2em auto; padding:20px; width:340px; border:1px solid #FDBF3B; background-color:#FFEBC1; border-radius:4px; box-sizing: border-box;}
106 #login-form {margin:5em auto 2em auto; padding:20px; width:340px; border:1px solid #FDBF3B; background-color:#FFEBC1; border-radius:4px; box-sizing: border-box;}
107 #login-form label {display:block; margin-bottom:5px;}
107 #login-form label {display:block; margin-bottom:5px;}
108 #login-form input[type=text], #login-form input[type=password] {border:1px solid #ccc; border-radius:3px; margin-bottom:15px; padding:7px; display:block; width:100%; box-sizing: border-box;}
108 #login-form input[type=text], #login-form input[type=password] {border:1px solid #ccc; border-radius:3px; margin-bottom:15px; padding:7px; display:block; width:100%; box-sizing: border-box;}
109 #login-form label {font-weight:bold;}
109 #login-form label {font-weight:bold;}
110 #login-form label[for=autologin] {font-weight:normal;}
110 #login-form label[for=autologin] {font-weight:normal;}
111 #login-form a.lost_password {float:right; font-weight:normal;}
111 #login-form a.lost_password {float:right; font-weight:normal;}
112 #login-form input#openid_url {background:#fff url(../images/openid-bg.gif) no-repeat 4px 50%; padding-left:24px !important;}
112 #login-form input#openid_url {background:#fff url(../images/openid-bg.gif) no-repeat 4px 50%; padding-left:24px !important;}
113 #login-form input#login-submit {margin-top:15px; padding:7px; display:block; width:100%; box-sizing: border-box;}
113 #login-form input#login-submit {margin-top:15px; padding:7px; display:block; width:100%; box-sizing: border-box;}
114
114
115 div.modal { border-radius:5px; background:#fff; z-index:50; padding:4px;}
115 div.modal { border-radius:5px; background:#fff; z-index:50; padding:4px;}
116 div.modal h3.title {display:none;}
116 div.modal h3.title {display:none;}
117 div.modal p.buttons {text-align:right; margin-bottom:0;}
117 div.modal p.buttons {text-align:right; margin-bottom:0;}
118 div.modal .box p {margin: 0.3em 0;}
118 div.modal .box p {margin: 0.3em 0;}
119
119
120 .clear:after{ content: "."; display: block; height: 0; clear: both; visibility: hidden; }
120 .clear:after{ content: "."; display: block; height: 0; clear: both; visibility: hidden; }
121
121
122 .mobile-show {display: none;}
122 .mobile-show {display: none;}
123
123
124 /***** Links *****/
124 /***** Links *****/
125 a, a:link, a:visited{ color: #169; text-decoration: none; }
125 a, a:link, a:visited{ color: #169; text-decoration: none; }
126 a:hover, a:active{ color: #c61a1a; text-decoration: underline;}
126 a:hover, a:active{ color: #c61a1a; text-decoration: underline;}
127 a img{ border: 0; }
127 a img{ border: 0; }
128
128
129 a.issue.closed, a.issue.closed:link, a.issue.closed:visited { color: #999; text-decoration: line-through; }
129 a.issue.closed, a.issue.closed:link, a.issue.closed:visited { color: #999; text-decoration: line-through; }
130 a.project.closed, a.project.closed:link, a.project.closed:visited { color: #999; }
130 a.project.closed, a.project.closed:link, a.project.closed:visited { color: #999; }
131 a.user.locked, a.user.locked:link, a.user.locked:visited {color: #999;}
131 a.user.locked, a.user.locked:link, a.user.locked:visited {color: #999;}
132
132
133 #sidebar a.selected {line-height:1.7em; padding:1px 3px 2px 2px; margin-left:-2px; background-color:#9DB9D5; color:#fff; border-radius:2px;}
133 #sidebar a.selected {line-height:1.7em; padding:1px 3px 2px 2px; margin-left:-2px; background-color:#9DB9D5; color:#fff; border-radius:2px;}
134 #sidebar a.selected:hover {text-decoration:none;}
134 #sidebar a.selected:hover {text-decoration:none;}
135 #admin-menu a {line-height:1.7em;}
135 #admin-menu a {line-height:1.7em;}
136 #admin-menu a.selected {padding-left: 20px !important; background-position: 2px 40%;}
136 #admin-menu a.selected {padding-left: 20px !important; background-position: 2px 40%;}
137
137
138 a.collapsible {padding-left: 12px; background: url(../images/arrow_expanded.png) no-repeat -3px 40%;}
138 a.collapsible {padding-left: 12px; background: url(../images/arrow_expanded.png) no-repeat -3px 40%;}
139 a.collapsible.collapsed {background: url(../images/arrow_collapsed.png) no-repeat -5px 40%;}
139 a.collapsible.collapsed {background: url(../images/arrow_collapsed.png) no-repeat -5px 40%;}
140
140
141 a#toggle-completed-versions {color:#999;}
141 a#toggle-completed-versions {color:#999;}
142
142
143 a.toggle-checkboxes { margin-left: 5px; padding-left: 12px; background: url(../images/toggle_check.png) no-repeat 0% 50%; }
143 a.toggle-checkboxes { margin-left: 5px; padding-left: 12px; background: url(../images/toggle_check.png) no-repeat 0% 50%; }
144
144
145 /***** Dropdown *****/
145 /***** Dropdown *****/
146 .drdn {position:relative;}
146 .drdn {position:relative;}
147 .drdn-trigger {
147 .drdn-trigger {
148 width:100%;
148 width:100%;
149 height:24px;
149 height:24px;
150 box-sizing:border-box;
150 box-sizing:border-box;
151 overflow:hidden;
151 overflow:hidden;
152 text-overflow:ellipsis;
152 text-overflow:ellipsis;
153 white-space:nowrap;
153 white-space:nowrap;
154 padding:3px 18px 3px 6px;
154 padding:3px 18px 3px 6px;
155 background:#fff url(../images/sort_desc.png) no-repeat 97% 50%;
155 background:#fff url(../images/sort_desc.png) no-repeat 97% 50%;
156 cursor:pointer;
156 cursor:pointer;
157 user-select:none;
157 user-select:none;
158 -moz-user-select:none;
158 -moz-user-select:none;
159 -webkit-user-select:none;
159 -webkit-user-select:none;
160 }
160 }
161 .drdn-content {
161 .drdn-content {
162 display:none;
162 display:none;
163 position:absolute;
163 position:absolute;
164 right:0px;
164 right:0px;
165 top:25px;
165 top:25px;
166 min-width:100px;
166 min-width:100px;
167 background-color:#fff;
167 background-color:#fff;
168 border:1px solid #ccc;
168 border:1px solid #ccc;
169 border-radius:4px;
169 border-radius:4px;
170 color:#555;
170 color:#555;
171 z-index:99;
171 z-index:99;
172 }
172 }
173 .drdn.expanded .drdn-trigger {background-image:url(../images/sort_asc.png);}
173 .drdn.expanded .drdn-trigger {background-image:url(../images/sort_asc.png);}
174 .drdn.expanded .drdn-content {display:block;}
174 .drdn.expanded .drdn-content {display:block;}
175
175
176 .drdn-content .quick-search {margin:8px;}
176 .drdn-content .quick-search {margin:8px;}
177 .drdn-content .autocomplete {box-sizing: border-box; width:100% !important; height:28px;}
177 .drdn-content .autocomplete {box-sizing: border-box; width:100% !important; height:28px;}
178 .drdn-content .autocomplete:focus {border-color:#5ad;}
178 .drdn-content .autocomplete:focus {border-color:#5ad;}
179 .drdn-items {max-height:400px; overflow:auto;}
179 .drdn-items {max-height:400px; overflow:auto;}
180 div + .drdn-items {border-top:1px solid #ccc;}
180 div + .drdn-items {border-top:1px solid #ccc;}
181 .drdn-items>* {
181 .drdn-items>* {
182 display:block;
182 display:block;
183 border:1px solid #fff;
183 border:1px solid #fff;
184 color:#555 !important;
184 color:#555 !important;
185 overflow:hidden;
185 overflow:hidden;
186 text-overflow: ellipsis;
186 text-overflow: ellipsis;
187 white-space:nowrap;
187 white-space:nowrap;
188 padding:4px 8px;
188 padding:4px 8px;
189 }
189 }
190 .drdn-items>a:hover {text-decoration:none; background-color:#759FCF; color:#fff !important;}
190 .drdn-items>a:hover {text-decoration:none; background-color:#759FCF; color:#fff !important;}
191 .drdn-items>*:focus {border:1px dotted #bbb;}
191 .drdn-items>*:focus {border:1px dotted #bbb;}
192
192
193 .drdn-items.selection>*:before {
193 .drdn-items.selection>*:before {
194 content:' ';
194 content:' ';
195 display:inline-block;
195 display:inline-block;
196 line-height:1em;
196 line-height:1em;
197 width:1em;
197 width:1em;
198 height:1em;
198 height:1em;
199 margin-right:4px;
199 margin-right:4px;
200 font-weight:bold;
200 font-weight:bold;
201 }
201 }
202 .drdn-items.selection>*.selected:before {
202 .drdn-items.selection>*.selected:before {
203 content:"\2713 ";
203 content:"\2713 ";
204 }
204 }
205 .drdn-items.selection:empty {
206 border: none;
207 }
205 .drdn-items>span {color:#999;}
208 .drdn-items>span {color:#999;}
206
209
207 #project-jump.drdn {width:200px;display:inline-block;}
210 #project-jump.drdn {width:200px;display:inline-block;}
208 #project-jump .drdn-trigger {
211 #project-jump .drdn-trigger {
209 display:inline-block;
212 display:inline-block;
210 border-radius:3px;
213 border-radius:3px;
211 border:1px solid #ccc;
214 border:1px solid #ccc;
212 margin:0 !important;
215 margin:0 !important;
213 vertical-align:middle;
216 vertical-align:middle;
214 color:#555;
217 color:#555;
215 }
218 }
216 #project-jump .drdn-content {width:280px;}
219 #project-jump .drdn-content {width:280px;}
217
220
218 /***** Tables *****/
221 /***** Tables *****/
219 table.list, .table-list { border: 1px solid #e4e4e4; border-collapse: collapse; width: 100%; margin-bottom: 4px; }
222 table.list, .table-list { border: 1px solid #e4e4e4; border-collapse: collapse; width: 100%; margin-bottom: 4px; }
220 table.list th, .table-list-header { background-color:#EEEEEE; padding: 4px; white-space:nowrap; font-weight:bold; }
223 table.list th, .table-list-header { background-color:#EEEEEE; padding: 4px; white-space:nowrap; font-weight:bold; }
221 table.list td {text-align:center; vertical-align:middle; padding-right:10px;}
224 table.list td {text-align:center; vertical-align:middle; padding-right:10px;}
222 table.list td.id { width: 2%; text-align: center;}
225 table.list td.id { width: 2%; text-align: center;}
223 table.list td.name, table.list td.description, table.list td.subject, table.list td.comments, table.list td.roles {text-align: left;}
226 table.list td.name, table.list td.description, table.list td.subject, table.list td.comments, table.list td.roles {text-align: left;}
224 table.list td.tick {width:15%}
227 table.list td.tick {width:15%}
225 table.list td.checkbox { width: 15px; padding: 2px 0 0 0; }
228 table.list td.checkbox { width: 15px; padding: 2px 0 0 0; }
226 table.list td.checkbox input {padding:0px;}
229 table.list td.checkbox input {padding:0px;}
227 table.list td.buttons, div.buttons { white-space:nowrap; text-align: right; }
230 table.list td.buttons, div.buttons { white-space:nowrap; text-align: right; }
228 table.list td.buttons a, div.buttons a { margin-right: 0.6em; }
231 table.list td.buttons a, div.buttons a { margin-right: 0.6em; }
229 table.list td.buttons img, div.buttons img {vertical-align:middle;}
232 table.list td.buttons img, div.buttons img {vertical-align:middle;}
230 table.list td.reorder {width:15%; white-space:nowrap; text-align:center; }
233 table.list td.reorder {width:15%; white-space:nowrap; text-align:center; }
231 table.list table.progress td {padding-right:0px;}
234 table.list table.progress td {padding-right:0px;}
232 table.list caption { text-align: left; padding: 0.5em 0.5em 0.5em 0; }
235 table.list caption { text-align: left; padding: 0.5em 0.5em 0.5em 0; }
233 #role-permissions-trackers table.list th {white-space:normal;}
236 #role-permissions-trackers table.list th {white-space:normal;}
234
237
235 .table-list-cell {display: table-cell; vertical-align: top; padding:2px; }
238 .table-list-cell {display: table-cell; vertical-align: top; padding:2px; }
236 .table-list div.buttons {width: 15%;}
239 .table-list div.buttons {width: 15%;}
237
240
238 tr.project td.name a { white-space:nowrap; }
241 tr.project td.name a { white-space:nowrap; }
239 tr.project.closed, tr.project.archived { color: #aaa; }
242 tr.project.closed, tr.project.archived { color: #aaa; }
240 tr.project.closed a, tr.project.archived a { color: #aaa; }
243 tr.project.closed a, tr.project.archived a { color: #aaa; }
241
244
242 tr.project.idnt td.name span {background: url(../images/bullet_arrow_right.png) no-repeat 0 50%; padding-left: 16px;}
245 tr.project.idnt td.name span {background: url(../images/bullet_arrow_right.png) no-repeat 0 50%; padding-left: 16px;}
243 tr.project.idnt-1 td.name {padding-left: 0.5em;}
246 tr.project.idnt-1 td.name {padding-left: 0.5em;}
244 tr.project.idnt-2 td.name {padding-left: 2em;}
247 tr.project.idnt-2 td.name {padding-left: 2em;}
245 tr.project.idnt-3 td.name {padding-left: 3.5em;}
248 tr.project.idnt-3 td.name {padding-left: 3.5em;}
246 tr.project.idnt-4 td.name {padding-left: 5em;}
249 tr.project.idnt-4 td.name {padding-left: 5em;}
247 tr.project.idnt-5 td.name {padding-left: 6.5em;}
250 tr.project.idnt-5 td.name {padding-left: 6.5em;}
248 tr.project.idnt-6 td.name {padding-left: 8em;}
251 tr.project.idnt-6 td.name {padding-left: 8em;}
249 tr.project.idnt-7 td.name {padding-left: 9.5em;}
252 tr.project.idnt-7 td.name {padding-left: 9.5em;}
250 tr.project.idnt-8 td.name {padding-left: 11em;}
253 tr.project.idnt-8 td.name {padding-left: 11em;}
251 tr.project.idnt-9 td.name {padding-left: 12.5em;}
254 tr.project.idnt-9 td.name {padding-left: 12.5em;}
252
255
253 tr.issue { text-align: center; white-space: nowrap; }
256 tr.issue { text-align: center; white-space: nowrap; }
254 tr.issue td.subject, tr.issue td.category, td.assigned_to, tr.issue td.string, tr.issue td.text, tr.issue td.list, tr.issue td.relations, tr.issue td.parent { white-space: normal; }
257 tr.issue td.subject, tr.issue td.category, td.assigned_to, tr.issue td.string, tr.issue td.text, tr.issue td.list, tr.issue td.relations, tr.issue td.parent { white-space: normal; }
255 tr.issue td.relations { text-align: left; }
258 tr.issue td.relations { text-align: left; }
256 tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;}
259 tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;}
257 tr.issue td.relations span {white-space: nowrap;}
260 tr.issue td.relations span {white-space: nowrap;}
258 table.issues td.description {color:#777; font-size:90%; padding:4px 4px 4px 24px; text-align:left; white-space:normal;}
261 table.issues td.description {color:#777; font-size:90%; padding:4px 4px 4px 24px; text-align:left; white-space:normal;}
259 table.issues td.description pre {white-space:normal;}
262 table.issues td.description pre {white-space:normal;}
260
263
261 tr.issue.idnt td.subject {background: url(../images/bullet_arrow_right.png) no-repeat 0 50%;}
264 tr.issue.idnt td.subject {background: url(../images/bullet_arrow_right.png) no-repeat 0 50%;}
262 tr.issue.idnt-1 td.subject {padding-left: 24px; background-position: 8px 50%;}
265 tr.issue.idnt-1 td.subject {padding-left: 24px; background-position: 8px 50%;}
263 tr.issue.idnt-2 td.subject {padding-left: 40px; background-position: 24px 50%;}
266 tr.issue.idnt-2 td.subject {padding-left: 40px; background-position: 24px 50%;}
264 tr.issue.idnt-3 td.subject {padding-left: 56px; background-position: 40px 50%;}
267 tr.issue.idnt-3 td.subject {padding-left: 56px; background-position: 40px 50%;}
265 tr.issue.idnt-4 td.subject {padding-left: 72px; background-position: 56px 50%;}
268 tr.issue.idnt-4 td.subject {padding-left: 72px; background-position: 56px 50%;}
266 tr.issue.idnt-5 td.subject {padding-left: 88px; background-position: 72px 50%;}
269 tr.issue.idnt-5 td.subject {padding-left: 88px; background-position: 72px 50%;}
267 tr.issue.idnt-6 td.subject {padding-left: 104px; background-position: 88px 50%;}
270 tr.issue.idnt-6 td.subject {padding-left: 104px; background-position: 88px 50%;}
268 tr.issue.idnt-7 td.subject {padding-left: 120px; background-position: 104px 50%;}
271 tr.issue.idnt-7 td.subject {padding-left: 120px; background-position: 104px 50%;}
269 tr.issue.idnt-8 td.subject {padding-left: 136px; background-position: 120px 50%;}
272 tr.issue.idnt-8 td.subject {padding-left: 136px; background-position: 120px 50%;}
270 tr.issue.idnt-9 td.subject {padding-left: 152px; background-position: 136px 50%;}
273 tr.issue.idnt-9 td.subject {padding-left: 152px; background-position: 136px 50%;}
271
274
272 table.issue-report {table-layout:fixed;}
275 table.issue-report {table-layout:fixed;}
273
276
274 tr.entry { border: 1px solid #f8f8f8; }
277 tr.entry { border: 1px solid #f8f8f8; }
275 tr.entry td { white-space: nowrap; }
278 tr.entry td { white-space: nowrap; }
276 tr.entry td.filename {width:30%; text-align:left;}
279 tr.entry td.filename {width:30%; text-align:left;}
277 tr.entry td.filename_no_report {width:70%; text-align:left;}
280 tr.entry td.filename_no_report {width:70%; text-align:left;}
278 tr.entry td.size { text-align: right; font-size: 90%; }
281 tr.entry td.size { text-align: right; font-size: 90%; }
279 tr.entry td.revision, tr.entry td.author { text-align: center; }
282 tr.entry td.revision, tr.entry td.author { text-align: center; }
280 tr.entry td.age { text-align: right; }
283 tr.entry td.age { text-align: right; }
281 tr.entry.file td.filename a { margin-left: 16px; }
284 tr.entry.file td.filename a { margin-left: 16px; }
282 tr.entry.file td.filename_no_report a { margin-left: 16px; }
285 tr.entry.file td.filename_no_report a { margin-left: 16px; }
283
286
284 tr span.expander {background-image: url(../images/bullet_toggle_plus.png); padding-left: 8px; margin-left: 0; cursor: pointer;}
287 tr span.expander {background-image: url(../images/bullet_toggle_plus.png); padding-left: 8px; margin-left: 0; cursor: pointer;}
285 tr.open span.expander {background-image: url(../images/bullet_toggle_minus.png);}
288 tr.open span.expander {background-image: url(../images/bullet_toggle_minus.png);}
286
289
287 tr.changeset { height: 20px }
290 tr.changeset { height: 20px }
288 tr.changeset ul, ol { margin-top: 0px; margin-bottom: 0px; }
291 tr.changeset ul, ol { margin-top: 0px; margin-bottom: 0px; }
289 tr.changeset td.revision_graph { width: 15%; background-color: #fffffb; }
292 tr.changeset td.revision_graph { width: 15%; background-color: #fffffb; }
290 tr.changeset td.author { text-align: center; width: 15%; white-space:nowrap;}
293 tr.changeset td.author { text-align: center; width: 15%; white-space:nowrap;}
291 tr.changeset td.committed_on { text-align: center; width: 15%; white-space:nowrap;}
294 tr.changeset td.committed_on { text-align: center; width: 15%; white-space:nowrap;}
292
295
293 table.files tbody th {text-align:left;}
296 table.files tbody th {text-align:left;}
294 table.files tr.file td.filename { text-align: left; padding-left: 24px; }
297 table.files tr.file td.filename { text-align: left; padding-left: 24px; }
295 table.files tr.file td.digest { font-size: 80%; }
298 table.files tr.file td.digest { font-size: 80%; }
296
299
297 table.members td.roles, table.memberships td.roles { width: 45%; }
300 table.members td.roles, table.memberships td.roles { width: 45%; }
298
301
299 tr.message { height: 2.6em; }
302 tr.message { height: 2.6em; }
300 tr.message td.created_on { white-space: nowrap; }
303 tr.message td.created_on { white-space: nowrap; }
301 tr.message td.last_message { font-size: 80%; white-space: nowrap; }
304 tr.message td.last_message { font-size: 80%; white-space: nowrap; }
302 tr.message.sticky td.subject { font-weight: bold; }
305 tr.message.sticky td.subject { font-weight: bold; }
303
306
304 tr.version.closed, tr.version.closed a { color: #999; }
307 tr.version.closed, tr.version.closed a { color: #999; }
305 tr.version td.name { padding-left: 20px; }
308 tr.version td.name { padding-left: 20px; }
306 tr.version td.date, tr.version td.status, tr.version td.sharing { text-align: center; white-space:nowrap; }
309 tr.version td.date, tr.version td.status, tr.version td.sharing { text-align: center; white-space:nowrap; }
307
310
308 tr.member td.icon-user {background:transparent;}
311 tr.member td.icon-user {background:transparent;}
309
312
310 tr.user td {width:13%;white-space: nowrap;}
313 tr.user td {width:13%;white-space: nowrap;}
311 td.username, td.firstname, td.lastname, td.email {text-align:left !important;}
314 td.username, td.firstname, td.lastname, td.email {text-align:left !important;}
312 tr.user td.email { width:18%; }
315 tr.user td.email { width:18%; }
313 tr.user.locked, tr.user.registered { color: #aaa; }
316 tr.user.locked, tr.user.registered { color: #aaa; }
314 tr.user.locked a, tr.user.registered a { color: #aaa; }
317 tr.user.locked a, tr.user.registered a { color: #aaa; }
315
318
316 table.permissions td.role {color:#999;font-size:90%;font-weight:normal !important;text-align:center;vertical-align:bottom;}
319 table.permissions td.role {color:#999;font-size:90%;font-weight:normal !important;text-align:center;vertical-align:bottom;}
317
320
318 tr.wiki-page-version td.updated_on, tr.wiki-page-version td.author {text-align:center;}
321 tr.wiki-page-version td.updated_on, tr.wiki-page-version td.author {text-align:center;}
319
322
320 tr.time-entry { text-align: center; white-space: nowrap; }
323 tr.time-entry { text-align: center; white-space: nowrap; }
321 tr.time-entry td.issue, tr.time-entry td.comments, tr.time-entry td.subject, tr.time-entry td.activity { text-align: left; white-space: normal; }
324 tr.time-entry td.issue, tr.time-entry td.comments, tr.time-entry td.subject, tr.time-entry td.activity { text-align: left; white-space: normal; }
322 td.hours { text-align: right; font-weight: bold; padding-right: 0.5em; }
325 td.hours { text-align: right; font-weight: bold; padding-right: 0.5em; }
323 td.hours .hours-dec { font-size: 0.9em; }
326 td.hours .hours-dec { font-size: 0.9em; }
324
327
325 table.plugins td { vertical-align: middle; }
328 table.plugins td { vertical-align: middle; }
326 table.plugins td.configure { text-align: right; padding-right: 1em; }
329 table.plugins td.configure { text-align: right; padding-right: 1em; }
327 table.plugins span.name { font-weight: bold; display: block; margin-bottom: 6px; }
330 table.plugins span.name { font-weight: bold; display: block; margin-bottom: 6px; }
328 table.plugins span.description { display: block; font-size: 0.9em; }
331 table.plugins span.description { display: block; font-size: 0.9em; }
329 table.plugins span.url { display: block; font-size: 0.9em; }
332 table.plugins span.url { display: block; font-size: 0.9em; }
330
333
331 table.list.enumerations {table-layout: fixed; margin-bottom: 2em;}
334 table.list.enumerations {table-layout: fixed; margin-bottom: 2em;}
332
335
333 tr.group td { padding: 0.8em 0 0.5em 0.3em; border-bottom: 1px solid #ccc; text-align:left; }
336 tr.group td { padding: 0.8em 0 0.5em 0.3em; border-bottom: 1px solid #ccc; text-align:left; }
334 tr.group span.name {font-weight:bold;}
337 tr.group span.name {font-weight:bold;}
335 tr.group span.count {font-weight:bold; position:relative; top:-1px; color:#fff; font-size:10px; background:#9DB9D5; padding:0px 6px 1px 6px; border-radius:3px; margin-left:4px;}
338 tr.group span.count {font-weight:bold; position:relative; top:-1px; color:#fff; font-size:10px; background:#9DB9D5; padding:0px 6px 1px 6px; border-radius:3px; margin-left:4px;}
336 tr.group span.totals {color: #aaa; font-size: 80%;}
339 tr.group span.totals {color: #aaa; font-size: 80%;}
337 tr.group span.totals .value {font-weight:bold; color:#777;}
340 tr.group span.totals .value {font-weight:bold; color:#777;}
338 tr.group a.toggle-all { color: #aaa; font-size: 80%; display:none; float:right; margin-right:4px;}
341 tr.group a.toggle-all { color: #aaa; font-size: 80%; display:none; float:right; margin-right:4px;}
339 tr.group:hover a.toggle-all { display:inline;}
342 tr.group:hover a.toggle-all { display:inline;}
340 a.toggle-all:hover {text-decoration:none;}
343 a.toggle-all:hover {text-decoration:none;}
341
344
342 table.list tbody tr:hover { background-color:#ffffdd; }
345 table.list tbody tr:hover { background-color:#ffffdd; }
343 table.list tbody tr.group:hover { background-color:inherit; }
346 table.list tbody tr.group:hover { background-color:inherit; }
344 table td {padding:2px;}
347 table td {padding:2px;}
345 table p {margin:0;}
348 table p {margin:0;}
346 .odd {background-color:#f6f7f8;}
349 .odd {background-color:#f6f7f8;}
347 .even {background-color: #fff;}
350 .even {background-color: #fff;}
348
351
349 tr.builtin td.name {font-style:italic;}
352 tr.builtin td.name {font-style:italic;}
350
353
351 a.sort { padding-right: 16px; background-position: 100% 50%; background-repeat: no-repeat; }
354 a.sort { padding-right: 16px; background-position: 100% 50%; background-repeat: no-repeat; }
352 a.sort.asc { background-image: url(../images/sort_asc.png); }
355 a.sort.asc { background-image: url(../images/sort_asc.png); }
353 a.sort.desc { background-image: url(../images/sort_desc.png); }
356 a.sort.desc { background-image: url(../images/sort_desc.png); }
354
357
355 table.boards a.board { background: url(../images/comment.png) no-repeat 0% 50%; padding-left: 20px; }
358 table.boards a.board { background: url(../images/comment.png) no-repeat 0% 50%; padding-left: 20px; }
356 table.boards td.last-message {text-align:left;font-size:80%;}
359 table.boards td.last-message {text-align:left;font-size:80%;}
357
360
358 div.table-list.boards .table-list-cell.name {width: 30%;}
361 div.table-list.boards .table-list-cell.name {width: 30%;}
359
362
360 #content table.list-simple {table-layout:fixed;}
363 #content table.list-simple {table-layout:fixed;}
361 #content table.list-simple td {white-space:nowrap; overflow:hidden; text-overflow: ellipsis; text-align:left;}
364 #content table.list-simple td {white-space:nowrap; overflow:hidden; text-overflow: ellipsis; text-align:left;}
362 #content table.list-simple th.id, #content table.list-simple th.project {width:18%;}
365 #content table.list-simple th.id, #content table.list-simple th.project {width:18%;}
363 #content table.list-simple th.status {width:14%;}
366 #content table.list-simple th.status {width:14%;}
364
367
365 table.messages td.last_message {text-align:left;}
368 table.messages td.last_message {text-align:left;}
366
369
367 #query_form_content {font-size:90%;}
370 #query_form_content {font-size:90%;}
368
371
369 .query_sort_criteria_count {
372 .query_sort_criteria_count {
370 display: inline-block;
373 display: inline-block;
371 min-width: 1em;
374 min-width: 1em;
372 }
375 }
373
376
374 table.query-columns {
377 table.query-columns {
375 border-collapse: collapse;
378 border-collapse: collapse;
376 border: 0;
379 border: 0;
377 }
380 }
378
381
379 table.query-columns td.buttons {
382 table.query-columns td.buttons {
380 vertical-align: middle;
383 vertical-align: middle;
381 text-align: center;
384 text-align: center;
382 }
385 }
383 table.query-columns td.buttons input[type=button] {width:35px;}
386 table.query-columns td.buttons input[type=button] {width:35px;}
384 .query-totals {text-align:right;}
387 .query-totals {text-align:right;}
385 .query-totals>span:not(:first-child) {margin-left:0.6em;}
388 .query-totals>span:not(:first-child) {margin-left:0.6em;}
386 .query-totals .value {font-weight:bold;}
389 .query-totals .value {font-weight:bold;}
387 body.controller-issues .query-totals {margin-top:-2.3em;}
390 body.controller-issues .query-totals {margin-top:-2.3em;}
388
391
389 td.center {text-align:center;}
392 td.center {text-align:center;}
390
393
391 #watchers select {width: 95%; display: block;}
394 #watchers select {width: 95%; display: block;}
392 #watchers a.delete {opacity: 0.4; margin-left: 5px;}
395 #watchers a.delete {opacity: 0.4; margin-left: 5px;}
393 #watchers a.delete:hover {opacity: 1;}
396 #watchers a.delete:hover {opacity: 1;}
394 #watchers img.gravatar {margin: 0 4px 2px 0;}
397 #watchers img.gravatar {margin: 0 4px 2px 0;}
395
398
396 span#watchers_inputs {overflow:auto; display:block;}
399 span#watchers_inputs {overflow:auto; display:block;}
397 span.search_for_watchers {display:block;}
400 span.search_for_watchers {display:block;}
398 span.search_for_watchers, span.add_attachment {font-size:80%; line-height:2.5em;}
401 span.search_for_watchers, span.add_attachment {font-size:80%; line-height:2.5em;}
399 span.add_attachment a {padding-left:16px; background: url(../images/bullet_add.png) no-repeat 0 50%; }
402 span.add_attachment a {padding-left:16px; background: url(../images/bullet_add.png) no-repeat 0 50%; }
400
403
401
404
402 .highlight { background-color: #FCFD8D;}
405 .highlight { background-color: #FCFD8D;}
403 .highlight.token-1 { background-color: #faa;}
406 .highlight.token-1 { background-color: #faa;}
404 .highlight.token-2 { background-color: #afa;}
407 .highlight.token-2 { background-color: #afa;}
405 .highlight.token-3 { background-color: #aaf;}
408 .highlight.token-3 { background-color: #aaf;}
406
409
407 .box{
410 .box{
408 padding:6px;
411 padding:6px;
409 margin-bottom: 10px;
412 margin-bottom: 10px;
410 background-color:#f6f6f6;
413 background-color:#f6f6f6;
411 color:#505050;
414 color:#505050;
412 line-height:1.5em;
415 line-height:1.5em;
413 border: 1px solid #e4e4e4;
416 border: 1px solid #e4e4e4;
414 word-wrap: break-word;
417 word-wrap: break-word;
415 border-radius: 3px;
418 border-radius: 3px;
416 }
419 }
417
420
418 div.square {
421 div.square {
419 border: 1px solid #999;
422 border: 1px solid #999;
420 float: left;
423 float: left;
421 margin: .3em .4em 0 .4em;
424 margin: .3em .4em 0 .4em;
422 overflow: hidden;
425 overflow: hidden;
423 width: .6em; height: .6em;
426 width: .6em; height: .6em;
424 }
427 }
425 .contextual {float:right; white-space: nowrap; line-height:1.4em;margin:5px 0px; padding-left: 10px; font-size:0.9em;}
428 .contextual {float:right; white-space: nowrap; line-height:1.4em;margin:5px 0px; padding-left: 10px; font-size:0.9em;}
426 .contextual .icon {padding-top: 2px; padding-bottom: 3px;}
429 .contextual .icon {padding-top: 2px; padding-bottom: 3px;}
427 .contextual input, .contextual select {font-size:0.9em;}
430 .contextual input, .contextual select {font-size:0.9em;}
428 .message .contextual { margin-top: 0; }
431 .message .contextual { margin-top: 0; }
429
432
430 .splitcontent {overflow:auto;}
433 .splitcontent {overflow:auto;}
431 .splitcontentleft{float:left; width:49%;}
434 .splitcontentleft{float:left; width:49%;}
432 .splitcontentright{float:right; width:49%;}
435 .splitcontentright{float:right; width:49%;}
433 form {display: inline;}
436 form {display: inline;}
434 input, select {vertical-align: middle; margin-top: 1px; margin-bottom: 1px;}
437 input, select {vertical-align: middle; margin-top: 1px; margin-bottom: 1px;}
435 input[type="submit"] { -webkit-appearance: button; }
438 input[type="submit"] { -webkit-appearance: button; }
436 fieldset {border: 1px solid #e4e4e4; margin:0;}
439 fieldset {border: 1px solid #e4e4e4; margin:0;}
437 legend {color: #333;}
440 legend {color: #333;}
438 hr { width: 100%; height: 1px; background: #ccc; border: 0;}
441 hr { width: 100%; height: 1px; background: #ccc; border: 0;}
439 blockquote { font-style: italic; border-left: 3px solid #e0e0e0; padding-left: 0.6em; margin-left: 2.4em;}
442 blockquote { font-style: italic; border-left: 3px solid #e0e0e0; padding-left: 0.6em; margin-left: 2.4em;}
440 blockquote blockquote { margin-left: 0;}
443 blockquote blockquote { margin-left: 0;}
441 abbr, span.field-description[title] { border-bottom: 1px dotted #aaa; cursor: help; }
444 abbr, span.field-description[title] { border-bottom: 1px dotted #aaa; cursor: help; }
442 textarea.wiki-edit {width:99%; resize:vertical;}
445 textarea.wiki-edit {width:99%; resize:vertical;}
443 body.textarea-monospace textarea.wiki-edit {font-family: Consolas, Menlo, "Liberation Mono", Courier, monospace; font-size: 12px;}
446 body.textarea-monospace textarea.wiki-edit {font-family: Consolas, Menlo, "Liberation Mono", Courier, monospace; font-size: 12px;}
444 body.textarea-proportional textarea.wiki-edit {font-family: Verdana, sans-serif; font-size: 12px;}
447 body.textarea-proportional textarea.wiki-edit {font-family: Verdana, sans-serif; font-size: 12px;}
445 li p {margin-top: 0;}
448 li p {margin-top: 0;}
446 div.issue {background:#ffffdd; padding:6px; margin-bottom:6px; border: 1px solid #d7d7d7; border-radius:3px;}
449 div.issue {background:#ffffdd; padding:6px; margin-bottom:6px; border: 1px solid #d7d7d7; border-radius:3px;}
447 p.breadcrumb { font-size: 0.9em; margin: 4px 0 4px 0;}
450 p.breadcrumb { font-size: 0.9em; margin: 4px 0 4px 0;}
448 p.subtitle { font-size: 0.9em; margin: -6px 0 12px 0; font-style: italic; }
451 p.subtitle { font-size: 0.9em; margin: -6px 0 12px 0; font-style: italic; }
449 p.footnote { font-size: 0.9em; margin-top: 0px; margin-bottom: 0px; }
452 p.footnote { font-size: 0.9em; margin-top: 0px; margin-bottom: 0px; }
450 .ltr {direction:ltr !important; unicode-bidi:bidi-override;}
453 .ltr {direction:ltr !important; unicode-bidi:bidi-override;}
451 .rtl {direction:rtl !important; unicode-bidi:bidi-override;}
454 .rtl {direction:rtl !important; unicode-bidi:bidi-override;}
452
455
453 div.issue div.subject div div { padding-left: 16px; }
456 div.issue div.subject div div { padding-left: 16px; }
454 div.issue div.subject p {margin: 0; margin-bottom: 0.1em; font-size: 90%; color: #999;}
457 div.issue div.subject p {margin: 0; margin-bottom: 0.1em; font-size: 90%; color: #999;}
455 div.issue div.subject>div>p { margin-top: 0.5em; }
458 div.issue div.subject>div>p { margin-top: 0.5em; }
456 div.issue div.subject h3 {margin: 0; margin-bottom: 0.1em;}
459 div.issue div.subject h3 {margin: 0; margin-bottom: 0.1em;}
457 div.issue span.private, div.journal span.private { position:relative; bottom: 2px; text-transform: uppercase; background: #d22; color: #fff; font-weight:bold; padding: 0px 2px 0px 2px; font-size: 60%; margin-right: 2px; border-radius: 2px;}
460 div.issue span.private, div.journal span.private { position:relative; bottom: 2px; text-transform: uppercase; background: #d22; color: #fff; font-weight:bold; padding: 0px 2px 0px 2px; font-size: 60%; margin-right: 2px; border-radius: 2px;}
458 div.issue .next-prev-links {color:#999;}
461 div.issue .next-prev-links {color:#999;}
459 div.issue .attributes {margin-top: 2em;}
462 div.issue .attributes {margin-top: 2em;}
460 div.issue .attribute {padding-left:180px; clear:left; min-height: 1.8em;}
463 div.issue .attribute {padding-left:180px; clear:left; min-height: 1.8em;}
461 div.issue .attribute .label {width: 170px; margin-left:-180px; font-weight:bold; float:left; overflow:hidden; text-overflow: ellipsis;}
464 div.issue .attribute .label {width: 170px; margin-left:-180px; font-weight:bold; float:left; overflow:hidden; text-overflow: ellipsis;}
462 div.issue .attribute .value {overflow:hidden; text-overflow: ellipsis;}
465 div.issue .attribute .value {overflow:hidden; text-overflow: ellipsis;}
463 div.issue.overdue .due-date .value { color: #c22; }
466 div.issue.overdue .due-date .value { color: #c22; }
464
467
465 #issue_tree table.issues, #relations table.issues { border: 0; }
468 #issue_tree table.issues, #relations table.issues { border: 0; }
466 #issue_tree td.checkbox, #relations td.checkbox {display:none;}
469 #issue_tree td.checkbox, #relations td.checkbox {display:none;}
467 #relations td.buttons {padding:0;}
470 #relations td.buttons {padding:0;}
468
471
469 fieldset.collapsible {border-width: 1px 0 0 0;}
472 fieldset.collapsible {border-width: 1px 0 0 0;}
470 fieldset.collapsible>legend { padding-left: 16px; background: url(../images/arrow_expanded.png) no-repeat 0% 40%; cursor:pointer; }
473 fieldset.collapsible>legend { padding-left: 16px; background: url(../images/arrow_expanded.png) no-repeat 0% 40%; cursor:pointer; }
471 fieldset.collapsible.collapsed>legend { background-image: url(../images/arrow_collapsed.png); }
474 fieldset.collapsible.collapsed>legend { background-image: url(../images/arrow_collapsed.png); }
472
475
473 fieldset#date-range p { margin: 2px 0 2px 0; }
476 fieldset#date-range p { margin: 2px 0 2px 0; }
474 fieldset#filters table { border-collapse: collapse; }
477 fieldset#filters table { border-collapse: collapse; }
475 fieldset#filters table td { padding: 0; vertical-align: middle; }
478 fieldset#filters table td { padding: 0; vertical-align: middle; }
476 fieldset#filters tr.filter { height: 2.1em; }
479 fieldset#filters tr.filter { height: 2.1em; }
477 fieldset#filters td.field { width:230px; }
480 fieldset#filters td.field { width:230px; }
478 fieldset#filters td.operator { width:130px; }
481 fieldset#filters td.operator { width:130px; }
479 fieldset#filters td.operator select {max-width:120px;}
482 fieldset#filters td.operator select {max-width:120px;}
480 fieldset#filters td.values { white-space:nowrap; }
483 fieldset#filters td.values { white-space:nowrap; }
481 fieldset#filters td.values select {min-width:130px; max-width:200px;}
484 fieldset#filters td.values select {min-width:130px; max-width:200px;}
482 fieldset#filters td.values input {height:1em;}
485 fieldset#filters td.values input {height:1em;}
483
486
484 #filters-table {width:60%; float:left;}
487 #filters-table {width:60%; float:left;}
485 .add-filter {width:35%; float:right; text-align: right; vertical-align: top;}
488 .add-filter {width:35%; float:right; text-align: right; vertical-align: top;}
486
489
487 #issue_is_private_wrap {float:right; margin-right:1em;}
490 #issue_is_private_wrap {float:right; margin-right:1em;}
488 .toggle-multiselect {background: url(../images/bullet_toggle_plus.png) no-repeat 0% 40%; padding-left:16px; margin-left:0; margin-right:5px; cursor:pointer;}
491 .toggle-multiselect {background: url(../images/bullet_toggle_plus.png) no-repeat 0% 40%; padding-left:16px; margin-left:0; margin-right:5px; cursor:pointer;}
489 .buttons { font-size: 0.9em; margin-bottom: 1.4em; margin-top: 1em; }
492 .buttons { font-size: 0.9em; margin-bottom: 1.4em; margin-top: 1em; }
490
493
491 div#issue-changesets {float:right; width:45%; margin-left: 1em; margin-bottom: 1em; background: #fff; padding-left: 1em; font-size: 90%;}
494 div#issue-changesets {float:right; width:45%; margin-left: 1em; margin-bottom: 1em; background: #fff; padding-left: 1em; font-size: 90%;}
492 div#issue-changesets div.changeset { padding: 4px;}
495 div#issue-changesets div.changeset { padding: 4px;}
493 div#issue-changesets div.changeset { border-bottom: 1px solid #ddd; }
496 div#issue-changesets div.changeset { border-bottom: 1px solid #ddd; }
494 div#issue-changesets p { margin-top: 0; margin-bottom: 1em;}
497 div#issue-changesets p { margin-top: 0; margin-bottom: 1em;}
495 .changeset-comments {margin-bottom:1em; font-family:}
498 .changeset-comments {margin-bottom:1em; font-family:}
496
499
497 div.journal {overflow:auto;}
500 div.journal {overflow:auto;}
498 div.journal.private-notes {border-left:2px solid #d22; padding-left:4px; margin-left:-6px;}
501 div.journal.private-notes {border-left:2px solid #d22; padding-left:4px; margin-left:-6px;}
499 div.journal ul.details, ul.revision-info {color:#959595; margin-bottom: 1.5em;}
502 div.journal ul.details, ul.revision-info {color:#959595; margin-bottom: 1.5em;}
500 div.journal ul.details a, ul.revision-info a {color:#70A7CD;}
503 div.journal ul.details a, ul.revision-info a {color:#70A7CD;}
501 div.journal ul.details a:hover, ul.revision-info a:hover {color:#D14848;}
504 div.journal ul.details a:hover, ul.revision-info a:hover {color:#D14848;}
502
505
503 div#activity dl, #search-results { margin-left: 2em; }
506 div#activity dl, #search-results { margin-left: 2em; }
504 div#activity dd, #search-results dd { margin-bottom: 1em; padding-left: 18px; font-size: 0.9em; }
507 div#activity dd, #search-results dd { margin-bottom: 1em; padding-left: 18px; font-size: 0.9em; }
505 div#activity dt.me .time { border-bottom: 1px solid #999; }
508 div#activity dt.me .time { border-bottom: 1px solid #999; }
506 div#activity dt .time { color: #777; font-size: 80%; }
509 div#activity dt .time { color: #777; font-size: 80%; }
507 div#activity dd .description, #search-results dd .description { font-style: italic; }
510 div#activity dd .description, #search-results dd .description { font-style: italic; }
508 div#activity span.project:after, #search-results span.project:after { content: " -"; }
511 div#activity span.project:after, #search-results span.project:after { content: " -"; }
509 div#activity dd span.description, #search-results dd span.description { display:block; color: #808080; }
512 div#activity dd span.description, #search-results dd span.description { display:block; color: #808080; }
510 div#activity dt.grouped {margin-left:5em;}
513 div#activity dt.grouped {margin-left:5em;}
511 div#activity dd.grouped {margin-left:9em;}
514 div#activity dd.grouped {margin-left:9em;}
512 div#activity dt { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; height: 18px;}
515 div#activity dt { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; height: 18px;}
513
516
514 #search-results dd { margin-bottom: 1em; padding-left: 20px; margin-left:0px; }
517 #search-results dd { margin-bottom: 1em; padding-left: 20px; margin-left:0px; }
515
518
516 div#search-results-counts {float:right;}
519 div#search-results-counts {float:right;}
517 div#search-results-counts ul { margin-top: 0.5em; }
520 div#search-results-counts ul { margin-top: 0.5em; }
518 div#search-results-counts li { list-style-type:none; float: left; margin-left: 1em; }
521 div#search-results-counts li { list-style-type:none; float: left; margin-left: 1em; }
519
522
520 div#roadmap .related-issues { margin-bottom: 1em; }
523 div#roadmap .related-issues { margin-bottom: 1em; }
521 div#roadmap .related-issues td.checkbox { display: none; }
524 div#roadmap .related-issues td.checkbox { display: none; }
522 div#roadmap .wiki h1:first-child { display: none; }
525 div#roadmap .wiki h1:first-child { display: none; }
523 div#roadmap .wiki h1 { font-size: 120%; }
526 div#roadmap .wiki h1 { font-size: 120%; }
524 div#roadmap .wiki h2 { font-size: 110%; }
527 div#roadmap .wiki h2 { font-size: 110%; }
525 body.controller-versions.action-show div#roadmap .related-issues {width:70%;}
528 body.controller-versions.action-show div#roadmap .related-issues {width:70%;}
526
529
527 div#version-summary { float:right; width:28%; margin-left: 16px; margin-bottom: 16px; background-color: #fff; }
530 div#version-summary { float:right; width:28%; margin-left: 16px; margin-bottom: 16px; background-color: #fff; }
528 div#version-summary fieldset { margin-bottom: 1em; }
531 div#version-summary fieldset { margin-bottom: 1em; }
529 div#version-summary fieldset.time-tracking table { width:100%; }
532 div#version-summary fieldset.time-tracking table { width:100%; }
530 div#version-summary th, div#version-summary td.total-hours { text-align: right; }
533 div#version-summary th, div#version-summary td.total-hours { text-align: right; }
531
534
532 table#time-report td.hours, table#time-report th.period, table#time-report th.total { text-align: right; padding-right: 0.5em; }
535 table#time-report td.hours, table#time-report th.period, table#time-report th.total { text-align: right; padding-right: 0.5em; }
533 table#time-report tbody tr.subtotal { font-style: italic; color:#777;}
536 table#time-report tbody tr.subtotal { font-style: italic; color:#777;}
534 table#time-report tbody tr.subtotal td.hours { color:#b0b0b0; }
537 table#time-report tbody tr.subtotal td.hours { color:#b0b0b0; }
535 table#time-report tbody tr.total { font-weight: bold; background-color:#EEEEEE; border-top:1px solid #e4e4e4;}
538 table#time-report tbody tr.total { font-weight: bold; background-color:#EEEEEE; border-top:1px solid #e4e4e4;}
536 table#time-report .hours-dec { font-size: 0.9em; }
539 table#time-report .hours-dec { font-size: 0.9em; }
537
540
538 div.wiki-page .contextual a {opacity: 0.4}
541 div.wiki-page .contextual a {opacity: 0.4}
539 div.wiki-page .contextual a:hover {opacity: 1}
542 div.wiki-page .contextual a:hover {opacity: 1}
540
543
541 form .attributes select { width: 60%; }
544 form .attributes select { width: 60%; }
542 form .attributes select + a.icon-only { vertical-align: middle; margin-left: 4px; }
545 form .attributes select + a.icon-only { vertical-align: middle; margin-left: 4px; }
543 input#issue_subject, input#document_title { width: 99%; }
546 input#issue_subject, input#document_title { width: 99%; }
544 select#issue_done_ratio { width: 95px; }
547 select#issue_done_ratio { width: 95px; }
545
548
546 ul.projects {margin:0; padding-left:1em;}
549 ul.projects {margin:0; padding-left:1em;}
547 ul.projects ul {padding-left:1.6em;}
550 ul.projects ul {padding-left:1.6em;}
548 ul.projects.root {margin:0; padding:0;}
551 ul.projects.root {margin:0; padding:0;}
549 ul.projects li {list-style-type:none;}
552 ul.projects li {list-style-type:none;}
550
553
551 #projects-index {
554 #projects-index {
552 column-count: auto;
555 column-count: auto;
553 column-width: 400px;
556 column-width: 400px;
554 -webkit-column-count: auto;
557 -webkit-column-count: auto;
555 -webkit-column-width: 400px;
558 -webkit-column-width: 400px;
556 -webkit-column-gap : 0.5rem;
559 -webkit-column-gap : 0.5rem;
557 -moz-column-count: auto;
560 -moz-column-count: auto;
558 -moz-column-width: 400px;
561 -moz-column-width: 400px;
559 -moz-column-gap : 0.5rem;
562 -moz-column-gap : 0.5rem;
560 }
563 }
561 #projects-index ul.projects li.root>ul.projects { border-left: 3px solid #e0e0e0; padding-left:1em;}
564 #projects-index ul.projects li.root>ul.projects { border-left: 3px solid #e0e0e0; padding-left:1em;}
562 #projects-index ul.projects li.root {margin-bottom: 1em;}
565 #projects-index ul.projects li.root {margin-bottom: 1em;}
563 #projects-index ul.projects li.child {margin-top: 1em;}
566 #projects-index ul.projects li.child {margin-top: 1em;}
564 #projects-index ul.projects div.root a.project { font-family: "Trebuchet MS", Verdana, sans-serif; font-weight: bold; font-size: 16px; margin: 0 0 10px 0; }
567 #projects-index ul.projects div.root a.project { font-family: "Trebuchet MS", Verdana, sans-serif; font-weight: bold; font-size: 16px; margin: 0 0 10px 0; }
565 #projects-index a.icon-fav {padding-left:0; padding-right:20px; background-position:98% 50%;}
568 #projects-index a.icon-fav {padding-left:0; padding-right:20px; background-position:98% 50%;}
566
569
567 #notified-projects>ul, #tracker_project_ids>ul, #custom_field_project_ids>ul {max-height:250px; overflow-y:auto;}
570 #notified-projects>ul, #tracker_project_ids>ul, #custom_field_project_ids>ul {max-height:250px; overflow-y:auto;}
568
571
569 #related-issues li img {vertical-align:middle;}
572 #related-issues li img {vertical-align:middle;}
570
573
571 ul.properties {padding:0; font-size: 0.9em; color: #777;}
574 ul.properties {padding:0; font-size: 0.9em; color: #777;}
572 ul.properties li {list-style-type:none;}
575 ul.properties li {list-style-type:none;}
573 ul.properties li span {font-style:italic;}
576 ul.properties li span {font-style:italic;}
574
577
575 .total-hours { font-size: 110%; font-weight: bold; }
578 .total-hours { font-size: 110%; font-weight: bold; }
576 .total-hours span.hours-int { font-size: 120%; }
579 .total-hours span.hours-int { font-size: 120%; }
577
580
578 .autoscroll {overflow-x: auto; padding:1px; margin-bottom: 1.2em; position: relative;}
581 .autoscroll {overflow-x: auto; padding:1px; margin-bottom: 1.2em; position: relative;}
579 #user_login, #user_firstname, #user_lastname, #user_mail, #my_account_form select, #user_form select, #user_identity_url { width: 90%; }
582 #user_login, #user_firstname, #user_lastname, #user_mail, #my_account_form select, #user_form select, #user_identity_url { width: 90%; }
580
583
581 #workflow_copy_form select { width: 200px; }
584 #workflow_copy_form select { width: 200px; }
582 table.transitions td.enabled {background: #bfb;}
585 table.transitions td.enabled {background: #bfb;}
583 #workflow_form table select {font-size:90%; max-width:100px;}
586 #workflow_form table select {font-size:90%; max-width:100px;}
584 table.fields_permissions td.readonly {background:#ddd;}
587 table.fields_permissions td.readonly {background:#ddd;}
585 table.fields_permissions td.required {background:#d88;}
588 table.fields_permissions td.required {background:#d88;}
586
589
587 select.expandable {vertical-align:top;}
590 select.expandable {vertical-align:top;}
588
591
589 textarea#custom_field_possible_values {width: 95%; resize:vertical}
592 textarea#custom_field_possible_values {width: 95%; resize:vertical}
590 textarea#custom_field_default_value {width: 95%; resize:vertical}
593 textarea#custom_field_default_value {width: 95%; resize:vertical}
591 .sort-handle {display:inline-block; vertical-align:middle;}
594 .sort-handle {display:inline-block; vertical-align:middle;}
592
595
593 input#content_comments {width: 99%}
596 input#content_comments {width: 99%}
594
597
595 span.pagination {margin-left:3px; color:#888; display:block;}
598 span.pagination {margin-left:3px; color:#888; display:block;}
596 .pagination ul.pages {
599 .pagination ul.pages {
597 margin: 0 5px 0 0;
600 margin: 0 5px 0 0;
598 padding: 0;
601 padding: 0;
599 display: inline;
602 display: inline;
600 }
603 }
601 .pagination ul.pages li {
604 .pagination ul.pages li {
602 display: inline-block;
605 display: inline-block;
603 padding: 0;
606 padding: 0;
604 border: 1px solid #ddd;
607 border: 1px solid #ddd;
605 margin-left: -1px;
608 margin-left: -1px;
606 line-height: 2em;
609 line-height: 2em;
607 margin-bottom: 1em;
610 margin-bottom: 1em;
608 white-space: nowrap;
611 white-space: nowrap;
609 text-align: center;
612 text-align: center;
610 }
613 }
611 .pagination ul.pages li a,
614 .pagination ul.pages li a,
612 .pagination ul.pages li span {
615 .pagination ul.pages li span {
613 padding: 3px 8px;
616 padding: 3px 8px;
614 }
617 }
615 .pagination ul.pages li:first-child {
618 .pagination ul.pages li:first-child {
616 border-top-left-radius: 4px;
619 border-top-left-radius: 4px;
617 border-bottom-left-radius: 4px;
620 border-bottom-left-radius: 4px;
618 }
621 }
619 .pagination ul.pages li:last-child {
622 .pagination ul.pages li:last-child {
620 border-top-right-radius: 4px;
623 border-top-right-radius: 4px;
621 border-bottom-right-radius: 4px;
624 border-bottom-right-radius: 4px;
622 }
625 }
623 .pagination ul.pages li.current {
626 .pagination ul.pages li.current {
624 color: white;
627 color: white;
625 background-color: #628DB6;
628 background-color: #628DB6;
626 border-color: #628DB6;
629 border-color: #628DB6;
627 }
630 }
628 .pagination ul.pages li.page:hover {
631 .pagination ul.pages li.page:hover {
629 background-color: #ddd;
632 background-color: #ddd;
630 }
633 }
631 .pagination ul.pages li.page a:hover,
634 .pagination ul.pages li.page a:hover,
632 .pagination ul.pages li.page a:active {
635 .pagination ul.pages li.page a:active {
633 color: #169;
636 color: #169;
634 text-decoration: inherit;
637 text-decoration: inherit;
635 }
638 }
636 .pagination .per-page span.selected {
639 .pagination .per-page span.selected {
637 font-weight: bold;
640 font-weight: bold;
638 }
641 }
639 span.pagination>span {white-space:nowrap;}
642 span.pagination>span {white-space:nowrap;}
640
643
641 #search-form fieldset p {margin:0.2em 0;}
644 #search-form fieldset p {margin:0.2em 0;}
642
645
643 /***** Tabular forms ******/
646 /***** Tabular forms ******/
644 .tabular p{
647 .tabular p{
645 margin: 0;
648 margin: 0;
646 padding: 3px 0 3px 0;
649 padding: 3px 0 3px 0;
647 padding-left: 180px; /* width of left column containing the label elements */
650 padding-left: 180px; /* width of left column containing the label elements */
648 min-height: 2em;
651 min-height: 2em;
649 clear:left;
652 clear:left;
650 }
653 }
651
654
652 html>body .tabular p {overflow:hidden;}
655 html>body .tabular p {overflow:hidden;}
653
656
654 .tabular input, .tabular select {max-width:95%}
657 .tabular input, .tabular select {max-width:95%}
655 .tabular textarea {width:95%; resize:vertical;}
658 .tabular textarea {width:95%; resize:vertical;}
656
659
657 .tabular label{
660 .tabular label{
658 font-weight: bold;
661 font-weight: bold;
659 float: left;
662 float: left;
660 text-align: right;
663 text-align: right;
661 /* width of left column */
664 /* width of left column */
662 margin-left: -180px;
665 margin-left: -180px;
663 /* width of labels. Should be smaller than left column to create some right margin */
666 /* width of labels. Should be smaller than left column to create some right margin */
664 width: 175px;
667 width: 175px;
665 }
668 }
666
669
667 .tabular label.floating{
670 .tabular label.floating{
668 font-weight: normal;
671 font-weight: normal;
669 margin-left: 0px;
672 margin-left: 0px;
670 text-align: left;
673 text-align: left;
671 width: 270px;
674 width: 270px;
672 }
675 }
673
676
674 label.block {
677 label.block {
675 display: block;
678 display: block;
676 width: auto !important;
679 width: auto !important;
677 }
680 }
678
681
679 .tabular label.block{
682 .tabular label.block{
680 font-weight: normal;
683 font-weight: normal;
681 margin-left: 0px !important;
684 margin-left: 0px !important;
682 text-align: left;
685 text-align: left;
683 float: none;
686 float: none;
684 }
687 }
685
688
686 .tabular label.inline{
689 .tabular label.inline{
687 font-weight: normal;
690 font-weight: normal;
688 float:none;
691 float:none;
689 margin-left: 5px !important;
692 margin-left: 5px !important;
690 width: auto;
693 width: auto;
691 }
694 }
692
695
693 label.no-css {
696 label.no-css {
694 font-weight: inherit;
697 font-weight: inherit;
695 float:none;
698 float:none;
696 text-align:left;
699 text-align:left;
697 margin-left:0px;
700 margin-left:0px;
698 width:auto;
701 width:auto;
699 }
702 }
700 input#time_entry_comments { width: 90%;}
703 input#time_entry_comments { width: 90%;}
701
704
702 #preview fieldset {margin-top: 1em; background: url(../images/draft.png)}
705 #preview fieldset {margin-top: 1em; background: url(../images/draft.png)}
703
706
704 .tabular.settings p{ padding-left: 300px; }
707 .tabular.settings p{ padding-left: 300px; }
705 .tabular.settings label{ margin-left: -300px; width: 295px; }
708 .tabular.settings label{ margin-left: -300px; width: 295px; }
706 .tabular.settings textarea { width: 99%; }
709 .tabular.settings textarea { width: 99%; }
707
710
708 .settings.enabled_scm table {width:100%}
711 .settings.enabled_scm table {width:100%}
709 .settings.enabled_scm td.scm_name{ font-weight: bold; }
712 .settings.enabled_scm td.scm_name{ font-weight: bold; }
710
713
711 fieldset.settings label { display: block; }
714 fieldset.settings label { display: block; }
712 fieldset#notified_events .parent { padding-left: 20px; }
715 fieldset#notified_events .parent { padding-left: 20px; }
713
716
714 span.required {color: #bb0000;}
717 span.required {color: #bb0000;}
715 .summary {font-style: italic;}
718 .summary {font-style: italic;}
716
719
717 .check_box_group {
720 .check_box_group {
718 display:block;
721 display:block;
719 width:95%;
722 width:95%;
720 max-height:300px;
723 max-height:300px;
721 overflow-y:auto;
724 overflow-y:auto;
722 padding:2px 4px 4px 2px;
725 padding:2px 4px 4px 2px;
723 background:#fff;
726 background:#fff;
724 border:1px solid #9EB1C2;
727 border:1px solid #9EB1C2;
725 border-radius:2px
728 border-radius:2px
726 }
729 }
727 .check_box_group label {
730 .check_box_group label {
728 font-weight: normal;
731 font-weight: normal;
729 margin-left: 0px !important;
732 margin-left: 0px !important;
730 text-align: left;
733 text-align: left;
731 float: none;
734 float: none;
732 display: block;
735 display: block;
733 width: auto;
736 width: auto;
734 }
737 }
735 .check_box_group.bool_cf {border:0; background:inherit;}
738 .check_box_group.bool_cf {border:0; background:inherit;}
736 .check_box_group.bool_cf label {display: inline;}
739 .check_box_group.bool_cf label {display: inline;}
737
740
738 .attachments_fields input.description, #existing-attachments input.description {margin-left:4px; width:340px;}
741 .attachments_fields input.description, #existing-attachments input.description {margin-left:4px; width:340px;}
739 .attachments_fields>span, #existing-attachments>span {display:block; white-space:nowrap;}
742 .attachments_fields>span, #existing-attachments>span {display:block; white-space:nowrap;}
740 .attachments_fields input.filename, #existing-attachments .filename {border:0; width:250px; color:#555; background-color:inherit; }
743 .attachments_fields input.filename, #existing-attachments .filename {border:0; width:250px; color:#555; background-color:inherit; }
741 .tabular input.filename {max-width:75% !important;}
744 .tabular input.filename {max-width:75% !important;}
742 .attachments_fields input.filename {height:1.8em;}
745 .attachments_fields input.filename {height:1.8em;}
743 .attachments_fields .ajax-waiting input.filename {background:url(../images/hourglass.png) no-repeat 0px 50%;}
746 .attachments_fields .ajax-waiting input.filename {background:url(../images/hourglass.png) no-repeat 0px 50%;}
744 .attachments_fields .ajax-loading input.filename {background:url(../images/loading.gif) no-repeat 0px 50%;}
747 .attachments_fields .ajax-loading input.filename {background:url(../images/loading.gif) no-repeat 0px 50%;}
745 .attachments_fields div.ui-progressbar { width: 100px; height:14px; margin: 2px 0 -5px 8px; display: inline-block; }
748 .attachments_fields div.ui-progressbar { width: 100px; height:14px; margin: 2px 0 -5px 8px; display: inline-block; }
746
749
747 a.remove-upload:hover {text-decoration:none !important;}
750 a.remove-upload:hover {text-decoration:none !important;}
748 .existing-attachment.deleted .filename {text-decoration:line-through; color:#999 !important;}
751 .existing-attachment.deleted .filename {text-decoration:line-through; color:#999 !important;}
749
752
750 div.fileover { background-color: lavender; }
753 div.fileover { background-color: lavender; }
751
754
752 div.attachments { margin: 12px 0; }
755 div.attachments { margin: 12px 0; }
753 div.attachments p { margin:4px 0 2px 0; }
756 div.attachments p { margin:4px 0 2px 0; }
754 div.attachments img { vertical-align: middle; }
757 div.attachments img { vertical-align: middle; }
755 div.attachments span.author { font-size: 0.9em; color: #888; }
758 div.attachments span.author { font-size: 0.9em; color: #888; }
756
759
757 div.thumbnails {margin:0.6em;}
760 div.thumbnails {margin:0.6em;}
758 div.thumbnails div {background:#fff;border:2px solid #ddd;display:inline-block;margin-right:2px;}
761 div.thumbnails div {background:#fff;border:2px solid #ddd;display:inline-block;margin-right:2px;}
759 div.thumbnails img {margin: 3px; vertical-align: middle;}
762 div.thumbnails img {margin: 3px; vertical-align: middle;}
760 #history div.thumbnails {margin-left: 2em;}
763 #history div.thumbnails {margin-left: 2em;}
761
764
762 p.other-formats { text-align: right; font-size:0.9em; color: #666; }
765 p.other-formats { text-align: right; font-size:0.9em; color: #666; }
763 .other-formats span + span:before { content: "| "; }
766 .other-formats span + span:before { content: "| "; }
764
767
765 a.atom { background: url(../images/feed.png) no-repeat 1px 50%; padding: 2px 0px 3px 16px; }
768 a.atom { background: url(../images/feed.png) no-repeat 1px 50%; padding: 2px 0px 3px 16px; }
766
769
767 em.info {font-style:normal;font-size:90%;color:#888;display:block;}
770 em.info {font-style:normal;font-size:90%;color:#888;display:block;}
768 em.info.error {padding-left:20px; background:url(../images/exclamation.png) no-repeat 0 50%;}
771 em.info.error {padding-left:20px; background:url(../images/exclamation.png) no-repeat 0 50%;}
769
772
770 textarea.text_cf {width:95%; resize:vertical;}
773 textarea.text_cf {width:95%; resize:vertical;}
771 input.string_cf, input.link_cf {width:95%;}
774 input.string_cf, input.link_cf {width:95%;}
772 select.bool_cf {width:auto !important;}
775 select.bool_cf {width:auto !important;}
773
776
774 #tab-content-modules fieldset p {margin:3px 0 4px 0;}
777 #tab-content-modules fieldset p {margin:3px 0 4px 0;}
775
778
776 #tab-content-users .splitcontentleft {width: 64%;}
779 #tab-content-users .splitcontentleft {width: 64%;}
777 #tab-content-users .splitcontentright {width: 34%;}
780 #tab-content-users .splitcontentright {width: 34%;}
778 #tab-content-users fieldset {padding:1em; margin-bottom: 1em;}
781 #tab-content-users fieldset {padding:1em; margin-bottom: 1em;}
779 #tab-content-users fieldset legend {font-weight: bold;}
782 #tab-content-users fieldset legend {font-weight: bold;}
780 #tab-content-users fieldset label {display: block;}
783 #tab-content-users fieldset label {display: block;}
781 #tab-content-users #principals {max-height: 400px; overflow: auto;}
784 #tab-content-users #principals {max-height: 400px; overflow: auto;}
782
785
783 #users_for_watcher {height: 200px; overflow:auto;}
786 #users_for_watcher {height: 200px; overflow:auto;}
784 #users_for_watcher label {display: block;}
787 #users_for_watcher label {display: block;}
785
788
786 input#principal_search, input#user_search {width:90%}
789 input#principal_search, input#user_search {width:90%}
787 .roles-selection label {display:inline-block; width:210px;}
790 .roles-selection label {display:inline-block; width:210px;}
788
791
789 input.autocomplete {
792 input.autocomplete {
790 background: #fff url(../images/magnifier.png) no-repeat 2px 50%; padding-left:20px !important;
793 background: #fff url(../images/magnifier.png) no-repeat 2px 50%; padding-left:20px !important;
791 border:1px solid #9EB1C2; border-radius:2px; height:1.5em;
794 border:1px solid #9EB1C2; border-radius:2px; height:1.5em;
792 }
795 }
793 input.autocomplete.ajax-loading {
796 input.autocomplete.ajax-loading {
794 background-image: url(../images/loading.gif);
797 background-image: url(../images/loading.gif);
795 }
798 }
796
799
797 .role-visibility {padding-left:2em;}
800 .role-visibility {padding-left:2em;}
798
801
799 .objects-selection {
802 .objects-selection {
800 height: 300px;
803 height: 300px;
801 overflow: auto;
804 overflow: auto;
802 margin-bottom: 1em;
805 margin-bottom: 1em;
803 }
806 }
804
807
805 .objects-selection label {
808 .objects-selection label {
806 display: block;
809 display: block;
807 }
810 }
808
811
809 .objects-selection>div, #user_group_ids {
812 .objects-selection>div, #user_group_ids {
810 column-count: auto;
813 column-count: auto;
811 column-width: 200px;
814 column-width: 200px;
812 -webkit-column-count: auto;
815 -webkit-column-count: auto;
813 -webkit-column-width: 200px;
816 -webkit-column-width: 200px;
814 -webkit-column-gap : 0.5rem;
817 -webkit-column-gap : 0.5rem;
815 -webkit-column-rule: 1px solid #ccc;
818 -webkit-column-rule: 1px solid #ccc;
816 -moz-column-count: auto;
819 -moz-column-count: auto;
817 -moz-column-width: 200px;
820 -moz-column-width: 200px;
818 -moz-column-gap : 0.5rem;
821 -moz-column-gap : 0.5rem;
819 -moz-column-rule: 1px solid #ccc;
822 -moz-column-rule: 1px solid #ccc;
820 }
823 }
821
824
822 /***** Flash & error messages ****/
825 /***** Flash & error messages ****/
823 #errorExplanation, div.flash, .nodata, .warning, .conflict {
826 #errorExplanation, div.flash, .nodata, .warning, .conflict {
824 padding: 6px 4px 6px 30px;
827 padding: 6px 4px 6px 30px;
825 margin-bottom: 12px;
828 margin-bottom: 12px;
826 font-size: 1.1em;
829 font-size: 1.1em;
827 border: 1px solid;
830 border: 1px solid;
828 border-radius: 3px;
831 border-radius: 3px;
829 }
832 }
830
833
831 div.flash {margin-top: 8px;}
834 div.flash {margin-top: 8px;}
832
835
833 div.flash.error, #errorExplanation {
836 div.flash.error, #errorExplanation {
834 background: url(../images/exclamation.png) 8px 50% no-repeat;
837 background: url(../images/exclamation.png) 8px 50% no-repeat;
835 background-color: #ffe3e3;
838 background-color: #ffe3e3;
836 border-color: #d88;
839 border-color: #d88;
837 color: #880000;
840 color: #880000;
838 }
841 }
839
842
840 div.flash.notice {
843 div.flash.notice {
841 background: url(../images/true.png) 8px 5px no-repeat;
844 background: url(../images/true.png) 8px 5px no-repeat;
842 background-color: #dfffdf;
845 background-color: #dfffdf;
843 border-color: #9fcf9f;
846 border-color: #9fcf9f;
844 color: #005f00;
847 color: #005f00;
845 }
848 }
846
849
847 div.flash.warning, .conflict {
850 div.flash.warning, .conflict {
848 background: url(../images/warning.png) 8px 5px no-repeat;
851 background: url(../images/warning.png) 8px 5px no-repeat;
849 background-color: #F3EDD1;
852 background-color: #F3EDD1;
850 border-color: #eadbbc;
853 border-color: #eadbbc;
851 color: #A6750C;
854 color: #A6750C;
852 text-align: left;
855 text-align: left;
853 }
856 }
854
857
855 .nodata, .warning {
858 .nodata, .warning {
856 text-align: center;
859 text-align: center;
857 background-color: #F3EDD1;
860 background-color: #F3EDD1;
858 border-color: #eadbbc;
861 border-color: #eadbbc;
859 color: #A6750C;
862 color: #A6750C;
860 }
863 }
861
864
862 #errorExplanation ul { font-size: 0.9em;}
865 #errorExplanation ul { font-size: 0.9em;}
863 #errorExplanation h2, #errorExplanation p { display: none; }
866 #errorExplanation h2, #errorExplanation p { display: none; }
864
867
865 .conflict-details {font-size:80%;}
868 .conflict-details {font-size:80%;}
866
869
867 /***** Ajax indicator ******/
870 /***** Ajax indicator ******/
868 #ajax-indicator {
871 #ajax-indicator {
869 position: absolute; /* fixed not supported by IE */
872 position: absolute; /* fixed not supported by IE */
870 background-color:#eee;
873 background-color:#eee;
871 border: 1px solid #bbb;
874 border: 1px solid #bbb;
872 top:35%;
875 top:35%;
873 left:40%;
876 left:40%;
874 width:20%;
877 width:20%;
875 font-weight:bold;
878 font-weight:bold;
876 text-align:center;
879 text-align:center;
877 padding:0.6em;
880 padding:0.6em;
878 z-index:100;
881 z-index:100;
879 opacity: 0.5;
882 opacity: 0.5;
880 }
883 }
881
884
882 html>body #ajax-indicator { position: fixed; }
885 html>body #ajax-indicator { position: fixed; }
883
886
884 #ajax-indicator span {
887 #ajax-indicator span {
885 background-position: 0% 40%;
888 background-position: 0% 40%;
886 background-repeat: no-repeat;
889 background-repeat: no-repeat;
887 background-image: url(../images/loading.gif);
890 background-image: url(../images/loading.gif);
888 padding-left: 26px;
891 padding-left: 26px;
889 vertical-align: bottom;
892 vertical-align: bottom;
890 }
893 }
891
894
892 /***** Calendar *****/
895 /***** Calendar *****/
893 table.cal {border-collapse: collapse; width: 100%; margin: 0px 0 6px 0;border: 1px solid #d7d7d7;}
896 table.cal {border-collapse: collapse; width: 100%; margin: 0px 0 6px 0;border: 1px solid #d7d7d7;}
894 table.cal thead th {width: 14%; background-color:#EEEEEE; padding: 4px; }
897 table.cal thead th {width: 14%; background-color:#EEEEEE; padding: 4px; }
895 table.cal thead th.week-number {width: auto;}
898 table.cal thead th.week-number {width: auto;}
896 table.cal tbody tr {height: 100px;}
899 table.cal tbody tr {height: 100px;}
897 table.cal td .icon {padding-top: 2px; padding-bottom: 3px;}
900 table.cal td .icon {padding-top: 2px; padding-bottom: 3px;}
898 table.cal td {border: 1px solid #d7d7d7; vertical-align: top; font-size: 0.9em;}
901 table.cal td {border: 1px solid #d7d7d7; vertical-align: top; font-size: 0.9em;}
899 table.cal td.week-number { background-color:#EEEEEE; padding: 4px; border:none; font-size: 1em;}
902 table.cal td.week-number { background-color:#EEEEEE; padding: 4px; border:none; font-size: 1em;}
900 table.cal td p.day-num {font-size: 1.1em; text-align:right;}
903 table.cal td p.day-num {font-size: 1.1em; text-align:right;}
901 table.cal td.odd p.day-num {color: #bbb;}
904 table.cal td.odd p.day-num {color: #bbb;}
902 table.cal td.today {background:#ffffdd;}
905 table.cal td.today {background:#ffffdd;}
903 table.cal td.today p.day-num {font-weight: bold;}
906 table.cal td.today p.day-num {font-weight: bold;}
904 table.cal .starting a, p.cal.legend .starting {background: url(../images/bullet_go.png) no-repeat -1px -2px; padding-left:16px;}
907 table.cal .starting a, p.cal.legend .starting {background: url(../images/bullet_go.png) no-repeat -1px -2px; padding-left:16px;}
905 table.cal .ending a, p.cal.legend .ending {background: url(../images/bullet_end.png) no-repeat -1px -2px; padding-left:16px;}
908 table.cal .ending a, p.cal.legend .ending {background: url(../images/bullet_end.png) no-repeat -1px -2px; padding-left:16px;}
906 table.cal .starting.ending a, p.cal.legend .starting.ending {background: url(../images/bullet_diamond.png) no-repeat -1px -2px; padding-left:16px;}
909 table.cal .starting.ending a, p.cal.legend .starting.ending {background: url(../images/bullet_diamond.png) no-repeat -1px -2px; padding-left:16px;}
907 p.cal.legend span {display:block;}
910 p.cal.legend span {display:block;}
908
911
909 /***** Tooltips ******/
912 /***** Tooltips ******/
910 .tooltip{position:relative;z-index:24;}
913 .tooltip{position:relative;z-index:24;}
911 .tooltip:hover{z-index:25;color:#000;}
914 .tooltip:hover{z-index:25;color:#000;}
912 .tooltip span.tip{display: none; text-align:left;}
915 .tooltip span.tip{display: none; text-align:left;}
913
916
914 div.tooltip:hover span.tip{
917 div.tooltip:hover span.tip{
915 display:block;
918 display:block;
916 position:absolute;
919 position:absolute;
917 top:12px; width:270px;
920 top:12px; width:270px;
918 border:1px solid #555;
921 border:1px solid #555;
919 background-color:#fff;
922 background-color:#fff;
920 padding: 4px;
923 padding: 4px;
921 font-size: 0.8em;
924 font-size: 0.8em;
922 color:#505050;
925 color:#505050;
923 }
926 }
924
927
925 img.ui-datepicker-trigger {
928 img.ui-datepicker-trigger {
926 cursor: pointer;
929 cursor: pointer;
927 vertical-align: middle;
930 vertical-align: middle;
928 margin-left: 4px;
931 margin-left: 4px;
929 }
932 }
930
933
931 /***** Progress bar *****/
934 /***** Progress bar *****/
932 table.progress {
935 table.progress {
933 border-collapse: collapse;
936 border-collapse: collapse;
934 border-spacing: 0pt;
937 border-spacing: 0pt;
935 empty-cells: show;
938 empty-cells: show;
936 text-align: center;
939 text-align: center;
937 float:left;
940 float:left;
938 margin: 1px 6px 1px 0px;
941 margin: 1px 6px 1px 0px;
939 }
942 }
940
943
941 table.progress {width:80px;}
944 table.progress {width:80px;}
942 table.progress td { height: 1em; }
945 table.progress td { height: 1em; }
943 table.progress td.closed { background: #BAE0BA none repeat scroll 0%; }
946 table.progress td.closed { background: #BAE0BA none repeat scroll 0%; }
944 table.progress td.done { background: #D3EDD3 none repeat scroll 0%; }
947 table.progress td.done { background: #D3EDD3 none repeat scroll 0%; }
945 table.progress td.todo { background: #eee none repeat scroll 0%; }
948 table.progress td.todo { background: #eee none repeat scroll 0%; }
946 p.percent {font-size: 80%; margin:0;}
949 p.percent {font-size: 80%; margin:0;}
947 p.progress-info {clear: left; font-size: 80%; margin-top:-4px; color:#777;}
950 p.progress-info {clear: left; font-size: 80%; margin-top:-4px; color:#777;}
948
951
949 .version-overview table.progress {width:40em;}
952 .version-overview table.progress {width:40em;}
950 .version-overview table.progress td { height: 1.2em; }
953 .version-overview table.progress td { height: 1.2em; }
951
954
952 /***** Tabs *****/
955 /***** Tabs *****/
953 #content .tabs {height: 2.6em; margin-bottom:1.2em; position:relative; overflow:hidden;}
956 #content .tabs {height: 2.6em; margin-bottom:1.2em; position:relative; overflow:hidden;}
954 #content .tabs ul {margin:0; position:absolute; bottom:0; padding-left:0.5em; width: 2000px; border-bottom: 1px solid #bbbbbb;}
957 #content .tabs ul {margin:0; position:absolute; bottom:0; padding-left:0.5em; width: 2000px; border-bottom: 1px solid #bbbbbb;}
955 #content .tabs ul li {
958 #content .tabs ul li {
956 float:left;
959 float:left;
957 list-style-type:none;
960 list-style-type:none;
958 white-space:nowrap;
961 white-space:nowrap;
959 margin-right:4px;
962 margin-right:4px;
960 background:#fff;
963 background:#fff;
961 position:relative;
964 position:relative;
962 margin-bottom:-1px;
965 margin-bottom:-1px;
963 }
966 }
964 #content .tabs ul li a{
967 #content .tabs ul li a{
965 display:block;
968 display:block;
966 font-size: 0.9em;
969 font-size: 0.9em;
967 text-decoration:none;
970 text-decoration:none;
968 line-height:1.3em;
971 line-height:1.3em;
969 padding:4px 6px 4px 6px;
972 padding:4px 6px 4px 6px;
970 border: 1px solid #ccc;
973 border: 1px solid #ccc;
971 border-bottom: 1px solid #bbbbbb;
974 border-bottom: 1px solid #bbbbbb;
972 background-color: #f6f6f6;
975 background-color: #f6f6f6;
973 color:#999;
976 color:#999;
974 font-weight:bold;
977 font-weight:bold;
975 border-top-left-radius:3px;
978 border-top-left-radius:3px;
976 border-top-right-radius:3px;
979 border-top-right-radius:3px;
977 }
980 }
978
981
979 #content .tabs ul li a:hover {
982 #content .tabs ul li a:hover {
980 background-color: #ffffdd;
983 background-color: #ffffdd;
981 text-decoration:none;
984 text-decoration:none;
982 }
985 }
983
986
984 #content .tabs ul li a.selected {
987 #content .tabs ul li a.selected {
985 background-color: #fff;
988 background-color: #fff;
986 border: 1px solid #bbbbbb;
989 border: 1px solid #bbbbbb;
987 border-bottom: 1px solid #fff;
990 border-bottom: 1px solid #fff;
988 color:#444;
991 color:#444;
989 }
992 }
990
993
991 #content .tabs ul li a.selected:hover {background-color: #fff;}
994 #content .tabs ul li a.selected:hover {background-color: #fff;}
992
995
993 div.tabs-buttons { position:absolute; right: 0; width: 54px; height: 24px; background: white; bottom: 0; border-bottom: 1px solid #bbbbbb; }
996 div.tabs-buttons { position:absolute; right: 0; width: 54px; height: 24px; background: white; bottom: 0; border-bottom: 1px solid #bbbbbb; }
994
997
995 button.tab-left, button.tab-right {
998 button.tab-left, button.tab-right {
996 font-size: 0.9em;
999 font-size: 0.9em;
997 cursor: pointer;
1000 cursor: pointer;
998 height:24px;
1001 height:24px;
999 border: 1px solid #ccc;
1002 border: 1px solid #ccc;
1000 border-bottom: 1px solid #bbbbbb;
1003 border-bottom: 1px solid #bbbbbb;
1001 position:absolute;
1004 position:absolute;
1002 padding:4px;
1005 padding:4px;
1003 width: 20px;
1006 width: 20px;
1004 bottom: -1px;
1007 bottom: -1px;
1005 }
1008 }
1006 button.tab-left:hover, button.tab-right:hover {
1009 button.tab-left:hover, button.tab-right:hover {
1007 background-color: #f5f5f5;
1010 background-color: #f5f5f5;
1008 }
1011 }
1009 button.tab-left:focus, button.tab-right:focus {
1012 button.tab-left:focus, button.tab-right:focus {
1010 outline: 0;
1013 outline: 0;
1011 }
1014 }
1012
1015
1013 button.tab-left {
1016 button.tab-left {
1014 right: 20px;
1017 right: 20px;
1015 background: #eeeeee url(../images/bullet_arrow_left.png) no-repeat 50% 50%;
1018 background: #eeeeee url(../images/bullet_arrow_left.png) no-repeat 50% 50%;
1016 border-top-left-radius:3px;
1019 border-top-left-radius:3px;
1017 }
1020 }
1018
1021
1019 button.tab-right {
1022 button.tab-right {
1020 right: 0;
1023 right: 0;
1021 background: #eeeeee url(../images/bullet_arrow_right.png) no-repeat 50% 50%;
1024 background: #eeeeee url(../images/bullet_arrow_right.png) no-repeat 50% 50%;
1022 border-top-right-radius:3px;
1025 border-top-right-radius:3px;
1023 }
1026 }
1024
1027
1025 button.tab-left.disabled, button.tab-right.disabled {
1028 button.tab-left.disabled, button.tab-right.disabled {
1026 background-color: #ccc;
1029 background-color: #ccc;
1027 cursor: unset;
1030 cursor: unset;
1028 }
1031 }
1029
1032
1030 /***** Diff *****/
1033 /***** Diff *****/
1031 .diff_out { background: #fcc; }
1034 .diff_out { background: #fcc; }
1032 .diff_out span { background: #faa; }
1035 .diff_out span { background: #faa; }
1033 .diff_in { background: #cfc; }
1036 .diff_in { background: #cfc; }
1034 .diff_in span { background: #afa; }
1037 .diff_in span { background: #afa; }
1035
1038
1036 .text-diff {
1039 .text-diff {
1037 padding: 1em;
1040 padding: 1em;
1038 background-color:#f6f6f6;
1041 background-color:#f6f6f6;
1039 color:#505050;
1042 color:#505050;
1040 border: 1px solid #e4e4e4;
1043 border: 1px solid #e4e4e4;
1041 }
1044 }
1042
1045
1043 /***** Wiki *****/
1046 /***** Wiki *****/
1044 div.wiki table {
1047 div.wiki table {
1045 border-collapse: collapse;
1048 border-collapse: collapse;
1046 margin-bottom: 1em;
1049 margin-bottom: 1em;
1047 }
1050 }
1048
1051
1049 div.wiki table, div.wiki td, div.wiki th {
1052 div.wiki table, div.wiki td, div.wiki th {
1050 border: 1px solid #bbb;
1053 border: 1px solid #bbb;
1051 padding: 4px;
1054 padding: 4px;
1052 }
1055 }
1053
1056
1054 div.wiki .noborder, div.wiki .noborder td, div.wiki .noborder th {border:0;}
1057 div.wiki .noborder, div.wiki .noborder td, div.wiki .noborder th {border:0;}
1055
1058
1056 div.wiki .external {
1059 div.wiki .external {
1057 background-position: 0% 60%;
1060 background-position: 0% 60%;
1058 background-repeat: no-repeat;
1061 background-repeat: no-repeat;
1059 padding-left: 12px;
1062 padding-left: 12px;
1060 background-image: url(../images/external.png);
1063 background-image: url(../images/external.png);
1061 }
1064 }
1062
1065
1063 div.wiki a {word-wrap: break-word;}
1066 div.wiki a {word-wrap: break-word;}
1064 div.wiki a.new {color: #b73535;}
1067 div.wiki a.new {color: #b73535;}
1065
1068
1066 div.wiki ul, div.wiki ol {margin-bottom:1em;}
1069 div.wiki ul, div.wiki ol {margin-bottom:1em;}
1067 div.wiki li>ul, div.wiki li>ol {margin-bottom: 0;}
1070 div.wiki li>ul, div.wiki li>ol {margin-bottom: 0;}
1068
1071
1069 div.wiki pre {
1072 div.wiki pre {
1070 margin: 1em 1em 1em 1.6em;
1073 margin: 1em 1em 1em 1.6em;
1071 padding: 8px;
1074 padding: 8px;
1072 background-color: #fafafa;
1075 background-color: #fafafa;
1073 border: 1px solid #e2e2e2;
1076 border: 1px solid #e2e2e2;
1074 border-radius: 3px;
1077 border-radius: 3px;
1075 width:auto;
1078 width:auto;
1076 overflow-x: auto;
1079 overflow-x: auto;
1077 overflow-y: hidden;
1080 overflow-y: hidden;
1078 }
1081 }
1079
1082
1080 div.wiki ul.toc {
1083 div.wiki ul.toc {
1081 background-color: #ffffdd;
1084 background-color: #ffffdd;
1082 border: 1px solid #e4e4e4;
1085 border: 1px solid #e4e4e4;
1083 padding: 4px;
1086 padding: 4px;
1084 line-height: 1.2em;
1087 line-height: 1.2em;
1085 margin-bottom: 12px;
1088 margin-bottom: 12px;
1086 margin-right: 12px;
1089 margin-right: 12px;
1087 margin-left: 0;
1090 margin-left: 0;
1088 display: table
1091 display: table
1089 }
1092 }
1090 * html div.wiki ul.toc { width: 50%; } /* IE6 doesn't autosize div */
1093 * html div.wiki ul.toc { width: 50%; } /* IE6 doesn't autosize div */
1091
1094
1092 div.wiki ul.toc.right { float: right; margin-left: 12px; margin-right: 0; width: auto; }
1095 div.wiki ul.toc.right { float: right; margin-left: 12px; margin-right: 0; width: auto; }
1093 div.wiki ul.toc.left { float: left; margin-right: 12px; margin-left: 0; width: auto; }
1096 div.wiki ul.toc.left { float: left; margin-right: 12px; margin-left: 0; width: auto; }
1094 div.wiki ul.toc ul { margin: 0; padding: 0; }
1097 div.wiki ul.toc ul { margin: 0; padding: 0; }
1095 div.wiki ul.toc li {list-style-type:none; margin: 0; font-size:12px;}
1098 div.wiki ul.toc li {list-style-type:none; margin: 0; font-size:12px;}
1096 div.wiki ul.toc>li:first-child {margin-bottom: .5em; color: #777;}
1099 div.wiki ul.toc>li:first-child {margin-bottom: .5em; color: #777;}
1097 div.wiki ul.toc li li {margin-left: 1.5em; font-size:10px;}
1100 div.wiki ul.toc li li {margin-left: 1.5em; font-size:10px;}
1098 div.wiki ul.toc a {
1101 div.wiki ul.toc a {
1099 font-size: 0.9em;
1102 font-size: 0.9em;
1100 font-weight: normal;
1103 font-weight: normal;
1101 text-decoration: none;
1104 text-decoration: none;
1102 color: #606060;
1105 color: #606060;
1103 }
1106 }
1104 div.wiki ul.toc a:hover { color: #c61a1a; text-decoration: underline;}
1107 div.wiki ul.toc a:hover { color: #c61a1a; text-decoration: underline;}
1105
1108
1106 a.wiki-anchor { display: none; margin-left: 6px; text-decoration: none; }
1109 a.wiki-anchor { display: none; margin-left: 6px; text-decoration: none; }
1107 a.wiki-anchor:hover { color: #aaa !important; text-decoration: none; }
1110 a.wiki-anchor:hover { color: #aaa !important; text-decoration: none; }
1108 h1:hover a.wiki-anchor, h2:hover a.wiki-anchor, h3:hover a.wiki-anchor { display: inline; color: #ddd; }
1111 h1:hover a.wiki-anchor, h2:hover a.wiki-anchor, h3:hover a.wiki-anchor { display: inline; color: #ddd; }
1109
1112
1110 div.wiki img {vertical-align:middle; max-width:100%;}
1113 div.wiki img {vertical-align:middle; max-width:100%;}
1111
1114
1112 /***** My page layout *****/
1115 /***** My page layout *****/
1113 .block-receiver {
1116 .block-receiver {
1114 border:1px dashed #c0c0c0;
1117 border:1px dashed #c0c0c0;
1115 margin-bottom: 20px;
1118 margin-bottom: 20px;
1116 padding: 15px 0 15px 0;
1119 padding: 15px 0 15px 0;
1117 }
1120 }
1118
1121
1119 .mypage-box {
1122 .mypage-box {
1120 margin:0 0 20px 0;
1123 margin:0 0 20px 0;
1121 color:#505050;
1124 color:#505050;
1122 line-height:1.5em;
1125 line-height:1.5em;
1123 }
1126 }
1124 .mypage-box .icon-close {
1127 .mypage-box .icon-close {
1125 float:right;
1128 float:right;
1126 }
1129 }
1127
1130
1128 .handle {cursor: move;}
1131 .handle {cursor: move;}
1129
1132
1130 /***** Gantt chart *****/
1133 /***** Gantt chart *****/
1131 .gantt_hdr {
1134 .gantt_hdr {
1132 position:absolute;
1135 position:absolute;
1133 top:0;
1136 top:0;
1134 height:16px;
1137 height:16px;
1135 border-top: 1px solid #c0c0c0;
1138 border-top: 1px solid #c0c0c0;
1136 border-bottom: 1px solid #c0c0c0;
1139 border-bottom: 1px solid #c0c0c0;
1137 border-right: 1px solid #c0c0c0;
1140 border-right: 1px solid #c0c0c0;
1138 text-align: center;
1141 text-align: center;
1139 overflow: hidden;
1142 overflow: hidden;
1140 }
1143 }
1141
1144
1142 .gantt_hdr.nwday {background-color:#f1f1f1; color:#999;}
1145 .gantt_hdr.nwday {background-color:#f1f1f1; color:#999;}
1143
1146
1144 .gantt_subjects { font-size: 0.8em; }
1147 .gantt_subjects { font-size: 0.8em; }
1145 .gantt_subjects div { line-height:16px;height:16px;overflow:hidden;white-space:nowrap;text-overflow: ellipsis; }
1148 .gantt_subjects div { line-height:16px;height:16px;overflow:hidden;white-space:nowrap;text-overflow: ellipsis; }
1146
1149
1147 .task {
1150 .task {
1148 position: absolute;
1151 position: absolute;
1149 height:8px;
1152 height:8px;
1150 font-size:0.8em;
1153 font-size:0.8em;
1151 color:#888;
1154 color:#888;
1152 padding:0;
1155 padding:0;
1153 margin:0;
1156 margin:0;
1154 line-height:16px;
1157 line-height:16px;
1155 white-space:nowrap;
1158 white-space:nowrap;
1156 }
1159 }
1157
1160
1158 .task.label {width:100%;}
1161 .task.label {width:100%;}
1159 .task.label.project, .task.label.version { font-weight: bold; }
1162 .task.label.project, .task.label.version { font-weight: bold; }
1160
1163
1161 .task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; }
1164 .task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; }
1162 .task_done { background:#00c600 url(../images/task_done.png); border: 1px solid #00c600; }
1165 .task_done { background:#00c600 url(../images/task_done.png); border: 1px solid #00c600; }
1163 .task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; }
1166 .task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; }
1164
1167
1165 .task_todo.parent { background: #888; border: 1px solid #888; height: 3px;}
1168 .task_todo.parent { background: #888; border: 1px solid #888; height: 3px;}
1166 .task_late.parent, .task_done.parent { height: 3px;}
1169 .task_late.parent, .task_done.parent { height: 3px;}
1167 .task.parent.marker.starting { position: absolute; background: url(../images/task_parent_end.png) no-repeat 0 0; width: 8px; height: 16px; margin-left: -4px; left: 0px; top: -1px;}
1170 .task.parent.marker.starting { position: absolute; background: url(../images/task_parent_end.png) no-repeat 0 0; width: 8px; height: 16px; margin-left: -4px; left: 0px; top: -1px;}
1168 .task.parent.marker.ending { position: absolute; background: url(../images/task_parent_end.png) no-repeat 0 0; width: 8px; height: 16px; margin-left: -4px; right: 0px; top: -1px;}
1171 .task.parent.marker.ending { position: absolute; background: url(../images/task_parent_end.png) no-repeat 0 0; width: 8px; height: 16px; margin-left: -4px; right: 0px; top: -1px;}
1169
1172
1170 .version.task_late { background:#f66 url(../images/milestone_late.png); border: 1px solid #f66; height: 2px; margin-top: 3px;}
1173 .version.task_late { background:#f66 url(../images/milestone_late.png); border: 1px solid #f66; height: 2px; margin-top: 3px;}
1171 .version.task_done { background:#00c600 url(../images/milestone_done.png); border: 1px solid #00c600; height: 2px; margin-top: 3px;}
1174 .version.task_done { background:#00c600 url(../images/milestone_done.png); border: 1px solid #00c600; height: 2px; margin-top: 3px;}
1172 .version.task_todo { background:#fff url(../images/milestone_todo.png); border: 1px solid #fff; height: 2px; margin-top: 3px;}
1175 .version.task_todo { background:#fff url(../images/milestone_todo.png); border: 1px solid #fff; height: 2px; margin-top: 3px;}
1173 .version.marker { background-image:url(../images/version_marker.png); background-repeat: no-repeat; border: 0; margin-left: -4px; margin-top: 1px; }
1176 .version.marker { background-image:url(../images/version_marker.png); background-repeat: no-repeat; border: 0; margin-left: -4px; margin-top: 1px; }
1174
1177
1175 .project.task_late { background:#f66 url(../images/milestone_late.png); border: 1px solid #f66; height: 2px; margin-top: 3px;}
1178 .project.task_late { background:#f66 url(../images/milestone_late.png); border: 1px solid #f66; height: 2px; margin-top: 3px;}
1176 .project.task_done { background:#00c600 url(../images/milestone_done.png); border: 1px solid #00c600; height: 2px; margin-top: 3px;}
1179 .project.task_done { background:#00c600 url(../images/milestone_done.png); border: 1px solid #00c600; height: 2px; margin-top: 3px;}
1177 .project.task_todo { background:#fff url(../images/milestone_todo.png); border: 1px solid #fff; height: 2px; margin-top: 3px;}
1180 .project.task_todo { background:#fff url(../images/milestone_todo.png); border: 1px solid #fff; height: 2px; margin-top: 3px;}
1178 .project.marker { background-image:url(../images/project_marker.png); background-repeat: no-repeat; border: 0; margin-left: -4px; margin-top: 1px; }
1181 .project.marker { background-image:url(../images/project_marker.png); background-repeat: no-repeat; border: 0; margin-left: -4px; margin-top: 1px; }
1179
1182
1180 .version-behind-schedule a, .issue-behind-schedule a {color: #f66914;}
1183 .version-behind-schedule a, .issue-behind-schedule a {color: #f66914;}
1181 .version-overdue a, .issue-overdue a, .project-overdue a {color: #f00;}
1184 .version-overdue a, .issue-overdue a, .project-overdue a {color: #f00;}
1182
1185
1183 /***** Icons *****/
1186 /***** Icons *****/
1184 .icon {
1187 .icon {
1185 background-position: 0% 50%;
1188 background-position: 0% 50%;
1186 background-repeat: no-repeat;
1189 background-repeat: no-repeat;
1187 padding-left: 20px;
1190 padding-left: 20px;
1188 }
1191 }
1189 .icon-only {
1192 .icon-only {
1190 background-position: 0% 50%;
1193 background-position: 0% 50%;
1191 background-repeat: no-repeat;
1194 background-repeat: no-repeat;
1192 padding-left: 16px;
1195 padding-left: 16px;
1193 display: inline-block;
1196 display: inline-block;
1194 width: 0;
1197 width: 0;
1195 height: 16px;
1198 height: 16px;
1196 overflow: hidden;
1199 overflow: hidden;
1197 padding-top: 0;
1200 padding-top: 0;
1198 padding-bottom: 0;
1201 padding-bottom: 0;
1199 font-size: 8px;
1202 font-size: 8px;
1200 vertical-align: middle;
1203 vertical-align: middle;
1201 }
1204 }
1202 .icon-only::after {
1205 .icon-only::after {
1203 content: "&nbsp;";
1206 content: "&nbsp;";
1204 }
1207 }
1205
1208
1206 .icon-add { background-image: url(../images/add.png); }
1209 .icon-add { background-image: url(../images/add.png); }
1207 .icon-edit { background-image: url(../images/edit.png); }
1210 .icon-edit { background-image: url(../images/edit.png); }
1208 .icon-copy { background-image: url(../images/copy.png); }
1211 .icon-copy { background-image: url(../images/copy.png); }
1209 .icon-duplicate { background-image: url(../images/duplicate.png); }
1212 .icon-duplicate { background-image: url(../images/duplicate.png); }
1210 .icon-del { background-image: url(../images/delete.png); }
1213 .icon-del { background-image: url(../images/delete.png); }
1211 .icon-move { background-image: url(../images/move.png); }
1214 .icon-move { background-image: url(../images/move.png); }
1212 .icon-save { background-image: url(../images/save.png); }
1215 .icon-save { background-image: url(../images/save.png); }
1213 .icon-cancel { background-image: url(../images/cancel.png); }
1216 .icon-cancel { background-image: url(../images/cancel.png); }
1214 .icon-multiple { background-image: url(../images/table_multiple.png); }
1217 .icon-multiple { background-image: url(../images/table_multiple.png); }
1215 .icon-folder { background-image: url(../images/folder.png); }
1218 .icon-folder { background-image: url(../images/folder.png); }
1216 .open .icon-folder { background-image: url(../images/folder_open.png); }
1219 .open .icon-folder { background-image: url(../images/folder_open.png); }
1217 .icon-package { background-image: url(../images/package.png); }
1220 .icon-package { background-image: url(../images/package.png); }
1218 .icon-user { background-image: url(../images/user.png); }
1221 .icon-user { background-image: url(../images/user.png); }
1219 .icon-project, .icon-projects { background-image: url(../images/projects.png); }
1222 .icon-project, .icon-projects { background-image: url(../images/projects.png); }
1220 .icon-help { background-image: url(../images/help.png); }
1223 .icon-help { background-image: url(../images/help.png); }
1221 .icon-attachment { background-image: url(../images/attachment.png); }
1224 .icon-attachment { background-image: url(../images/attachment.png); }
1222 .icon-history { background-image: url(../images/history.png); }
1225 .icon-history { background-image: url(../images/history.png); }
1223 .icon-time-entry, .icon-time { background-image: url(../images/time.png); }
1226 .icon-time-entry, .icon-time { background-image: url(../images/time.png); }
1224 .icon-time-add { background-image: url(../images/time_add.png); }
1227 .icon-time-add { background-image: url(../images/time_add.png); }
1225 .icon-stats { background-image: url(../images/stats.png); }
1228 .icon-stats { background-image: url(../images/stats.png); }
1226 .icon-warning { background-image: url(../images/warning.png); }
1229 .icon-warning { background-image: url(../images/warning.png); }
1227 .icon-error { background-image: url(../images/exclamation.png); }
1230 .icon-error { background-image: url(../images/exclamation.png); }
1228 .icon-fav { background-image: url(../images/fav.png); }
1231 .icon-fav { background-image: url(../images/fav.png); }
1229 .icon-fav-off { background-image: url(../images/fav_off.png); }
1232 .icon-fav-off { background-image: url(../images/fav_off.png); }
1230 .icon-reload { background-image: url(../images/reload.png); }
1233 .icon-reload { background-image: url(../images/reload.png); }
1231 .icon-lock, .icon-locked { background-image: url(../images/locked.png); }
1234 .icon-lock, .icon-locked { background-image: url(../images/locked.png); }
1232 .icon-unlock { background-image: url(../images/unlock.png); }
1235 .icon-unlock { background-image: url(../images/unlock.png); }
1233 .icon-checked { background-image: url(../images/toggle_check.png); }
1236 .icon-checked { background-image: url(../images/toggle_check.png); }
1234 .icon-report { background-image: url(../images/report.png); }
1237 .icon-report { background-image: url(../images/report.png); }
1235 .icon-comment, .icon-comments { background-image: url(../images/comment.png); }
1238 .icon-comment, .icon-comments { background-image: url(../images/comment.png); }
1236 .icon-summary { background-image: url(../images/lightning.png); }
1239 .icon-summary { background-image: url(../images/lightning.png); }
1237 .icon-server-authentication { background-image: url(../images/server_key.png); }
1240 .icon-server-authentication { background-image: url(../images/server_key.png); }
1238 .icon-issue { background-image: url(../images/ticket.png); }
1241 .icon-issue { background-image: url(../images/ticket.png); }
1239 .icon-zoom-in { background-image: url(../images/zoom_in.png); }
1242 .icon-zoom-in { background-image: url(../images/zoom_in.png); }
1240 .icon-zoom-out { background-image: url(../images/zoom_out.png); }
1243 .icon-zoom-out { background-image: url(../images/zoom_out.png); }
1241 .icon-magnifier { background-image: url(../images/magnifier.png); }
1244 .icon-magnifier { background-image: url(../images/magnifier.png); }
1242 .icon-passwd { background-image: url(../images/textfield_key.png); }
1245 .icon-passwd { background-image: url(../images/textfield_key.png); }
1243 .icon-arrow-right, .icon-test, .icon-sticky { background-image: url(../images/bullet_go.png); }
1246 .icon-arrow-right, .icon-test, .icon-sticky { background-image: url(../images/bullet_go.png); }
1244 .icon-email { background-image: url(../images/email.png); }
1247 .icon-email { background-image: url(../images/email.png); }
1245 .icon-email-disabled { background-image: url(../images/email_disabled.png); }
1248 .icon-email-disabled { background-image: url(../images/email_disabled.png); }
1246 .icon-email-add { background-image: url(../images/email_add.png); }
1249 .icon-email-add { background-image: url(../images/email_add.png); }
1247 .icon-move-up { background-image: url(../images/1uparrow.png); }
1250 .icon-move-up { background-image: url(../images/1uparrow.png); }
1248 .icon-move-top { background-image: url(../images/2uparrow.png); }
1251 .icon-move-top { background-image: url(../images/2uparrow.png); }
1249 .icon-move-down { background-image: url(../images/1downarrow.png); }
1252 .icon-move-down { background-image: url(../images/1downarrow.png); }
1250 .icon-move-bottom { background-image: url(../images/2downarrow.png); }
1253 .icon-move-bottom { background-image: url(../images/2downarrow.png); }
1251 .icon-ok { background-image: url(../images/true.png); }
1254 .icon-ok { background-image: url(../images/true.png); }
1252 .icon-not-ok { background-image: url(../images/false.png); }
1255 .icon-not-ok { background-image: url(../images/false.png); }
1253 .icon-link-break { background-image: url(../images/link_break.png); }
1256 .icon-link-break { background-image: url(../images/link_break.png); }
1254 .icon-list { background-image: url(../images/text_list_bullets.png); }
1257 .icon-list { background-image: url(../images/text_list_bullets.png); }
1255 .icon-close { background-image: url(../images/close.png); }
1258 .icon-close { background-image: url(../images/close.png); }
1256 .icon-close:hover { background-image: url(../images/close_hl.png); }
1259 .icon-close:hover { background-image: url(../images/close_hl.png); }
1257 .icon-settings { background-image: url(../images/changeset.png); }
1260 .icon-settings { background-image: url(../images/changeset.png); }
1258 .icon-group, .icon-groupnonmember, .icon-groupanonymous { background-image: url(../images/group.png); }
1261 .icon-group, .icon-groupnonmember, .icon-groupanonymous { background-image: url(../images/group.png); }
1259 .icon-roles { background-image: url(../images/database_key.png); }
1262 .icon-roles { background-image: url(../images/database_key.png); }
1260 .icon-issue-edit { background-image: url(../images/ticket_edit.png); }
1263 .icon-issue-edit { background-image: url(../images/ticket_edit.png); }
1261 .icon-workflows { background-image: url(../images/ticket_go.png); }
1264 .icon-workflows { background-image: url(../images/ticket_go.png); }
1262 .icon-custom-fields { background-image: url(../images/textfield.png); }
1265 .icon-custom-fields { background-image: url(../images/textfield.png); }
1263 .icon-plugins { background-image: url(../images/plugin.png); }
1266 .icon-plugins { background-image: url(../images/plugin.png); }
1264 .icon-news { background-image: url(../images/news.png); }
1267 .icon-news { background-image: url(../images/news.png); }
1265 .icon-issue-closed { background-image: url(../images/ticket_checked.png); }
1268 .icon-issue-closed { background-image: url(../images/ticket_checked.png); }
1266 .icon-issue-note { background-image: url(../images/ticket_note.png); }
1269 .icon-issue-note { background-image: url(../images/ticket_note.png); }
1267 .icon-changeset { background-image: url(../images/changeset.png); }
1270 .icon-changeset { background-image: url(../images/changeset.png); }
1268 .icon-message { background-image: url(../images/message.png); }
1271 .icon-message { background-image: url(../images/message.png); }
1269 .icon-reply { background-image: url(../images/comments.png); }
1272 .icon-reply { background-image: url(../images/comments.png); }
1270 .icon-wiki-page { background-image: url(../images/wiki_edit.png); }
1273 .icon-wiki-page { background-image: url(../images/wiki_edit.png); }
1271 .icon-document { background-image: url(../images/document.png); }
1274 .icon-document { background-image: url(../images/document.png); }
1272 .icon-project { background-image: url(../images/projects.png); }
1275 .icon-project { background-image: url(../images/projects.png); }
1273 .icon-add-bullet { background-image: url(../images/bullet_add.png); }
1276 .icon-add-bullet { background-image: url(../images/bullet_add.png); }
1274 .icon-shared { background-image: url(../images/link.png) };
1277 .icon-shared { background-image: url(../images/link.png) };
1275
1278
1276 .icon-file { background-image: url(../images/files/default.png); }
1279 .icon-file { background-image: url(../images/files/default.png); }
1277 .icon-file.text-plain { background-image: url(../images/files/text.png); }
1280 .icon-file.text-plain { background-image: url(../images/files/text.png); }
1278 .icon-file.text-x-c { background-image: url(../images/files/c.png); }
1281 .icon-file.text-x-c { background-image: url(../images/files/c.png); }
1279 .icon-file.text-x-csharp { background-image: url(../images/files/csharp.png); }
1282 .icon-file.text-x-csharp { background-image: url(../images/files/csharp.png); }
1280 .icon-file.text-x-java { background-image: url(../images/files/java.png); }
1283 .icon-file.text-x-java { background-image: url(../images/files/java.png); }
1281 .icon-file.text-x-javascript { background-image: url(../images/files/js.png); }
1284 .icon-file.text-x-javascript { background-image: url(../images/files/js.png); }
1282 .icon-file.text-x-php { background-image: url(../images/files/php.png); }
1285 .icon-file.text-x-php { background-image: url(../images/files/php.png); }
1283 .icon-file.text-x-ruby { background-image: url(../images/files/ruby.png); }
1286 .icon-file.text-x-ruby { background-image: url(../images/files/ruby.png); }
1284 .icon-file.text-xml { background-image: url(../images/files/xml.png); }
1287 .icon-file.text-xml { background-image: url(../images/files/xml.png); }
1285 .icon-file.text-css { background-image: url(../images/files/css.png); }
1288 .icon-file.text-css { background-image: url(../images/files/css.png); }
1286 .icon-file.text-html { background-image: url(../images/files/html.png); }
1289 .icon-file.text-html { background-image: url(../images/files/html.png); }
1287 .icon-file.image-gif { background-image: url(../images/files/image.png); }
1290 .icon-file.image-gif { background-image: url(../images/files/image.png); }
1288 .icon-file.image-jpeg { background-image: url(../images/files/image.png); }
1291 .icon-file.image-jpeg { background-image: url(../images/files/image.png); }
1289 .icon-file.image-png { background-image: url(../images/files/image.png); }
1292 .icon-file.image-png { background-image: url(../images/files/image.png); }
1290 .icon-file.image-tiff { background-image: url(../images/files/image.png); }
1293 .icon-file.image-tiff { background-image: url(../images/files/image.png); }
1291 .icon-file.application-pdf { background-image: url(../images/files/pdf.png); }
1294 .icon-file.application-pdf { background-image: url(../images/files/pdf.png); }
1292 .icon-file.application-zip { background-image: url(../images/files/zip.png); }
1295 .icon-file.application-zip { background-image: url(../images/files/zip.png); }
1293 .icon-file.application-x-gzip { background-image: url(../images/files/zip.png); }
1296 .icon-file.application-x-gzip { background-image: url(../images/files/zip.png); }
1294
1297
1295 .sort-handle { width:16px; height:16px; background:url(../images/reorder.png) no-repeat 0 50%; cursor:move; }
1298 .sort-handle { width:16px; height:16px; background:url(../images/reorder.png) no-repeat 0 50%; cursor:move; }
1296 .sort-handle.ajax-loading { background-image: url(../images/loading.gif); }
1299 .sort-handle.ajax-loading { background-image: url(../images/loading.gif); }
1297 tr.ui-sortable-helper { border:1px solid #e4e4e4; }
1300 tr.ui-sortable-helper { border:1px solid #e4e4e4; }
1298
1301
1299 .contextual>*:not(:first-child), .buttons>.icon:not(:first-child) { margin-left: 5px; }
1302 .contextual>*:not(:first-child), .buttons>.icon:not(:first-child) { margin-left: 5px; }
1300
1303
1301 img.gravatar {
1304 img.gravatar {
1302 vertical-align: middle;
1305 vertical-align: middle;
1303 border-radius: 20%;
1306 border-radius: 20%;
1304 }
1307 }
1305
1308
1306 div.issue img.gravatar {
1309 div.issue img.gravatar {
1307 float: left;
1310 float: left;
1308 margin: 0 6px 0 0;
1311 margin: 0 6px 0 0;
1309 }
1312 }
1310
1313
1311 h2 img.gravatar {margin: -2px 4px -4px 0;}
1314 h2 img.gravatar {margin: -2px 4px -4px 0;}
1312 h3 img.gravatar {margin: -4px 4px -4px 0;}
1315 h3 img.gravatar {margin: -4px 4px -4px 0;}
1313 h4 img.gravatar {margin: -2px 4px -4px 0;}
1316 h4 img.gravatar {margin: -2px 4px -4px 0;}
1314 td.username img.gravatar {margin: 0 0.5em 0 0; vertical-align: top;}
1317 td.username img.gravatar {margin: 0 0.5em 0 0; vertical-align: top;}
1315 #activity dt img.gravatar {float: left; margin: 0 1em 1em 0;}
1318 #activity dt img.gravatar {float: left; margin: 0 1em 1em 0;}
1316 /* Used on 12px Gravatar img tags without the icon background */
1319 /* Used on 12px Gravatar img tags without the icon background */
1317 .icon-gravatar {float: left; margin-right: 4px;}
1320 .icon-gravatar {float: left; margin-right: 4px;}
1318
1321
1319 #activity dt, .journal {clear: left;}
1322 #activity dt, .journal {clear: left;}
1320
1323
1321 .journal-link {float: right;}
1324 .journal-link {float: right;}
1322
1325
1323 h2 img { vertical-align:middle; }
1326 h2 img { vertical-align:middle; }
1324
1327
1325 .hascontextmenu { cursor: context-menu; }
1328 .hascontextmenu { cursor: context-menu; }
1326
1329
1327 .sample-data {border:1px solid #ccc; border-collapse:collapse; background-color:#fff; margin:0.5em;}
1330 .sample-data {border:1px solid #ccc; border-collapse:collapse; background-color:#fff; margin:0.5em;}
1328 .sample-data td {border:1px solid #ccc; padding: 2px 4px; font-family: Consolas, Menlo, "Liberation Mono", Courier, monospace;}
1331 .sample-data td {border:1px solid #ccc; padding: 2px 4px; font-family: Consolas, Menlo, "Liberation Mono", Courier, monospace;}
1329 .sample-data tr:first-child td {font-weight:bold; text-align:center;}
1332 .sample-data tr:first-child td {font-weight:bold; text-align:center;}
1330
1333
1331 .ui-progressbar {position: relative;}
1334 .ui-progressbar {position: relative;}
1332 #progress-label {
1335 #progress-label {
1333 position: absolute; left: 50%; top: 4px;
1336 position: absolute; left: 50%; top: 4px;
1334 font-weight: bold;
1337 font-weight: bold;
1335 color: #555; text-shadow: 1px 1px 0 #fff;
1338 color: #555; text-shadow: 1px 1px 0 #fff;
1336 }
1339 }
1337
1340
1338 /* Custom JQuery styles */
1341 /* Custom JQuery styles */
1339 .ui-datepicker-title select {width:70px !important; margin-top:-2px !important; margin-right:4px !important;}
1342 .ui-datepicker-title select {width:70px !important; margin-top:-2px !important; margin-right:4px !important;}
1340
1343
1341
1344
1342 /************* CodeRay styles *************/
1345 /************* CodeRay styles *************/
1343 .syntaxhl div {display: inline;}
1346 .syntaxhl div {display: inline;}
1344 .syntaxhl .code pre { overflow: auto }
1347 .syntaxhl .code pre { overflow: auto }
1345
1348
1346 .syntaxhl .annotation { color:#007 }
1349 .syntaxhl .annotation { color:#007 }
1347 .syntaxhl .attribute-name { color:#b48 }
1350 .syntaxhl .attribute-name { color:#b48 }
1348 .syntaxhl .attribute-value { color:#700 }
1351 .syntaxhl .attribute-value { color:#700 }
1349 .syntaxhl .binary { color:#549 }
1352 .syntaxhl .binary { color:#549 }
1350 .syntaxhl .binary .char { color:#325 }
1353 .syntaxhl .binary .char { color:#325 }
1351 .syntaxhl .binary .delimiter { color:#325 }
1354 .syntaxhl .binary .delimiter { color:#325 }
1352 .syntaxhl .char { color:#D20 }
1355 .syntaxhl .char { color:#D20 }
1353 .syntaxhl .char .content { color:#D20 }
1356 .syntaxhl .char .content { color:#D20 }
1354 .syntaxhl .char .delimiter { color:#710 }
1357 .syntaxhl .char .delimiter { color:#710 }
1355 .syntaxhl .class { color:#B06; font-weight:bold }
1358 .syntaxhl .class { color:#B06; font-weight:bold }
1356 .syntaxhl .class-variable { color:#369 }
1359 .syntaxhl .class-variable { color:#369 }
1357 .syntaxhl .color { color:#0A0 }
1360 .syntaxhl .color { color:#0A0 }
1358 .syntaxhl .comment { color:#777 }
1361 .syntaxhl .comment { color:#777 }
1359 .syntaxhl .comment .char { color:#444 }
1362 .syntaxhl .comment .char { color:#444 }
1360 .syntaxhl .comment .delimiter { color:#444 }
1363 .syntaxhl .comment .delimiter { color:#444 }
1361 .syntaxhl .constant { color:#036; font-weight:bold }
1364 .syntaxhl .constant { color:#036; font-weight:bold }
1362 .syntaxhl .decorator { color:#B0B }
1365 .syntaxhl .decorator { color:#B0B }
1363 .syntaxhl .definition { color:#099; font-weight:bold }
1366 .syntaxhl .definition { color:#099; font-weight:bold }
1364 .syntaxhl .delimiter { color:black }
1367 .syntaxhl .delimiter { color:black }
1365 .syntaxhl .directive { color:#088; font-weight:bold }
1368 .syntaxhl .directive { color:#088; font-weight:bold }
1366 .syntaxhl .docstring { color:#D42; }
1369 .syntaxhl .docstring { color:#D42; }
1367 .syntaxhl .doctype { color:#34b }
1370 .syntaxhl .doctype { color:#34b }
1368 .syntaxhl .done { text-decoration: line-through; color: gray }
1371 .syntaxhl .done { text-decoration: line-through; color: gray }
1369 .syntaxhl .entity { color:#800; font-weight:bold }
1372 .syntaxhl .entity { color:#800; font-weight:bold }
1370 .syntaxhl .error { color:#F00; background-color:#FAA }
1373 .syntaxhl .error { color:#F00; background-color:#FAA }
1371 .syntaxhl .escape { color:#666 }
1374 .syntaxhl .escape { color:#666 }
1372 .syntaxhl .exception { color:#C00; font-weight:bold }
1375 .syntaxhl .exception { color:#C00; font-weight:bold }
1373 .syntaxhl .float { color:#60E }
1376 .syntaxhl .float { color:#60E }
1374 .syntaxhl .function { color:#06B; font-weight:bold }
1377 .syntaxhl .function { color:#06B; font-weight:bold }
1375 .syntaxhl .function .delimiter { color:#059 }
1378 .syntaxhl .function .delimiter { color:#059 }
1376 .syntaxhl .function .content { color:#037 }
1379 .syntaxhl .function .content { color:#037 }
1377 .syntaxhl .global-variable { color:#d70 }
1380 .syntaxhl .global-variable { color:#d70 }
1378 .syntaxhl .hex { color:#02b }
1381 .syntaxhl .hex { color:#02b }
1379 .syntaxhl .id { color:#33D; font-weight:bold }
1382 .syntaxhl .id { color:#33D; font-weight:bold }
1380 .syntaxhl .include { color:#B44; font-weight:bold }
1383 .syntaxhl .include { color:#B44; font-weight:bold }
1381 .syntaxhl .inline { background-color: hsla(0,0%,0%,0.07); color: black }
1384 .syntaxhl .inline { background-color: hsla(0,0%,0%,0.07); color: black }
1382 .syntaxhl .inline-delimiter { font-weight: bold; color: #666 }
1385 .syntaxhl .inline-delimiter { font-weight: bold; color: #666 }
1383 .syntaxhl .instance-variable { color:#33B }
1386 .syntaxhl .instance-variable { color:#33B }
1384 .syntaxhl .integer { color:#00D }
1387 .syntaxhl .integer { color:#00D }
1385 .syntaxhl .imaginary { color:#f00 }
1388 .syntaxhl .imaginary { color:#f00 }
1386 .syntaxhl .important { color:#D00 }
1389 .syntaxhl .important { color:#D00 }
1387 .syntaxhl .key { color: #606 }
1390 .syntaxhl .key { color: #606 }
1388 .syntaxhl .key .char { color: #60f }
1391 .syntaxhl .key .char { color: #60f }
1389 .syntaxhl .key .delimiter { color: #404 }
1392 .syntaxhl .key .delimiter { color: #404 }
1390 .syntaxhl .keyword { color:#080; font-weight:bold }
1393 .syntaxhl .keyword { color:#080; font-weight:bold }
1391 .syntaxhl .label { color:#970; font-weight:bold }
1394 .syntaxhl .label { color:#970; font-weight:bold }
1392 .syntaxhl .local-variable { color:#950 }
1395 .syntaxhl .local-variable { color:#950 }
1393 .syntaxhl .map .content { color:#808 }
1396 .syntaxhl .map .content { color:#808 }
1394 .syntaxhl .map .delimiter { color:#40A}
1397 .syntaxhl .map .delimiter { color:#40A}
1395 .syntaxhl .map { background-color:hsla(200,100%,50%,0.06); }
1398 .syntaxhl .map { background-color:hsla(200,100%,50%,0.06); }
1396 .syntaxhl .namespace { color:#707; font-weight:bold }
1399 .syntaxhl .namespace { color:#707; font-weight:bold }
1397 .syntaxhl .octal { color:#40E }
1400 .syntaxhl .octal { color:#40E }
1398 .syntaxhl .operator { }
1401 .syntaxhl .operator { }
1399 .syntaxhl .predefined { color:#369; font-weight:bold }
1402 .syntaxhl .predefined { color:#369; font-weight:bold }
1400 .syntaxhl .predefined-constant { color:#069 }
1403 .syntaxhl .predefined-constant { color:#069 }
1401 .syntaxhl .predefined-type { color:#0a8; font-weight:bold }
1404 .syntaxhl .predefined-type { color:#0a8; font-weight:bold }
1402 .syntaxhl .preprocessor { color:#579 }
1405 .syntaxhl .preprocessor { color:#579 }
1403 .syntaxhl .pseudo-class { color:#00C; font-weight:bold }
1406 .syntaxhl .pseudo-class { color:#00C; font-weight:bold }
1404 .syntaxhl .regexp { background-color:hsla(300,100%,50%,0.06); }
1407 .syntaxhl .regexp { background-color:hsla(300,100%,50%,0.06); }
1405 .syntaxhl .regexp .content { color:#808 }
1408 .syntaxhl .regexp .content { color:#808 }
1406 .syntaxhl .regexp .delimiter { color:#404 }
1409 .syntaxhl .regexp .delimiter { color:#404 }
1407 .syntaxhl .regexp .modifier { color:#C2C }
1410 .syntaxhl .regexp .modifier { color:#C2C }
1408 .syntaxhl .reserved { color:#080; font-weight:bold }
1411 .syntaxhl .reserved { color:#080; font-weight:bold }
1409 .syntaxhl .shell { background-color:hsla(120,100%,50%,0.06); }
1412 .syntaxhl .shell { background-color:hsla(120,100%,50%,0.06); }
1410 .syntaxhl .shell .content { color:#2B2 }
1413 .syntaxhl .shell .content { color:#2B2 }
1411 .syntaxhl .shell .delimiter { color:#161 }
1414 .syntaxhl .shell .delimiter { color:#161 }
1412 .syntaxhl .string { background-color:hsla(0,100%,50%,0.05); }
1415 .syntaxhl .string { background-color:hsla(0,100%,50%,0.05); }
1413 .syntaxhl .string .char { color: #b0b }
1416 .syntaxhl .string .char { color: #b0b }
1414 .syntaxhl .string .content { color: #D20 }
1417 .syntaxhl .string .content { color: #D20 }
1415 .syntaxhl .string .delimiter { color: #710 }
1418 .syntaxhl .string .delimiter { color: #710 }
1416 .syntaxhl .string .modifier { color: #E40 }
1419 .syntaxhl .string .modifier { color: #E40 }
1417 .syntaxhl .symbol { color:#A60 }
1420 .syntaxhl .symbol { color:#A60 }
1418 .syntaxhl .symbol .content { color:#A60 }
1421 .syntaxhl .symbol .content { color:#A60 }
1419 .syntaxhl .symbol .delimiter { color:#740 }
1422 .syntaxhl .symbol .delimiter { color:#740 }
1420 .syntaxhl .tag { color:#070; font-weight:bold }
1423 .syntaxhl .tag { color:#070; font-weight:bold }
1421 .syntaxhl .type { color:#339; font-weight:bold }
1424 .syntaxhl .type { color:#339; font-weight:bold }
1422 .syntaxhl .value { color: #088 }
1425 .syntaxhl .value { color: #088 }
1423 .syntaxhl .variable { color:#037 }
1426 .syntaxhl .variable { color:#037 }
1424
1427
1425 .syntaxhl .insert { background: hsla(120,100%,50%,0.12) }
1428 .syntaxhl .insert { background: hsla(120,100%,50%,0.12) }
1426 .syntaxhl .delete { background: hsla(0,100%,50%,0.12) }
1429 .syntaxhl .delete { background: hsla(0,100%,50%,0.12) }
1427 .syntaxhl .change { color: #bbf; background: #007 }
1430 .syntaxhl .change { color: #bbf; background: #007 }
1428 .syntaxhl .head { color: #f8f; background: #505 }
1431 .syntaxhl .head { color: #f8f; background: #505 }
1429 .syntaxhl .head .filename { color: white; }
1432 .syntaxhl .head .filename { color: white; }
1430
1433
1431 .syntaxhl .delete .eyecatcher { background-color: hsla(0,100%,50%,0.2); border: 1px solid hsla(0,100%,45%,0.5); margin: -1px; border-bottom: none; border-top-left-radius: 5px; border-top-right-radius: 5px; }
1434 .syntaxhl .delete .eyecatcher { background-color: hsla(0,100%,50%,0.2); border: 1px solid hsla(0,100%,45%,0.5); margin: -1px; border-bottom: none; border-top-left-radius: 5px; border-top-right-radius: 5px; }
1432 .syntaxhl .insert .eyecatcher { background-color: hsla(120,100%,50%,0.2); border: 1px solid hsla(120,100%,25%,0.5); margin: -1px; border-top: none; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; }
1435 .syntaxhl .insert .eyecatcher { background-color: hsla(120,100%,50%,0.2); border: 1px solid hsla(120,100%,25%,0.5); margin: -1px; border-top: none; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; }
1433
1436
1434 .syntaxhl .insert .insert { color: #0c0; background:transparent; font-weight:bold }
1437 .syntaxhl .insert .insert { color: #0c0; background:transparent; font-weight:bold }
1435 .syntaxhl .delete .delete { color: #c00; background:transparent; font-weight:bold }
1438 .syntaxhl .delete .delete { color: #c00; background:transparent; font-weight:bold }
1436 .syntaxhl .change .change { color: #88f }
1439 .syntaxhl .change .change { color: #88f }
1437 .syntaxhl .head .head { color: #f4f }
1440 .syntaxhl .head .head { color: #f4f }
1438
1441
1439 /***** Media print specific styles *****/
1442 /***** Media print specific styles *****/
1440 @media print {
1443 @media print {
1441 #top-menu, #header, #main-menu, #sidebar, #footer, .contextual, .other-formats { display:none; }
1444 #top-menu, #header, #main-menu, #sidebar, #footer, .contextual, .other-formats { display:none; }
1442 #main { background: #fff; }
1445 #main { background: #fff; }
1443 #content { width: 99%; margin: 0; padding: 0; border: 0; background: #fff; overflow: visible !important;}
1446 #content { width: 99%; margin: 0; padding: 0; border: 0; background: #fff; overflow: visible !important;}
1444 #wiki_add_attachment { display:none; }
1447 #wiki_add_attachment { display:none; }
1445 .hide-when-print, .pagination ul.pages, .pagination .per-page { display: none !important; }
1448 .hide-when-print, .pagination ul.pages, .pagination .per-page { display: none !important; }
1446 .autoscroll {overflow-x: visible;}
1449 .autoscroll {overflow-x: visible;}
1447 table.list {margin-top:0.5em;}
1450 table.list {margin-top:0.5em;}
1448 table.list th, table.list td {border: 1px solid #aaa;}
1451 table.list th, table.list td {border: 1px solid #aaa;}
1449 }
1452 }
1450
1453
1451 /* Accessibility specific styles */
1454 /* Accessibility specific styles */
1452 .hidden-for-sighted {
1455 .hidden-for-sighted {
1453 position:absolute;
1456 position:absolute;
1454 left:-10000px;
1457 left:-10000px;
1455 top:auto;
1458 top:auto;
1456 width:1px;
1459 width:1px;
1457 height:1px;
1460 height:1px;
1458 overflow:hidden;
1461 overflow:hidden;
1459 }
1462 }
General Comments 0
You need to be logged in to leave comments. Login now