Feature #2024 » gantt_edit_r3764.patch
app/controllers/gantts_controller.rb (working copy) | ||
---|---|---|
1 | 1 |
class GanttsController < ApplicationController |
2 | 2 |
before_filter :find_optional_project |
3 |
before_filter :find_issue, :only => [:edit_gantt] |
|
3 | 4 | |
4 | 5 |
rescue_from Query::StatementInvalid, :with => :query_statement_invalid |
5 | 6 | |
... | ... | |
10 | 11 |
helper :sort |
11 | 12 |
include SortHelper |
12 | 13 |
include Redmine::Export::PDF |
14 |
include IssuesHelper |
|
13 | 15 |
|
14 | 16 |
def show |
15 | 17 |
@gantt = Redmine::Helpers::Gantt.new(params) |
... | ... | |
42 | 44 |
end |
43 | 45 |
end |
44 | 46 | |
47 |
def find_optional_project |
|
48 |
@project = Project.find(params[:project_id]) unless params[:project_id].blank? |
|
49 |
if params[:action] == "edit_gantt" |
|
50 |
allowed = User.current.allowed_to?({:controller => 'issues', :action => 'edit'}, @project, :global => true) |
|
51 |
else |
|
52 |
allowed = User.current.allowed_to?({:controller => params[:controller], :action => params[:action]}, @project, :global => true) |
|
53 |
end |
|
54 |
allowed ? true : deny_access |
|
55 |
rescue ActiveRecord::RecordNotFound |
|
56 |
render_404 |
|
57 |
end |
|
58 | ||
59 |
def edit_gantt |
|
60 |
if !@issue.start_date || !@issue.due_before |
|
61 |
render :text=>l(:notice_locking_conflict), :status=>400 |
|
62 |
return |
|
63 |
end |
|
64 |
@issue.init_journal(User.current) |
|
65 |
date_from = Date.parse(params[:date_from]) |
|
66 |
old_start_date = @issue.start_date |
|
67 |
o = get_position(@issue, date_from, Date.parse(params[:date_to]), params[:zoom]) |
|
68 |
text_for_revert = "#{@issue.id}=#{format_date(@issue.start_date)},#{@issue.start_date},#{format_date(@issue.due_before)},#{@issue.due_before},#{o[0]},#{o[1]},#{o[2]},#{o[3]}" |
|
69 | ||
70 |
if params[:day] |
|
71 |
#bar moved |
|
72 |
day = params[:day].to_i |
|
73 |
duration = @issue.due_before - @issue.start_date |
|
74 |
@issue.start_date = date_from + day |
|
75 |
@issue.due_date = @issue.start_date + duration.to_i if @issue.due_date |
|
76 |
elsif params[:start_date] |
|
77 |
#start date changed |
|
78 |
start_date = Date.parse(params[:start_date]) |
|
79 |
if @issue.start_date == start_date |
|
80 |
render :text=>"" |
|
81 |
return #nothing has changed |
|
82 |
end |
|
83 |
@issue.start_date = start_date |
|
84 |
@issue.due_date = start_date if @issue.due_date && start_date > @issue.due_date |
|
85 |
elsif params[:due_date] |
|
86 |
#due date changed |
|
87 |
due_date = Date.parse(params[:due_date]) |
|
88 |
if @issue.due_date == due_date |
|
89 |
render :text=>"" |
|
90 |
return #nothing has changed |
|
91 |
end |
|
92 |
@issue.due_date = due_date |
|
93 |
@issue.start_date = due_date if due_date < @issue.start_date |
|
94 |
end |
|
95 |
fv = @issue.fixed_version |
|
96 |
if fv && fv.effective_date && !@issue.due_date && fv.effective_date < @issue.start_date |
|
97 |
@issue.start_date = old_start_date |
|
98 |
end |
|
99 | ||
100 |
begin |
|
101 |
@issue.save! |
|
102 |
o = get_position(@issue, date_from, Date.parse(params[:date_to]), params[:zoom]) |
|
103 |
text = "#{@issue.id}=#{format_date(@issue.start_date)},#{@issue.start_date},#{format_date(@issue.due_before)},#{@issue.due_before},#{o[0]},#{o[1]},#{o[2]},#{o[3]}" |
|
104 | ||
105 |
#check dependencies |
|
106 |
issues = @issue.all_precedes_issues |
|
107 |
issues.each do |i| |
|
108 |
o = get_position(i, date_from, Date.parse(params[:date_to]), params[:zoom]) |
|
109 |
text += "|#{i.id}=#{format_date(i.start_date)},#{i.start_date},#{format_date(i.due_before)},#{i.due_before},#{o[0]},#{o[1]},#{o[2]},#{o[3]}" |
|
110 |
end |
|
111 |
render :text=>text |
|
112 |
rescue |
|
113 |
render :text=>@issue.errors.full_messages.join("\n") + "|" + text_for_revert , :status=>400 |
|
114 |
end |
|
115 |
end |
|
116 | ||
117 |
private |
|
118 |
def find_issue |
|
119 |
@issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category]) |
|
120 |
@project = @issue.project |
|
121 |
rescue ActiveRecord::RecordNotFound |
|
122 |
render_404 |
|
123 |
end |
|
124 | ||
45 | 125 |
end |
app/helpers/issues_helper.rb (working copy) | ||
---|---|---|
36 | 36 |
@cached_label_priority ||= l(:field_priority) |
37 | 37 |
|
38 | 38 |
link_to_issue(issue) + "<br /><br />" + |
39 |
"<strong>#{@cached_label_start_date}</strong>: #{format_date(issue.start_date)}<br />" +
|
|
40 |
"<strong>#{@cached_label_due_date}</strong>: #{format_date(issue.due_date)}<br />" +
|
|
39 |
"<strong>#{@cached_label_start_date}</strong>: <span id='tooltip_start_date_#{issue.id}'>#{format_date(issue.start_date)}</span><br />" +
|
|
40 |
"<strong>#{@cached_label_due_date}</strong>: <span id='tooltip_due_date_#{issue.id}'>#{format_date(issue.due_date)}</span><br />" +
|
|
41 | 41 |
"<strong>#{@cached_label_assigned_to}</strong>: #{issue.assigned_to}<br />" + |
42 | 42 |
"<strong>#{@cached_label_priority}</strong>: #{issue.priority.name}" |
43 | 43 |
end |
... | ... | |
259 | 259 |
end |
260 | 260 |
end |
261 | 261 |
end |
262 | ||
263 |
def get_position(event, date_from, date_to, zoom_str) |
|
264 |
zoom = zoom_str.to_i |
|
265 |
i_start_date = (event.start_date >= date_from ? event.start_date : date_from ) |
|
266 |
i_end_date = (event.due_before <= date_to ? event.due_before : date_to ) |
|
267 | ||
268 |
i_done_date = event.start_date + ((event.due_before - event.start_date+1)*event.done_ratio/100).floor |
|
269 |
i_done_date = (i_done_date <= date_from ? date_from : i_done_date ) |
|
270 |
i_done_date = (i_done_date >= date_to ? date_to : i_done_date ) |
|
271 | ||
272 |
i_late_date = [i_end_date, Date.today].min if i_start_date <= Date.today |
|
273 | ||
274 |
i_left = ((i_start_date - date_from)*zoom).floor |
|
275 |
i_left = 0 if i_left < 0 |
|
276 |
i_width = ((i_end_date - i_start_date + 1)*zoom).floor - 2 # total width of the issue (- 2 for left and right borders) |
|
277 |
i_width = 0 if i_width < 0 |
|
278 |
d_width = ((i_done_date - i_start_date)*zoom).floor - 2 # done width |
|
279 |
d_width = 0 if d_width < 0 |
|
280 |
l_width = i_late_date ? ((i_late_date - i_start_date+1)*zoom).floor - 2 : 0 # delay width |
|
281 |
l_width = 0 if l_width < 0 |
|
282 |
return i_left, i_width, l_width, d_width |
|
283 |
end |
|
262 | 284 |
end |
app/models/issue.rb (working copy) | ||
---|---|---|
415 | 415 |
end |
416 | 416 |
dependencies |
417 | 417 |
end |
418 | ||
419 |
def all_precedes_issues |
|
420 |
dependencies = [] |
|
421 |
relations_from.each do |relation| |
|
422 |
next unless relation.relation_type == IssueRelation::TYPE_PRECEDES |
|
423 |
dependencies << relation.issue_to |
|
424 |
dependencies += relation.issue_to.all_dependent_issues |
|
425 |
end |
|
426 |
dependencies |
|
427 |
end |
|
418 | 428 |
|
419 | 429 |
# Returns an array of issues that duplicate this one |
420 | 430 |
def duplicates |
app/views/gantts/show.html.erb (working copy) | ||
---|---|---|
1 |
<% include_calendar_headers_tags %> |
|
1 | 2 |
<h2><%= l(:label_gantt) %></h2> |
2 | 3 | |
3 | 4 |
<% form_tag(params.merge(:month => nil, :year => nil, :months => nil), :id => 'query_form') do %> |
... | ... | |
38 | 39 |
<% zoom = 1 |
39 | 40 |
@gantt.zoom.times { zoom = zoom * 2 } |
40 | 41 | |
41 |
subject_width = 330
|
|
42 |
subject_width = 280
|
|
42 | 43 |
header_heigth = 18 |
43 | 44 | |
44 | 45 |
headers_height = header_heigth |
... | ... | |
58 | 59 |
g_height = [(20 * @gantt.events.length + 6)+150, 206].max |
59 | 60 |
t_height = g_height + headers_height |
60 | 61 |
%> |
62 |
<input type="hidden" name="_date_from" id="i_date_from" value="<%=h(@gantt.date_from)%>" /> |
|
63 |
<input type="hidden" name="_date_to" id="i_date_to" value="<%=h(@gantt.date_to)%>" /> |
|
64 |
<input type="hidden" name="zm" id="i_zm" value="<%=h(zoom)%>" /> |
|
65 |
<script type='text/javascript'> |
|
66 |
function issue_moved(elem) { |
|
67 |
var id_str = elem.id.substring(3, elem.id.length); |
|
68 |
var v_date_from = document.getElementById('i_date_from').getAttribute("value"); |
|
69 |
var v_date_to = document.getElementById('i_date_to').getAttribute("value"); |
|
70 |
var v_zm = document.getElementById('i_zm').getAttribute("value"); |
|
71 |
var url_str = '/issues/edit_gantt/' + id_str; |
|
72 |
var day = parseInt(elem.style.left)/parseInt(v_zm); |
|
73 |
new Ajax.Request(url_str, {asynchronous:true, evalScripts:true, |
|
74 |
parameters: 'day='+day+'&date_from='+v_date_from+'&date_to='+v_date_to+'&zoom='+v_zm, |
|
75 |
onSuccess:function(obj) { |
|
76 |
change_dates(obj.responseText); |
|
77 |
}, |
|
78 |
onFailure:function(obj) { |
|
79 |
handle_failure(obj.responseText); |
|
80 |
} |
|
81 |
}); |
|
61 | 82 | |
83 |
} |
|
84 |
|
|
85 |
function handle_failure(res_text) { |
|
86 |
var text = res_text.split('|'); |
|
87 |
alert(text[0]); |
|
88 |
if (text.length == 1) { |
|
89 |
return; |
|
90 |
} |
|
91 |
change_dates(text[1]);//revert |
|
92 |
} |
|
93 | ||
94 |
function change_dates(issue_infos) { |
|
95 |
if (!issue_infos) { |
|
96 |
return; |
|
97 |
} |
|
98 |
var issue_list = issue_infos.split("|"); |
|
99 |
for (i = 0; i < issue_list.length; i++) { |
|
100 |
change_date(issue_list[i]); |
|
101 |
} |
|
102 |
} |
|
103 | ||
104 |
function change_date(text) { |
|
105 |
if (!text) { |
|
106 |
return; |
|
107 |
} |
|
108 |
var issue_info = text.split("="); |
|
109 |
var elem_id = issue_info[0]; |
|
110 |
var vals = issue_info[1].split(','); |
|
111 |
var start_date_elem = document.getElementById(elem_id + '_start_date_str'); |
|
112 |
if (!start_date_elem) { |
|
113 |
//target not exists |
|
114 |
return; |
|
115 |
} |
|
116 |
start_date_elem.innerHTML = vals[0]; |
|
117 |
var tooltip_start_date_elem = document.getElementById('tooltip_start_date_' + elem_id); |
|
118 |
tooltip_start_date_elem.innerHTML = vals[0]; |
|
119 |
var due_date_elem = document.getElementById(elem_id + '_due_date_str'); |
|
120 |
due_date_elem.innerHTML = vals[2]; |
|
121 |
var tooltip_due_date_elem = document.getElementById('tooltip_due_date_' + elem_id); |
|
122 |
tooltip_due_date_elem.innerHTML = vals[2]; |
|
123 | ||
124 |
var ev_elem = document.getElementById('ev_' + elem_id); |
|
125 |
ev_elem.style.left = vals[4] + 'px'; |
|
126 |
ev_elem.style.width = (parseInt(vals[5])+100)+'px'; |
|
127 |
var todo_elem = document.getElementById('task_todo_' + elem_id); |
|
128 |
todo_elem.style.width = vals[5] + 'px'; |
|
129 |
var late_elem = document.getElementById('task_late_' + elem_id); |
|
130 |
if (late_elem) { |
|
131 |
late_elem.style.width = vals[6] + 'px'; |
|
132 |
if (vals[6] == '0') { |
|
133 |
late_elem.className = 'task task_none'; |
|
134 |
} else { |
|
135 |
late_elem.className = 'task task_late'; |
|
136 |
} |
|
137 |
} |
|
138 |
var done_elem = document.getElementById('task_done_' + elem_id); |
|
139 |
if (done_elem) { |
|
140 |
done_elem.style.width = vals[7] + 'px'; |
|
141 |
if (vals[7] == '0') { |
|
142 |
done_elem.className = 'task task_none'; |
|
143 |
} else { |
|
144 |
done_elem.className = 'task task_done'; |
|
145 |
} |
|
146 |
} |
|
147 |
var task_elem = document.getElementById('task_task_' + elem_id); |
|
148 |
if (task_elem) { |
|
149 |
task_elem.style.left = (parseInt(vals[5])+5) + 'px'; |
|
150 |
} |
|
151 |
var tooltip = document.getElementById("tt_" + elem_id); |
|
152 |
tooltip.style.left = ev_elem.style.left; |
|
153 | ||
154 |
//change calendar date |
|
155 |
document.getElementById(elem_id+"_hidden_start_date").value = vals[1]; |
|
156 |
document.getElementById(elem_id+"_start_date").value = vals[1]; |
|
157 |
document.getElementById(elem_id+"_hidden_due_date").value = vals[3]; |
|
158 |
document.getElementById(elem_id+"_due_date").value = vals[3]; |
|
159 |
} |
|
160 |
</script> |
|
161 | ||
62 | 162 |
<table width="100%" style="border:0; border-collapse: collapse;"> |
63 | 163 |
<tr> |
64 | 164 |
<td style="width:<%= subject_width %>px; padding:0px;"> |
... | ... | |
88 | 188 |
end %> |
89 | 189 |
</div> |
90 | 190 |
</td> |
191 |
<td style="width:225px; padding:0px;"> |
|
192 |
<div style="position:relative;height:<%= t_height + 24 %>px;width:225px;"> |
|
193 |
<div style="width:225px;height:<%= headers_height %>px;background: #eee;" class="gantt_hdr"></div> |
|
194 |
<div style="width:225px;height:<%= t_height %>px;border-left: 1px solid #c0c0c0;overflow:hidden;" class="gantt_hdr"></div> |
|
195 |
<% |
|
196 |
top = headers_height + 8 |
|
197 |
@gantt.events.each do |i| %> |
|
198 |
<div style="position: absolute;line-height:1.2em;height:16px;top:<%= top %>px;"><small> |
|
199 |
<% if i.is_a? Issue %> |
|
200 |
<span id="<%=i.id%>_start_date_str" style="font-size: 7pt;"><%= format_date(i.start_date) %></span> |
|
201 |
<input type="hidden" size="12" id="<%=i.id%>_hidden_start_date" value="<%= i.start_date %>"> |
|
202 |
<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 %> |
|
203 |
<script type="text/javascript"> |
|
204 |
//<![CDATA[ |
|
205 |
new Form.Element.Observer('<%=i.id%>_start_date', 0.25, |
|
206 |
function(element, value) { |
|
207 |
if (value == document.getElementById('<%=i.id%>_hidden_start_date').value) { |
|
208 |
return ; |
|
209 |
} |
|
210 |
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)}); |
|
211 |
}) |
|
212 |
//]]> |
|
213 |
</script> |
|
214 |
<span id="<%=i.id%>_due_date_str" style="font-size: 7pt;<%= "color: blue;" unless i.due_date%>"> |
|
215 |
<%= format_date(i.due_before) %> |
|
216 |
</span> |
|
217 |
<input type="hidden" size="12" id="<%=i.id%>_hidden_due_date" value="<%= i.due_date %>"> |
|
218 |
<input type="hidden" size="12" id="<%=i.id%>_due_date" value="<%= i.due_date %>"><%= calendar_for("#{i.id}_due_date") if i.due_date%> |
|
219 |
<script type="text/javascript"> |
|
220 |
//<![CDATA[ |
|
221 |
new Form.Element.Observer('<%=i.id%>_due_date', 0.25, |
|
222 |
function(element, value) { |
|
223 |
if (value == document.getElementById('<%=i.id%>_hidden_due_date').value) { |
|
224 |
return ; |
|
225 |
} |
|
226 |
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)}); |
|
227 |
}) |
|
228 |
//]]> |
|
229 |
</script> |
|
230 |
<% else %> |
|
231 |
<span style="font-size: 7pt;"><%= format_date(i.start_date) %></span> |
|
232 |
<% end %> |
|
233 |
</small></div> |
|
234 |
<% top = top + 20 |
|
235 |
end %> |
|
236 |
</div> |
|
237 |
</td> |
|
91 | 238 |
<td> |
92 | 239 | |
93 |
<div style="position:relative;height:<%= t_height + 24 %>px;overflow:auto;"> |
|
240 |
<div style="position:relative;height:<%= t_height + 24 %>px;overflow:auto;" id="gantt-container">
|
|
94 | 241 |
<div style="width:<%= g_width-1 %>px;height:<%= headers_height %>px;background: #eee;" class="gantt_hdr"> </div> |
95 | 242 |
<% |
96 | 243 |
# |
... | ... | |
150 | 297 |
left = 0 |
151 | 298 |
height = g_height + header_heigth - 1 |
152 | 299 |
wday = @gantt.date_from.cwday |
300 |
dt = @gantt.date_from |
|
153 | 301 |
(@gantt.date_to - @gantt.date_from + 1).to_i.times do |
154 | 302 |
width = zoom - 1 |
155 | 303 |
%> |
156 | 304 |
<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"> |
157 |
<%= day_name(wday).first %> |
|
305 |
<%= "#{dt.day}<br>"if @gantt.zoom == 4 %><%= day_name(wday).first %>
|
|
158 | 306 |
</div> |
159 | 307 |
<% |
160 | 308 |
left = left + width+1 |
161 | 309 |
wday = wday + 1 |
310 |
dt = dt + 1 |
|
162 | 311 |
wday = 1 if wday > 7 |
163 | 312 |
end |
164 | 313 |
end %> |
... | ... | |
169 | 318 |
# |
170 | 319 |
top = headers_height + 10 |
171 | 320 |
@gantt.events.each do |i| |
172 |
if i.is_a? Issue |
|
173 |
i_start_date = (i.start_date >= @gantt.date_from ? i.start_date : @gantt.date_from ) |
|
174 |
i_end_date = (i.due_before <= @gantt.date_to ? i.due_before : @gantt.date_to ) |
|
175 |
|
|
176 |
i_done_date = i.start_date + ((i.due_before - i.start_date+1)*i.done_ratio/100).floor |
|
177 |
i_done_date = (i_done_date <= @gantt.date_from ? @gantt.date_from : i_done_date ) |
|
178 |
i_done_date = (i_done_date >= @gantt.date_to ? @gantt.date_to : i_done_date ) |
|
179 |
|
|
180 |
i_late_date = [i_end_date, Date.today].min if i_start_date < Date.today |
|
181 |
|
|
182 |
i_left = ((i_start_date - @gantt.date_from)*zoom).floor |
|
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 |
d_width = ((i_done_date - i_start_date)*zoom).floor - 2 # done width |
|
185 |
l_width = i_late_date ? ((i_late_date - i_start_date+1)*zoom).floor - 2 : 0 # delay width |
|
186 |
css = "task " + (i.leaf? ? 'leaf' : 'parent') |
|
321 |
if i.is_a? Issue |
|
322 |
i_left, i_width, l_width, d_width = get_position(i, @gantt.date_from, @gantt.date_to, zoom) |
|
187 | 323 |
%> |
188 |
<div style="top:<%= top %>px;left:<%= i_left %>px;width:<%= i_width %>px;" class="<%= css %> task_todo"><div class="left"></div> <div class="right"></div></div> |
|
189 |
<% if l_width > 0 %> |
|
190 |
<div style="top:<%= top %>px;left:<%= i_left %>px;width:<%= l_width %>px;" class="<%= css %> task_late"> </div> |
|
191 |
<% end %> |
|
192 |
<% if d_width > 0 %> |
|
193 |
<div style="top:<%= top %>px;left:<%= i_left %>px;width:<%= d_width %>px;" class="<%= css %> task_done"> </div> |
|
194 |
<% end %> |
|
195 |
<div style="top:<%= top %>px;left:<%= i_left + i_width + 8 %>px;background:#fff;" class="<%= css %>"> |
|
196 |
<%= i.status.name %> |
|
197 |
<%= (i.done_ratio).to_i %>% |
|
198 |
</div> |
|
199 |
<div class="tooltip" style="position: absolute;top:<%= top %>px;left:<%= i_left %>px;width:<%= i_width %>px;height:12px;"> |
|
200 |
<span class="tip"> |
|
324 |
<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"> |
|
325 |
<div id="task_todo_<%=i.id%>" style="float:left:0px; width:<%= i_width %>px;" class="task task_todo"> </div> |
|
326 |
<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> |
|
327 |
<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> |
|
328 |
<div id="task_task_<%=i.id%>" style="position:absolute;left:<%= (i_width + 5) %>px;background:#fff;" class="task"> |
|
329 |
<%= h(i.status.name) %> |
|
330 |
<%= (i.done_ratio).to_i %>% |
|
331 |
<% if !i.due_date && i.fixed_version %> |
|
332 |
- <strong><%= h(i.fixed_version.name) %></strong> |
|
333 |
<% end %> |
|
334 |
</div> |
|
335 |
</div> |
|
336 |
<%# === tooltip === %> |
|
337 |
<div id="tt_<%=i.id%>" class="tooltip" style="position: absolute;top:<%= top+14 %>px;left:<%= i_left %>px;width:<%= i_width %>px;height:8px;"> |
|
338 |
<span class="tip" style="position: relative;top:-2px;"> |
|
201 | 339 |
<%= render_issue_tooltip i %> |
202 | 340 |
</span></div> |
341 |
<%= draggable_element("ev_#{i.id}", |
|
342 |
:revert =>false, :scroll=>"'gantt-container'", :constraint => "'horizontal'", :snap=>zoom, |
|
343 |
:onEnd=>"function( draggable, event ) {issue_moved(draggable.element);}" |
|
344 |
) %> |
|
203 | 345 |
<% else |
204 | 346 |
i_left = ((i.start_date - @gantt.date_from)*zoom).floor |
205 | 347 |
%> |
config/routes.rb (working copy) | ||
---|---|---|
111 | 111 |
issues_views.connect 'projects/:project_id/issues.:format', :action => 'index' |
112 | 112 |
issues_views.connect 'projects/:project_id/issues/new', :action => 'new' |
113 | 113 |
issues_views.connect 'projects/:project_id/issues/gantt', :controller => 'gantts', :action => 'show' |
114 |
issues_views.connect 'projects/:project_id/issues/edit_gantt/:id', :controller => 'gantts', :action => 'edit_gantt', :id => /\d+/ |
|
114 | 115 |
issues_views.connect 'projects/:project_id/issues/calendar', :controller => 'calendars', :action => 'show' |
115 | 116 |
issues_views.connect 'projects/:project_id/issues/:copy_from/copy', :action => 'new' |
116 | 117 |
issues_views.connect 'issues/:id', :action => 'show', :id => /\d+/ |
... | ... | |
122 | 123 |
issues_actions.connect 'issues', :action => 'index' |
123 | 124 |
issues_actions.connect 'projects/:project_id/issues', :action => 'create' |
124 | 125 |
issues_actions.connect 'projects/:project_id/issues/gantt', :controller => 'gantts', :action => 'show' |
126 |
issues_actions.connect 'projects/:project_id/issues/edit_gantt:id', :controller => 'gantts', :action => 'edit_gantt', :id => /\d+/ |
|
125 | 127 |
issues_actions.connect 'projects/:project_id/issues/calendar', :controller => 'calendars', :action => 'show' |
126 | 128 |
issues_actions.connect 'issues/:id/quoted', :action => 'reply', :id => /\d+/ |
127 | 129 |
issues_actions.connect 'issues/:id/:action', :action => /edit|move|destroy/, :id => /\d+/ |
... | ... | |
135 | 137 |
issues_actions.connect 'issues/:id.:format', :action => 'destroy', :id => /\d+/, :format => /xml/ |
136 | 138 |
end |
137 | 139 |
issues_routes.connect 'issues/gantt', :controller => 'gantts', :action => 'show' |
140 |
issues_routes.connect 'issues/edit_gantt/:id', :controller => 'gantts', :action => 'edit_gantt', :id => /\d+/ |
|
138 | 141 |
issues_routes.connect 'issues/calendar', :controller => 'calendars', :action => 'show' |
139 | 142 |
issues_routes.connect 'issues/:action' |
140 | 143 |
end |
public/stylesheets/application.css (working copy) | ||
---|---|---|
788 | 788 |
.task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; } |
789 | 789 |
.task_done { background:#66f url(../images/task_done.png); border: 1px solid #66f; } |
790 | 790 |
.task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; } |
791 |
.task_none { background:transparent; border-style: none; } |
|
791 | 792 | |
792 | 793 |
.task_todo.parent { background: #888; border: 1px solid #888; height: 6px;} |
793 | 794 |
.task_late.parent, .task_done.parent { height: 3px;} |