DRY up code around Immediate and Deferred actions, including controller methods and views

Relocated todo_controller#deferred_update_action to be next to todo_controller#update_action 
Include all non-hidden contexts on the home page, but hide the empty ones. Ground work for supporting the automatic showing of a context with zero items when an item is moved to it.
Added a comment about todo_controller#update_element -- is it used?
Remove unused #list_of method from context, note & project models
Remove unused #list_all method from note model
Methods to lazy load done_todos and not_done_todos for project and context models

Fixes #322



git-svn-id: http://www.rousette.org.uk/svn/tracks-repos/trunk@282 a4c988fc-2ded-0310-b66e-134b36920a42
This commit is contained in:
lukemelia 2006-07-17 03:40:35 +00:00
parent 13f7f443af
commit 1ee651f8bb
19 changed files with 132 additions and 255 deletions

View file

@ -223,8 +223,8 @@ class ContextController < ApplicationController
def init_todos
check_user_set_context
@done = @context.find_done_todos
@not_done = @context.find_not_done_todos
@done = @context.done_todos
@not_done = @context.not_done_todos
@count = @not_done.size
end

View file

@ -256,8 +256,8 @@ class ProjectController < ApplicationController
def init_todos
check_user_set_project
@done = @project.find_done_todos
@not_done = @project.find_not_done_todos
@done = @project.done_todos
@not_done = @project.not_done_todos
@count = @not_done.size
end

View file

