##// END OF EJS Templates
tooltips added on Gantt chart to view the details of the issues...
Jean-Philippe Lang -
r157:f35194e6046e
parent child
Show More
@@ -0,0 +1,120
1 <attach event="ondocumentready" handler="parseStylesheets" />
2 <script>
3 /**
4 * Whatever:hover - V1.42.060206 - hover & active
5 * ------------------------------------------------------------
6 * (c) 2005 - Peter Nederlof
7 * Peterned - http://www.xs4all.nl/~peterned/
8 * License - http://creativecommons.org/licenses/LGPL/2.1/
9 *
10 * Whatever:hover is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * Whatever:hover is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * Credits and thanks to:
21 * Arnoud Berendsen, Martin Reurings, Robert Hanson
22 *
23 * howto: body { behavior:url("csshover.htc"); }
24 * ------------------------------------------------------------
25 */
26
27 var csshoverReg = /(^|\s)(([^a]([^ ]+)?)|(a([^#.][^ ]+)+)):(hover|active)/i,
28 currentSheet, doc = window.document, hoverEvents = [], activators = {
29 onhover:{on:'onmouseover', off:'onmouseout'},
30 onactive:{on:'onmousedown', off:'onmouseup'}
31 }
32
33 function parseStylesheets() {
34 if(!/MSIE (5|6)/.test(navigator.userAgent)) return;
35 window.attachEvent('onunload', unhookHoverEvents);
36 var sheets = doc.styleSheets, l = sheets.length;
37 for(var i=0; i<l; i++)
38 parseStylesheet(sheets[i]);
39 }
40 function parseStylesheet(sheet) {
41 if(sheet.imports) {
42 try {
43 var imports = sheet.imports, l = imports.length;
44 for(var i=0; i<l; i++) parseStylesheet(sheet.imports[i]);
45 } catch(securityException){}
46 }
47
48 try {
49 var rules = (currentSheet = sheet).rules, l = rules.length;
50 for(var j=0; j<l; j++) parseCSSRule(rules[j]);
51 } catch(securityException){}
52 }
53
54 function parseCSSRule(rule) {
55 var select = rule.selectorText, style = rule.style.cssText;
56 if(!csshoverReg.test(select) || !style) return;
57
58 var pseudo = select.replace(/[^:]+:([a-z-]+).*/i, 'on$1');
59 var newSelect = select.replace(/(\.([a-z0-9_-]+):[a-z]+)|(:[a-z]+)/gi, '.$2' + pseudo);
60 var className = (/\.([a-z0-9_-]*on(hover|active))/i).exec(newSelect)[1];
61 var affected = select.replace(/:(hover|active).*$/, '');
62 var elements = getElementsBySelect(affected);
63 if(elements.length == 0) return;
64
65 currentSheet.addRule(newSelect, style);
66 for(var i=0; i<elements.length; i++)
67 new HoverElement(elements[i], className, activators[pseudo]);
68 }
69
70 function HoverElement(node, className, events) {
71 if(!node.hovers) node.hovers = {};
72 if(node.hovers[className]) return;
73 node.hovers[className] = true;
74 hookHoverEvent(node, events.on, function() { node.className += ' ' + className; });
75 hookHoverEvent(node, events.off, function() { node.className = node.className.replace(new RegExp('\\s+'+className, 'g'),''); });
76 }
77 function hookHoverEvent(node, type, handler) {
78 node.attachEvent(type, handler);
79 hoverEvents[hoverEvents.length] = {
80 node:node, type:type, handler:handler
81 };
82 }
83
84 function unhookHoverEvents() {
85 for(var e,i=0; i<hoverEvents.length; i++) {
86 e = hoverEvents[i];
87 e.node.detachEvent(e.type, e.handler);
88 }
89 }
90
91 function getElementsBySelect(rule) {
92 var parts, nodes = [doc];
93 parts = rule.split(' ');
94 for(var i=0; i<parts.length; i++) {
95 nodes = getSelectedNodes(parts[i], nodes);
96 } return nodes;
97 }
98 function getSelectedNodes(select, elements) {
99 var result, node, nodes = [];
100 var identify = (/\#([a-z0-9_-]+)/i).exec(select);
101 if(identify) {
102 var element = doc.getElementById(identify[1]);
103 return element? [element]:nodes;
104 }
105
106 var classname = (/\.([a-z0-9_-]+)/i).exec(select);
107 var tagName = select.replace(/(\.|\#|\:)[a-z0-9_-]+/i, '');
108 var classReg = classname? new RegExp('\\b' + classname[1] + '\\b'):false;
109 for(var i=0; i<elements.length; i++) {
110 result = tagName? elements[i].all.tags(tagName):elements[i].all;
111 for(var j=0; j<result.length; j++) {
112 node = result[j];
113 if(classReg && !classReg.test(node.className)) continue;
114 nodes[nodes.length] = node;
115 }
116 }
117
118 return nodes;
119 }
120 </script> No newline at end of file
@@ -1,534 +1,534
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 class ProjectsController < ApplicationController
19 19 layout 'base'
20 20 before_filter :find_project, :authorize, :except => [ :index, :list, :add ]
21 21 before_filter :require_admin, :only => [ :add, :destroy ]
22 22
23 23 helper :sort
24 24 include SortHelper
25 25 helper :custom_fields
26 26 include CustomFieldsHelper
27 27 helper :ifpdf
28 28 include IfpdfHelper
29 29 helper IssuesHelper
30 30 helper :queries
31 31 include QueriesHelper
32 32
33 33 def index
34 34 list
35 35 render :action => 'list' unless request.xhr?
36 36 end
37 37
38 38 # Lists public projects
39 39 def list
40 40 sort_init 'name', 'asc'
41 41 sort_update
42 42 @project_count = Project.count(["is_public=?", true])
43 43 @project_pages = Paginator.new self, @project_count,
44 44 15,
45 45 params['page']
46 46 @projects = Project.find :all, :order => sort_clause,
47 47 :conditions => ["is_public=?", true],
48 48 :limit => @project_pages.items_per_page,
49 49 :offset => @project_pages.current.offset
50 50
51 51 render :action => "list", :layout => false if request.xhr?
52 52 end
53 53
54 54 # Add a new project
55 55 def add
56 56 @custom_fields = IssueCustomField.find(:all)
57 57 @root_projects = Project.find(:all, :conditions => "parent_id is null")
58 58 @project = Project.new(params[:project])
59 59 if request.get?
60 60 @custom_values = ProjectCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @project) }
61 61 else
62 62 @project.custom_fields = CustomField.find(params[:custom_field_ids]) if params[:custom_field_ids]
63 63 @custom_values = ProjectCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @project, :value => params["custom_fields"][x.id.to_s]) }
64 64 @project.custom_values = @custom_values
65 65 if params[:repository_enabled] && params[:repository_enabled] == "1"
66 66 @project.repository = Repository.new
67 67 @project.repository.attributes = params[:repository]
68 68 end
69 69 if @project.save
70 70 flash[:notice] = l(:notice_successful_create)
71 71 redirect_to :controller => 'admin', :action => 'projects'
72 72 end
73 73 end
74 74 end
75 75
76 76 # Show @project
77 77 def show
78 78 @custom_values = @project.custom_values.find(:all, :include => :custom_field)
79 79 @members = @project.members.find(:all, :include => [:user, :role])
80 80 @subprojects = @project.children if @project.children_count > 0
81 81 @news = @project.news.find(:all, :limit => 5, :include => [ :author, :project ], :order => "news.created_on DESC")
82 82 @trackers = Tracker.find(:all)
83 83 @open_issues_by_tracker = Issue.count(:group => :tracker, :joins => "INNER JOIN issue_statuses ON issue_statuses.id = issues.status_id", :conditions => ["project_id=? and issue_statuses.is_closed=?", @project.id, false])
84 84 @total_issues_by_tracker = Issue.count(:group => :tracker, :conditions => ["project_id=?", @project.id])
85 85 end
86 86
87 87 def settings
88 88 @root_projects = Project::find(:all, :conditions => ["parent_id is null and id <> ?", @project.id])
89 89 @custom_fields = IssueCustomField.find(:all)
90 90 @issue_category ||= IssueCategory.new
91 91 @member ||= @project.members.new
92 92 @roles = Role.find(:all)
93 93 @users = User.find(:all) - @project.members.find(:all, :include => :user).collect{|m| m.user }
94 94 @custom_values ||= ProjectCustomField.find(:all).collect { |x| @project.custom_values.find_by_custom_field_id(x.id) || CustomValue.new(:custom_field => x) }
95 95 end
96 96
97 97 # Edit @project
98 98 def edit
99 99 if request.post?
100 100 @project.custom_fields = IssueCustomField.find(params[:custom_field_ids]) if params[:custom_field_ids]
101 101 if params[:custom_fields]
102 102 @custom_values = ProjectCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @project, :value => params["custom_fields"][x.id.to_s]) }
103 103 @project.custom_values = @custom_values
104 104 end
105 105 if params[:repository_enabled]
106 106 case params[:repository_enabled]
107 107 when "0"
108 108 @project.repository = nil
109 109 when "1"
110 110 @project.repository ||= Repository.new
111 111 @project.repository.attributes = params[:repository]
112 112 end
113 113 end
114 114 @project.attributes = params[:project]
115 115 if @project.save
116 116 flash[:notice] = l(:notice_successful_update)
117 117 redirect_to :action => 'settings', :id => @project
118 118 else
119 119 settings
120 120 render :action => 'settings'
121 121 end
122 122 end
123 123 end
124 124
125 125 # Delete @project
126 126 def destroy
127 127 if request.post? and params[:confirm]
128 128 @project.destroy
129 129 redirect_to :controller => 'admin', :action => 'projects'
130 130 end
131 131 end
132 132
133 133 # Add a new issue category to @project
134 134 def add_issue_category
135 135 if request.post?
136 136 @issue_category = @project.issue_categories.build(params[:issue_category])
137 137 if @issue_category.save
138 138 flash[:notice] = l(:notice_successful_create)
139 139 redirect_to :action => 'settings', :id => @project
140 140 else
141 141 settings
142 142 render :action => 'settings'
143 143 end
144 144 end
145 145 end
146 146
147 147 # Add a new version to @project
148 148 def add_version
149 149 @version = @project.versions.build(params[:version])
150 150 if request.post? and @version.save
151 151 flash[:notice] = l(:notice_successful_create)
152 152 redirect_to :action => 'settings', :id => @project
153 153 end
154 154 end
155 155
156 156 # Add a new member to @project
157 157 def add_member
158 158 @member = @project.members.build(params[:member])
159 159 if request.post?
160 160 if @member.save
161 161 flash[:notice] = l(:notice_successful_create)
162 162 redirect_to :action => 'settings', :id => @project
163 163 else
164 164 settings
165 165 render :action => 'settings'
166 166 end
167 167 end
168 168 end
169 169
170 170 # Show members list of @project
171 171 def list_members
172 172 @members = @project.members
173 173 end
174 174
175 175 # Add a new document to @project
176 176 def add_document
177 177 @categories = Enumeration::get_values('DCAT')
178 178 @document = @project.documents.build(params[:document])
179 179 if request.post? and @document.save
180 180 # Save the attachments
181 181 params[:attachments].each { |a|
182 182 Attachment.create(:container => @document, :file => a, :author => logged_in_user) unless a.size == 0
183 183 } if params[:attachments] and params[:attachments].is_a? Array
184 184 flash[:notice] = l(:notice_successful_create)
185 185 redirect_to :action => 'list_documents', :id => @project
186 186 end
187 187 end
188 188
189 189 # Show documents list of @project
190 190 def list_documents
191 191 @documents = @project.documents.find :all, :include => :category
192 192 end
193 193
194 194 # Add a new issue to @project
195 195 def add_issue
196 196 @tracker = Tracker.find(params[:tracker_id])
197 197 @priorities = Enumeration::get_values('IPRI')
198 198 @issue = Issue.new(:project => @project, :tracker => @tracker)
199 199 if request.get?
200 200 @issue.start_date = Date.today
201 201 @custom_values = @project.custom_fields_for_issues(@tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue) }
202 202 else
203 203 @issue.attributes = params[:issue]
204 204 @issue.author_id = self.logged_in_user.id if self.logged_in_user
205 205 # Multiple file upload
206 206 @attachments = []
207 207 params[:attachments].each { |a|
208 208 @attachments << Attachment.new(:container => @issue, :file => a, :author => logged_in_user) unless a.size == 0
209 209 } if params[:attachments] and params[:attachments].is_a? Array
210 210 @custom_values = @project.custom_fields_for_issues(@tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue, :value => params["custom_fields"][x.id.to_s]) }
211 211 @issue.custom_values = @custom_values
212 212 if @issue.save
213 213 @attachments.each(&:save)
214 214 flash[:notice] = l(:notice_successful_create)
215 215 Mailer.deliver_issue_add(@issue) if Permission.find_by_controller_and_action(params[:controller], params[:action]).mail_enabled?
216 216 redirect_to :action => 'list_issues', :id => @project
217 217 end
218 218 end
219 219 end
220 220
221 221 # Show filtered/sorted issues list of @project
222 222 def list_issues
223 223 sort_init 'issues.id', 'desc'
224 224 sort_update
225 225
226 226 retrieve_query
227 227
228 228 @results_per_page_options = [ 15, 25, 50, 100 ]
229 229 if params[:per_page] and @results_per_page_options.include? params[:per_page].to_i
230 230 @results_per_page = params[:per_page].to_i
231 231 session[:results_per_page] = @results_per_page
232 232 else
233 233 @results_per_page = session[:results_per_page] || 25
234 234 end
235 235
236 236 if @query.valid?
237 237 @issue_count = Issue.count(:include => [:status, :project], :conditions => @query.statement)
238 238 @issue_pages = Paginator.new self, @issue_count, @results_per_page, params['page']
239 239 @issues = Issue.find :all, :order => sort_clause,
240 240 :include => [ :author, :status, :tracker, :project ],
241 241 :conditions => @query.statement,
242 242 :limit => @issue_pages.items_per_page,
243 243 :offset => @issue_pages.current.offset
244 244 end
245 245 @trackers = Tracker.find :all
246 246 render :layout => false if request.xhr?
247 247 end
248 248
249 249 # Export filtered/sorted issues list to CSV
250 250 def export_issues_csv
251 251 sort_init 'issues.id', 'desc'
252 252 sort_update
253 253
254 254 retrieve_query
255 255 render :action => 'list_issues' and return unless @query.valid?
256 256
257 257 @issues = Issue.find :all, :order => sort_clause,
258 258 :include => [ :author, :status, :tracker, :project, :custom_values ],
259 259 :conditions => @query.statement
260 260
261 261 ic = Iconv.new('ISO-8859-1', 'UTF-8')
262 262 export = StringIO.new
263 263 CSV::Writer.generate(export, l(:general_csv_separator)) do |csv|
264 264 # csv header fields
265 265 headers = [ "#", l(:field_status), l(:field_tracker), l(:field_subject), l(:field_author), l(:field_created_on), l(:field_updated_on) ]
266 266 for custom_field in @project.all_custom_fields
267 267 headers << custom_field.name
268 268 end
269 269 csv << headers.collect {|c| ic.iconv(c) }
270 270 # csv lines
271 271 @issues.each do |issue|
272 272 fields = [issue.id, issue.status.name, issue.tracker.name, issue.subject, issue.author.display_name, l_datetime(issue.created_on), l_datetime(issue.updated_on)]
273 273 for custom_field in @project.all_custom_fields
274 274 fields << (show_value issue.custom_value_for(custom_field))
275 275 end
276 276 csv << fields.collect {|c| ic.iconv(c.to_s) }
277 277 end
278 278 end
279 279 export.rewind
280 280 send_data(export.read, :type => 'text/csv; header=present', :filename => 'export.csv')
281 281 end
282 282
283 283 # Export filtered/sorted issues to PDF
284 284 def export_issues_pdf
285 285 sort_init 'issues.id', 'desc'
286 286 sort_update
287 287
288 288 retrieve_query
289 289 render :action => 'list_issues' and return unless @query.valid?
290 290
291 291 @issues = Issue.find :all, :order => sort_clause,
292 292 :include => [ :author, :status, :tracker, :project, :custom_values ],
293 293 :conditions => @query.statement
294 294
295 295 @options_for_rfpdf ||= {}
296 296 @options_for_rfpdf[:file_name] = "export.pdf"
297 297 render :layout => false
298 298 end
299 299
300 300 def move_issues
301 301 @issues = @project.issues.find(params[:issue_ids]) if params[:issue_ids]
302 302 redirect_to :action => 'list_issues', :id => @project and return unless @issues
303 303 @projects = []
304 304 # find projects to which the user is allowed to move the issue
305 305 @logged_in_user.memberships.each {|m| @projects << m.project if Permission.allowed_to_role("projects/move_issues", m.role_id)}
306 306 # issue can be moved to any tracker
307 307 @trackers = Tracker.find(:all)
308 308 if request.post? and params[:new_project_id] and params[:new_tracker_id]
309 309 new_project = Project.find(params[:new_project_id])
310 310 new_tracker = Tracker.find(params[:new_tracker_id])
311 311 @issues.each { |i|
312 312 # project dependent properties
313 313 unless i.project_id == new_project.id
314 314 i.category = nil
315 315 i.fixed_version = nil
316 316 end
317 317 # move the issue
318 318 i.project = new_project
319 319 i.tracker = new_tracker
320 320 i.save
321 321 }
322 322 flash[:notice] = l(:notice_successful_update)
323 323 redirect_to :action => 'list_issues', :id => @project
324 324 end
325 325 end
326 326
327 327 def add_query
328 328 @query = Query.new(params[:query])
329 329 @query.project = @project
330 330 @query.user = logged_in_user
331 331
332 332 params[:fields].each do |field|
333 333 @query.add_filter(field, params[:operators][field], params[:values][field])
334 334 end if params[:fields]
335 335
336 336 if request.post? and @query.save
337 337 flash[:notice] = l(:notice_successful_create)
338 338 redirect_to :controller => 'reports', :action => 'issue_report', :id => @project
339 339 end
340 340 render :layout => false if request.xhr?
341 341 end
342 342
343 343 # Add a news to @project
344 344 def add_news
345 345 @news = News.new(:project => @project)
346 346 if request.post?
347 347 @news.attributes = params[:news]
348 348 @news.author_id = self.logged_in_user.id if self.logged_in_user
349 349 if @news.save
350 350 flash[:notice] = l(:notice_successful_create)
351 351 redirect_to :action => 'list_news', :id => @project
352 352 end
353 353 end
354 354 end
355 355
356 356 # Show news list of @project
357 357 def list_news
358 358 @news_pages, @news = paginate :news, :per_page => 10, :conditions => ["project_id=?", @project.id], :include => :author, :order => "news.created_on DESC"
359 359 render :action => "list_news", :layout => false if request.xhr?
360 360 end
361 361
362 362 def add_file
363 363 if request.post?
364 364 @version = @project.versions.find_by_id(params[:version_id])
365 365 # Save the attachments
366 366 params[:attachments].each { |a|
367 367 Attachment.create(:container => @version, :file => a, :author => logged_in_user) unless a.size == 0
368 368 } if params[:attachments] and params[:attachments].is_a? Array
369 369 redirect_to :controller => 'projects', :action => 'list_files', :id => @project
370 370 end
371 371 @versions = @project.versions
372 372 end
373 373
374 374 def list_files
375 375 @versions = @project.versions
376 376 end
377 377
378 378 # Show changelog for @project
379 379 def changelog
380 380 @trackers = Tracker.find(:all, :conditions => ["is_in_chlog=?", true])
381 381 if request.get?
382 382 @selected_tracker_ids = @trackers.collect {|t| t.id.to_s }
383 383 else
384 384 @selected_tracker_ids = params[:tracker_ids].collect { |id| id.to_i.to_s } if params[:tracker_ids] and params[:tracker_ids].is_a? Array
385 385 end
386 386 @selected_tracker_ids ||= []
387 387 @fixed_issues = @project.issues.find(:all,
388 388 :include => [ :fixed_version, :status, :tracker ],
389 389 :conditions => [ "issue_statuses.is_closed=? and issues.tracker_id in (#{@selected_tracker_ids.join(',')}) and issues.fixed_version_id is not null", true],
390 390 :order => "versions.effective_date DESC, issues.id DESC"
391 391 ) unless @selected_tracker_ids.empty?
392 392 @fixed_issues ||= []
393 393 end
394 394
395 395 def activity
396 396 if params[:year] and params[:year].to_i > 1900
397 397 @year = params[:year].to_i
398 398 if params[:month] and params[:month].to_i > 0 and params[:month].to_i < 13
399 399 @month = params[:month].to_i
400 400 end
401 401 end
402 402 @year ||= Date.today.year
403 403 @month ||= Date.today.month
404 404
405 405 @date_from = Date.civil(@year, @month, 1)
406 406 @date_to = (@date_from >> 1)-1
407 407
408 408 @events_by_day = {}
409 409
410 410 unless params[:show_issues] == "0"
411 411 @project.issues.find(:all, :include => [:author, :status], :conditions => ["issues.created_on>=? and issues.created_on<=?", @date_from, @date_to] ).each { |i|
412 412 @events_by_day[i.created_on.to_date] ||= []
413 413 @events_by_day[i.created_on.to_date] << i
414 414 }
415 415 @show_issues = 1
416 416 end
417 417
418 418 unless params[:show_news] == "0"
419 419 @project.news.find(:all, :conditions => ["news.created_on>=? and news.created_on<=?", @date_from, @date_to], :include => :author ).each { |i|
420 420 @events_by_day[i.created_on.to_date] ||= []
421 421 @events_by_day[i.created_on.to_date] << i
422 422 }
423 423 @show_news = 1
424 424 end
425 425
426 426 unless params[:show_files] == "0"
427 427 Attachment.find(:all, :select => "attachments.*", :joins => "LEFT JOIN versions ON versions.id = attachments.container_id", :conditions => ["attachments.container_type='Version' and versions.project_id=? and attachments.created_on>=? and attachments.created_on<=?", @project.id, @date_from, @date_to], :include => :author ).each { |i|
428 428 @events_by_day[i.created_on.to_date] ||= []
429 429 @events_by_day[i.created_on.to_date] << i
430 430 }
431 431 @show_files = 1
432 432 end
433 433
434 434 unless params[:show_documents] == "0"
435 435 @project.documents.find(:all, :conditions => ["documents.created_on>=? and documents.created_on<=?", @date_from, @date_to] ).each { |i|
436 436 @events_by_day[i.created_on.to_date] ||= []
437 437 @events_by_day[i.created_on.to_date] << i
438 438 }
439 439 Attachment.find(:all, :select => "attachments.*", :joins => "LEFT JOIN documents ON documents.id = attachments.container_id", :conditions => ["attachments.container_type='Document' and documents.project_id=? and attachments.created_on>=? and attachments.created_on<=?", @project.id, @date_from, @date_to], :include => :author ).each { |i|
440 440 @events_by_day[i.created_on.to_date] ||= []
441 441 @events_by_day[i.created_on.to_date] << i
442 442 }
443 443 @show_documents = 1
444 444 end
445 445
446 446 render :layout => false if request.xhr?
447 447 end
448 448
449 449 def calendar
450 450 if params[:year] and params[:year].to_i > 1900
451 451 @year = params[:year].to_i
452 452 if params[:month] and params[:month].to_i > 0 and params[:month].to_i < 13
453 453 @month = params[:month].to_i
454 454 end
455 455 end
456 456 @year ||= Date.today.year
457 457 @month ||= Date.today.month
458 458
459 459 @date_from = Date.civil(@year, @month, 1)
460 460 @date_to = (@date_from >> 1)-1
461 461 # start on monday
462 462 @date_from = @date_from - (@date_from.cwday-1)
463 463 # finish on sunday
464 464 @date_to = @date_to + (7-@date_to.cwday)
465 465
466 466 @issues = @project.issues.find(:all, :include => :tracker, :conditions => ["((start_date>=? and start_date<=?) or (due_date>=? and due_date<=?))", @date_from, @date_to, @date_from, @date_to])
467 467 render :layout => false if request.xhr?
468 468 end
469 469
470 470 def gantt
471 471 if params[:year] and params[:year].to_i >0
472 472 @year_from = params[:year].to_i
473 473 if params[:month] and params[:month].to_i >=1 and params[:month].to_i <= 12
474 474 @month_from = params[:month].to_i
475 475 else
476 476 @month_from = 1
477 477 end
478 478 else
479 479 @month_from ||= (Date.today << 1).month
480 480 @year_from ||= (Date.today << 1).year
481 481 end
482 482
483 483 @zoom = (params[:zoom].to_i > 0 and params[:zoom].to_i < 5) ? params[:zoom].to_i : 2
484 484 @months = (params[:months].to_i > 0 and params[:months].to_i < 25) ? params[:months].to_i : 6
485 485
486 486 @date_from = Date.civil(@year_from, @month_from, 1)
487 487 @date_to = (@date_from >> @months) - 1
488 @issues = @project.issues.find(:all, :order => "start_date, due_date", :conditions => ["(((start_date>=? and start_date<=?) or (due_date>=? and due_date<=?) or (start_date<? and due_date>?)) and start_date is not null and due_date is not null)", @date_from, @date_to, @date_from, @date_to, @date_from, @date_to])
488 @issues = @project.issues.find(:all, :order => "start_date, due_date", :include => [:tracker, :status, :author, :priority], :conditions => ["(((start_date>=? and start_date<=?) or (due_date>=? and due_date<=?) or (start_date<? and due_date>?)) and start_date is not null and due_date is not null)", @date_from, @date_to, @date_from, @date_to, @date_from, @date_to])
489 489
490 490 if params[:output]=='pdf'
491 491 @options_for_rfpdf ||= {}
492 492 @options_for_rfpdf[:file_name] = "gantt.pdf"
493 493 render :template => "projects/gantt.rfpdf", :layout => false
494 494 else
495 495 render :template => "projects/gantt.rhtml"
496 496 end
497 497 end
498 498
499 499 private
500 500 # Find project of id params[:id]
501 501 # if not found, redirect to project list
502 502 # Used as a before_filter
503 503 def find_project
504 504 @project = Project.find(params[:id])
505 505 @html_title = @project.name
506 506 rescue ActiveRecord::RecordNotFound
507 507 render_404
508 508 end
509 509
510 510 # Retrieve query from session or build a new query
511 511 def retrieve_query
512 512 if params[:query_id]
513 513 @query = @project.queries.find(params[:query_id])
514 514 else
515 515 if params[:set_filter] or !session[:query] or session[:query].project_id != @project.id
516 516 # Give it a name, required to be valid
517 517 @query = Query.new(:name => "_")
518 518 @query.project = @project
519 519 if params[:fields] and params[:fields].is_a? Array
520 520 params[:fields].each do |field|
521 521 @query.add_filter(field, params[:operators][field], params[:values][field])
522 522 end
523 523 else
524 524 @query.available_filters.keys.each do |field|
525 525 @query.add_short_filter(field, params[field]) if params[field]
526 526 end
527 527 end
528 528 session[:query] = @query
529 529 else
530 530 @query = session[:query]
531 531 end
532 532 end
533 533 end
534 534 end
@@ -1,140 +1,145
1 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
2 2 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
3 3 <head>
4 4 <title><%= $RDM_HEADER_TITLE + (@html_title ? ": #{@html_title}" : "") %></title>
5 5 <meta http-equiv="content-type" content="text/html; charset=utf-8" />
6 6 <meta name="description" content="redMine" />
7 7 <meta name="keywords" content="issue,bug,tracker" />
8 <!--[if IE]>
9 <style type="text/css">
10 body {behavior: url(<%= stylesheet_path "csshover.htc" %>);}
11 </style>
12 <![endif]-->
8 13 <%= stylesheet_link_tag "application" %>
9 14 <%= stylesheet_link_tag "print", :media => "print" %>
10 15 <%= javascript_include_tag :defaults %>
11 16 <%= javascript_include_tag 'menu' %>
12 17 <%= stylesheet_link_tag 'jstoolbar' %>
13 18 <!-- page specific tags --><%= yield :header_tags %>
14 19 </head>
15 20
16 21 <body>
17 22 <div id="container" >
18 23
19 24 <div id="header">
20 25 <div style="float: left;">
21 26 <h1><%= $RDM_HEADER_TITLE %></h1>
22 27 <h2><%= $RDM_HEADER_SUBTITLE %></h2>
23 28 </div>
24 29 <div style="float: right; padding-right: 1em; padding-top: 0.2em;">
25 30 <% if loggedin? %><small><%=l(:label_logged_as)%> <b><%= @logged_in_user.login %></b></small><% end %>
26 31 </div>
27 32 </div>
28 33
29 34 <div id="navigation">
30 35 <ul>
31 36 <li class="selected"><%= link_to l(:label_home), { :controller => '' }, :class => "icon icon-home" %></li>
32 37 <li><%= link_to l(:label_my_page), { :controller => 'my', :action => 'page'}, :class => "icon icon-mypage" %></li>
33 38 <li><%= link_to l(:label_project_plural), { :controller => 'projects' }, :class => "icon icon-projects" %></li>
34 39
35 40 <% unless @project.nil? || @project.id.nil? %>
36 41 <li class="submenu"><%= link_to @project.name, { :controller => 'projects', :action => 'show', :id => @project }, :class => "icon icon-projects", :onmouseover => "buttonMouseover(event, 'menuProject');" %></li>
37 42 <% end %>
38 43
39 44 <% if loggedin? %>
40 45 <li><%= link_to l(:label_my_account), { :controller => 'my', :action => 'account' }, :class => "icon icon-user" %></li>
41 46 <% end %>
42 47
43 48 <% if admin_loggedin? %>
44 49 <li class="submenu"><%= link_to l(:label_administration), { :controller => 'admin' }, :class => "icon icon-admin", :onmouseover => "buttonMouseover(event, 'menuAdmin');" %></li>
45 50 <% end %>
46 51
47 52 <li class="right"><%= link_to l(:label_help), { :controller => 'help', :ctrl => params[:controller], :page => params[:action] }, :onclick => "window.open(this.href); return false;", :class => "icon icon-help" %></li>
48 53
49 54 <% if loggedin? %>
50 55 <li class="right"><%= link_to l(:label_logout), { :controller => 'account', :action => 'logout' }, :class => "icon icon-user" %></li>
51 56 <% else %>
52 57 <li class="right"><%= link_to l(:label_login), { :controller => 'account', :action => 'login' }, :class => "icon icon-user" %></li>
53 58 <% end %>
54 59 </ul>
55 60 </div>
56 61
57 62 <% if admin_loggedin? %>
58 63 <div id="menuAdmin" class="menu" onmouseover="menuMouseover(event)">
59 64 <a class="menuItem" href="/admin/projects" onmouseover="menuItemMouseover(event,'menuProjects');"><span class="menuItemText"><%=l(:label_project_plural)%></span><span class="menuItemArrow">&#9654;</span></a>
60 65 <a class="menuItem" href="/users" onmouseover="menuItemMouseover(event,'menuUsers');"><span class="menuItemText"><%=l(:label_user_plural)%></span><span class="menuItemArrow">&#9654;</span></a>
61 66 <a class="menuItem" href="/roles"><%=l(:label_role_and_permissions)%></a>
62 67 <a class="menuItem" href="/trackers" onmouseover="menuItemMouseover(event,'menuTrackers');"><span class="menuItemText"><%=l(:label_tracker_plural)%></span><span class="menuItemArrow">&#9654;</span></a>
63 68 <a class="menuItem" href="/custom_fields"><%=l(:label_custom_field_plural)%></a>
64 69 <a class="menuItem" href="/enumerations"><%=l(:label_enumerations)%></a>
65 70 <a class="menuItem" href="/admin/mail_options"><%=l(:field_mail_notification)%></a>
66 71 <a class="menuItem" href="/auth_sources"><%=l(:label_authentication)%></a>
67 72 <a class="menuItem" href="/admin/info"><%=l(:label_information_plural)%></a>
68 73 </div>
69 74 <div id="menuTrackers" class="menu">
70 75 <a class="menuItem" href="/issue_statuses"><%=l(:label_issue_status_plural)%></a>
71 76 <a class="menuItem" href="/roles/workflow"><%=l(:label_workflow)%></a>
72 77 </div>
73 78 <div id="menuProjects" class="menu"><a class="menuItem" href="/projects/add"><%=l(:label_new)%></a></div>
74 79 <div id="menuUsers" class="menu"><a class="menuItem" href="/users/add"><%=l(:label_new)%></a></div>
75 80 <% end %>
76 81
77 82 <% unless @project.nil? || @project.id.nil? %>
78 83 <div id="menuProject" class="menu" onmouseover="menuMouseover(event)">
79 84 <%= link_to l(:label_calendar), {:controller => 'projects', :action => 'calendar', :id => @project }, :class => "menuItem" %>
80 85 <%= link_to l(:label_gantt), {:controller => 'projects', :action => 'gantt', :id => @project }, :class => "menuItem" %>
81 86 <%= link_to l(:label_issue_plural), {:controller => 'projects', :action => 'list_issues', :id => @project }, :class => "menuItem" %>
82 87 <%= link_to l(:label_report_plural), {:controller => 'reports', :action => 'issue_report', :id => @project }, :class => "menuItem" %>
83 88 <%= link_to l(:label_activity), {:controller => 'projects', :action => 'activity', :id => @project }, :class => "menuItem" %>
84 89 <%= link_to l(:label_news_plural), {:controller => 'projects', :action => 'list_news', :id => @project }, :class => "menuItem" %>
85 90 <%= link_to l(:label_change_log), {:controller => 'projects', :action => 'changelog', :id => @project }, :class => "menuItem" %>
86 91 <%= link_to l(:label_document_plural), {:controller => 'projects', :action => 'list_documents', :id => @project }, :class => "menuItem" %>
87 92 <%= link_to l(:label_member_plural), {:controller => 'projects', :action => 'list_members', :id => @project }, :class => "menuItem" %>
88 93 <%= link_to l(:label_attachment_plural), {:controller => 'projects', :action => 'list_files', :id => @project }, :class => "menuItem" %>
89 94 <%= link_to l(:label_repository), {:controller => 'repositories', :action => 'show', :id => @project}, :class => "menuItem" if @project.repository and !@project.repository.new_record? %>
90 95 <%= link_to_if_authorized l(:label_settings), {:controller => 'projects', :action => 'settings', :id => @project }, :class => "menuItem" %>
91 96 </div>
92 97 <% end %>
93 98
94 99
95 100 <div id="subcontent">
96 101
97 102 <% unless @project.nil? || @project.id.nil? %>
98 103 <h2><%= @project.name %></h2>
99 104 <ul class="menublock">
100 105 <li><%= link_to l(:label_overview), :controller => 'projects', :action => 'show', :id => @project %></li>
101 106 <li><%= link_to l(:label_calendar), :controller => 'projects', :action => 'calendar', :id => @project %></li>
102 107 <li><%= link_to l(:label_gantt), :controller => 'projects', :action => 'gantt', :id => @project %></li>
103 108 <li><%= link_to l(:label_issue_plural), :controller => 'projects', :action => 'list_issues', :id => @project %></li>
104 109 <li><%= link_to l(:label_report_plural), :controller => 'reports', :action => 'issue_report', :id => @project %></li>
105 110 <li><%= link_to l(:label_activity), :controller => 'projects', :action => 'activity', :id => @project %></li>
106 111 <li><%= link_to l(:label_news_plural), :controller => 'projects', :action => 'list_news', :id => @project %></li>
107 112 <li><%= link_to l(:label_change_log), :controller => 'projects', :action => 'changelog', :id => @project %></li>
108 113 <li><%= link_to l(:label_document_plural), :controller => 'projects', :action => 'list_documents', :id => @project %></li>
109 114 <li><%= link_to l(:label_member_plural), :controller => 'projects', :action => 'list_members', :id => @project %></li>
110 115 <li><%= link_to l(:label_attachment_plural), :controller => 'projects', :action => 'list_files', :id => @project %></li>
111 116 <li><%= link_to l(:label_repository), :controller => 'repositories', :action => 'show', :id => @project if @project.repository and !@project.repository.new_record? %></li>
112 117 <li><%= link_to_if_authorized l(:label_settings), :controller => 'projects', :action => 'settings', :id => @project %></li>
113 118 </ul>
114 119 <% end %>
115 120
116 121 <% if loggedin? and @logged_in_user.memberships.length > 0 %>
117 122 <h2><%=l(:label_my_projects) %></h2>
118 123 <ul class="menublock">
119 124 <% for membership in @logged_in_user.memberships %>
120 125 <li><%= link_to membership.project.name, :controller => 'projects', :action => 'show', :id => membership.project %></li>
121 126 <% end %>
122 127 </ul>
123 128 <% end %>
124 129 </div>
125 130
126 131 <div id="content">
127 132 <% if flash[:notice] %><p style="color: green"><%= flash[:notice] %></p><% end %>
128 133 <%= @content_for_layout %>
129 134 </div>
130 135
131 136 <div id="footer">
132 137 <p>
133 138 <%= auto_link $RDM_FOOTER_SIG %> |
134 139 <a href="http://redmine.rubyforge.org/"><%= RDM_APP_NAME %></a> <%= RDM_APP_VERSION %>
135 140 </p>
136 141 </div>
137 142
138 143 </div>
139 144 </body>
140 145 </html> No newline at end of file
@@ -1,210 +1,219
1 1 <div class="contextual">
2 2 <%= l(:label_export_to) %>
3 3 <%= link_to 'PDF', {:zoom => @zoom, :year => @year_from, :month => @month_from, :months => @months, :output => 'pdf'}, :class => 'icon icon-pdf' %>
4 4 </div>
5 5
6 6 <h2><%= l(:label_gantt) %></h2>
7 7
8 8 <table width="100%">
9 9 <tr>
10 10 <td align="left">
11 11 <%= start_form_tag %>
12 12 <p>
13 13 <input type="text" name="months" size="2" value="<%= @months %>" />
14 14 <%= l(:label_months_from) %>
15 15 <%= select_month(@month_from, :prefix => "month", :discard_type => true) %>
16 16 <%= select_year(@year_from, :prefix => "year", :discard_type => true) %>
17 17 <%= hidden_field_tag 'zoom', @zoom %>
18 18 <%= submit_tag l(:button_submit), :class => "button-small" %>
19 19 </p>
20 20 <%= end_form_tag %>
21 21 </td>
22 22 <td align="right">
23 23 <%= if @zoom < 4
24 24 link_to image_tag('zoom_in.png'), {:zoom => (@zoom+1), :year => @year_from, :month => @month_from, :months => @months}
25 25 else
26 26 image_tag 'zoom_in_g.png'
27 27 end %>
28 28 <%= if @zoom > 1
29 29 link_to image_tag('zoom_out.png'), :zoom => (@zoom-1), :year => @year_from, :month => @month_from, :months => @months
30 30 else
31 31 image_tag 'zoom_out_g.png'
32 32 end %>
33 33 </td>
34 34 </tr>
35 35 </table>
36 36 <br />
37 37
38 38 <% zoom = 1
39 39 @zoom.times { zoom = zoom * 2 }
40 40
41 41 subject_width = 260
42 42 header_heigth = 18
43 43
44 44 headers_heigth = header_heigth
45 45 show_weeks = false
46 46 show_days = false
47 47
48 48 if @zoom >1
49 49 show_weeks = true
50 50 headers_heigth = 2*header_heigth
51 51 if @zoom > 2
52 52 show_days = true
53 53 headers_heigth = 3*header_heigth
54 54 end
55 55 end
56 56
57 57 g_width = (@date_to - @date_from + 1)*zoom
58 g_height = [(20 * @issues.length + 6), 206].max
58 g_height = [(20 * @issues.length + 6)+150, 206].max
59 59 t_height = g_height + headers_heigth
60 60 %>
61 61
62 62 <table width="100%" style="border:0; border-collapse: collapse;">
63 63 <tr>
64 64 <td style="width:260px;">
65 65
66 66 <div style="position:relative;height:<%= t_height + 24 %>px;width:<%= subject_width + 1 %>px;">
67 67 <div style="right:-2px;width:<%= subject_width %>px;height:<%= headers_heigth %>px;background: #eee;" class="gantt_hdr"></div>
68 <div style="right:-2px;width:<%= subject_width %>px;height:<%= t_height %>px;border-left: 1px solid #c0c0c0;" class="gantt_hdr"></div>
68 <div style="right:-2px;width:<%= subject_width %>px;height:<%= t_height %>px;border-left: 1px solid #c0c0c0;overflow:hidden;" class="gantt_hdr"></div>
69 69 <%
70 70 #
71 71 # Tasks subjects
72 72 #
73 73 top = headers_heigth + 8
74 74 @issues.each do |i| %>
75 <div style="position: absolute;line-height:1em;height:16px;top:<%= top %>px;left:4px;width:<%= subject_width - 5 %>px;overflow:hidden;">
75 <div style="position: absolute;line-height:1.2em;height:16px;top:<%= top %>px;left:4px;overflow:hidden;">
76 76 <small><%= link_to "#{i.tracker.name} ##{i.id}", { :controller => 'issues', :action => 'show', :id => i }, :title => "#{i.subject}" %>:
77 77 <%=h i.subject.sub(/^(.{30}[^\s]*\s).*$/, '\1 (...)') %></small>
78 78 </div>
79 79 <% top = top + 20
80 80 end %>
81 81 </div>
82 82 </td>
83 83 <td>
84 84
85 <div style="position:relative;height:<%= t_height + 24 %>px;width:<%= subject_width %>;overflow:auto;">
85 <div style="position:relative;height:<%= t_height + 24 %>px;overflow:auto;">
86 86 <div style="width:<%= g_width-1 %>px;height:<%= headers_heigth %>px;background: #eee;" class="gantt_hdr">&nbsp;</div>
87 87 <%
88 88 #
89 89 # Months headers
90 90 #
91 91 month_f = @date_from
92 92 left = 0
93 93 height = (show_weeks ? header_heigth : header_heigth + g_height)
94 94 @months.times do
95 95 width = ((month_f >> 1) - month_f) * zoom - 1
96 96 %>
97 97 <div style="left:<%= left %>px;width:<%= width %>px;height:<%= height %>px;" class="gantt_hdr">
98 98 <%= link_to "#{month_f.year}-#{month_f.month}", { :year => month_f.year, :month => month_f.month, :zoom => @zoom, :months => @months }, :title => "#{month_name(month_f.month)} #{month_f.year}"%>
99 99 </div>
100 100 <%
101 101 left = left + width + 1
102 102 month_f = month_f >> 1
103 103 end %>
104 104
105 105 <%
106 106 #
107 107 # Weeks headers
108 108 #
109 109 if show_weeks
110 110 left = 0
111 111 height = (show_days ? header_heigth-1 : header_heigth-1 + g_height)
112 112 if @date_from.cwday == 1
113 113 # @date_from is monday
114 114 week_f = @date_from
115 115 else
116 116 # find next monday after @date_from
117 117 week_f = @date_from + (7 - @date_from.cwday + 1)
118 118 width = (7 - @date_from.cwday + 1) * zoom-1
119 119 %>
120 120 <div style="left:<%= left %>px;top:19px;width:<%= width %>px;height:<%= height %>px;" class="gantt_hdr">&nbsp;</div>
121 121 <%
122 122 left = left + width+1
123 123 end %>
124 124 <%
125 125 while week_f <= @date_to
126 126 width = (week_f + 6 <= @date_to) ? 7 * zoom -1 : (@date_to - week_f + 1) * zoom-1
127 127 %>
128 128 <div style="left:<%= left %>px;top:19px;width:<%= width %>px;height:<%= height %>px;" class="gantt_hdr">
129 129 <small><%= week_f.cweek if width >= 16 %></small>
130 130 </div>
131 131 <%
132 132 left = left + width+1
133 133 week_f = week_f+7
134 134 end
135 135 end %>
136 136
137 137 <%
138 138 #
139 139 # Days headers
140 140 #
141 141 if show_days
142 142 left = 0
143 143 height = g_height + header_heigth - 1
144 144 wday = @date_from.cwday
145 145 (@date_to - @date_from + 1).to_i.times do
146 146 width = zoom - 1
147 147 %>
148 148 <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">
149 149 <%= day_name(wday)[0,1] %>
150 150 </div>
151 151 <%
152 152 left = left + width+1
153 153 wday = wday + 1
154 154 wday = 1 if wday > 7
155 155 end
156 156 end %>
157 157
158 158 <%
159 159 #
160 160 # Today red line
161 161 #
162 162 if Date.today >= @date_from and Date.today <= @date_to %>
163 163 <div style="position: absolute;height:<%= g_height %>px;top:<%= headers_heigth + 1 %>px;left:<%= ((Date.today-@date_from+1)*zoom).floor()-1 %>px;width:10px;border-left: 1px dashed red;">&nbsp;</div>
164 164 <% end %>
165 165
166 166 <%
167 167 #
168 168 # Tasks
169 169 #
170 top = headers_heigth + 12
170 top = headers_heigth + 10
171 171 @issues.each do |i| %>
172 172 <%
173 173 i_start_date = (i.start_date >= @date_from ? i.start_date : @date_from )
174 174 i_end_date = (i.due_date <= @date_to ? i.due_date : @date_to )
175 175
176 176 i_done_date = i.start_date + ((i.due_date - i.start_date+1)*i.done_ratio/100).floor
177 177 i_done_date = (i_done_date <= @date_from ? @date_from : i_done_date )
178 178 i_done_date = (i_done_date >= @date_to ? @date_to : i_done_date )
179 179
180 180 i_late_date = [i_end_date, Date.today].min if i_start_date < Date.today
181 181
182 182 i_left = ((i_start_date - @date_from)*zoom).floor
183 183 i_width = ((i_end_date - i_start_date + 1)*zoom).floor - 2 # total width of the issue (- 2 for left and right borders)
184 184 d_width = ((i_done_date - i_start_date)*zoom).floor - 2 # done width
185 185 l_width = i_late_date ? ((i_late_date - i_start_date+1)*zoom).floor - 2 : 0 # delay width
186 186 %>
187 187 <div style="top:<%= top %>px;left:<%= i_left %>px;width:<%= i_width %>px;" class="task task_todo">&nbsp;</div>
188 188 <% if l_width > 0 %>
189 189 <div style="top:<%= top %>px;left:<%= i_left %>px;width:<%= l_width %>px;" class="task task_late">&nbsp;</div>
190 190 <% end %>
191 191 <% if d_width > 0 %>
192 192 <div style="top:<%= top %>px;left:<%= i_left %>px;width:<%= d_width %>px;" class="task task_done">&nbsp;</div>
193 193 <% end %>
194 194 <div style="top:<%= top %>px;left:<%= i_left + i_width + 5 %>px;background:#fff;" class="task">
195 195 <%= i.status.name %>
196 196 <%= (i.done_ratio).to_i %>%
197 197 </div>
198 <% # === tooltip === %>
199 <div style="position: absolute;top:<%= top %>px;left:<%= i_left %>px;width:<%= i_width %>px;height:12px;" class="tooltip"><span class="tip">
200 <strong><%= "#{i.tracker.name} ##{i.id}" %></strong>: <%=h i.subject %><br />
201 <br />
202 <strong><%= l(:field_start_date) %></strong>: <%= format_date(i.start_date) %><br />
203 <strong><%= l(:field_due_date) %></strong>: <%= format_date(i.due_date) %><br />
204 <strong><%= l(:field_assigned_to) %></strong>: <%= i.assigned_to ? i.assigned_to.name : "-" %><br />
205 <strong><%=l(:field_priority)%></strong>: <%= i.priority.name %>
206 </span></div>
198 207 <% top = top + 20
199 208 end %>
200 209 </div>
201 210 </td>
202 211 </tr>
203 212 </table>
204 213
205 214 <table width="100%">
206 215 <tr>
207 216 <td align="left"><%= link_to ('&#171; ' + l(:label_previous)), :year => (@date_from << @months).year, :month => (@date_from << @months).month, :zoom => @zoom, :months => @months %></td>
208 217 <td align="right"><%= link_to (l(:label_next) + ' &#187;'), :year => (@date_from >> @months).year, :month => (@date_from >> @months).month, :zoom => @zoom, :months => @months %></td>
209 218 </tr>
210 219 </table> No newline at end of file
@@ -1,589 +1,604
1 1 /* andreas08 - an open source xhtml/css website layout by Andreas Viklund - http://andreasviklund.com . Free to use in any way and for any purpose as long as the proper credits are given to the original designer. Version: 1.0, November 28, 2005 */
2 2 /* Edited by Jean-Philippe Lang *>
3 3 /**************** Body and tag styles ****************/
4 4
5 5
6 6 #header * {margin:0; padding:0;}
7 7 p, ul, ol, li {margin:0; padding:0;}
8 8
9 9
10 10 body{
11 11 font:76% Verdana,Tahoma,Arial,sans-serif;
12 12 line-height:1.4em;
13 13 text-align:center;
14 14 color:#303030;
15 15 background:#e8eaec;
16 16 margin:0;
17 17 }
18 18
19 19
20 20 a{
21 21 color:#467aa7;
22 22 font-weight:bold;
23 23 text-decoration:none;
24 24 background-color:inherit;
25 25 }
26 26
27 27 a:hover{color:#2a5a8a; text-decoration:none; background-color:inherit;}
28 28 a img{border:none;}
29 29
30 30 p{margin:0 0 1em 0;}
31 31 p form{margin-top:0; margin-bottom:20px;}
32 32
33 33 img.left,img.center,img.right{padding:4px; border:1px solid #a0a0a0;}
34 34 img.left{float:left; margin:0 12px 5px 0;}
35 35 img.center{display:block; margin:0 auto 5px auto;}
36 36 img.right{float:right; margin:0 0 5px 12px;}
37 37
38 38 /**************** Header and navigation styles ****************/
39 39
40 40 #container{
41 41 width:100%;
42 42 min-width: 800px;
43 43 margin:0;
44 44 padding:0;
45 45 text-align:left;
46 46 background:#ffffff;
47 47 color:#303030;
48 48 }
49 49
50 50 #header{
51 51 height:4.5em;
52 52 margin:0;
53 53 background:#467aa7;
54 54 color:#ffffff;
55 55 margin-bottom:1px;
56 56 }
57 57
58 58 #header h1{
59 59 padding:10px 0 0 20px;
60 60 font-size:2em;
61 61 background-color:inherit;
62 62 color:#fff;
63 63 letter-spacing:-1px;
64 64 font-weight:bold;
65 65 font-family: Trebuchet MS,Georgia,"Times New Roman",serif;
66 66 }
67 67
68 68 #header h2{
69 69 margin:3px 0 0 40px;
70 70 font-size:1.5em;
71 71 background-color:inherit;
72 72 color:#f0f2f4;
73 73 letter-spacing:-1px;
74 74 font-weight:normal;
75 75 font-family: Trebuchet MS,Georgia,"Times New Roman",serif;
76 76 }
77 77
78 78 #navigation{
79 79 height:2.2em;
80 80 line-height:2.2em;
81 81 margin:0;
82 82 background:#578bb8;
83 83 color:#ffffff;
84 84 }
85 85
86 86 #navigation li{
87 87 float:left;
88 88 list-style-type:none;
89 89 border-right:1px solid #ffffff;
90 90 white-space:nowrap;
91 91 }
92 92
93 93 #navigation li.right {
94 94 float:right;
95 95 list-style-type:none;
96 96 border-right:0;
97 97 border-left:1px solid #ffffff;
98 98 white-space:nowrap;
99 99 }
100 100
101 101 #navigation li a{
102 102 display:block;
103 103 padding:0px 10px 0px 22px;
104 104 font-size:0.8em;
105 105 font-weight:normal;
106 106 text-decoration:none;
107 107 background-color:inherit;
108 108 color: #ffffff;
109 109 }
110 110
111 111 #navigation li.submenu {
112 112 background:url(../images/arrow_down.png) 96% 80% no-repeat;
113 113 }
114 114
115 115 #navigation li.submenu a {
116 116 padding:0px 16px 0px 22px;
117 117 }
118 118
119 119 * html #navigation a {width:1%;}
120 120
121 121 #navigation .selected,#navigation a:hover{
122 122 color:#ffffff;
123 123 text-decoration:none;
124 124 background-color: #80b0da;
125 125 }
126 126
127 127 /**************** Icons *******************/
128 128 .icon {
129 129 background-position: 0% 40%;
130 130 background-repeat: no-repeat;
131 131 padding-left: 20px;
132 132 padding-top: 2px;
133 133 padding-bottom: 3px;
134 134 vertical-align: middle;
135 135 }
136 136
137 137 #navigation .icon {
138 138 background-position: 4px 50%;
139 139 }
140 140
141 141 .icon22 {
142 142 background-position: 0% 40%;
143 143 background-repeat: no-repeat;
144 144 padding-left: 24px;
145 145 line-height: 22px;
146 146 vertical-align: middle;
147 147 }
148 148
149 149 .icon-add { background-image: url(../images/add.png); }
150 150 .icon-edit { background-image: url(../images/edit.png); }
151 151 .icon-del { background-image: url(../images/delete.png); }
152 152 .icon-move { background-image: url(../images/move.png); }
153 153 .icon-save { background-image: url(../images/save.png); }
154 154 .icon-pdf { background-image: url(../images/pdf.png); }
155 155 .icon-csv { background-image: url(../images/csv.png); }
156 156 .icon-file { background-image: url(../images/file.png); }
157 157 .icon-folder { background-image: url(../images/folder.png); }
158 158 .icon-package { background-image: url(../images/package.png); }
159 159 .icon-home { background-image: url(../images/home.png); }
160 160 .icon-user { background-image: url(../images/user.png); }
161 161 .icon-mypage { background-image: url(../images/user_page.png); }
162 162 .icon-admin { background-image: url(../images/admin.png); }
163 163 .icon-projects { background-image: url(../images/projects.png); }
164 164 .icon-logout { background-image: url(../images/logout.png); }
165 165 .icon-help { background-image: url(../images/help.png); }
166 166 .icon-attachment { background-image: url(../images/attachment.png); }
167 167
168 168 .icon22-projects { background-image: url(../images/22x22/projects.png); }
169 169 .icon22-users { background-image: url(../images/22x22/users.png); }
170 170 .icon22-tracker { background-image: url(../images/22x22/tracker.png); }
171 171 .icon22-role { background-image: url(../images/22x22/role.png); }
172 172 .icon22-workflow { background-image: url(../images/22x22/workflow.png); }
173 173 .icon22-options { background-image: url(../images/22x22/options.png); }
174 174 .icon22-notifications { background-image: url(../images/22x22/notifications.png); }
175 175 .icon22-authent { background-image: url(../images/22x22/authent.png); }
176 176 .icon22-info { background-image: url(../images/22x22/info.png); }
177 177 .icon22-comment { background-image: url(../images/22x22/comment.png); }
178 178
179 179 /**************** Content styles ****************/
180 180
181 181 html>body #content {
182 182 height: auto;
183 183 min-height: 500px;
184 184 }
185 185
186 186 #content{
187 187 width: auto;
188 188 height:500px;
189 189 font-size:0.9em;
190 190 padding:20px 10px 10px 20px;
191 191 margin-left: 120px;
192 192 border-left: 1px dashed #c0c0c0;
193 193
194 194 }
195 195
196 196 #content h2{
197 197 display:block;
198 198 margin:0 0 16px 0;
199 199 font-size:1.7em;
200 200 font-weight:normal;
201 201 letter-spacing:-1px;
202 202 color:#606060;
203 203 background-color:inherit;
204 204 font-family: Trebuchet MS,Georgia,"Times New Roman",serif;
205 205 }
206 206
207 207 #content h2 a{font-weight:normal;}
208 208 #content h3{margin:0 0 12px 0; font-size:1.4em;color:#707070;font-family: Trebuchet MS,Georgia,"Times New Roman",serif;}
209 209 #content h4{font-size: 1em; margin-bottom: 12px; margin-top: 20px; font-weight: normal; border-bottom: dotted 1px #c0c0c0;}
210 210 #content a:hover,#subcontent a:hover{text-decoration:underline;}
211 211 #content ul,#content ol{margin:0 5px 16px 35px;}
212 212 #content dl{margin:0 5px 10px 25px;}
213 213 #content dt{font-weight:bold; margin-bottom:5px;}
214 214 #content dd{margin:0 0 10px 15px;}
215 215
216 216
217 217 /***********************************************/
218 218
219 219 form {
220 220 display: inline;
221 221 }
222 222
223 223 blockquote {
224 224 padding-left: 6px;
225 225 border-left: 2px solid #ccc;
226 226 }
227 227
228 228 input, select {
229 229 vertical-align: middle;
230 230 margin-bottom: 4px;
231 231 }
232 232
233 233 input.button-small
234 234 {
235 235 font-size: 0.8em;
236 236 }
237 237
238 238 .select-small
239 239 {
240 240 font-size: 0.8em;
241 241 }
242 242
243 243 label {
244 244 font-weight: bold;
245 245 font-size: 1em;
246 246 color: #505050;
247 247 }
248 248
249 249 fieldset {
250 250 border:1px solid #c0c0c0;
251 251 padding: 6px;
252 252 }
253 253
254 254 legend {
255 255 color: #505050;
256 256
257 257 }
258 258
259 259 .required {
260 260 color: #bb0000;
261 261 }
262 262
263 263 .odd {
264 264 background-color:#f6f7f8;
265 265 }
266 266 .even {
267 267 background-color: #fff;
268 268 }
269 269
270 270 hr { border:none; border-bottom: dotted 1px #c0c0c0; }
271 271
272 272 div.square {
273 273 border: 1px solid #999;
274 274 float: left;
275 275 margin: .4em .5em 0 0;
276 276 overflow: hidden;
277 277 width: .6em; height: .6em;
278 278 }
279 279
280 280 table p {
281 281 margin:0;
282 282 padding:0;
283 283 }
284 284
285 285 ul.documents {
286 286 list-style-type: none;
287 287 padding: 0;
288 288 margin: 0;
289 289 }
290 290
291 291 ul.documents li {
292 292 background-image: url(../images/32x32/file.png);
293 293 background-repeat: no-repeat;
294 294 background-position: 0 1px;
295 295 padding-left: 36px;
296 296 margin-bottom: 10px;
297 297 margin-left: -37px;
298 298 }
299 299
300 300 /********** Table used to display lists of things ***********/
301 301
302 302 table.list {
303 303 width:100%;
304 304 border-collapse: collapse;
305 305 border: 1px dotted #d0d0d0;
306 306 margin-bottom: 6px;
307 307 }
308 308
309 309 table.with-cells td {
310 310 border: 1px solid #d7d7d7;
311 311 }
312 312
313 313 table.list thead th {
314 314 text-align: center;
315 315 background: #eee;
316 316 border: 1px solid #d7d7d7;
317 317 color: #777;
318 318 }
319 319
320 320 table.list tbody th {
321 321 font-weight: normal;
322 322 background: #eed;
323 323 border: 1px solid #d7d7d7;
324 324 }
325 325
326 326 /********** Validation error messages *************/
327 327 #errorExplanation {
328 328 width: 400px;
329 329 border: 0;
330 330 padding: 7px;
331 331 padding-bottom: 3px;
332 332 margin-bottom: 0px;
333 333 }
334 334
335 335 #errorExplanation h2 {
336 336 text-align: left;
337 337 font-weight: bold;
338 338 padding: 5px 5px 10px 26px;
339 339 font-size: 1em;
340 340 margin: -7px;
341 341 background: url(../images/alert.png) no-repeat 6px 6px;
342 342 }
343 343
344 344 #errorExplanation p {
345 345 color: #333;
346 346 margin-bottom: 0;
347 347 padding: 5px;
348 348 }
349 349
350 350 #errorExplanation ul li {
351 351 font-size: 1em;
352 352 list-style: none;
353 353 margin-left: -16px;
354 354 }
355 355
356 356 /*========== Drop down menu ==============*/
357 357 div.menu {
358 358 background-color: #FFFFFF;
359 359 border-style: solid;
360 360 border-width: 1px;
361 361 border-color: #7F9DB9;
362 362 position: absolute;
363 363 top: 0px;
364 364 left: 0px;
365 365 padding: 0;
366 366 visibility: hidden;
367 367 z-index: 101;
368 368 }
369 369
370 370 div.menu a.menuItem {
371 371 font-size: 10px;
372 372 font-weight: normal;
373 373 line-height: 2em;
374 374 color: #000000;
375 375 background-color: #FFFFFF;
376 376 cursor: default;
377 377 display: block;
378 378 padding: 0 1em;
379 379 margin: 0;
380 380 border: 0;
381 381 text-decoration: none;
382 382 white-space: nowrap;
383 383 }
384 384
385 385 div.menu a.menuItem:hover, div.menu a.menuItemHighlight {
386 386 background-color: #80b0da;
387 387 color: #ffffff;
388 388 }
389 389
390 390 div.menu a.menuItem span.menuItemText {}
391 391
392 392 div.menu a.menuItem span.menuItemArrow {
393 393 margin-right: -.75em;
394 394 }
395 395
396 396 /**************** Sidebar styles ****************/
397 397
398 398 #subcontent{
399 399 position: absolute;
400 400 left: 0px;
401 401 width:110px;
402 402 padding:20px 20px 10px 5px;
403 403 }
404 404
405 405 #subcontent h2{
406 406 display:block;
407 407 margin:0 0 5px 0;
408 408 font-size:1.0em;
409 409 font-weight:bold;
410 410 text-align:left;
411 411 color:#606060;
412 412 background-color:inherit;
413 413 font-family: Trebuchet MS,Georgia,"Times New Roman",serif;
414 414 }
415 415
416 416 #subcontent p{margin:0 0 16px 0; font-size:0.9em;}
417 417
418 418 /**************** Menublock styles ****************/
419 419
420 420 .menublock{margin:0 0 20px 8px; font-size:0.8em;}
421 421 .menublock li{list-style:none; display:block; padding:1px; margin-bottom:0px;}
422 422 .menublock li a{font-weight:bold; text-decoration:none;}
423 423 .menublock li a:hover{text-decoration:none;}
424 424 .menublock li ul{margin:0; font-size:1em; font-weight:normal;}
425 425 .menublock li ul li{margin-bottom:0;}
426 426 .menublock li ul a{font-weight:normal;}
427 427
428 428 /**************** Footer styles ****************/
429 429
430 430 #footer{
431 431 clear:both;
432 432 padding:5px 0;
433 433 margin:0;
434 434 font-size:0.9em;
435 435 color:#f0f0f0;
436 436 background:#467aa7;
437 437 }
438 438
439 439 #footer p{padding:0; margin:0; text-align:center;}
440 440 #footer a{color:#f0f0f0; background-color:inherit; font-weight:bold;}
441 441 #footer a:hover{color:#ffffff; background-color:inherit; text-decoration: underline;}
442 442
443 443 /**************** Misc classes and styles ****************/
444 444
445 445 .splitcontentleft{float:left; width:49%;}
446 446 .splitcontentright{float:right; width:49%;}
447 447 .clear{clear:both;}
448 448 .small{font-size:0.8em;line-height:1.4em;padding:0 0 0 0;}
449 449 .hide{display:none;}
450 450 .textcenter{text-align:center;}
451 451 .textright{text-align:right;}
452 452 .important{color:#f02025; background-color:inherit; font-weight:bold;}
453 453
454 454 .box{
455 455 margin:0 0 20px 0;
456 456 padding:10px;
457 457 border:1px solid #c0c0c0;
458 458 background-color:#fafbfc;
459 459 color:#505050;
460 460 line-height:1.5em;
461 461 }
462 462
463 463 a.close-icon {
464 464 display:block;
465 465 margin-top:3px;
466 466 overflow:hidden;
467 467 width:12px;
468 468 height:12px;
469 469 background-repeat: no-repeat;
470 470 cursor:pointer;
471 471 background-image:url('../images/close.png');
472 472 }
473 473
474 474 a.close-icon:hover {
475 475 background-image:url('../images/close_hl.png');
476 476 }
477 477
478 478 .rightbox{
479 479 background: #fafbfc;
480 480 border: 1px solid #c0c0c0;
481 481 float: right;
482 482 padding: 8px;
483 483 position: relative;
484 484 margin: 0 5px 5px;
485 485 }
486 486
487 487 .layout-active {
488 488 background: #ECF3E1;
489 489 }
490 490
491 491 .block-receiver {
492 492 border:1px dashed #c0c0c0;
493 493 margin-bottom: 20px;
494 494 padding: 15px 0 15px 0;
495 495 }
496 496
497 497 .mypage-box {
498 498 margin:0 0 20px 0;
499 499 color:#505050;
500 500 line-height:1.5em;
501 501 }
502 502
503 503 .handle {
504 504 cursor: move;
505 505 }
506 506
507 507 .login {
508 508 width: 50%;
509 509 text-align: left;
510 510 }
511 511
512 512 img.calendar-trigger {
513 513 cursor: pointer;
514 514 vertical-align: middle;
515 515 margin-left: 4px;
516 516 }
517 517
518 518 #history p {
519 519 margin-left: 34px;
520 520 }
521 521
522 522 /***** Contextual links div *****/
523 523 .contextual {
524 524 float: right;
525 525 font-size: 0.8em;
526 526 line-height: 16px;
527 527 padding: 2px;
528 528 }
529 529
530 530 .contextual select, .contextual input {
531 531 font-size: 1em;
532 532 }
533 533
534 534 /***** Gantt chart *****/
535 535 .gantt_hdr {
536 536 position:absolute;
537 537 top:0;
538 538 height:16px;
539 539 border-top: 1px solid #c0c0c0;
540 540 border-bottom: 1px solid #c0c0c0;
541 541 border-right: 1px solid #c0c0c0;
542 542 text-align: center;
543 543 overflow: hidden;
544 544 }
545 545
546 546 .task {
547 547 position: absolute;
548 548 height:8px;
549 549 font-size:0.8em;
550 550 color:#888;
551 background:#aaa;
552 551 padding:0;
553 552 margin:0;
554 553 line-height:0.8em;
555 554 }
556 555
557 556 .task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; }
558 557 .task_done { background:#66f url(../images/task_done.png); border: 1px solid #66f; }
559 558 .task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; }
560 559
560 /***** Tooltips ******/
561 .tooltip{position:absolute;z-index:24;}
562 .tooltip:hover{z-index:25;color:#000;}
563 .tooltip span.tip{display: none}
564
565 div.tooltip:hover span.tip{
566 display:block;
567 position:absolute;
568 top:12px; left:20px; width:270px;
569 border:1px solid #555;
570 background-color:#fff;
571 padding: 4px;
572 font-size: 0.8em;
573 color:#505050;
574 }
575
561 576 /***** CSS FORM ******/
562 577 .tabular p{
563 578 margin: 0;
564 579 padding: 5px 0 8px 0;
565 580 padding-left: 180px; /*width of left column containing the label elements*/
566 581 height: 1%;
567 582 }
568 583
569 584 .tabular label{
570 585 font-weight: bold;
571 586 float: left;
572 587 margin-left: -180px; /*width of left column*/
573 588 width: 175px; /*width of labels. Should be smaller than left column to create some right
574 589 margin*/
575 590 }
576 591
577 592 .error {
578 593 color: #cc0000;
579 594 }
580 595
581 596
582 597 /*.threepxfix class below:
583 598 Targets IE6- ONLY. Adds 3 pixel indent for multi-line form contents.
584 599 to account for 3 pixel bug: http://www.positioniseverything.net/explorer/threepxtest.html
585 600 */
586 601
587 602 * html .threepxfix{
588 603 margin-left: 3px;
589 604 } No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now