Project

General

Profile

Feature #2024 » gantt-editting-r1928.patch

against revision 1928 - Hiroyuki Yoshioka, 2008-10-12 01:54

View differences:

app/controllers/issues_controller.rb (working copy)
18 18
class IssuesController < ApplicationController
19 19
  menu_item :new_issue, :only => :new
20 20
  
21
  before_filter :find_issue, :only => [:show, :edit, :reply, :destroy_attachment]
21
  before_filter :find_issue, :only => [:show, :edit, :reply, :destroy_attachment, :edit_gantt]
22 22
  before_filter :find_issues, :only => [:bulk_edit, :move, :destroy]
23 23
  before_filter :find_project, :only => [:new, :update_form, :preview, :gantt, :calendar]
24
  before_filter :authorize, :except => [:index, :changes, :preview, :update_form, :context_menu]
24
  before_filter :authorize, :except => [:index, :changes, :preview, :update_form, :context_menu, :edit_gantt]
25 25
  before_filter :find_optional_project, :only => [:index, :changes]
26 26
  accept_key_auth :index, :changes
27 27

  
......
154 154
  # Attributes that can be updated on workflow transition (without :edit permission)
155 155
  # TODO: make it configurable (at least per role)
156 156
  UPDATABLE_ATTRS_ON_TRANSITION = %w(status_id assigned_to_id fixed_version_id done_ratio) unless const_defined?(:UPDATABLE_ATTRS_ON_TRANSITION)
157

  
158
  def edit_gantt
159
    date_from = Date.parse(params[:date_from])
160
    if params[:day]
161
      #bar moved
162
      day = params[:day].to_i
163
      duration = @issue.due_date - @issue.start_date
164
      @issue.start_date = date_from + day
165
      @issue.due_date = @issue.start_date + duration.to_i
166
    elsif params[:start_date]
167
      #start date changed
168
      start_date = Date.parse(params[:start_date])
169
      @issue.start_date = start_date
170
      @issue.due_date = start_date if start_date > @issue.due_date
171
    elsif params[:due_date]
172
      #due date changed
173
      due_date = Date.parse(params[:due_date])
174
      @issue.due_date = due_date
175
      @issue.start_date = due_date if due_date < @issue.start_date
176
    end
177
    @issue.save!
178
    
179
    o = get_position(@issue, date_from, Date.parse(params[:date_to]), params[:zoom])
180
    render :text=>"#{format_date(@issue.start_date)},#{format_date(@issue.due_date)},#{o[0]},#{o[1]},#{o[2]},#{o[3]}"
181
  end
157 182
  
158 183
  def edit
159 184
    @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
app/helpers/issues_helper.rb (working copy)
27 27
    @cached_label_priority ||= l(:field_priority)
28 28
    
29 29
    link_to_issue(issue) + ": #{h(issue.subject)}<br /><br />" +
30
      "<strong>#{@cached_label_start_date}</strong>: #{format_date(issue.start_date)}<br />" +
31
      "<strong>#{@cached_label_due_date}</strong>: #{format_date(issue.due_date)}<br />" +
30
      "<strong>#{@cached_label_start_date}</strong>: <span id='tooltip_start_date_#{issue.id}'>#{format_date(issue.start_date)}</span><br />" +
31
      "<strong>#{@cached_label_due_date}</strong>: <span id='tooltip_due_date_#{issue.id}'>#{format_date(issue.due_date)}</span><br />" +
32 32
      "<strong>#{@cached_label_assigned_to}</strong>: #{issue.assigned_to}<br />" +
33 33
      "<strong>#{@cached_label_priority}</strong>: #{issue.priority.name}"
34 34
  end
......
185 185
    export.rewind
186 186
    export
187 187
  end
188

  
189
  def get_position(event, date_from, date_to, zoom_str)
190
    zoom = zoom_str.to_i
191
    i_start_date = (event.start_date >= date_from ? event.start_date : date_from )
192
    i_end_date = (event.due_date <= date_to ? event.due_date : date_to )
193

  
194
    i_done_date = event.start_date + ((event.due_date - event.start_date+1)*event.done_ratio/100).floor
195
    i_done_date = (i_done_date <= date_from ? date_from : i_done_date )
