Merge branch 'master' into clinton/master

* master: (40 commits)
  Updated the manual in HTML, PDF and .tex format.
  Minor updates to the example db.
  set version to 1.7RC
  update version in template
  update changelog
  OpenSearch support.
  update the sample sqlite databases and update sample content sql. Solves #802
  forgot ot change one version to 1.7
  update documentation for 1.7rc release
  No point in changing the name of the OpenID identity column in users table. Use the existing one.
  show recurrence pattern in :title of a recurring todo. Needed slight refactoring to make it happen
  Re-write OpenID code to use new authentication plugin. Tested to work!
  Upgraded to open_id_authentication plugin at 00d8bc7f97 and unpacked ruby-openid gem version 2.1.2.
  remove old compressed js and css from the asset_packager plugin that we don't use anymore
  applied the patches from Jakub to improve the mobile html
  adds test for changing context on a todo in tag view. Resolves #762
  Add testcase where changing the name of a project should be reflected in the default project name. resolves #756
  add testcase for deleting a user. Resolves #734
  implement suggestions for search in #787
  fix failing tests
  ...
This commit is contained in:
bsag 2008-12-14 15:08:28 +00:00
commit 4fb4a98bc8
1905 changed files with 119478 additions and 58883 deletions

View file

@ -32,13 +32,13 @@ class ApplicationController < ActionController::Base
before_filter :set_time_zone
prepend_before_filter :login_required
prepend_before_filter :enable_mobile_content_negotiation
after_filter :restore_content_type_for_mobile
after_filter :set_charset
include ActionView::Helpers::TextHelper
include ActionView::Helpers::SanitizeHelper
extend ActionView::Helpers::SanitizeHelper::ClassMethods
helper_method :format_date, :markdown
# By default, sets the charset to UTF-8 if it isn't already set
@ -148,21 +148,15 @@ class ApplicationController < ActionController::Base
# during the processing and then setting it to 'text/html' in an
# 'after_filter' -LKM 2007-04-01
def mobile?
return params[:format] == 'm' || response.content_type == MOBILE_CONTENT_TYPE
return params[:format] == 'm'
end
def enable_mobile_content_negotiation
if mobile?
request.accepts.unshift(Mime::Type::lookup(MOBILE_CONTENT_TYPE))
request.format = :m
end
end
def restore_content_type_for_mobile
if mobile?
response.content_type = 'text/html'
end
end
def create_todo_from_recurring_todo(rt, date=nil)
# create todo and initialize with data from recurring_todo rt
todo = current_user.todos.build( { :description => rt.description, :notes => rt.notes, :project_id => rt.project_id, :context_id => rt.context_id})
@ -234,8 +228,13 @@ class ApplicationController < ActionController::Base
end
def init_data_for_sidebar
@projects = @projects || current_user.projects.find(:all, :include => [:default_context ])
@contexts = @contexts || current_user.contexts
@completed_projects = current_user.projects.completed
@hidden_projects = current_user.projects.hidden
@active_projects = current_user.projects.active
@active_contexts = current_user.contexts.active
@hidden_contexts = current_user.contexts.hidden
init_not_done_counts
if prefs.show_hidden_projects_in_sidebar
init_project_hidden_todo_counts(['project'])
@ -244,13 +243,13 @@ class ApplicationController < ActionController::Base
def init_not_done_counts(parents = ['project','context'])
parents.each do |parent|
eval("@#{parent}_not_done_counts = @#{parent}_not_done_counts || Todo.count(:conditions => ['user_id = ? and state = ?', current_user.id, 'active'], :group => :#{parent}_id)")
eval("@#{parent}_not_done_counts = @#{parent}_not_done_counts || current_user.todos.active.count(:group => :#{parent}_id)")
end
end
def init_project_hidden_todo_counts(parents = ['project','context'])
parents.each do |parent|
eval("@#{parent}_project_hidden_todo_counts = @#{parent}_project_hidden_todo_counts || Todo.count(:conditions => ['user_id = ? and (state = ? or state = ?)', current_user.id, 'project_hidden', 'active'], :group => :#{parent}_id)")
eval("@#{parent}_project_hidden_todo_counts = @#{parent}_project_hidden_todo_counts || current_user.todos.count(:conditions => ['state = ? or state = ?', 'project_hidden', 'active'], :group => :#{parent}_id)")
end
end

View file

@ -134,8 +134,8 @@ class ContextsController < ApplicationController
def render_contexts_mobile
lambda do
@page_title = "TRACKS::List Contexts"
@active_contexts = @contexts.find(:all, { :conditions => ["hide = ?", false]})
@hidden_contexts = @contexts.find(:all, { :conditions => ["hide = ?", true]})
@active_contexts = @contexts.active
@hidden_contexts = @contexts.hidden
@down_count = @active_contexts.size + @hidden_contexts.size
cookies[:mobile_url]= {:value => request.request_uri, :secure => TRACKS_COOKIES_SECURE}
render :action => 'index_mobile'
@ -201,6 +201,9 @@ class ContextsController < ApplicationController
:conditions => ['todos.state = ? AND (todos.project_id IS ? OR projects.state = ?)', 'active', nil, 'active'],
:order => "todos.due IS NULL, todos.due ASC, todos.created_at ASC",
:include => [:project, :tags])
@projects = current_user.projects
@count = @not_done_todos.size
@default_project_context_name_map = build_default_project_context_name_map(@projects).to_json
end

View file

@ -12,12 +12,12 @@ class FeedlistController < ApplicationController
@contexts = current_user.contexts
end
@active_projects = @projects.select{ |p| p.active? }
@hidden_projects = @projects.select{ |p| p.hidden? }
@completed_projects = @projects.select{ |p| p.completed? }
@active_projects = current_user.projects.active
@hidden_projects = current_user.projects.hidden
@completed_projects = current_user.projects.completed
@active_contexts = @contexts.select{ |c| !c.hidden? }
@hidden_contexts = @contexts.select{ |c| c.hidden? }
@active_contexts = current_user.contexts.active
@hidden_contexts = current_user.contexts.hidden
respond_to do |format|
format.html { render :layout => 'standard' }

View file

@ -1,5 +1,7 @@
class IntegrationsController < ApplicationController
skip_before_filter :login_required, :only => :search_plugin
def index
@page_title = 'TRACKS::Integrations'
end
@ -22,4 +24,12 @@ class IntegrationsController < ApplicationController
context = current_user.contexts.find params[:context_id]
render :partial => 'applescript2', :locals => { :context => context }
end
def search_plugin
@icon_data = [File.open(RAILS_ROOT + '/public/images/done.png').read].
pack('m').gsub(/\n/, '')
render :layout => false
end
end

View file

