* Replaced select widgets with AutoCompleters for project & context in new item and edit forms. You can now create a new project and/or context on the fly as you're adding an item.

* Rolled Deferred controller, views & helper into Todo.
* Made the show_from field always available on the add new item and edit forms.
* Added validation to Todo to make sure a context is specified.
* Set initial state of Todo to :deferred when show_from is specified (I still need to make handle setting show_from during an edit).
* Created a generic rescue_action in ApplicationController and removed boilerplate rescue code from a few actions in TodoController.
* Made all Todo creation requests use the TodoController, removing duplicate logic from ContextController and ContextController
* Removed unused lightbox-style add item form
* Remove unused update_context and update_project actions
* Updated rails javascripts to the same as our vendor/rails



git-svn-id: http://www.rousette.org.uk/svn/tracks-repos/trunk@352 a4c988fc-2ded-0310-b66e-134b36920a42
This commit is contained in:
lukemelia 2006-11-20 04:31:00 +00:00
parent 5d51ca84ba
commit bb1cfe613a
36 changed files with 627 additions and 720 deletions

View file

@ -54,6 +54,18 @@ class ApplicationController < ActionController::Base
render :text => message, :status => status
end
def rescue_action(exception)
log_error(exception) if logger
respond_to do |wants|
wants.html do
notify :warning, "An error occurred on the server."
render :action => "index"
end
wants.js { render :action => 'error' }
wants.xml { render :text => 'An error occurred on the server.' + $! }
end
end
private
def get_current_user

View file

@ -61,46 +61,6 @@ class ContextController < ApplicationController
end
end
# Called by a form button
# Parameters from form fields are passed to create new action
# in the selected context.
def add_item
self.init
@item = @user.todos.build
@item.attributes = params["todo"]
if @item.due?
@date = parse_date_per_user_prefs(params["todo"]["due"])
@item.due = @date.to_s(:db)
else
@item.due = ""
end
@saved = @item.save
if @saved
@up_count = Todo.find(:all, :conditions => ["todos.user_id = ? and todos.state = ? and todos.context_id = ?", @user.id, 'active', @item.context_id]).size.to_s
end
return if request.xhr?
# fallback for standard requests
if @saved
notify :notice, 'Added new next action.'
redirect_to :controller => 'todo', :action => 'list'
else
notify :warning, 'The next action was not added. Please try again.'
redirect_to :controller => 'todo', :action => 'list'
end
rescue
if request.xhr? # be sure to include an error.rjs
render :action => 'error'
else
notify :warning, 'An error occurred on the server.'
redirect_to :controller => 'todo', :action => 'list'
end
end
# Edit the details of the context
#
def update

View file

@ -1,131 +0,0 @@
class DeferredController < ApplicationController
model :user
model :project
model :context
helper :todo
prepend_before_filter :login_required
layout "standard"
def index
@source_view = 'deferred'
init_data_for_sidebar
@page_title = "TRACKS::Tickler"
@tickles = @user.todos.find_in_state(:all, :deferred, :order => "show_from ASC")
@count = @tickles.size
end
def create
@source_view = 'deferred'
@item = Todo.new_deferred
@item.attributes = params["todo"]
if params["todo"]["show_from"]
@item.show_from = parse_date_per_user_prefs(params["todo"]["show_from"])
end
@item.user_id = @user.id
if @item.due?
@item.due = parse_date_per_user_prefs(params["todo"]["due"])
else
@item.due = ""
end
@saved = @item.save
if @saved
@up_count = @user.todos.count_in_state(:deferred)
end
respond_to do |wants|
wants.html { redirect_to :action => "index" }
wants.js
wants.xml { render :xml => @item.to_xml( :root => 'todo', :except => :user_id ) }
end
end
def edit
@source_view = 'deferred'
init_projects_and_contexts
@item = check_user_return_item
render :template => 'todo/edit.rjs'
end
def update
@source_view = 'deferred'
@item = check_user_return_item
@original_item_context_id = @item.context_id
@item.attributes = params["item"]
if params["item"]["show_from"]
@item.show_from = parse_date_per_user_prefs(params["item"]["show_from"])
end
if @item.due?
@item.due = parse_date_per_user_prefs(params["item"]["due"])
else
@item.due = ""
end
@saved = @item.save
end
def destroy
@item = check_user_return_item
context_id = @item.context_id
@saved = @item.destroy
respond_to do |wants|
wants.html do
notify :notice, 'Successfully deleted next action' if @saved
redirect_to :action => "index"
end
wants.js do
@down_count = @user.todos.count_in_state(:deferred) if @saved
render
end
wants.xml { render :xml => @item.to_xml( :root => 'todo', :except => :user_id ) }
end
rescue
respond_to do |wants|
wants.html do
notify :warning, 'An error occurred on the server.'
redirect_to :action => "index"
end
wants.js { render :action => 'error' }
wants.xml { render :text => "500 Server Error: There was an error deleting the action.", :status => 500 }
end
end
# Check for any due tickler items, activate them
# Called by periodically_call_remote
def check_tickler
now = Date.today()
@due_tickles = @user.todos.find_in_state(:all, :deferred, :conditions => ['show_from < ? OR show_from = ?', now, now ], :order => "show_from ASC")
# Change the due tickles to active
@due_tickles.each do |t|
t.activate!
t.save
end
respond_to do |wants|
wants.html { redirect_to :controller => 'todo', :action => 'index' }
wants.js
end
end
private
def check_user_return_item
item = Todo.find( params['id'] )
if @user == item.user
return item
else
notify :warning, "Item and session user mis-match: #{item.user.name} and #{@user.name}!"
render_text ""
end
end
end