@ -28,7 +28,7 @@ class TodoController < ApplicationController
max_completed = @user.preferences["no_completed"].to_i-1
@done = (max_completed > 0) ? @done[0..max_completed] : nil
@contexts_to_show = @contexts.reject {|x| x.hide? || x.find_not_done_todos.empty? }
@contexts_to_show = @contexts.reject {|x| x.hide? }
if @contexts.empty?
flash['warning'] = 'You must add at least one context before adding next actions.'
@ -43,6 +43,7 @@ class TodoController < ApplicationController
end
end
# Is this used? Seems like it should be deleted. -lukemelia, 2006-07-16
def update_element
end
@ -53,83 +54,26 @@ class TodoController < ApplicationController
self.init
@item = @user.todos.build
@item.attributes = params["todo"]
if @item.due?
@item.due = Date.strptime(params["todo"]["due"], @user.preferences["date_format"])
else
@item.due = ""
end
@saved = @item.save
@on_page = "home"
if @saved
self.init # we have to do this again to update @todos
@up_count = @todos.reject { |x| x.done? or x.context.hide? }.size.to_s
end
respond_to do |wants|
# if @saved
# flash["notice"] = 'Added new next action.'
# else
# flash["warning"] = 'The next action was not added. Please try again.'
# end
wants.html { redirect_to :action => 'list' }
wants.js
wants.xml { render :xml => @item.to_xml( :root => 'todo', :except => :user_id ) }
end
rescue
respond_to do |wants|
wants.html { render :action => 'list' } # flash["warning"] = 'An error occurred on the server.' render :action => 'list' }# flash["warning"] = 'An error occurred on the server.' # render :action => 'list'
wants.js { render :action => 'error' }
wants.xml { render :text => 'An error occurred on the server.' + $! }
end
perform_add_item('list')
end
# Adding deferred actions from form on todo/tickler
#
def add_deferred_item
self.init
@tickle = Deferred.create(params["todo"])
if @tickle.due?
@tickle.due = Date.strptime(params["todo"]["due"], @user.preferences["date_format"])
else
@tickle.due = ""
end
@saved = @tickle.save
@item = Deferred.create(params["todo"])
@item.user_id = @user.id
@on_page = "tickler"
@on_page = "home"
if @saved
@up_count = @todos.collect { |x| ( !x.done? and !x.context.hide? ) ? x:nil }.compact.size.to_s
end
return if request.xhr?
# fallback for standard requests
if @saved
flash["notice"] = 'Added new next action.'
redirect_to :action => 'tickler'
else
flash["warning"] = 'The next action was not added. Please try again.'
redirect_to :action => 'tickler'
end
rescue
if request.xhr? # be sure to include an error.rjs
render :action => 'error'
else
flash["warning"] = 'An error occurred on the server.'
render :action => 'tickler'
end
perform_add_item('tickler')
end
def edit_action
self.init
item = check_user_return_item
render :partial => 'action_edit_form', :object => item
@item = check_user_return_item
render :layout => false
end
def show
@ -140,13 +84,6 @@ class TodoController < ApplicationController
end
end
def edit_deferred_action
self.init
item = check_user_return_item
render :partial => 'action_edit_deferred_form', :object => item
end
# Toggles the 'done' status of the action
#
def toggle_check
@ -190,6 +127,21 @@ class TodoController < ApplicationController
@saved = @item.save
end
def deferred_update_action
#self.init
@tickle = check_user_return_item
@original_item_context_id = @tickle.context_id
@tickle.attributes = params["item"]
if @tickle.due?
@tickle.due = Date.strptime(params["item"]["due"], @user.preferences["date_format"])
else
@tickle.due = ""
end
@saved = @tickle.save
end
def update_context
self.init
@item = check_user_return_item
@ -223,21 +175,6 @@ class TodoController < ApplicationController
end
end
end
def deferred_update_action
#self.init
@tickle = check_user_return_item
@original_item_context_id = @tickle.context_id
@tickle.attributes = params["item"]
if @tickle.due?
@tickle.due = Date.strptime(params["item"]["due"], @user.preferences["date_format"])
else
@tickle.due = ""
end
@saved = @tickle.save
end
# Delete a next action
#
@ -304,6 +241,7 @@ class TodoController < ApplicationController
@page_title = "TRACKS::Tickler"
@tickles = @user.todos.find(:all, :conditions => ['type = ?', "Deferred"], :order => "show_from ASC")
@count = @tickles.size
@on_page = "tickler"
end
# Called by periodically_call_remote
@ -339,9 +277,43 @@ class TodoController < ApplicationController
def init
@projects = @user.projects
@contexts = @user.contexts
@todos = Todo.find(:all, :conditions => ['user_id = ? and type = ?', @user.id, "Immediate"])
@done = Todo.find(:all, :conditions => ['user_id = ? and done = ?', @user.id, true], :order => 'completed DESC')
# @todos = @todos.collect { |x| (x.class == Immediate) ? x : nil }.compact
init_todos
end
def init_todos
@todos = Todo.find(:all, :conditions => ['user_id = ? and type = ?', @user.id, "Immediate"])
@done = Todo.find(:all, :conditions => ['user_id = ? and done = ?', @user.id, true], :order => 'completed DESC')
end
def perform_add_item(redirect_action)
if @item.due?
@item.due = Date.strptime(params["todo"]["due"], @user.preferences["date_format"])
else
@item.due = ""
end
@saved = @item.save
if @saved
init_todos
@up_count = @todos.reject { |x| x.done? or x.context.hide? }.size.to_s
end
respond_to do |wants|
wants.html { redirect_to :action => redirect_action }
wants.js
wants.xml { render :xml => @item.to_xml( :root => 'todo', :except => :user_id ) }
end
# if you're seeing the message 'An error occurred on the server.' and you want to debug, comment out the rescue section and check the Ajax response for an exception message
rescue
respond_to do |wants|
wants.html { render :action => redirect_action } # TODO: would prefer something like: flash["warning"] = 'An error occurred on the server.' render :action => 'list'
wants.js { render :action => 'error' }
wants.xml { render :text => 'An error occurred on the server.' + $! }
end
end
end

View file

