Fix impediment drag and drop

pull/6827/head
Mark Maglana 14 years ago
parent b2a6131c54
commit 2f30788109
  1. 17
      app/controllers/tasks_controller.rb
  2. 2
      app/views/backlogs/show.html.erb
  3. 1
      app/views/tasks/_impediment.html.erb
  4. 1
      app/views/tasks/_task.html.erb
  5. 3
      app/views/tasks/index.html.erb
  6. 10
      assets/javascripts/impediment.js
  7. 28
      assets/javascripts/task.js
  8. 37
      assets/javascripts/taskboard.js
  9. 27
      assets/javascripts/taskboard_updater.js

@ -25,14 +25,25 @@ class TasksController < ApplicationController
def index def index
@sprint = Sprint.find(params[:sprint_id]) @sprint = Sprint.find(params[:sprint_id])
@story_ids = @sprint.stories.map{|s| s.id} @story_ids = @sprint.stories.map{|s| s.id}
@impediment_ids = @sprint.impediments.map{|i| i.id}
@tasks = Task.find(:all, @tasks = Task.find(:all,
:conditions => ["parent_id in (?) AND updated_on > ?", @story_ids, params[:after]], :conditions => ["parent_id in (?) AND updated_on > ?", @story_ids, params[:after]],
:order => "updated_on ASC") :order => "updated_on ASC")
if params[:include_impediments]=='true'
@impediments = Task.find(:all,
:conditions => ["id in (?) AND updated_on > ?", @impediment_ids, params[:after]],
:order => "updated_on ASC")
end
@include_meta = true @include_meta = true
@last_updated_conditions = "parent_id in (?) " +
(@impediments ? "OR id in (?)" : "")
@last_updated = Task.find(:first, @last_updated = Task.find(:first,
:conditions => ["parent_id in (?)", @story_ids], :conditions => [@last_updated_conditions, @story_ids, @impediment_ids],
:order => "updated_on DESC") :order => "updated_on DESC")
render :action => "index", :layout => false render :action => "index", :layout => false
end end

@ -30,7 +30,7 @@
<td<div class="label_sprint_impediments"><%= l(:label_sprint_impediments) %></div></td> <td<div class="label_sprint_impediments"><%= l(:label_sprint_impediments) %></div></td>
<td class="add_new">+</td> <td class="add_new">+</td>
<%- @statuses.each do |status| %> <%- @statuses.each do |status| %>
<td class="swimlane list <%= status.is_closed? ? 'closed' : '' %>" id="impstat_<%= status.id %>"> <td class="swimlane list <%= status.is_closed? ? 'closed' : '' %>" id="impcell_<%= status.id %>">
<%= render :partial => "tasks/impediment", :collection => @sprint.impediments.select{|impediment| impediment.status_id==status.id} %> <%= render :partial => "tasks/impediment", :collection => @sprint.impediments.select{|impediment| impediment.status_id==status.id} %>
</td> </td>
<%- end %> <%- end %>

@ -11,7 +11,6 @@
<div class="meta"> <div class="meta">
<div class="story_id"><%= impediment.parent_id %></div> <div class="story_id"><%= impediment.parent_id %></div>
<div class="status_id"><%= impediment.status_id %></div> <div class="status_id"><%= impediment.status_id %></div>
<div class="position"><%= impediment.position %></div>
<div class="previous"><%= impediment.higher_item.nil? ? '' : impediment.higher_item.id %></div> <div class="previous"><%= impediment.higher_item.nil? ? '' : impediment.higher_item.id %></div>
</div> </div>
<%- end %> <%- end %>

@ -11,7 +11,6 @@
<div class="meta"> <div class="meta">
<div class="story_id"><%= task.parent_id %></div> <div class="story_id"><%= task.parent_id %></div>
<div class="status_id"><%= task.status_id %></div> <div class="status_id"><%= task.status_id %></div>
<div class="position"><%= task.position %></div>
<div class="previous"><%= task.higher_item.nil? ? '' : task.higher_item.id %></div> <div class="previous"><%= task.higher_item.nil? ? '' : task.higher_item.id %></div>
</div> </div>
<%- end %> <%- end %>