196
    i_done_date = (i_done_date >= date_to ? date_to : i_done_date )
197

  
198
    i_late_date = [i_end_date, Date.today].min if i_start_date < Date.today
199

  
200
    i_left = ((i_start_date - date_from)*zoom).floor 	
201
    i_left = 0 if i_left < 0
202
    i_width = ((i_end_date - i_start_date + 1)*zoom).floor - 2                  # total width of the issue (- 2 for left and right borders)
203
    i_width = 0 if i_width < 0
204
    d_width = ((i_done_date - i_start_date)*zoom).floor - 2                     # done width
205
    d_width = 0 if d_width < 0
206
    l_width = i_late_date ? ((i_late_date - i_start_date+1)*zoom).floor - 2 : 0 # delay width
207
    l_width = 0 if l_width < 0
208
    return i_left, i_width, l_width, d_width
209
  end
188 210
end
app/views/issues/gantt.rhtml (working copy)
49 49
<% zoom = 1
50 50
@gantt.zoom.times { zoom = zoom * 2 }
51 51

  
52
subject_width = 330
52
subject_width = 280
53 53
header_heigth = 18
54 54

  
55 55
headers_height = header_heigth
......
70 70
t_height = g_height + headers_height
71 71
%>
72 72

  
73
<script type='text/javascript'>
74
<!-- 
75
  function issue_moved(elem) {
76
    id_str = elem.id.substring(3, elem.id.length);
77
    url_str = '/issues/edit_gantt/' + id_str;
78
    day = parseInt(elem.style.left)/parseInt(<%=zoom%>);
79
    new Ajax.Request(url_str, {asynchronous:true, evalScripts:true, 
80
      parameters: 'day='+day+'&date_from=<%=@gantt.date_from.strftime("%Y-%m-%d")%>&date_to=<%=@gantt.date_to.strftime("%Y-%m-%d")%>&zoom=<%=zoom%>',
81
      onSuccess:function(obj) {
82
        change_date(id_str, obj.responseText);
83
      }
84
    });
85
    
86
  }
87
  function change_date(elem_id, text) {
88
    vals = text.split(',');
89
    start_date_elem = document.getElementById(elem_id + '_start_date_str');
90
    start_date_elem.innerHTML = vals[0];
91
    tooltip_start_date_elem = document.getElementById('tooltip_start_date_' + elem_id);
92
    tooltip_start_date_elem.innerHTML = vals[0];
93
    due_date_elem = document.getElementById(elem_id + '_due_date_str');
94
    due_date_elem.innerHTML = vals[1];
95
    tooltip_due_date_elem = document.getElementById('tooltip_due_date_' + elem_id);
96
    tooltip_due_date_elem.innerHTML = vals[1];
97
    
98
    ev_elem = document.getElementById('ev_' + elem_id);
99
    ev_elem.style.left = vals[2] + 'px';
100
    ev_elem.style.width = (parseInt(vals[3])+100)+'px';
101
    todo_elem = document.getElementById('task_todo_' + elem_id);
102
    todo_elem.style.width = vals[3] + 'px';
103
    late_elem = document.getElementById('task_late_' + elem_id);
104
    if (late_elem) {
105
      late_elem.style.width = vals[4] + 'px';
106
    }
107
    done_elem = document.getElementById('task_done_' + elem_id);
108
    if (done_elem) {
109
      done_elem.style.width = vals[5] + 'px';
110
    }
111
    task_elem = document.getElementById('task_task_' + elem_id);
112
    if (task_elem) {
113
      task_elem.style.left = (parseInt(vals[3])+5) + 'px';
114
    }
115
    tooltip = document.getElementById("tt_" + id_str);
116
    tooltip.style.left = ev_elem.style.left;
117
    tooltip.style.width = todo_elem.style.width;
118
  }