@ -15,11 +15,6 @@ module TodoHelper
end
def link_to_remote_todo( item, handled_by, type)
if type == "deferred"
act = "edit_deferred_action"
else
act = "edit_action"
end
str = link_to_remote( image_tag("blank", :title =>"Delete action", :class=>"delete_item"),
{:url => { :controller => handled_by, :action => "destroy_action", :id => item.id },
@ -30,7 +25,7 @@ module TodoHelper
{
:update => "form-action-#{item.id}",
:loading => visual_effect(:pulsate, "action-#{item.id}-edit-icon"),
:url => { :controller => "todo", :action => act, :id => item.id },
:url => { :controller => "todo", :action => "edit_action", :id => item.id },
:success => "Element.toggle('item-#{item.id}','action-#{item.id}-edit-form'); new Effect.Appear('action-#{item.id}-edit-form', { duration: .2 }); Form.focusFirstElement('form-action-#{item.id}')"
},
{

View file

@ -13,8 +13,14 @@ class Context < ActiveRecord::Base
validates_uniqueness_of :name, :message => "already exists", :scope => "user_id"
validates_format_of :name, :with => /^[^\/]*$/i, :message => "cannot contain the slash ('/') character"
def self.list_of(hidden=false)
find(:all, :conditions => [ "hide = ?" , hidden ], :order => "position ASC")
def not_done_todos
@not_done_todos = self.find_not_done_todos if @not_done_todos == nil
@not_done_todos
end
def done_todos
@done_todos = self.find_done_todos if @done_todos == nil
@done_todos
end
def find_not_done_todos
@ -35,7 +41,7 @@ class Context < ActiveRecord::Base
# actions or multiple actions
#
def count_undone_todos(string="actions")
count = self.find_not_done_todos.size
count = self.not_done_todos.size
if count == 1
word = string.singularize
else

View file

@ -1,2 +1,9 @@
class Deferred < Todo
validates_presence_of :show_from
def validate
if show_from != nil && show_from < Date.today()
errors.add("Show From", "must be a date in the future.")
end
end
end

View file

@ -4,12 +4,4 @@ class Note < ActiveRecord::Base
attr_protected :user
def self.list_all
find(:all, :order => "created_at DESC")
end
def self.list_of(project_id)
find(:all, :conditions => [ "project_id = ?" , project_id ])
end
end

View file

@ -14,10 +14,6 @@ class Project < ActiveRecord::Base
validates_uniqueness_of :name, :message => "already exists", :scope =>"user_id"
validates_format_of :name, :with => /^[^\/]*$/i, :message => "cannot contain the slash ('/') character"
def self.list_of(isdone=0)
find(:all, :conditions => [ "done = ?" , true ], :order => "position ASC")
end
def description_present?
attribute_present?("description")
end
@ -26,15 +22,25 @@ class Project < ActiveRecord::Base
attribute_present?("linkurl")
end
def not_done_todos
@not_done_todos = self.find_not_done_todos if @not_done_todos == nil
@not_done_todos
end
def done_todos
@done_todos = self.find_done_todos if @done_todos == nil
@done_todos
end
def find_not_done_todos
todos = Todo.find :all, :conditions => ["project_id = ? AND done = ?", id, false],
:order => "due IS NULL, due ASC, created_at ASC"
Todo.find :all, :conditions => ["project_id = ? AND done = ?", id, false],
:order => "due IS NULL, due ASC, created_at ASC"
end
def find_done_todos
todos = Todo.find :all, :conditions => ["project_id = ? AND done = ?", id, true],
:order => "completed DESC",
:limit => @user.preferences["no_completed"].to_i
Todo.find :all, :conditions => ["project_id = ? AND done = ?", id, true],
:order => "completed DESC",
:limit => @user.preferences["no_completed"].to_i
end
# Returns a count of next actions in the given project
@ -42,7 +48,7 @@ class Project < ActiveRecord::Base
# actions or multiple actions
#
def count_undone_todos(string="actions")
count = find_not_done_todos.size
count = not_done_todos.size
if count == 1
word = string.singularize
else

View file

@ -1,5 +1,5 @@
<% @not_done = context.find_not_done_todos %>
<div id="c<%= context.id %>" class="container context">
<% @not_done = context.not_done_todos %>
<div id="c<%= context.id %>" class="container context" <%= "style=\"display:none\"" if collapsible && @not_done.empty? %>>
<h2>
<% if collapsible -%>
<a href="#" class="container_toggle" id="toggle_c<%= context.id %>"><%= image_tag("collapse.png") %></a>
@ -12,4 +12,4 @@
</div>
<%= render :partial => "todo/item", :collection => @not_done %>
</div><!-- [end:items] -->
</div><!-- [end:c<%= context.id %>] -->
</div><!-- [end:c<%= context.id %>] -->

View file

@ -1,4 +1,4 @@
<% @not_done = project.find_not_done_todos -%>
<% @not_done = project.not_done_todos -%>
<div id="p<%= project.id %>" class="container project">
<h2>

View file

@ -8,7 +8,7 @@
add_string = "Add a next action &#187;"
end
if request.request_uri == "/todo/tickler"
if @on_page == "tickler"
add_string = "Add a deferred action &#187;"
end
%>
@ -25,7 +25,7 @@
<div id="status">
</div>
<!--[form:todo]-->
<% if request.request_uri == "/todo/tickler" -%>
<% if @on_page == "tickler" -%>
<%= form_remote_tag(
:url => { :controller => controller.controller_name, :action => "add_deferred_item" },
:html=> { :id=>'todo-form-new-action', :name=>'todo', :class => 'inline-form' }) %>
@ -62,13 +62,16 @@
<%= hidden_field( "todo", "context_id", "value" => "#{@context.id}") %>
<% end -%>
<% if request.request_uri == "/todo/tickler" -%>
<% if @on_page == "tickler" -%>
<br /> <label for="todo_show_from">Show from</label><br />
<%= date_select( "todo", "show_from", :start_year => Date.today.year, :order => [:year, :month, :day] ) %>
<%= text_field("todo", "show_from", "size" => 10, "class" => "Date", "onFocus" => "Calendar.setup", "tabindex" => 5, "autocomplete" => "off") %><br />
<% end -%>
<br /><br />
<input type="submit" value="Add item" tabindex="6">
<%= end_form_tag %><!--[eoform:todo]-->
<%= calendar_setup( "todo_due" ) %>
<% if @on_page == "tickler" -%>
<%= calendar_setup( "todo_show_from" ) %>
<% end -%>
</div><!-- [end:todo-new-action] -->

View file

@ -49,7 +49,7 @@
<%= hidden_field( "todo", "context_id", "value" => "#{@context.id}") %>
<% end -%>
<% if request.request_uri == "/todo/tickler" -%>
<% if @on_page == "tickler" -%>
<tr>
<td><label for="todo_show_from">Show from</label></td>
<td><%= date_select( "todo", "show_from", :start_year => Date.today.year, :order => [:year, :month, :day] ) %></td>

View file

@ -1,62 +0,0 @@
<%
@item = action_edit_deferred_form
%>
<%= error_messages_for("item") %>
<%= hidden_field( "item", "id" ) %>
<table>
<tr>
<td class="label"><label for="item_description">Next action</label></td>
<td><%= text_field( "item", "description", "tabindex" => 1) %></td>
</tr>
<tr>
<td class="label"><label for="item_notes">Notes</label></td>
<td><%= text_area( "item", "notes", "cols" => 20, "rows" => 5, "tabindex" => 2) %></td>
</tr>
<tr>
<td class="label"><label for="item_context_id">Context</label></td>
<td><select name="item[context_id]" id="item_context_id" tabindex="3">
<% for @place in @contexts %>
<% if @item %>
<% if @place.id == @item.context_id %>
<option value="<%= @place.id %>" selected="selected"><%= @place.name %></option>
<% else %>
<option value="<%= @place.id %>"><%= @place.name %></option>
<% end %>
<% else %>
<option value="<%= @place.id %>"><%= @place.name %></option>
<% end %>
<% end %>
</select></td>
</tr>
<tr>
<td class="label"><label for="item_project_id">Project</label></td>
<td>
<select name="item[project_id]" id="item_project_id" tabindex="4">
<% if !@item.project_id? %>
<option selected="selected"></option>
<%= options_from_collection_for_select(@projects, "id", "name") %>
<% else %>
<option></option>
<%= options_from_collection_for_select(@projects, "id", "name", @item.project_id) %>
<% end %>
</select>
</td>
</tr>
<tr>
<td class="label"><label for="item_due">Due</td>
<td><input name="item[due]" id="due_<%= @item.id %>" type="text" value="<%= format_date(@item.due) %>" tabindex="5" size="10" onFocus="Calendar.setup" /></td>
</tr>
<tr>
<td class="label"><label for="item_show_from">Show from</label></td>
<td><%= date_select( "item", "show_from", :start_year => Date.today.year,
:order => [:year, :month, :day]) %></td>
</tr>
<tr>
<td><input type="hidden" name="on_project_page" value="true" /></td>
<td><input type="submit" value="Update" tabindex="6" />
<a href="javascript:void(0);" onclick="Element.toggle('item-<%= @item.id %>','action-<%= @item.id %>-edit-form');Form.reset('form-action-<%= @item.id %>');">Cancel</a></td>
</tr>
</table>
<%= calendar_setup( "due_#{@item.id}" ) %>
<% @item = nil %>

View file

@ -1,46 +0,0 @@
<%
add_string = "Add a deferred action &#187;"
%>
<% hide_link ||= false %>
<% unless hide_link -%>
<%= link_to_function(
add_string,
"Element.toggle('todo_new_action');Form.focusFirstElement('todo-form-new-action');",
{:title => "Add the next action", :accesskey => "n"}) %>
<% end -%>
<div id="todo_new_action" class="context_new" style="display:<%= hide_link ? 'block' : 'none'%>">
<div id="status">
</div>
<!--[form:todo]-->
<%= form_remote_tag(
:url => { :controller => "todo", :action => "add_deferred_item" },
:html=> { :id=>'todo-form-new-action', :name=>'todo', :class => 'inline-form' }) %>
<label for="todo_description">Description</label><br />
<%= text_field( "todo", "description", "size" => 25, "tabindex" => 1) %><br />
<label for="todo_notes">Notes</label><br />
<%= text_area( "todo", "notes", "cols" => 25, "rows" => 10, "tabindex" => 2) %><br />
<label for="todo_context_id">Context</label><br />
<%= collection_select( "todo", "context_id", @contexts, "id", "name",
{}, {"tabindex" => 3}) %><br />
<label for="todo_project_id">Project</label><br />
<%= collection_select( "todo", "project_id", @projects, "id", "name",
{ :include_blank => true }, {"tabindex" => 4}) %><br />
<label for="todo_due">Due</label><br />
<%= text_field("todo", "due", "size" => 10, "class" => "Date", "onFocus" => "Calendar.setup", "tabindex" => 5, "autocomplete" => "off") %><br />
<label for="todo_show_from">Show from</label><br />
<%= date_select( "todo", "show_from", :start_year => Date.today.year, :order => [:year, :month, :day] ) %>
<br /><br />
<input type="submit" value="Add item" tabindex="6">
<%= end_form_tag %><!--[eoform:todo]-->
<%= calendar_setup( "todo_due" ) %>
</div><!-- [end:todo-new-action] -->

View file

@ -1,13 +1,12 @@
page.hide "status"
if @saved
page.hide "status"
page.replace_html "status", content_tag("div", "Added new next action", "class" => "confirmation")
page.visual_effect :appear, 'status', :duration => 0.5
page.replace_html "badge_count", @up_count
page.send :record, "Form.reset('todo-form-new-action');Form.focusFirstElement('todo-form-new-action')"
page.insert_html :bottom, "tickler", :partial => 'todo/tickle'
page.visual_effect :highlight, "item-#{@tickle.id}-container", :duration => 3
page.insert_html :bottom, "tickler", :partial => 'todo/tickle', :object => @item
page.visual_effect :highlight, "item-#{@item.id}-container", :duration => 3
else
page.hide "status"
page.replace_html "status", content_tag("div", content_tag("h2", "#{pluralize(@tickle.errors.count, "error")} prohibited this record from being saved") + content_tag("p", "There were problems with the following fields:") + content_tag("ul", @tickle.errors.each_full { |msg| content_tag("li", msg) }), "id" => "ErrorExplanation", "class" => "ErrorExplanation")
page.replace_html "status", content_tag("div", content_tag("h2", "#{pluralize(@item.errors.count, "error")} prohibited this record from being saved") + content_tag("p", "There were problems with the following fields:") + content_tag("ul", @item.errors.each_full { |msg| content_tag("li", msg) }), "id" => "ErrorExplanation", "class" => "ErrorExplanation")
page.visual_effect :appear, 'status', :duration => 0.5
end

View file

@ -1,6 +1,7 @@
page.hide "info"
if @saved
if @tickle.context_id == @original_item_context_id
page.replace_html "item-#{@tickle.id}-container", :partial => 'todo/tickle'
page.replace "item-#{@tickle.id}-container", :partial => 'todo/tickle'
page.visual_effect :highlight, "item-#{@tickle.id}-container", :duration => 3
else
page["item-#{@tickle.id}-container"].remove
@ -8,7 +9,6 @@ if @saved
page.visual_effect :highlight, "item-#{@tickle.id}-container", :duration => 3
end
else
page.hide "info"
page.replace_html "info", content_tag("div", content_tag("div", "#{pluralize(@tickle.errors.count, "error")} prohibited this record from being saved", "id" => "warning", "class" => "warning") + content_tag("p", "There were problems with the following fields:") + content_tag("ul", @tickle.errors.each_full { |msg| content_tag("li", msg) }))
page.visual_effect :appear, 'info', :duration => 0.5
end

View file

@ -1,6 +1,3 @@
<%
@item = action_edit_form
%>
<%= error_messages_for("item") %>
<%= hidden_field( "item", "id" ) %>
@ -47,13 +44,21 @@
<td class="label"><label for="item_due">Due</td>
<td><input name="item[due]" id="due_<%= @item.id %>" type="text" value="<%= format_date(@item.due) %>" tabindex="5" size="10" onFocus="Calendar.setup" /></td>
</tr>
<% if @item.class == Deferred -%>
<tr>
<% if controller.controller_name == "project" -%>
<td class="label"><label for="item_show_from">Show from</td>
<td><input name="item[show_from]" id="show_from_<%= @item.id %>" type="text" value="<%= format_date(@item.show_from) %>" tabindex="5" size="10" onFocus="Calendar.setup" /></td>
</tr>
<% end -%>
<% if controller.controller_name == "project" || @item.class == 'Deferred' -%>
<input type="hidden" name="on_project_page" value="true" />
<% end -%>
<tr>
<td><input type="submit" value="Update" tabindex="6" />
<a href="javascript:void(0);" onclick="Element.toggle('item-<%= @item.id %>','action-<%= @item.id %>-edit-form');Form.reset('form-action-<%= @item.id %>');">Cancel</a></td>
</tr>
</table>
<%= calendar_setup( "due_#{@item.id}" ) %>
<% @item = nil %>
<% if @item.class == Deferred -%>
<%= calendar_setup( "show_from_#{@item.id}" ) %>
<% end -%>

View file

@ -6,7 +6,7 @@ xml.todos_by_context do
xml.hide c.hide, :type => :boolean
xml.id c.id, :type => :integer
xml.position c.position, :type => :integer
c.find_not_done_todos.each { |t|
c.not_done_todos.each { |t|
xml << t.to_xml( :skip_instruct => true, :root => 'todo', :except => [:user_id, :context_id] )
}
end

View file

@ -1,7 +1,8 @@
page.hide "info"
if @saved
item_container_id = "item-#{@item.id}-container"
if @item.context_id == @original_item_context_id
page.replace_html item_container_id, :partial => 'todo/item'
page.replace item_container_id, :partial => 'todo/item'
page.visual_effect :highlight, item_container_id, :duration => 3
else
page[item_container_id].remove
@ -14,7 +15,6 @@ if @saved
end
end
else
page.hide "info"
page.replace_html "info", content_tag("div", content_tag("div", "#{pluralize(@item.errors.count, "error")} prohibited this record from being saved", "id" => "warning", "class" => "warning") + content_tag("p", "There were problems with the following fields:") + content_tag("ul", @item.errors.each_full { |msg| content_tag("li", msg) }))
page.visual_effect :appear, 'info', :duration => 0.5
end