View file

@ -86,46 +86,6 @@ class ProjectController < ApplicationController
end
end
# Called by a form button
# Parameters from form fields are passed to create new action
# in the selected context.
def add_item
self.init
@item = @user.todos.build
@item.attributes = params["todo"]
if @item.due?
@date = parse_date_per_user_prefs(params["todo"]["due"])
@item.due = @date.to_s(:db)
else
@item.due = ""
end
@saved = @item.save
if @saved
@up_count = Todo.find(:all, :conditions => ["todos.user_id = ? and todos.state = ? and todos.project_id = ?", @user.id, 'active', @item.project_id]).size.to_s
end
return if request.xhr?
# fallback for standard requests
if @saved
notify :notice, 'Added new next action.'
redirect_to :controller => 'todo', :action => 'index'
else
notify :warning, 'The next action was not added. Please try again.'
redirect_to :controller => 'todo', :action => 'index'
end
rescue
if request.xhr? # be sure to include an error.rjs
render :action => 'error'
else
notify :warning, 'An error occurred on the server.'
redirect_to :controller => 'todo', :action => 'index'
end
end
# Edit the details of the project
#
def update

View file

@ -62,15 +62,41 @@ class TodoController < ApplicationController
def create
init
@item = @user.todos.build
p = params['todo'] || params['request']['todo']
@item.attributes = p
p = params['request'] || params
@item.attributes = p['todo']
if p['todo']['project_id'].blank? && !p['project_name'].blank? && p['project_name'] != 'None'
project = @user.projects.find_by_name(p['project_name'].strip)
unless project
project = @user.projects.build
project.name = p['project_name'].strip
project.save
@new_project_created = true
end
@item.project_id = project.id
end
if p['todo']['context_id'].blank? && !p['context_name'].blank?
context = @user.contexts.find_by_name(p['context_name'].strip)
unless context
context = @user.contexts.build
context.name = p['context_name'].strip
context.save
@new_context_created = true
end
@item.context_id = context.id
end
if @item.due?
@date = parse_date_per_user_prefs(p["due"])
@date = parse_date_per_user_prefs(p['todo']['due'])
@item.due = @date.to_s(:db)
else
@item.due = ""
end
if p['todo']['show_from']
@item.show_from = parse_date_per_user_prefs(p['todo']['show_from'])
end
@saved = @item.save
@ -78,28 +104,12 @@ class TodoController < ApplicationController
wants.html { redirect_to :action => "index" }
wants.js do
if @saved
init_todos
@up_count = @todos.reject { |x| !x.active? or x.context.hide? }.size.to_s
determine_down_count
end
render :action => 'create'
end
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 do
notify :warning, "An error occurred on the server."
render :action => "index"
end
wants.js { render :action => 'error' }
wants.xml { render :text => 'An error occurred on the server.' + $! }
end
end
def add_item
create
end
def edit
@ -119,7 +129,6 @@ class TodoController < ApplicationController
#
def toggle_check
init
logger.info "source view is " + @source_view
@item = check_user_return_item
@item.toggle_completion()
@saved = @item.save
@ -144,7 +153,28 @@ class TodoController < ApplicationController
@item = check_user_return_item
@original_item_context_id = @item.context_id
@original_item_project_id = @item.project_id
@item.attributes = params["item"]
if params['item']['project_id'].blank? && !params['project_name'].blank? && params['project_name'] != 'None'
project = @user.projects.find_by_name(params['project_name'].strip)
unless project
project = @user.projects.build
project.name = params['project_name'].strip
project.save
@new_project_created = true
end
params["item"]["project_id"] = project.id
end
if params['item']['context_id'].blank? && !params['context_name'].blank?
context = @user.contexts.find_by_name(params['context_name'].strip)
unless context
context = @user.contexts.build
context.name = params['context_name'].strip
context.save
@new_context_created = true
end
params["item"]["context_id"] = context.id
end
if params["item"].has_key?("due")
params["item"]["due"] = parse_date_per_user_prefs(params["item"]["due"])
else
@ -155,42 +185,9 @@ class TodoController < ApplicationController
if @context_changed then @remaining_undone_in_context = @user.contexts.find(@original_item_context_id).not_done_todos.length; end
@project_changed = @original_item_project_id != @item.project_id
if (@project_changed && !@original_item_project_id.nil?) then @remaining_undone_in_project = @user.projects.find(@original_item_project_id).not_done_todos.length; end
determine_down_count
end
def update_context
init
@item = check_user_return_item
context = Context.find(params['context_id']);
if @user == context.user
@original_item_context_id = @item.context_id
@item.context_id = context.id
@item.context = context
@saved = @item.save
render :action => 'update'
else
render :update do |page|
page.notify :warning, content_tag("div", "Error updating the context of the dragged item. Item and context user mis-match: #{@item.user.name} and #{@context.user.name}! - refresh the page to see them."), 8.0
end
end
end
def update_project
init
@item = check_user_return_item
project = Project.find(params['project_id']);
if @user == project.user
@original_item_context_id = @item.context_id
@item.project_id = project.id
@item.project = project
@saved = @item.save
render :action => 'update'
else
render :update do |page|
page.notify :warning, content_tag("div", "Error updating the project of the dragged item. Item and project user mis-match: #{@item.user.name} and #{@project.user.name}! - refresh the page to see them."), 8.0
end
end
end
def destroy
@item = check_user_return_item
@context_id = @item.context_id
@ -224,16 +221,6 @@ class TodoController < ApplicationController
wants.xml { render :text => '200 OK. Action deleted.', :status => 200 }
end
rescue
respond_to do |wants|
wants.html do
notify :error, 'An error occurred on the server.', 8.0
redirect_to :action => 'index'
end
wants.js { render :action => 'error' }
wants.xml { render :text => 'An error occurred on the server.' + $! }
end
end
def completed
@ -250,6 +237,31 @@ class TodoController < ApplicationController
@done_archive = @done.completed_more_than 28.day.ago
end
def tickler
init
@source_view = 'deferred'
@page_title = "TRACKS::Tickler"
@tickles = @user.todos.find_in_state(:all, :deferred, :order => "show_from ASC")
@count = @tickles.size
end
# Check for any due tickler items, activate them
# Called by periodically_call_remote
def check_tickler
now = Date.today()
@due_tickles = @user.todos.find_in_state(:all, :deferred, :conditions => ['show_from < ? OR show_from = ?', now, now ], :order => "show_from ASC")
# Change the due tickles to active
@due_tickles.each do |t|
t.activate!
t.save
end
respond_to do |wants|
wants.html { redirect_to :controller => 'todo', :action => 'index' }
wants.js
end
end
private
def check_user_return_item
@ -296,6 +308,9 @@ class TodoController < ApplicationController
@down_count = @user.projects.find(@item.project_id).todos.count_in_state(:active)
end
end
from.deferred do
@down_count = @user.todos.count_in_state(:deferred)
end
end
end

