##// END OF EJS Templates
added multiple file upload for documents and files modules...
Jean-Philippe Lang -
r127:ff65a5b22a54
parent child
Show More
@@ -1,68 +1,66
1 1 # redMine - project management software
2 2 # Copyright (C) 2006 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class DocumentsController < ApplicationController
19 19 layout 'base'
20 20 before_filter :find_project, :authorize
21 21
22 22 def show
23 23 @attachments = @document.attachments.find(:all, :order => "created_on DESC")
24 24 end
25 25
26 26 def edit
27 27 @categories = Enumeration::get_values('DCAT')
28 28 if request.post? and @document.update_attributes(params[:document])
29 29 flash[:notice] = l(:notice_successful_update)
30 30 redirect_to :action => 'show', :id => @document
31 31 end
32 32 end
33 33
34 34 def destroy
35 35 @document.destroy
36 36 redirect_to :controller => 'projects', :action => 'list_documents', :id => @project
37 37 end
38 38
39 39 def download
40 40 @attachment = @document.attachments.find(params[:attachment_id])
41 41 @attachment.increment_download
42 42 send_file @attachment.diskfile, :filename => @attachment.filename
43 43 rescue
44 44 flash.now[:notice] = l(:notice_file_not_found)
45 45 render :text => "", :layout => true, :status => 404
46 46 end
47 47
48 48 def add_attachment
49 # Save the attachment
50 if params[:attachment][:file].size > 0
51 @attachment = @document.attachments.build(params[:attachment])
52 @attachment.author_id = self.logged_in_user.id if self.logged_in_user
53 @attachment.save
54 end
49 # Save the attachments
50 params[:attachments].each { |a|
51 Attachment.create(:container => @document, :file => a, :author => logged_in_user) unless a.size == 0
52 } if params[:attachments] and params[:attachments].is_a? Array
55 53 redirect_to :action => 'show', :id => @document
56 54 end
57 55
58 56 def destroy_attachment
59 57 @document.attachments.find(params[:attachment_id]).destroy
60 58 redirect_to :action => 'show', :id => @document
61 59 end
62 60
63 61 private
64 62 def find_project
65 63 @document = Document.find(params[:id])
66 64 @project = @document.project
67 65 end
68 66 end
@@ -1,535 +1,531
1 1 # redMine - project management software
2 2 # Copyright (C) 2006 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class 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 end
84 84
85 85 def settings
86 86 @root_projects = Project::find(:all, :conditions => ["parent_id is null and id <> ?", @project.id])
87 87 @custom_fields = IssueCustomField.find(:all)
88 88 @issue_category ||= IssueCategory.new
89 89 @member ||= @project.members.new
90 90 @roles = Role.find(:all)
91 91 @users = User.find(:all) - @project.members.find(:all, :include => :user).collect{|m| m.user }
92 92 @custom_values ||= ProjectCustomField.find(:all).collect { |x| @project.custom_values.find_by_custom_field_id(x.id) || CustomValue.new(:custom_field => x) }
93 93 end
94 94
95 95 # Edit @project
96 96 def edit
97 97 if request.post?
98 98 @project.custom_fields = IssueCustomField.find(params[:custom_field_ids]) if params[:custom_field_ids]
99 99 if params[:custom_fields]
100 100 @custom_values = ProjectCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @project, :value => params["custom_fields"][x.id.to_s]) }
101 101 @project.custom_values = @custom_values
102 102 end
103 103 if params[:repository_enabled]
104 104 case params[:repository_enabled]
105 105 when "0"
106 106 @project.repository = nil
107 107 when "1"
108 108 @project.repository ||= Repository.new
109 109 @project.repository.attributes = params[:repository]
110 110 end
111 111 end
112 112 @project.attributes = params[:project]
113 113 if @project.save
114 114 flash[:notice] = l(:notice_successful_update)
115 115 redirect_to :action => 'settings', :id => @project
116 116 else
117 117 settings
118 118 render :action => 'settings'
119 119 end
120 120 end
121 121 end
122 122
123 123 # Delete @project
124 124 def destroy
125 125 if request.post? and params[:confirm]
126 126 @project.destroy
127 127 redirect_to :controller => 'admin', :action => 'projects'
128 128 end
129 129 end
130 130
131 131 # Add a new issue category to @project
132 132 def add_issue_category
133 133 if request.post?
134 134 @issue_category = @project.issue_categories.build(params[:issue_category])
135 135 if @issue_category.save
136 136 flash[:notice] = l(:notice_successful_create)
137 137 redirect_to :action => 'settings', :id => @project
138 138 else
139 139 settings
140 140 render :action => 'settings'
141 141 end
142 142 end
143 143 end
144 144
145 145 # Add a new version to @project
146 146 def add_version
147 147 @version = @project.versions.build(params[:version])
148 148 if request.post? and @version.save
149 149 flash[:notice] = l(:notice_successful_create)
150 150 redirect_to :action => 'settings', :id => @project
151 151 end
152 152 end
153 153
154 154 # Add a new member to @project
155 155 def add_member
156 156 @member = @project.members.build(params[:member])
157 157 if request.post?
158 158 if @member.save
159 159 flash[:notice] = l(:notice_successful_create)
160 160 redirect_to :action => 'settings', :id => @project
161 161 else
162 162 settings
163 163 render :action => 'settings'
164 164 end
165 165 end
166 166 end
167 167
168 168 # Show members list of @project
169 169 def list_members
170 170 @members = @project.members
171 171 end
172 172
173 173 # Add a new document to @project
174 174 def add_document
175 175 @categories = Enumeration::get_values('DCAT')
176 176 @document = @project.documents.build(params[:document])
177 if request.post?
178 # Save the attachment
179 if params[:attachment][:file].size > 0
180 @attachment = @document.attachments.build(params[:attachment])
181 @attachment.author_id = self.logged_in_user.id if self.logged_in_user
182 end
183 if @document.save
177 if request.post? and @document.save
178 # Save the attachments
179 params[:attachments].each { |a|
180 Attachment.create(:container => @document, :file => a, :author => logged_in_user) unless a.size == 0
181 } if params[:attachments] and params[:attachments].is_a? Array
184 182 flash[:notice] = l(:notice_successful_create)
185 183 redirect_to :action => 'list_documents', :id => @project
186 184 end
187 185 end
188 end
189 186
190 187 # Show documents list of @project
191 188 def list_documents
192 189 @documents = @project.documents.find :all, :include => :category
193 190 end
194 191
195 192 # Add a new issue to @project
196 193 def add_issue
197 194 @tracker = Tracker.find(params[:tracker_id])
198 195 @priorities = Enumeration::get_values('IPRI')
199 196 @issue = Issue.new(:project => @project, :tracker => @tracker)
200 197 if request.get?
201 198 @issue.start_date = Date.today
202 199 @custom_values = @project.custom_fields_for_issues(@tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue) }
203 200 else
204 201 @issue.attributes = params[:issue]
205 202 @issue.author_id = self.logged_in_user.id if self.logged_in_user
206 203 # Multiple file upload
207 204 @attachments = []
208 205 params[:attachments].each { |a|
209 206 @attachments << Attachment.new(:container => @issue, :file => a, :author => logged_in_user) unless a.size == 0
210 207 } if params[:attachments] and params[:attachments].is_a? Array
211 208 @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]) }
212 209 @issue.custom_values = @custom_values
213 210 if @issue.save
214 211 @attachments.each(&:save)
215 212 flash[:notice] = l(:notice_successful_create)
216 213 Mailer.deliver_issue_add(@issue) if Permission.find_by_controller_and_action(params[:controller], params[:action]).mail_enabled?
217 214 redirect_to :action => 'list_issues', :id => @project
218 215 end
219 216 end
220 217 end
221 218
222 219 # Show filtered/sorted issues list of @project
223 220 def list_issues
224 221 sort_init 'issues.id', 'desc'
225 222 sort_update
226 223
227 224 retrieve_query
228 225
229 226 @results_per_page_options = [ 15, 25, 50, 100 ]
230 227 if params[:per_page] and @results_per_page_options.include? params[:per_page].to_i
231 228 @results_per_page = params[:per_page].to_i
232 229 session[:results_per_page] = @results_per_page
233 230 else
234 231 @results_per_page = session[:results_per_page] || 25
235 232 end
236 233
237 234 if @query.valid?
238 235 @issue_count = Issue.count(:include => [:status, :project], :conditions => @query.statement)
239 236 @issue_pages = Paginator.new self, @issue_count, @results_per_page, params['page']
240 237 @issues = Issue.find :all, :order => sort_clause,
241 238 :include => [ :author, :status, :tracker, :project ],
242 239 :conditions => @query.statement,
243 240 :limit => @issue_pages.items_per_page,
244 241 :offset => @issue_pages.current.offset
245 242 end
246 243 render :layout => false if request.xhr?
247 244 end
248 245
249 246 # Export filtered/sorted issues list to CSV
250 247 def export_issues_csv
251 248 sort_init 'issues.id', 'desc'
252 249 sort_update
253 250
254 251 retrieve_query
255 252 render :action => 'list_issues' and return unless @query.valid?
256 253
257 254 @issues = Issue.find :all, :order => sort_clause,
258 255 :include => [ :author, :status, :tracker, :project, :custom_values ],
259 256 :conditions => @query.statement
260 257
261 258 ic = Iconv.new('ISO-8859-1', 'UTF-8')
262 259 export = StringIO.new
263 260 CSV::Writer.generate(export, l(:general_csv_separator)) do |csv|
264 261 # csv header fields
265 262 headers = [ "#", l(:field_status), l(:field_tracker), l(:field_subject), l(:field_author), l(:field_created_on), l(:field_updated_on) ]
266 263 for custom_field in @project.all_custom_fields
267 264 headers << custom_field.name
268 265 end
269 266 csv << headers.collect {|c| ic.iconv(c) }
270 267 # csv lines
271 268 @issues.each do |issue|
272 269 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 270 for custom_field in @project.all_custom_fields
274 271 fields << (show_value issue.custom_value_for(custom_field))
275 272 end
276 273 csv << fields.collect {|c| ic.iconv(c.to_s) }
277 274 end
278 275 end
279 276 export.rewind
280 277 send_data(export.read, :type => 'text/csv; header=present', :filename => 'export.csv')
281 278 end
282 279
283 280 # Export filtered/sorted issues to PDF
284 281 def export_issues_pdf
285 282 sort_init 'issues.id', 'desc'
286 283 sort_update
287 284
288 285 retrieve_query
289 286 render :action => 'list_issues' and return unless @query.valid?
290 287
291 288 @issues = Issue.find :all, :order => sort_clause,
292 289 :include => [ :author, :status, :tracker, :project, :custom_values ],
293 290 :conditions => @query.statement
294 291
295 292 @options_for_rfpdf ||= {}
296 293 @options_for_rfpdf[:file_name] = "export.pdf"
297 294 render :layout => false
298 295 end
299 296
300 297 def move_issues
301 298 @issues = @project.issues.find(params[:issue_ids]) if params[:issue_ids]
302 299 redirect_to :action => 'list_issues', :id => @project and return unless @issues
303 300 @projects = []
304 301 # find projects to which the user is allowed to move the issue
305 302 @logged_in_user.memberships.each {|m| @projects << m.project if Permission.allowed_to_role("projects/move_issues", m.role_id)}
306 303 # issue can be moved to any tracker
307 304 @trackers = Tracker.find(:all)
308 305 if request.post? and params[:new_project_id] and params[:new_tracker_id]
309 306 new_project = Project.find(params[:new_project_id])
310 307 new_tracker = Tracker.find(params[:new_tracker_id])
311 308 @issues.each { |i|
312 309 # project dependent properties
313 310 unless i.project_id == new_project.id
314 311 i.category = nil
315 312 i.fixed_version = nil
316 313 end
317 314 # move the issue
318 315 i.project = new_project
319 316 i.tracker = new_tracker
320 317 i.save
321 318 }
322 319 flash[:notice] = l(:notice_successful_update)
323 320 redirect_to :action => 'list_issues', :id => @project
324 321 end
325 322 end
326 323
327 324 def add_query
328 325 @query = Query.new(params[:query])
329 326 @query.project = @project
330 327 @query.user = logged_in_user
331 328
332 329 params[:fields].each do |field|
333 330 @query.add_filter(field, params[:operators][field], params[:values][field])
334 331 end if params[:fields]
335 332
336 333 if request.post? and @query.save
337 334 flash[:notice] = l(:notice_successful_create)
338 335 redirect_to :controller => 'reports', :action => 'issue_report', :id => @project
339 336 end
340 337 render :layout => false if request.xhr?
341 338 end
342 339
343 340 # Add a news to @project
344 341 def add_news
345 342 @news = News.new(:project => @project)
346 343 if request.post?
347 344 @news.attributes = params[:news]
348 345 @news.author_id = self.logged_in_user.id if self.logged_in_user
349 346 if @news.save
350 347 flash[:notice] = l(:notice_successful_create)
351 348 redirect_to :action => 'list_news', :id => @project
352 349 end
353 350 end
354 351 end
355 352
356 353 # Show news list of @project
357 354 def list_news
358 355 @news_pages, @news = paginate :news, :per_page => 10, :conditions => ["project_id=?", @project.id], :include => :author, :order => "news.created_on DESC"
359 356 render :action => "list_news", :layout => false if request.xhr?
360 357 end
361 358
362 359 def add_file
363 @attachment = Attachment.new(params[:attachment])
364 if request.post? and params[:attachment][:file].size > 0
365 @attachment.container = @project.versions.find_by_id(params[:version_id])
366 @attachment.author = logged_in_user
367 if @attachment.save
368 flash[:notice] = l(:notice_successful_create)
360 if request.post?
361 @version = @project.versions.find_by_id(params[:version_id])
362 # Save the attachments
363 params[:attachments].each { |a|
364 Attachment.create(:container => @version, :file => a, :author => logged_in_user) unless a.size == 0
365 } if params[:attachments] and params[:attachments].is_a? Array
369 366 redirect_to :controller => 'projects', :action => 'list_files', :id => @project
370 367 end
371 end
372 368 @versions = @project.versions
373 369 end
374 370
375 371 def list_files
376 372 @versions = @project.versions
377 373 end
378 374
379 375 # Show changelog for @project
380 376 def changelog
381 377 @trackers = Tracker.find(:all, :conditions => ["is_in_chlog=?", true])
382 378 if request.get?
383 379 @selected_tracker_ids = @trackers.collect {|t| t.id.to_s }
384 380 else
385 381 @selected_tracker_ids = params[:tracker_ids].collect { |id| id.to_i.to_s } if params[:tracker_ids] and params[:tracker_ids].is_a? Array
386 382 end
387 383 @selected_tracker_ids ||= []
388 384 @fixed_issues = @project.issues.find(:all,
389 385 :include => [ :fixed_version, :status, :tracker ],
390 386 :conditions => [ "issue_statuses.is_closed=? and issues.tracker_id in (#{@selected_tracker_ids.join(',')}) and issues.fixed_version_id is not null", true],
391 387 :order => "versions.effective_date DESC, issues.id DESC"
392 388 ) unless @selected_tracker_ids.empty?
393 389 @fixed_issues ||= []
394 390 end
395 391
396 392 def activity
397 393 if params[:year] and params[:year].to_i > 1900
398 394 @year = params[:year].to_i
399 395 if params[:month] and params[:month].to_i > 0 and params[:month].to_i < 13
400 396 @month = params[:month].to_i
401 397 end
402 398 end
403 399 @year ||= Date.today.year
404 400 @month ||= Date.today.month
405 401
406 402 @date_from = Date.civil(@year, @month, 1)
407 403 @date_to = (@date_from >> 1)-1
408 404
409 405 @events_by_day = {}
410 406
411 407 unless params[:show_issues] == "0"
412 408 @project.issues.find(:all, :include => [:author, :status], :conditions => ["issues.created_on>=? and issues.created_on<=?", @date_from, @date_to] ).each { |i|
413 409 @events_by_day[i.created_on.to_date] ||= []
414 410 @events_by_day[i.created_on.to_date] << i
415 411 }
416 412 @show_issues = 1
417 413 end
418 414
419 415 unless params[:show_news] == "0"
420 416 @project.news.find(:all, :conditions => ["news.created_on>=? and news.created_on<=?", @date_from, @date_to], :include => :author ).each { |i|
421 417 @events_by_day[i.created_on.to_date] ||= []
422 418 @events_by_day[i.created_on.to_date] << i
423 419 }
424 420 @show_news = 1
425 421 end
426 422
427 423 unless params[:show_files] == "0"
428 424 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|
429 425 @events_by_day[i.created_on.to_date] ||= []
430 426 @events_by_day[i.created_on.to_date] << i
431 427 }
432 428 @show_files = 1
433 429 end
434 430
435 431 unless params[:show_documents] == "0"
436 432 @project.documents.find(:all, :conditions => ["documents.created_on>=? and documents.created_on<=?", @date_from, @date_to] ).each { |i|
437 433 @events_by_day[i.created_on.to_date] ||= []
438 434 @events_by_day[i.created_on.to_date] << i
439 435 }
440 436 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|
441 437 @events_by_day[i.created_on.to_date] ||= []
442 438 @events_by_day[i.created_on.to_date] << i
443 439 }
444 440 @show_documents = 1
445 441 end
446 442
447 443 render :layout => false if request.xhr?
448 444 end
449 445
450 446 def calendar
451 447 if params[:year] and params[:year].to_i > 1900
452 448 @year = params[:year].to_i
453 449 if params[:month] and params[:month].to_i > 0 and params[:month].to_i < 13
454 450 @month = params[:month].to_i
455 451 end
456 452 end
457 453 @year ||= Date.today.year
458 454 @month ||= Date.today.month
459 455
460 456 @date_from = Date.civil(@year, @month, 1)
461 457 @date_to = (@date_from >> 1)-1
462 458 # start on monday
463 459 @date_from = @date_from - (@date_from.cwday-1)
464 460 # finish on sunday
465 461 @date_to = @date_to + (7-@date_to.cwday)
466 462
467 463 @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])
468 464 render :layout => false if request.xhr?
469 465 end
470 466
471 467 def gantt
472 468 if params[:year] and params[:year].to_i >0
473 469 @year_from = params[:year].to_i
474 470 if params[:month] and params[:month].to_i >=1 and params[:month].to_i <= 12
475 471 @month_from = params[:month].to_i
476 472 else
477 473 @month_from = 1
478 474 end
479 475 else
480 476 @month_from ||= (Date.today << 1).month
481 477 @year_from ||= (Date.today << 1).year
482 478 end
483 479
484 480 @zoom = (params[:zoom].to_i > 0 and params[:zoom].to_i < 5) ? params[:zoom].to_i : 2
485 481 @months = (params[:months].to_i > 0 and params[:months].to_i < 25) ? params[:months].to_i : 6
486 482
487 483 @date_from = Date.civil(@year_from, @month_from, 1)
488 484 @date_to = (@date_from >> @months) - 1
489 485 @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])
490 486
491 487 if params[:output]=='pdf'
492 488 @options_for_rfpdf ||= {}
493 489 @options_for_rfpdf[:file_name] = "gantt.pdf"
494 490 render :template => "projects/gantt.rfpdf", :layout => false
495 491 else
496 492 render :template => "projects/gantt.rhtml"
497 493 end
498 494 end
499 495
500 496 private
501 497 # Find project of id params[:id]
502 498 # if not found, redirect to project list
503 499 # Used as a before_filter
504 500 def find_project
505 501 @project = Project.find(params[:id])
506 502 @html_title = @project.name
507 503 rescue
508 504 redirect_to :action => 'list'
509 505 end
510 506
511 507 # Retrieve query from session or build a new query
512 508 def retrieve_query
513 509 if params[:query_id]
514 510 @query = @project.queries.find(params[:query_id])
515 511 else
516 512 if params[:set_filter] or !session[:query] or session[:query].project_id != @project.id
517 513 # Give it a name, required to be valid
518 514 @query = Query.new(:name => "_")
519 515 @query.project = @project
520 516 if params[:fields] and params[:fields].is_a? Array
521 517 params[:fields].each do |field|
522 518 @query.add_filter(field, params[:operators][field], params[:values][field])
523 519 end
524 520 else
525 521 @query.available_filters.keys.each do |field|
526 522 @query.add_short_filter(field, params[field]) if params[field]
527 523 end
528 524 end
529 525 session[:query] = @query
530 526 else
531 527 @query = session[:query]
532 528 end
533 529 end
534 530 end
535 531 end
@@ -1,36 +1,37
1 1 <div class="contextual">
2 2 <%= link_to_if_authorized l(:button_edit), {:controller => 'documents', :action => 'edit', :id => @document}, :class => 'pic picEdit' %>
3 3 <%= link_to_if_authorized l(:button_delete), {:controller => 'documents', :action => 'destroy', :id => @document}, :confirm => l(:text_are_you_sure), :post => true, :class => 'pic picDelete' %>
4 4 </div>
5 5
6 6 <h2><%= @document.title %></h2>
7 7
8 8 <p><em><%= @document.category.name %><br />
9 9 <%= format_date @document.created_on %></em></p>
10 10 <%= textilizable @document.description %>
11 11 <br />
12 12
13 13 <h3><%= l(:label_attachment_plural) %></h3>
14 14 <ul class="documents">
15 15 <% for attachment in @attachments %>
16 16 <li>
17 17 <div class="contextual">
18 18 <%= link_to_if_authorized l(:button_delete), {:controller => 'documents', :action => 'destroy_attachment', :id => @document, :attachment_id => attachment}, :confirm => l(:text_are_you_sure), :post => true, :class => 'pic picDelete' %>
19 19 </div>
20 20 <%= link_to attachment.filename, :action => 'download', :id => @document, :attachment_id => attachment %>
21 21 (<%= human_size attachment.filesize %>)<br />
22 22 <em><%= attachment.author.display_name %>, <%= format_date(attachment.created_on) %></em><br />
23 23 <%= lwr(:label_download, attachment.downloads) %>
24 24 </li>
25 25 <% end %>
26 26 </ul>
27 27 <br />
28 28
29 29
30 30 <% if authorize_for('documents', 'add_attachment') %>
31 <%= start_form_tag ({ :controller => 'documents', :action => 'add_attachment', :id => @document }, :multipart => true) %>
32 <label><%=l(:label_attachment_new)%></label>&nbsp;&nbsp;
33 <%= file_field 'attachment', 'file' %>
31 <%= start_form_tag ({ :controller => 'documents', :action => 'add_attachment', :id => @document }, :multipart => true, :class => "tabular") %>
32 <p id="attachments_p"><label for="attachment_file"><%=l(:label_attachment)%>&nbsp;
33 <%= link_to_function image_tag('add'), "addFileField()" %></label>
34 <%= file_field_tag 'attachments[]', :size => 30 %></p>
34 35 <%= submit_tag l(:button_add) %>
35 36 <%= end_form_tag %>
36 37 <% end %>
@@ -1,14 +1,15
1 1 <h2><%=l(:label_document_new)%></h2>
2 2
3 3 <%= start_form_tag( { :action => 'add_document', :id => @project }, :class => "tabular", :multipart => true) %>
4 4 <%= render :partial => 'documents/form' %>
5 5
6 6 <div class="box">
7 <p><label for="attachment_file"><%=l(:label_attachment)%></label>
8 <%= file_field 'attachment', 'file' %></p>
7 <p id="attachments_p"><label for="attachment_file"><%=l(:label_attachment)%>&nbsp;
8 <%= link_to_function image_tag('add'), "addFileField()" %></label>
9 <%= file_field_tag 'attachments[]', :size => 30 %></p>
9 10 </div>
10 11
11 12 <%= submit_tag l(:button_create) %>
12 13 <%= end_form_tag %>
13 14
14 15
@@ -1,14 +1,15
1 1 <h2><%=l(:label_attachment_new)%></h2>
2 2
3 3 <%= error_messages_for 'attachment' %>
4 4 <div class="box">
5 5 <%= start_form_tag ({ :action => 'add_file', :id => @project }, :multipart => true, :class => "tabular") %>
6 6
7 7 <p><label for="version_id"><%=l(:field_version)%> <span class="required">*</span></label>
8 8 <%= select_tag "version_id", options_from_collection_for_select(@versions, "id", "name") %></p>
9 9
10 <p><label for="attachment_file"><%=l(:label_attachment)%> <span class="required">*</span></label>
11 <%= file_field 'attachment', 'file' %></p>
10 <p id="attachments_p"><label for="attachment_file"><%=l(:label_attachment)%>&nbsp;
11 <%= link_to_function image_tag('add'), "addFileField()" %></label>
12 <%= file_field_tag 'attachments[]', :size => 30 %></p>
12 13 </div>
13 14 <%= submit_tag l(:button_add) %>
14 15 <%= end_form_tag %> No newline at end of file
@@ -1,20 +1,19
1 1 function checkAll (id, checked) {
2 2 var el = document.getElementById(id);
3 3 for (var i = 0; i < el.elements.length; i++) {
4 4 if (el.elements[i].disabled==false) {
5 5 el.elements[i].checked = checked;
6 6 }
7 7 }
8 8 }
9 9
10 10 function addFileField() {
11 11 var f = document.createElement("input");
12 12 f.type = "file";
13 13 f.name = "attachments[]";
14 14 f.size = 30;
15 15
16 16 p = document.getElementById("attachments_p");
17 17 p.appendChild(document.createElement("br"));
18 p.appendChild(document.createElement("br"));
19 18 p.appendChild(f);
20 19 } No newline at end of file
@@ -1,536 +1,537
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{padding: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 links *******************/
128 128 .picHome { background: url(../images/home.png) no-repeat 4px 50%; }
129 129 .picUser { background: url(../images/user.png) no-repeat 4px 50%; }
130 130 .picUserPage { background: url(../images/user_page.png) no-repeat 4px 50%; }
131 131 .picAdmin { background: url(../images/admin.png) no-repeat 4px 50%; }
132 132 .picProject { background: url(../images/projects.png) no-repeat 4px 50%; }
133 133 .picLogout { background: url(../images/logout.png) no-repeat 4px 50%; }
134 134 .picHelp { background: url(../images/help.png) no-repeat 4px 50%; }
135 135
136 136 .picEdit { background: url(../images/edit.png) no-repeat 4px 50%; }
137 137 .picDelete { background: url(../images/delete.png) no-repeat 4px 50%; }
138 138 .picAdd { background: url(../images/add.png) no-repeat 4px 50%; }
139 139 .picMove { background: url(../images/move.png) no-repeat 4px 50%; }
140 140 .picCheck { background: url(../images/check.png) no-repeat 4px 70%; }
141 141 .picPdf { background: url(../images/pdf.png) no-repeat 4px 50%;}
142 142 .picCsv { background: url(../images/csv.png) no-repeat 4px 50%;}
143 143
144 144 .pic { padding-left: 18px; margin-left: 3px; }
145 145
146 146 .icon {
147 147 background-position: 0% 40%;
148 148 background-repeat: no-repeat;
149 149 padding-left: 20px;
150 150 }
151 151
152 152 .folder { background-image: url(../images/folder.png); }
153 153 .file { background-image: url(../images/file.png); }
154 154 .attachment { background-image: url(../images/attachment.png); }
155 155
156 156 /**************** Content styles ****************/
157 157
158 158 html>body #content {
159 159 height: auto;
160 160 min-height: 500px;
161 161 }
162 162
163 163 #content{
164 164 width: auto;
165 165 height:500px;
166 166 font-size:0.9em;
167 167 padding:20px 10px 10px 20px;
168 168 margin-left: 120px;
169 169 border-left: 1px dashed #c0c0c0;
170 170
171 171 }
172 172
173 173 #content h2{
174 174 display:block;
175 175 margin:0 0 16px 0;
176 176 font-size:1.7em;
177 177 font-weight:normal;
178 178 letter-spacing:-1px;
179 179 color:#606060;
180 180 background-color:inherit;
181 181 font-family: Trebuchet MS,Georgia,"Times New Roman",serif;
182 182 }
183 183
184 184 #content h2 a{font-weight:normal;}
185 185 #content h3{margin:0 0 12px 0; font-size:1.4em;color:#707070;font-family: Trebuchet MS,Georgia,"Times New Roman",serif;}
186 186 #content h4{font-size: 1em; margin-bottom: 12px; margin-top: 20px; font-weight: normal; border-bottom: dotted 1px #c0c0c0;}
187 187 #content a:hover,#subcontent a:hover{text-decoration:underline;}
188 188 #content ul,#content ol{margin:0 5px 16px 35px;}
189 189 #content dl{margin:0 5px 10px 25px;}
190 190 #content dt{font-weight:bold; margin-bottom:5px;}
191 191 #content dd{margin:0 0 10px 15px;}
192 192
193 193
194 194 /***********************************************/
195 195
196 196 form {
197 197 display: inline;
198 198 }
199 199
200 200 blockquote {
201 201 padding-left: 6px;
202 202 border-left: 2px solid #ccc;
203 203 }
204 204
205 205 input, select {
206 206 vertical-align: middle;
207 margin-bottom: 4px;
207 208 }
208 209
209 210 input.button-small
210 211 {
211 212 font-size: 0.8em;
212 213 }
213 214
214 215 .select-small
215 216 {
216 217 font-size: 0.8em;
217 218 }
218 219
219 220 label {
220 221 font-weight: bold;
221 222 font-size: 1em;
222 223 }
223 224
224 225 fieldset {
225 226 border:1px solid #c0c0c0;
226 227 padding: 6px;
227 228 }
228 229
229 230 legend {
230 231 color: #505050;
231 232
232 233 }
233 234
234 235 .required {
235 236 color: #bb0000;
236 237 }
237 238
238 239 .odd {
239 240 background-color:#f6f7f8;
240 241 }
241 242 .even {
242 243 background-color: #fff;
243 244 }
244 245
245 246 hr { border:none; border-bottom: dotted 1px #c0c0c0; }
246 247
247 248 div.square {
248 249 border: 1px solid #999;
249 250 float: left;
250 251 margin: .4em .5em 0 0;
251 252 overflow: hidden;
252 253 width: .6em; height: .6em;
253 254 }
254 255
255 256 table p {
256 257 margin:0;
257 258 padding:0;
258 259 }
259 260
260 261 ul.documents {
261 262 list-style-type: none;
262 263 padding: 0;
263 264 margin: 0;
264 265 }
265 266
266 267 ul.documents li {
267 268 background-image: url(../images/file.png);
268 269 background-repeat: no-repeat;
269 270 background-position: 0 .4em;
270 271 padding-left: 20px;
271 272 margin-bottom: 10px;
272 273 margin-left: -37px;
273 274 }
274 275
275 276 /********** Table used to display lists of things ***********/
276 277
277 278 table.list {
278 279 width:100%;
279 280 border-collapse: collapse;
280 281 border: 1px dotted #d0d0d0;
281 282 margin-bottom: 6px;
282 283 }
283 284
284 285 table.with-cells td {
285 286 border: 1px solid #d7d7d7;
286 287 }
287 288
288 289 table.list thead th {
289 290 text-align: center;
290 291 background: #eee;
291 292 border: 1px solid #d7d7d7;
292 293 color: #777;
293 294 }
294 295
295 296 table.list tbody th {
296 297 font-weight: normal;
297 298 background: #eed;
298 299 border: 1px solid #d7d7d7;
299 300 }
300 301
301 302 /********** Validation error messages *************/
302 303 #errorExplanation {
303 304 width: 400px;
304 305 border: 0;
305 306 padding: 7px;
306 307 padding-bottom: 3px;
307 308 margin-bottom: 0px;
308 309 }
309 310
310 311 #errorExplanation h2 {
311 312 text-align: left;
312 313 font-weight: bold;
313 314 padding: 5px 5px 10px 26px;
314 315 font-size: 1em;
315 316 margin: -7px;
316 317 background: url(../images/alert.png) no-repeat 6px 6px;
317 318 }
318 319
319 320 #errorExplanation p {
320 321 color: #333;
321 322 margin-bottom: 0;
322 323 padding: 5px;
323 324 }
324 325
325 326 #errorExplanation ul li {
326 327 font-size: 1em;
327 328 list-style: none;
328 329 margin-left: -16px;
329 330 }
330 331
331 332 /*========== Drop down menu ==============*/
332 333 div.menu {
333 334 background-color: #FFFFFF;
334 335 border-style: solid;
335 336 border-width: 1px;
336 337 border-color: #7F9DB9;
337 338 position: absolute;
338 339 top: 0px;
339 340 left: 0px;
340 341 padding: 0;
341 342 visibility: hidden;
342 343 z-index: 101;
343 344 }
344 345
345 346 div.menu a.menuItem {
346 347 font-size: 10px;
347 348 font-weight: normal;
348 349 line-height: 2em;
349 350 color: #000000;
350 351 background-color: #FFFFFF;
351 352 cursor: default;
352 353 display: block;
353 354 padding: 0 1em;
354 355 margin: 0;
355 356 border: 0;
356 357 text-decoration: none;
357 358 white-space: nowrap;
358 359 }
359 360
360 361 div.menu a.menuItem:hover, div.menu a.menuItemHighlight {
361 362 background-color: #80b0da;
362 363 color: #ffffff;
363 364 }
364 365
365 366 div.menu a.menuItem span.menuItemText {}
366 367
367 368 div.menu a.menuItem span.menuItemArrow {
368 369 margin-right: -.75em;
369 370 }
370 371
371 372 /**************** Sidebar styles ****************/
372 373
373 374 #subcontent{
374 375 position: absolute;
375 376 left: 0px;
376 377 width:110px;
377 378 padding:20px 20px 10px 5px;
378 379 }
379 380
380 381 #subcontent h2{
381 382 display:block;
382 383 margin:0 0 5px 0;
383 384 font-size:1.0em;
384 385 font-weight:bold;
385 386 text-align:left;
386 387 color:#606060;
387 388 background-color:inherit;
388 389 font-family: Trebuchet MS,Georgia,"Times New Roman",serif;
389 390 }
390 391
391 392 #subcontent p{margin:0 0 16px 0; font-size:0.9em;}
392 393
393 394 /**************** Menublock styles ****************/
394 395
395 396 .menublock{margin:0 0 20px 8px; font-size:0.8em;}
396 397 .menublock li{list-style:none; display:block; padding:1px; margin-bottom:0px;}
397 398 .menublock li a{font-weight:bold; text-decoration:none;}
398 399 .menublock li a:hover{text-decoration:none;}
399 400 .menublock li ul{margin:0; font-size:1em; font-weight:normal;}
400 401 .menublock li ul li{margin-bottom:0;}
401 402 .menublock li ul a{font-weight:normal;}
402 403
403 404 /**************** Footer styles ****************/
404 405
405 406 #footer{
406 407 clear:both;
407 408 padding:5px 0;
408 409 margin:0;
409 410 font-size:0.9em;
410 411 color:#f0f0f0;
411 412 background:#467aa7;
412 413 }
413 414
414 415 #footer p{padding:0; margin:0; text-align:center;}
415 416 #footer a{color:#f0f0f0; background-color:inherit; font-weight:bold;}
416 417 #footer a:hover{color:#ffffff; background-color:inherit; text-decoration: underline;}
417 418
418 419 /**************** Misc classes and styles ****************/
419 420
420 421 .splitcontentleft{float:left; width:49%;}
421 422 .splitcontentright{float:right; width:49%;}
422 423 .clear{clear:both;}
423 424 .small{font-size:0.8em;line-height:1.4em;padding:0 0 0 0;}
424 425 .hide{display:none;}
425 426 .textcenter{text-align:center;}
426 427 .textright{text-align:right;}
427 428 .important{color:#f02025; background-color:inherit; font-weight:bold;}
428 429
429 430 .box{
430 431 margin:0 0 20px 0;
431 432 padding:10px;
432 433 border:1px solid #c0c0c0;
433 434 background-color:#fafbfc;
434 435 color:#505050;
435 436 line-height:1.5em;
436 437 }
437 438
438 439 a.close-icon {
439 440 display:block;
440 441 margin-top:3px;
441 442 overflow:hidden;
442 443 width:12px;
443 444 height:12px;
444 445 background-repeat: no-repeat;
445 446 cursor:pointer;
446 447 background-image:url('../images/close.png');
447 448 }
448 449
449 450 a.close-icon:hover {
450 451 background-image:url('../images/close_hl.png');
451 452 }
452 453
453 454 .rightbox{
454 455 background: #fafbfc;
455 456 border: 1px solid #c0c0c0;
456 457 float: right;
457 458 padding: 8px;
458 459 position: relative;
459 460 margin: 0 5px 5px;
460 461 }
461 462
462 463 .layout-active {
463 464 background: #ECF3E1;
464 465 }
465 466
466 467 .block-receiver {
467 468 border:1px dashed #c0c0c0;
468 469 margin-bottom: 20px;
469 470 padding: 15px 0 15px 0;
470 471 }
471 472
472 473 .mypage-box {
473 474 margin:0 0 20px 0;
474 475 color:#505050;
475 476 line-height:1.5em;
476 477 }
477 478
478 479 .handle {
479 480 cursor: move;
480 481 }
481 482
482 483 .login {
483 484 width: 50%;
484 485 text-align: left;
485 486 }
486 487
487 488 img.calendar-trigger {
488 489 cursor: pointer;
489 490 vertical-align: middle;
490 491 margin-left: 4px;
491 492 }
492 493
493 494 #history p {
494 495 margin-left: 34px;
495 496 }
496 497
497 498 /***** Contextual links div *****/
498 499 .contextual {
499 500 float: right;
500 501 font-size: 0.8em;
501 502 }
502 503
503 504 .contextual select, .contextual input {
504 505 font-size: 1em;
505 506 }
506 507
507 508
508 509 /***** CSS FORM ******/
509 510 .tabular p{
510 511 margin: 0;
511 512 padding: 5px 0 8px 0;
512 513 padding-left: 180px; /*width of left column containing the label elements*/
513 514 height: 1%;
514 515 }
515 516
516 517 .tabular label{
517 518 font-weight: bold;
518 519 float: left;
519 520 margin-left: -180px; /*width of left column*/
520 521 width: 175px; /*width of labels. Should be smaller than left column to create some right
521 522 margin*/
522 523 }
523 524
524 525 .error {
525 526 color: #cc0000;
526 527 }
527 528
528 529
529 530 /*.threepxfix class below:
530 531 Targets IE6- ONLY. Adds 3 pixel indent for multi-line form contents.
531 532 to account for 3 pixel bug: http://www.positioniseverything.net/explorer/threepxtest.html
532 533 */
533 534
534 535 * html .threepxfix{
535 536 margin-left: 3px;
536 537 } No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now