mirror of
https://github.com/TracksApp/tracks.git
synced 2025-09-22 05:50:47 +02:00

Up to r881 * 'master' of /Users/jackie/Sites/tracks_svn: (22 commits) Added .gitconfig Added yaml_db plugin: http://opensource.heroku.com/ applied patch from Eric from #732 fixes #730 restores ability to delete user from user management page fixes #724 where editing todos truncates the project name of the todo when the project name contains quotes (") Applied patch from Eric Pallen whcih automatically converts url's to links. Thanks Eric! explain that yaml cannot yet be used for backup as importing is not implemented yet. from mailinglist. hopefully fixes #727.Changes the check on running animation to finished animation regenerate compressed js and cleanup whitespace turns out that getElementsByClassName is removed from prototype and it therfore falls back to the function of the browser which has different semantics. Found here http://www.prototypejs.org/api/utility/getElementsByClassName forgot to create a new compressed js from the previous js changes in the stats page you can downdrill to see the active todos in a certain week from the running time charts. This patch adds the option to see all active todos from the selected week and older. fix #727. Adds a check to prevent expand/collapse while a previous expand/collaps is still animating fixed small problem where updating a todo from mobile resulted in an error becase source_view was nil fixes #726. Thanks Eric Pallen for the fix. The mobile view showed active todos from completed projects while the home page does not. merges changes from tracks1.6 to trunk prepares trunk for 1.6 release fixes #713. Adds behavior for edit/star/delete/check buttons of todo even if there is no todo to show. This makes sure that the behaviors are present when you add a new todo through AJAX. fixes #718. The link included the number of actions which resulted from last commit removed some more whitespace to reduce the download of the mobile view. ...
716 lines
24 KiB
Ruby
716 lines
24 KiB
Ruby
class TodosController < ApplicationController
|
|
|
|
helper :todos
|
|
|
|
skip_before_filter :login_required, :only => [:index]
|
|
prepend_before_filter :login_or_feed_token_required, :only => [:index]
|
|
append_before_filter :init, :except => [ :destroy, :completed, :completed_archive, :check_deferred, :toggle_check, :toggle_star, :edit, :update, :create ]
|
|
append_before_filter :get_todo_from_params, :only => [ :edit, :toggle_check, :toggle_star, :show, :update, :destroy ]
|
|
|
|
session :off, :only => :index, :if => Proc.new { |req| is_feed_request(req) }
|
|
|
|
def index
|
|
@projects = current_user.projects.find(:all, :include => [:default_context])
|
|
@contexts = current_user.contexts.find(:all)
|
|
|
|
@contexts_to_show = @contexts.reject {|x| x.hide? }
|
|
|
|
respond_to do |format|
|
|
format.html &render_todos_html
|
|
format.m &render_todos_mobile
|
|
format.xml { render :xml => @todos.to_xml( :except => :user_id ) }
|
|
format.rss &render_rss_feed
|
|
format.atom &render_atom_feed
|
|
format.text &render_text_feed
|
|
format.ics &render_ical_feed
|
|
end
|
|
end
|
|
|
|
def new
|
|
@projects = current_user.projects.select { |p| p.active? }
|
|
@contexts = current_user.contexts.find(:all)
|
|
respond_to do |format|
|
|
format.m {
|
|
@new_mobile = true
|
|
@return_path=cookies[:mobile_url]
|
|
render :action => "new"
|
|
}
|
|
end
|
|
end
|
|
|
|
def create
|
|
@source_view = params['_source_view'] || 'todo'
|
|
p = TodoCreateParamsHelper.new(params, prefs)
|
|
p.parse_dates() unless mobile?
|
|
|
|
@todo = current_user.todos.build(p.attributes)
|
|
|
|
if p.project_specified_by_name?
|
|
project = current_user.projects.find_or_create_by_name(p.project_name)
|
|
@new_project_created = project.new_record_before_save?
|
|
@todo.project_id = project.id
|
|
end
|
|
|
|
if p.context_specified_by_name?
|
|
context = current_user.contexts.find_or_create_by_name(p.context_name)
|
|
@new_context_created = context.new_record_before_save?
|
|
@not_done_todos = [@todo] if @new_context_created
|
|
@todo.context_id = context.id
|
|
end
|
|
|
|
@saved = @todo.save
|
|
unless (@saved == false) || p.tag_list.blank?
|
|
@todo.tag_with(p.tag_list, current_user)
|
|
@todo.tags.reload
|
|
end
|
|
|
|
respond_to do |format|
|
|
format.html { redirect_to :action => "index" }
|
|
format.m do
|
|
@return_path=cookies[:mobile_url]
|
|
# todo: use function for this fixed path
|
|
@return_path='/mobile' if @return_path.nil?
|
|
if @saved
|
|
redirect_to mobile_abbrev_url
|
|
else
|
|
@projects = current_user.projects.find(:all)
|
|
@contexts = current_user.contexts.find(:all)
|
|
render :action => "new"
|
|
end
|
|
end
|
|
format.js do
|
|
determine_down_count if @saved
|
|
@contexts = current_user.contexts.find(:all) if @new_context_created
|
|
@projects = current_user.projects.find(:all) if @new_project_created
|
|
@initial_context_name = params['default_context_name']
|
|
render :action => 'create'
|
|
end
|
|
format.xml do
|
|
if @saved
|
|
head :created, :location => todo_url(@todo)
|
|
else
|
|
render :xml => @todo.errors.to_xml, :status => 422
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def edit
|
|
@projects = current_user.projects.find(:all)
|
|
@contexts = current_user.contexts.find(:all)
|
|
@source_view = params['_source_view'] || 'todo'
|
|
respond_to do |format|
|
|
format.js
|
|
end
|
|
end
|
|
|
|
def show
|
|
respond_to do |format|
|
|
format.m do
|
|
@projects = current_user.projects.select { |p| p.active? }
|
|
@contexts = current_user.contexts.find(:all)
|
|
@edit_mobile = true
|
|
@return_path=cookies[:mobile_url]
|
|
render :action => 'show'
|
|
end
|
|
format.xml { render :xml => @todo.to_xml( :root => 'todo', :except => :user_id ) }
|
|
end
|
|
end
|
|
|
|
# Toggles the 'done' status of the action
|
|
#
|
|
def toggle_check
|
|
@saved = @todo.toggle_completion!
|
|
respond_to do |format|
|
|
format.js do
|
|
if @saved
|
|
determine_remaining_in_context_count(@todo.context_id)
|
|
determine_down_count
|
|
determine_completed_count if @todo.completed?
|
|
end
|
|
render
|
|
end
|
|
format.xml { render :xml => @todo.to_xml( :except => :user_id ) }
|
|
format.html do
|
|
if @saved
|
|
# TODO: I think this will work, but can't figure out how to test it
|
|
notify :notice, "The action <strong>'#{@todo.description}'</strong> was marked as <strong>#{@todo.completed? ? 'complete' : 'incomplete' }</strong>"
|
|
redirect_to :action => "index"
|
|
else
|
|
notify :notice, "The action <strong>'#{@todo.description}'</strong> was NOT marked as <strong>#{@todo.completed? ? 'complete' : 'incomplete' } due to an error on the server.</strong>", "index"
|
|
redirect_to :action => "index"
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def toggle_star
|
|
@todo.toggle_star!
|
|
@saved = @todo.save!
|
|
respond_to do |format|
|
|
format.js
|
|
format.xml { render :xml => @todo.to_xml( :except => :user_id ) }
|
|
end
|
|
end
|
|
|
|
def update
|
|
@source_view = params['_source_view'] || 'todo'
|
|
init_data_for_sidebar unless mobile?
|
|
@todo.tag_with(params[:tag_list], current_user) if params[:tag_list]
|
|
@original_item_context_id = @todo.context_id
|
|
@original_item_project_id = @todo.project_id
|
|
@original_item_was_deferred = @todo.deferred?
|
|
if params['todo']['project_id'].blank? && !params['project_name'].nil?
|
|
if params['project_name'] == 'None'
|
|
project = Project.null_object
|
|
else
|
|
project = current_user.projects.find_by_name(params['project_name'].strip)
|
|
unless project
|
|
project = current_user.projects.build
|
|
project.name = params['project_name'].strip
|
|
project.save
|
|
@new_project_created = true
|
|
end
|
|
end
|
|
params["todo"]["project_id"] = project.id
|
|
end
|
|
|
|
if params['todo']['context_id'].blank? && !params['context_name'].blank?
|
|
context = current_user.contexts.find_by_name(params['context_name'].strip)
|
|
unless context
|
|
context = current_user.contexts.build
|
|
context.name = params['context_name'].strip
|
|
context.save
|
|
@new_context_created = true
|
|
@not_done_todos = [@todo]
|
|
end
|
|
params["todo"]["context_id"] = context.id
|
|
end
|
|
|
|
if params["todo"].has_key?("due")
|
|
params["todo"]["due"] = parse_date_per_user_prefs(params["todo"]["due"])
|
|
else
|
|
params["todo"]["due"] = ""
|
|
end
|
|
|
|
if params['todo']['show_from']
|
|
params['todo']['show_from'] = parse_date_per_user_prefs(params['todo']['show_from'])
|
|
end
|
|
|
|
if params['done'] == '1' && !@todo.completed?
|
|
@todo.complete!
|
|
end
|
|
# strange. if checkbox is not checked, there is no 'done' in params.
|
|
# Therfore I've used the negation
|
|
if !(params['done'] == '1') && @todo.completed?
|
|
@todo.activate!
|
|
end
|
|
|
|
@saved = @todo.update_attributes params["todo"]
|
|
@context_changed = @original_item_context_id != @todo.context_id
|
|
@todo_was_activated_from_deferred_state = @original_item_was_deferred && @todo.active?
|
|
determine_remaining_in_context_count(@original_item_context_id) if @context_changed
|
|
@project_changed = @original_item_project_id != @todo.project_id
|
|
if (@project_changed && !@original_item_project_id.nil?) then @remaining_undone_in_project = current_user.projects.find(@original_item_project_id).not_done_todo_count; end
|
|
determine_down_count
|
|
respond_to do |format|
|
|
format.js
|
|
format.xml { render :xml => @todo.to_xml( :except => :user_id ) }
|
|
format.m do
|
|
if @saved
|
|
if cookies[:mobile_url]
|
|
cookies[:mobile_url] = nil
|
|
redirect_to cookies[:mobile_url]
|
|
else
|
|
redirect_to formatted_todos_path(:m)
|
|
end
|
|
else
|
|
render :action => "edit", :format => :m
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def destroy
|
|
@todo = get_todo_from_params
|
|
@context_id = @todo.context_id
|
|
@project_id = @todo.project_id
|
|
@saved = @todo.destroy
|
|
|
|
respond_to do |format|
|
|
|
|
format.html do
|
|
if @saved
|
|
notify :notice, "Successfully deleted next action", 2.0
|
|
redirect_to :action => 'index'
|
|
else
|
|
notify :error, "Failed to delete the action", 2.0
|
|
redirect_to :action => 'index'
|
|
end
|
|
end
|
|
|
|
format.js do
|
|
if @saved
|
|
determine_down_count
|
|
if source_view_is_one_of(:todo, :deferred)
|
|
determine_remaining_in_context_count(@context_id)
|
|
end
|
|
end
|
|
render
|
|
end
|
|
|
|
format.xml { render :text => '200 OK. Action deleted.', :status => 200 }
|
|
|
|
end
|
|
end
|
|
|
|
def completed
|
|
@page_title = "TRACKS::Completed tasks"
|
|
@done = current_user.completed_todos
|
|
@done_today = @done.completed_within current_user.time - 1.day
|
|
@done_this_week = @done.completed_within current_user.time - 1.week
|
|
@done_this_month = @done.completed_within current_user.time - 4.week
|
|
@count = @done_today.size + @done_this_week.size + @done_this_month.size
|
|
end
|
|
|
|
def completed_archive
|
|
@page_title = "TRACKS::Archived completed tasks"
|
|
@done = current_user.completed_todos
|
|
@count = @done.size
|
|
@done_archive = @done.completed_more_than current_user.time - 28.days
|
|
end
|
|
|
|
def list_deferred
|
|
@source_view = 'deferred'
|
|
@page_title = "TRACKS::Tickler"
|
|
|
|
@projects = current_user.projects.find(:all, :include => [ :todos, :default_context ])
|
|
@contexts_to_show = @contexts = current_user.contexts.find(:all, :include => [ :todos ])
|
|
|
|
current_user.deferred_todos.find_and_activate_ready
|
|
@not_done_todos = current_user.deferred_todos
|
|
@count = @not_done_todos.size
|
|
@down_count = @count
|
|
@default_project_context_name_map = build_default_project_context_name_map(@projects).to_json unless mobile?
|
|
|
|
respond_to do |format|
|
|
format.html
|
|
format.m { render :action => 'mobile_list_deferred' }
|
|
end
|
|
end
|
|
|
|
# Check for any due tickler items, activate them Called by
|
|
# periodically_call_remote
|
|
def check_deferred
|
|
@due_tickles = current_user.deferred_todos.find_and_activate_ready
|
|
respond_to do |format|
|
|
format.html { redirect_to home_path }
|
|
format.js
|
|
end
|
|
end
|
|
|
|
def filter_to_context
|
|
context = current_user.contexts.find(params['context']['id'])
|
|
redirect_to formatted_context_todos_path(context, :m)
|
|
end
|
|
|
|
def filter_to_project
|
|
project = current_user.projects.find(params['project']['id'])
|
|
redirect_to formatted_project_todos_path(project, :m)
|
|
end
|
|
|
|
# /todos/tag/[tag_name] shows all the actions tagged with tag_name
|
|
def tag
|
|
@source_view = params['_source_view'] || 'tag'
|
|
@tag_name = params[:name]
|
|
|
|
# mobile tags are routed with :name ending on .m. So we need to chomp it
|
|
if mobile?
|
|
@tag_name = @tag_name.chomp('.m')
|
|
end
|
|
|
|
@tag = Tag.find_by_name(@tag_name)
|
|
if @tag.nil?
|
|
@tag = Tag.new(:name => @tag_name)
|
|
end
|
|
tag_collection = @tag.todos
|
|
@not_done_todos = tag_collection.find(:all, :conditions => ['taggings.user_id = ? and state = ?', current_user.id, 'active'])
|
|
|
|
@contexts = current_user.contexts.find(:all, :include => [ :todos ])
|
|
@contexts_to_show = @contexts.reject {|x| x.hide? }
|
|
|
|
@deferred = tag_collection.find(:all, :conditions => ['taggings.user_id = ? and state = ?', current_user.id, 'deferred'])
|
|
|
|
@page_title = "TRACKS::Tagged with \'#{@tag_name}\'"
|
|
# If you've set no_completed to zero, the completed items box isn't shown on
|
|
# the home page
|
|
max_completed = current_user.prefs.show_number_completed
|
|
@done = tag_collection.find(:all, :limit => max_completed, :conditions => ['taggings.user_id = ? and state = ?', current_user.id, 'completed'])
|
|
# Set count badge to number of items with this tag
|
|
@not_done_todos.empty? ? @count = 0 : @count = @not_done_todos.size
|
|
@down_count = @count
|
|
# @default_project_context_name_map =
|
|
# build_default_project_context_name_map(@projects).to_json
|
|
respond_to do |format|
|
|
format.html
|
|
format.m {
|
|
cookies[:mobile_url]=request.request_uri
|
|
render :action => "mobile_tag"
|
|
}
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def get_todo_from_params
|
|
@todo = current_user.todos.find(params['id'])
|
|
end
|
|
|
|
def init
|
|
@source_view = params['_source_view'] || 'todo'
|
|
init_data_for_sidebar unless mobile?
|
|
init_todos
|
|
end
|
|
|
|
def with_feed_query_scope(&block)
|
|
unless TodosController.is_feed_request(request)
|
|
Todo.send(:with_scope, :find => {:conditions => ['todos.state = ?', 'active']}) do
|
|
yield
|
|
return
|
|
end
|
|
end
|
|
condition_builder = FindConditionBuilder.new
|
|
|
|
if params.key?('done')
|
|
condition_builder.add 'todos.state = ?', 'completed'
|
|
else
|
|
condition_builder.add 'todos.state = ?', 'active'
|
|
end
|
|
|
|
@title = "Tracks - Next Actions"
|
|
@description = "Filter: "
|
|
|
|
if params.key?('due')
|
|
due_within = params['due'].to_i
|
|
due_within_when = current_user.time + due_within.days
|
|
condition_builder.add('todos.due <= ?', due_within_when)
|
|
due_within_date_s = due_within_when.strftime("%Y-%m-%d")
|
|
@title << " due today" if (due_within == 0)
|
|
@title << " due within a week" if (due_within == 6)
|
|
@description << " with a due date #{due_within_date_s} or earlier"
|
|
end
|
|
|
|
if params.key?('done')
|
|
done_in_last = params['done'].to_i
|
|
condition_builder.add('todos.completed_at >= ?', current_user.time - done_in_last.days)
|
|
@title << " actions completed"
|
|
@description << " in the last #{done_in_last.to_s} days"
|
|
end
|
|
|
|
Todo.send :with_scope, :find => {:conditions => condition_builder.to_conditions} do
|
|
yield
|
|
end
|
|
|
|
end
|
|
|
|
def with_parent_resource_scope(&block)
|
|
if (params[:context_id])
|
|
@context = current_user.contexts.find_by_params(params)
|
|
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)
|
|
Todo.send :with_scope, :find => {:conditions => ['todos.project_id = ?', @project.id]} do
|
|
yield
|
|
end
|
|
else
|
|
yield
|
|
end
|
|
end
|
|
|
|
def with_limit_scope(&block)
|
|
if params.key?('limit')
|
|
Todo.send :with_scope, :find => { :limit => params['limit'] } do
|
|
yield
|
|
end
|
|
if TodosController.is_feed_request(request) && @description
|
|
if params.key?('limit')
|
|
@description << "Lists the last #{params['limit']} incomplete next actions"
|
|
else
|
|
@description << "Lists incomplete next actions"
|
|
end
|
|
end
|
|
else
|
|
yield
|
|
end
|
|
end
|
|
|
|
def init_todos
|
|
with_feed_query_scope do
|
|
with_parent_resource_scope do # @context or @project may get defined here
|
|
with_limit_scope do
|
|
|
|
if mobile?
|
|
init_todos_for_mobile_view
|
|
else
|
|
|
|
# Note: these next two finds were previously using
|
|
# current_users.todos.find but that broke with_scope for :limit
|
|
|
|
# Exclude hidden projects from count on home page
|
|
@todos = Todo.find(:all, :conditions => ['todos.user_id = ?', current_user.id], :include => [ :project, :context, :tags ])
|
|
|
|
# Exclude hidden projects from the home page
|
|
@not_done_todos = Todo.find(:all,
|
|
:conditions => ['todos.user_id = ? AND contexts.hide = ? AND (projects.state = ? OR todos.project_id IS NULL)',
|
|
current_user.id, false, 'active'],
|
|
:order => "todos.due IS NULL, todos.due ASC, todos.created_at ASC",
|
|
:include => [ :project, :context, :tags ])
|
|
end
|
|
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def init_todos_for_mobile_view
|
|
# Note: these next two finds were previously using current_users.todos.find
|
|
# but that broke with_scope for :limit
|
|
|
|
# Exclude hidden projects from the home page
|
|
@not_done_todos = Todo.find(:all,
|
|
:conditions => ['todos.user_id = ? AND todos.state = ? AND contexts.hide = ? AND (projects.state = ? OR todos.project_id IS NULL)',
|
|
current_user.id, 'active', false, 'active'],
|
|
:order => "todos.due IS NULL, todos.due ASC, todos.created_at ASC",
|
|
:include => [ :project, :context ])
|
|
end
|
|
|
|
def determine_down_count
|
|
source_view do |from|
|
|
from.todo do
|
|
@down_count = Todo.count(
|
|
:all,
|
|
:conditions => ['todos.user_id = ? and todos.state = ? and contexts.hide = ? AND (projects.state = ? OR todos.project_id IS NULL)', current_user.id, 'active', false, 'active'],
|
|
:include => [ :project, :context ])
|
|
# #@down_count = Todo.count_by_sql(['SELECT COUNT(*) FROM todos,
|
|
# contexts WHERE todos.context_id = contexts.id and todos.user_id = ?
|
|
# and todos.state = ? and contexts.hide = ?', current_user.id, 'active',
|
|
# false])
|
|
end
|
|
from.context do
|
|
@down_count = current_user.contexts.find(@todo.context_id).not_done_todo_count
|
|
end
|
|
from.project do
|
|
unless @todo.project_id == nil
|
|
@down_count = current_user.projects.find(@todo.project_id).not_done_todo_count(:include_project_hidden_todos => true)
|
|
@deferred_count = current_user.projects.find(@todo.project_id).deferred_todo_count
|
|
end
|
|
end
|
|
from.deferred do
|
|
@down_count = current_user.todos.count_in_state(:deferred)
|
|
end
|
|
from.tag do
|
|
@tag_name = params['_tag_name']
|
|
@tag = Tag.find_by_name(@tag_name)
|
|
if @tag.nil?
|
|
@tag = Tag.new(:name => @tag_name)
|
|
end
|
|
tag_collection = @tag.todos
|
|
@not_done_todos = tag_collection.find(:all, :conditions => ['taggings.user_id = ? and state = ?', current_user.id, 'active'])
|
|
@not_done_todos.empty? ? @down_count = 0 : @down_count = @not_done_todos.size
|
|
end
|
|
end
|
|
end
|
|
|
|
def determine_remaining_in_context_count(context_id = @todo.context_id)
|
|
if source_view_is :deferred
|
|
@remaining_in_context = current_user.contexts.find(context_id).deferred_todo_count
|
|
else
|
|
@remaining_in_context = current_user.contexts.find(context_id).not_done_todo_count
|
|
end
|
|
end
|
|
|
|
def determine_completed_count
|
|
source_view do |from|
|
|
from.todo do
|
|
@completed_count = Todo.count_by_sql(['SELECT COUNT(*) FROM todos, contexts WHERE todos.context_id = contexts.id and todos.user_id = ? and todos.state = ? and contexts.hide = ?', current_user.id, 'completed', false])
|
|
end
|
|
from.context do
|
|
@completed_count = current_user.contexts.find(@todo.context_id).done_todo_count
|
|
end
|
|
from.project do
|
|
unless @todo.project_id == nil
|
|
@completed_count = current_user.projects.find(@todo.project_id).done_todo_count
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def render_todos_html
|
|
lambda do
|
|
@page_title = "TRACKS::List tasks"
|
|
|
|
# If you've set no_completed to zero, the completed items box isn't shown
|
|
# on the home page
|
|
max_completed = current_user.prefs.show_number_completed
|
|
@done = current_user.completed_todos.find(:all, :limit => max_completed, :include => [ :context, :project, :tags ]) unless max_completed == 0
|
|
|
|
# Set count badge to number of not-done, not hidden context items
|
|
@count = 0
|
|
@todos.each do |x|
|
|
if x.active?
|
|
if x.project.nil?
|
|
@count += 1 if !x.context.hide?
|
|
else
|
|
@count += 1 if x.project.active? && !x.context.hide?
|
|
end
|
|
end
|
|
end
|
|
|
|
@default_project_context_name_map = build_default_project_context_name_map(@projects).to_json
|
|
|
|
render
|
|
end
|
|
end
|
|
|
|
def render_todos_mobile
|
|
lambda do
|
|
@page_title = "All actions"
|
|
@home = true
|
|
cookies[:mobile_url]=request.request_uri
|
|
determine_down_count
|
|
|
|
render :action => 'index'
|
|
end
|
|
end
|
|
|
|
def render_rss_feed
|
|
lambda do
|
|
render_rss_feed_for @todos, :feed => todo_feed_options,
|
|
:item => {
|
|
:title => :description,
|
|
:link => lambda { |t| context_url(t.context) },
|
|
:guid => lambda { |t| todo_url(t) },
|
|
:description => todo_feed_content
|
|
}
|
|
end
|
|
end
|
|
|
|
def todo_feed_options
|
|
Todo.feed_options(current_user)
|
|
end
|
|
|
|
def todo_feed_content
|
|
lambda do |i|
|
|
item_notes = sanitize(markdown( i.notes )) if i.notes?
|
|
due = "<div>Due: #{format_date(i.due)}</div>\n" if i.due?
|
|
done = "<div>Completed: #{format_date(i.completed_at)}</div>\n" if i.completed?
|
|
context_link = "<a href=\"#{ context_url(i.context) }\">#{ i.context.name }</a>"
|
|
if i.project_id?
|
|
project_link = "<a href=\"#{ project_url(i.project) }\">#{ i.project.name }</a>"
|
|
else
|
|
project_link = "<em>none</em>"
|
|
end
|
|
"#{done||''}#{due||''}#{item_notes||''}\n<div>Project: #{project_link}</div>\n<div>Context: #{context_link}</div>"
|
|
end
|
|
end
|
|
|
|
def render_atom_feed
|
|
lambda do
|
|
render_atom_feed_for @todos, :feed => todo_feed_options,
|
|
:item => {
|
|
:title => :description,
|
|
:link => lambda { |t| context_url(t.context) },
|
|
:description => todo_feed_content,
|
|
:author => lambda { |p| nil }
|
|
}
|
|
end
|
|
end
|
|
|
|
def render_text_feed
|
|
lambda do
|
|
render :action => 'index', :layout => false, :content_type => Mime::TEXT
|
|
end
|
|
end
|
|
|
|
def render_ical_feed
|
|
lambda do
|
|
render :action => 'index', :layout => false, :content_type => Mime::ICS
|
|
end
|
|
end
|
|
|
|
def self.is_feed_request(req)
|
|
['rss','atom','txt','ics'].include?(req.parameters[:format])
|
|
end
|
|
|
|
class FindConditionBuilder
|
|
|
|
def initialize
|
|
@queries = Array.new
|
|
@params = Array.new
|
|
end
|
|
|
|
def add(query, param)
|
|
@queries << query
|
|
@params << param
|
|
end
|
|
|
|
def to_conditions
|
|
[@queries.join(' AND ')] + @params
|
|
end
|
|
end
|
|
|
|
class TodoCreateParamsHelper
|
|
|
|
def initialize(params, prefs)
|
|
@params = params['request'] || params
|
|
@prefs = prefs
|
|
@attributes = params['request'] && params['request']['todo'] || params['todo']
|
|
end
|
|
|
|
def attributes
|
|
@attributes
|
|
end
|
|
|
|
def show_from
|
|
@attributes['show_from']
|
|
end
|
|
|
|
def due
|
|
@attributes['due']
|
|
end
|
|
|
|
def project_name
|
|
@params['project_name'].strip unless @params['project_name'].nil?
|
|
end
|
|
|
|
def context_name
|
|
@params['context_name'].strip unless @params['context_name'].nil?
|
|
end
|
|
|
|
def tag_list
|
|
@params['tag_list']
|
|
end
|
|
|
|
def parse_dates()
|
|
@attributes['show_from'] = @prefs.parse_date(show_from)
|
|
@attributes['due'] = @prefs.parse_date(due)
|
|
@attributes['due'] ||= ''
|
|
end
|
|
|
|
def project_specified_by_name?
|
|
return false unless @attributes['project_id'].blank?
|
|
return false if project_name.blank?
|
|
return false if project_name == 'None'
|
|
true
|
|
end
|
|
|
|
def context_specified_by_name?
|
|
return false unless @attributes['context_id'].blank?
|
|
return false if context_name.blank?
|
|
true
|
|
end
|
|
|
|
end
|
|
end
|