119
// -->
120
</script> 
121

  
73 122
<table width="100%" style="border:0; border-collapse: collapse;">
74 123
<tr>
75 124
<td style="width:<%= subject_width %>px; padding:0px;">
......
98 147
end %>
99 148
</div>
100 149
</td>
150
<td style="width:225px; padding:0px;">
151
<div style="position:relative;height:<%= t_height + 24 %>px;width:225px;">
152
<div style="width:225px;height:<%= headers_height %>px;background: #eee;" class="gantt_hdr"></div>
153
<div style="width:225px;height:<%= t_height %>px;border-left: 1px solid #c0c0c0;overflow:hidden;" class="gantt_hdr"></div>
154
<%
155
top = headers_height + 8
156
@gantt.events.each do |i| %>
157
  <div style="position: absolute;line-height:1.2em;height:16px;top:<%= top %>px;"><small>
158
    <span id="<%=i.id%>_start_date_str" style="font-size: 7pt;"><%= format_date(i.start_date) %></span>
159
    <input type="hidden" size="12" id="<%=i.id%>_start_date" value="<%= i.start_date %>"><%= calendar_for("#{i.id}_start_date") if i.is_a? Issue %>
160
    <%= observe_field "#{i.id}_start_date", 
161
          :url => { :controller=>:issues, :action => :edit_gantt, :id=>i.id, 
162
          :date_from=>@gantt.date_from.strftime("%Y-%m-%d"), :date_to=>@gantt.date_to.strftime("%Y-%m-%d"), :zoom=>zoom },
163
          :frequency => 0.25,
164
          :with => 'start_date',
165
          :success=>"change_date('#{i.id}', request.responseText)",
166
          :failure=>"alert('Error! See the log')"
167
    %>
168
    <% if i.is_a? Issue %>
169
    <span id="<%=i.id%>_due_date_str" style="font-size: 7pt;"><%= format_date(i.due_date) %></span>
170
    <input type="hidden" size="12" id="<%=i.id%>_due_date" value="<%= i.due_date %>"><%= calendar_for("#{i.id}_due_date") %>
171
      <%= observe_field "#{i.id}_due_date", 
172
          :url => { :controller=>:issues, :action => :edit_gantt, :id=>i.id, 
173
          :date_from=>@gantt.date_from.strftime("%Y-%m-%d"), :date_to=>@gantt.date_to.strftime("%Y-%m-%d"), :zoom=>zoom },
174
          :frequency => 0.25,
175
          :with => 'due_date',
176
          :success=>"change_date('#{i.id}', request.responseText)",
177
          :failure=>"alert('Error! See the log')"
178
      %>
179
    <% end %>
180
  </small></div>
181
<% top = top + 20
182
end %>
183
</div>
184
</td>
101 185
<td>
102 186

  
103
<div style="position:relative;height:<%= t_height + 24 %>px;overflow:auto;">
187
<div style="position:relative;height:<%= t_height + 24 %>px;overflow:auto;" id="gantt-container">
104 188
<div style="width:<%= g_width-1 %>px;height:<%= headers_height %>px;background: #eee;" class="gantt_hdr">&nbsp;</div>
105 189
<% 
106 190
#
......
160 244
	left = 0
161 245
	height = g_height + header_heigth - 1
162 246
	wday = @gantt.date_from.cwday
247
  dt = @gantt.date_from
163 248
	(@gantt.date_to - @gantt.date_from + 1).to_i.times do 
164 249
	width =  zoom - 1
165 250
	%>
166 251
	<div style="left:<%= left %>px;top:37px;width:<%= width %>px;height:<%= height %>px;font-size:0.7em;<%= "background:#f1f1f1;" if wday > 5 %>" class="gantt_hdr">
167
	<%= day_name(wday).first %>
252
	<%=  "#{dt.day}<br>"if @gantt.zoom == 4 %><%= day_name(wday).first %>
168 253
	</div>
169 254
	<% 
170 255
	left = left + width+1
171 256
	wday = wday + 1
257
  dt = dt + 1
172 258
	wday = 1 if wday > 7
173 259
	end
174 260
end %>
......
180 266
top = headers_height + 10
181 267
@gantt.events.each do |i| 
182 268
  if i.is_a? Issue 
183
	i_start_date = (i.start_date >= @gantt.date_from ? i.start_date : @gantt.date_from )
184
	i_end_date = (i.due_before <= @gantt.date_to ? i.due_before : @gantt.date_to )
185
	
186
	i_done_date = i.start_date + ((i.due_before - i.start_date+1)*i.done_ratio/100).floor
187
	i_done_date = (i_done_date <= @gantt.date_from ? @gantt.date_from : i_done_date )