@ -6,114 +6,45 @@ class LoginController < ApplicationController
skip_before_filter :login_required
before_filter :login_optional
before_filter :get_current_user
open_id_consumer if openid_enabled?
def login
@page_title = "TRACKS::Login"
@openid_url = cookies[:openid_url] if openid_enabled?
case request.method
when :post
if @user = User.authenticate(params['user_login'], params['user_password'])
session['user_id'] = @user.id
# If checkbox on login page checked, we don't expire the session after 1 hour
# of inactivity and we remember this user for future browser sessions
session['noexpiry'] = params['user_noexpiry']
msg = (should_expire_sessions?) ? "will expire after 1 hour of inactivity." : "will not expire."
notify :notice, "Login successful: session #{msg}"
cookies[:tracks_login] = { :value => @user.login, :expires => Time.now + 1.year, :secure => TRACKS_COOKIES_SECURE }
unless should_expire_sessions?
@user.remember_me
cookies[:auth_token] = { :value => @user.remember_token , :expires => @user.remember_token_expires_at, :secure => TRACKS_COOKIES_SECURE }
if openid_enabled? && using_open_id?
login_openid
else
@page_title = "TRACKS::Login"
case request.method
when :post
if @user = User.authenticate(params['user_login'], params['user_password'])
session['user_id'] = @user.id
# If checkbox on login page checked, we don't expire the session after 1 hour
# of inactivity and we remember this user for future browser sessions
session['noexpiry'] = params['user_noexpiry']
msg = (should_expire_sessions?) ? "will expire after 1 hour of inactivity." : "will not expire."
notify :notice, "Login successful: session #{msg}"
cookies[:tracks_login] = { :value => @user.login, :expires => Time.now + 1.year, :secure => TRACKS_COOKIES_SECURE }
unless should_expire_sessions?
@user.remember_me
cookies[:auth_token] = { :value => @user.remember_token , :expires => @user.remember_token_expires_at, :secure => TRACKS_COOKIES_SECURE }
end
redirect_back_or_home
return
else
@login = params['user_login']
notify :warning, "Login unsuccessful"
end
redirect_back_or_home
return
else
@login = params['user_login']
notify :warning, "Login unsuccessful"
end
when :get
if User.no_users_yet?
redirect_to :controller => 'users', :action => 'new'
return
end
end
respond_to do |format|
format.html
format.m { render :action => 'login_mobile.html.erb', :layout => 'mobile' }
when :get
if User.no_users_yet?
redirect_to :controller => 'users', :action => 'new'
return
end
end
respond_to do |format|
format.html
format.m { render :action => 'login_mobile.html.erb', :layout => 'mobile' }
end
end
end
def begin
# If the URL was unusable (either because of network conditions,
# a server error, or that the response returned was not an OpenID
# identity page), the library will return HTTP_FAILURE or PARSE_ERROR.
# Let the user know that the URL is unusable.
case open_id_response.status
when OpenID::SUCCESS
session['openid_url'] = params[:openid_url]
session['user_noexpiry'] = params[:user_noexpiry]
# The URL was a valid identity URL. Now we just need to send a redirect
# to the server using the redirect_url the library created for us.
# redirect to the server
respond_to do |format|
format.html { redirect_to open_id_response.redirect_url((request.protocol + request.host_with_port + "/"), open_id_complete_url) }
format.m { redirect_to open_id_response.redirect_url((request.protocol + request.host_with_port + "/"), formatted_open_id_complete_url(:format => 'm')) }
end
else
notify :warning, "Unable to find openid server for <q>#{openid_url}</q>"
redirect_to_login
end
end
def complete
openid_url = session['openid_url']
if openid_url.blank?
notify :error, "expected an openid_url"
end
case open_id_response.status
when OpenID::FAILURE
# In the case of failure, if info is non-nil, it is the
# URL that we were verifying. We include it in the error
# message to help the user figure out what happened.
if open_id_response.identity_url
msg = "Verification of #{openid_url}(#{open_id_response.identity_url}) failed. "
else
msg = "Verification failed. "
end
notify :error, open_id_response.msg.to_s + msg
when OpenID::SUCCESS
# Success means that the transaction completed without
# error. If info is nil, it means that the user cancelled
# the verification.
@user = User.find_by_open_id_url(openid_url)
unless (@user.nil?)
session['user_id'] = @user.id
session['noexpiry'] = session['user_noexpiry']
msg = (should_expire_sessions?) ? "will expire after 1 hour of inactivity." : "will not expire."
notify :notice, "You have successfully verified #{openid_url} as your identity. Login successful: session #{msg}"
cookies[:tracks_login] = { :value => @user.login, :expires => Time.now + 1.year, :secure => TRACKS_COOKIES_SECURE }
unless should_expire_sessions?
@user.remember_me
cookies[:auth_token] = { :value => @user.remember_token , :expires => @user.remember_token_expires_at, :secure => TRACKS_COOKIES_SECURE }
end
cookies[:openid_url] = { :value => openid_url, :expires => Time.now + 1.year, :secure => TRACKS_COOKIES_SECURE }
redirect_back_or_home
else
notify :warning, "You have successfully verified #{openid_url} as your identity, but you do not have a Tracks account. Please ask your administrator to sign you up."
end
when OpenID::CANCEL
notify :warning, "Verification cancelled."
else
notify :warning, "Unknown response status: #{open_id_response.status}"
end
redirect_to_login unless performed?
end
def logout
@user.forget_me if logged_in?
cookies.delete :auth_token
@ -156,5 +87,31 @@ class LoginController < ApplicationController
def should_expire_sessions?
session['noexpiry'] != "on"
end
protected
def login_openid
# If checkbox on login page checked, we don't expire the session after 1 hour
# of inactivity and we remember this user for future browser sessions
session['noexpiry'] ||= params['user_noexpiry']
authenticate_with_open_id do |result, identity_url|
if result.successful?
if @user = User.find_by_open_id_url(identity_url)
session['user_id'] = @user.id
msg = (should_expire_sessions?) ? "will expire after 1 hour of inactivity." : "will not expire."
notify :notice, "Login successful: session #{msg}"
cookies[:tracks_login] = { :value => @user.login, :expires => Time.now + 1.year, :secure => TRACKS_COOKIES_SECURE }
unless should_expire_sessions?
@user.remember_me
cookies[:auth_token] = { :value => @user.remember_token , :expires => @user.remember_token_expires_at, :secure => TRACKS_COOKIES_SECURE }
end
redirect_back_or_home
else
notify :warning, "Sorry, no user by that identity URL exists (#{identity_url})"
end
else
notify :warning, result.message
end
end
end
end

View file

