diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb
index 0721b35a..affd101b 100644
--- a/app/controllers/todos_controller.rb
+++ b/app/controllers/todos_controller.rb
@@ -236,7 +236,7 @@ class TodosController < ApplicationController
@original_item_was_deferred = @todo.deferred?
@original_item_due = @todo.due
@original_item_due_id = get_due_id_for_calendar(@todo.due)
- @original_item_predecessor_list = @todo.predecessors.collect{|t| t.description}.join(', ')
+ @original_item_predecessor_list = @todo.predecessors.map{|t| t.specification}.join(', ')
if params['todo']['project_id'].blank? && !params['project_name'].nil?
if params['project_name'] == 'None'
@@ -604,7 +604,7 @@ class TodosController < ApplicationController
get_todo_from_params
# Begin matching todos in current project
@items = current_user.todos.find(:all,
- :select => :description,
+ :select => 'description, project_id, context_id, created_at',
:conditions => [ '(todos.state = ? OR todos.state = ?) AND ' +
'NOT (id = ?) AND lower(description) LIKE ? AND project_id = ?',
'active', 'pending',
@@ -616,7 +616,7 @@ class TodosController < ApplicationController
)
if @items.empty? # Match todos in other projects
@items = current_user.todos.find(:all,
- :select => :description,
+ :select => 'description, project_id, context_id, created_at',
:conditions => [ '(todos.state = ? OR todos.state = ?) AND ' +
'NOT (id = ?) AND lower(description) LIKE ?',
'active', 'pending',
@@ -628,7 +628,7 @@ class TodosController < ApplicationController
else
# New todo - TODO: Filter on project
@items = current_user.todos.find(:all,
- :select => :description,
+ :select => 'description, project_id, context_id, created_at',
:conditions => [ '(todos.state = ? OR todos.state = ?) AND lower(description) LIKE ?',
'active', 'pending',
'%' + params[:predecessor_list].downcase + '%' ],
@@ -636,7 +636,7 @@ class TodosController < ApplicationController
:limit => 10
)
end
- render :inline => "<%= auto_complete_result(@items, :description) %>"
+ render :inline => "<%= auto_complete_result2(@items) %>"
end
private
diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb
index 9cf5c3eb..45bdcb3c 100644
--- a/app/helpers/todos_helper.rb
+++ b/app/helpers/todos_helper.rb
@@ -134,20 +134,10 @@ module TodosHelper
if tag_list.empty? then "" else "#{tag_list}" end
end
- # TODO: Use DELIMITER
def predecessor_list_text
- @todo.predecessors.collect{|t| t.description}.join(', ')
+ @todo.predecessors.map{|t| t.specification}.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)})"
@@ -316,4 +306,14 @@ module TodosHelper
class_str = todo.starred? ? "starred_todo" : "unstarred_todo"
image_tag("blank.png", :title =>"Star action", :class => class_str)
end
+
+ def auto_complete_result2(entries, phrase = nil)
+ return unless entries
+ items = entries.map do |entry|
+ item = entry.specification()
+ content_tag("li", phrase ? highlight(h(item), phrase) : h(item))
+ end
+ content_tag("ul", items.uniq)
+ end
+
end
diff --git a/app/models/todo.rb b/app/models/todo.rb
index 6dc75816..28a1f16f 100644
--- a/app/models/todo.rb
+++ b/app/models/todo.rb
@@ -75,52 +75,72 @@ class Todo < ActiveRecord::Base
end
def no_uncompleted_predecessors_or_deferral?
- value = (show_from.blank? or Time.zone.now > show_from and uncompleted_predecessors.empty?)
- logger.debug "=== no_uncompleted_predecessors_or_deferral #{value}"
- return value
+ return (show_from.blank? or Time.zone.now > show_from and uncompleted_predecessors.empty?)
end
def no_uncompleted_predecessors?
- value = self.uncompleted_predecessors.empty?
- logger.debug "=== no_uncompleted_predecessor #{value}"
- return value
+ return uncompleted_predecessors.empty?
+ end
+
+
+ def todo_from_string(specification)
+ # Split specification into parts: description
+ parts = specification.split(%r{\ \<|; |\>})
+ return nil unless parts.length == 3
+ todos = Todo.all(:joins => [:project, :context],
+ :include => [:context, :project],
+ :conditions => {:description => parts[0],
+ :contexts => {:name => parts[2]}})
+ return nil if todos.empty?
+ # todos now contains all todos with matching description and context
+ # TODO: Is this possible to do with a single query?
+ todos.each do |todo|
+ project_name = todo.project.is_a?(NullProject) ? "(none)" : todo.project.name
+ return todo if project_name == parts[1]
+ end
+ return nil
end
- # TODO: Handle duplicate descriptions
def validate
if !show_from.blank? && show_from < user.date
errors.add("show_from", "must be a date in the future")
end
unless @predecessor_array.nil? # Only validate predecessors if they changed
- @predecessor_array.each do |description|
- t = Todo.find_by_description(description)
+ @predecessor_array.each do |specification|
+ t = todo_from_string(specification)
if t.nil?
- errors.add("Depends on:", "Could not find action '#{description}'")
+ errors.add("Depends on:", "Could not find action '#{h(specification)}'")
else
- errors.add("Depends on:", "Adding '#{description}' would create a circular dependency") if is_successor?(t)
+ errors.add("Depends on:", "Adding '#{h(specification)}' would create a circular dependency") if is_successor?(t)
end
end
end
end
+ # Returns a string with description, project and context
+ def specification
+ project_name = project.is_a?(NullProject) ? "(none)" : project.name
+ return "#{description} <#{project_name}; #{context.title}>"
+ end
+
def save_predecessors
unless @predecessor_array.nil? # Only save predecessors if they changed
- current_array = predecessors.map(&:description)
+ current_array = predecessors.map{|p| p.specification}
remove_array = current_array - @predecessor_array
add_array = @predecessor_array - current_array
# This is probably a bit naive code...
- remove_array.each do |description|
- t = Todo.find_by_description(description)
- self.predecessors.delete(t)
+ remove_array.each do |specification|
+ t = todo_from_string(specification)
+ self.predecessors.delete(t) unless t.nil?
end
# ... as is this?
- add_array.each do |description|
- t = Todo.find_by_description(description)
+ add_array.each do |specification|
+ t = todo_from_string(specification)
unless t.nil?
self.predecessors << t unless self.predecessors.include?(t)
else
- logger.error "Could not find #{description}" # Unexpected since validation passed
+ logger.error "Could not find #{specification}" # Unexpected since validation passed
end
end
end
@@ -235,7 +255,6 @@ class Todo < ActiveRecord::Base
end
# TODO: DELIMITER
- # TODO: Handle todos with the same description
# TODO: Should possibly handle state changes also?
def add_predecessor_list(predecessor_list)
if predecessor_list.kind_of? String
diff --git a/public/stylesheets/standard.css b/public/stylesheets/standard.css
index 45617228..997f2f2d 100644
--- a/public/stylesheets/standard.css
+++ b/public/stylesheets/standard.css
@@ -1270,6 +1270,7 @@ div.auto_complete ul {
list-style-type:none;
}
div.auto_complete ul li {
+ font-size: 1.0em;
margin:0;
padding:3px;
list-style-type: none;