##// END OF EJS Templates
Adds an helper to render other formats download links....
Jean-Philippe Lang -
r2331:f1aa0df32666
parent child
Show More
@@ -0,0 +1,33
1 # Redmine - project management software
2 # Copyright (C) 2006-2009 Jean-Philippe Lang
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
18 module Redmine
19 module Views
20 class OtherFormatsBuilder
21 def initialize(view)
22 @view = view
23 end
24
25 def link_to(name, options={})
26 url = { :format => name.to_s.downcase }.merge(options.delete(:url) || {})
27 caption = options.delete(:caption) || name
28 html_options = { :class => name.to_s.downcase }.merge(options)
29 @view.content_tag('span', @view.link_to(caption, url, html_options))
30 end
31 end
32 end
33 end
@@ -1,211 +1,211
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require 'diff'
19 19
20 20 class WikiController < ApplicationController
21 21 before_filter :find_wiki, :authorize
22 22 before_filter :find_existing_page, :only => [:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy]
23 23
24 24 verify :method => :post, :only => [:destroy, :protect], :redirect_to => { :action => :index }
25 25
26 26 helper :attachments
27 27 include AttachmentsHelper
28 28
29 29 # display a page (in editing mode if it doesn't exist)
30 30 def index
31 31 page_title = params[:page]
32 32 @page = @wiki.find_or_new_page(page_title)
33 33 if @page.new_record?
34 34 if User.current.allowed_to?(:edit_wiki_pages, @project)
35 35 edit
36 36 render :action => 'edit'
37 37 else
38 38 render_404
39 39 end
40 40 return
41 41 end
42 42 if params[:version] && !User.current.allowed_to?(:view_wiki_edits, @project)
43 43 # Redirects user to the current version if he's not allowed to view previous versions
44 44 redirect_to :version => nil
45 45 return
46 46 end
47 47 @content = @page.content_for_version(params[:version])
48 if params[:export] == 'html'
48 if params[:format] == 'html'
49 49 export = render_to_string :action => 'export', :layout => false
50 50 send_data(export, :type => 'text/html', :filename => "#{@page.title}.html")
51 51 return
52 elsif params[:export] == 'txt'
52 elsif params[:format] == 'txt'
53 53 send_data(@content.text, :type => 'text/plain', :filename => "#{@page.title}.txt")
54 54 return
55 55 end
56 56 @editable = editable?
57 57 render :action => 'show'
58 58 end
59 59
60 60 # edit an existing page or a new one
61 61 def edit
62 62 @page = @wiki.find_or_new_page(params[:page])
63 63 return render_403 unless editable?
64 64 @page.content = WikiContent.new(:page => @page) if @page.new_record?
65 65
66 66 @content = @page.content_for_version(params[:version])
67 67 @content.text = initial_page_content(@page) if @content.text.blank?
68 68 # don't keep previous comment
69 69 @content.comments = nil
70 70 if request.get?
71 71 # To prevent StaleObjectError exception when reverting to a previous version
72 72 @content.version = @page.content.version
73 73 else
74 74 if !@page.new_record? && @content.text == params[:content][:text]
75 75 # don't save if text wasn't changed
76 76 redirect_to :action => 'index', :id => @project, :page => @page.title
77 77 return
78 78 end
79 79 #@content.text = params[:content][:text]
80 80 #@content.comments = params[:content][:comments]
81 81 @content.attributes = params[:content]
82 82 @content.author = User.current
83 83 # if page is new @page.save will also save content, but not if page isn't a new record
84 84 if (@page.new_record? ? @page.save : @content.save)
85 85 redirect_to :action => 'index', :id => @project, :page => @page.title
86 86 end
87 87 end
88 88 rescue ActiveRecord::StaleObjectError
89 89 # Optimistic locking exception
90 90 flash[:error] = l(:notice_locking_conflict)
91 91 end
92 92
93 93 # rename a page
94 94 def rename
95 95 return render_403 unless editable?
96 96 @page.redirect_existing_links = true
97 97 # used to display the *original* title if some AR validation errors occur
98 98 @original_title = @page.pretty_title
99 99 if request.post? && @page.update_attributes(params[:wiki_page])
100 100 flash[:notice] = l(:notice_successful_update)
101 101 redirect_to :action => 'index', :id => @project, :page => @page.title
102 102 end
103 103 end
104 104
105 105 def protect
106 106 @page.update_attribute :protected, params[:protected]
107 107 redirect_to :action => 'index', :id => @project, :page => @page.title
108 108 end
109 109
110 110 # show page history
111 111 def history
112 112 @version_count = @page.content.versions.count
113 113 @version_pages = Paginator.new self, @version_count, per_page_option, params['p']
114 114 # don't load text
115 115 @versions = @page.content.versions.find :all,
116 116 :select => "id, author_id, comments, updated_on, version",
117 117 :order => 'version DESC',
118 118 :limit => @version_pages.items_per_page + 1,
119 119 :offset => @version_pages.current.offset
120 120
121 121 render :layout => false if request.xhr?
122 122 end
123 123
124 124 def diff
125 125 @diff = @page.diff(params[:version], params[:version_from])
126 126 render_404 unless @diff
127 127 end
128 128
129 129 def annotate
130 130 @annotate = @page.annotate(params[:version])
131 131 render_404 unless @annotate
132 132 end
133 133
134 134 # remove a wiki page and its history
135 135 def destroy
136 136 return render_403 unless editable?
137 137 @page.destroy
138 138 redirect_to :action => 'special', :id => @project, :page => 'Page_index'
139 139 end
140 140
141 141 # display special pages
142 142 def special
143 143 page_title = params[:page].downcase
144 144 case page_title
145 145 # show pages index, sorted by title
146 146 when 'page_index', 'date_index'
147 147 # eager load information about last updates, without loading text
148 148 @pages = @wiki.pages.find :all, :select => "#{WikiPage.table_name}.*, #{WikiContent.table_name}.updated_on",
149 149 :joins => "LEFT JOIN #{WikiContent.table_name} ON #{WikiContent.table_name}.page_id = #{WikiPage.table_name}.id",
150 150 :order => 'title'
151 151 @pages_by_date = @pages.group_by {|p| p.updated_on.to_date}
152 152 @pages_by_parent_id = @pages.group_by(&:parent_id)
153 153 # export wiki to a single html file
154 154 when 'export'
155 155 @pages = @wiki.pages.find :all, :order => 'title'
156 156 export = render_to_string :action => 'export_multiple', :layout => false
157 157 send_data(export, :type => 'text/html', :filename => "wiki.html")
158 158 return
159 159 else
160 160 # requested special page doesn't exist, redirect to default page
161 161 redirect_to :action => 'index', :id => @project, :page => nil and return
162 162 end
163 163 render :action => "special_#{page_title}"
164 164 end
165 165
166 166 def preview
167 167 page = @wiki.find_page(params[:page])
168 168 # page is nil when previewing a new page
169 169 return render_403 unless page.nil? || editable?(page)
170 170 if page
171 171 @attachements = page.attachments
172 172 @previewed = page.content
173 173 end
174 174 @text = params[:content][:text]
175 175 render :partial => 'common/preview'
176 176 end
177 177
178 178 def add_attachment
179 179 return render_403 unless editable?
180 180 attach_files(@page, params[:attachments])
181 181 redirect_to :action => 'index', :page => @page.title
182 182 end
183 183
184 184 private
185 185
186 186 def find_wiki
187 187 @project = Project.find(params[:id])
188 188 @wiki = @project.wiki
189 189 render_404 unless @wiki
190 190 rescue ActiveRecord::RecordNotFound
191 191 render_404
192 192 end
193 193
194 194 # Finds the requested page and returns a 404 error if it doesn't exist
195 195 def find_existing_page
196 196 @page = @wiki.find_page(params[:page])
197 197 render_404 if @page.nil?
198 198 end
199 199
200 200 # Returns true if the current user is allowed to edit the page, otherwise false
201 201 def editable?(page = @page)
202 202 page.editable_by?(User.current)
203 203 end
204 204
205 205 # Returns the default content of a new wiki page
206 206 def initial_page_content(page)
207 207 helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting)
208 208 extend helper unless self.instance_of?(helper)
209 209 helper.instance_method(:initial_page_content).bind(self).call(page)
210 210 end
211 211 end
@@ -1,672 +1,678
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require 'coderay'
19 19 require 'coderay/helpers/file_type'
20 20 require 'forwardable'
21 21 require 'cgi'
22 22
23 23 module ApplicationHelper
24 24 include Redmine::WikiFormatting::Macros::Definitions
25 25 include GravatarHelper::PublicMethods
26 26
27 27 extend Forwardable
28 28 def_delegators :wiki_helper, :wikitoolbar_for, :heads_for_wiki_formatter
29 29
30 30 def current_role
31 31 @current_role ||= User.current.role_for_project(@project)
32 32 end
33 33
34 34 # Return true if user is authorized for controller/action, otherwise false
35 35 def authorize_for(controller, action)
36 36 User.current.allowed_to?({:controller => controller, :action => action}, @project)
37 37 end
38 38
39 39 # Display a link if user is authorized
40 40 def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference)
41 41 link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller] || params[:controller], options[:action])
42 42 end
43 43
44 44 # Display a link to remote if user is authorized
45 45 def link_to_remote_if_authorized(name, options = {}, html_options = nil)
46 46 url = options[:url] || {}
47 47 link_to_remote(name, options, html_options) if authorize_for(url[:controller] || params[:controller], url[:action])
48 48 end
49 49
50 50 # Display a link to user's account page
51 51 def link_to_user(user, options={})
52 52 (user && !user.anonymous?) ? link_to(user.name(options[:format]), :controller => 'account', :action => 'show', :id => user) : 'Anonymous'
53 53 end
54 54
55 55 def link_to_issue(issue, options={})
56 56 options[:class] ||= ''
57 57 options[:class] << ' issue'
58 58 options[:class] << ' closed' if issue.closed?
59 59 link_to "#{issue.tracker.name} ##{issue.id}", {:controller => "issues", :action => "show", :id => issue}, options
60 60 end
61 61
62 62 # Generates a link to an attachment.
63 63 # Options:
64 64 # * :text - Link text (default to attachment filename)
65 65 # * :download - Force download (default: false)
66 66 def link_to_attachment(attachment, options={})
67 67 text = options.delete(:text) || attachment.filename
68 68 action = options.delete(:download) ? 'download' : 'show'
69 69
70 70 link_to(h(text), {:controller => 'attachments', :action => action, :id => attachment, :filename => attachment.filename }, options)
71 71 end
72 72
73 73 def toggle_link(name, id, options={})
74 74 onclick = "Element.toggle('#{id}'); "
75 75 onclick << (options[:focus] ? "Form.Element.focus('#{options[:focus]}'); " : "this.blur(); ")
76 76 onclick << "return false;"
77 77 link_to(name, "#", :onclick => onclick)
78 78 end
79 79
80 80 def image_to_function(name, function, html_options = {})
81 81 html_options.symbolize_keys!
82 82 tag(:input, html_options.merge({
83 83 :type => "image", :src => image_path(name),
84 84 :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};"
85 85 }))
86 86 end
87 87
88 88 def prompt_to_remote(name, text, param, url, html_options = {})
89 89 html_options[:onclick] = "promptToRemote('#{text}', '#{param}', '#{url_for(url)}'); return false;"
90 90 link_to name, {}, html_options
91 91 end
92 92
93 93 def format_date(date)
94 94 return nil unless date
95 95 # "Setting.date_format.size < 2" is a temporary fix (content of date_format setting changed)
96 96 @date_format ||= (Setting.date_format.blank? || Setting.date_format.size < 2 ? l(:general_fmt_date) : Setting.date_format)
97 97 date.strftime(@date_format)
98 98 end
99 99
100 100 def format_time(time, include_date = true)
101 101 return nil unless time
102 102 time = time.to_time if time.is_a?(String)
103 103 zone = User.current.time_zone
104 104 local = zone ? time.in_time_zone(zone) : (time.utc? ? time.localtime : time)
105 105 @date_format ||= (Setting.date_format.blank? || Setting.date_format.size < 2 ? l(:general_fmt_date) : Setting.date_format)
106 106 @time_format ||= (Setting.time_format.blank? ? l(:general_fmt_time) : Setting.time_format)
107 107 include_date ? local.strftime("#{@date_format} #{@time_format}") : local.strftime(@time_format)
108 108 end
109 109
110 110 def format_activity_title(text)
111 111 h(truncate_single_line(text, 100))
112 112 end
113 113
114 114 def format_activity_day(date)
115 115 date == Date.today ? l(:label_today).titleize : format_date(date)
116 116 end
117 117
118 118 def format_activity_description(text)
119 119 h(truncate(text.to_s, 250).gsub(%r{<(pre|code)>.*$}m, '...'))
120 120 end
121 121
122 122 def distance_of_date_in_words(from_date, to_date = 0)
123 123 from_date = from_date.to_date if from_date.respond_to?(:to_date)
124 124 to_date = to_date.to_date if to_date.respond_to?(:to_date)
125 125 distance_in_days = (to_date - from_date).abs
126 126 lwr(:actionview_datehelper_time_in_words_day, distance_in_days)
127 127 end
128 128
129 129 def due_date_distance_in_words(date)
130 130 if date
131 131 l((date < Date.today ? :label_roadmap_overdue : :label_roadmap_due_in), distance_of_date_in_words(Date.today, date))
132 132 end
133 133 end
134 134
135 135 def render_page_hierarchy(pages, node=nil)
136 136 content = ''
137 137 if pages[node]
138 138 content << "<ul class=\"pages-hierarchy\">\n"
139 139 pages[node].each do |page|
140 140 content << "<li>"
141 141 content << link_to(h(page.pretty_title), {:controller => 'wiki', :action => 'index', :id => page.project, :page => page.title},
142 142 :title => (page.respond_to?(:updated_on) ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil))
143 143 content << "\n" + render_page_hierarchy(pages, page.id) if pages[page.id]
144 144 content << "</li>\n"
145 145 end
146 146 content << "</ul>\n"
147 147 end
148 148 content
149 149 end
150 150
151 151 # Renders flash messages
152 152 def render_flash_messages
153 153 s = ''
154 154 flash.each do |k,v|
155 155 s << content_tag('div', v, :class => "flash #{k}")
156 156 end
157 157 s
158 158 end
159 159
160 160 # Renders the project quick-jump box
161 161 def render_project_jump_box
162 162 # Retrieve them now to avoid a COUNT query
163 163 projects = User.current.projects.all
164 164 if projects.any?
165 165 s = '<select onchange="if (this.value != \'\') { window.location = this.value; }">' +
166 166 "<option selected='selected'>#{ l(:label_jump_to_a_project) }</option>" +
167 167 '<option disabled="disabled">---</option>'
168 168 s << project_tree_options_for_select(projects) do |p|
169 169 { :value => url_for(:controller => 'projects', :action => 'show', :id => p, :jump => current_menu_item) }
170 170 end
171 171 s << '</select>'
172 172 s
173 173 end
174 174 end
175 175
176 176 def project_tree_options_for_select(projects, options = {})
177 177 s = ''
178 178 project_tree(projects) do |project, level|
179 179 name_prefix = (level > 0 ? ('&nbsp;' * 2 * level + '&#187; ') : '')
180 180 tag_options = {:value => project.id, :selected => ((project == options[:selected]) ? 'selected' : nil)}
181 181 tag_options.merge!(yield(project)) if block_given?
182 182 s << content_tag('option', name_prefix + h(project), tag_options)
183 183 end
184 184 s
185 185 end
186 186
187 187 # Yields the given block for each project with its level in the tree
188 188 def project_tree(projects, &block)
189 189 ancestors = []
190 190 projects.sort_by(&:lft).each do |project|
191 191 while (ancestors.any? && !project.is_descendant_of?(ancestors.last))
192 192 ancestors.pop
193 193 end
194 194 yield project, ancestors.size
195 195 ancestors << project
196 196 end
197 197 end
198 198
199 199 # Truncates and returns the string as a single line
200 200 def truncate_single_line(string, *args)
201 201 truncate(string, *args).gsub(%r{[\r\n]+}m, ' ')
202 202 end
203 203
204 204 def html_hours(text)
205 205 text.gsub(%r{(\d+)\.(\d+)}, '<span class="hours hours-int">\1</span><span class="hours hours-dec">.\2</span>')
206 206 end
207 207
208 208 def authoring(created, author, options={})
209 209 time_tag = @project.nil? ? content_tag('acronym', distance_of_time_in_words(Time.now, created), :title => format_time(created)) :
210 210 link_to(distance_of_time_in_words(Time.now, created),
211 211 {:controller => 'projects', :action => 'activity', :id => @project, :from => created.to_date},
212 212 :title => format_time(created))
213 213 author_tag = (author.is_a?(User) && !author.anonymous?) ? link_to(h(author), :controller => 'account', :action => 'show', :id => author) : h(author || 'Anonymous')
214 214 l(options[:label] || :label_added_time_by, author_tag, time_tag)
215 215 end
216 216
217 217 def l_or_humanize(s, options={})
218 218 k = "#{options[:prefix]}#{s}".to_sym
219 219 l_has_string?(k) ? l(k) : s.to_s.humanize
220 220 end
221 221
222 222 def day_name(day)
223 223 l(:general_day_names).split(',')[day-1]
224 224 end
225 225
226 226 def month_name(month)
227 227 l(:actionview_datehelper_select_month_names).split(',')[month-1]
228 228 end
229 229
230 230 def syntax_highlight(name, content)
231 231 type = CodeRay::FileType[name]
232 232 type ? CodeRay.scan(content, type).html : h(content)
233 233 end
234 234
235 235 def to_path_param(path)
236 236 path.to_s.split(%r{[/\\]}).select {|p| !p.blank?}
237 237 end
238 238
239 239 def pagination_links_full(paginator, count=nil, options={})
240 240 page_param = options.delete(:page_param) || :page
241 241 url_param = params.dup
242 242 # don't reuse params if filters are present
243 243 url_param.clear if url_param.has_key?(:set_filter)
244 244
245 245 html = ''
246 246 if paginator.current.previous
247 247 html << link_to_remote_content_update('&#171; ' + l(:label_previous), url_param.merge(page_param => paginator.current.previous)) + ' '
248 248 end
249 249
250 250 html << (pagination_links_each(paginator, options) do |n|
251 251 link_to_remote_content_update(n.to_s, url_param.merge(page_param => n))
252 252 end || '')
253 253
254 254 if paginator.current.next
255 255 html << ' ' + link_to_remote_content_update((l(:label_next) + ' &#187;'), url_param.merge(page_param => paginator.current.next))
256 256 end
257 257
258 258 unless count.nil?
259 259 html << [
260 260 " (#{paginator.current.first_item}-#{paginator.current.last_item}/#{count})",
261 261 per_page_links(paginator.items_per_page)
262 262 ].compact.join(' | ')
263 263 end
264 264
265 265 html
266 266 end
267 267
268 268 def per_page_links(selected=nil)
269 269 url_param = params.dup
270 270 url_param.clear if url_param.has_key?(:set_filter)
271 271
272 272 links = Setting.per_page_options_array.collect do |n|
273 273 n == selected ? n : link_to_remote(n, {:update => "content",
274 274 :url => params.dup.merge(:per_page => n),
275 275 :method => :get},
276 276 {:href => url_for(url_param.merge(:per_page => n))})
277 277 end
278 278 links.size > 1 ? l(:label_display_per_page, links.join(', ')) : nil
279 279 end
280 280
281 281 def breadcrumb(*args)
282 282 elements = args.flatten
283 283 elements.any? ? content_tag('p', args.join(' &#187; ') + ' &#187; ', :class => 'breadcrumb') : nil
284 284 end
285
286 def other_formats_links(&block)
287 concat('<p class="other-formats">' + l(:label_export_to), block.binding)
288 yield Redmine::Views::OtherFormatsBuilder.new(self)
289 concat('</p>', block.binding)
290 end
285 291
286 292 def html_title(*args)
287 293 if args.empty?
288 294 title = []
289 295 title << @project.name if @project
290 296 title += @html_title if @html_title
291 297 title << Setting.app_title
292 298 title.compact.join(' - ')
293 299 else
294 300 @html_title ||= []
295 301 @html_title += args
296 302 end
297 303 end
298 304
299 305 def accesskey(s)
300 306 Redmine::AccessKeys.key_for s
301 307 end
302 308
303 309 # Formats text according to system settings.
304 310 # 2 ways to call this method:
305 311 # * with a String: textilizable(text, options)
306 312 # * with an object and one of its attribute: textilizable(issue, :description, options)
307 313 def textilizable(*args)
308 314 options = args.last.is_a?(Hash) ? args.pop : {}
309 315 case args.size
310 316 when 1
311 317 obj = options[:object]
312 318 text = args.shift
313 319 when 2
314 320 obj = args.shift
315 321 text = obj.send(args.shift).to_s
316 322 else
317 323 raise ArgumentError, 'invalid arguments to textilizable'
318 324 end
319 325 return '' if text.blank?
320 326
321 327 only_path = options.delete(:only_path) == false ? false : true
322 328
323 329 # when using an image link, try to use an attachment, if possible
324 330 attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil)
325 331
326 332 if attachments
327 333 attachments = attachments.sort_by(&:created_on).reverse
328 334 text = text.gsub(/!((\<|\=|\>)?(\([^\)]+\))?(\[[^\]]+\])?(\{[^\}]+\})?)(\S+\.(bmp|gif|jpg|jpeg|png))!/i) do |m|
329 335 style = $1
330 336 filename = $6
331 337 rf = Regexp.new(Regexp.escape(filename), Regexp::IGNORECASE)
332 338 # search for the picture in attachments
333 339 if found = attachments.detect { |att| att.filename =~ rf }
334 340 image_url = url_for :only_path => only_path, :controller => 'attachments', :action => 'download', :id => found
335 341 desc = found.description.to_s.gsub(/^([^\(\)]*).*$/, "\\1")
336 342 alt = desc.blank? ? nil : "(#{desc})"
337 343 "!#{style}#{image_url}#{alt}!"
338 344 else
339 345 "!#{style}#{filename}!"
340 346 end
341 347 end
342 348 end
343 349
344 350 text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text) { |macro, args| exec_macro(macro, obj, args) }
345 351
346 352 # different methods for formatting wiki links
347 353 case options[:wiki_links]
348 354 when :local
349 355 # used for local links to html files
350 356 format_wiki_link = Proc.new {|project, title, anchor| "#{title}.html" }
351 357 when :anchor
352 358 # used for single-file wiki export
353 359 format_wiki_link = Proc.new {|project, title, anchor| "##{title}" }
354 360 else
355 361 format_wiki_link = Proc.new {|project, title, anchor| url_for(:only_path => only_path, :controller => 'wiki', :action => 'index', :id => project, :page => title, :anchor => anchor) }
356 362 end
357 363
358 364 project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil)
359 365
360 366 # Wiki links
361 367 #
362 368 # Examples:
363 369 # [[mypage]]
364 370 # [[mypage|mytext]]
365 371 # wiki links can refer other project wikis, using project name or identifier:
366 372 # [[project:]] -> wiki starting page
367 373 # [[project:|mytext]]
368 374 # [[project:mypage]]
369 375 # [[project:mypage|mytext]]
370 376 text = text.gsub(/(!)?(\[\[([^\]\n\|]+)(\|([^\]\n\|]+))?\]\])/) do |m|
371 377 link_project = project
372 378 esc, all, page, title = $1, $2, $3, $5
373 379 if esc.nil?
374 380 if page =~ /^([^\:]+)\:(.*)$/
375 381 link_project = Project.find_by_name($1) || Project.find_by_identifier($1)
376 382 page = $2
377 383 title ||= $1 if page.blank?
378 384 end
379 385
380 386 if link_project && link_project.wiki
381 387 # extract anchor
382 388 anchor = nil
383 389 if page =~ /^(.+?)\#(.+)$/
384 390 page, anchor = $1, $2
385 391 end
386 392 # check if page exists
387 393 wiki_page = link_project.wiki.find_page(page)
388 394 link_to((title || page), format_wiki_link.call(link_project, Wiki.titleize(page), anchor),
389 395 :class => ('wiki-page' + (wiki_page ? '' : ' new')))
390 396 else
391 397 # project or wiki doesn't exist
392 398 title || page
393 399 end
394 400 else
395 401 all
396 402 end
397 403 end
398 404
399 405 # Redmine links
400 406 #
401 407 # Examples:
402 408 # Issues:
403 409 # #52 -> Link to issue #52
404 410 # Changesets:
405 411 # r52 -> Link to revision 52
406 412 # commit:a85130f -> Link to scmid starting with a85130f
407 413 # Documents:
408 414 # document#17 -> Link to document with id 17
409 415 # document:Greetings -> Link to the document with title "Greetings"
410 416 # document:"Some document" -> Link to the document with title "Some document"
411 417 # Versions:
412 418 # version#3 -> Link to version with id 3
413 419 # version:1.0.0 -> Link to version named "1.0.0"
414 420 # version:"1.0 beta 2" -> Link to version named "1.0 beta 2"
415 421 # Attachments:
416 422 # attachment:file.zip -> Link to the attachment of the current object named file.zip
417 423 # Source files:
418 424 # source:some/file -> Link to the file located at /some/file in the project's repository
419 425 # source:some/file@52 -> Link to the file's revision 52
420 426 # source:some/file#L120 -> Link to line 120 of the file
421 427 # source:some/file@52#L120 -> Link to line 120 of the file's revision 52
422 428 # export:some/file -> Force the download of the file
423 429 # Forum messages:
424 430 # message#1218 -> Link to message with id 1218
425 431 text = text.gsub(%r{([\s\(,\-\>]|^)(!)?(attachment|document|version|commit|source|export|message)?((#|r)(\d+)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]]\W)|\s|<|$)}) do |m|
426 432 leading, esc, prefix, sep, oid = $1, $2, $3, $5 || $7, $6 || $8
427 433 link = nil
428 434 if esc.nil?
429 435 if prefix.nil? && sep == 'r'
430 436 if project && (changeset = project.changesets.find_by_revision(oid))
431 437 link = link_to("r#{oid}", {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => oid},
432 438 :class => 'changeset',
433 439 :title => truncate_single_line(changeset.comments, 100))
434 440 end
435 441 elsif sep == '#'
436 442 oid = oid.to_i
437 443 case prefix
438 444 when nil
439 445 if issue = Issue.find_by_id(oid, :include => [:project, :status], :conditions => Project.visible_by(User.current))
440 446 link = link_to("##{oid}", {:only_path => only_path, :controller => 'issues', :action => 'show', :id => oid},
441 447 :class => (issue.closed? ? 'issue closed' : 'issue'),
442 448 :title => "#{truncate(issue.subject, 100)} (#{issue.status.name})")
443 449 link = content_tag('del', link) if issue.closed?
444 450 end
445 451 when 'document'
446 452 if document = Document.find_by_id(oid, :include => [:project], :conditions => Project.visible_by(User.current))
447 453 link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
448 454 :class => 'document'
449 455 end
450 456 when 'version'
451 457 if version = Version.find_by_id(oid, :include => [:project], :conditions => Project.visible_by(User.current))
452 458 link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
453 459 :class => 'version'
454 460 end
455 461 when 'message'
456 462 if message = Message.find_by_id(oid, :include => [:parent, {:board => :project}], :conditions => Project.visible_by(User.current))
457 463 link = link_to h(truncate(message.subject, 60)), {:only_path => only_path,
458 464 :controller => 'messages',
459 465 :action => 'show',
460 466 :board_id => message.board,
461 467 :id => message.root,
462 468 :anchor => (message.parent ? "message-#{message.id}" : nil)},
463 469 :class => 'message'
464 470 end
465 471 end
466 472 elsif sep == ':'
467 473 # removes the double quotes if any
468 474 name = oid.gsub(%r{^"(.*)"$}, "\\1")
469 475 case prefix
470 476 when 'document'
471 477 if project && document = project.documents.find_by_title(name)
472 478 link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
473 479 :class => 'document'
474 480 end
475 481 when 'version'
476 482 if project && version = project.versions.find_by_name(name)
477 483 link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
478 484 :class => 'version'
479 485 end
480 486 when 'commit'
481 487 if project && (changeset = project.changesets.find(:first, :conditions => ["scmid LIKE ?", "#{name}%"]))
482 488 link = link_to h("#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.revision},
483 489 :class => 'changeset',
484 490 :title => truncate_single_line(changeset.comments, 100)
485 491 end
486 492 when 'source', 'export'
487 493 if project && project.repository
488 494 name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$}
489 495 path, rev, anchor = $1, $3, $5
490 496 link = link_to h("#{prefix}:#{name}"), {:controller => 'repositories', :action => 'entry', :id => project,
491 497 :path => to_path_param(path),
492 498 :rev => rev,
493 499 :anchor => anchor,
494 500 :format => (prefix == 'export' ? 'raw' : nil)},
495 501 :class => (prefix == 'export' ? 'source download' : 'source')
496 502 end
497 503 when 'attachment'
498 504 if attachments && attachment = attachments.detect {|a| a.filename == name }
499 505 link = link_to h(attachment.filename), {:only_path => only_path, :controller => 'attachments', :action => 'download', :id => attachment},
500 506 :class => 'attachment'
501 507 end
502 508 end
503 509 end
504 510 end
505 511 leading + (link || "#{prefix}#{sep}#{oid}")
506 512 end
507 513
508 514 text
509 515 end
510 516
511 517 # Same as Rails' simple_format helper without using paragraphs
512 518 def simple_format_without_paragraph(text)
513 519 text.to_s.
514 520 gsub(/\r\n?/, "\n"). # \r\n and \r -> \n
515 521 gsub(/\n\n+/, "<br /><br />"). # 2+ newline -> 2 br
516 522 gsub(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br
517 523 end
518 524
519 525 def error_messages_for(object_name, options = {})
520 526 options = options.symbolize_keys
521 527 object = instance_variable_get("@#{object_name}")
522 528 if object && !object.errors.empty?
523 529 # build full_messages here with controller current language
524 530 full_messages = []
525 531 object.errors.each do |attr, msg|
526 532 next if msg.nil?
527 533 msg = msg.first if msg.is_a? Array
528 534 if attr == "base"
529 535 full_messages << l(msg)
530 536 else
531 537 full_messages << "&#171; " + (l_has_string?("field_" + attr) ? l("field_" + attr) : object.class.human_attribute_name(attr)) + " &#187; " + l(msg) unless attr == "custom_values"
532 538 end
533 539 end
534 540 # retrieve custom values error messages
535 541 if object.errors[:custom_values]
536 542 object.custom_values.each do |v|
537 543 v.errors.each do |attr, msg|
538 544 next if msg.nil?
539 545 msg = msg.first if msg.is_a? Array
540 546 full_messages << "&#171; " + v.custom_field.name + " &#187; " + l(msg)
541 547 end
542 548 end
543 549 end
544 550 content_tag("div",
545 551 content_tag(
546 552 options[:header_tag] || "span", lwr(:gui_validation_error, full_messages.length) + ":"
547 553 ) +
548 554 content_tag("ul", full_messages.collect { |msg| content_tag("li", msg) }),
549 555 "id" => options[:id] || "errorExplanation", "class" => options[:class] || "errorExplanation"
550 556 )
551 557 else
552 558 ""
553 559 end
554 560 end
555 561
556 562 def lang_options_for_select(blank=true)
557 563 (blank ? [["(auto)", ""]] : []) +
558 564 GLoc.valid_languages.collect{|lang| [ ll(lang.to_s, :general_lang_name), lang.to_s]}.sort{|x,y| x.last <=> y.last }
559 565 end
560 566
561 567 def label_tag_for(name, option_tags = nil, options = {})
562 568 label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "")
563 569 content_tag("label", label_text)
564 570 end
565 571
566 572 def labelled_tabular_form_for(name, object, options, &proc)
567 573 options[:html] ||= {}
568 574 options[:html][:class] = 'tabular' unless options[:html].has_key?(:class)
569 575 form_for(name, object, options.merge({ :builder => TabularFormBuilder, :lang => current_language}), &proc)
570 576 end
571 577
572 578 def back_url_hidden_field_tag
573 579 back_url = params[:back_url] || request.env['HTTP_REFERER']
574 580 back_url = CGI.unescape(back_url.to_s)
575 581 hidden_field_tag('back_url', CGI.escape(back_url)) unless back_url.blank?
576 582 end
577 583
578 584 def check_all_links(form_name)
579 585 link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") +
580 586 " | " +
581 587 link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)")
582 588 end
583 589
584 590 def progress_bar(pcts, options={})
585 591 pcts = [pcts, pcts] unless pcts.is_a?(Array)
586 592 pcts[1] = pcts[1] - pcts[0]
587 593 pcts << (100 - pcts[1] - pcts[0])
588 594 width = options[:width] || '100px;'
589 595 legend = options[:legend] || ''
590 596 content_tag('table',
591 597 content_tag('tr',
592 598 (pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0].floor}%;", :class => 'closed') : '') +
593 599 (pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1].floor}%;", :class => 'done') : '') +
594 600 (pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2].floor}%;", :class => 'todo') : '')
595 601 ), :class => 'progress', :style => "width: #{width};") +
596 602 content_tag('p', legend, :class => 'pourcent')
597 603 end
598 604
599 605 def context_menu_link(name, url, options={})
600 606 options[:class] ||= ''
601 607 if options.delete(:selected)
602 608 options[:class] << ' icon-checked disabled'
603 609 options[:disabled] = true
604 610 end
605 611 if options.delete(:disabled)
606 612 options.delete(:method)
607 613 options.delete(:confirm)
608 614 options.delete(:onclick)
609 615 options[:class] << ' disabled'
610 616 url = '#'
611 617 end
612 618 link_to name, url, options
613 619 end
614 620
615 621 def calendar_for(field_id)
616 622 include_calendar_headers_tags
617 623 image_tag("calendar.png", {:id => "#{field_id}_trigger",:class => "calendar-trigger"}) +
618 624 javascript_tag("Calendar.setup({inputField : '#{field_id}', ifFormat : '%Y-%m-%d', button : '#{field_id}_trigger' });")
619 625 end
620 626
621 627 def include_calendar_headers_tags
622 628 unless @calendar_headers_tags_included
623 629 @calendar_headers_tags_included = true
624 630 content_for :header_tags do
625 631 javascript_include_tag('calendar/calendar') +
626 632 javascript_include_tag("calendar/lang/calendar-#{current_language}.js") +
627 633 javascript_include_tag('calendar/calendar-setup') +
628 634 stylesheet_link_tag('calendar')
629 635 end
630 636 end
631 637 end
632 638
633 639 def content_for(name, content = nil, &block)
634 640 @has_content ||= {}
635 641 @has_content[name] = true
636 642 super(name, content, &block)
637 643 end
638 644
639 645 def has_content?(name)
640 646 (@has_content && @has_content[name]) || false
641 647 end
642 648
643 649 # Returns the avatar image tag for the given +user+ if avatars are enabled
644 650 # +user+ can be a User or a string that will be scanned for an email address (eg. 'joe <joe@foo.bar>')
645 651 def avatar(user, options = { })
646 652 if Setting.gravatar_enabled?
647 653 email = nil
648 654 if user.respond_to?(:mail)
649 655 email = user.mail
650 656 elsif user.to_s =~ %r{<(.+?)>}
651 657 email = $1
652 658 end
653 659 return gravatar(email.to_s.downcase, options) unless email.blank? rescue nil
654 660 end
655 661 end
656 662
657 663 private
658 664
659 665 def wiki_helper
660 666 helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting)
661 667 extend helper
662 668 return self
663 669 end
664 670
665 671 def link_to_remote_content_update(text, url_params)
666 672 link_to_remote(text,
667 673 {:url => url_params, :method => :get, :update => 'content', :complete => 'window.scrollTo(0,0)'},
668 674 {:href => url_for(:params => url_params)}
669 675 )
670 676 end
671 677
672 678 end
@@ -1,69 +1,68
1 1 <div class="contextual">
2 2 <%= link_to(l(:button_edit), {:controller => 'users', :action => 'edit', :id => @user}, :class => 'icon icon-edit') if User.current.admin? %>
3 3 </div>
4 4
5 5 <h2><%= avatar @user %> <%=h @user.name %></h2>
6 6
7 7 <div class="splitcontentleft">
8 8 <ul>
9 9 <% unless @user.pref.hide_mail %>
10 10 <li><%=l(:field_mail)%>: <%= mail_to(h(@user.mail), nil, :encode => 'javascript') %></li>
11 11 <% end %>
12 12 <% for custom_value in @custom_values %>
13 13 <% if !custom_value.value.empty? %>
14 14 <li><%= custom_value.custom_field.name%>: <%=h show_value(custom_value) %></li>
15 15 <% end %>
16 16 <% end %>
17 17 <li><%=l(:label_registered_on)%>: <%= format_date(@user.created_on) %></li>
18 18 <% unless @user.last_login_on.nil? %>
19 19 <li><%=l(:field_last_login_on)%>: <%= format_date(@user.last_login_on) %></li>
20 20 <% end %>
21 21 </ul>
22 22
23 23 <% unless @memberships.empty? %>
24 24 <h3><%=l(:label_project_plural)%></h3>
25 25 <ul>
26 26 <% for membership in @memberships %>
27 27 <li><%= link_to(h(membership.project.name), :controller => 'projects', :action => 'show', :id => membership.project) %>
28 28 (<%=h membership.role.name %>, <%= format_date(membership.created_on) %>)</li>
29 29 <% end %>
30 30 </ul>
31 31 <% end %>
32 32 </div>
33 33
34 34 <div class="splitcontentright">
35 35
36 36 <% unless @events_by_day.empty? %>
37 37 <h3><%= link_to l(:label_activity), :controller => 'projects', :action => 'activity', :user_id => @user, :from => @events_by_day.keys.first %></h3>
38 38
39 39 <p>
40 40 <%=l(:label_reported_issues)%>: <%= Issue.count(:conditions => ["author_id=?", @user.id]) %>
41 41 </p>
42 42
43 43 <div id="activity">
44 44 <% @events_by_day.keys.sort.reverse.each do |day| %>
45 45 <h4><%= format_activity_day(day) %></h4>
46 46 <dl>
47 47 <% @events_by_day[day].sort {|x,y| y.event_datetime <=> x.event_datetime }.each do |e| -%>
48 48 <dt class="<%= e.event_type %>">
49 49 <span class="time"><%= format_time(e.event_datetime, false) %></span>
50 50 <%= content_tag('span', h(e.project), :class => 'project') %>
51 51 <%= link_to format_activity_title(e.event_title), e.event_url %></dt>
52 52 <dd><span class="description"><%= format_activity_description(e.event_description) %></span></dd>
53 53 <% end -%>
54 54 </dl>
55 55 <% end -%>
56 56 </div>
57 57
58 <p class="other-formats">
59 <%= l(:label_export_to) %>
60 <%= link_to 'Atom', {:controller => 'projects', :action => 'activity', :id => nil, :user_id => @user, :format => :atom, :key => User.current.rss_key}, :class => 'feed' %>
61 </p>
58 <% other_formats_links do |f| %>
59 <%= f.link_to 'Atom', :url => {:controller => 'projects', :action => 'activity', :id => nil, :user_id => @user, :key => User.current.rss_key} %>
60 <% end %>
62 61
63 62 <% content_for :header_tags do %>
64 63 <%= auto_discovery_link_tag(:atom, :controller => 'projects', :action => 'activity', :user_id => @user, :format => :atom, :key => User.current.rss_key) %>
65 64 <% end %>
66 65 <% end %>
67 66 </div>
68 67
69 68 <% html_title @user.name %>
@@ -1,42 +1,40
1 1 <h2><%= l(:label_board_plural) %></h2>
2 2
3 3 <table class="list boards">
4 4 <thead><tr>
5 5 <th><%= l(:label_board) %></th>
6 6 <th><%= l(:label_topic_plural) %></th>
7 7 <th><%= l(:label_message_plural) %></th>
8 8 <th><%= l(:label_message_last) %></th>
9 9 </tr></thead>
10 10 <tbody>
11 11 <% for board in @boards %>
12 12 <tr class="<%= cycle 'odd', 'even' %>">
13 13 <td>
14 14 <%= link_to h(board.name), {:action => 'show', :id => board}, :class => "icon22 icon22-comment" %><br />
15 15 <%=h board.description %>
16 16 </td>
17 17 <td align="center"><%= board.topics_count %></td>
18 18 <td align="center"><%= board.messages_count %></td>
19 19 <td>
20 20 <small>
21 21 <% if board.last_message %>
22 22 <%= authoring board.last_message.created_on, board.last_message.author %><br />
23 23 <%= link_to_message board.last_message %>
24 24 <% end %>
25 25 </small>
26 26 </td>
27 27 </tr>
28 28 <% end %>
29 29 </tbody>
30 30 </table>
31 31
32 <p class="other-formats">
33 <%= l(:label_export_to) %>
34 <span><%= link_to 'Atom', {:controller => 'projects', :action => 'activity', :id => @project, :format => 'atom', :show_messages => 1, :key => User.current.rss_key},
35 :class => 'feed' %></span>
36 </p>
32 <% other_formats_links do |f| %>
33 <%= f.link_to 'Atom', :url => {:controller => 'projects', :action => 'activity', :id => @project, :show_messages => 1, :key => User.current.rss_key} %>
34 <% end %>
37 35
38 36 <% content_for :header_tags do %>
39 37 <%= auto_discovery_link_tag(:atom, {:controller => 'projects', :action => 'activity', :id => @project, :format => 'atom', :show_messages => 1, :key => User.current.rss_key}) %>
40 38 <% end %>
41 39
42 40 <% html_title l(:label_board_plural) %>
@@ -1,257 +1,254
1 1 <% form_tag(params.merge(:month => nil, :year => nil, :months => nil), :id => 'query_form') do %>
2 2 <% if @query.new_record? %>
3 3 <h2><%=l(:label_gantt)%></h2>
4 4 <fieldset id="filters"><legend><%= l(:label_filter_plural) %></legend>
5 5 <%= render :partial => 'queries/filters', :locals => {:query => @query} %>
6 6 </fieldset>
7 7 <% else %>
8 8 <h2><%=h @query.name %></h2>
9 9 <% html_title @query.name %>
10 10 <% end %>
11 11
12 12 <fieldset id="date-range"><legend><%= l(:label_date_range) %></legend>
13 13 <%= text_field_tag 'months', @gantt.months, :size => 2 %>
14 14 <%= l(:label_months_from) %>
15 15 <%= select_month(@gantt.month_from, :prefix => "month", :discard_type => true) %>
16 16 <%= select_year(@gantt.year_from, :prefix => "year", :discard_type => true) %>
17 17 <%= hidden_field_tag 'zoom', @gantt.zoom %>
18 18 </fieldset>
19 19
20 20 <p style="float:right; margin:0px;">
21 21 <%= if @gantt.zoom < 4
22 22 link_to_remote image_tag('zoom_in.png'), {:url => @gantt.params.merge(:zoom => (@gantt.zoom+1)), :update => 'content'}, {:href => url_for(@gantt.params.merge(:zoom => (@gantt.zoom+1)))}
23 23 else
24 24 image_tag 'zoom_in_g.png'
25 25 end %>
26 26 <%= if @gantt.zoom > 1
27 27 link_to_remote image_tag('zoom_out.png'), {:url => @gantt.params.merge(:zoom => (@gantt.zoom-1)), :update => 'content'}, {:href => url_for(@gantt.params.merge(:zoom => (@gantt.zoom-1)))}
28 28 else
29 29 image_tag 'zoom_out_g.png'
30 30 end %>
31 31 </p>
32 32
33 33 <p class="buttons">
34 34 <%= link_to_remote l(:button_apply),
35 35 { :url => { :set_filter => (@query.new_record? ? 1 : nil) },
36 36 :update => "content",
37 37 :with => "Form.serialize('query_form')"
38 38 }, :class => 'icon icon-checked' %>
39 39
40 40 <%= link_to_remote l(:button_clear),
41 41 { :url => { :set_filter => (@query.new_record? ? 1 : nil) },
42 42 :update => "content",
43 43 }, :class => 'icon icon-reload' if @query.new_record? %>
44 44 </p>
45 45 <% end %>
46 46
47 47 <%= error_messages_for 'query' %>
48 48 <% if @query.valid? %>
49 49 <% zoom = 1
50 50 @gantt.zoom.times { zoom = zoom * 2 }
51 51
52 52 subject_width = 330
53 53 header_heigth = 18
54 54
55 55 headers_height = header_heigth
56 56 show_weeks = false
57 57 show_days = false
58 58
59 59 if @gantt.zoom >1
60 60 show_weeks = true
61 61 headers_height = 2*header_heigth
62 62 if @gantt.zoom > 2
63 63 show_days = true
64 64 headers_height = 3*header_heigth
65 65 end
66 66 end
67 67
68 68 g_width = (@gantt.date_to - @gantt.date_from + 1)*zoom
69 69 g_height = [(20 * @gantt.events.length + 6)+150, 206].max
70 70 t_height = g_height + headers_height
71 71 %>
72 72
73 73 <table width="100%" style="border:0; border-collapse: collapse;">
74 74 <tr>
75 75 <td style="width:<%= subject_width %>px; padding:0px;">
76 76
77 77 <div style="position:relative;height:<%= t_height + 24 %>px;width:<%= subject_width + 1 %>px;">
78 78 <div style="right:-2px;width:<%= subject_width %>px;height:<%= headers_height %>px;background: #eee;" class="gantt_hdr"></div>
79 79 <div style="right:-2px;width:<%= subject_width %>px;height:<%= t_height %>px;border-left: 1px solid #c0c0c0;overflow:hidden;" class="gantt_hdr"></div>
80 80 <%
81 81 #
82 82 # Tasks subjects
83 83 #
84 84 top = headers_height + 8
85 85 @gantt.events.each do |i| %>
86 86 <div style="position: absolute;line-height:1.2em;height:16px;top:<%= top %>px;left:4px;overflow:hidden;"><small>
87 87 <% if i.is_a? Issue %>
88 88 <%= h("#{i.project} -") unless @project && @project == i.project %>
89 89 <%= link_to_issue i %>: <%=h i.subject %>
90 90 <% else %>
91 91 <span class="icon icon-package">
92 92 <%= h("#{i.project} -") unless @project && @project == i.project %>
93 93 <%= link_to_version i %>
94 94 </span>
95 95 <% end %>
96 96 </small></div>
97 97 <% top = top + 20
98 98 end %>
99 99 </div>
100 100 </td>
101 101 <td>
102 102
103 103 <div style="position:relative;height:<%= t_height + 24 %>px;overflow:auto;">
104 104 <div style="width:<%= g_width-1 %>px;height:<%= headers_height %>px;background: #eee;" class="gantt_hdr">&nbsp;</div>
105 105 <%
106 106 #
107 107 # Months headers
108 108 #
109 109 month_f = @gantt.date_from
110 110 left = 0
111 111 height = (show_weeks ? header_heigth : header_heigth + g_height)
112 112 @gantt.months.times do
113 113 width = ((month_f >> 1) - month_f) * zoom - 1
114 114 %>
115 115 <div style="left:<%= left %>px;width:<%= width %>px;height:<%= height %>px;" class="gantt_hdr">
116 116 <%= link_to "#{month_f.year}-#{month_f.month}", @gantt.params.merge(:year => month_f.year, :month => month_f.month), :title => "#{month_name(month_f.month)} #{month_f.year}"%>
117 117 </div>
118 118 <%
119 119 left = left + width + 1
120 120 month_f = month_f >> 1
121 121 end %>
122 122
123 123 <%
124 124 #
125 125 # Weeks headers
126 126 #
127 127 if show_weeks
128 128 left = 0
129 129 height = (show_days ? header_heigth-1 : header_heigth-1 + g_height)
130 130 if @gantt.date_from.cwday == 1
131 131 # @date_from is monday
132 132 week_f = @gantt.date_from
133 133 else
134 134 # find next monday after @date_from
135 135 week_f = @gantt.date_from + (7 - @gantt.date_from.cwday + 1)
136 136 width = (7 - @gantt.date_from.cwday + 1) * zoom-1
137 137 %>
138 138 <div style="left:<%= left %>px;top:19px;width:<%= width %>px;height:<%= height %>px;" class="gantt_hdr">&nbsp;</div>
139 139 <%
140 140 left = left + width+1
141 141 end %>
142 142 <%
143 143 while week_f <= @gantt.date_to
144 144 width = (week_f + 6 <= @gantt.date_to) ? 7 * zoom -1 : (@gantt.date_to - week_f + 1) * zoom-1
145 145 %>
146 146 <div style="left:<%= left %>px;top:19px;width:<%= width %>px;height:<%= height %>px;" class="gantt_hdr">
147 147 <small><%= week_f.cweek if width >= 16 %></small>
148 148 </div>
149 149 <%
150 150 left = left + width+1
151 151 week_f = week_f+7
152 152 end
153 153 end %>
154 154
155 155 <%
156 156 #
157 157 # Days headers
158 158 #
159 159 if show_days
160 160 left = 0
161 161 height = g_height + header_heigth - 1
162 162 wday = @gantt.date_from.cwday
163 163 (@gantt.date_to - @gantt.date_from + 1).to_i.times do
164 164 width = zoom - 1
165 165 %>
166 166 <div style="left:<%= left %>px;top:37px;width:<%= width %>px;height:<%= height %>px;font-size:0.7em;<%= "background:#f1f1f1;" if wday > 5 %>" class="gantt_hdr">
167 167 <%= day_name(wday).first %>
168 168 </div>
169 169 <%
170 170 left = left + width+1
171 171 wday = wday + 1
172 172 wday = 1 if wday > 7
173 173 end
174 174 end %>
175 175
176 176 <%
177 177 #
178 178 # Tasks
179 179 #
180 180 top = headers_height + 10
181 181 @gantt.events.each do |i|
182 182 if i.is_a? Issue
183 183 i_start_date = (i.start_date >= @gantt.date_from ? i.start_date : @gantt.date_from )
184 184 i_end_date = (i.due_before <= @gantt.date_to ? i.due_before : @gantt.date_to )
185 185
186 186 i_done_date = i.start_date + ((i.due_before - i.start_date+1)*i.done_ratio/100).floor
187 187 i_done_date = (i_done_date <= @gantt.date_from ? @gantt.date_from : i_done_date )
188 188 i_done_date = (i_done_date >= @gantt.date_to ? @gantt.date_to : i_done_date )
189 189
190 190 i_late_date = [i_end_date, Date.today].min if i_start_date < Date.today
191 191
192 192 i_left = ((i_start_date - @gantt.date_from)*zoom).floor
193 193 i_width = ((i_end_date - i_start_date + 1)*zoom).floor - 2 # total width of the issue (- 2 for left and right borders)
194 194 d_width = ((i_done_date - i_start_date)*zoom).floor - 2 # done width
195 195 l_width = i_late_date ? ((i_late_date - i_start_date+1)*zoom).floor - 2 : 0 # delay width
196 196 %>
197 197 <div style="top:<%= top %>px;left:<%= i_left %>px;width:<%= i_width %>px;" class="task task_todo">&nbsp;</div>
198 198 <% if l_width > 0 %>
199 199 <div style="top:<%= top %>px;left:<%= i_left %>px;width:<%= l_width %>px;" class="task task_late">&nbsp;</div>
200 200 <% end %>
201 201 <% if d_width > 0 %>
202 202 <div style="top:<%= top %>px;left:<%= i_left %>px;width:<%= d_width %>px;" class="task task_done">&nbsp;</div>
203 203 <% end %>
204 204 <div style="top:<%= top %>px;left:<%= i_left + i_width + 5 %>px;background:#fff;" class="task">
205 205 <%= i.status.name %>
206 206 <%= (i.done_ratio).to_i %>%
207 207 </div>
208 208 <div class="tooltip" style="position: absolute;top:<%= top %>px;left:<%= i_left %>px;width:<%= i_width %>px;height:12px;">
209 209 <span class="tip">
210 210 <%= render_issue_tooltip i %>
211 211 </span></div>
212 212 <% else
213 213 i_left = ((i.start_date - @gantt.date_from)*zoom).floor
214 214 %>
215 215 <div style="top:<%= top %>px;left:<%= i_left %>px;width:15px;" class="task milestone">&nbsp;</div>
216 216 <div style="top:<%= top %>px;left:<%= i_left + 12 %>px;background:#fff;" class="task">
217 217 <%= h("#{i.project} -") unless @project && @project == i.project %>
218 218 <strong><%=h i %></strong>
219 219 </div>
220 220 <% end %>
221 221 <% top = top + 20
222 222 end %>
223 223
224 224 <%
225 225 #
226 226 # Today red line (excluded from cache)
227 227 #
228 228 if Date.today >= @gantt.date_from and Date.today <= @gantt.date_to %>
229 229 <div style="position: absolute;height:<%= g_height %>px;top:<%= headers_height + 1 %>px;left:<%= ((Date.today-@gantt.date_from+1)*zoom).floor()-1 %>px;width:10px;border-left: 1px dashed red;">&nbsp;</div>
230 230 <% end %>
231 231
232 232 </div>
233 233 </td>
234 234 </tr>
235 235 </table>
236 236
237 237 <table width="100%">
238 238 <tr>
239 239 <td align="left"><%= link_to_remote ('&#171; ' + l(:label_previous)), {:url => @gantt.params_previous, :update => 'content', :complete => 'window.scrollTo(0,0)'}, {:href => url_for(@gantt.params_previous)} %></td>
240 240 <td align="right"><%= link_to_remote (l(:label_next) + ' &#187;'), {:url => @gantt.params_next, :update => 'content', :complete => 'window.scrollTo(0,0)'}, {:href => url_for(@gantt.params_next)} %></td>
241 241 </tr>
242 242 </table>
243 243
244 <p class="other-formats">
245 <%= l(:label_export_to) %>
246 <span><%= link_to 'PDF', @gantt.params.merge(:format => 'pdf'), :class => 'pdf' %></span>
247 <% if @gantt.respond_to?('to_image') %>
248 <span><%= link_to 'PNG', @gantt.params.merge(:format => 'png'), :class => 'image' %></span>
244 <% other_formats_links do |f| %>
245 <%= f.link_to 'PDF', :url => @gantt.params %>
246 <%= f.link_to('PNG', :url => @gantt.params) if @gantt.respond_to?('to_image') %>
249 247 <% end %>
250 </p>
251 248 <% end # query.valid? %>
252 249
253 250 <% content_for :sidebar do %>
254 251 <%= render :partial => 'issues/sidebar' %>
255 252 <% end %>
256 253
257 254 <% html_title(l(:label_gantt)) -%>
@@ -1,68 +1,68
1 1 <% if @query.new_record? %>
2 2 <h2><%=l(:label_issue_plural)%></h2>
3 3 <% html_title(l(:label_issue_plural)) %>
4 4
5 5 <% form_tag({ :controller => 'queries', :action => 'new' }, :id => 'query_form') do %>
6 6 <%= hidden_field_tag('project_id', @project.id) if @project %>
7 7 <fieldset id="filters"><legend><%= l(:label_filter_plural) %></legend>
8 8 <%= render :partial => 'queries/filters', :locals => {:query => @query} %>
9 9 <p class="buttons">
10 10 <%= link_to_remote l(:button_apply),
11 11 { :url => { :set_filter => 1 },
12 12 :update => "content",
13 13 :with => "Form.serialize('query_form')"
14 14 }, :class => 'icon icon-checked' %>
15 15
16 16 <%= link_to_remote l(:button_clear),
17 17 { :url => { :set_filter => 1, :project_id => (@project.nil? ? nil : @project.id) },
18 18 :method => :get,
19 19 :update => "content",
20 20 }, :class => 'icon icon-reload' %>
21 21
22 22 <% if User.current.allowed_to?(:save_queries, @project, :global => true) %>
23 23 <%= link_to l(:button_save), {}, :onclick => "$('query_form').submit(); return false;", :class => 'icon icon-save' %>
24 24 <% end %>
25 25 </p>
26 26 </fieldset>
27 27 <% end %>
28 28 <% else %>
29 29 <div class="contextual">
30 30 <% if @query.editable_by?(User.current) %>
31 31 <%= link_to l(:button_edit), {:controller => 'queries', :action => 'edit', :id => @query}, :class => 'icon icon-edit' %>
32 32 <%= link_to l(:button_delete), {:controller => 'queries', :action => 'destroy', :id => @query}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %>
33 33 <% end %>
34 34 </div>
35 35 <h2><%=h @query.name %></h2>
36 36 <div id="query_form"></div>
37 37 <% html_title @query.name %>
38 38 <% end %>
39 39 <%= error_messages_for 'query' %>
40 40 <% if @query.valid? %>
41 41 <% if @issues.empty? %>
42 42 <p class="nodata"><%= l(:label_no_data) %></p>
43 43 <% else %>
44 44 <%= render :partial => 'issues/list', :locals => {:issues => @issues, :query => @query} %>
45 45 <p class="pagination"><%= pagination_links_full @issue_pages, @issue_count %></p>
46 46
47 <p class="other-formats">
48 <%= l(:label_export_to) %>
49 <span><%= link_to 'Atom', {:query_id => @query, :format => 'atom', :key => User.current.rss_key}, :class => 'feed' %></span>
50 <span><%= link_to 'CSV', {:format => 'csv'}, :class => 'csv' %></span>
51 <span><%= link_to 'PDF', {:format => 'pdf'}, :class => 'pdf' %></span>
52 </p>
47 <% other_formats_links do |f| %>
48 <%= f.link_to 'Atom', :url => {:query_id => (@query.new_record? ? nil : @query), :key => User.current.rss_key} %>
49 <%= f.link_to 'CSV' %>
50 <%= f.link_to 'PDF' %>
51 <% end %>
52
53 53 <% end %>
54 54 <% end %>
55 55
56 56 <% content_for :sidebar do %>
57 57 <%= render :partial => 'issues/sidebar' %>
58 58 <% end %>
59 59
60 60 <% content_for :header_tags do %>
61 61 <%= auto_discovery_link_tag(:atom, {:query_id => @query, :format => 'atom', :page => nil, :key => User.current.rss_key}, :title => l(:label_issue_plural)) %>
62 62 <%= auto_discovery_link_tag(:atom, {:action => 'changes', :query_id => @query, :format => 'atom', :page => nil, :key => User.current.rss_key}, :title => l(:label_changes_details)) %>
63 63 <%= javascript_include_tag 'context_menu' %>
64 64 <%= stylesheet_link_tag 'context_menu' %>
65 65 <% end %>
66 66
67 67 <div id="context-menu" style="display: none;"></div>
68 68 <%= javascript_tag "new ContextMenu('#{url_for(:controller => 'issues', :action => 'context_menu')}')" %>
@@ -1,126 +1,125
1 1 <div class="contextual">
2 2 <%= link_to_if_authorized(l(:button_update), {:controller => 'issues', :action => 'edit', :id => @issue }, :onclick => 'showAndScrollTo("update", "notes"); return false;', :class => 'icon icon-edit', :accesskey => accesskey(:edit)) %>
3 3 <%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'edit', :issue_id => @issue}, :class => 'icon icon-time' %>
4 4 <%= watcher_tag(@issue, User.current) %>
5 5 <%= link_to_if_authorized l(:button_copy), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue }, :class => 'icon icon-copy' %>
6 6 <%= link_to_if_authorized l(:button_move), {:controller => 'issues', :action => 'move', :id => @issue }, :class => 'icon icon-move' %>
7 7 <%= link_to_if_authorized l(:button_delete), {:controller => 'issues', :action => 'destroy', :id => @issue}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %>
8 8 </div>
9 9
10 10 <h2><%= @issue.tracker.name %> #<%= @issue.id %></h2>
11 11
12 12 <div class="<%= css_issue_classes(@issue) %>">
13 13 <%= avatar(@issue.author, :size => "64") %>
14 14 <h3><%=h @issue.subject %></h3>
15 15 <p class="author">
16 16 <%= authoring @issue.created_on, @issue.author %>.
17 17 <%= l(:label_updated_time, distance_of_time_in_words(Time.now, @issue.updated_on)) + '.' if @issue.created_on != @issue.updated_on %>
18 18 </p>
19 19
20 20 <table width="100%">
21 21 <tr>
22 22 <td style="width:15%" class="status"><b><%=l(:field_status)%>:</b></td><td style="width:35%" class="status status-<%= @issue.status.name %>"><%= @issue.status.name %></td>
23 23 <td style="width:15%" class="start-date"><b><%=l(:field_start_date)%>:</b></td><td style="width:35%"><%= format_date(@issue.start_date) %></td>
24 24 </tr>
25 25 <tr>
26 26 <td class="priority"><b><%=l(:field_priority)%>:</b></td><td class="priority priority-<%= @issue.priority.name %>"><%= @issue.priority.name %></td>
27 27 <td class="due-date"><b><%=l(:field_due_date)%>:</b></td><td class="due-date"><%= format_date(@issue.due_date) %></td>
28 28 </tr>
29 29 <tr>
30 30 <td class="assigned-to"><b><%=l(:field_assigned_to)%>:</b></td><td><%= avatar(@issue.assigned_to, :size => "14") %><%= @issue.assigned_to ? link_to_user(@issue.assigned_to) : "-" %></td>
31 31 <td class="progress"><b><%=l(:field_done_ratio)%>:</b></td><td class="progress"><%= progress_bar @issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%" %></td>
32 32 </tr>
33 33 <tr>
34 34 <td class="category"><b><%=l(:field_category)%>:</b></td><td><%=h @issue.category ? @issue.category.name : "-" %></td>
35 35 <% if User.current.allowed_to?(:view_time_entries, @project) %>
36 36 <td class="spent-time"><b><%=l(:label_spent_time)%>:</b></td>
37 37 <td class="spent-hours"><%= @issue.spent_hours > 0 ? (link_to lwr(:label_f_hour, @issue.spent_hours), {:controller => 'timelog', :action => 'details', :project_id => @project, :issue_id => @issue}, :class => 'icon icon-time') : "-" %></td>
38 38 <% end %>
39 39 </tr>
40 40 <tr>
41 41 <td class="fixed-version"><b><%=l(:field_fixed_version)%>:</b></td><td><%= @issue.fixed_version ? link_to_version(@issue.fixed_version) : "-" %></td>
42 42 <% if @issue.estimated_hours %>
43 43 <td class="estimated-hours"><b><%=l(:field_estimated_hours)%>:</b></td><td><%= lwr(:label_f_hour, @issue.estimated_hours) %></td>
44 44 <% end %>
45 45 </tr>
46 46 <tr>
47 47 <% n = 0 -%>
48 48 <% @issue.custom_values.each do |value| -%>
49 49 <td valign="top"><b><%=h value.custom_field.name %>:</b></td><td valign="top"><%= simple_format(h(show_value(value))) %></td>
50 50 <% n = n + 1
51 51 if (n > 1)
52 52 n = 0 %>
53 53 </tr><tr>
54 54 <%end
55 55 end %>
56 56 </tr>
57 57 <%= call_hook(:view_issues_show_details_bottom, :issue => @issue) %>
58 58 </table>
59 59 <hr />
60 60
61 61 <div class="contextual">
62 62 <%= link_to_remote_if_authorized(l(:button_quote), { :url => {:action => 'reply', :id => @issue} }, :class => 'icon icon-comment') unless @issue.description.blank? %>
63 63 </div>
64 64
65 65 <p><strong><%=l(:field_description)%></strong></p>
66 66 <div class="wiki">
67 67 <%= textilizable @issue, :description, :attachments => @issue.attachments %>
68 68 </div>
69 69
70 70 <%= link_to_attachments @issue %>
71 71
72 72 <% if authorize_for('issue_relations', 'new') || @issue.relations.any? %>
73 73 <hr />
74 74 <div id="relations">
75 75 <%= render :partial => 'relations' %>
76 76 </div>
77 77 <% end %>
78 78
79 79 <% if User.current.allowed_to?(:add_issue_watchers, @project) ||
80 80 (@issue.watchers.any? && User.current.allowed_to?(:view_issue_watchers, @project)) %>
81 81 <hr />
82 82 <div id="watchers">
83 83 <%= render :partial => 'watchers/watchers', :locals => {:watched => @issue} %>
84 84 </div>
85 85 <% end %>
86 86
87 87 </div>
88 88
89 89 <% if @issue.changesets.any? && User.current.allowed_to?(:view_changesets, @project) %>
90 90 <div id="issue-changesets">
91 91 <h3><%=l(:label_associated_revisions)%></h3>
92 92 <%= render :partial => 'changesets', :locals => { :changesets => @issue.changesets} %>
93 93 </div>
94 94 <% end %>
95 95
96 96 <% if @journals.any? %>
97 97 <div id="history">
98 98 <h3><%=l(:label_history)%></h3>
99 99 <%= render :partial => 'history', :locals => { :journals => @journals } %>
100 100 </div>
101 101 <% end %>
102 102 <div style="clear: both;"></div>
103 103
104 104 <% if authorize_for('issues', 'edit') %>
105 105 <div id="update" style="display:none;">
106 106 <h3><%= l(:button_update) %></h3>
107 107 <%= render :partial => 'edit' %>
108 108 </div>
109 109 <% end %>
110 110
111 <p class="other-formats">
112 <%= l(:label_export_to) %>
113 <span><%= link_to 'Atom', {:format => 'atom', :key => User.current.rss_key}, :class => 'feed' %></span>
114 <span><%= link_to 'PDF', {:format => 'pdf'}, :class => 'pdf' %></span>
115 </p>
111 <% other_formats_links do |f| %>
112 <%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %>
113 <%= f.link_to 'PDF' %>
114 <% end %>
116 115
117 116 <% html_title "#{@issue.tracker.name} ##{@issue.id}: #{@issue.subject}" %>
118 117
119 118 <% content_for :sidebar do %>
120 119 <%= render :partial => 'issues/sidebar' %>
121 120 <% end %>
122 121
123 122 <% content_for :header_tags do %>
124 123 <%= auto_discovery_link_tag(:atom, {:format => 'atom', :key => User.current.rss_key}, :title => "#{@issue.project} - #{@issue.tracker} ##{@issue.id}: #{@issue.subject}") %>
125 124 <%= stylesheet_link_tag 'scm' %>
126 125 <% end %>
@@ -1,51 +1,50
1 1 <div class="contextual">
2 2 <%= link_to_if_authorized(l(:label_news_new),
3 3 {:controller => 'news', :action => 'new', :project_id => @project},
4 4 :class => 'icon icon-add',
5 5 :onclick => 'Element.show("add-news"); Form.Element.focus("news_title"); return false;') if @project %>
6 6 </div>
7 7
8 8 <div id="add-news" style="display:none;">
9 9 <h2><%=l(:label_news_new)%></h2>
10 10 <% labelled_tabular_form_for :news, @news, :url => { :controller => 'news', :action => 'new', :project_id => @project },
11 11 :html => { :id => 'news-form' } do |f| %>
12 12 <%= render :partial => 'news/form', :locals => { :f => f } %>
13 13 <%= submit_tag l(:button_create) %>
14 14 <%= link_to_remote l(:label_preview),
15 15 { :url => { :controller => 'news', :action => 'preview', :project_id => @project },
16 16 :method => 'post',
17 17 :update => 'preview',
18 18 :with => "Form.serialize('news-form')"
19 19 }, :accesskey => accesskey(:preview) %> |
20 20 <%= link_to l(:button_cancel), "#", :onclick => 'Element.hide("add-news")' %>
21 21 <% end if @project %>
22 22 <div id="preview" class="wiki"></div>
23 23 </div>
24 24
25 25 <h2><%=l(:label_news_plural)%></h2>
26 26
27 27 <% if @newss.empty? %>
28 28 <p class="nodata"><%= l(:label_no_data) %></p>
29 29 <% else %>
30 30 <% @newss.each do |news| %>
31 31 <h3><%= link_to(h(news.project.name), :controller => 'projects', :action => 'show', :id => news.project) + ': ' unless news.project == @project %>
32 32 <%= link_to h(news.title), :controller => 'news', :action => 'show', :id => news %>
33 33 <%= "(#{news.comments_count} #{lwr(:label_comment, news.comments_count).downcase})" if news.comments_count > 0 %></h3>
34 34 <p class="author"><%= authoring news.created_on, news.author %></p>
35 35 <div class="wiki">
36 36 <%= textilizable(news.description) %>
37 37 </div>
38 38 <% end %>
39 39 <% end %>
40 40 <p class="pagination"><%= pagination_links_full @news_pages %></p>
41 41
42 <p class="other-formats">
43 <%= l(:label_export_to) %>
44 <span><%= link_to 'Atom', {:project_id => @project, :format => 'atom', :key => User.current.rss_key}, :class => 'feed' %></span>
45 </p>
42 <% other_formats_links do |f| %>
43 <%= f.link_to 'Atom', :url => {:project_id => @project, :key => User.current.rss_key} %>
44 <% end %>
46 45
47 46 <% content_for :header_tags do %>
48 47 <%= auto_discovery_link_tag(:atom, params.merge({:format => 'atom', :page => nil, :key => User.current.rss_key})) %>
49 48 <% end %>
50 49
51 50 <% html_title(l(:label_news_plural)) -%>
@@ -1,60 +1,59
1 1 <h2><%= @author.nil? ? l(:label_activity) : l(:label_user_activity, link_to_user(@author)) %></h2>
2 2 <p class="subtitle"><%= "#{l(:label_date_from)} #{format_date(@date_to - @days)} #{l(:label_date_to).downcase} #{format_date(@date_to-1)}" %></p>
3 3
4 4 <div id="activity">
5 5 <% @events_by_day.keys.sort.reverse.each do |day| %>
6 6 <h3><%= format_activity_day(day) %></h3>
7 7 <dl>
8 8 <% @events_by_day[day].sort {|x,y| y.event_datetime <=> x.event_datetime }.each do |e| -%>
9 9 <dt class="<%= e.event_type %> <%= User.current.logged? && e.respond_to?(:event_author) && User.current == e.event_author ? 'me' : nil %>">
10 10 <%= avatar(e.event_author, :size => "24") if e.respond_to?(:event_author) %>
11 11 <span class="time"><%= format_time(e.event_datetime, false) %></span>
12 12 <%= content_tag('span', h(e.project), :class => 'project') if @project.nil? || @project != e.project %>
13 13 <%= link_to format_activity_title(e.event_title), e.event_url %></dt>
14 14 <dd><span class="description"><%= format_activity_description(e.event_description) %></span>
15 15 <span class="author"><%= e.event_author if e.respond_to?(:event_author) %></span></dd>
16 16 <% end -%>
17 17 </dl>
18 18 <% end -%>
19 19 </div>
20 20
21 21 <%= content_tag('p', l(:label_no_data), :class => 'nodata') if @events_by_day.empty? %>
22 22
23 23 <div style="float:left;">
24 24 <%= link_to_remote(('&#171; ' + l(:label_previous)),
25 25 {:update => "content", :url => params.merge(:from => @date_to - @days - 1), :method => :get, :complete => 'window.scrollTo(0,0)'},
26 26 {:href => url_for(params.merge(:from => @date_to - @days - 1)),
27 27 :title => "#{l(:label_date_from)} #{format_date(@date_to - 2*@days)} #{l(:label_date_to).downcase} #{format_date(@date_to - @days - 1)}"}) %>
28 28 </div>
29 29 <div style="float:right;">
30 30 <%= link_to_remote((l(:label_next) + ' &#187;'),
31 31 {:update => "content", :url => params.merge(:from => @date_to + @days - 1), :method => :get, :complete => 'window.scrollTo(0,0)'},
32 32 {:href => url_for(params.merge(:from => @date_to + @days - 1)),
33 33 :title => "#{l(:label_date_from)} #{format_date(@date_to)} #{l(:label_date_to).downcase} #{format_date(@date_to + @days - 1)}"}) unless @date_to >= Date.today %>
34 34 </div>
35 35 &nbsp;
36 <p class="other-formats">
37 <%= l(:label_export_to) %>
38 <%= link_to 'Atom', params.merge(:format => :atom, :from => nil, :key => User.current.rss_key), :class => 'feed' %>
39 </p>
36 <% other_formats_links do |f| %>
37 <%= f.link_to 'Atom', :url => params.merge(:from => nil, :key => User.current.rss_key) %>
38 <% end %>
40 39
41 40 <% content_for :header_tags do %>
42 41 <%= auto_discovery_link_tag(:atom, params.merge(:format => 'atom', :from => nil, :key => User.current.rss_key)) %>
43 42 <% end %>
44 43
45 44 <% content_for :sidebar do %>
46 45 <% form_tag({}, :method => :get) do %>
47 46 <h3><%= l(:label_activity) %></h3>
48 47 <p><% @activity.event_types.each do |t| %>
49 48 <label><%= check_box_tag "show_#{t}", 1, @activity.scope.include?(t) %> <%= l("label_#{t.singularize}_plural")%></label><br />
50 49 <% end %></p>
51 50 <% if @project && @project.descendants.active.any? %>
52 51 <p><label><%= check_box_tag 'with_subprojects', 1, @with_subprojects %> <%=l(:label_subproject_plural)%></label></p>
53 52 <%= hidden_field_tag 'with_subprojects', 0 %>
54 53 <% end %>
55 54 <%= hidden_field_tag('user_id', params[:user_id]) unless params[:user_id].blank? %>
56 55 <p><%= submit_tag l(:button_apply), :class => 'button-small', :name => nil %></p>
57 56 <% end %>
58 57 <% end %>
59 58
60 59 <% html_title(l(:label_activity), @author) -%>
@@ -1,22 +1,21
1 1 <div class="contextual">
2 2 <%= link_to(l(:label_project_new), {:controller => 'projects', :action => 'add'}, :class => 'icon icon-add') + ' |' if User.current.admin? %>
3 3 <%= link_to l(:label_issue_view_all), { :controller => 'issues' } %> |
4 4 <%= link_to l(:label_overall_activity), { :controller => 'projects', :action => 'activity' }%>
5 5 </div>
6 6
7 7 <h2><%=l(:label_project_plural)%></h2>
8 8
9 9 <%= render_project_hierarchy(@projects)%>
10 10
11 11 <% if User.current.logged? %>
12 12 <p style="text-align:right;">
13 13 <span class="my-project"><%= l(:label_my_projects) %></span>
14 14 </p>
15 15 <% end %>
16 16
17 <p class="other-formats">
18 <%= l(:label_export_to) %>
19 <span><%= link_to 'Atom', {:format => 'atom', :key => User.current.rss_key}, :class => 'feed' %></span>
20 </p>
17 <% other_formats_links do |f| %>
18 <%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %>
19 <% end %>
21 20
22 21 <% html_title(l(:label_project_plural)) -%>
@@ -1,27 +1,26
1 1 <h2><%= l(:label_revision) %> <%= format_revision(@rev) %> <%= @path.gsub(/^.*\//, '') %></h2>
2 2
3 3 <!-- Choose view type -->
4 4 <% form_tag({ :controller => 'repositories', :action => 'diff'}, :method => 'get') do %>
5 5 <% params.each do |k, p| %>
6 6 <% if k != "type" %>
7 7 <%= hidden_field_tag(k,p) %>
8 8 <% end %>
9 9 <% end %>
10 10 <p><label><%= l(:label_view_diff) %></label>
11 11 <%= select_tag 'type', options_for_select([[l(:label_diff_inline), "inline"], [l(:label_diff_side_by_side), "sbs"]], @diff_type), :onchange => "if (this.value != '') {this.form.submit()}" %></p>
12 12 <% end %>
13 13
14 14 <% cache(@cache_key) do -%>
15 15 <%= render :partial => 'common/diff', :locals => {:diff => @diff, :diff_type => @diff_type} %>
16 16 <% end -%>
17 17
18 <p class="other-formats">
19 <%= l(:label_export_to) %>
20 <span><%= link_to 'Unified diff', params.merge(:format => 'diff') %></span>
21 </p>
18 <% other_formats_links do |f| %>
19 <%= f.link_to 'Diff', :url => params, :caption => 'Unified diff' %>
20 <% end %>
22 21
23 22 <% html_title(with_leading_slash(@path), 'Diff') -%>
24 23
25 24 <% content_for :header_tags do %>
26 25 <%= stylesheet_link_tag "scm" %>
27 26 <% end %>
@@ -1,24 +1,23
1 1 <div class="contextual">
2 2 <% form_tag({:action => 'revision', :id => @project}) do %>
3 3 <%= l(:label_revision) %>: <%= text_field_tag 'rev', @rev, :size => 5 %>
4 4 <%= submit_tag 'OK' %>
5 5 <% end %>
6 6 </div>
7 7
8 8 <h2><%= l(:label_revision_plural) %></h2>
9 9
10 10 <%= render :partial => 'revisions', :locals => {:project => @project, :path => '', :revisions => @changesets, :entry => nil }%>
11 11
12 12 <p class="pagination"><%= pagination_links_full @changeset_pages,@changeset_count %></p>
13 13
14 14 <% content_for :header_tags do %>
15 15 <%= stylesheet_link_tag "scm" %>
16 16 <%= auto_discovery_link_tag(:atom, params.merge({:format => 'atom', :page => nil, :key => User.current.rss_key})) %>
17 17 <% end %>
18 18
19 <p class="other-formats">
20 <%= l(:label_export_to) %>
21 <span><%= link_to 'Atom', {:format => 'atom', :key => User.current.rss_key}, :class => 'feed' %></span>
22 </p>
19 <% other_formats_links do |f| %>
20 <%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %>
21 <% end %>
23 22
24 23 <% html_title(l(:label_revision_plural)) -%>
@@ -1,35 +1,35
1 1 <div class="contextual">
2 2 <%= call_hook(:view_repositories_show_contextual, { :repository => @repository, :project => @project }) %>
3 3 <%= link_to l(:label_statistics), {:action => 'stats', :id => @project}, :class => 'icon icon-stats' %>
4 4
5 5 <% if !@entries.nil? && authorize_for('repositories', 'browse') -%>
6 6 <% form_tag(:action => 'browse', :id => @project) do -%>
7 7 | <%= l(:label_revision) %>: <%= text_field_tag 'rev', @rev, :size => 5 %>
8 8 <% end -%>
9 9 <% end -%>
10 10 </div>
11 11
12 12 <h2><%= l(:label_repository) %> (<%= @repository.scm_name %>)</h2>
13 13
14 14 <% if !@entries.nil? && authorize_for('repositories', 'browse') %>
15 15 <%= render :partial => 'dir_list' %>
16 16 <% end %>
17 17
18 18 <% if !@changesets.empty? && authorize_for('repositories', 'revisions') %>
19 19 <h3><%= l(:label_latest_revision_plural) %></h3>
20 20 <%= render :partial => 'revisions', :locals => {:project => @project, :path => '', :revisions => @changesets, :entry => nil }%>
21 21 <p><%= link_to l(:label_view_revisions), :action => 'revisions', :id => @project %></p>
22 22 <% content_for :header_tags do %>
23 23 <%= auto_discovery_link_tag(:atom, params.merge({:format => 'atom', :action => 'revisions', :id => @project, :page => nil, :key => User.current.rss_key})) %>
24 24 <% end %>
25 <p class="other-formats">
26 <%= l(:label_export_to) %>
27 <span><%= link_to 'Atom', {:action => 'revisions', :id => @project, :format => 'atom', :key => User.current.rss_key}, :class => 'feed' %></span>
28 </p>
25
26 <% other_formats_links do |f| %>
27 <%= f.link_to 'Atom', :url => {:action => 'revisions', :id => @project, :key => User.current.rss_key} %>
28 <% end %>
29 29 <% end %>
30 30
31 31 <% content_for :header_tags do %>
32 32 <%= stylesheet_link_tag "scm" %>
33 33 <% end %>
34 34
35 35 <% html_title(l(:label_repository)) -%>
@@ -1,36 +1,35
1 1 <div class="contextual">
2 2 <%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'edit', :project_id => @project, :issue_id => @issue}, :class => 'icon icon-time' %>
3 3 </div>
4 4
5 5 <%= render_timelog_breadcrumb %>
6 6
7 7 <h2><%= l(:label_spent_time) %></h2>
8 8
9 9 <% form_remote_tag( :url => {}, :html => {:method => :get}, :method => :get, :update => 'content' ) do %>
10 10 <%# TOOD: remove the project_id and issue_id hidden fields, that information is
11 11 already in the URI %>
12 12 <%= hidden_field_tag 'project_id', params[:project_id] %>
13 13 <%= hidden_field_tag 'issue_id', params[:issue_id] if @issue %>
14 14 <%= render :partial => 'date_range' %>
15 15 <% end %>
16 16
17 17 <div class="total-hours">
18 18 <p><%= l(:label_total) %>: <%= html_hours(lwr(:label_f_hour, @total_hours)) %></p>
19 19 </div>
20 20
21 21 <% unless @entries.empty? %>
22 22 <%= render :partial => 'list', :locals => { :entries => @entries }%>
23 23 <p class="pagination"><%= pagination_links_full @entry_pages, @entry_count %></p>
24 24
25 <p class="other-formats">
26 <%= l(:label_export_to) %>
27 <span><%= link_to 'Atom', {:issue_id => @issue, :format => 'atom', :key => User.current.rss_key}, :class => 'feed' %></span>
28 <span><%= link_to 'CSV', params.merge(:format => 'csv'), :class => 'csv' %></span>
29 </p>
25 <% other_formats_links do |f| %>
26 <%= f.link_to 'Atom', :url => params.merge({:issue_id => @issue, :key => User.current.rss_key}) %>
27 <%= f.link_to 'CSV', :url => params %>
28 <% end %>
30 29 <% end %>
31 30
32 31 <% html_title l(:label_spent_time), l(:label_details) %>
33 32
34 33 <% content_for :header_tags do %>
35 34 <%= auto_discovery_link_tag(:atom, {:issue_id => @issue, :format => 'atom', :key => User.current.rss_key}, :title => l(:label_spent_time)) %>
36 35 <% end %>
@@ -1,76 +1,75
1 1 <div class="contextual">
2 2 <%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'edit', :project_id => @project, :issue_id => @issue}, :class => 'icon icon-time' %>
3 3 </div>
4 4
5 5 <%= render_timelog_breadcrumb %>
6 6
7 7 <h2><%= l(:label_spent_time) %></h2>
8 8
9 9 <% form_remote_tag(:url => {}, :html => {:method => :get}, :method => :get, :update => 'content') do %>
10 10 <% @criterias.each do |criteria| %>
11 11 <%= hidden_field_tag 'criterias[]', criteria, :id => nil %>
12 12 <% end %>
13 13 <%# TODO: get rid of the project_id field, that should already be in the URL %>
14 14 <%= hidden_field_tag 'project_id', params[:project_id] %>
15 15 <%= render :partial => 'date_range' %>
16 16
17 17 <p><%= l(:label_details) %>: <%= select_tag 'columns', options_for_select([[l(:label_year), 'year'],
18 18 [l(:label_month), 'month'],
19 19 [l(:label_week), 'week'],
20 20 [l(:label_day_plural).titleize, 'day']], @columns),
21 21 :onchange => "this.form.onsubmit();" %>
22 22
23 23 <%= l(:button_add) %>: <%= select_tag('criterias[]', options_for_select([[]] + (@available_criterias.keys - @criterias).collect{|k| [l(@available_criterias[k][:label]), k]}),
24 24 :onchange => "this.form.onsubmit();",
25 25 :style => 'width: 200px',
26 26 :id => nil,
27 27 :disabled => (@criterias.length >= 3)) %>
28 28 <%= link_to_remote l(:button_clear), {:url => {:project_id => @project, :period_type => params[:period_type], :period => params[:period], :from => @from, :to => @to, :columns => @columns},
29 29 :method => :get,
30 30 :update => 'content'
31 31 }, :class => 'icon icon-reload' %></p>
32 32 <% end %>
33 33
34 34 <% unless @criterias.empty? %>
35 35 <div class="total-hours">
36 36 <p><%= l(:label_total) %>: <%= html_hours(lwr(:label_f_hour, @total_hours)) %></p>
37 37 </div>
38 38
39 39 <% unless @hours.empty? %>
40 40 <table class="list" id="time-report">
41 41 <thead>
42 42 <tr>
43 43 <% @criterias.each do |criteria| %>
44 44 <th><%= l(@available_criterias[criteria][:label]) %></th>
45 45 <% end %>
46 46 <% columns_width = (40 / (@periods.length+1)).to_i %>
47 47 <% @periods.each do |period| %>
48 48 <th class="period" width="<%= columns_width %>%"><%= period %></th>
49 49 <% end %>
50 50 <th class="total" width="<%= columns_width %>%"><%= l(:label_total) %></th>
51 51 </tr>
52 52 </thead>
53 53 <tbody>
54 54 <%= render :partial => 'report_criteria', :locals => {:criterias => @criterias, :hours => @hours, :level => 0} %>
55 55 <tr class="total">
56 56 <td><%= l(:label_total) %></td>
57 57 <%= '<td></td>' * (@criterias.size - 1) %>
58 58 <% total = 0 -%>
59 59 <% @periods.each do |period| -%>
60 60 <% sum = sum_hours(select_hours(@hours, @columns, period.to_s)); total += sum -%>
61 61 <td class="hours"><%= html_hours("%.2f" % sum) if sum > 0 %></td>
62 62 <% end -%>
63 63 <td class="hours"><%= html_hours("%.2f" % total) if total > 0 %></td>
64 64 </tr>
65 65 </tbody>
66 66 </table>
67 67
68 <p class="other-formats">
69 <%= l(:label_export_to) %>
70 <span><%= link_to 'CSV', params.merge({:format => 'csv'}), :class => 'csv' %></span>
71 </p>
68 <% other_formats_links do |f| %>
69 <%= f.link_to 'CSV', :url => params %>
70 <% end %>
72 71 <% end %>
73 72 <% end %>
74 73
75 74 <% html_title l(:label_spent_time), l(:label_report) %>
76 75
@@ -1,59 +1,58
1 1 <div class="contextual">
2 2 <% if @editable %>
3 3 <%= link_to_if_authorized(l(:button_edit), {:action => 'edit', :page => @page.title}, :class => 'icon icon-edit', :accesskey => accesskey(:edit)) if @content.version == @page.content.version %>
4 4 <%= link_to_if_authorized(l(:button_lock), {:action => 'protect', :page => @page.title, :protected => 1}, :method => :post, :class => 'icon icon-lock') if !@page.protected? %>
5 5 <%= link_to_if_authorized(l(:button_unlock), {:action => 'protect', :page => @page.title, :protected => 0}, :method => :post, :class => 'icon icon-unlock') if @page.protected? %>
6 6 <%= link_to_if_authorized(l(:button_rename), {:action => 'rename', :page => @page.title}, :class => 'icon icon-move') if @content.version == @page.content.version %>
7 7 <%= link_to_if_authorized(l(:button_delete), {:action => 'destroy', :page => @page.title}, :method => :post, :confirm => l(:text_are_you_sure), :class => 'icon icon-del') %>
8 8 <%= link_to_if_authorized(l(:button_rollback), {:action => 'edit', :page => @page.title, :version => @content.version }, :class => 'icon icon-cancel') if @content.version < @page.content.version %>
9 9 <% end %>
10 10 <%= link_to_if_authorized(l(:label_history), {:action => 'history', :page => @page.title}, :class => 'icon icon-history') %>
11 11 </div>
12 12
13 13 <%= breadcrumb(@page.ancestors.reverse.collect {|parent| link_to h(parent.pretty_title), {:page => parent.title}}) %>
14 14
15 15 <% if @content.version != @page.content.version %>
16 16 <p>
17 17 <%= link_to(('&#171; ' + l(:label_previous)), :action => 'index', :page => @page.title, :version => (@content.version - 1)) + " - " if @content.version > 1 %>
18 18 <%= "#{l(:label_version)} #{@content.version}/#{@page.content.version}" %>
19 19 <%= '(' + link_to('diff', :controller => 'wiki', :action => 'diff', :page => @page.title, :version => @content.version) + ')' if @content.version > 1 %> -
20 20 <%= link_to((l(:label_next) + ' &#187;'), :action => 'index', :page => @page.title, :version => (@content.version + 1)) + " - " if @content.version < @page.content.version %>
21 21 <%= link_to(l(:label_current_version), :action => 'index', :page => @page.title) %>
22 22 <br />
23 23 <em><%= @content.author ? @content.author.name : "anonyme" %>, <%= format_time(@content.updated_on) %> </em><br />
24 24 <%=h @content.comments %>
25 25 </p>
26 26 <hr />
27 27 <% end %>
28 28
29 29 <%= render(:partial => "wiki/content", :locals => {:content => @content}) %>
30 30
31 31 <%= link_to_attachments @page %>
32 32
33 33 <% if @editable && authorize_for('wiki', 'add_attachment') %>
34 34 <p><%= link_to l(:label_attachment_new), {}, :onclick => "Element.show('add_attachment_form'); Element.hide(this); Element.scrollTo('add_attachment_form'); return false;",
35 35 :id => 'attach_files_link' %></p>
36 36 <% form_tag({ :controller => 'wiki', :action => 'add_attachment', :page => @page.title }, :multipart => true, :id => "add_attachment_form", :style => "display:none;") do %>
37 37 <div class="box">
38 38 <p><%= render :partial => 'attachments/form' %></p>
39 39 </div>
40 40 <%= submit_tag l(:button_add) %>
41 41 <%= link_to l(:button_cancel), {}, :onclick => "Element.hide('add_attachment_form'); Element.show('attach_files_link'); return false;" %>
42 42 <% end %>
43 43 <% end %>
44 44
45 <p class="other-formats">
46 <%= l(:label_export_to) %>
47 <span><%= link_to 'HTML', {:page => @page.title, :export => 'html', :version => @content.version}, :class => 'html' %></span>
48 <span><%= link_to 'TXT', {:page => @page.title, :export => 'txt', :version => @content.version}, :class => 'text' %></span>
49 </p>
45 <% other_formats_links do |f| %>
46 <%= f.link_to 'HTML', :url => {:page => @page.title, :version => @content.version} %>
47 <%= f.link_to 'TXT', :url => {:page => @page.title, :version => @content.version} %>
48 <% end %>
50 49
51 50 <% content_for :header_tags do %>
52 51 <%= stylesheet_link_tag 'scm' %>
53 52 <% end %>
54 53
55 54 <% content_for :sidebar do %>
56 55 <%= render :partial => 'sidebar' %>
57 56 <% end %>
58 57
59 58 <% html_title @page.pretty_title %>
@@ -1,30 +1,29
1 1 <h2><%= l(:label_index_by_date) %></h2>
2 2
3 3 <% if @pages.empty? %>
4 4 <p class="nodata"><%= l(:label_no_data) %></p>
5 5 <% end %>
6 6
7 7 <% @pages_by_date.keys.sort.reverse.each do |date| %>
8 8 <h3><%= format_date(date) %></h3>
9 9 <ul>
10 10 <% @pages_by_date[date].each do |page| %>
11 11 <li><%= link_to page.pretty_title, :action => 'index', :page => page.title %></li>
12 12 <% end %>
13 13 </ul>
14 14 <% end %>
15 15
16 16 <% content_for :sidebar do %>
17 17 <%= render :partial => 'sidebar' %>
18 18 <% end %>
19 19
20 20 <% unless @pages.empty? %>
21 <p class="other-formats">
22 <%= l(:label_export_to) %>
23 <span><%= link_to 'Atom', {:controller => 'projects', :action => 'activity', :id => @project, :show_wiki_pages => 1, :format => 'atom', :key => User.current.rss_key}, :class => 'feed' %></span>
24 <span><%= link_to 'HTML', {:action => 'special', :page => 'export'}, :class => 'html' %></span>
25 </p>
21 <% other_formats_links do |f| %>
22 <%= f.link_to 'Atom', :url => {:controller => 'projects', :action => 'activity', :id => @project, :show_wiki_pages => 1, :key => User.current.rss_key} %>
23 <%= f.link_to 'HTML', :url => {:action => 'special', :page => 'export'} %>
24 <% end %>
26 25 <% end %>
27 26
28 27 <% content_for :header_tags do %>
29 28 <%= auto_discovery_link_tag(:atom, :controller => 'projects', :action => 'activity', :id => @project, :show_wiki_pages => 1, :format => 'atom', :key => User.current.rss_key) %>
30 29 <% end %>
@@ -1,23 +1,22
1 1 <h2><%= l(:label_index_by_title) %></h2>
2 2
3 3 <% if @pages.empty? %>
4 4 <p class="nodata"><%= l(:label_no_data) %></p>
5 5 <% end %>
6 6
7 7 <%= render_page_hierarchy(@pages_by_parent_id) %>
8 8
9 9 <% content_for :sidebar do %>
10 10 <%= render :partial => 'sidebar' %>
11 11 <% end %>
12 12
13 13 <% unless @pages.empty? %>
14 <p class="other-formats">
15 <%= l(:label_export_to) %>
16 <span><%= link_to 'Atom', {:controller => 'projects', :action => 'activity', :id => @project, :show_wiki_pages => 1, :format => 'atom', :key => User.current.rss_key}, :class => 'feed' %></span>
17 <span><%= link_to 'HTML', {:action => 'special', :page => 'export'} %></span>
18 </p>
14 <% other_formats_links do |f| %>
15 <%= f.link_to 'Atom', :url => {:controller => 'projects', :action => 'activity', :id => @project, :show_wiki_pages => 1, :key => User.current.rss_key} %>
16 <%= f.link_to 'HTML', :url => {:action => 'special', :page => 'export'} %>
17 <% end %>
19 18 <% end %>
20 19
21 20 <% content_for :header_tags do %>
22 21 <%= auto_discovery_link_tag(:atom, :controller => 'projects', :action => 'activity', :id => @project, :show_wiki_pages => 1, :format => 'atom', :key => User.current.rss_key) %>
23 22 <% end %>
@@ -1,701 +1,701
1 1 body { font-family: Verdana, sans-serif; font-size: 12px; color:#484848; margin: 0; padding: 0; min-width: 900px; }
2 2
3 3 h1, h2, h3, h4 { font-family: "Trebuchet MS", Verdana, sans-serif;}
4 4 h1 {margin:0; padding:0; font-size: 24px;}
5 5 h2, .wiki h1 {font-size: 20px;padding: 2px 10px 1px 0px;margin: 0 0 10px 0; border-bottom: 1px solid #bbbbbb; color: #444;}
6 6 h3, .wiki h2 {font-size: 16px;padding: 2px 10px 1px 0px;margin: 0 0 10px 0; border-bottom: 1px solid #bbbbbb; color: #444;}
7 7 h4, .wiki h3 {font-size: 13px;padding: 2px 10px 1px 0px;margin-bottom: 5px; border-bottom: 1px dotted #bbbbbb; color: #444;}
8 8
9 9 /***** Layout *****/
10 10 #wrapper {background: white;}
11 11
12 12 #top-menu {background: #2C4056; color: #fff; height:1.8em; font-size: 0.8em; padding: 2px 2px 0px 6px;}
13 13 #top-menu ul {margin: 0; padding: 0;}
14 14 #top-menu li {
15 15 float:left;
16 16 list-style-type:none;
17 17 margin: 0px 0px 0px 0px;
18 18 padding: 0px 0px 0px 0px;
19 19 white-space:nowrap;
20 20 }
21 21 #top-menu a {color: #fff; margin-right: 8px; font-weight: bold;}
22 22 #top-menu #loggedas { float: right; margin-right: 0.5em; color: #fff; }
23 23
24 24 #account {float:right;}
25 25
26 26 #header {height:5.3em;margin:0;background-color:#507AAA;color:#f8f8f8; padding: 4px 8px 0px 6px; position:relative;}
27 27 #header a {color:#f8f8f8;}
28 28 #quick-search {float:right;}
29 29
30 30 #main-menu {position: absolute; bottom: 0px; left:6px; margin-right: -500px;}
31 31 #main-menu ul {margin: 0; padding: 0;}
32 32 #main-menu li {
33 33 float:left;
34 34 list-style-type:none;
35 35 margin: 0px 2px 0px 0px;
36 36 padding: 0px 0px 0px 0px;
37 37 white-space:nowrap;
38 38 }
39 39 #main-menu li a {
40 40 display: block;
41 41 color: #fff;
42 42 text-decoration: none;
43 43 font-weight: bold;
44 44 margin: 0;
45 45 padding: 4px 10px 4px 10px;
46 46 }
47 47 #main-menu li a:hover {background:#759FCF; color:#fff;}
48 48 #main-menu li a.selected, #main-menu li a.selected:hover {background:#fff; color:#555;}
49 49
50 50 #main {background-color:#EEEEEE;}
51 51
52 52 #sidebar{ float: right; width: 17%; position: relative; z-index: 9; min-height: 600px; padding: 0; margin: 0;}
53 53 * html #sidebar{ width: 17%; }
54 54 #sidebar h3{ font-size: 14px; margin-top:14px; color: #666; }
55 55 #sidebar hr{ width: 100%; margin: 0 auto; height: 1px; background: #ccc; border: 0; }
56 56 * html #sidebar hr{ width: 95%; position: relative; left: -6px; color: #ccc; }
57 57
58 58 #content { width: 80%; background-color: #fff; margin: 0px; border-right: 1px solid #ddd; padding: 6px 10px 10px 10px; z-index: 10; }
59 59 * html #content{ width: 80%; padding-left: 0; margin-top: 0px; padding: 6px 10px 10px 10px;}
60 60 html>body #content { min-height: 600px; }
61 61 * html body #content { height: 600px; } /* IE */
62 62
63 63 #main.nosidebar #sidebar{ display: none; }
64 64 #main.nosidebar #content{ width: auto; border-right: 0; }
65 65
66 66 #footer {clear: both; border-top: 1px solid #bbb; font-size: 0.9em; color: #aaa; padding: 5px; text-align:center; background:#fff;}
67 67
68 68 #login-form table {margin-top:5em; padding:1em; margin-left: auto; margin-right: auto; border: 2px solid #FDBF3B; background-color:#FFEBC1; }
69 69 #login-form table td {padding: 6px;}
70 70 #login-form label {font-weight: bold;}
71 71
72 72 .clear:after{ content: "."; display: block; height: 0; clear: both; visibility: hidden; }
73 73
74 74 /***** Links *****/
75 75 a, a:link, a:visited{ color: #2A5685; text-decoration: none; }
76 76 a:hover, a:active{ color: #c61a1a; text-decoration: underline;}
77 77 a img{ border: 0; }
78 78
79 79 a.issue.closed { text-decoration: line-through; }
80 80
81 81 /***** Tables *****/
82 82 table.list { border: 1px solid #e4e4e4; border-collapse: collapse; width: 100%; margin-bottom: 4px; }
83 83 table.list th { background-color:#EEEEEE; padding: 4px; white-space:nowrap; }
84 84 table.list td { vertical-align: top; }
85 85 table.list td.id { width: 2%; text-align: center;}
86 86 table.list td.checkbox { width: 15px; padding: 0px;}
87 87
88 88 tr.project td.name a { padding-left: 16px; white-space:nowrap; }
89 89 tr.project.parent td.name a { background: url('../images/bullet_toggle_minus.png') no-repeat; }
90 90
91 91 tr.issue { text-align: center; white-space: nowrap; }
92 92 tr.issue td.subject, tr.issue td.category, td.assigned_to { white-space: normal; }
93 93 tr.issue td.subject { text-align: left; }
94 94 tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;}
95 95
96 96 tr.entry { border: 1px solid #f8f8f8; }
97 97 tr.entry td { white-space: nowrap; }
98 98 tr.entry td.filename { width: 30%; }
99 99 tr.entry td.size { text-align: right; font-size: 90%; }
100 100 tr.entry td.revision, tr.entry td.author { text-align: center; }
101 101 tr.entry td.age { text-align: right; }
102 102
103 103 tr.entry span.expander {background-image: url(../images/bullet_toggle_plus.png); padding-left: 8px; margin-left: 0; cursor: pointer;}
104 104 tr.entry.open span.expander {background-image: url(../images/bullet_toggle_minus.png);}
105 105 tr.entry.file td.filename a { margin-left: 16px; }
106 106
107 107 tr.changeset td.author { text-align: center; width: 15%; }
108 108 tr.changeset td.committed_on { text-align: center; width: 15%; }
109 109
110 110 tr.message { height: 2.6em; }
111 111 tr.message td.last_message { font-size: 80%; }
112 112 tr.message.locked td.subject a { background-image: url(../images/locked.png); }
113 113 tr.message.sticky td.subject a { background-image: url(../images/sticky.png); font-weight: bold; }
114 114
115 115 tr.user td { width:13%; }
116 116 tr.user td.email { width:18%; }
117 117 tr.user td { white-space: nowrap; }
118 118 tr.user.locked, tr.user.registered { color: #aaa; }
119 119 tr.user.locked a, tr.user.registered a { color: #aaa; }
120 120
121 121 tr.time-entry { text-align: center; white-space: nowrap; }
122 122 tr.time-entry td.subject, tr.time-entry td.comments { text-align: left; white-space: normal; }
123 123 td.hours { text-align: right; font-weight: bold; padding-right: 0.5em; }
124 124 td.hours .hours-dec { font-size: 0.9em; }
125 125
126 126 table.plugins td { vertical-align: middle; }
127 127 table.plugins td.configure { text-align: right; padding-right: 1em; }
128 128 table.plugins span.name { font-weight: bold; display: block; margin-bottom: 6px; }
129 129 table.plugins span.description { display: block; font-size: 0.9em; }
130 130 table.plugins span.url { display: block; font-size: 0.9em; }
131 131
132 132 table.list tbody tr:hover { background-color:#ffffdd; }
133 133 table td {padding:2px;}
134 134 table p {margin:0;}
135 135 .odd {background-color:#f6f7f8;}
136 136 .even {background-color: #fff;}
137 137
138 138 .highlight { background-color: #FCFD8D;}
139 139 .highlight.token-1 { background-color: #faa;}
140 140 .highlight.token-2 { background-color: #afa;}
141 141 .highlight.token-3 { background-color: #aaf;}
142 142
143 143 .box{
144 144 padding:6px;
145 145 margin-bottom: 10px;
146 146 background-color:#f6f6f6;
147 147 color:#505050;
148 148 line-height:1.5em;
149 149 border: 1px solid #e4e4e4;
150 150 }
151 151
152 152 div.square {
153 153 border: 1px solid #999;
154 154 float: left;
155 155 margin: .3em .4em 0 .4em;
156 156 overflow: hidden;
157 157 width: .6em; height: .6em;
158 158 }
159 159 .contextual {float:right; white-space: nowrap; line-height:1.4em;margin-top:5px; padding-left: 10px; font-size:0.9em;}
160 160 .contextual input {font-size:0.9em;}
161 161
162 162 .splitcontentleft{float:left; width:49%;}
163 163 .splitcontentright{float:right; width:49%;}
164 164 form {display: inline;}
165 165 input, select {vertical-align: middle; margin-top: 1px; margin-bottom: 1px;}
166 166 fieldset {border: 1px solid #e4e4e4; margin:0;}
167 167 legend {color: #484848;}
168 168 hr { width: 100%; height: 1px; background: #ccc; border: 0;}
169 169 blockquote { font-style: italic; border-left: 3px solid #e0e0e0; padding-left: 0.6em; margin-left: 2.4em;}
170 170 blockquote blockquote { margin-left: 0;}
171 171 textarea.wiki-edit { width: 99%; }
172 172 li p {margin-top: 0;}
173 173 div.issue {background:#ffffdd; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7;}
174 174 p.breadcrumb { font-size: 0.9em; margin: 4px 0 4px 0;}
175 175 p.subtitle { font-size: 0.9em; margin: -6px 0 12px 0; font-style: italic; }
176 176 p.footnote { font-size: 0.9em; margin-top: 0px; margin-bottom: 0px; }
177 177
178 178 fieldset#filters, fieldset#date-range { padding: 0.7em; margin-bottom: 8px; }
179 179 fieldset#filters p { margin: 1.2em 0 0.8em 2px; }
180 180 fieldset#filters table { border-collapse: collapse; }
181 181 fieldset#filters table td { padding: 0; vertical-align: middle; }
182 182 fieldset#filters tr.filter { height: 2em; }
183 183 fieldset#filters td.add-filter { text-align: right; vertical-align: top; }
184 184 .buttons { font-size: 0.9em; }
185 185
186 186 div#issue-changesets {float:right; width:45%; margin-left: 1em; margin-bottom: 1em; background: #fff; padding-left: 1em; font-size: 90%;}
187 187 div#issue-changesets .changeset { padding: 4px;}
188 188 div#issue-changesets .changeset { border-bottom: 1px solid #ddd; }
189 189 div#issue-changesets p { margin-top: 0; margin-bottom: 1em;}
190 190
191 191 div#activity dl, #search-results { margin-left: 2em; }
192 192 div#activity dd, #search-results dd { margin-bottom: 1em; padding-left: 18px; font-size: 0.9em; }
193 193 div#activity dt, #search-results dt { margin-bottom: 0px; padding-left: 20px; line-height: 18px; background-position: 0 50%; background-repeat: no-repeat; }
194 194 div#activity dt.me .time { border-bottom: 1px solid #999; }
195 195 div#activity dt .time { color: #777; font-size: 80%; }
196 196 div#activity dd .description, #search-results dd .description { font-style: italic; }
197 197 div#activity span.project:after, #search-results span.project:after { content: " -"; }
198 198 div#activity dd span.description, #search-results dd span.description { display:block; }
199 199
200 200 #search-results dd { margin-bottom: 1em; padding-left: 20px; margin-left:0px; }
201 201
202 202 div#search-results-counts {float:right;}
203 203 div#search-results-counts ul { margin-top: 0.5em; }
204 204 div#search-results-counts li { list-style-type:none; float: left; margin-left: 1em; }
205 205
206 206 dt.issue { background-image: url(../images/ticket.png); }
207 207 dt.issue-edit { background-image: url(../images/ticket_edit.png); }
208 208 dt.issue-closed { background-image: url(../images/ticket_checked.png); }
209 209 dt.issue-note { background-image: url(../images/ticket_note.png); }
210 210 dt.changeset { background-image: url(../images/changeset.png); }
211 211 dt.news { background-image: url(../images/news.png); }
212 212 dt.message { background-image: url(../images/message.png); }
213 213 dt.reply { background-image: url(../images/comments.png); }
214 214 dt.wiki-page { background-image: url(../images/wiki_edit.png); }
215 215 dt.attachment { background-image: url(../images/attachment.png); }
216 216 dt.document { background-image: url(../images/document.png); }
217 217 dt.project { background-image: url(../images/projects.png); }
218 218
219 219 #search-results dt.issue.closed { background-image: url(../images/ticket_checked.png); }
220 220
221 221 div#roadmap fieldset.related-issues { margin-bottom: 1em; }
222 222 div#roadmap fieldset.related-issues ul { margin-top: 0.3em; margin-bottom: 0.3em; }
223 223 div#roadmap .wiki h1:first-child { display: none; }
224 224 div#roadmap .wiki h1 { font-size: 120%; }
225 225 div#roadmap .wiki h2 { font-size: 110%; }
226 226
227 227 div#version-summary { float:right; width:380px; margin-left: 16px; margin-bottom: 16px; background-color: #fff; }
228 228 div#version-summary fieldset { margin-bottom: 1em; }
229 229 div#version-summary .total-hours { text-align: right; }
230 230
231 231 table#time-report td.hours, table#time-report th.period, table#time-report th.total { text-align: right; padding-right: 0.5em; }
232 232 table#time-report tbody tr { font-style: italic; color: #777; }
233 233 table#time-report tbody tr.last-level { font-style: normal; color: #555; }
234 234 table#time-report tbody tr.total { font-style: normal; font-weight: bold; color: #555; background-color:#EEEEEE; }
235 235 table#time-report .hours-dec { font-size: 0.9em; }
236 236
237 237 form#issue-form .attributes { margin-bottom: 8px; }
238 238 form#issue-form .attributes p { padding-top: 1px; padding-bottom: 2px; }
239 239 form#issue-form .attributes select { min-width: 30%; }
240 240
241 241 ul.projects { margin: 0; padding-left: 1em; }
242 242 ul.projects.root { margin: 0; padding: 0; }
243 243 ul.projects ul { border-left: 3px solid #e0e0e0; }
244 244 ul.projects li { list-style-type:none; }
245 245 ul.projects li.root { margin-bottom: 1em; }
246 246 ul.projects li.child { margin-top: 1em;}
247 247 ul.projects div.root a.project { font-family: "Trebuchet MS", Verdana, sans-serif; font-weight: bold; font-size: 16px; margin: 0 0 10px 0; }
248 248 .my-project { padding-left: 18px; background: url(../images/fav.png) no-repeat 0 50%; }
249 249
250 250 ul.properties {padding:0; font-size: 0.9em; color: #777;}
251 251 ul.properties li {list-style-type:none;}
252 252 ul.properties li span {font-style:italic;}
253 253
254 254 .total-hours { font-size: 110%; font-weight: bold; }
255 255 .total-hours span.hours-int { font-size: 120%; }
256 256
257 257 .autoscroll {overflow-x: auto; padding:1px; margin-bottom: 1.2em;}
258 258 #user_firstname, #user_lastname, #user_mail, #my_account_form select { width: 90%; }
259 259
260 260 .pagination {font-size: 90%}
261 261 p.pagination {margin-top:8px;}
262 262
263 263 /***** Tabular forms ******/
264 264 .tabular p{
265 265 margin: 0;
266 266 padding: 5px 0 8px 0;
267 267 padding-left: 180px; /*width of left column containing the label elements*/
268 268 height: 1%;
269 269 clear:left;
270 270 }
271 271
272 272 html>body .tabular p {overflow:hidden;}
273 273
274 274 .tabular label{
275 275 font-weight: bold;
276 276 float: left;
277 277 text-align: right;
278 278 margin-left: -180px; /*width of left column*/
279 279 width: 175px; /*width of labels. Should be smaller than left column to create some right
280 280 margin*/
281 281 }
282 282
283 283 .tabular label.floating{
284 284 font-weight: normal;
285 285 margin-left: 0px;
286 286 text-align: left;
287 287 width: 270px;
288 288 }
289 289
290 290 input#time_entry_comments { width: 90%;}
291 291
292 292 #preview fieldset {margin-top: 1em; background: url(../images/draft.png)}
293 293
294 294 .tabular.settings p{ padding-left: 300px; }
295 295 .tabular.settings label{ margin-left: -300px; width: 295px; }
296 296
297 297 .required {color: #bb0000;}
298 298 .summary {font-style: italic;}
299 299
300 300 #attachments_fields input[type=text] {margin-left: 8px; }
301 301
302 302 div.attachments { margin-top: 12px; }
303 303 div.attachments p { margin:4px 0 2px 0; }
304 304 div.attachments img { vertical-align: middle; }
305 305 div.attachments span.author { font-size: 0.9em; color: #888; }
306 306
307 307 p.other-formats { text-align: right; font-size:0.9em; color: #666; }
308 308 .other-formats span + span:before { content: "| "; }
309 309
310 a.feed { background: url(../images/feed.png) no-repeat 1px 50%; padding: 2px 0px 3px 16px; }
310 a.atom { background: url(../images/feed.png) no-repeat 1px 50%; padding: 2px 0px 3px 16px; }
311 311
312 312 /***** Flash & error messages ****/
313 313 #errorExplanation, div.flash, .nodata, .warning {
314 314 padding: 4px 4px 4px 30px;
315 315 margin-bottom: 12px;
316 316 font-size: 1.1em;
317 317 border: 2px solid;
318 318 }
319 319
320 320 div.flash {margin-top: 8px;}
321 321
322 322 div.flash.error, #errorExplanation {
323 323 background: url(../images/false.png) 8px 5px no-repeat;
324 324 background-color: #ffe3e3;
325 325 border-color: #dd0000;
326 326 color: #550000;
327 327 }
328 328
329 329 div.flash.notice {
330 330 background: url(../images/true.png) 8px 5px no-repeat;
331 331 background-color: #dfffdf;
332 332 border-color: #9fcf9f;
333 333 color: #005f00;
334 334 }
335 335
336 336 div.flash.warning {
337 337 background: url(../images/warning.png) 8px 5px no-repeat;
338 338 background-color: #FFEBC1;
339 339 border-color: #FDBF3B;
340 340 color: #A6750C;
341 341 text-align: left;
342 342 }
343 343
344 344 .nodata, .warning {
345 345 text-align: center;
346 346 background-color: #FFEBC1;
347 347 border-color: #FDBF3B;
348 348 color: #A6750C;
349 349 }
350 350
351 351 #errorExplanation ul { font-size: 0.9em;}
352 352
353 353 /***** Ajax indicator ******/
354 354 #ajax-indicator {
355 355 position: absolute; /* fixed not supported by IE */
356 356 background-color:#eee;
357 357 border: 1px solid #bbb;
358 358 top:35%;
359 359 left:40%;
360 360 width:20%;
361 361 font-weight:bold;
362 362 text-align:center;
363 363 padding:0.6em;
364 364 z-index:100;
365 365 filter:alpha(opacity=50);
366 366 opacity: 0.5;
367 367 }
368 368
369 369 html>body #ajax-indicator { position: fixed; }
370 370
371 371 #ajax-indicator span {
372 372 background-position: 0% 40%;
373 373 background-repeat: no-repeat;
374 374 background-image: url(../images/loading.gif);
375 375 padding-left: 26px;
376 376 vertical-align: bottom;
377 377 }
378 378
379 379 /***** Calendar *****/
380 380 table.cal {border-collapse: collapse; width: 100%; margin: 0px 0 6px 0;border: 1px solid #d7d7d7;}
381 381 table.cal thead th {width: 14%;}
382 382 table.cal tbody tr {height: 100px;}
383 383 table.cal th { background-color:#EEEEEE; padding: 4px; }
384 384 table.cal td {border: 1px solid #d7d7d7; vertical-align: top; font-size: 0.9em;}
385 385 table.cal td p.day-num {font-size: 1.1em; text-align:right;}
386 386 table.cal td.odd p.day-num {color: #bbb;}
387 387 table.cal td.today {background:#ffffdd;}
388 388 table.cal td.today p.day-num {font-weight: bold;}
389 389
390 390 /***** Tooltips ******/
391 391 .tooltip{position:relative;z-index:24;}
392 392 .tooltip:hover{z-index:25;color:#000;}
393 393 .tooltip span.tip{display: none; text-align:left;}
394 394
395 395 div.tooltip:hover span.tip{
396 396 display:block;
397 397 position:absolute;
398 398 top:12px; left:24px; width:270px;
399 399 border:1px solid #555;
400 400 background-color:#fff;
401 401 padding: 4px;
402 402 font-size: 0.8em;
403 403 color:#505050;
404 404 }
405 405
406 406 /***** Progress bar *****/
407 407 table.progress {
408 408 border: 1px solid #D7D7D7;
409 409 border-collapse: collapse;
410 410 border-spacing: 0pt;
411 411 empty-cells: show;
412 412 text-align: center;
413 413 float:left;
414 414 margin: 1px 6px 1px 0px;
415 415 }
416 416
417 417 table.progress td { height: 0.9em; }
418 418 table.progress td.closed { background: #BAE0BA none repeat scroll 0%; }
419 419 table.progress td.done { background: #DEF0DE none repeat scroll 0%; }
420 420 table.progress td.open { background: #FFF none repeat scroll 0%; }
421 421 p.pourcent {font-size: 80%;}
422 422 p.progress-info {clear: left; font-style: italic; font-size: 80%;}
423 423
424 424 /***** Tabs *****/
425 425 #content .tabs {height: 2.6em; border-bottom: 1px solid #bbbbbb; margin-bottom:1.2em; position:relative;}
426 426 #content .tabs ul {margin:0; position:absolute; bottom:-2px; padding-left:1em;}
427 427 #content .tabs>ul { bottom:-1px; } /* others */
428 428 #content .tabs ul li {
429 429 float:left;
430 430 list-style-type:none;
431 431 white-space:nowrap;
432 432 margin-right:8px;
433 433 background:#fff;
434 434 }
435 435 #content .tabs ul li a{
436 436 display:block;
437 437 font-size: 0.9em;
438 438 text-decoration:none;
439 439 line-height:1.3em;
440 440 padding:4px 6px 4px 6px;
441 441 border: 1px solid #ccc;
442 442 border-bottom: 1px solid #bbbbbb;
443 443 background-color: #eeeeee;
444 444 color:#777;
445 445 font-weight:bold;
446 446 }
447 447
448 448 #content .tabs ul li a:hover {
449 449 background-color: #ffffdd;
450 450 text-decoration:none;
451 451 }
452 452
453 453 #content .tabs ul li a.selected {
454 454 background-color: #fff;
455 455 border: 1px solid #bbbbbb;
456 456 border-bottom: 1px solid #fff;
457 457 }
458 458
459 459 #content .tabs ul li a.selected:hover {
460 460 background-color: #fff;
461 461 }
462 462
463 463 /***** Diff *****/
464 464 .diff_out { background: #fcc; }
465 465 .diff_in { background: #cfc; }
466 466
467 467 /***** Wiki *****/
468 468 div.wiki table {
469 469 border: 1px solid #505050;
470 470 border-collapse: collapse;
471 471 margin-bottom: 1em;
472 472 }
473 473
474 474 div.wiki table, div.wiki td, div.wiki th {
475 475 border: 1px solid #bbb;
476 476 padding: 4px;
477 477 }
478 478
479 479 div.wiki .external {
480 480 background-position: 0% 60%;
481 481 background-repeat: no-repeat;
482 482 padding-left: 12px;
483 483 background-image: url(../images/external.png);
484 484 }
485 485
486 486 div.wiki a.new {
487 487 color: #b73535;
488 488 }
489 489
490 490 div.wiki pre {
491 491 margin: 1em 1em 1em 1.6em;
492 492 padding: 2px;
493 493 background-color: #fafafa;
494 494 border: 1px solid #dadada;
495 495 width:95%;
496 496 overflow-x: auto;
497 497 }
498 498
499 499 div.wiki ul.toc {
500 500 background-color: #ffffdd;
501 501 border: 1px solid #e4e4e4;
502 502 padding: 4px;
503 503 line-height: 1.2em;
504 504 margin-bottom: 12px;
505 505 margin-right: 12px;
506 506 margin-left: 0;
507 507 display: table
508 508 }
509 509 * html div.wiki ul.toc { width: 50%; } /* IE6 doesn't autosize div */
510 510
511 511 div.wiki ul.toc.right { float: right; margin-left: 12px; margin-right: 0; width: auto; }
512 512 div.wiki ul.toc.left { float: left; margin-right: 12px; margin-left: 0; width: auto; }
513 513 div.wiki ul.toc li { list-style-type:none;}
514 514 div.wiki ul.toc li.heading2 { margin-left: 6px; }
515 515 div.wiki ul.toc li.heading3 { margin-left: 12px; font-size: 0.8em; }
516 516
517 517 div.wiki ul.toc a {
518 518 font-size: 0.9em;
519 519 font-weight: normal;
520 520 text-decoration: none;
521 521 color: #606060;
522 522 }
523 523 div.wiki ul.toc a:hover { color: #c61a1a; text-decoration: underline;}
524 524
525 525 a.wiki-anchor { display: none; margin-left: 6px; text-decoration: none; }
526 526 a.wiki-anchor:hover { color: #aaa !important; text-decoration: none; }
527 527 h1:hover a.wiki-anchor, h2:hover a.wiki-anchor, h3:hover a.wiki-anchor { display: inline; color: #ddd; }
528 528
529 529 /***** My page layout *****/
530 530 .block-receiver {
531 531 border:1px dashed #c0c0c0;
532 532 margin-bottom: 20px;
533 533 padding: 15px 0 15px 0;
534 534 }
535 535
536 536 .mypage-box {
537 537 margin:0 0 20px 0;
538 538 color:#505050;
539 539 line-height:1.5em;
540 540 }
541 541
542 542 .handle {
543 543 cursor: move;
544 544 }
545 545
546 546 a.close-icon {
547 547 display:block;
548 548 margin-top:3px;
549 549 overflow:hidden;
550 550 width:12px;
551 551 height:12px;
552 552 background-repeat: no-repeat;
553 553 cursor:pointer;
554 554 background-image:url('../images/close.png');
555 555 }
556 556
557 557 a.close-icon:hover {
558 558 background-image:url('../images/close_hl.png');
559 559 }
560 560
561 561 /***** Gantt chart *****/
562 562 .gantt_hdr {
563 563 position:absolute;
564 564 top:0;
565 565 height:16px;
566 566 border-top: 1px solid #c0c0c0;
567 567 border-bottom: 1px solid #c0c0c0;
568 568 border-right: 1px solid #c0c0c0;
569 569 text-align: center;
570 570 overflow: hidden;
571 571 }
572 572
573 573 .task {
574 574 position: absolute;
575 575 height:8px;
576 576 font-size:0.8em;
577 577 color:#888;
578 578 padding:0;
579 579 margin:0;
580 580 line-height:0.8em;
581 581 }
582 582
583 583 .task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; }
584 584 .task_done { background:#66f url(../images/task_done.png); border: 1px solid #66f; }
585 585 .task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; }
586 586 .milestone { background-image:url(../images/milestone.png); background-repeat: no-repeat; border: 0; }
587 587
588 588 /***** Icons *****/
589 589 .icon {
590 590 background-position: 0% 40%;
591 591 background-repeat: no-repeat;
592 592 padding-left: 20px;
593 593 padding-top: 2px;
594 594 padding-bottom: 3px;
595 595 }
596 596
597 597 .icon22 {
598 598 background-position: 0% 40%;
599 599 background-repeat: no-repeat;
600 600 padding-left: 26px;
601 601 line-height: 22px;
602 602 vertical-align: middle;
603 603 }
604 604
605 605 .icon-add { background-image: url(../images/add.png); }
606 606 .icon-edit { background-image: url(../images/edit.png); }
607 607 .icon-copy { background-image: url(../images/copy.png); }
608 608 .icon-del { background-image: url(../images/delete.png); }
609 609 .icon-move { background-image: url(../images/move.png); }
610 610 .icon-save { background-image: url(../images/save.png); }
611 611 .icon-cancel { background-image: url(../images/cancel.png); }
612 612 .icon-file { background-image: url(../images/file.png); }
613 613 .icon-folder { background-image: url(../images/folder.png); }
614 614 .open .icon-folder { background-image: url(../images/folder_open.png); }
615 615 .icon-package { background-image: url(../images/package.png); }
616 616 .icon-home { background-image: url(../images/home.png); }
617 617 .icon-user { background-image: url(../images/user.png); }
618 618 .icon-mypage { background-image: url(../images/user_page.png); }
619 619 .icon-admin { background-image: url(../images/admin.png); }
620 620 .icon-projects { background-image: url(../images/projects.png); }
621 621 .icon-help { background-image: url(../images/help.png); }
622 622 .icon-attachment { background-image: url(../images/attachment.png); }
623 623 .icon-index { background-image: url(../images/index.png); }
624 624 .icon-history { background-image: url(../images/history.png); }
625 625 .icon-time { background-image: url(../images/time.png); }
626 626 .icon-stats { background-image: url(../images/stats.png); }
627 627 .icon-warning { background-image: url(../images/warning.png); }
628 628 .icon-fav { background-image: url(../images/fav.png); }
629 629 .icon-fav-off { background-image: url(../images/fav_off.png); }
630 630 .icon-reload { background-image: url(../images/reload.png); }
631 631 .icon-lock { background-image: url(../images/locked.png); }
632 632 .icon-unlock { background-image: url(../images/unlock.png); }
633 633 .icon-checked { background-image: url(../images/true.png); }
634 634 .icon-details { background-image: url(../images/zoom_in.png); }
635 635 .icon-report { background-image: url(../images/report.png); }
636 636 .icon-comment { background-image: url(../images/comment.png); }
637 637
638 638 .icon22-projects { background-image: url(../images/22x22/projects.png); }
639 639 .icon22-users { background-image: url(../images/22x22/users.png); }
640 640 .icon22-tracker { background-image: url(../images/22x22/tracker.png); }
641 641 .icon22-role { background-image: url(../images/22x22/role.png); }
642 642 .icon22-workflow { background-image: url(../images/22x22/workflow.png); }
643 643 .icon22-options { background-image: url(../images/22x22/options.png); }
644 644 .icon22-notifications { background-image: url(../images/22x22/notifications.png); }
645 645 .icon22-authent { background-image: url(../images/22x22/authent.png); }
646 646 .icon22-info { background-image: url(../images/22x22/info.png); }
647 647 .icon22-comment { background-image: url(../images/22x22/comment.png); }
648 648 .icon22-package { background-image: url(../images/22x22/package.png); }
649 649 .icon22-settings { background-image: url(../images/22x22/settings.png); }
650 650 .icon22-plugin { background-image: url(../images/22x22/plugin.png); }
651 651
652 652 img.gravatar {
653 653 padding: 2px;
654 654 border: solid 1px #d5d5d5;
655 655 background: #fff;
656 656 }
657 657
658 658 div.issue img.gravatar {
659 659 float: right;
660 660 margin: 0 0 0 1em;
661 661 padding: 5px;
662 662 }
663 663
664 664 div.issue table img.gravatar {
665 665 height: 14px;
666 666 width: 14px;
667 667 padding: 2px;
668 668 float: left;
669 669 margin: 0 0.5em 0 0;
670 670 }
671 671
672 672 #history img.gravatar {
673 673 padding: 3px;
674 674 margin: 0 1.5em 1em 0;
675 675 float: left;
676 676 }
677 677
678 678 td.username img.gravatar {
679 679 float: left;
680 680 margin: 0 1em 0 0;
681 681 }
682 682
683 683 #activity dt img.gravatar {
684 684 float: left;
685 685 margin: 0 1em 1em 0;
686 686 }
687 687
688 688 #activity dt,
689 689 .journal {
690 690 clear: left;
691 691 }
692 692
693 693 h2 img { vertical-align:middle; }
694 694
695 695
696 696 /***** Media print specific styles *****/
697 697 @media print {
698 698 #top-menu, #header, #main-menu, #sidebar, #footer, .contextual, .other-formats { display:none; }
699 699 #main { background: #fff; }
700 700 #content { width: 99%; margin: 0; padding: 0; border: 0; background: #fff; overflow: visible !important;}
701 701 }
General Comments 0
You need to be logged in to leave comments. Login now