View file

@ -1,2 +0,0 @@
module DeferredHelper
end

View file

@ -7,16 +7,14 @@ module TodoHelper
count = Todo.find_all("done=0 AND context_id=#{context.id}").length
end
def form_remote_tag_edit_todo( item, type )
(type == "deferred") ? controller_name = 'deferred' : controller_name = 'todo'
form_remote_tag( :url => { :controller => controller_name, :action => 'update', :id => item.id },
def form_remote_tag_edit_todo( item )
form_remote_tag( :url => { :controller => 'todo', :action => 'update', :id => item.id },
:html => { :id => "form-action-#{item.id}", :class => "inline-form" }
)
end
def link_to_remote_todo( item, options = {})
(options[:type] == "deferred") ? controller_name = 'deferred' : controller_name = 'todo'
url_options = { :controller => controller_name, :action => 'destroy', :id => item.id, :_source_view => @source_view }
def link_to_remote_todo(item)
url_options = { :controller => 'todo', :action => 'destroy', :id => item.id, :_source_view => @source_view }
str = link_to_remote( image_tag_for_delete,
{ :url => url_options, :confirm => "Are you sure that you want to delete the action, \'#{item.description}\'?" },
@ -107,6 +105,33 @@ module TodoHelper
javascript_tag str
end
def item_container_id
return "tickler-items" if source_view_is :deferred
return "p#{@item.project_id}" if source_view_is :project
return "c#{@item.context_id}"
end
def parent_container_type
return 'tickler' if source_view_is :deferred
return 'project' if source_view_is :project
return 'context'
end
def empty_container_msg_div_id
return "p#{@item.project_id}empty-nd" if source_view_is :project
return "c#{@item.context_id}empty-nd" if source_view_is :context
return "tickler-empty-nd" if source_view_is :deferred
nil
end
def project_names_for_autocomplete
array_or_string_for_javascript( ['None'] + @projects.collect{|p| p.name } )
end
def context_names_for_autocomplete
array_or_string_for_javascript( @contexts.collect{|c| c.name } )
end
private
def image_tag_for_delete

View file

@ -42,6 +42,7 @@ class Todo < ActiveRecord::Base
validates_length_of :notes, :maximum => 60000, :allow_nil => true
# validates_chronic_date :due, :allow_nil => true
validates_presence_of :show_from, :if => :deferred?
validates_presence_of :context
def validate
if deferred? && show_from != nil && show_from < Date.today()
@ -63,12 +64,14 @@ class Todo < ActiveRecord::Base
original_project.nil? ? Project.null_object : original_project
end
def self.new_deferred
todo = self.new
def todo.set_initial_state
self.state = 'deferred'
alias_method :original_set_initial_state, :set_initial_state
def set_initial_state
if show_from && (show_from > Date.today())
write_attribute self.class.state_column, 'deferred'
else
original_set_initial_state
end
todo
end
def self.not_done( id=id )

View file

@ -7,8 +7,6 @@
</div><!-- [end:display_box] -->
<div id="input_box">
<%= render :partial => "shared/add_new_item_form", :locals => {:hide_link => false, :msg => ""} %>
<%= render :partial => "shared/new_action_form", :locals => {:hide_link => false, :msg => ""} %>
<%= render :partial => "shared/new_action_form" %>
<%= render :partial => "shared/add_new_item_form" %>
<%= render "shared/sidebar" %>
</div><!-- End of input box -->

View file

@ -1,25 +0,0 @@
<div id="item-<%= item.id %>-container" class="item-container">
<div id="item-<%= item.id %>">
<%= link_to_remote_todo item, { :type => 'deferred' } %>
<div class="description">
<%= show_date( item.show_from ) -%>
<%= sanitize(item.description) %>
<% if item.due -%>
(action due on <%= item.due.to_s %>)
<% end -%>
<%= link_to( "[C]", { :controller => "context", :action => "show", :name => urlize(item.context.name) }, :title => "View context: #{item.context.name}" ) %>
<% if item.project_id -%>
<%= link_to( "[P]", { :controller => "project", :action => "show", :name => urlize(item.project.name) }, :title => "View project: #{item.project.name}" ) %>
<% end -%>
<% if item.notes? -%>
<%= toggle_show_notes( item ) %>
<% end -%>
</div>
</div><!-- [end:item-<%= item.id %>] -->
<div id="action-<%= item.id %>-edit-form" class="edit-form" style="display:none;">
<%= form_remote_tag_edit_todo( item, "deferred" ) -%>
<% #note: edit form will load here remotely -%>
<%= end_form_tag -%>
</div><!-- [end:action-<%= item.id %>-edit-form] -->
</div><!-- [end:item-<%= item.id %>-container] -->

View file

@ -1,12 +0,0 @@
<div id="tickler" class="container project">
<h2>Deferred actions</h2>
<div class="items toggle_target">
<div id="tickler-empty-nd" style="display:<%= @tickles.empty? ? 'block' : 'none'%>;">
<div class="message"><p>Currently there are no deferred actions</p></div>
</div>
<%= render :partial => "item", :collection => @tickles %>
</div><!-- [end:items] -->
</div><!-- [end:tickler] -->

View file

@ -1,12 +0,0 @@
page.hide "status"
if @saved
page.notify :notice, "Added new next action", 5.0
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 => 'deferred/item', :object => @item
page.visual_effect :highlight, "item-#{@item.id}-container", :duration => 3
page["tickler-empty-nd"].hide
else
page.show 'status'
page.replace_html 'status', "#{error_messages_for('item')}"
end

View file

@ -1,9 +0,0 @@
if @saved
page["item-#{@item.id}-container"].remove
page['badge_count'].replace_html @down_count
if @down_count == 0
page.visual_effect :appear, "tickler-empty-nd", :duration => 0.4
end
else
page.notify :error, "There was an error deleting the item #{@item.description}", 8.0
end

View file

@ -1 +0,0 @@
page.notify :error, @error_message || "An error occurred on the server.", 8.0

View file

@ -1,10 +0,0 @@
<div id="display_box">
<%= render :partial => "items" %>
</div><!-- End of display_box -->
<div id="input_box">
<%= render :partial => "shared/add_new_item_form", :locals => {:hide_link => false, :msg => ""} %>
<%= render "shared/sidebar" %>
</div><!-- End of input box -->

View file

@ -1,14 +0,0 @@
page.hide "info"
if @saved
if @item.context_id == @original_item_context_id
page.replace "item-#{@item.id}-container", :partial => 'deferred/item'
page.visual_effect :highlight, "item-#{@item.id}-container", :duration => 3
else
page["item-#{@item.id}-container"].remove
page.insert_html :bottom, "c#{@item.context_id}items", :partial => 'deferred/item'
page.visual_effect :highlight, "item-#{@item.id}-container", :duration => 3
end
else
page.show 'status'
page.replace_html 'status', "#{error_messages_for('item')}"
end

View file

@ -46,7 +46,7 @@
<li><%= navigation_link("Home", {:controller => "todo", :action => "index"}, {:accesskey => "t", :title => "Home"} ) %></li>
<li><%= navigation_link( "Contexts", {:controller => "context", :action => "list"}, {:accesskey=>"c", :title=>"Contexts"} ) %></li>
<li><%= navigation_link( "Projects", {:controller => "project", :action => "list"}, {:accesskey=>"p", :title=>"Projects"} ) %></li>
<li><%= navigation_link( "Tickler", {:controller => "deferred", :action => "index"}, :title => "Ticker" ) %></li>
<li><%= navigation_link( "Tickler", {:controller => "todo", :action => "tickler"}, :title => "Tickler" ) %></li>
<li><%= navigation_link( "Done", {:controller => "todo", :action => "completed"}, {:accesskey=>"d", :title=>"Completed"} ) %></li>
<li><%= navigation_link( "Notes", {:controller => "note", :action => "index"}, {:accesskey => "o", :title => "Show all notes"} ) %></li>
<li><%= navigation_link( "Preferences", {:controller => "user", :action => "preferences"}, {:accesskey => "u", :title => "Show my preferences"} ) %></li>
@ -63,7 +63,7 @@
<%= periodically_call_remote( :url => {:controller => "login", :action => "check_expiry"},
:frequency => (5*60)) %>
<% end -%>
<%= periodically_call_remote( :url => {:controller => "deferred", :action => "check_tickler"},
<%= periodically_call_remote( :url => {:controller => "todo", :action => "check_tickler"},
:frequency => (10*60)) %>
<%= yield %>
</div>

View file

@ -46,8 +46,6 @@
</div><!-- [end:display_box] -->
<div id="input_box">
<%= render :partial => "shared/add_new_item_form", :locals => {:hide_link => false, :msg => ""} %>
<%= render :partial => "shared/new_action_form", :locals => {:hide_link => false, :msg => ""} %>
<%= render "shared/sidebar" %>
<%= render :partial => "shared/add_new_item_form" %>
<%= render "shared/sidebar" %>
</div><!-- End of input box -->

View file

@ -1,44 +1,19 @@
<%
case controller.controller_name
when "context"
add_string = "Add a next action in this context &#187;"
@selected_context = @context.id
@selected_project = nil
when "project"
add_string = "Add a next action in this project &#187;"
@selected_context = @contexts[0].id unless @contexts.empty?
@selected_project = @project.id
when "deferred"
add_string = "Add a deferred action &#187;"
@selected_context = @contexts[0].id unless @contexts.empty?
@selected_project = nil
else
add_string = "Add a next action &#187;"
@selected_context = @contexts[0].id unless @contexts.empty?
@selected_project = nil
end
@initial_context_name = @context.name unless @context.nil?
@initial_context_name ||= @contexts[0].name unless @contexts[0].nil?
@initial_project_name = @project.name unless @project.nil?
%>
<% 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 -%>
<%= link_to_function("Add a next action &#187;",
"Element.toggle('todo_new_action');Form.focusFirstElement('todo-form-new-action');",
{:title => "Add a next action", :accesskey => "n"}) %>
<div id="todo_new_action" class="context_new" style="display:<%= hide_link ? 'block' : 'none'%>">
<div id="todo_new_action" class="context_new" style="display:block">
<!--[form:todo]-->
<% if controller.controller_name == "deferred" -%>
<%= form_remote_tag(
:url => { :controller => "deferred", :action => "create" },
:html=> { :id=>'todo-form-new-action', :name=>'todo', :class => 'inline-form' }) %>
<% else -%>
<%= form_remote_tag(
:url => { :controller => controller.controller_name, :action => "add_item" },
:url => { :controller => "todo", :action => "create" },
:html=> { :id=>'todo-form-new-action', :name=>'todo', :class => 'inline-form' }) %>
<% end -%>
<div id="status"><%= error_messages_for("item") %></div>
@ -46,28 +21,40 @@
<%= 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 />
<%= text_area( "todo", "notes", "cols" => 25, "rows" => 6, "tabindex" => 2) %><br />
<label for="todo_context_id">Context</label><br />
<%= select("todo", "context_id", @contexts.collect {|c| [c.name, c.id] }, { :selected => @selected_context }, {"tabindex" => 3}) %>
<label for="todo_context_name">Context</label><br />
<input id="todo_context_name" name="context_name" autocomplete="off" tabindex="3" size="25" type="text" value="<%= @initial_context_name %>" />
<div class="page_name_auto_complete" id="context_list" style="display:none"></div>
<script type="text/javascript">
contextAutoCompleter = new Autocompleter.Local('todo_context_name', 'context_list', <%= context_names_for_autocomplete %>, {choices:100,autoSelect:true});
Event.observe($('todo_context_name'), "focus", contextAutoCompleter.activate.bind(contextAutoCompleter));
Event.observe($('todo_context_name'), "click", contextAutoCompleter.activate.bind(contextAutoCompleter));
</script>
<br />
<label for="todo_project_id">Project</label><br />
<%= select( "todo", "project_id", @projects.select{|x| x.active? }.collect {|p| [p.name, p.id] },
{ :selected => @selected_project, :include_blank => true }, {"tabindex" => 4}) %>
<label for="todo_project_name">Project</label><br />
<input id="todo_project_name" name="project_name" autocomplete="off" tabindex="4" size="25" type="text" value="<%= @initial_project_name %>" />
<div class="page_name_auto_complete" id="project_list" style="display:none"></div>
<script type="text/javascript">
projectAutoCompleter = new Autocompleter.Local('todo_project_name', 'project_list', <%= project_names_for_autocomplete %>, {choices:100,autoSelect:true});
Event.observe($('todo_project_name'), "focus", projectAutoCompleter.activate.bind(projectAutoCompleter));
Event.observe($('todo_project_name'), "click", projectAutoCompleter.activate.bind(projectAutoCompleter));
</script>
<br />
<label for="todo_due">Due</label><br />
<%= text_field("todo", "due", "size" => 10, "class" => "Date", "onFocus" => "Calendar.setup", "tabindex" => 5, "autocomplete" => "off") %>
<% if controller.controller_name == "deferred" -%>
<br /> <label for="todo_show_from">Show from</label><br />
<%= text_field("todo", "show_from", "size" => 10, "class" => "Date", "onFocus" => "Calendar.setup", "tabindex" => 5, "autocomplete" => "off") %><br />
<% end -%>
<%= text_field("todo", "show_from", "size" => 10, "class" => "Date", "onFocus" => "Calendar.setup", "tabindex" => 6, "autocomplete" => "off") %><br />
<div id="date-preview" style="display: none;"></div>
<br /><br />
<input type="submit" value="Add item" tabindex="6">
<%= source_view_tag( @source_view ) %>
<input type="submit" value="Add item" tabindex="7">
<%= end_form_tag %><!--[eoform:todo]-->
<%= observe_field "todo_due",
@ -78,7 +65,5 @@
:url => { :controller => "todo", :action => "date_preview" } %>
<%= calendar_setup( "todo_due" ) %>
<% if controller.controller_name == "deferred" -%>
<%= calendar_setup( "todo_show_from" ) %>
<% end -%>
</div><!-- [end:todo-new-action] -->

View file

@ -1,71 +0,0 @@
<%
@selected_context = @contexts[0].id unless @contexts.empty?
@selected_project = nil
case controller.controller_name
when "context"
add_string = "Add a next action in this context &#187;"
@selected_context = @context.id
when "project"
add_string = "Add a next action in this project &#187;"
@selected_project = @project.id
when "deferred"
add_string = "Add a next action &#187;"
else
add_string = "Add a deferred action &#187;"
end
%>
<% hide_link ||= false %>
<% unless hide_link -%>
<%= link_to_function(
"&nbsp;",
"onclick=new Lightbox.base('mybox', { closeOnOverlayClick : true });Form.focusFirstElement('todo-form-new-action-lightbox'); return false;",
{:title => "Add the next action", :accesskey => "q"}) %>
<% end -%>
<div id="mybox" style="display:none">
<div id="todo_new_action-lightbox" class="context_new">
<%= form_remote_tag(
:url => { :controller => controller.controller_name, :action => "add_item" },
:html=> { :id=>'todo-form-new-action-lightbox', :name=>'todo', :class => 'inline-form' }) %>
<h2>Add a new next action:</h2>
<div id="status">
</div>
<table>
<tr>
<td><label for="todo_description">Description</label></td>
<td><%= text_field( "todo", "description", "size" => 30, "tabindex" => 1) %></td>
</tr>
<tr>
<td><label for="todo_notes">Notes</label></td>
<td><%= text_area( "todo", "notes", "cols" => 25, "rows" => 10, "tabindex" => 2) %></td>
</tr>
<tr>
<td><label for="todo_context_id">Context</label></td>
<td><%= select("todo", "context_id", @contexts.collect {|c| [c.name, c.id] }, { :selected => @selected_context }, {"tabindex" => 3}) %></td>
</tr>
<tr>
<td><label for="todo_project_id">Project</label></td>
<td><%= select( "todo", "project_id", @projects.select{|x| x.active? }.collect {|p| [p.name, p.id] }, { :selected => @selected_project, :include_blank => true }, {"tabindex" => 4}) %></td>
</tr>
<tr>
<td><label for="todo_due">Due</label></td>
<td><%= text_field("todo", "due", "size" => 10, "class" => "Date", "onFocus" => "Calendar.setup", "tabindex" => 5, "autocomplete" => "off") %></td>
</tr>
<% if controller.controller_name == "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>
</tr>
<% end -%>
<tr>
<td></td>
<td><input type="submit" value="Add item" tabindex="6"></td>
</tr>
</table>
<%= end_form_tag %><!--[eoform:todo]-->
<%= calendar_setup( "todo_due" ) %>
</div><!-- [end:todo-new-action] -->
</div>

View file

@ -13,34 +13,26 @@
<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>
<td class="label"><label for="item_context_name">Context</label></td>
<td><input id="item_context_name" name="context_name" autocomplete="off" tabindex="3" size="25" type="text" value="<%= @item.context.name %>" />
<div class="page_name_auto_complete" id="edit_form_context_list" style="display:none"></div></td>
<script type="text/javascript">
editFormContextAutoCompleter = new Autocompleter.Local('item_context_name', 'edit_form_context_list', <%= context_names_for_autocomplete %>, {choices:100,autoSelect:true});
Event.observe($('item_context_name'), "focus", editFormContextAutoCompleter.activate.bind(editFormContextAutoCompleter));
Event.observe($('item_context_name'), "click", editFormContextAutoCompleter.activate.bind(editFormContextAutoCompleter));
</script>
</tr>
<tr>
<td class="label"><label for="item_project_id">Project</label></td>
<td class="label"><label for="item_project_name">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>
<input id="item_project_name" name="project_name" autocomplete="off" tabindex="4" size="25" type="text" value="<%= @item.project.nil? ? 'None' : @item.project.name %>" />
<div class="page_name_auto_complete" id="edit_form_project_list" style="display:none"></div>
</td>
<script type="text/javascript">
editFormProjectAutoCompleter = new Autocompleter.Local('item_project_name', 'edit_form_project_list', <%= project_names_for_autocomplete %>, {choices:100,autoSelect:true});
Event.observe($('item_project_name'), "focus", editFormProjectAutoCompleter.activate.bind(editFormProjectAutoCompleter));
Event.observe($('item_project_name'), "click", editFormProjectAutoCompleter.activate.bind(editFormProjectAutoCompleter));
</script>
</tr>
<tr>
<td class="label"><label for="item_due">Due</td>
@ -52,7 +44,7 @@
<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.current_state == :deferred -%>
<% if controller.controller_name == "project" || @item.deferred? -%>
<input type="hidden" name="on_project_page" value="true" />
<% end -%>
<tr>
@ -62,6 +54,6 @@
</table>
<%= calendar_setup( "due_#{@item.id}" ) %>
<% if @item.current_state == :deferred -%>
<% if @item.deferred? -%>
<%= calendar_setup( "show_from_#{@item.id}" ) %>
<% end -%>

View file

@ -1,35 +1,47 @@
<div id="item-<%= item.id %>-container" class="item-container">
<div id="item-<%= item.id %>">
<%= link_to_remote_todo item %>
<% unless source_view_is :deferred -%>
<input type="checkbox" class="item-checkbox"
onclick="new Ajax.Request('<%= url_for :controller => 'todo', :action => 'toggle_check', :id => item.id, :_source_view => @source_view %>', {asynchronous:true, evalScripts:true});"
name="item_id" value="<%= item.id %>"<% if item.completed? %> checked="checked" <% end %> />
<div class="description<%= staleness_class( item ) %>"><% # start of div which has a class 'description', and possibly 'stale_11', 'stale_12', 'stale_13' etc %>
<% if item.completed? -%>
<span class="grey"><%= format_date( item.completed_at ) %></span>
<% else -%>
<%= due_date( item.due ) -%>
<% end -%>
<% end -%>
<%= sanitize(item.description) %>
<% if item.completed? -%>
(<%= item.context.name %><%= ", " + item.project.name if item.project_id %>)
<% else -%>
<% if parent_container_type == "project" -%>
<div class="description<%= staleness_class( item ) %>"><% # start of div which has a class 'description', and possibly 'stale_11', 'stale_12', 'stale_13' etc %>
<% if item.completed? -%>
<span class="grey"><%= format_date( item.completed_at ) %></span>
<% elsif item.deferred? -%>
<%= show_date( item.show_from ) -%>
<% else -%>
<%= due_date( item.due ) -%>
<% end -%>
<%= sanitize(item.description) %>
<% if item.deferred? && item.due -%>
(action due on <%= item.due.to_s %>)
<% end -%>
<% if item.completed? -%>
(<%= item.context.name %><%= ", " + item.project.name if item.project_id %>)
<% else -%>
<% if (parent_container_type == "project" || parent_container_type == "tickler") -%>
<%= item_link_to_context( item ) %>
<% elsif item.project_id -%>
<% end -%>
<% if (parent_container_type == "context" || parent_container_type == "tickler") && item.project_id -%>
<%= item_link_to_project( item ) %>
<% end -%>
<% end -%>
<% if item.notes? -%>
<%= toggle_show_notes( item ) %>
<% end -%>
</div>
<% end -%>
<% end -%>
<% if item.notes? -%>
<%= toggle_show_notes( item ) %>
<% end -%>
</div>
</div><!-- [end:item-item.id] -->
<div id="action-<%= item.id %>-edit-form" class="edit-form" style="display:none;">
<%= form_remote_tag_edit_todo( item, "immediate" ) -%>
<%= form_remote_tag_edit_todo( item ) -%>
<% #note: edit form will load here remotely -%>
<%= end_form_tag -%>
</div><!-- [end:action-item.id-edit-form] -->
</div><!-- [end:item-item.id-container] -->
</div><!-- [end:item-item.id-container] -->

View file

@ -1,13 +1,18 @@
if @saved
page.notify :notice, "Added new next action", 5.0
page['badge_count'].replace_html @up_count
status_message = 'Added new next action'
status_message += ' to tickler' if @item.deferred?
status_message = 'Added new project / ' + status_message if @new_project_created
status_message = 'Added new context / ' + status_message if @new_context_created
page.notify :notice, status_message, 5.0
page['badge_count'].replace_html @down_count
page.send :record, "Form.reset('todo-form-new-action');Form.focusFirstElement('todo-form-new-action')"
page.send :record, "Form.reset('todo-form-new-action-lightbox');Form.focusFirstElement('todo-form-new-action-lightbox')"
page.call "todoItems.ensureVisibleWithEffectAppear", "c#{@item.context_id}"
page.insert_html :bottom, "c#{@item.context_id}items", :partial => 'todo/item', :locals => { :parent_container_type => "context" }
page.call "todoItems.ensureVisibleWithEffectAppear", "c#{@item.context_id}" if source_view_is(:todo)
page << "contextAutoCompleter.options.array = #{context_names_for_autocomplete}" if @new_context_created
page << "projectAutoCompleter.options.array = #{project_names_for_autocomplete}" if @new_project_created
page.insert_html :bottom, item_container_id, :partial => 'todo/item', :locals => { :parent_container_type => parent_container_type, :source_view => @source_view }
page.visual_effect :highlight, "item-#{@item.id}-container", :duration => 3
page["c#{@item.context_id}empty-nd"].hide
page[empty_container_msg_div_id].hide unless empty_container_msg_div_id.nil?
else
page.show 'status'
page.replace_html 'status', "#{error_messages_for('item')}"
end
end

View file

@ -1,11 +1,8 @@
if @saved
page["item-#{@item.id}-container"].remove
page['badge_count'].replace_html @down_count
source_view do |from|
from.todo { page.visual_effect :fade, "c#{@item.context_id}", :duration => 0.4 if @remaining_undone_in_context == 0 }
from.context { page["c#{@item.context_id}empty-nd"].show if @down_count == 0 }
from.project { page["p#{@item.project_id}empty-nd"].show if @down_count == 0 }
end
page.visual_effect :fade, "c#{@item.context_id}", :duration => 0.4 if source_view_is :todo && @remaining_undone_in_context == 0
page[empty_container_msg_div_id].show if !empty_container_msg_div_id.nil? && @down_count == 0
else
page.notify :error, "There was an error deleting the item #{@item.description}", 8.0
end

View file

@ -9,8 +9,6 @@
</div><!-- End of display_box -->
<div id="input_box">
<%= render :partial => "shared/add_new_item_form", :locals => {:hide_link => false, :msg => ""} %>
<%= render :partial => "shared/new_action_form", :locals => {:hide_link => false, :msg => ""} %>
<%= render :partial => "shared/new_action_form" %>
<%= render :partial => "shared/add_new_item_form" %>
<%= render "shared/sidebar" %>
</div><!-- End of input box -->

View file

@ -1,10 +1,21 @@
<div id="display_box">
<%= render :partial => "tickler_items" %>
<div id="tickler" class="container project">
<h2>Deferred actions</h2>
<div id="tickler-items" class="items toggle_target">
<div id="tickler-empty-nd" style="display:<%= @tickles.empty? ? 'block' : 'none'%>;">
<div class="message"><p>Currently there are no deferred actions</p></div>
</div>
<%= render :partial => "todo/item", :collection => @tickles, :locals => { :parent_container_type => 'tickler' } %>
</div><!-- [end:items] -->
</div><!-- [end:tickler] -->
</div><!-- End of display_box -->
<div id="input_box">
<%= render :partial => "shared/add_new_item_form", :locals => {:hide_link => false, :msg => ""} %>
<%= render :partial => "shared/add_new_item_form" %>
<%= render "shared/sidebar" %>
</div><!-- End of input box -->

View file

@ -1,15 +1,4 @@
if @saved
item_container_id = "c#{@item.context_id}"
parent_container_type = "context"
if source_view_is :context
empty_container_msg_div_id = "c#{@item.context_id}empty-nd"
elsif source_view_is :project
item_container_id = "p#{@item.project_id}"
empty_container_msg_div_id = "p#{@item.project_id}empty-nd"
parent_container_type = "project"
end
if @saved
page.remove "item-#{@item.id}-container"
if @item.completed?
# Don't try to insert contents into a non-existent container!

View file

@ -1,5 +1,12 @@
if @saved
item_container_id = "item-#{@item.id}-container"
status_message = 'Action saved'
status_message += ' to tickler' if @item.deferred?
status_message = 'Added new project / ' + status_message if @new_project_created
status_message = 'Added new context / ' + status_message if @new_context_created
page.notify :notice, status_message, 5.0
page << "contextAutoCompleter.options.array = #{context_names_for_autocomplete}; contextAutoCompleter.changed = true" if @new_context_created
page << "projectAutoCompleter.options.array = #{project_names_for_autocomplete}; projectAutoCompleter.changed = true" if @new_project_created
if source_view_is_one_of [:todo, :context]
if @context_changed
page[item_container_id].remove
@ -12,7 +19,7 @@ if @saved
if source_view_is :todo
page.call "todoItems.ensureVisibleWithEffectAppear", "c#{@item.context_id}"
page.call "todoItems.expandNextActionListingByContext", "c#{@item.context_id}items", true
page.insert_html :bottom, "c#{@item.context_id}items", :partial => 'todo/item', :locals => { :parent_container_type => "context" }
page.insert_html :bottom, "c#{@item.context_id}items", :partial => 'todo/item', :locals => { :parent_container_type => parent_container_type }
end
page.replace_html("badge_count", @remaining_undone_in_context) if source_view_is :context
page.delay(0.5) do
@ -23,7 +30,7 @@ if @saved
end
end
else
page.replace item_container_id, :partial => 'todo/item', :locals => { :parent_container_type => "context" }
page.replace item_container_id, :partial => 'todo/item', :locals => { :parent_container_type => parent_container_type }
page.visual_effect :highlight, item_container_id, :duration => 3
end
elsif source_view_is :project
@ -32,9 +39,18 @@ if @saved
page.show("p#{@original_item_project_id}empty-nd") if (@remaining_undone_in_project == 0)
page.replace_html "badge_count", @remaining_undone_in_project
else
page.replace item_container_id, :partial => 'todo/item', :locals => { :parent_container_type => "project" }
page.replace item_container_id, :partial => 'todo/item', :locals => { :parent_container_type => parent_container_type }
page.visual_effect :highlight, item_container_id, :duration => 3
end
elsif source_view_is :deferred
if @item.deferred?
page.replace item_container_id, :partial => 'todo/item', :locals => { :parent_container_type => parent_container_type }
page.visual_effect :highlight, item_container_id, :duration => 3
else
page[item_container_id].remove
page.show(empty_container_msg_div_id) if (@down_count == 0)
page.replace_html "badge_count", @down_count
end
else
logger.error "unexpected source_view '#{params[:_source_view]}'"
end