@ -31,7 +31,7 @@ class ProjectsController < ApplicationController
end
def projects_and_actions
@projects = @projects.select { |p| p.active? }
@projects = @projects.active
respond_to do |format|
format.text {
render :action => 'index_text_projects_and_actions', :layout => false, :content_type => Mime::TEXT
@ -83,7 +83,7 @@ class ProjectsController < ApplicationController
@go_to_project = params['go_to_project']
@saved = @project.save
@project_not_done_counts = { @project.id => 0 }
@active_projects_count = current_user.projects.count(:conditions => "state = 'active'")
@active_projects_count = current_user.projects.active.count
@contexts = current_user.contexts
respond_to do |format|
format.js { @down_count = current_user.projects.size }
@ -124,9 +124,9 @@ class ProjectsController < ApplicationController
@project_not_done_counts[@project.id] = @project.reload().not_done_todo_count(:include_project_hidden_todos => true)
end
@contexts = current_user.contexts
@active_projects_count = current_user.projects.count(:conditions => "state = 'active'")
@hidden_projects_count = current_user.projects.count(:conditions => "state = 'hidden'")
@completed_projects_count = current_user.projects.count(:conditions => "state = 'completed'")
@active_projects_count = current_user.projects.active.count
@hidden_projects_count = current_user.projects.hidden.count
@completed_projects_count = current_user.projects.completed.count
render :template => 'projects/update.js.rjs'
return
elsif boolean_param('update_status')
@ -161,9 +161,9 @@ class ProjectsController < ApplicationController
def destroy
@project.destroy
@active_projects_count = current_user.projects.count(:conditions => "state = 'active'")
@hidden_projects_count = current_user.projects.count(:conditions => "state = 'hidden'")
@completed_projects_count = current_user.projects.count(:conditions => "state = 'completed'")
@active_projects_count = current_user.projects.active.count
@hidden_projects_count = current_user.projects.hidden.count
@completed_projects_count = current_user.projects.completed.count
respond_to do |format|
format.js { @down_count = current_user.projects.size }
format.xml { render :text => "Deleted project #{@project.name}" }
@ -199,9 +199,9 @@ class ProjectsController < ApplicationController
lambda do
@page_title = "TRACKS::List Projects"
@count = current_user.projects.size
@active_projects = @projects.select{ |p| p.active? }
@hidden_projects = @projects.select{ |p| p.hidden? }
@completed_projects = @projects.select{ |p| p.completed? }
@active_projects = @projects.active
@hidden_projects = @projects.hidden
@completed_projects = @projects.completed
@no_projects = @projects.empty?
@projects.cache_note_counts
@new_project = current_user.projects.build
@ -211,9 +211,9 @@ class ProjectsController < ApplicationController
def render_projects_mobile
lambda do
@active_projects = @projects.select{ |p| p.active? }
@hidden_projects = @projects.select{ |p| p.hidden? }
@completed_projects = @projects.select{ |p| p.completed? }
@active_projects = @projects.active
@hidden_projects = @projects.hidden
@completed_projects = @projects.completed
@down_count = @active_projects.size + @hidden_projects.size + @completed_projects.size
cookies[:mobile_url]= {:value => request.request_uri, :secure => TRACKS_COOKIES_SECURE}
render :action => 'index_mobile'

View file

@ -118,7 +118,7 @@ class RecurringTodosController < ApplicationController
else
@message += " / did not create todo"
end
@count = current_user.recurring_todos.count(:all, :conditions => ["state = ?", "active"])
@count = current_user.recurring_todos.active.count
else
@message = "Error saving recurring todo"
end
@ -140,7 +140,7 @@ class RecurringTodosController < ApplicationController
# delete the recurring todo
@saved = @recurring_todo.destroy
@remaining = current_user.recurring_todos.count(:all)
@remaining = current_user.recurring_todos.count
respond_to do |format|

View file

@ -1,27 +1,30 @@
class SearchController < ApplicationController
helper :todos, :application, :notes, :projects
def results
@source_view = params['_source_view'] || 'search'
@page_title = "TRACKS::Search Results for #{params[:search]}"
terms = '%' + params[:search] + '%'
@found_todos = current_user.todos.find(:all, :conditions => ["todos.description LIKE ? OR todos.notes LIKE ?", terms, terms], :include => [:tags, :project, :context])
@found_projects = current_user.projects.find(:all, :conditions => ["name LIKE ? or description LIKE ?", terms, terms])
@found_notes = current_user.notes.find(:all, :conditions => ["body LIKE ?", terms])
@count = @found_todos.size + @found_projects.size + @found_notes.size
init_not_done_counts(['project'])
init_project_hidden_todo_counts(['project'])
end
def index
@page_title = "TRACKS::Search"
end
def init
@source_view = params['_source_view'] || 'search'
end
end
class SearchController < ApplicationController
helper :todos, :application, :notes, :projects
def results
@source_view = params['_source_view'] || 'search'
@page_title = "TRACKS::Search Results for #{params[:search]}"
terms = '%' + params[:search] + '%'
@found_todos = current_user.todos.find(:all, :conditions => ["todos.description LIKE ? OR todos.notes LIKE ?", terms, terms], :include => [:tags, :project, :context])
@found_projects = current_user.projects.find(:all, :conditions => ["name LIKE ? OR description LIKE ?", terms, terms])
@found_notes = current_user.notes.find(:all, :conditions => ["body LIKE ?", terms])
@found_contexts = current_user.contexts.find(:all, :conditions => ["name LIKE ?", terms])
# TODO: limit search to tags on todos
@found_tags = current_user.tags.find(:all, :conditions => ["name LIKE ?", terms])
@count = @found_todos.size + @found_projects.size + @found_notes.size + @found_contexts.size + @found_tags.size
init_not_done_counts
init_project_hidden_todo_counts
end
def index
@page_title = "TRACKS::Search"
end
def init
@source_view = params['_source_view'] || 'search'
end
end

View file

@ -8,7 +8,7 @@ class StatsController < ApplicationController
@page_title = 'TRACKS::Statistics'
@unique_tags = @tags.count(:all, {:group=>"tag_id"})
@hidden_contexts = @contexts.find(:all, {:conditions => ["hide = ? ", true]})
@hidden_contexts = @contexts.hidden
@first_action = @actions.find(:first, :order => "created_at ASC")
get_stats_actions

View file

@ -14,7 +14,7 @@ class TodosController < ApplicationController
@projects = current_user.projects.find(:all, :include => [:default_context])
@contexts = current_user.contexts.find(:all)
@contexts_to_show = @contexts.reject {|x| x.hide? }
@contexts_to_show = current_user.contexts.active
respond_to do |format|
format.html &render_todos_html
@ -28,7 +28,7 @@ class TodosController < ApplicationController
end
def new
@projects = current_user.projects.select { |p| p.active? }
@projects = current_user.projects.active
@contexts = current_user.contexts.find(:all)
respond_to do |format|
format.m {
@ -76,7 +76,7 @@ class TodosController < ApplicationController
format.m do
@return_path=cookies[:mobile_url]
# todo: use function for this fixed path
@return_path='/mobile' if @return_path.nil?
@return_path='/m' if @return_path.nil?
if @saved
redirect_to @return_path
else
@ -116,7 +116,7 @@ class TodosController < ApplicationController
def show
respond_to do |format|
format.m do
@projects = current_user.projects.select { |p| p.active? }
@projects = current_user.projects.active
@contexts = current_user.contexts.find(:all)
@edit_mobile = true
@return_path=cookies[:mobile_url]
@ -399,8 +399,9 @@ class TodosController < ApplicationController
:limit => max_completed,
:conditions => ['taggings.user_id = ? and state = ?', current_user.id, 'completed'],
:order => 'todos.completed_at DESC')
@contexts = current_user.contexts.find(:all)
@projects = current_user.projects
@contexts = current_user.contexts
@contexts_to_show = @contexts.reject {|x| x.hide? }
# Set count badge to number of items with this tag
@ -442,33 +443,33 @@ class TodosController < ApplicationController
due_next_week_date = due_this_week_date + 7.days
due_this_month_date = Time.zone.now.end_of_month
@due_today = current_user.todos.find(:all,
@due_today = current_user.todos.not_completed.find(:all,
:include => [:taggings, :tags],
:conditions => ['(todos.state = ? OR todos.state = ?) AND todos.due <= ?', 'active', 'deferred', due_today_date],
:conditions => ['todos.due <= ?', due_today_date],
:order => "due")
@due_this_week = current_user.todos.find(:all,
@due_this_week = current_user.todos.not_completed.find(:all,
:include => [:taggings, :tags],
:conditions => ['(todos.state = ? OR todos.state = ?) AND todos.due > ? AND todos.due <= ?', 'active', 'deferred', due_today_date, due_this_week_date],
:conditions => ['todos.due > ? AND todos.due <= ?', due_today_date, due_this_week_date],
:order => "due")
@due_next_week = current_user.todos.find(:all,
@due_next_week = current_user.todos.not_completed.find(:all,
:include => [:taggings, :tags],
:conditions => ['(todos.state = ? OR todos.state = ?) AND todos.due > ? AND todos.due <= ?', 'active', 'deferred', due_this_week_date, due_next_week_date],
:conditions => ['todos.due > ? AND todos.due <= ?', due_this_week_date, due_next_week_date],
:order => "due")
@due_this_month = current_user.todos.find(:all,
@due_this_month = current_user.todos.not_completed.find(:all,
:include => [:taggings, :tags],
:conditions => ['(todos.state = ? OR todos.state = ?) AND todos.due > ? AND todos.due <= ?', 'active', 'deferred', due_next_week_date, due_this_month_date],
:conditions => ['todos.due > ? AND todos.due <= ?', due_next_week_date, due_this_month_date],
:order => "due")
@due_after_this_month = current_user.todos.find(:all,
@due_after_this_month = current_user.todos.not_completed.find(:all,
:include => [:taggings, :tags],
:conditions => ['(todos.state = ? OR todos.state = ?) AND todos.due > ?', 'active', 'deferred', due_this_month_date],
:conditions => ['todos.due > ?', due_this_month_date],
:order => "due")
@count = current_user.todos.not_completed.are_due.count
respond_to do |format|
format.html
format.ics {
@due_all = current_user.todos.find(:all,
:conditions => ['(todos.state = ? OR todos.state = ?) AND NOT todos.due IS NULL', 'active', 'deferred'],
:order => "due")
@due_all = current_user.todos.not_completed.are_due.find(:all, :order => "due")
render :action => 'calendar', :layout => false, :content_type => Mime::ICS
}
end
@ -536,13 +537,17 @@ class TodosController < ApplicationController
end
def with_parent_resource_scope(&block)
@feed_title = "Actions "
if (params[:context_id])
@context = current_user.contexts.find_by_params(params)
@feed_title = @feed_title + "in context '#{@context.name}'"
Todo.send :with_scope, :find => {:conditions => ['todos.context_id = ?', @context.id]} do
yield
end
elsif (params[:project_id])
@project = current_user.projects.find_by_params(params)
@feed_title = @feed_title + "in project '#{@project.name}'"
@project_feed = true
Todo.send :with_scope, :find => {:conditions => ['todos.project_id = ?', @project.id]} do
yield
end
@ -718,7 +723,7 @@ class TodosController < ApplicationController
render_rss_feed_for @todos, :feed => todo_feed_options,
:item => {
:title => :description,
:link => lambda { |t| context_url(t.context) },
:link => lambda { |t| @project_feed.nil? ? context_url(t.context) : project_url(t.project) },
:guid => lambda { |t| todo_url(t) },
:description => todo_feed_content
}
@ -726,7 +731,9 @@ class TodosController < ApplicationController
end
def todo_feed_options
Todo.feed_options(current_user)
options = Todo.feed_options(current_user)
options[:title] = @feed_title
return options
end
def todo_feed_content
@ -779,8 +786,8 @@ class TodosController < ApplicationController
if todo.from_recurring_todo?
recurring_todo = todo.recurring_todo
# check if there are active todos belonging to this recurring todo.
# only add new one if all active todos are completed
# check if there are active todos belonging to this recurring todo. only
# add new one if all active todos are completed
if recurring_todo.todos.active.count == 0
# check for next todo either from the due date or the show_from date
@ -788,7 +795,7 @@ class TodosController < ApplicationController
# if both due and show_from are nil, check for a next todo from now
date_to_check = Time.zone.now if date_to_check.nil?
if recurring_todo.active? && recurring_todo.has_next_todo(date_to_check)
# shift the reference date to yesterday if date_to_check is furher in
@ -799,7 +806,7 @@ class TodosController < ApplicationController
# that new todos due for today will be created instead of new todos
# for tomorrow.
date = date_to_check.at_midnight >= Time.zone.now.at_midnight ? date_to_check : Time.zone.now-1.day
new_recurring_todo = create_todo_from_recurring_todo(recurring_todo, date)
end
end
@ -834,20 +841,20 @@ class TodosController < ApplicationController
due_this_month_date = Time.zone.now.end_of_month
case id
when "due_today"
return 0 == current_user.todos.count(:all,
:conditions => ['(todos.state = ? OR todos.state = ?) AND todos.due <= ?', 'active', 'deferred', due_today_date])
return 0 == current_user.todos.not_completed.count(:all,
:conditions => ['todos.due <= ?', due_today_date])
when "due_this_week"
return 0 == current_user.todos.count(:all,
:conditions => ['(todos.state = ? OR todos.state = ?) AND todos.due > ? AND todos.due <= ?', 'active', 'deferred', due_today_date, due_this_week_date])
return 0 == current_user.todos.not_completed.count(:all,
:conditions => ['todos.due > ? AND todos.due <= ?', due_today_date, due_this_week_date])
when "due_next_week"
return 0 == current_user.todos.count(:all,
:conditions => ['(todos.state = ? OR todos.state = ?) AND todos.due > ? AND todos.due <= ?', 'active', 'deferred', due_this_week_date, due_next_week_date])
return 0 == current_user.todos.not_completed.count(:all,
:conditions => ['todos.due > ? AND todos.due <= ?', due_this_week_date, due_next_week_date])
when "due_this_month"
return 0 == current_user.todos.count(:all,
:conditions => ['(todos.state = ? OR todos.state = ?) AND todos.due > ? AND todos.due <= ?', 'active', 'deferred', due_next_week_date, due_this_month_date])
return 0 == current_user.todos.not_completed.count(:all,
:conditions => ['todos.due > ? AND todos.due <= ?', due_next_week_date, due_this_month_date])
when "due_after_this_month"
return 0 == current_user.todos.count(:all,
:conditions => ['(todos.state = ? OR todos.state = ?) AND todos.due > ?', 'active', 'deferred', due_this_month_date])
return 0 == current_user.todos.not_completed.count(:all,
:conditions => ['todos.due > ?', due_this_month_date])
else
raise Exception.new, "unknown due id for calendar: '#{id}'"
end

View file

@ -1,10 +1,4 @@
class UsersController < ApplicationController
if openid_enabled?
open_id_consumer
before_filter :begin_open_id_auth, :only => :update_auth_type
end
before_filter :admin_login_required, :only => [ :index, :show, :destroy ]
skip_before_filter :login_required, :only => [ :new, :create ]
prepend_before_filter :login_optional, :only => [ :new, :create ]
@ -153,18 +147,25 @@ class UsersController < ApplicationController
end
def update_auth_type
if (params[:user][:auth_type] == 'open_id') && openid_enabled?
case open_id_response.status
when OpenID::SUCCESS
# The URL was a valid identity URL. Now we just need to send a redirect
# to the server using the redirect_url the library created for us.
session['openid_url'] = params[:openid_url]
# redirect to the server
redirect_to open_id_response.redirect_url((request.protocol + request.host_with_port + "/"), url_for(:action => 'complete'))
if (params[:open_id_complete] || (params[:user][:auth_type] == 'open_id')) && openid_enabled?
authenticate_with_open_id do |result, identity_url|
if result.successful?
# Success means that the transaction completed without
# error. If info is nil, it means that the user cancelled
# the verification.
@user.auth_type = 'open_id'
@user.open_id_url = identity_url
if @user.save
notify :notice, "You have successfully verified #{identity_url} as your identity and set your authentication type to Open ID."
else
debugger
notify :warning, "You have successfully verified #{identity_url} as your identity but there was a problem saving your authentication preferences."
end
redirect_to preferences_path
else
notify :warning, "Unable to find openid server for <q>#{openid_url}</q>"
notify :warning, result.message
redirect_to :action => 'change_auth_type'
end
end
return
end
@ -178,47 +179,6 @@ class UsersController < ApplicationController
end
end
def complete
return unless openid_enabled?
openid_url = session['openid_url']
if openid_url.blank?
notify :error, "expected an openid_url"
end
case open_id_response.status
when OpenID::FAILURE
# In the case of failure, if info is non-nil, it is the
# URL that we were verifying. We include it in the error
# message to help the user figure out what happened.
if open_id_response.identity_url
msg = "Verification of #{openid_url}(#{open_id_response.identity_url}) failed. "
else
msg = "Verification failed. "
end
notify :error, open_id_response.msg.to_s + msg
when OpenID::SUCCESS
# Success means that the transaction completed without
# error. If info is nil, it means that the user cancelled
# the verification.
@user.auth_type = 'open_id'
@user.open_id_url = openid_url
if @user.save
notify :notice, "You have successfully verified #{openid_url} as your identity and set your authentication type to Open ID."
else
notify :warning, "You have successfully verified #{openid_url} as your identity but there was a problem saving your authentication preferences."
end
redirect_to preferences_path
when OpenID::CANCEL
notify :warning, "Verification cancelled."
else
notify :warning, "Unknown response status: #{open_id_response.status}"
end
redirect_to :action => 'change_auth_type' unless performed?
end
def refresh_token
@user.generate_token
@user.save!

View file

@ -8,7 +8,7 @@ module ApplicationHelper
# Replicates the link_to method but also checks request.request_uri to find
# current page. If that matches the url, the link is marked id = "current"
#
#
def navigation_link(name, options = {}, html_options = nil, *parameters_for_method_reference)
if html_options
html_options = html_options.stringify_keys
@ -29,7 +29,7 @@ module ApplicationHelper
# Check due date in comparison to today's date Flag up date appropriately with
# a 'traffic light' colour code
#
#
def due_date(due)
if due == nil
return ""
@ -62,7 +62,7 @@ module ApplicationHelper
# Check due date in comparison to today's date Flag up date appropriately with
# a 'traffic light' colour code Modified method for mobile screen
#
#
def due_date_mobile(due)
if due == nil
return ""
@ -92,7 +92,7 @@ module ApplicationHelper
# Returns a count of next actions in the given context or project. The result
# is count and a string descriptor, correctly pluralised if there are no
# actions or multiple actions
#
#
def count_undone_todos_phrase(todos_parent, string="actions")
@controller.count_undone_todos_phrase(todos_parent, string)
end
@ -143,5 +143,31 @@ module ApplicationHelper
page.replace 'flash', "<h4 id='flash' class='alert #{type}'>#{message}</h4>"
page.visual_effect :fade, 'flash', :duration => fade_duration
end
def recurrence_time_span(rt)
case rt.ends_on
when "no_end_date"
return rt.start_from.nil? ? "" : "from " + format_date(rt.start_from)
when "ends_on_number_of_times"
return "for "+rt.number_of_occurences.to_s + " times"
when "ends_on_end_date"
starts = rt.start_from.nil? ? "" : "from " + format_date(rt.start_from)
ends = rt.end_date.nil? ? "" : " until " + format_date(rt.end_date)
return starts+ends
else
raise Exception.new, "unknown recurrence time span selection (#{rt.ends_on})"
end
end
def recurrence_pattern_as_text(recurring_todo)
rt = recurring_todo.recurring_target_as_text
rp = recurring_todo.recurrence_pattern
# only add space if recurrence_pattern has content
rp = " " + rp if !rp.nil?
rts = recurrence_time_span(recurring_todo)
# only add space if recurrence_time_span has content
rts = " " + rts if !(rts == "")
return rt+rp+rts
end
end

View file

@ -1,5 +1,5 @@
module NotesHelper
def truncated_note(note, characters = 50)
sanitize(textilize_without_paragraph(truncate(note.body, characters, "...")))
sanitize(textilize_without_paragraph(truncate(note.body, :length => characters, :omission => "...")))
end
end

View file

@ -20,12 +20,12 @@ module ProjectsHelper
def project_next_prev
html = ''
unless @previous_project.nil?
project_name = truncate(@previous_project.name, 40, "...")
project_name = truncate(@previous_project.name, :length => 40, :omission => "...")
html << link_to_project(@previous_project, "&laquo; #{project_name}")
end
html << ' | ' if @previous_project && @next_project
unless @next_project.nil?
project_name = truncate(@next_project.name, 40, "...")
project_name = truncate(@next_project.name, :length => 40, :omission => "...")
html << link_to_project(@next_project, "#{project_name} &raquo;")
end
html
@ -34,12 +34,12 @@ module ProjectsHelper
def project_next_prev_mobile
html = ''
unless @previous_project.nil?
project_name = truncate(@previous_project.name, 40, "...")
project_name = truncate(@previous_project.name, :length => 40, :omission => "...")
html << link_to_project_mobile(@previous_project, "5", "&laquo; 5-#{project_name}")
end
html << ' | ' if @previous_project && @next_project
unless @next_project.nil?
project_name = truncate(@next_project.name, 40, "...")
project_name = truncate(@next_project.name, :length => 40, :omission => "...")
html << link_to_project_mobile(@next_project, "6", "6-#{project_name} &raquo;")
end
html

View file

@ -1,37 +1,11 @@
module RecurringTodosHelper
def recurrence_time_span(rt)
case rt.ends_on
when "no_end_date"
return ""
when "ends_on_number_of_times"
return "for "+rt.number_of_occurences.to_s + " times"
when "ends_on_end_date"
starts = rt.start_from.nil? ? "" : "from " + format_date(rt.start_from)
ends = rt.end_date.nil? ? "" : " until " + format_date(rt.end_date)
return starts+ends
else
raise Exception.new, "unknown recurrence time span selection (#{self.ends_on})"
end
end
def recurrence_target(rt)
case rt.target
when 'due_date'
return "due"
when 'show_from_date'
return "show"
else
return "ERROR"
end
end
def recurring_todo_tag_list
tags_except_starred = @recurring_todo.tags.reject{|t| t.name == Todo::STARRED_TAG_NAME}
tag_list = tags_except_starred.collect{|t| "<span class=\"tag #{t.name.gsub(' ','-')}\">" +
tag_list = tags_except_starred.collect{|t| "<span class=\"tag #{t.name.gsub(' ','-')}\">" +
# link_to(t.name, :controller => "todos", :action => "tag", :id =>
# t.name) + TODO: tag view for recurring_todos (yet?)
t.name +
t.name +
"</span>"}.join('')
"<span class='tags'>#{tag_list}</span>"
end
@ -44,7 +18,7 @@ module RecurringTodosHelper
str
end
def recurring_todo_remote_star_icon
def recurring_todo_remote_star_icon
str = link_to( image_tag_for_star(@recurring_todo),
toggle_star_recurring_todo_path(@recurring_todo),
:class => "icon star_item", :title => "star the action '#{@recurring_todo.description}'")

View file

@ -117,7 +117,7 @@ module TodosHelper
"<span class=\"tag\">" +
link_to(t.name, {:action => "tag", :controller => "todos", :id => t.name+".m"}) +
"</span>"}.join('')
"<span class=\"tags\">#{tag_list}</span>"
if tag_list.empty? then "" else "<span class=\"tags\">#{tag_list}</span>" end
end
def deferred_due_date
@ -242,13 +242,13 @@ module TodosHelper
end
def project_names_for_autocomplete
array_or_string_for_javascript( ['None'] + @projects.select{ |p| p.active? }.collect{|p| escape_javascript(p.name) } )
array_or_string_for_javascript( ['None'] + current_user.projects.active.collect{|p| escape_javascript(p.name) } )
end
def context_names_for_autocomplete
# #return array_or_string_for_javascript(['Create a new context']) if
# @contexts.empty?
array_or_string_for_javascript( @contexts.collect{|c| escape_javascript(c.name) } )
array_or_string_for_javascript( current_user.contexts.collect{|c| escape_javascript(c.name) } )
end
def format_ical_notes(notes)

View file

@ -2,7 +2,10 @@ class Context < ActiveRecord::Base
has_many :todos, :dependent => :delete_all, :include => :project, :order => "todos.completed_at DESC"
belongs_to :user
named_scope :active, :conditions => { :hide => false }
named_scope :hidden, :conditions => { :hide => true }
acts_as_list :scope => :user
extend NamePartFinder
include Tracks::TodoList

View file

@ -1,5 +1,7 @@
class MessageGateway < ActionMailer::Base
include ActionView::Helpers::SanitizeHelper
extend ActionView::Helpers::SanitizeHelper::ClassMethods
def receive(email)
user = User.find(:first, :include => [:preference], :conditions => ["preferences.sms_email = ?", email.from[0].strip])
if user.nil?

View file

@ -3,6 +3,10 @@ class Project < ActiveRecord::Base
has_many :notes, :dependent => :delete_all, :order => "created_at DESC"
belongs_to :default_context, :class_name => "Context", :foreign_key => "default_context_id"
belongs_to :user
named_scope :active, :conditions => { :state => 'active' }
named_scope :hidden, :conditions => { :state => 'hidden' }
named_scope :completed, :conditions => { :state => 'completed'}
validates_presence_of :name, :message => "project must have a name"
validates_length_of :name, :maximum => 255, :message => "project name must be less than 256 characters"

View file

@ -295,6 +295,17 @@ class RecurringTodo < ActiveRecord::Base
def recurring_target=(t)
self.target = t
end
def recurring_target_as_text
case self.target
when 'due_date'
return "due"
when 'show_from_date'
return "show"
else
raise Exception.new, "unexpected value of recurrence target '#{self.target}'"
end
end
def recurring_show_days_before=(days)
self.show_from_delta=days
@ -361,6 +372,8 @@ class RecurringTodo < ActiveRecord::Base
when 'show_from'
# so leave due date empty
return nil
else
raise Exception.new, "unexpected value of recurrence target '#{self.target}'"
end
end
@ -471,12 +484,23 @@ class RecurringTodo < ActiveRecord::Base
start = determine_start(previous)
day = self.every_other1
n = self.every_other2
case self.recurrence_selector
when 0 # specific day of the month
if start.mday >= day
if start.mday >= day
# there is no next day n in this month, search in next month
start += n.months
#
# start += n.months
#
# The above seems to not work. Fiddle with timezone. Looks like we hit a
# bug in rails here where 2008-12-01 +0100 plus 1.month becomes
# 2008-12-31 +0100. For now, just calculate in UTC and convert back to
# local timezone.
#
# TODO: recheck if future rails versions have this problem too
start = Time.utc(start.year, start.month, start.day)+n.months
start = Time.zone.local(start.year, start.month, start.day)
# go back to day
end
return Time.zone.local(start.year, start.month, day)

View file

@ -7,6 +7,7 @@ class Todo < ActiveRecord::Base
named_scope :active, :conditions => { :state => 'active' }
named_scope :not_completed, :conditions => ['NOT state = ? ', 'completed']
named_scope :are_due, :conditions => ['NOT todos.due IS NULL']
STARRED_TAG_NAME = "starred"

View file

@ -124,7 +124,7 @@ class User < ActiveRecord::Base
#for will_paginate plugin
cattr_accessor :per_page
@@per_page = 1
@@per_page = 5
def validate
unless Tracks::Config.auth_schemes.include?(auth_type)
@ -145,8 +145,8 @@ class User < ActiveRecord::Base
return nil
end
def self.find_by_open_id_url(raw_open_id_url)
normalized_open_id_url = normalize_open_id_url(raw_open_id_url)
def self.find_by_open_id_url(raw_identity_url)
normalized_open_id_url = OpenIdAuthentication.normalize_url(raw_identity_url)
find(:first, :conditions => ['open_id_url = ?', normalized_open_id_url])
end
@ -188,7 +188,7 @@ class User < ActiveRecord::Base
end
def at_midnight(date)
return TimeZone[prefs.time_zone].local(date.year, date.month, date.day, 0, 0, 0)
return ActiveSupport::TimeZone[prefs.time_zone].local(date.year, date.month, date.day, 0, 0, 0)
end
def generate_token
@ -237,13 +237,6 @@ protected
def normalize_open_id_url
return if open_id_url.nil?
self.open_id_url = self.class.normalize_open_id_url(open_id_url)
self.open_id_url = OpenIdAuthentication.normalize_url(open_id_url)
end
def self.normalize_open_id_url(raw_open_id_url)
normalized = raw_open_id_url
normalized = "http://#{raw_open_id_url}" unless raw_open_id_url =~ /\:\/\//
normalized.downcase.chomp('/')
end
end

View file

@ -1,9 +1,14 @@
<% context = context_listing %>
<% context = context_listing
suppress_drag_handle ||= false
suppress_edit_button ||= false
%>
<div id="<%= dom_id(context, "container") %>" class="list">
<div id="<%= dom_id(context) %>" class="context sortable_row" style="display:'';">
<div class="position">
<span class="handle">DRAG</span>
</div>
<% unless suppress_drag_handle -%>
<div class="position">
<span class="handle">DRAG</span>
</div>
<% end -%>
<div class="data">
<%= link_to_context( context ) %> <%= " (" + count_undone_todos_phrase(context,"actions") + ")" %>
</div>
@ -32,5 +37,5 @@
-%>
</div>
</div>
<%= render :partial => 'context_form', :object => context %>
<%= render :partial => 'contexts/context_form', :object => context %>
</div>

View file

@ -6,9 +6,9 @@ if not @not_done.empty?
# only show a context when there are actions in it
-%>
<h2><%=mobile_context.name%></h2>
<table cellpadding="0" cellspacing="0" border="0">
<ul class="c">
<%= render :partial => "todos/mobile_todo",
:collection => @not_done,
:locals => { :parent_container_type => "context" }-%>
</table>
<% end -%>
</ul>
<% end -%>

View file

@ -8,5 +8,5 @@
<div id="input_box">
<%= render :partial => "shared/add_new_item_form" %>
<%= render "sidebar/sidebar" %>
<%= render :template => "sidebar/sidebar" %>
</div><!-- End of input box -->

View file

@ -123,7 +123,7 @@
</div><!-- End of display_box -->
<div id="input_box">
<%= render "sidebar/sidebar" %>
<%= render :template => "sidebar/sidebar" %>
</div><!-- End of input box -->
<script type="text/javascript">

View file

@ -0,0 +1,14 @@
xml.instruct!
xml.OpenSearchDescription 'xmlns' => "http://a9.com/-/spec/opensearch/1.1/" do
xml.ShortName Tracks
xml.Description 'Search in Tracks'
xml.InputEncoding 'UTF-8'
xml.Image("data:image/x-icon;base64," + @icon_data,
'width' => '16', 'height' => '16')
xml.Url 'type' => 'text/html', 'method' => 'GET',
'template' => url_for(:controller => 'search', :action => 'results',
:only_path => false) + '?search={searchTerms}'
end

View file

@ -2,35 +2,40 @@
new_todo_params = {}
new_todo_params[:from_project] = @mobile_from_project if @mobile_from_project
new_todo_params[:from_context] = @mobile_from_context if @mobile_from_context
-%><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-%><?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="initial-scale = 1.0" />
<%= stylesheet_link_tag "mobile"%>
<%= stylesheet_link_tag "mobile", :media => 'handheld,all' %>
<title><%= @page_title %></title>
</head><body>
<% if !(@new_mobile || @edit_mobile)
if !@prefs.nil? -%>
<h1><span class="count"><%= @down_count %></span> <%=
user_time.strftime(@prefs.title_date_format) -%></h1>
<%= (link_to("0-Add new action", formatted_new_todo_path(:m, new_todo_params))+" | ") unless @new_mobile -%>
<div class="nav">
<%= (link_to("0-New action", formatted_new_todo_path(:m, new_todo_params))+" | ") unless @new_mobile -%>
<%= (link_to("1-Home", formatted_todos_path(:m))+" | ") unless @home -%>
<%= (link_to("2-Contexts", formatted_contexts_path(:m))+" | ") -%>
<%= (link_to("3-Projects", formatted_projects_path(:m))+" | ") -%>
<%= (link_to("4-Starred", {:action => "tag", :controller => "todos", :id => "starred.m"})) -%>
<% end
end -%><%= render_flash -%>
<hr/><%= yield -%>
</div>
<%= yield -%>
<hr/><% if !@prefs.nil? -%>
<div class="nav">
<%= (link_to("Logout", formatted_logout_path(:format => 'm')) +" | ") -%>
<%= (link_to("0-Add new action", formatted_new_todo_path(:m), {:accesskey => "0"})+" | ") unless @new_mobile -%>
<%= (link_to("0-New action", formatted_new_todo_path(:m), {:accesskey => "0"})+" | ") unless @new_mobile -%>
<%= (link_to("1-Home", formatted_todos_path(:m), {:accesskey => "1"})+" | ") unless @home -%>
<%= (link_to("2-Contexts", formatted_contexts_path(:m), {:accesskey => "2"})+" | ") -%>
<%= (link_to("3-Projects", formatted_projects_path(:m), {:accesskey => "3"})+" | ") -%>
<%= (link_to("4-Starred", {:action => "tag", :controller => "todos", :id => "starred.m"}, {:accesskey => "4"})+" | ") -%>
<%= (link_to("Tickler", {:action => "index", :controller => "tickler.m"})+" | ") -%>
<%= (link_to("Feeds", {:action => "index", :controller => "feeds.m"})) -%>
</div>
<% end -%>
<%= render :partial => "shared/mobile_footer" -%>
</body></html>

View file

@ -5,13 +5,23 @@
<% if @prefs.refresh != 0 -%>
<meta http-equiv="Refresh" content="<%= @prefs["refresh"].to_i*60 %>;url=<%= request.request_uri %>">
<% end -%>
<%= javascript_include_merged :tracks %>
<% bundle do %>
<%= javascript_include_tag *%w[
prototype effects dragdrop controls application
calendar calendar-en calendar-setup
accesskey-hints todo-items niftycube
protoload flashobject lowpro
] %>
<%= stylesheet_link_tag *%w[ standard calendar-system niftyCorners] %>
<% end %>
<%= javascript_include_tag :unobtrusive %>
<%= stylesheet_link_merged :tracks %>
<%= stylesheet_link_tag "print", :media => "print" %>
<link rel="shortcut icon" href="<%= url_for(:controller => 'favicon.ico') %>" />
<%= auto_discovery_link_tag(:rss, {:controller => "todos", :action => "index", :format => 'rss', :token => "#{current_user.token}"}, {:title => "RSS feed of next actions"}) %>
<link rel="search" type="application/opensearchdescription+xml"
title="Tracks"
href="<%= search_plugin_path %>" />
<script type="text/javascript">
window.onload=function(){

View file

@ -14,19 +14,19 @@
<% form_tag :action=> 'login' do %>
<table>
<tr>
<td width="100px"><label for="user_login">Login:</label></td>
<td width="100px"><input type="text" name="user_login" id="user_login" value="" class="login_text" /></td>
<td><label for="user_login">Login:</label></td>
<td><input type="text" name="user_login" id="user_login" value="" class="login_text" /></td>
</tr>
<tr>
<td width="100px"><label for="user_password">Password:</label></td>
<td width="100px"><input type="password" name="user_password" id="user_password" class="login_text" /></td>
<td><label for="user_password">Password:</label></td>
<td><input type="password" name="user_password" id="user_password" class="login_text" /></td>
</tr>
<tr>
<td width="100px"><label for="user_noexpiry">Stay logged in:</label></td>
<td width="100px"><input type="checkbox" name="user_noexpiry" id="user_noexpiry" checked /></td>
<td><label for="user_noexpiry">Stay logged in:</label></td>
<td><input type="checkbox" name="user_noexpiry" id="user_noexpiry" checked /></td>
</tr>
<tr>
<td width="100px"></td>
<td></td>
<td><input type="submit" name="login" value="Sign In &#187;" class="primary" /></td>
</tr>
</table>
@ -36,18 +36,18 @@
<% if show_openid_form %>
<div id="openid_auth_form" style="display:none">
<% form_tag :action=> 'login', :action => 'begin' do %>
<% form_tag :action=> 'login' do %>
<table>
<tr>
<td width="100px"><label for="openid_url">Identity URL:</label></td>
<td width="100px"><input type="text" name="openid_url" id="openid_url" value="<%= @openid_url %>" class="login_text open_id" /></td>
<td><label for="openid_url">Identity URL:</label></td>
<td><input type="text" name="openid_url" id="openid_url" value="<%= @openid_url %>" class="login_text open_id" /></td>
</tr>
<tr>
<td width="100px"><label for="user_noexpiry">Stay logged in:</label></td>
<td width="100px"><input type="checkbox" name="user_noexpiry" id="user_noexpiry" checked /></td>
<td><label for="user_noexpiry">Stay logged in:</label></td>
<td><input type="checkbox" name="user_noexpiry" id="user_noexpiry" checked /></td>
</tr>
<tr>
<td width="100px"></td>
<td></td>
<td><input type="submit" name="login" value="Sign In &#187;" class="primary" /></td>
</tr>
</table>

View file

@ -14,19 +14,19 @@
<% form_tag formatted_login_path(:format => 'm') do %>
<table>
<tr>
<td width="100px"><label for="user_login">Login:</label></td>
<td width="100px"><input type="text" name="user_login" id="user_login" value="" class="login_text" /></td>
<td><label for="user_login">Login:</label></td>
<td><input type="text" name="user_login" id="user_login" value="" class="login_text" /></td>
</tr>
<tr>
<td width="100px"><label for="user_password">Password:</label></td>
<td width="100px"><input type="password" name="user_password" id="user_password" class="login_text" /></td>
<td><label for="user_password">Password:</label></td>
<td><input type="password" name="user_password" id="user_password" class="login_text" /></td>
</tr>
<tr>
<td width="100px"><label for="user_noexpiry">Stay logged in:</label></td>
<td width="100px"><input type="checkbox" name="user_noexpiry" id="user_noexpiry" checked /></td>
<td><label for="user_noexpiry">Stay logged in:</label></td>
<td><input type="checkbox" name="user_noexpiry" id="user_noexpiry" checked="checked" /></td>
</tr>
<tr>
<td width="100px"></td>
<td>&nbsp;</td>
<td><input type="submit" name="login" value="Sign In &#187;" class="primary" /></td>
</tr>
</table>

View file

@ -1,6 +1,6 @@
<div class="page_name_auto_complete" id="default_context_list" style="display:none;z-index:9999"></div>
<script type="text/javascript">
defaultContextAutoCompleter = new Autocompleter.Local('project[default_context_name]', 'default_context_list', <%= context_names_for_autocomplete %>, {choices:100,autoSelect:false});
Event.observe($('project[default_context_name]'), "focus", defaultContextAutoCompleter.activate.bind(defaultContextAutoCompleter));
Event.observe($('project[default_context_name]'), "click", defaultContextAutoCompleter.activate.bind(defaultContextAutoCompleter));
defaultContextAutoCompleter = new Autocompleter.Local('project_default_context_name', 'default_context_list', <%= context_names_for_autocomplete %>, {choices:100,autoSelect:false});
Event.observe($('project_default_context_name'), "focus", defaultContextAutoCompleter.activate.bind(defaultContextAutoCompleter));
Event.observe($('project_default_context_name'), "click", defaultContextAutoCompleter.activate.bind(defaultContextAutoCompleter));
</script>

View file

@ -74,5 +74,5 @@
<div id="input_box">
<%= render :partial => "shared/add_new_item_form" %>
<%= render "sidebar/sidebar" %>
<%= render :template => "sidebar/sidebar" %>
</div><!-- End of input box -->

View file

@ -6,7 +6,7 @@
<div class="description">
<span class="todo.descr"><%= sanitize(recurring_todo.description) %></span> <%= recurring_todo_tag_list %>
<span class='recurrence_pattern'>
[<%=recurrence_target(recurring_todo)%> <%= recurring_todo.recurrence_pattern %> <%= recurrence_time_span(recurring_todo) %>]
[<%= recurrence_pattern_as_text(@recurring_todo) %>]
</span>
</div>
</div>

View file

@ -13,7 +13,7 @@ if @recurring_saved
page.hide 'recurring-todos-empty-nd'
page.insert_html :bottom,
'recurring_todos_container',
:partial => 'recurring_todos/recurring_todo'
:partial => 'recurring_todos/recurring_todo', :locals => { :recurring_todo => @recurring_todo}
page.visual_effect :highlight, dom_id(@recurring_todo), :duration => 3
# update badge count
page['badge_count'].replace_html @count

View file

@ -4,7 +4,7 @@ if @saved
if @recurring_todo.completed?
# show completed recurring todo
page.insert_html :top, "completed_recurring_todos_container", :partial => 'recurring_todos/recurring_todo'
page.insert_html :top, "completed_recurring_todos_container", :partial => 'recurring_todos/recurring_todo', :locals => { :recurring_todo => @recurring_todo }
page.visual_effect :highlight, dom_id(@recurring_todo), :duration => 3
# set empty messages
@ -14,7 +14,7 @@ if @saved
# recurring_todo is activated
# show completed recurring todo
page.insert_html :top, "recurring_todos_container", :partial => 'recurring_todos/recurring_todo'
page.insert_html :top, "recurring_todos_container", :partial => 'recurring_todos/recurring_todo', :locals => { :recurring_todo => @recurring_todo }
page.visual_effect :highlight, dom_id(@recurring_todo), :duration => 3
# inform user if a new todo has been created because of the activation

View file

@ -13,7 +13,7 @@ if @saved
page << "projectAutoCompleter.options.array = #{project_names_for_autocomplete}; projectAutoCompleter.changed = true" if @new_project_created
# replace old recurring todo with updated todo
page.replace dom_id(@recurring_todo), :partial => 'recurring_todos/recurring_todo'
page.replace dom_id(@recurring_todo), :partial => 'recurring_todos/recurring_todo', :locals => { :recurring_todo => @recurring_todo }
page.visual_effect :highlight, dom_id(@recurring_todo), :duration => 3
else

View file

@ -1,6 +1,9 @@
<div id="display_box_search">
<% form_tag(:action => :results) do %>
<%= text_field_tag(:search, params[:search]) %>
<%= submit_tag "Search" %>
<% end %>
</div>
<div id="display_box_search">
<% form_tag({:action => :results}, :id => 'search-form') do %>
<%= text_field_tag(:search, params[:search]) %>
<%= submit_tag "Search" %>
<% end %>
</div>
<script type="text/javascript">
Form.focusFirstElement('search-form')
</script>

View file

@ -1,32 +1,48 @@
<div id="display_box_results">
<% if @count == 0 -%>
<div class="message"><p>Your search yielded no results.</p></div>
<% else -%>
<% source_view_is = :search %>
<% parent_container_type = 'search' %>
<% if not @found_todos.empty? -%>
<div id="found-todos-container" class="container">
<h2><span id="found-todos-count" class="badge"><%= @found_todos.size %></span>Todos matching query</h2>
<%= render :partial => "todos/todo", :collection => @found_todos, :locals => { :parent_container_type => 'search', :suppress_context => false, :suppress_project => false, :suppress_edit_button => true } %>
</div>
<% end -%>
<% if not @found_projects.empty? -%>
<div id="found-projects-container" class="container">
<h2><span id="found-projects-count" class="badge"><%= @found_projects.size %></span>Projects matching query</h2>
<%= render :partial => "projects/project_listing", :collection => @found_projects, :locals => { :suppress_drag_handle => true, :suppress_edit_button => true } %>
</div>
<% end -%>
<% if not @found_notes.empty? -%>
<div id="found-notes-container" class="container">
<h2><span id="found-notes-count" class="badge"><%= @found_notes.size %></span>Notes matching query</h2>
<% for notes in @found_notes -%>
<div class="container" id="note-<%= notes.id %>-wrapper">
<%= render :partial => "notes/notes_summary", :object => notes %>
</div>
<% end -%>
</div>
<% end -%>
<% end -%>
</div>
<div id="display_box_results">
<% if @count == 0 -%>
<div class="message"><p>Your search yielded no results.</p></div>
<% else -%>
<% unless @found_todos.empty? -%>
<div id="found-todos-container" class="container">
<h2><span id="found-todos-count" class="badge"><%= @found_todos.size %></span>Todos matching query</h2>
<%= render :partial => "todos/todo", :collection => @found_todos, :locals => { :parent_container_type => 'search', :suppress_context => false, :suppress_project => false, :suppress_edit_button => true } %>
</div>
<% end -%>
<% unless @found_projects.empty? -%>
<div id="found-projects-container" class="container">
<h2><span id="found-projects-count" class="badge"><%= @found_projects.size %></span>Projects matching query</h2>
<%= render :partial => "projects/project_listing", :collection => @found_projects, :locals => { :suppress_drag_handle => true, :suppress_edit_button => true } %>
</div>
<% end -%>
<% unless @found_notes.empty? -%>
<div id="found-notes-container" class="container">
<h2><span id="found-notes-count" class="badge"><%= @found_notes.size %></span>Notes matching query</h2>
<% for notes in @found_notes -%>
<div class="container" id="note-<%= notes.id %>-wrapper">
<%= render :partial => "notes/notes_summary", :object => notes %>
</div>
<% end -%>
</div>
<% end -%>
<% unless @found_contexts.empty? -%>
<div id="found-contexts-container" class="container">
<h2><span id="found-contexts-count" class="badge"><%= @found_contexts.size %></span>Contexts matching query</h2>
<%= render :partial => "contexts/context_listing", :collection => @found_contexts, :locals => { :suppress_drag_handle => true, :suppress_edit_button => true } %>
</div>
<% end -%>
<% unless @found_tags.empty? -%>
<div id="found-tags-container" class="container">
<h2><span id="found-tags-count" class="badge"><%= @found_tags.size %></span>Tags matching query</h2>
<span class="tags"><% @found_tags.each do |tag| -%>
<span class="tag"><%= link_to tag.name, {:controller => "todos", :action => "tag", :id => tag.name} -%></span>
<% end %>
</span>
<br/>
</div>
<% end %>
<% end -%>
</div>

View file

@ -2,7 +2,7 @@
@todo = nil
@initial_context_name = @context.name unless @context.nil?
@initial_context_name ||= @project.default_context.name unless @project.nil? || @project.default_context.nil?
@initial_context_name ||= @contexts[0].name unless @contexts[0].nil?
@initial_context_name ||= current_user.contexts.first.name unless current_user.contexts.first.nil?
@initial_project_name = @project.name unless @project.nil?
%>
<div id="todo_new_action_container">

View file

@ -1,30 +1,30 @@
<div id="sidebar">
<% # show active items before hidden / completed items -%>
<% # show active items before hidden / completed items -%>
<%= render :partial => "sidebar/project_list",
:locals => { :list_name => 'Active Projects',
:projects => @projects.select{|p| p.active? } } -%>
:projects => @active_projects } -%>
<%= render :partial => "sidebar/context_list",
:locals => { :list_name => 'Active Contexts',
:contexts => @contexts.reject{|c| c.hide? } } -%>
:contexts => @active_contexts } -%>
<% if prefs.show_hidden_projects_in_sidebar -%>
<%= render :partial => "sidebar/project_list",
:locals => { :list_name => 'Hidden Projects',
:projects => @projects.select{|p| p.hidden? } } -%>
:projects => @hidden_projects } -%>
<% end -%>
<% if prefs.show_completed_projects_in_sidebar -%>
<%= render :partial => "sidebar/project_list",
:locals => { :list_name => 'Completed Projects',
:projects => @projects.select{|p| p.completed? } } -%>
:projects => @completed_projects } -%>
<% end -%>
<% if prefs.show_hidden_contexts_in_sidebar -%>
<%= render :partial => "sidebar/context_list",
:locals => { :list_name => 'Hidden Contexts',
:contexts => @contexts.select{|c| c.hide? } } -%>
:contexts => @hidden_contexts } -%>
<% end -%>
<div class="integrations-link"><ul>

View file

@ -8,9 +8,9 @@ end
-%><%=@actions_per_context[@actions_per_context.size()-1]['total'].to_i*100/@sum%>&
&pie_labels=<%
0.upto @actions_per_context.size()-2 do | i |
%><%=truncate(@actions_per_context[i]['name'],@truncate_chars, '...')%>,<%
%><%=truncate(@actions_per_context[i]['name'], :length => @truncate_chars, :omission => '...')%>,<%
end
-%><%=truncate(@actions_per_context[@actions_per_context.size()-1]['name'],@truncate_chars,'...') %>&
-%><%=truncate(@actions_per_context[@actions_per_context.size()-1]['name'], :legnth => @truncate_chars, :omission => '...') %>&
&links=<%
0.upto @actions_per_context.size()-2 do | i |
%><%=url_for :controller => "contexts", :action => "show", :id=>@actions_per_context[i]['id']%>,<%

View file

@ -8,9 +8,9 @@ end
-%><%=@actions_per_context[@actions_per_context.size()-1]['total'].to_i*100/@sum%>&
&pie_labels=<%
0.upto @actions_per_context.size()-2 do | i |
%><%=truncate(@actions_per_context[i]['name'], @truncate_chars, '...') %>,<%
%><%=truncate(@actions_per_context[i]['name'], :length => @truncate_chars, :omission => '...') %>,<%
end
-%><%=truncate(@actions_per_context[@actions_per_context.size()-1]['name'], @truncate_chars, '...') %>&
-%><%=truncate(@actions_per_context[@actions_per_context.size()-1]['name'], :length => @truncate_chars, :omission => '...') %>&
&links=<%
0.upto @actions_per_context.size()-2 do | i |
%><%=url_for :controller => "contexts", :action => "show", :id=>@actions_per_context[i]['id']%>,<%

View file

@ -10,7 +10,7 @@ if parent_container_type == 'show_mobile' -%>
<h2><label for="todo_description">Description</label></h2>
<%= text_field( "todo", "description", "tabindex" => 2) %>
<h2><label for="todo_notes">Notes</label></h2>
<%= text_area( "todo", "notes", "cols" => 30, "rows" => 5, "tabindex" => 3) %>
<%= text_area( "todo", "notes", "cols" => 30, "rows" => 2, "tabindex" => 3) %>
<h2><label for="todo_context_id">Context</label></h2>
<%= unless @mobile_from_context
collection_select( "todo", "context_id", @contexts, "id", "name", {}, {"tabindex" => 4} )
@ -22,7 +22,7 @@ end %>
<h2><label for="todo_project_id">Project</label></h2>
<%= unless @mobile_from_project
collection_select( "todo", "project_id", @projects, "id", "name",
{:include_blank => true}, {"tabindex" => 5} )
{:include_blank => '--No project--'}, {"tabindex" => 5} )
else
# manually add blank option since :include_blank does not work
# with options_from_collection_for_select
@ -34,7 +34,7 @@ end %>
<%= text_field_tag "tag_list", @tag_list_text, :size => 30, :tabindex => 6 %>
<h2><label for="todo_due">Due</label></h2>
<%= date_select("todo", "due", {:order => [:day, :month, :year],
:start_year => this_year, :include_blank => true}, :tabindex => 7) %>
:start_year => this_year, :include_blank => '--'}, :tabindex => 7) %>
<h2><label for="todo_show_from">Show from</label></h2>
<%= date_select("todo", "show_from", {:order => [:day, :month, :year],
:start_year => this_year, :include_blank => true}, :tabindex => 8) %>