188
	i_done_date = (i_done_date >= @gantt.date_to ? @gantt.date_to : i_done_date )
189
	
190
	i_late_date = [i_end_date, Date.today].min if i_start_date < Date.today
191
	
192
	i_left = ((i_start_date - @gantt.date_from)*zoom).floor 	
193
	i_width = ((i_end_date - i_start_date + 1)*zoom).floor - 2                  # total width of the issue (- 2 for left and right borders)
194
	d_width = ((i_done_date - i_start_date)*zoom).floor - 2                     # done width
195
	l_width = i_late_date ? ((i_late_date - i_start_date+1)*zoom).floor - 2 : 0 # delay width
269
    i_left, i_width, l_width, d_width = get_position(i, @gantt.date_from, @gantt.date_to, zoom)
196 270
	%>
197
	<div style="top:<%= top %>px;left:<%= i_left %>px;width:<%= i_width %>px;" class="task task_todo">&nbsp;</div>
198
	<% if l_width > 0 %>
199
	    <div style="top:<%= top %>px;left:<%= i_left %>px;width:<%= l_width %>px;" class="task task_late">&nbsp;</div>
200
	<% end %>
201
	<% if d_width > 0 %>
202
	    <div style="top:<%= top %>px;left:<%= i_left %>px;width:<%= d_width %>px;" class="task task_done">&nbsp;</div>
203
	<% end %>
204
	<div style="top:<%= top %>px;left:<%= i_left + i_width + 5 %>px;background:#fff;" class="task">
205
	<%= i.status.name %>
206
	<%= (i.done_ratio).to_i %>%
207
	</div>
208
	<div class="tooltip" style="position: absolute;top:<%= top %>px;left:<%= i_left %>px;width:<%= i_width %>px;height:12px;">
209
	<span class="tip">
271
  <div id="ev_<%=i.id%>" style="position:absolute;left:<%= i_left %>px;top:<%= top %>px;padding-top:3px;height:18px;width:<%= i_width+100 %>px;" class="handle">
272
    <div id="task_todo_<%=i.id%>" style="float:left; width:<%= i_width %>px;" class="task task_todo">&nbsp;</div>
273
    <% if l_width > 0 %>
274
      <div id="task_late_<%=i.id%>" style="float:left; width:<%= l_width %>px;" class="task task_late">&nbsp;</div>
275
    <% end %>
276
    <% if d_width > 0 %>
277
      <div id="task_done_<%=i.id%>" style="float:left; width:<%= d_width %>px;" class="task task_done">&nbsp;</div>
278
    <% end %>
279
    <div id="task_task_<%=i.id%>" style="position:absolute;left:<%= (i_width + 5) %>px;background:#fff;" class="task">
280
    <%= i.status.name %>
281
    <%= (i.done_ratio).to_i %>%
282
    </div>
283
  </div>
284
	<% # === tooltip === %>
285
	<div id="tt_<%=i.id%>" class="tooltip" style="position: absolute;top:<%= top+14 %>px;left:<%= i_left %>px;width:<%= i_width %>px;height:8px;">
286
	<span class="tip" style="position: relative;top:-2px;">
210 287
    <%= render_issue_tooltip i %>
211 288
	</span></div>
289
  <%= draggable_element("ev_#{i.id}",  
290
    :revert =>false, :scroll=>"'gantt-container'", :constraint => "'horizontal'", :snap=>zoom,
291
       :onEnd=>"function( draggable, event )  {issue_moved(draggable.element);}"
292
    ) %>
293

  
212 294
<% else 
213 295
    i_left = ((i.start_date - @gantt.date_from)*zoom).floor
214 296
    %>
215
    <div style="top:<%= top %>px;left:<%= i_left %>px;width:15px;" class="task milestone">&nbsp;</div>
297
  <div style="top:<%= top %>px;left:<%= i_left %>px;width:15px;" class="task milestone">&nbsp;</div>
216 298
	<div style="top:<%= top %>px;left:<%= i_left + 12 %>px;background:#fff;" class="task">
217 299
		<%= h("#{i.project} -") unless @project && @project == i.project %>
218 300
		<strong><%=h i %></strong>
(1-1/35)