diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index 83207f76..69c6c621 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -8,7 +8,7 @@ class TodosController < ApplicationController :completed_archive, :check_deferred, :toggle_check, :toggle_star, :edit, :update, :create, :calendar, :auto_complete_for_tag] append_before_filter :get_todo_from_params, :only => [ :edit, :toggle_check, :toggle_star, :show, :update, :destroy ] - protect_from_forgery :except => [:auto_complete_for_tag] + protect_from_forgery :except => [:auto_complete_for_tag, :auto_complete_for_predecessor] session :off, :only => :index, :if => Proc.new { |req| is_feed_request(req) } @@ -214,7 +214,25 @@ class TodosController < ApplicationController @original_item_project_id = @todo.project_id @original_item_was_deferred = @todo.deferred? @original_item_due = @todo.due - @original_item_due_id = get_due_id_for_calendar(@todo.due) + @original_item_due_id = get_due_id_for_calendar(@todo.due) + @original_item_predecessor_list = @todo.predecessors.collect{|t| t.description}.join(', ') + if params[:predecessor_list] + logger.debug "---old #{@original_item_predecessor_list}" + logger.debug "---new #{params[:predecessor_list]}" + @todo.add_predecessor_list(params[:predecessor_list]) + if @original_item_predecessor_list != params[:predecessor_list] + # Recalculate dependencies for this todo + if @todo.uncompleted_predecessors.empty? + if @todo.state == 'pending' + @todo.activate! # Activate pending if no uncompleted predecessors + end + else + if @todo.state == 'active' + @todo.block! # Block active if we got uncompleted predecessors + end + end + end + end if params['todo']['project_id'].blank? && !params['project_name'].nil? if params['project_name'] == 'None' @@ -540,6 +558,28 @@ class TodosController < ApplicationController render :inline => "<%= auto_complete_result(@items, :name) %>" end + def auto_complete_for_predecessor + get_todo_from_params + # Begin matching todos in current project + @items = current_user.todos.find(:all, + :conditions => [ 'NOT (id = ?) AND description LIKE ? AND project_id = ?', + @todo.id, + '%' + params[:predecessor_list] + '%', + @todo.project_id ], + :order => 'description ASC', + :limit => 10 + ) + if @items.empty? # Match todos in other projects + @items = current_user.todos.find(:all, + :conditions => [ 'NOT (id = ?) AND description LIKE ?', + params[:id], '%' + params[:predecessor_list] + '%' ], + :order => 'description ASC', + :limit => 10 + ) + end + render :inline => "<%= auto_complete_result(@items, :description) %>" + end + private def get_todo_from_params diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index ec7a2d3c..70c54385 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -116,6 +116,20 @@ module TodosHelper if tag_list.empty? then "" else "" end end + # TODO: Use DELIMITER + def predecessor_list_text + @todo.predecessors.collect{|t| t.description}.join(', ') + end + + def predecessor_list + predecessor_list = @todo.predecessors.collect{|t| + '' + + link_to(t.name, :controller => "todos", :action => "tag", :id => t.name) + + "" + }.join('') + '#{predecessor_list}' + end + def deferred_due_date if @todo.deferred? && @todo.due "(action due on #{format_date(@todo.due)})" diff --git a/app/models/todo.rb b/app/models/todo.rb index 9c5488eb..06ab02d5 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -154,6 +154,39 @@ class Todo < ActiveRecord::Base return self.recurring_todo_id != nil end + def add_predecessor(predecessor) + logger.debug "add_predecessor #{predecessor.description}" + end + + # TODO: DELIMITER + # TODO: Todo::Error + # TODO: Handle todos with the same description + def add_predecessor_list(predecessor_list) + logger.debug "add_predecessor_list #{predecessor_list}" + raise "Can't handle other types than string for now" unless predecessor_list.kind_of? String + list = predecessor_list.split(',').map do |description| + description.strip.squeeze(" ") + end + current = self.predecessors.map(&:description) + remove_list = current - list + # This is probably a bit naive code... + remove_list.each do |description| + t = Todo.find_by_description(description) + logger.debug "Removing #{t.description} from #{self.description} as predecessor" + self.predecessors.delete(t) + end + add_list = list - current + # ... as is this? + add_list.each do |description| + t = Todo.find_by_description(description) + #raise Todo::Error, "predecessor could not be found: #{description}" if t.nil? + # Create dependency record + self.predecessors << t unless self.predecessors.include?(t) + end +# debugger + + end + # Rich Todo API def self.from_rich_message(user, default_context_id, description, notes) diff --git a/app/views/todos/_edit_form.rhtml b/app/views/todos/_edit_form.rhtml index e471984e..2f8e4bc5 100644 --- a/app/views/todos/_edit_form.rhtml +++ b/app/views/todos/_edit_form.rhtml @@ -46,13 +46,21 @@ + +<%= text_field_tag 'predecessor_list', predecessor_list_text, :id => dom_id(@todo, 'predecessor_list'), :size => 30, :tabindex => 15 %> +<%= content_tag("div", "", :id => dom_id(@todo, 'predecessor_list')+"_auto_complete", :class => "auto_complete") %> +<%= auto_complete_field dom_id(@todo, 'predecessor_list'), { + :url => {:controller => 'todos', :action => 'auto_complete_for_predecessor', :id => @todo.id}, + :tokens => [','] +} %> + <% if controller.controller_name == "project" || @todo.deferred? -%> <% end -%>