View file

@ -1,11 +1,10 @@
<% @todo = mobile_todo
if mobile_todo.starred?
bullet = "<span class=star>"+image_tag("menustar_small.gif")+"</span>"
li_class = " class=\"star\""
else
bullet = "<span class=r>&raquo;&nbsp;</span>"
li_class = ""
end -%>
<div class="t" id="<%= dom_id(mobile_todo) %>">
<tr valign="top"><td><%= bullet %></td><td><%
<li id="<%= dom_id(mobile_todo) %>" <%= li_class %>><%
if mobile_todo.completed?
-%><span class="m_t_d">
<% else
@ -23,4 +22,4 @@ end -%>
")</span>" -%>
<% end -%>
<%= tag_list_mobile -%>
</span></td></tr></div>
</span></li>

View file

@ -14,7 +14,10 @@
<% unless @todo.completed? %><span class="defer-container"><%= defer_link(1) %> <%= defer_link(7) %></span><% end %>
<%= date_span -%>
<span class="todo.descr"><%= h sanitize(todo.description) %></span>
<%= link_to(image_tag("recurring16x16.png"), {:controller => "recurring_todos", :action => "index"}, :class => "recurring_icon") if @todo.from_recurring_todo? %>
<%= link_to(
image_tag("recurring16x16.png"),
{:controller => "recurring_todos", :action => "index"},
:class => "recurring_icon", :title => recurrence_pattern_as_text(@todo.recurring_todo)) if @todo.from_recurring_todo? %>
<%= tag_list %>
<%= deferred_due_date %>
<%= project_and_context_links( parent_container_type, :suppress_context => suppress_context, :suppress_project => suppress_project ) %>

