|
1 |
<% include_calendar_headers_tags %>
|
1 |
2 |
<% form_tag(params.merge(:month => nil, :year => nil, :months => nil), :id => 'query_form') do %>
|
2 |
3 |
<% if @query.new_record? %>
|
3 |
4 |
<h2><%=l(:label_gantt)%></h2>
|
... | ... | |
31 |
32 |
</p>
|
32 |
33 |
|
33 |
34 |
<p class="buttons">
|
34 |
|
<%= link_to_remote l(:button_apply),
|
|
35 |
<%= link_to_remote l(:button_apply),
|
35 |
36 |
{ :url => { :set_filter => (@query.new_record? ? 1 : nil) },
|
36 |
37 |
:update => "content",
|
37 |
38 |
:with => "Form.serialize('query_form')"
|
38 |
39 |
}, :class => 'icon icon-checked' %>
|
39 |
|
|
|
40 |
|
40 |
41 |
<%= link_to_remote l(:button_clear),
|
41 |
|
{ :url => { :set_filter => (@query.new_record? ? 1 : nil) },
|
|
42 |
{ :url => { :set_filter => (@query.new_record? ? 1 : nil) },
|
42 |
43 |
:update => "content",
|
43 |
44 |
}, :class => 'icon icon-reload' if @query.new_record? %>
|
44 |
45 |
</p>
|
... | ... | |
49 |
50 |
<% zoom = 1
|
50 |
51 |
@gantt.zoom.times { zoom = zoom * 2 }
|
51 |
52 |
|
52 |
|
subject_width = 330
|
|
53 |
subject_width = 280
|
53 |
54 |
header_heigth = 18
|
54 |
55 |
|
55 |
56 |
headers_height = header_heigth
|
... | ... | |
69 |
70 |
g_height = [(20 * @gantt.events.length + 6)+150, 206].max
|
70 |
71 |
t_height = g_height + headers_height
|
71 |
72 |
%>
|
|
73 |
<input type="hidden" name="_date_from" id="i_date_from" value="<%=h(@gantt.date_from)%>" />
|
|
74 |
<input type="hidden" name="_date_to" id="i_date_to" value="<%=h(@gantt.date_to)%>" />
|
|
75 |
<input type="hidden" name="zm" id="i_zm" value="<%=h(zoom)%>" />
|
|
76 |
<script type='text/javascript'>
|
|
77 |
function issue_moved(elem) {
|
|
78 |
var id_str = elem.id.substring(3, elem.id.length);
|
|
79 |
var v_date_from = document.getElementById('i_date_from').getAttribute("value");
|
|
80 |
var v_date_to = document.getElementById('i_date_to').getAttribute("value");
|
|
81 |
var v_zm = document.getElementById('i_zm').getAttribute("value");
|
|
82 |
var url_str = '/issues/edit_gantt/' + id_str;
|
|
83 |
var day = parseInt(elem.style.left)/parseInt(v_zm);
|
|
84 |
new Ajax.Request(url_str, {asynchronous:true, evalScripts:true,
|
|
85 |
parameters: 'day='+day+'&date_from='+v_date_from+'&date_to='+v_date_to+'&zoom='+v_zm,
|
|
86 |
onSuccess:function(obj) {
|
|
87 |
change_dates(obj.responseText);
|
|
88 |
},
|
|
89 |
onFailure:function(obj) {
|
|
90 |
handle_failure(obj.responseText);
|
|
91 |
}
|
|
92 |
});
|
72 |
93 |
|
|
94 |
}
|
|
95 |
|
|
96 |
function handle_failure(res_text) {
|
|
97 |
var text = res_text.split('|');
|
|
98 |
alert(text[0]);
|
|
99 |
if (text.length == 1) {
|
|
100 |
return;
|
|
101 |
}
|
|
102 |
change_dates(text[1]);//revert
|
|
103 |
}
|
|
104 |
|
|
105 |
function change_dates(issue_infos) {
|
|
106 |
if (!issue_infos) {
|
|
107 |
return;
|
|
108 |
}
|
|
109 |
var issue_list = issue_infos.split("|");
|
|
110 |
for (i = 0; i < issue_list.length; i++) {
|
|
111 |
change_date(issue_list[i]);
|
|
112 |
}
|
|
113 |
}
|
|
114 |
|
|
115 |
function change_date(text) {
|
|
116 |
if (!text) {
|
|
117 |
return;
|
|
118 |
}
|
|
119 |
var issue_info = text.split("=");
|
|
120 |
var elem_id = issue_info[0];
|
|
121 |
var vals = issue_info[1].split(',');
|
|
122 |
var start_date_elem = document.getElementById(elem_id + '_start_date_str');
|
|
123 |
if (!start_date_elem) {
|
|
124 |
//target not exists
|
|
125 |
return;
|
|
126 |
}
|
|
127 |
start_date_elem.innerHTML = vals[0];
|
|
128 |
var tooltip_start_date_elem = document.getElementById('tooltip_start_date_' + elem_id);
|
|
129 |
tooltip_start_date_elem.innerHTML = vals[0];
|
|
130 |
var due_date_elem = document.getElementById(elem_id + '_due_date_str');
|
|
131 |
due_date_elem.innerHTML = vals[2];
|
|
132 |
var tooltip_due_date_elem = document.getElementById('tooltip_due_date_' + elem_id);
|
|
133 |
tooltip_due_date_elem.innerHTML = vals[2];
|
|
134 |
|
|
135 |
var ev_elem = document.getElementById('ev_' + elem_id);
|
|
136 |
ev_elem.style.left = vals[4] + 'px';
|
|
137 |
ev_elem.style.width = (parseInt(vals[5])+100)+'px';
|
|
138 |
var todo_elem = document.getElementById('task_todo_' + elem_id);
|
|
139 |
todo_elem.style.width = vals[5] + 'px';
|
|
140 |
var late_elem = document.getElementById('task_late_' + elem_id);
|
|
141 |
if (late_elem) {
|
|
142 |
late_elem.style.width = vals[6] + 'px';
|
|
143 |
if (vals[6] == '0') {
|
|
144 |
late_elem.className = 'task task_none';
|
|
145 |
} else {
|
|
146 |
late_elem.className = 'task task_late';
|
|
147 |
}
|
|
148 |
}
|
|
149 |
var done_elem = document.getElementById('task_done_' + elem_id);
|
|
150 |
if (done_elem) {
|
|
151 |
done_elem.style.width = vals[7] + 'px';
|
|
152 |
if (vals[7] == '0') {
|
|
153 |
done_elem.className = 'task task_none';
|
|
154 |
} else {
|
|
155 |
done_elem.className = 'task task_done';
|
|
156 |
}
|
|
157 |
}
|
|
158 |
var task_elem = document.getElementById('task_task_' + elem_id);
|
|
159 |
if (task_elem) {
|
|
160 |
task_elem.style.left = (parseInt(vals[5])+5) + 'px';
|
|
161 |
}
|
|
162 |
var tooltip = document.getElementById("tt_" + elem_id);
|
|
163 |
tooltip.style.left = ev_elem.style.left;
|
|
164 |
|
|
165 |
//change calendar date
|
|
166 |
document.getElementById(elem_id+"_hidden_start_date").value = vals[1];
|
|
167 |
document.getElementById(elem_id+"_start_date").value = vals[1];
|
|
168 |
document.getElementById(elem_id+"_hidden_due_date").value = vals[3];
|
|
169 |
document.getElementById(elem_id+"_due_date").value = vals[3];
|
|
170 |
}
|
|
171 |
</script>
|
|
172 |
|
73 |
173 |
<table width="100%" style="border:0; border-collapse: collapse;">
|
74 |
174 |
<tr>
|
75 |
175 |
<td style="width:<%= subject_width %>px; padding:0px;">
|
... | ... | |
83 |
183 |
#
|
84 |
184 |
top = headers_height + 8
|
85 |
185 |
@gantt.events.each do |i| %>
|
86 |
|
<div style="position: absolute;line-height:1.2em;height:16px;top:<%= top %>px;left:4px;overflow:hidden;"><small>
|
|
186 |
<div style="position: absolute;line-height:1.2em;height:16px;top:<%= top %>px;left:4px;overflow:hidden;"><small>
|
87 |
187 |
<% if i.is_a? Issue %>
|
88 |
188 |
<%= h("#{i.project} -") unless @project && @project == i.project %>
|
89 |
189 |
<%= link_to_issue i %>: <%=h i.subject %>
|
... | ... | |
92 |
192 |
<%= h("#{i.project} -") unless @project && @project == i.project %>
|
93 |
193 |
<%= link_to_version i %>
|
94 |
194 |
</span>
|
95 |
|
<% end %>
|
|
195 |
<% end %>
|
96 |
196 |
</small></div>
|
97 |
197 |
<% top = top + 20
|
98 |
198 |
end %>
|
99 |
199 |
</div>
|
100 |
200 |
</td>
|
|
201 |
<td style="width:225px; padding:0px;">
|
|
202 |
<div style="position:relative;height:<%= t_height + 24 %>px;width:225px;">
|
|
203 |
<div style="width:225px;height:<%= headers_height %>px;background: #eee;" class="gantt_hdr"></div>
|
|
204 |
<div style="width:225px;height:<%= t_height %>px;border-left: 1px solid #c0c0c0;overflow:hidden;" class="gantt_hdr"></div>
|
|
205 |
<%
|
|
206 |
top = headers_height + 8
|
|
207 |
@gantt.events.each do |i| %>
|
|
208 |
<div style="position: absolute;line-height:1.2em;height:16px;top:<%= top %>px;"><small>
|
|
209 |
<% if i.is_a? Issue %>
|
|
210 |
<span id="<%=i.id%>_start_date_str" style="font-size: 7pt;"><%= format_date(i.start_date) %></span>
|
|
211 |
<input type="hidden" size="12" id="<%=i.id%>_hidden_start_date" value="<%= i.start_date %>">
|
|
212 |
<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 %>
|
|
213 |
<script type="text/javascript">
|
|
214 |
//<![CDATA[
|
|
215 |
new Form.Element.Observer('<%=i.id%>_start_date', 0.25,
|
|
216 |
function(element, value) {
|
|
217 |
if (value == document.getElementById('<%=i.id%>_hidden_start_date').value) {
|
|
218 |
return ;
|
|
219 |
}
|
|
220 |
new Ajax.Request('<%=url_for(:controller=>:issues, :action => :edit_gantt, :id=>i.id, :date_from=>@gantt.date_from.strftime("%Y-%m-%d"), :date_to=>@gantt.date_to.strftime("%Y-%m-%d"), :zoom=>zoom, :escape => false) %>', {asynchronous:true, evalScripts:true, onFailure:function(request){handle_failure(request.responseText)}, onSuccess:function(request){change_dates(request.responseText)}, parameters:'start_date=' + encodeURIComponent(value)});
|
|
221 |
})
|
|
222 |
//]]>
|
|
223 |
</script>
|
|
224 |
<span id="<%=i.id%>_due_date_str" style="font-size: 7pt;<%= "color: blue;" unless i.due_date%>">
|
|
225 |
<%= format_date(i.due_before) %>
|
|
226 |
</span>
|
|
227 |
<input type="hidden" size="12" id="<%=i.id%>_hidden_due_date" value="<%= i.due_date %>">
|
|
228 |
<input type="hidden" size="12" id="<%=i.id%>_due_date" value="<%= i.due_date %>"><%= calendar_for("#{i.id}_due_date") if i.due_date%>
|
|
229 |
<script type="text/javascript">
|
|
230 |
//<![CDATA[
|
|
231 |
new Form.Element.Observer('<%=i.id%>_due_date', 0.25,
|
|
232 |
function(element, value) {
|
|
233 |
if (value == document.getElementById('<%=i.id%>_hidden_due_date').value) {
|
|
234 |
return ;
|
|
235 |
}
|
|
236 |
new Ajax.Request('<%=url_for(:controller=>:issues, :action => :edit_gantt, :id=>i.id, :date_from=>@gantt.date_from.strftime("%Y-%m-%d"), :date_to=>@gantt.date_to.strftime("%Y-%m-%d"), :zoom=>zoom, :escape => false) %>', {asynchronous:true, evalScripts:true, onFailure:function(request){handle_failure(request.responseText)}, onSuccess:function(request){change_dates(request.responseText)}, parameters:'due_date=' + encodeURIComponent(value)});
|
|
237 |
})
|
|
238 |
//]]>
|
|
239 |
</script>
|
|
240 |
<% else %>
|
|
241 |
<span style="font-size: 7pt;"><%= format_date(i.start_date) %></span>
|
|
242 |
<% end %>
|
|
243 |
</small></div>
|
|
244 |
<% top = top + 20
|
|
245 |
end %>
|
|
246 |
</div>
|
|
247 |
</td>
|
101 |
248 |
<td>
|
102 |
249 |
|
103 |
|
<div style="position:relative;height:<%= t_height + 24 %>px;overflow:auto;">
|
|
250 |
<div style="position:relative;height:<%= t_height + 24 %>px;overflow:auto;" id="gantt-container">
|
104 |
251 |
<div style="width:<%= g_width-1 %>px;height:<%= headers_height %>px;background: #eee;" class="gantt_hdr"> </div>
|
105 |
|
<%
|
|
252 |
<%
|
106 |
253 |
#
|
107 |
254 |
# Months headers
|
108 |
255 |
#
|
109 |
256 |
month_f = @gantt.date_from
|
110 |
257 |
left = 0
|
111 |
258 |
height = (show_weeks ? header_heigth : header_heigth + g_height)
|
112 |
|
@gantt.months.times do
|
|
259 |
@gantt.months.times do
|
113 |
260 |
width = ((month_f >> 1) - month_f) * zoom - 1
|
114 |
261 |
%>
|
115 |
262 |
<div style="left:<%= left %>px;width:<%= width %>px;height:<%= height %>px;" class="gantt_hdr">
|
116 |
263 |
<%= link_to "#{month_f.year}-#{month_f.month}", @gantt.params.merge(:year => month_f.year, :month => month_f.month), :title => "#{month_name(month_f.month)} #{month_f.year}"%>
|
117 |
264 |
</div>
|
118 |
|
<%
|
|
265 |
<%
|
119 |
266 |
left = left + width + 1
|
120 |
267 |
month_f = month_f >> 1
|
121 |
268 |
end %>
|
122 |
269 |
|
123 |
|
<%
|
|
270 |
<%
|
124 |
271 |
#
|
125 |
272 |
# Weeks headers
|
126 |
273 |
#
|
... | ... | |
136 |
283 |
width = (7 - @gantt.date_from.cwday + 1) * zoom-1
|
137 |
284 |
%>
|
138 |
285 |
<div style="left:<%= left %>px;top:19px;width:<%= width %>px;height:<%= height %>px;" class="gantt_hdr"> </div>
|
139 |
|
<%
|
|
286 |
<%
|
140 |
287 |
left = left + width+1
|
141 |
288 |
end %>
|
142 |
289 |
<%
|
... | ... | |
146 |
293 |
<div style="left:<%= left %>px;top:19px;width:<%= width %>px;height:<%= height %>px;" class="gantt_hdr">
|
147 |
294 |
<small><%= week_f.cweek if width >= 16 %></small>
|
148 |
295 |
</div>
|
149 |
|
<%
|
|
296 |
<%
|
150 |
297 |
left = left + width+1
|
151 |
298 |
week_f = week_f+7
|
152 |
299 |
end
|
153 |
300 |
end %>
|
154 |
301 |
|
155 |
|
<%
|
|
302 |
<%
|
156 |
303 |
#
|
157 |
304 |
# Days headers
|
158 |
305 |
#
|
... | ... | |
160 |
307 |
left = 0
|
161 |
308 |
height = g_height + header_heigth - 1
|
162 |
309 |
wday = @gantt.date_from.cwday
|
163 |
|
(@gantt.date_to - @gantt.date_from + 1).to_i.times do
|
|
310 |
dt = @gantt.date_from
|
|
311 |
(@gantt.date_to - @gantt.date_from + 1).to_i.times do
|
164 |
312 |
width = zoom - 1
|
165 |
313 |
%>
|
166 |
314 |
<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 %>
|
|
315 |
<%= "#{dt.day}<br>"if @gantt.zoom == 4 %><%= day_name(wday).first %>
|
168 |
316 |
</div>
|
169 |
|
<%
|
|
317 |
<%
|
170 |
318 |
left = left + width+1
|
171 |
319 |
wday = wday + 1
|
|
320 |
dt = dt + 1
|
172 |
321 |
wday = 1 if wday > 7
|
173 |
322 |
end
|
174 |
323 |
end %>
|
... | ... | |
178 |
327 |
# Tasks
|
179 |
328 |
#
|
180 |
329 |
top = headers_height + 10
|
181 |
|
@gantt.events.each do |i|
|
182 |
|
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
|
|
330 |
@gantt.events.each do |i|
|
|
331 |
if i.is_a? Issue
|
|
332 |
i_left, i_width, l_width, d_width = get_position(i, @gantt.date_from, @gantt.date_to, zoom)
|
196 |
333 |
%>
|
197 |
|
<div style="top:<%= top %>px;left:<%= i_left %>px;width:<%= i_width %>px;" class="task task_todo"> </div>
|
198 |
|
<% if l_width > 0 %>
|
199 |
|
<div style="top:<%= top %>px;left:<%= i_left %>px;width:<%= l_width %>px;" class="task task_late"> </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"> </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">
|
|
334 |
<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">
|
|
335 |
<div id="task_todo_<%=i.id%>" style="float:left:0px; width:<%= i_width %>px;" class="task task_todo"> </div>
|
|
336 |
<div id="task_late_<%=i.id%>" style="float:left:0px; width:<%= l_width %>px;" class="<%= l_width == 0 ? 'task task_none' : 'task task_late' %>"> </div>
|
|
337 |
<div id="task_done_<%=i.id%>" style="float:left:0px; width:<%= d_width %>px;" class="<%= d_width == 0 ? 'task task_none' : 'task task_done' %>"> </div>
|
|
338 |
<div id="task_task_<%=i.id%>" style="position:absolute;left:<%= (i_width + 5) %>px;background:#fff;" class="task">
|
|
339 |
<%= h(i.status.name) %>
|
|
340 |
<%= (i.done_ratio).to_i %>%
|
|
341 |
<% if !i.due_date && i.fixed_version %>
|
|
342 |
- <strong><%= h(i.fixed_version.name) %></strong>
|
|
343 |
<% end %>
|
|
344 |
</div>
|
|
345 |
</div>
|
|
346 |
<% # === tooltip === %>
|
|
347 |
<div id="tt_<%=i.id%>" class="tooltip" style="position: absolute;top:<%= top+14 %>px;left:<%= i_left %>px;width:<%= i_width %>px;height:8px;">
|
|
348 |
<span class="tip" style="position: relative;top:-2px;">
|
210 |
349 |
<%= render_issue_tooltip i %>
|
211 |
350 |
</span></div>
|
212 |
|
<% else
|
|
351 |
<%= draggable_element("ev_#{i.id}",
|
|
352 |
:revert =>false, :scroll=>"'gantt-container'", :constraint => "'horizontal'", :snap=>zoom,
|
|
353 |
:onEnd=>"function( draggable, event ) {issue_moved(draggable.element);}"
|
|
354 |
) %>
|
|
355 |
|
|
356 |
<% else
|
213 |
357 |
i_left = ((i.start_date - @gantt.date_from)*zoom).floor
|
214 |
358 |
%>
|
215 |
|
<div style="top:<%= top %>px;left:<%= i_left %>px;width:15px;" class="task milestone"> </div>
|
|
359 |
<div style="top:<%= top %>px;left:<%= i_left %>px;width:15px;" class="task milestone"> </div>
|
216 |
360 |
<div style="top:<%= top %>px;left:<%= i_left + 12 %>px;background:#fff;" class="task">
|
217 |
361 |
<%= h("#{i.project} -") unless @project && @project == i.project %>
|
218 |
362 |
<strong><%=h i %></strong>
|