@ -1,4 +1,7 @@
<div> <div>
<div class="meta" id="last_updated"><%= date_string_with_milliseconds( (@last_updated.nil? ? Time.parse(params[:after]) : @last_updated.updated_on), 0.001 ) %></div> <div class="meta" id="last_updated"><%= date_string_with_milliseconds( (@last_updated.nil? ? Time.parse(params[:after]) : @last_updated.updated_on), 0.001 ) %></div>
<%= render :partial => "task", :collection => @tasks, :locals => { :include_meta => @include_meta } %> <%= render :partial => "task", :collection => @tasks, :locals => { :include_meta => @include_meta } %>
<%- if @impediments %>
<%= render :partial => "impediment", :collection => @impediments, :locals => { :include_meta => @include_meta }%>
<%- end %>
</div> </div>

@ -15,20 +15,18 @@ RB.Impediment = RB.Object.create(RB.Task, {
// Associate this object with the element for later retrieval // Associate this object with the element for later retrieval
j.data('this', this); j.data('this', this);
// Observe click events in certain fields j.bind('mouseup', this.handleClick);
j.find('.editable').live('mouseup', this.triggerEdit);
}, },
// Override saveDirectives of RB.Task // Override saveDirectives of RB.Task
saveDirectives: function(){ saveDirectives: function(){
var j = this.$; var j = this.$;
var prev = this.$.prev(); var prev = this.$.prev();
var cellID = j.parent('td').first().attr('id').split("_"); var statusID = j.parent('td').first().attr('id').split("_")[1];
var sprint = $('#taskboard').data('this').getID();
var data = j.find('.editor').serialize() + var data = j.find('.editor').serialize() +
"&fixed_version_id=" + sprint + "&fixed_version_id=" + RB.constants['sprint_id'] +
"&status_id=" + cellID[1] + "&status_id=" + statusID +
"&prev=" + (prev.length==1 ? prev.data('this').getID() : '') + "&prev=" + (prev.length==1 ? prev.data('this').getID() : '') +
(this.isNew() ? "" : "&id=" + j.children('.id').text()); (this.isNew() ? "" : "&id=" + j.children('.id').text());
var url = RB.urlFor[(this.isNew() ? 'create_task' : 'update_task')]; var url = RB.urlFor[(this.isNew() ? 'create_task' : 'update_task')];

@ -15,8 +15,7 @@ RB.Task = RB.Object.create(RB.Story, {
// Associate this object with the element for later retrieval // Associate this object with the element for later retrieval
j.data('this', this); j.data('this', this);
// Observe click events in certain fields j.bind('mouseup', this.handleClick);
// j.find('.editable').live('mouseup', this.triggerEdit);
}, },
afterSaveEdits: function(){ afterSaveEdits: function(){
@ -24,9 +23,22 @@ RB.Task = RB.Object.create(RB.Story, {
this.$.css('background-color', c); this.$.css('background-color', c);
}, },
// Override RB.Story.checkSubjectLength() and do nothing
checkSubjectLength: function(){ checkSubjectLength: function(){
}, },
edit: function(){
throw "Edit is not yet implemented";
},
handleClick: function(event){
var j = $(this);
if(!j.hasClass('editing') && !j.hasClass('dragging')){
j.data('this').edit();
}
},
handleKeyup: function(event){ handleKeyup: function(event){
var j = $(this).parents('.task').first(); var j = $(this).parents('.task').first();
var that = j.data('this'); var that = j.data('this');
@ -107,18 +119,6 @@ RB.Task = RB.Object.create(RB.Story, {
} }
}, },
triggerEdit: function(event){
// Get the task since what was clicked was a field
var j = $(this).parents('.task').first();
if(!j.hasClass('editing') && !j.hasClass('dragging')){
j.data('this').edit();
// Focus on the input corresponding to the field clicked
j.find( '.' + $(event.currentTarget).attr('fieldname') + '.editor' ).focus();
}
},
unmarkSaving: function(){ unmarkSaving: function(){
this.$.removeClass('saving'); this.$.removeClass('saving');
} }

@ -21,7 +21,7 @@ RB.Taskboard = RB.Object.create(RB.Model, {
self.updateColWidths(); self.updateColWidths();
$("#col_width input").bind('keyup', function(e){ if(e.which==13) self.updateColWidths() }); $("#col_width input").bind('keyup', function(e){ if(e.which==13) self.updateColWidths() });
// Initialize tasks // Initialize task lists
j.find("#tasks .list").sortable({ j.find("#tasks .list").sortable({
connectWith: '#tasks .list', connectWith: '#tasks .list',
placeholder: 'placeholder', placeholder: 'placeholder',
@ -37,6 +37,24 @@ RB.Taskboard = RB.Object.create(RB.Model, {
// Add handler for .add_new click // Add handler for .add_new click
j.find('#tasks .add_new').bind('mouseup', self.handleAddNewTaskClick); j.find('#tasks .add_new').bind('mouseup', self.handleAddNewTaskClick);
// Initialize impediment lists
j.find("#impediments .list").sortable({
connectWith: '#impediments .list',
placeholder: 'placeholder',
start: self.dragStart,
stop: self.dragStop,
update: self.dragComplete
});
// Initialize each task in the board
j.find('.impediment').each(function(index){
var task = RB.Factory.initialize(RB.Impediment, this); // 'this' refers to an element with class="impediment"
});
// Add handler for .add_new click
j.find('#impediments .add_new').bind('mouseup', self.handleAddNewImpedimentClick);
}, },
dragComplete: function(event, ui) { dragComplete: function(event, ui) {
@ -54,6 +72,11 @@ RB.Taskboard = RB.Object.create(RB.Model, {
dragStop: function(event, ui){ dragStop: function(event, ui){
ui.item.removeClass("dragging"); ui.item.removeClass("dragging");
}, },
handleAddNewImpedimentClick: function(event){
var row = $(this).parents("tr").first();
$('#taskboard').data('this').newImpediment(row);
},
handleAddNewTaskClick: function(event){ handleAddNewTaskClick: function(event){
var row = $(this).parents("tr").first(); var row = $(this).parents("tr").first();
@ -68,13 +91,19 @@ RB.Taskboard = RB.Object.create(RB.Model, {
} }
$("#col_width input").val(w); $("#col_width input").val(w);
}, },
newImpediment: function(row){
var impediment = $('#impediment_template').children().first().clone();
row.find(".list").first().prepend(impediment);
var o = RB.Factory.initialize(RB.Impediment, impediment);
o.edit();
},
newTask: function(row){ newTask: function(row){
var task = $('#task_template').children().first().clone(); var task = $('#task_template').children().first().clone();
row.find(".list").first().prepend(task); row.find(".list").first().prepend(task);
o = RB.Factory.initialize(RB.Task, task[0]); var o = RB.Factory.initialize(RB.Task, task);
// o.edit(); o.edit();
// task.find('.editor' ).first().focus();
}, },
updateColWidths: function(){ updateColWidths: function(){

@ -8,6 +8,12 @@ RB.TaskboardUpdater = RB.Object.create(RB.BoardUpdater, {
items.each(function(i, v){ items.each(function(i, v){
self.processItem(v, false); self.processItem(v, false);
}); });
// Process impediments
var items = $(data).children('.impediment');
items.each(function(i, v){
self.processItem(v, true);
});
}, },
processItem: function(html, isImpediment){ processItem: function(html, isImpediment){
@ -22,19 +28,18 @@ RB.TaskboardUpdater = RB.Object.create(RB.BoardUpdater, {
target.refresh(update); target.refresh(update);
} }
// Position the item properly in the taskboard // Place the item in the correct cell
var cell, previous, items; var cell, previous, items;
if(isImpediment){ cell = isImpediment ? $('#impcell_' + target.$.find('.meta .status_id').text()) : $('#' + target.$.find('.meta .story_id').text() + '_' + target.$.find('.meta .status_id').text());
throw "Locator for impediment not yet defined"; cell.prepend(target.$);
} else {
cell = $('#' + target.$.find('.meta .story_id').text() + '_' + target.$.find('.meta .status_id').text()); // Sort items in the cell
cell.prepend(target.$);
}
// sort items in the cell according to position
items = cell.children('.task').get(); items = cell.children('.task').get();
items.sort( function(a, b) { return parseInt($(a).find('.position').text()) > parseInt($(b).find('.position').text()) }); items.sort( function(a, b) {
console.log(items); a = isNaN($(a).find('.prev').text()) ? 0 : parseInt($(a).find('.prev').text());
b = isNaN($(b).find('.prev').text()) ? 0 : parseInt($(b).find('.prev').text());
return a > b;
});
for(var ii=0; ii<items.length; ii++){ for(var ii=0; ii<items.length; ii++){
cell.append(items[ii]); cell.append(items[ii]);
} }

Loading…
Cancel
Save