View file

@ -20,7 +20,7 @@ CLASS:PUBLIC
CATEGORIES:Tracks
CREATED:<%= todo.created_at.strftime("%Y%m%dT%H%M%SZ") %>
DESCRIPTION:<%= format_ical_notes(todo.notes) %>
LAST-MODIFIED:<%= due_date.strftime("%Y%m%dT%H%M%SZ") %>
LAST-MODIFIED:<%= todo.updated_at.strftime("%Y%m%dT%H%M%SZ") %>
LOCATION:
SEQUENCE:0
STATUS:CONFIRMED

View file

@ -16,7 +16,7 @@ if @saved
page.insert_html :top, 'display_box', :partial => 'contexts/context', :locals => { :context => @todo.context, :collapsible => true }
else
page.call "todoItems.ensureVisibleWithEffectAppear", "c#{@todo.context_id}" if source_view_is_one_of(:todo, :deferred)
page.insert_html :bottom, item_container_id(@todo) + 'items', :partial => 'todos/todo', :locals => { :parent_container_type => parent_container_type, :source_view => @source_view }
page.insert_html :bottom, item_container_id(@todo) + 'items', :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type, :source_view => @source_view }
page.visual_effect :highlight, dom_id(@todo), :duration => 3
page[empty_container_msg_div_id].hide unless empty_container_msg_div_id.nil?
end

View file

@ -10,5 +10,7 @@
<div id="input_box">
<%= render :partial => "shared/add_new_item_form" %>
<%= render "sidebar/sidebar" %>
<%- # TODO: this used to be render :template, but somehow it was not
#rendered after the rails2.2.2 upgrade -%>
<%= render :file => "sidebar/sidebar.html.erb" %>
</div><!-- End of input box -->

View file

@ -11,5 +11,5 @@
<div id="input_box">
<%= render :partial => "shared/add_new_item_form" %>
<%= render "sidebar/sidebar" %>
<%= render :template => "sidebar/sidebar" %>
</div><!-- End of input box -->

View file

@ -23,5 +23,5 @@
<div id="input_box">
<%= render :partial => "shared/add_new_item_form" %>
<%= render "sidebar/sidebar" %>
<%= render :template => "sidebar/sidebar" %>
</div><!-- End of input box -->

View file

@ -5,7 +5,7 @@ if @saved
# completed todos move from their context to the completed container
unless @prefs.hide_completed_actions?
page.insert_html :top, "completed_containeritems", :partial => 'todos/todo', :locals => { :parent_container_type => "completed" }
page.insert_html :top, "completed_containeritems", :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => "completed" }
page.visual_effect :highlight, dom_id(@todo, 'line'), {'startcolor' => "'#99ff99'"}
page[empty_container_msg_div_id].show if @down_count == 0 && !empty_container_msg_div_id.nil?
page.show 'tickler-empty-nd' if source_view_is(:project) && @deferred_count == 0
@ -33,7 +33,7 @@ if @saved
else
# todo is activated from completed container
page.call "todoItems.ensureVisibleWithEffectAppear", item_container_id(@todo)
page.insert_html :bottom, item_container_id(@todo), :partial => 'todos/todo', :locals => { :parent_container_type => parent_container_type }
page.insert_html :bottom, item_container_id(@todo), :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
page.visual_effect :highlight, dom_id(@todo, 'line'), {'startcolor' => "'#99ff99'"}
page.show "empty-d" if @completed_count == 0
page[empty_container_msg_div_id].hide unless empty_container_msg_div_id.nil? # If we've checked something as undone, incomplete items can't be empty

View file

@ -36,7 +36,7 @@ if @saved
page.call "todoItems.expandNextActionListingByContext", "c#{@todo.context_id}items", true
page[empty_container_msg_div_id].hide unless empty_container_msg_div_id.nil?
# show all todos in context
page.insert_html :bottom, "c#{@todo.context_id}items", :partial => 'todos/todo', :locals => { :parent_container_type => parent_container_type }
page.insert_html :bottom, "c#{@todo.context_id}items", :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
end
# update badge count
@ -52,7 +52,7 @@ if @saved
end
end
else
page.replace dom_id(@todo), :partial => 'todos/todo', :locals => { :parent_container_type => parent_container_type }
page.replace dom_id(@todo), :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
page.visual_effect :highlight, dom_id(@todo), :duration => 3
end
elsif source_view_is :project
@ -63,17 +63,17 @@ if @saved
elsif @todo.deferred?
page[@todo].remove
page.show("p#{@original_item_project_id}empty-nd") if (@remaining_undone_in_project == 0)
page.insert_html :bottom, "tickler", :partial => 'todos/todo', :locals => { :parent_container_type => parent_container_type }
page.insert_html :bottom, "tickler", :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
page['tickler-empty-nd'].hide
page.replace_html "badge_count", @down_count
elsif @todo_was_activated_from_deferred_state
page[@todo].remove
page['tickler-empty-nd'].show if (@deferred_count == 0)
page.insert_html :bottom, "p#{@todo.project_id}", :partial => 'todos/todo', :locals => { :parent_container_type => parent_container_type }
page.insert_html :bottom, "p#{@todo.project_id}", :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
page["p#{@todo.project_id}empty-nd"].hide
page.replace_html "badge_count", @down_count
else
page.replace dom_id(@todo), :partial => 'todos/todo', :locals => { :parent_container_type => parent_container_type }
page.replace dom_id(@todo), :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
page.visual_effect :highlight, dom_id(@todo), :duration => 3
end
elsif source_view_is :deferred
@ -87,7 +87,7 @@ if @saved
page.call "todoItems.ensureVisibleWithEffectAppear", "c#{@todo.context_id}"
page.call "todoItems.expandNextActionListingByContext", "c#{@todo.context_id}items", true
page[empty_container_msg_div_id].hide unless empty_container_msg_div_id.nil?
page.insert_html :bottom, "c#{@todo.context_id}items", :partial => 'todos/todo', :locals => { :parent_container_type => parent_container_type }
page.insert_html :bottom, "c#{@todo.context_id}items", :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
page.replace_html("badge_count", @down_count)
page.delay(0.5) do
page.call "todoItems.ensureContainerHeight", "c#{@original_item_context_id}items"
@ -95,18 +95,18 @@ if @saved
page.visual_effect :highlight, dom_id(@todo), :duration => 3
end
else
page.replace dom_id(@todo), :partial => 'todos/todo', :locals => { :parent_container_type => parent_container_type }
page.replace dom_id(@todo), :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
page.visual_effect :highlight, dom_id(@todo), :duration => 3
end
elsif source_view_is :stats
page.replace dom_id(@todo), :partial => 'todos/todo', :locals => { :parent_container_type => parent_container_type }
page.replace dom_id(@todo), :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
page.visual_effect :highlight, dom_id(@todo), :duration => 3
elsif source_view_is :calendar
if @due_date_changed
page[@todo].remove
page.show "empty_"+@original_item_due_id if @old_due_empty
page.hide "empty_"+@new_due_id
page.insert_html :bottom, @new_due_id, :partial => 'todos/todo'
page.insert_html :bottom, @new_due_id, :partial => 'todos/todo', :locals => {:todo => @todo}
page.visual_effect :highlight, dom_id(@todo), :duration => 3
else
if @todo.due.nil?
@ -114,7 +114,7 @@ if @saved
page[@todo].remove
page.show "empty_"+@original_item_due_id if @old_due_empty
else
page.replace dom_id(@todo), :partial => 'todos/todo', :locals => { :parent_container_type => parent_container_type }
page.replace dom_id(@todo), :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type }
page.visual_effect :highlight, dom_id(@todo), :duration => 3
end
end