Merge branch 'master' of git://github.com/bsag/tracks into bsag

This commit is contained in:
Hans de Graaff 2011-02-19 11:27:15 +01:00
commit eea421f6d3
1281 changed files with 33862 additions and 58360 deletions

8
.gitignore vendored
View file

@ -15,6 +15,8 @@ public/stylesheets/cache
tmp
vendor/plugins/query_trace/
rerun.txt
public/javascripts/jquery-all.js
public/javascripts/tracks.js
public/stylesheets/all.css
public/javascripts/jquery-cached.js
public/javascripts/tracks-cached.js
public/stylesheets/tracks-cached.css
.idea
.rvmrc

View file

@ -33,10 +33,12 @@ class ApplicationController < ActionController::Base
before_filter :set_session_expiration
before_filter :set_time_zone
before_filter :set_zindex_counter
before_filter :set_locale
prepend_before_filter :login_required
prepend_before_filter :enable_mobile_content_negotiation
# after_filter :set_locale
after_filter :set_charset
include ActionView::Helpers::TextHelper
include ActionView::Helpers::SanitizeHelper
extend ActionView::Helpers::SanitizeHelper::ClassMethods
@ -47,6 +49,14 @@ class ApplicationController < ActionController::Base
headers["Content-Type"] ||= "text/html; charset=UTF-8"
end
def set_locale
locale = params[:locale] # specifying a locale in the request takes precedence
locale = locale || prefs.locale unless current_user.nil? # otherwise, the locale of the currently logged in user takes over
locale = locale || request.env['HTTP_ACCEPT_LANGUAGE'].scan(/^[a-z]{2}/).first if request.env['HTTP_ACCEPT_LANGUAGE']
I18n.locale = locale.nil? ? I18n.default_locale : (I18n::available_locales.include?(locale.to_sym) ? locale : I18n.default_locale)
logger.debug("Selected '#{I18n.locale}' as locale")
end
def set_session_expiration
# http://wiki.rubyonrails.com/rails/show/HowtoChangeSessionOptions
unless session == nil
@ -114,21 +124,25 @@ class ApplicationController < ActionController::Base
# config/settings.yml
#
def format_date(date)
if date
date_format = prefs.date_format
formatted_date = date.in_time_zone(prefs.time_zone).strftime("#{date_format}")
else
formatted_date = ''
end
formatted_date
return date ? date.in_time_zone(prefs.time_zone).strftime("#{prefs.date_format}") : ''
end
def for_autocomplete(coll, substr)
filtered = coll.find_all{|item| item.name.downcase.include? substr.downcase}
return filtered.map {|item| "#{item.name}|#{item.id}"}.join("\n")
if substr # protect agains empty request
filtered = coll.find_all{|item| item.name.downcase.include? substr.downcase}
json_elems = "[{" + filtered.map {|item| "\"value\" : \"#{item.name}\", \"id\" : \"#{item.id}\""}.join("},{") + "}]"
return json_elems == "[{}]" ? "" : json_elems
else
return ""
end
end
def auto_complete_result2(entries, phrase = nil)
json_elems = "[{" + entries.map {|item| "\"id\" : \"#{item.id}\", \"value\" : \"#{item.specification()}\""}.join("},{") + "}]"
return json_elems == "[{}]" ? "" : json_elems
end
# Uses RedCloth to transform text using either Textile or Markdown Need to
# require redcloth above RedCloth 3.0 or greater is needed to use Markdown,
# otherwise it only handles Textile
@ -196,7 +210,7 @@ class ApplicationController < ActionController::Base
def admin_login_required
unless User.find_by_id_and_is_admin(session['user_id'], true)
render :text => "401 Unauthorized: Only admin users are allowed access to this function.", :status => 401
render :text => t('errors.user_unauthorized'), :status => 401
return false
end
end

View file

@ -13,16 +13,25 @@ class ContextsController < ApplicationController
# checks later don't result in separate SQL queries
@active_contexts = current_user.contexts.active(true)
@hidden_contexts = current_user.contexts.hidden(true)
@count = @active_contexts.size + @hidden_contexts.size
@new_context = current_user.contexts.build
# save all contexts here as @new_context will add an empty one to current_user.contexts
@all_contexts = @active_contexts + @hidden_contexts
@count = @all_contexts.size
init_not_done_counts(['context'])
respond_to do |format|
format.html &render_contexts_html
format.m &render_contexts_mobile
format.xml { render :xml => current_user.contexts.to_xml( :except => :user_id ) }
format.xml { render :xml => @all_contexts.to_xml( :except => :user_id ) }
format.rss &render_contexts_rss_feed
format.atom &render_contexts_atom_feed
format.text { render :action => 'index', :layout => false, :content_type => Mime::TEXT }
format.autocomplete { render :text => for_autocomplete(@active_contexts + @hidden_contexts, params[:q])}
format.text do
@all_contexts = current_user.contexts.all
render :action => 'index', :layout => false, :content_type => Mime::TEXT
end
format.autocomplete { render :text => for_autocomplete(@active_contexts + @hidden_contexts, params[:term])}
end
end
@ -90,13 +99,18 @@ class ContextsController < ApplicationController
@original_context_hidden = @context.hidden?
@context.attributes = params["context"]
if @context.save
@saved = @context.save
if @saved
if boolean_param('wants_render')
@context_state_changed = (@original_context_hidden != @context.hidden?)
@new_state = (@context.hidden? ? "hidden" : "active") if @context_state_changed
@state_changed = (@original_context_hidden != @context.hidden?)
@new_state = (@context.hidden? ? "hidden" : "active") if @state_changed
respond_to do |format|
format.js
end
# TODO is this param ever used? is this dead code?
elsif boolean_param('update_context_name')
@contexts = current_user.projects
render :template => 'contexts/update_context_name.js.rjs'
@ -105,8 +119,9 @@ class ContextsController < ApplicationController
render :text => success_text || 'Success'
end
else
notify :warning, "Couldn't update new context"
render :text => ""
respond_to do |format|
format.js
end
end
end
@ -126,7 +141,10 @@ class ContextsController < ApplicationController
@context.destroy
respond_to do |format|
format.js { @down_count = current_user.contexts.size }
format.js do
@down_count = current_user.contexts.size
update_state_counts
end
format.xml { render :text => "Deleted context #{@context.name}" }
end
end
@ -144,6 +162,13 @@ class ContextsController < ApplicationController
protected
def update_state_counts
@active_contexts_count = current_user.contexts.active.count
@hidden_contexts_count = current_user.contexts.hidden.count
@show_active_contexts = @active_contexts_count > 0
@show_hidden_contexts = @hidden_contexts_count > 0
end
def render_contexts_html
lambda do
@page_title = "TRACKS::List Contexts"
@ -179,14 +204,14 @@ class ContextsController < ApplicationController
def render_contexts_rss_feed
lambda do
render_rss_feed_for current_user.contexts, :feed => feed_options,
render_rss_feed_for current_user.contexts.all, :feed => feed_options,
:item => { :description => lambda { |c| c.summary(count_undone_todos_phrase(c)) } }
end
end
def render_contexts_atom_feed
lambda do
render_atom_feed_for current_user.contexts, :feed => feed_options,
render_atom_feed_for current_user.contexts.all, :feed => feed_options,
:item => { :description => lambda { |c| c.summary(count_undone_todos_phrase(c)) },
:author => lambda { |c| nil } }
end
@ -230,6 +255,7 @@ class ContextsController < ApplicationController
@count = @not_done_todos.size
end
end
end

View file

@ -26,13 +26,19 @@ class FeedlistController < ApplicationController
end
def get_feeds_for_context
context = current_user.contexts.find params[:context_id]
render :partial => 'feed_for_context', :locals => { :context => context }
@context = current_user.contexts.find params[:context_id]
respond_to do |format|
format.html { render :file => 'feedlist/get_feeds_for_context'}
format.js
end
end
def get_feeds_for_project
project = current_user.projects.find params[:project_id]
render :partial => 'feed_for_project', :locals => { :project => project }
@project = current_user.projects.find params[:project_id]
respond_to do |format|
format.html { render :file => "feedlist/get_feeds_for_project"}
format.js
end
end
end

View file

@ -33,30 +33,30 @@ class LoginController < ApplicationController
@page_title = "TRACKS::Login"
cookies[:preferred_auth] = prefered_auth? unless cookies[:preferred_auth]
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 => SITE_CONFIG['secure_cookies'] }
unless should_expire_sessions?
@user.remember_me
cookies[:auth_token] = { :value => @user.remember_token , :expires => @user.remember_token_expires_at, :secure => SITE_CONFIG['secure_cookies'] }
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 signup_path
return
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 => SITE_CONFIG['secure_cookies'] }
unless should_expire_sessions?
@user.remember_me
cookies[:auth_token] = { :value => @user.remember_token , :expires => @user.remember_token_expires_at, :secure => SITE_CONFIG['secure_cookies'] }
end
redirect_back_or_home
return
else
@login = params['user_login']
notify :warning, t('login.unsuccessful')
end
when :get
if User.no_users_yet?
redirect_to signup_path
return
end
end
respond_to do |format|
format.html
@ -73,25 +73,38 @@ class LoginController < ApplicationController
CASClient::Frameworks::Rails::Filter.logout(self)
else
reset_session
notify :notice, "You have been logged out of Tracks."
notify :notice, t('login.logged_out')
redirect_to_login
end
end
def expire_session
# this is a hack to enable cucumber to expire a session by calling this
# method. The method will be unavailable for production environment
unless Rails.env.production?
session['expiry_time'] = Time.now
respond_to do |format|
format.html { render :text => "Session expired for test purposes"}
format.js { render :text => "" }
end
else
respond_to do |format|
format.html { render :text => "Not available for production use"}
format.js { render :text => "" }
end
end
end
def check_expiry
# Gets called by periodically_call_remote to check whether
# Gets called by periodically_call_remote to check whether
# the session has timed out yet
unless session == nil
if session
return unless should_expire_sessions?
# Get expiry time (allow ten seconds window for the case where we have none)
expiry_time = session['expiry_time'] || Time.now + 10
@time_left = expiry_time - Time.now
if @time_left < (10*60) # Session will time out before the next check
@msg = "Session has timed out. Please "
else
@msg = ""
end
time_left = expiry_time - Time.now
@session_expired = ( time_left < (10*60) ) # Session will time out before the next check
end
end
respond_to do |format|
@ -99,7 +112,7 @@ class LoginController < ApplicationController
end
end
def login_cas
def login_cas
# 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
@ -107,22 +120,21 @@ class LoginController < ApplicationController
if session[:cas_user]
if @user = User.find_by_login(session[:cas_user])
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}"
msg = (should_expire_sessions?) ? t('login.session_will_expire', :hours => 1) : t('login.session_will_not_expire')
notify :notice, (t('login.successful_with_session_info') + msg)
cookies[:tracks_login] = { :value => @user.login, :expires => Time.now + 1.year, :secure => SITE_CONFIG['secure_cookies'] }
unless should_expire_sessions?
@user.remember_me
cookies[:auth_token] = { :value => @user.remember_token, :expires => @user.remember_token_expires_at, :secure => SITE_CONFIG['secure_cookies'] }
end
#redirect_back_or_home
else
notify :warning, "Sorry, no user by that CAS username exists (#{session[:cas_user]})"
notify :warning, t('login.cas_username_not_found', :username => session[:cas_user])
redirect_to signup_url ; return
end
else
notify :warning, result.message
end
redirect_back_or_home
redirect_back_or_home
end
@ -149,8 +161,8 @@ class LoginController < ApplicationController
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}"
msg = (should_expire_sessions?) ? t('login.session_will_expire', :hours => 1) : t('login.session_will_not_expire')
notify :notice, (t('login.successful_with_session_info') + msg)
cookies[:tracks_login] = { :value => @user.login, :expires => Time.now + 1.year, :secure => SITE_CONFIG['secure_cookies'] }
unless should_expire_sessions?
@user.remember_me
@ -158,7 +170,7 @@ class LoginController < ApplicationController
end
redirect_back_or_home
else
notify :warning, "Sorry, no user by that identity URL exists (#{identity_url})"
notify :warning, t('login.openid_identity_url_not_found', :identity_url => identity_url)
end
else
notify :warning, result.message

View file

@ -1,87 +1,72 @@
class NotesController < ApplicationController
def index
@all_notes = current_user.notes
@count = @all_notes.size
@page_title = "TRACKS::All notes"
respond_to do |format|
format.html
format.xml { render :xml => @all_notes.to_xml( :except => :user_id ) }
end
end
def show
@note = current_user.notes.find(params['id'])
@page_title = "TRACKS::Note " + @note.id.to_s
respond_to do |format|
format.html
format.m &render_note_mobile
end
end
def render_note_mobile
lambda do
render :action => 'note_mobile'
end
end
def create
note = current_user.notes.build
note.attributes = params["note"]
class NotesController < ApplicationController
saved = note.save
before_filter :set_source_view
def index
@all_notes = current_user.notes.all
@count = @all_notes.size
@page_title = "TRACKS::All notes"
@source_view = 'note_list'
respond_to do |format|
format.html
format.xml { render :xml => @all_notes.to_xml( :except => :user_id ) }
end
end
def show
@note = current_user.notes.find(params['id'])
@page_title = "TRACKS::Note " + @note.id.to_s
respond_to do |format|
format.html
format.m { render :action => 'note_mobile' }
end
end
def create
@note = current_user.notes.build
@note.attributes = params["note"]
@saved = @note.save
respond_to do |format|
format.js do
if note.save
render :partial => 'notes_summary', :object => note
else
render :text => ''
end
end
format.js
format.xml do
if saved
head :created, :location => note_url(note), :text => "new note with id #{note.id}"
if @saved
head :created, :location => note_url(@note), :text => "new note with id #{@note.id}"
else
render_failure note.errors.full_messages.join(', ')
render_failure @note.errors.full_messages.join(', ')
end
end
format.html do
render :text => 'unexpected request for html rendering'
end
end
end
def destroy
@note = current_user.notes.find(params['id'])
@note.destroy
respond_to do |format|
format.html
format.js do
@count = current_user.notes.size
render
end
end
# if note.destroy
# render :text => ''
# else
# notify :warning, "Couldn't delete note \"#{note.id}\""
# render :text => ''
# end
end
def update
note = current_user.notes.find(params['id'])
note.attributes = params["note"]
if note.save
render :partial => 'notes', :object => note
else
notify :warning, "Couldn't update note \"#{note.id}\""
render :text => ''
end
end
end
end
def update
@note = current_user.notes.find(params['id'])
@note.attributes = params["note"]
@saved = @note.save
respond_to do |format|
format.html
format.js { render }
end
end
def destroy
@note = current_user.notes.find(params['id'])
@note.destroy
respond_to do |format|
format.html
format.js { @down_count = current_user.notes.size }
end
end
protected
def set_source_view
@source_view = params['_source_view'] || 'note'
end
end

View file

@ -1,12 +1,13 @@
class PreferencesController < ApplicationController
def index
@page_title = "TRACKS::Preferences"
@prefs = prefs
@page_title = t('preferences.page_title')
@prefs = current_user.prefs
end
def edit
@page_title = "TRACKS::Edit Preferences"
@page_title = t('preferences.page_title_edit')
@prefs = current_user.prefs
end
def update

View file

@ -9,14 +9,16 @@ class ProjectsController < ApplicationController
def index
@source_view = params['_source_view'] || 'project_list'
@projects = current_user.projects
@new_project = current_user.projects.build
if params[:projects_and_actions]
projects_and_actions
else
@contexts = current_user.contexts
@contexts = current_user.contexts.all
init_not_done_counts(['project'])
if params[:only_active_with_no_next_actions]
@projects = current_user.projects.active.select { |p| count_undone_todos(p) == 0 }
else
@projects = current_user.projects.all
end
init_project_hidden_todo_counts(['project'])
respond_to do |format|
@ -26,7 +28,7 @@ class ProjectsController < ApplicationController
format.rss &render_rss_feed
format.atom &render_atom_feed
format.text &render_text_feed
format.autocomplete { render :text => for_autocomplete(@projects.reject(&:completed?), params[:q]) }
format.autocomplete { render :text => for_autocomplete(current_user.projects.uncompleted, params[:term]) }
end
end
end
@ -43,9 +45,9 @@ class ProjectsController < ApplicationController
def show
@max_completed = current_user.prefs.show_number_completed
init_data_for_sidebar unless mobile?
@page_title = "TRACKS::Project: #{@project.name}"
@page_title = t('projects.page_title', :project => @project.name)
@not_done = @project.not_done_todos_including_hidden
@not_done = @project.todos.active_or_hidden
@deferred = @project.deferred_todos
@pending = @project.pending_todos
@done = @project.todos.find_in_state(:all, :completed, :order => "todos.completed_at DESC", :limit => current_user.prefs.show_number_completed, :include => [:context])
@ -55,6 +57,8 @@ class ProjectsController < ApplicationController
@next_project = current_user.projects.next_from(@project)
@previous_project = current_user.projects.previous_from(@project)
@default_tags = @project.default_tags
@new_note = current_user.notes.new
@new_note.project_id = @project.id
respond_to do |format|
format.html
format.m &render_project_mobile
@ -73,6 +77,7 @@ class ProjectsController < ApplicationController
render_failure "Expected post format is valid xml like so: <request><project><name>project name</name></project></request>."
return
end
@project = current_user.projects.build
params_are_invalid = true
if (params['project'] || (params['request'] && params['request']['project']))
@ -81,9 +86,11 @@ class ProjectsController < ApplicationController
end
@go_to_project = params['go_to_project']
@saved = @project.save
@project_not_done_counts = { @project.id => 0 }
@active_projects_count = current_user.projects.active.count
@contexts = current_user.contexts
respond_to do |format|
format.js { @down_count = current_user.projects.size }
format.xml do
@ -95,6 +102,7 @@ class ProjectsController < ApplicationController
head :created, :location => project_url(@project), :text => @project.id
end
end
format.html {redirect_to :action => 'index'}
end
end
@ -119,18 +127,19 @@ class ProjectsController < ApplicationController
if boolean_param('wants_render')
if (@project.hidden?)
@project_project_hidden_todo_counts = Hash.new
@project_project_hidden_todo_counts[@project.id] = @project.reload().not_done_todos_including_hidden.count
@project_project_hidden_todo_counts[@project.id] = @project.reload().todos.active_or_hidden.count
else
@project_not_done_counts = Hash.new
@project_not_done_counts[@project.id] = @project.reload().not_done_todos_including_hidden.count
@project_not_done_counts[@project.id] = @project.reload().todos.active_or_hidden.count
end
@contexts = current_user.contexts
@active_projects_count = current_user.projects.active.count
@hidden_projects_count = current_user.projects.hidden.count
@completed_projects_count = current_user.projects.completed.count
update_state_counts
init_data_for_sidebar
render :template => 'projects/update.js.rjs'
render :template => 'projects/update.js.erb'
return
# TODO: are these params ever set? or is this dead code?
elsif boolean_param('update_status')
render :template => 'projects/update_status.js.rjs'
return
@ -151,10 +160,10 @@ class ProjectsController < ApplicationController
end
else
init_data_for_sidebar
render :template => 'projects/update.js.rjs'
render :template => 'projects/update.js.erb'
return
end
render :template => 'projects/update.js.rjs'
render :template => 'projects/update.js.erb'
end
def edit
@ -166,11 +175,12 @@ class ProjectsController < ApplicationController
def destroy
@project.recurring_todos.each {|rt| rt.remove_from_project!}
@project.destroy
@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.js {
@down_count = current_user.projects.size
update_state_counts
}
format.xml { render :text => "Deleted project #{@project.name}" }
end
end
@ -201,11 +211,20 @@ class ProjectsController < ApplicationController
end
protected
def update_state_counts
@active_projects_count = current_user.projects.active.count
@hidden_projects_count = current_user.projects.hidden.count
@completed_projects_count = current_user.projects.completed.count
@show_active_projects = @active_projects_count > 0
@show_hidden_projects = @hidden_projects_count > 0
@show_completed_projects = @completed_projects_count > 0
end
def render_projects_html
lambda do
@page_title = "TRACKS::List Projects"
@count = current_user.projects.size
@page_title = t('projects.list_projects')
@count = current_user.projects.count
@active_projects = current_user.projects.active
@hidden_projects = current_user.projects.hidden
@completed_projects = current_user.projects.completed
@ -230,10 +249,9 @@ class ProjectsController < ApplicationController
def render_project_mobile
lambda do
if @project.default_context.nil?
@project_default_context = "This project does not have a default context"
@project_default_context = t('projects.no_default_context')
else
@project_default_context = "The default context for this project is "+
@project.default_context.name
@project_default_context = t('projects.default_context', :context => @project.default_context.name)
end
cookies[:mobile_url]= {:value => request.request_uri, :secure => SITE_CONFIG['secure_cookies']}
@mobile_from_project = @project.id
@ -244,7 +262,8 @@ class ProjectsController < ApplicationController
def render_rss_feed
lambda do
render_rss_feed_for @projects, :feed => feed_options,
:item => { :title => :name, :description => lambda { |p| summary(p) } }
:title => :name,
:item => { :description => lambda { |p| summary(p) } }
end
end
@ -293,7 +312,7 @@ class ProjectsController < ApplicationController
project_description = ''
project_description += sanitize(markdown( project.description )) unless project.description.blank?
project_description += "<p>#{count_undone_todos_phrase(p)}. "
project_description += "Project is #{project.state}."
project_description += t('projects.project_state', :state => project.state)
project_description += "</p>"
project_description
end

View file

@ -6,15 +6,17 @@ class RecurringTodosController < ApplicationController
append_before_filter :get_recurring_todo_from_param, :only => [:destroy, :toggle_check, :toggle_star, :edit, :update]
def index
find_and_inactivate
@page_title = t('todos.recurring_actions_title')
find_and_inactivate
@recurring_todos = current_user.recurring_todos.active
@completed_recurring_todos = current_user.recurring_todos.completed
@no_recurring_todos = @recurring_todos.size == 0
@no_completed_recurring_todos = @completed_recurring_todos.size == 0
@count = @recurring_todos.size
@page_title = "TRACKS::Recurring Actions"
@count = @recurring_todos.size
@new_recurring_todo = RecurringTodo.new
end
def new
@ -103,23 +105,24 @@ class RecurringTodosController < ApplicationController
@recurring_todo.context_id = context.id
end
@recurring_saved = @recurring_todo.save
unless (@recurring_saved == false) || p.tag_list.blank?
@saved = @recurring_todo.save
unless (@saved == false) || p.tag_list.blank?
@recurring_todo.tag_with(p.tag_list)
@recurring_todo.tags.reload
end
if @recurring_saved
@message = "The recurring todo was saved"
if @saved
@status_message = "The recurring todo was saved"
@todo_saved = create_todo_from_recurring_todo(@recurring_todo).nil? == false
if @todo_saved
@message += " / created a new todo"
@status_message += " / created a new todo"
else
@message += " / did not create todo"
@status_message += " / did not create todo"
end
@count = current_user.recurring_todos.active.count
@down_count = current_user.recurring_todos.active.count
@new_recurring_todo = RecurringTodo.new
else
@message = "Error saving recurring todo"
@status_message = "Error saving recurring todo"
end
respond_to do |format|
@ -139,7 +142,10 @@ class RecurringTodosController < ApplicationController
# delete the recurring todo
@saved = @recurring_todo.destroy
@remaining = current_user.recurring_todos.count
# count remaining recurring todos
@active_remaining = current_user.recurring_todos.active.count
@completed_remaining = current_user.recurring_todos.completed.count
respond_to do |format|
@ -162,11 +168,12 @@ class RecurringTodosController < ApplicationController
def toggle_check
@saved = @recurring_todo.toggle_completion!
@count = current_user.recurring_todos.active.count
@remaining = @count
@down_count = current_user.recurring_todos.active.count
@active_remaining = @down_count
@completed_remaining = 0
if @recurring_todo.active?
@remaining = current_user.recurring_todos.completed.count
@completed_remaining = current_user.recurring_todos.completed.count
# from completed back to active -> check if there is an active todo
# current_user.todos.count(:all, {:conditions => ["state = ? AND recurring_todo_id = ?", 'active',params[:id]]})

10
app/controllers/stats_controller.rb Executable file → Normal file
View file

@ -376,7 +376,7 @@ class StatsController < ApplicationController
end
if size==pie_cutoff
@actions_per_context[size-1]['name']='(others)'
@actions_per_context[size-1]['name']=t('stats.other_actions_label')
@actions_per_context[size-1]['total']=0
@actions_per_context[size-1]['id']=-1
(size-1).upto @all_actions_per_context.size()-1 do |i|
@ -417,7 +417,7 @@ class StatsController < ApplicationController
end
if size==pie_cutoff
@actions_per_context[size-1]['name']='(others)'
@actions_per_context[size-1]['name']=t('stats.other_actions_label')
@actions_per_context[size-1]['total']=0
@actions_per_context[size-1]['id']=-1
(size-1).upto @all_actions_per_context.size()-1 do |i|
@ -565,7 +565,7 @@ class StatsController < ApplicationController
end
def show_selected_actions_from_chart
@page_title = "TRACKS::Action selection"
@page_title = t('stats.action_selection_title')
@count = 99
@source_view = 'stats'
@ -582,10 +582,10 @@ class StatsController < ApplicationController
week_to = week_from+1
@chart_name = "actions_visible_running_time_data"
@page_title = "Actions selected from week "
@page_title = t('stats.actions_selected_from_week')
@further = false
if params['id'] == 'avrt_end'
@page_title += week_from.to_s + " and further"
@page_title += week_from.to_s + t('stats.actions_further')
@further = true
else
@page_title += week_from.to_s + " - " + week_to.to_s + ""

File diff suppressed because it is too large Load diff

View file

@ -35,15 +35,15 @@ class UsersController < ApplicationController
end
if User.no_users_yet?
@page_title = "TRACKS::Sign up as the admin user"
@heading = "Welcome to TRACKS. To get started, please create an admin account:"
@page_title = t('users.new_user_title')
@heading = t('users.first_user_heading')
@user = get_new_user
elsif (@user && @user.is_admin?) || SITE_CONFIG['open_signups']
@page_title = "TRACKS::Sign up a new user"
@heading = "Sign up a new user:"
@page_title = t('users.new_user_title')
@heading = t('users.new_user_heading')
@user = get_new_user
else # all other situations (i.e. a non-admin is logged in, or no one is logged in, but we have some users)
@page_title = "TRACKS::No signups"
@page_title = t('users.no_signups_title')
@admin_email = User.find_admin.preference.admin_email
render :action => "nosignup", :layout => "login"
return
@ -66,7 +66,7 @@ class UsersController < ApplicationController
respond_to do |format|
format.html do
unless User.no_users_yet? || (@user && @user.is_admin?) || SITE_CONFIG['open_signups']
@page_title = "No signups"
@page_title = t('users.no_signups_title')
@admin_email = User.find_admin.preference.admin_email
render :action => "nosignup", :layout => "login"
return
@ -98,10 +98,10 @@ class UsersController < ApplicationController
user.is_admin = true if first_user_signing_up
if user.save
@user = User.authenticate(user.login, params['user']['password'])
@user.create_preference
@user.create_preference({:locale => I18n.locale})
@user.save
session['user_id'] = @user.id if first_user_signing_up
notify :notice, "Signup successful for user #{@user.login}."
notify :notice, t('users.signup_successful', :username => @user.login)
redirect_back_or_home
end
return
@ -121,7 +121,7 @@ class UsersController < ApplicationController
end
user.password_confirmation = params[:request][:password]
if user.save
render :text => "User created.", :status => 200
render :text => t('users.user_created'), :status => 200
else
render_failure user.errors.to_xml
end
@ -139,9 +139,9 @@ class UsersController < ApplicationController
respond_to do |format|
format.html do
if @saved
notify :notice, "Successfully deleted user #{@deleted_user.login}", 2.0
notify :notice, t('users.successfully_deleted_user', :username => @deleted_user.login), 2.0
else
notify :error, "Failed to delete user #{@deleted_user.login}", 2.0
notify :error, t('users.failed_to_delete_user', :username => @deleted_user.login), 2.0
end
redirect_to users_url
end
@ -152,12 +152,12 @@ class UsersController < ApplicationController
def change_password
@page_title = "TRACKS::Change password"
@page_title = t('users.change_password_title')
end
def update_password
@user.change_password(params[:updateuser][:password], params[:updateuser][:password_confirmation])
notify :notice, "Password updated."
notify :notice, t('users.password_updated')
redirect_to preferences_path
rescue Exception => error
notify :error, error.message
@ -165,7 +165,7 @@ class UsersController < ApplicationController
end
def change_auth_type
@page_title = "TRACKS::Change authentication type"
@page_title = t('users.change_auth_type_title')
end
def update_auth_type
@ -177,10 +177,10 @@ class UsersController < ApplicationController
@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."
notify :notice, t('users.openid_url_verified', :url => identity_url)
else
debugger
notify :warning, "You have successfully verified #{identity_url} as your identity but there was a problem saving your authentication preferences."
notify :warning, t('users.openid_ok_pref_failed', :url => identity_url)
end
redirect_to preferences_path
else
@ -192,10 +192,10 @@ class UsersController < ApplicationController
end
@user.auth_type = params[:user][:auth_type]
if @user.save
notify :notice, "Authentication type updated."
notify :notice, t('users.auth_type_updated')
redirect_to preferences_path
else
notify :warning, "There was a problem updating your authentication type: #{ @user.errors.full_messages.join(', ')}"
notify :warning, t('users.auth_type_update_error', :error_messages => @user.errors.full_messages.join(', '))
redirect_to :action => 'change_auth_type'
end
end
@ -203,7 +203,7 @@ class UsersController < ApplicationController
def refresh_token
@user.generate_token
@user.save!
notify :notice, "New token successfully generated"
notify :notice, t('users.new_token_generated')
redirect_to preferences_path
end

View file

@ -104,11 +104,29 @@ module ApplicationHelper
end
def link_to_context(context, descriptor = sanitize(context.name))
link_to( descriptor, context_path(context), :title => "View context: #{context.name}" )
link_to( descriptor, context, :title => "View context: #{context.name}" )
end
def link_to_project(project, descriptor = sanitize(project.name))
link_to( descriptor, project_path(project), :title => "View project: #{project.name}" )
link_to( descriptor, project, :title => "View project: #{project.name}" )
end
def link_to_edit_project (project, descriptor = sanitize(project.name))
link_to(descriptor,
url_for({:controller => 'projects', :action => 'edit', :id => project.id}),
{:id => "link_edit_#{dom_id(project)}", :class => "project_edit_settings"})
end
def link_to_edit_context (context, descriptor = sanitize(context.name))
link_to(descriptor,
url_for({:controller => 'contexts', :action => 'edit', :id => context.id}),
{:id => "link_edit_#{dom_id(context)}", :class => "context_edit_settings"})
end
def link_to_edit_note (note, descriptor = sanitize(note.id.to_s))
link_to(descriptor,
url_for({:controller => 'notes', :action => 'edit', :id => note.id}),
{:id => "link_edit_#{dom_id(note)}", :class => "note_edit_settings"})
end
def link_to_project_mobile(project, accesskey, descriptor = sanitize(project.name))
@ -128,16 +146,7 @@ module ApplicationHelper
end
def render_flash
render :partial => 'shared/flash', :locals => { :flash => flash }
end
# Display a flash message in RJS templates Usage: page.notify :warning, "This
# is the message", 5.0 Puts the message into a flash of type 'warning', fades
# over 5 secs
def notify(type, message, fade_duration)
type = type.to_s # symbol to string
page.replace 'flash', "<h4 id='flash' class='alert #{type}'>#{message}</h4>"
page.visual_effect :fade, 'flash', :duration => fade_duration
render :partial => 'shared/flash', :object => flash
end
def recurrence_time_span(rt)
@ -213,4 +222,41 @@ module ApplicationHelper
note = Sanitize.clean(note, Sanitize::Config::RELAXED)
return note
end
def sidebar_html_for_titled_list (list, title)
return content_tag(:h3, title+" (#{list.length})") +
content_tag(:ul, sidebar_html_for_list(list))
end
def sidebar_html_for_list(list)
if list.empty?
return content_tag(:li, t('sidebar.list_empty'))
else
return list.inject("") do |html, item|
link = (item.class == "Project") ? link_to_project( item ) : link_to_context(item)
html << content_tag(:li, link + " (" + count_undone_todos_phrase(item,"actions")+")")
end
end
end
def generate_i18n_strings
js = ""
js << "i18n = new Array();\n"
%w{
shared.toggle_multi shared.toggle_multi_title
shared.hide_form shared.hide_action_form_title
shared.toggle_single shared.toggle_single_title
projects.hide_form projects.hide_form_title
projects.show_form projects.show_form_title
contexts.hide_form contexts.hide_form_title
contexts.show_form contexts.show_form_title
contexts.new_context_pre contexts.new_context_post
common.cancel common.ok
common.ajaxError
}.each do |s|
js << "i18n['#{s}'] = '#{ t(s).gsub(/'/, "\\\\'") }';\n"
end
return js
end
end

View file

@ -9,4 +9,17 @@ module ContextsHelper
}
end
def link_to_delete_context(context, descriptor = sanitize(context.name))
link_to(
descriptor,
context_path(context, :format => 'js'),
{
:id => "delete_context_#{context.id}",
:class => "delete_context_button",
:x_confirm_message => t('contexts.delete_context_confirmation', :name => context.name),
:title => t('contexts.delete_context_title')
}
)
end
end

View file

@ -15,7 +15,25 @@ module FeedlistHelper
linkoptions = merge_hashes( {:format => 'ics'}, user_token_hash, options)
link_to('<span class="feed">iCal</span>', linkoptions, :title => "iCal feed" )
end
def feed_links(feeds, link_options, title)
space = " "
html = ""
html << rss_formatted_link(link_options)+space if feeds.include?(:rss)
html << text_formatted_link(link_options)+space if feeds.include?(:txt)
html << ical_formatted_link(link_options)+space if feeds.include?(:ical)
html << title
return html
end
def all_feed_links_for_project(project)
feed_links([:rss, :txt, :ical], { :controller=> 'todos', :action => 'index', :project_id => project.to_param }, content_tag(:strong, project.name))
end
def all_feed_links_for_context(context)
feed_links([:rss, :txt, :ical], { :controller=> 'todos', :action => 'index', :context_id => context.to_param }, content_tag(:strong, context.name))
end
protected
def merge_hashes(*hashes)

View file

@ -6,4 +6,14 @@ module NotesHelper
def rendered_note(note)
sanitize(textilize_without_paragraph(note.body))
end
def link_to_delete_note(note, descriptor = sanitize(note.id.to_s))
link_to(
descriptor,
note_path(note, :format => 'js'),
{:id => "delete_note_#{note.id}", :class => "delete_note_button",
:title => t('notes.delete_note_title', :id => note.id), :x_confirm_message => t('notes.delete_note_confirm', :id => note.id)}
)
end
end

View file

@ -44,5 +44,18 @@ module ProjectsHelper
end
html
end
def link_to_delete_project(project, descriptor = sanitize(project.name))
link_to(
descriptor,
project_path(project, :format => 'js'),
{
:id => "delete_project_#{project.id}",
:class => "delete_project_button",
:x_confirm_message => t('projects.delete_project_confirmation', :name => project.name),
:title => t('projects.delete_project_title')
}
)
end
end

View file

@ -13,20 +13,20 @@ module RecurringTodosHelper
def recurring_todo_remote_delete_icon
link_to( image_tag_for_delete,
recurring_todo_path(@recurring_todo), :id => "delete_icon_"+@recurring_todo.id.to_s,
:class => "icon delete_icon", :title => "delete the recurring action '#{@recurring_todo.description}'")
:class => "icon delete_icon", :title => t('todos.delete_recurring_action_title'), :x_confirm_message => t('todos.delete_recurring_action_confirm', :description => @recurring_todo.description))
end
def recurring_todo_remote_star_icon
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}'")
toggle_star_recurring_todo_path(@recurring_todo), :id => "star_icon_"+@recurring_todo.id.to_s,
:class => "icon star_item", :title => t('todos.star_action'))
end
def recurring_todo_remote_edit_icon
if !@recurring_todo.completed?
str = link_to( image_tag_for_edit(@recurring_todo),
edit_recurring_todo_path(@recurring_todo),
:class => "icon edit_icon")
:class => "icon edit_icon", :id => "link_edit_recurring_todo_#{@recurring_todo.id}")
else
str = '<a class="icon">' + image_tag("blank.png") + "</a> "
end
@ -34,17 +34,16 @@ module RecurringTodosHelper
end
def recurring_todo_remote_toggle_checkbox
str = check_box_tag('item_id', toggle_check_recurring_todo_path(@recurring_todo), @recurring_todo.completed?, :class => 'item-checkbox')
str
return check_box_tag("check_#{@recurring_todo.id}", toggle_check_recurring_todo_path(@recurring_todo), @recurring_todo.completed?, :class => 'item-checkbox')
end
private
def image_tag_for_delete
image_tag("blank.png", :title =>"Delete action", :class=>"delete_item")
image_tag("blank.png", :title =>t('todos.delete_action'), :class=>"delete_item")
end
def image_tag_for_edit(todo)
image_tag("blank.png", :title =>"Edit action", :class=>"edit_item", :id=> dom_id(todo, 'edit_icon'))
image_tag("blank.png", :title =>t('todos.edit_action'), :class=>"edit_item", :id=> dom_id(todo, 'edit_icon'))
end
end

View file

@ -1,3 +1,2 @@
module SearchHelper
end
module SearchHelper
end

View file

@ -1,66 +1,50 @@
module TodosHelper
# #require 'users_controller' Counts the number of incomplete items in the
# specified context
#
def count_items(context)
count = Todo.find_all("done=0 AND context_id=#{context.id}").length
def remote_star_icon(todo=@todo)
link_to( image_tag_for_star(todo),
toggle_star_todo_path(todo),
:class => "icon star_item", :title => t('todos.star_action_with_description', :description => todo.description))
end
def form_remote_tag_edit_todo( &block )
form_remote_tag(
:url => todo_path(@todo),
:loading => "$('#submit_todo_#{@todo.id}').block({message: null})",
:html => {
:method => :put,
:id => dom_id(@todo, 'form'),
:class => dom_id(@todo, 'form') + " inline-form edit_todo_form" },
&block )
end
def remote_star_icon
link_to( image_tag_for_star(@todo),
toggle_star_todo_path(@todo),
:class => "icon star_item", :title => "star the action '#{@todo.description}'")
end
def remote_edit_button
def remote_edit_button(todo=@todo)
link_to(
image_tag("blank.png", :alt => "Edit", :align => "absmiddle", :id => 'edit_icon_todo_'+@todo.id.to_s, :class => 'edit_item'),
{:controller => 'todos', :action => 'edit', :id => @todo.id},
image_tag("blank.png", :alt => t('todos.edit'), :align => "absmiddle", :id => 'edit_icon_todo_'+todo.id.to_s, :class => 'edit_item'),
{:controller => 'todos', :action => 'edit', :id => todo.id},
:class => "icon edit_item",
:title => "Edit the action '#{@todo.description}'")
:title => t('todos.edit_action_with_description', :description => todo.description))
end
def remote_delete_menu_item(parameters, todo)
return link_to_remote(
image_tag("delete_off.png", :mouseover => "delete_on.png", :alt => "Delete", :align => "absmiddle")+" Delete",
:url => {:controller => 'todos', :action => 'destroy', :id => todo.id},
:method => 'delete',
:with => "'#{parameters}'",
:before => todo_start_waiting_js(todo),
:complete => todo_stop_waiting_js(todo),
:confirm => "Are you sure that you want to delete the action '#{todo.description}'?")
def remote_delete_menu_item(todo)
return link_to(
image_tag("delete_off.png", :mouseover => "delete_on.png", :alt => t('todos.delete'), :align => "absmiddle")+" "+t('todos.delete'),
{:controller => 'todos', :action => 'destroy', :id => todo.id},
:class => "icon_delete_item",
:id => "delete_#{dom_id(todo)}",
:x_confirm_message => t('todos.confirm_delete', :description => todo.description),
:title => t('todos.delete_action'));
end
def remote_defer_menu_item(days, todo)
url = {:controller => 'todos', :action => 'defer', :id => todo.id, :days => days,
:_source_view => (@source_view.underscore.gsub(/\s+/,'_') rescue "")}
url[:_tag_name] = @tag_name if @source_view == 'tag'
futuredate = (@todo.show_from || @todo.user.date) + days.days
if @todo.due && futuredate > @todo.due
return link_to_function(
image_tag("defer_#{days}_off.png", :mouseover => "defer_#{days}.png", :alt => "Defer #{pluralize(days, "day")}", :align => "absmiddle")+" Defer #{pluralize(days, "day")}",
"alert('Defer date is after due date. Please edit and adjust due date before deferring.')"
)
else
return link_to_remote(
image_tag("defer_#{days}_off.png", :mouseover => "defer_#{days}.png", :alt => "Defer #{pluralize(days, "day")}", :align => "absmiddle")+" Defer #{pluralize(days, "day")}",
:url => url,
:before => todo_start_waiting_js(todo),
:complete => todo_stop_waiting_js(todo))
futuredate = (todo.show_from || todo.user.date) + days.days
options = {:x_defer_alert => false, :class => "icon_defer_item" }
if todo.due && futuredate > todo.due
options[:x_defer_alert] = true
options[:x_defer_date_after_due_date] = t('todos.defer_date_after_due_date')
end
return link_to(image_tag_for_defer(days), url, options)
end
def remote_delete_dependency(todo, predecessor)
link_to(
image_tag("blank.png", :title => t('todos.remove_dependency'), :align => "absmiddle", :class => "delete_item"),
url_for({:controller => 'todos', :action => 'remove_predecessor', :id => todo.id}),
{:class => "delete_dependency_button", :x_predecessors_id => predecessor.id}
)
end
def remote_promote_to_project_menu_item(todo)
@ -68,19 +52,31 @@ module TodosHelper
:_source_view => (@source_view.underscore.gsub(/\s+/,'_') rescue "")}
url[:_tag_name] = @tag_name if @source_view == 'tag'
return link_to(image_tag("to_project_off.png", :align => "absmiddle")+" Make project", url)
end
def todo_start_waiting_js(todo)
return "$('#ul#{dom_id(todo)}').css('visibility', 'hidden'); $('##{dom_id(todo)}').block({message: null})"
return link_to(image_tag("to_project_off.png", :align => "absmiddle")+" " + t('todos.convert_to_project'), url)
end
def image_tag_for_defer(days)
image_tag("defer_#{days}_off.png", :mouseover => "defer_#{days}.png", :alt => t('todos.defer_x_days', :count => days), :align => "absmiddle")+" "+t('todos.defer_x_days', :count => days)
end
# waiting stuff can be deleted after migration of defer and dependencies
def successor_start_waiting_js(successor)
return "$('##{dom_id(successor, "successor")}').block({message: null})"
end
def todo_stop_waiting_js(todo)
return "$('##{dom_id(todo)}').unblock();enable_rich_interaction();"
def collapsed_notes_image(todo)
link = link_to(image_tag( 'blank.png', :width=>'16', :height=>'16', :border=>'0' ), "#", {:class => 'show_notes', :title => 'Show notes'})
notes = content_tag(:div, {:class => "todo_notes", :id => dom_id(todo, 'notes'), :style => "display:none"}) { format_note(todo.notes) }
return link+notes
end
def collapsed_successors_image(todo)
link = link_to(image_tag( 'blank.png', :width=>'16', :height=>'16', :border=>'0' ), "#", {:class => 'show_successors', :title => 'Show successors'})
successors = content_tag(:div, {:class => "todo_successors", :id => dom_id(todo, 'successors'), :style => "display:none"}) do
render :partial => "todos/successor", :collection => todo.pending_successors,
:locals => { :parent_container_type => parent_container_type, :suppress_dependencies => true, :predecessor => todo }
end
return link+successors
end
def image_tag_for_recurring_todo(todo)
@ -89,53 +85,52 @@ module TodosHelper
{:controller => "recurring_todos", :action => "index"},
:class => "recurring_icon", :title => recurrence_pattern_as_text(todo.recurring_todo))
end
def remote_toggle_checkbox
check_box_tag('item_id', toggle_check_todo_path(@todo), @todo.completed?, :class => 'item-checkbox',
:title => @todo.pending? ? 'Blocked by ' + @todo.uncompleted_predecessors.map(&:description).join(', ') : "", :readonly => @todo.pending?)
def remote_toggle_checkbox(todo=@todo)
check_box_tag('item_id', toggle_check_todo_path(todo), todo.completed?, :class => 'item-checkbox',
:title => todo.pending? ? t('todos.blocked_by', :predecessors => todo.uncompleted_predecessors.map(&:description).join(', ')) : "", :readonly => todo.pending?)
end
def date_span
if @todo.completed?
"<span class=\"grey\">#{format_date( @todo.completed_at )}</span>"
elsif @todo.pending?
"<a title='Depends on: #{@todo.uncompleted_predecessors.map(&:description).join(', ')}'><span class=\"orange\">Pending</span></a> "
elsif @todo.deferred?
show_date( @todo.show_from )
def date_span(todo=@todo)
if todo.completed?
"<span class=\"grey\">#{format_date( todo.completed_at )}</span>"
elsif todo.pending?
"<a title='#{t('todos.depends_on')}: #{todo.uncompleted_predecessors.map(&:description).join(', ')}'><span class=\"orange\">#{t('todos.pending')}</span></a> "
elsif todo.deferred?
show_date( todo.show_from )
else
due_date( @todo.due )
due_date( todo.due )
end
end
def successors_span
unless @todo.pending_successors.empty?
pending_count = @todo.pending_successors.length
title = "Has #{pluralize(pending_count, 'pending action')}: #{@todo.pending_successors.map(&:description).join(', ')}"
def successors_span(todo=@todo)
unless todo.pending_successors.empty?
pending_count = todo.pending_successors.length
title = "#{t('todos.has_x_pending', :count => pending_count)}: #{todo.pending_successors.map(&:description).join(', ')}"
image_tag( 'successor_off.png', :width=>'10', :height=>'16', :border=>'0', :title => title )
end
end
def grip_span
unless @todo.completed?
def grip_span(todo=@todo)
unless todo.completed?
image_tag('grip.png', :width => '7', :height => '16', :border => '0',
:title => 'Drag onto another action to make it depend on that action',
:title => t('todos.drag_action_title'),
:class => 'grip')
end
end
def tag_list_text
@todo.tags.collect{|t| t.name}.join(', ')
def tag_list_text(todo=@todo)
todo.tags.collect{|t| t.name}.join(', ')
end
def tag_list
tags_except_starred = @todo.tags.reject{|t| t.name == Todo::STARRED_TAG_NAME}
def tag_list(todo=@todo)
tags_except_starred = todo.tags.reject{|t| t.name == Todo::STARRED_TAG_NAME}
tag_list = tags_except_starred.collect{|t| "<span class=\"tag #{t.name.gsub(' ','-')}\">" + link_to(t.name, :controller => "todos", :action => "tag", :id => t.name) + "</span>"}.join('')
"<span class='tags'>#{tag_list}</span>"
end
def tag_list_mobile
tags_except_starred = @todo.tags.reject{|t| t.name == Todo::STARRED_TAG_NAME}
def tag_list_mobile(todo=@todo)
tags_except_starred = todo.tags.reject{|t| t.name == Todo::STARRED_TAG_NAME}
# removed the link. TODO: add link to mobile view of tagged actions
tag_list = tags_except_starred.collect{|t|
"<span class=\"tag\">" +
@ -144,30 +139,30 @@ module TodosHelper
if tag_list.empty? then "" else "<span class=\"tags\">#{tag_list}</span>" end
end
def predecessor_list_text
@todo.predecessors.map{|t| t.specification}.join(', ')
def predecessor_list_text(todo=@todo)
todo.predecessors.map{|t| t.specification}.join(', ')
end
def deferred_due_date
if @todo.deferred? && @todo.due
"(action due on #{format_date(@todo.due)})"
def deferred_due_date(todo=@todo)
if todo.deferred? && todo.due
t('todos.action_due_on', :date => format_date(todo.due))
end
end
def project_and_context_links(parent_container_type, opts = {})
def project_and_context_links(todo, parent_container_type, opts = {})
str = ''
if @todo.completed?
str += @todo.context.name unless opts[:suppress_context]
should_suppress_project = opts[:suppress_project] || @todo.project.nil?
if todo.completed?
str += todo.context.name unless opts[:suppress_context]
should_suppress_project = opts[:suppress_project] || todo.project.nil?
str += ", " unless str.blank? || should_suppress_project
str += @todo.project.name unless should_suppress_project
str += todo.project.name unless should_suppress_project
str = "(#{str})" unless str.blank?
else
if (['project', 'tag', 'stats', 'search'].include?(parent_container_type))
str << item_link_to_context( @todo )
str << item_link_to_context( todo )
end
if (['context', 'tickler', 'tag', 'stats', 'search'].include?(parent_container_type)) && @todo.project_id
str << item_link_to_project( @todo )
if (['context', 'tickler', 'tag', 'stats', 'search'].include?(parent_container_type)) && todo.project_id
str << item_link_to_project( todo )
end
end
return str
@ -207,66 +202,67 @@ module TodosHelper
case days
# overdue or due very soon! sound the alarm!
when -1000..-1
"<a title=\"" + format_date(d) + "\"><span class=\"red\">Scheduled to show " + (days * -1).to_s + " days ago</span></a> "
"<a title=\"" + format_date(d) + "\"><span class=\"red\">#{t('todos.scheduled_overdue', :days => (days * -1).to_s)}</span></a> "
when 0
"<a title=\"" + format_date(d) + "\"><span class=\"amber\">Show Today</span></a> "
"<a title=\"" + format_date(d) + "\"><span class=\"amber\">#{t('todos.show_today')}</span></a> "
when 1
"<a title=\"" + format_date(d) + "\"><span class=\"amber\">Show Tomorrow</span></a> "
"<a title=\"" + format_date(d) + "\"><span class=\"amber\">#{t('todos.show_tomorrow')}</span></a> "
# due 2-7 days away
when 2..7
if prefs.due_style == Preference.due_styles[:due_on]
"<a title=\"" + format_date(d) + "\"><span class=\"orange\">Show on " + d.strftime("%A") + "</span></a> "
"<a title=\"" + format_date(d) + "\"><span class=\"orange\">#{t('todos.show_on_date', :date => d.strftime("%A"))}</span></a> "
else
"<a title=\"" + format_date(d) + "\"><span class=\"orange\">Show in " + days.to_s + " days</span></a> "
"<a title=\"" + format_date(d) + "\"><span class=\"orange\">#{t('todos.show_in_days', :days => days.to_s)}</span></a> "
end
# more than a week away - relax
else
"<a title=\"" + format_date(d) + "\"><span class=\"green\">Show in " + days.to_s + " days</span></a> "
"<a title=\"" + format_date(d) + "\"><span class=\"green\">#{t('todos.show_in_days', :days => days.to_s)}</span></a> "
end
end
def item_container_id (todo)
if todo.deferred? or todo.pending?
return "tickleritems"
elsif source_view_is :project
return "p#{todo.project_id}items"
def should_show_new_item
source_view do |page|
page.todo { return !@todo.hidden? }
page.deferred { return @todo.deferred? || @todo.pending? }
page.context {
logger.debug "ci=#{@todo.context_id} dci=#{@default_context.id} th=#{@todo.hidden?} tch=#{@todo.context.hidden?}"
return @todo.context_id==@default_context.id && ( (@todo.hidden? && @todo.context.hidden?) || (!@todo.hidden?) )
}
page.tag {
return ( (@todo.pending? && @todo.has_tag?(@tag_name)) ||
(@todo.has_tag?(@tag_name)) ||
(@todo.starred? && @tag_name == Todo::STARRED_TAG_NAME)
)
}
page.project {
return (@todo.active? && @todo.project && @todo.project.id == @default_project.id) ||
(@todo.project.hidden? && @todo.project_hidden?) || @todo.deferred? || @todo.pending?
}
end
return "c#{todo.context_id}items"
return false
end
def should_show_new_item
def should_make_context_visible
return @todo.active? && (!@todo.hidden? && !source_view_is(:project) )
end
unless @todo.project.nil?
# do not show new actions that were added to hidden or completed projects
# on home page and context page
return false if source_view_is(:todo) && (@todo.project.hidden? || @todo.project.completed?)
return false if source_view_is(:context) && (@todo.project.hidden? || @todo.project.completed?)
end
return false if (source_view_is(:tag) && !@todo.tags.include?(@tag_name))
return true if source_view_is(:deferred) && @todo.deferred?
return true if source_view_is(:project) && @todo.project.hidden? && @todo.project_hidden?
return true if source_view_is(:project) && @todo.deferred?
return true if !source_view_is(:deferred) && @todo.active?
return true if source_view_is(:project) && @todo.pending?
return true if source_view_is(:tag) && @todo.pending?
return false
def should_add_new_context
return @new_context_created && !source_view_is(:project)
end
def parent_container_type
return 'tickler' if source_view_is :deferred
return 'project' if source_view_is :project
return 'stats' if source_view_is :stats
return 'tag' if source_view_is :tag
return 'context'
end
def empty_container_msg_div_id
todo = @todo || @successor
return "tickler-empty-nd" if source_view_is_one_of(:project, :tag) && todo.deferred?
return "p#{todo.project_id}empty-nd" if source_view_is :project
return "c#{todo.context_id}empty-nd"
def todo_container_is_empty
default_container_empty = ( @down_count == 0 )
deferred_container_empty = ( @todo.deferred? && @remaining_deferred_count == 0)
return default_container_empty || deferred_container_empty
end
def default_contexts_for_autocomplete
@ -280,7 +276,7 @@ module TodosHelper
end
def format_ical_notes(notes)
unless notes.blank?
unless notes.nil? || notes.blank?
split_notes = notes.split(/\n/)
joined_notes = split_notes.join("\\n")
end
@ -295,16 +291,128 @@ module TodosHelper
def date_field_tag(name, id, value = nil, options = {})
text_field_tag name, value, {"size" => 12, "id" => id, "class" => "Date", "onfocus" => "Calendar.setup", "autocomplete" => "off"}.update(options.stringify_keys)
end
def update_needs_to_hide_context
return (@remaining_in_context == 0 && (@todo_hidden_state_changed && @todo.hidden?)) ||
(@remaining_in_context == 0 && @todo_was_deferred_from_active_state) ||
(@remaining_in_context == 0 && @todo.completed? && !(@original_item_was_deferred || @original_item_was_hidden)) if source_view_is(:tag)
return false if source_view_is(:project)
return (@remaining_in_context == 0) && !source_view_is(:context)
end
def update_needs_to_remove_todo_from_container
source_view do |page|
page.context { return @context_changed || @todo.deferred? || @todo.pending? }
page.project { return @todo_deferred_state_changed || @todo_pending_state_changed }
page.deferred { return @context_changed || !(@todo.deferred? || @todo.pending?) }
page.calendar { return @due_date_changed || !@todo.due }
page.stats { return @todo.completed? }
page.tag { return (@context_changed && !@todo.hidden?) || @tag_was_removed || @todo_hidden_state_changed || @todo_deferred_state_changed }
page.todo { return @context_changed || @todo.hidden? || @todo.deferred? || @todo.pending?}
end
return false
end
def replace_with_updated_todo
source_view do |page|
page.context { return !update_needs_to_remove_todo_from_container }
page.project { return !update_needs_to_remove_todo_from_container }
page.deferred { return !@context_changed && (@todo.deferred? || @todo.pending?) }
page.calendar { return !@due_date_changed && @todo.due }
page.stats { return !@todo.completed? }
page.tag { return !update_needs_to_remove_todo_from_container && !@tag_was_removed }
page.todo { return !update_needs_to_remove_todo_from_container }
end
return false
end
def append_updated_todo
source_view do |page|
page.context { return false }
page.project { return @todo_deferred_state_changed || @todo_pending_state_changed }
page.deferred { return @context_changed && (@todo.deferred? || @todo.pending?) }
page.calendar { return @due_date_changed && @todo.due }
page.stats { return false }
page.tag { return update_needs_to_remove_todo_from_container && !@tag_was_removed}
page.todo { return @context_changed && !(@todo.deferred? || @todo.pending? || @todo.hidden?) }
end
return false
end
def item_container_id (todo)
return "hiddenitems" if source_view_is(:tag) && todo.hidden?
return "c#{todo.context_id}items" if source_view_is :deferred
return @new_due_id if source_view_is :calendar
return "tickleritems" if !source_view_is(:todo) && (todo.deferred? || todo.pending?)
return "completed_containeritems" if todo.completed?
return "p#{todo.project_id}items" if source_view_is :project
return "c#{todo.context_id}items"
end
def empty_container_msg_div_id(todo = @todo || @successor)
raise Exception.new, "no @todo or @successor set" if !todo
source_view do |page|
page.project {
return "tickler-empty-nd" if @todo_was_deferred_from_active_state || @todo_was_blocked_from_active_state
return "p#{todo.project_id}empty-nd"
}
page.tag {
return "tickler-empty-nd" if @todo_was_deferred_from_active_state
return "hidden-empty-nd" if @todo.hidden?
return "c#{todo.context_id}empty-nd"
}
page.calendar {
return "empty_#{@new_due_id}"
}
end
return "c#{todo.context_id}empty-nd"
end
def show_empty_message_in_source_container
container_id = ""
source_view do |page|
page.project {
container_id = "p#{@original_item_project_id}empty-nd" if @remaining_in_context == 0
container_id = "tickler-empty-nd" if (
( (@todo_was_activated_from_deferred_state || @todo_was_activated_from_pending_state) && @remaining_deferred_or_pending_count == 0) ||
(@original_item_was_deferred && @remaining_deferred_or_pending_count == 0 && @todo.completed?) )
container_id = "empty-d" if @completed_count && @completed_count == 0 && !@todo.completed?
}
page.deferred { container_id = "c#{@original_item_context_id}empty-nd" if @remaining_in_context == 0 }
page.calendar { container_id = "empty_#{@original_item_due_id}" if @old_due_empty }
page.tag {
container_id = "hidden-empty-nd" if (@remaining_hidden_count == 0 && !@todo.hidden? && @todo_hidden_state_changed) ||
(@remaining_hidden_count == 0 && @todo.completed? && @original_item_was_hidden)
container_id = "tickler-empty-nd" if (@todo_was_activated_from_deferred_state && @remaining_deferred_or_pending_count == 0) ||
(@original_item_was_deferred && @remaining_deferred_or_pending_count == 0 && @todo.completed?)
container_id = "empty-d" if @completed_count && @completed_count == 0 && !@todo.completed?
}
page.context { container_id = "c#{@original_item_context_id}empty-nd" if @remaining_in_context == 0 }
page.todo { container_id = "c#{@original_item_context_id}empty-nd" if @remaining_in_context == 0 }
end
return container_id.blank? ? "" : "$(\"##{container_id}\").slideDown(100);"
end
def render_animation(animation)
html = ""
animation.each do |step|
unless step.blank?
html += step + "({ go: function() {\r\n"
end
end
html += "}}) " * animation.count
return html
end
private
def image_tag_for_star(todo)
class_str = todo.starred? ? "starred_todo" : "unstarred_todo"
image_tag("blank.png", :title =>"Star action", :class => class_str)
image_tag("blank.png", :title =>t('todos.star_action'), :class => class_str, :id => "star_img_"+todo.id.to_s)
end
def auto_complete_result2(entries, phrase = nil)
return entries.map{|e| e.specification()}.join("\n") rescue ''
end
end

View file

@ -1,2 +1,12 @@
module UsersHelper
def remote_delete_user(user)
return link_to(
image_tag("blank.png", :title =>t('users.destroy_user'), :class=>"delete_item"),
url_for({:controller => 'users', :action => 'destroy', :id => user.id}),
{:id => "delete_user_#{user.id}",
:class => "delete_user_button",
:title => t('users.destroy_user'),
:x_confirm_message => t('users.destroy_confirmation', :login => user.login)
})
end
end

View file

@ -6,16 +6,6 @@ class Preference < ActiveRecord::Base
{ :due_in_n_days => 0, :due_on => 1}
end
def self.day_number_to_name_map
{ 0 => "Sunday",
1 => "Monday",
2 => "Tuesday",
3 => "Wednesday",
4 => "Thursday",
5 => "Friday",
6 => "Saturday"}
end
def hide_completed_actions?
return show_number_completed == 0
end

View file

@ -1,15 +1,12 @@
class Project < ActiveRecord::Base
has_many :todos, :dependent => :delete_all, :include => [:context,:tags]
has_many :todos, :dependent => :delete_all
# TODO: remove these scopes. Can be replaced by the named scopes on the todo relation
has_many :not_done_todos,
:include => [:context,:tags,:project],
:class_name => 'Todo',
:order => "todos.due IS NULL, todos.due ASC, todos.created_at ASC",
:conditions => ["todos.state = ?", 'active']
has_many :not_done_todos_including_hidden,
:include => [:context,:tags,:project],
:class_name => 'Todo',
:order => "todos.due IS NULL, todos.due ASC, todos.created_at ASC",
:conditions => ["(todos.state = ? OR todos.state = ?)", 'active', 'project_hidden']
has_many :done_todos,
:include => [:context,:tags,:project],
:class_name => 'Todo',
@ -35,11 +32,12 @@ class Project < ActiveRecord::Base
named_scope :active, :conditions => { :state => 'active' }
named_scope :hidden, :conditions => { :state => 'hidden' }
named_scope :completed, :conditions => { :state => 'completed'}
named_scope :uncompleted, :conditions => ["NOT 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"
validates_uniqueness_of :name, :message => "already exists", :scope =>"user_id"
validates_does_not_contain :name, :string => ',', :message => "cannot contain the comma (',') character"
validates_presence_of :name
validates_length_of :name, :maximum => 255
validates_uniqueness_of :name, :scope => "user_id"
validates_does_not_contain :name, :string => ','
acts_as_list :scope => 'user_id = #{user_id} AND state = \'#{state}\''
acts_as_state_machine :initial => :active, :column => 'state'
@ -71,8 +69,8 @@ class Project < ActiveRecord::Base
def self.feed_options(user)
{
:title => 'Tracks Projects',
:description => "Lists all the projects for #{user.display_name}"
:title => I18n.t('models.project.feed_title'),
:description => I18n.t('models.project.feed_description', :username => user.display_name)
}
end

View file

@ -10,27 +10,40 @@ class Todo < ActiveRecord::Base
has_many :predecessors, :through => :successor_dependencies
has_many :successors, :through => :predecessor_dependencies
has_many :uncompleted_predecessors, :through => :successor_dependencies,
:source => :predecessor, :conditions => ['NOT (state = ?)', 'completed']
:source => :predecessor, :conditions => ['NOT (todos.state = ?)', 'completed']
has_many :pending_successors, :through => :predecessor_dependencies,
:source => :successor, :conditions => ['state = ?', 'pending']
:source => :successor, :conditions => ['todos.state = ?', 'pending']
after_save :save_predecessors
named_scope :active, :conditions => { :state => 'active' }
named_scope :active_or_hidden, :conditions => ["todos.state = ? OR todos.state = ?", 'active', 'project_hidden']
named_scope :not_completed, :conditions => ['NOT (todos.state = ? )', 'completed']
named_scope :completed, :conditions => ["NOT completed_at IS NULL"]
named_scope :completed, :conditions => ["NOT todos.completed_at IS NULL"]
named_scope :are_due, :conditions => ['NOT (todos.due IS NULL)']
named_scope :deferred, :conditions => ["completed_at IS NULL AND NOT show_from IS NULL"]
named_scope :deferred, :conditions => ["todos.completed_at IS NULL AND NOT todos.show_from IS NULL"]
named_scope :blocked, :conditions => ['todos.state = ?', 'pending']
named_scope :deferred_or_blocked, :conditions => ["(todos.completed_at IS NULL AND NOT todos.show_from IS NULL) OR (todos.state = ?)", "pending"]
named_scope :not_deferred_or_blocked, :conditions => ["todos.completed_at IS NULL AND todos.show_from IS NULL AND NOT todos.state = ?", "pending"]
named_scope :with_tag, lambda { |tag| {:joins => :taggings, :conditions => ["taggings.tag_id = ? ", tag.id] } }
named_scope :of_user, lambda { |user_id| {:conditions => ["todos.user_id = ? ", user_id] } }
named_scope :hidden,
:joins => :context,
:conditions => ["todos.state = ? OR (contexts.hide = ? AND (todos.state = ? OR todos.state = ? OR todos.state = ?))",
'project_hidden', true, 'active', 'deferred', 'pending']
named_scope :not_hidden,
:joins => [:context],
:conditions => ['NOT(todos.state = ? OR (contexts.hide = ? AND (todos.state = ? OR todos.state = ? OR todos.state = ?)))',
'project_hidden', true, 'active', 'deferred', 'pending']
STARRED_TAG_NAME = "starred"
# regular expressions for dependencies
RE_TODO = /[^"]+/
RE_CONTEXT = /[^"]+/
RE_PROJECT = /[^"]+/
RE_PARTS = /"(#{RE_TODO})"\s<"(#{RE_CONTEXT})";\s"(#{RE_PROJECT})">/ # results in array
RE_SPEC = /"#{RE_TODO}"\s<"#{RE_CONTEXT}";\s"#{RE_PROJECT}">/ # results in string
RE_TODO = /[^']+/
RE_CONTEXT = /[^']+/
RE_PROJECT = /[^']+/
RE_PARTS = /'(#{RE_TODO})'\s<'(#{RE_CONTEXT})';\s'(#{RE_PROJECT})'>/ # results in array
RE_SPEC = /'#{RE_TODO}'\s<'#{RE_CONTEXT}';\s'#{RE_PROJECT}'>/ # results in string
acts_as_state_machine :initial => :active, :column => 'state'
@ -82,6 +95,7 @@ class Todo < ActiveRecord::Base
def initialize(*args)
super(*args)
@predecessor_array = nil # Used for deferred save of predecessors
@removed_predecessors = nil
end
def no_uncompleted_predecessors_or_deferral?
@ -91,12 +105,11 @@ class Todo < ActiveRecord::Base
def no_uncompleted_predecessors?
return uncompleted_predecessors.empty?
end
# Returns a string with description <context, project>
def specification
project_name = project.is_a?(NullProject) ? "(none)" : project.name
return "\"#{description}\" <\"#{context.title}\"; \"#{project_name}\">"
return "\'#{description}\' <\'#{context.title}\'; \'#{project_name}\'>"
end
def todo_from_specification(specification)
@ -112,9 +125,9 @@ class Todo < ActiveRecord::Base
project_id = nil;
unless project_name == "(none)"
project = Project.first(:conditions => {
:user_id => self.user.id,
:name => project_name
})
:user_id => self.user.id,
:name => project_name
})
project_id = project.id unless project.nil?
end
@ -127,6 +140,7 @@ class Todo < ActiveRecord::Base
:project_id => project_id
}
)
return nil if todos.empty?
# TODO: what todo if there are more than one todo that fit the specification
@ -135,7 +149,7 @@ class Todo < ActiveRecord::Base
def validate
if !show_from.blank? && show_from < user.date
errors.add("show_from", "must be a date in the future")
errors.add("show_from", I18n.t('models.todo.error_date_must_be_future'))
end
errors.add(:description, "may not contain \" characters") if /\"/.match(description)
unless @predecessor_array.nil? # Only validate predecessors if they changed
@ -155,11 +169,15 @@ class Todo < ActiveRecord::Base
current_array = predecessors.map{|p| p.specification}
remove_array = current_array - @predecessor_array
add_array = @predecessor_array - current_array
@removed_predecessors = []
# This is probably a bit naive code...
remove_array.each do |specification|
t = todo_from_specification(specification)
self.predecessors.delete(t) unless t.nil?
unless t.nil?
@removed_predecessors << t
self.predecessors.delete(t)
end
end
# ... as is this?
add_array.each do |specification|
@ -170,7 +188,11 @@ class Todo < ActiveRecord::Base
logger.error "Could not find #{specification}" # Unexpected since validation passed
end
end
end
end
end
def removed_predecessors
return @removed_predecessors
end
def remove_predecessor(predecessor)
@ -195,16 +217,25 @@ class Todo < ActiveRecord::Base
return false
end
def has_tag?(tag)
return self.tags.select{|t| t.name==tag }.size > 0
end
def hidden?
return self.state == 'project_hidden' || ( self.context.hidden? && (self.state == 'active' || self.state == 'deferred'))
end
def update_state_from_project
if state == 'project_hidden' and !project.hidden?
if self.state == 'project_hidden' and !self.project.hidden?
if self.uncompleted_predecessors.empty?
self.state = 'active'
else
self.state = 'pending'
end
elsif state == 'active' and project.hidden?
elsif self.state == 'active' and self.project.hidden?
self.state = 'project_hidden'
end
self.save!
end
def toggle_completion!

View file

@ -3,6 +3,7 @@ require 'digest/sha1'
class User < ActiveRecord::Base
# Virtual attribute for the unencrypted password
attr_accessor :password
attr_protected :is_admin # don't allow mass-assignment for this
has_many :contexts,
:order => 'position ASC',
@ -11,11 +12,11 @@ class User < ActiveRecord::Base
find(params['id'] || params['context_id']) || nil
end
def update_positions(context_ids)
context_ids.each_with_index do |id, position|
context_ids.each_with_index {|id, position|
context = self.detect { |c| c.id == id.to_i }
raise "Context id #{id} not associated with user id #{@user.id}." if context.nil?
raise I18n.t('models.user.error_context_not_associated', :context => id, :user => @user.id) if context.nil?
context.update_attribute(:position, position + 1)
end
}
end
end
has_many :projects,
@ -25,11 +26,11 @@ class User < ActiveRecord::Base
find(params['id'] || params['project_id'])
end
def update_positions(project_ids)
project_ids.each_with_index do |id, position|
project_ids.each_with_index {|id, position|
project = self.detect { |p| p.id == id.to_i }
raise "Project id #{id} not associated with user id #{@user.id}." if project.nil?
raise I18n.t('models.user.error_project_not_associated', :project => id, :user => @user.id) if project.nil?
project.update_attribute(:position, position + 1)
end
}
end
def projects_in_state_by_position(state)
self.sort{ |a,b| a.position <=> b.position }.select{ |p| p.state == state }
@ -149,13 +150,25 @@ class User < ActiveRecord::Base
return nil if login.blank?
candidate = find(:first, :conditions => ["login = ?", login])
return nil if candidate.nil?
return candidate if candidate.auth_type == 'database' && candidate.crypted_password == sha1(pass)
if Tracks::Config.auth_schemes.include?('database')
return candidate if candidate.auth_type == 'database' && candidate.crypted_password == sha1(pass)
end
if Tracks::Config.auth_schemes.include?('ldap')
return candidate if candidate.auth_type == 'ldap' && SimpleLdapAuthenticator.valid?(login, pass)
end
if Tracks::Config.auth_schemes.include?('cas') && candidate.auth_type.eql?("cas")
return candidate #because we can not auth them with out thier real password we have to settle for this
if Tracks::Config.auth_schemes.include?('cas')
# because we can not auth them with out thier real password we have to settle for this
return candidate if candidate.auth_type.eql?("cas")
end
if Tracks::Config.auth_schemes.include?('open_id')
# hope the user enters the correct data
return candidate if candidate.auth_type.eql?("open_id")
end
return nil
end
@ -251,6 +264,13 @@ protected
def normalize_open_id_url
return if open_id_url.nil?
# fixup empty url value
if open_id_url.empty?
self.open_id_url = nil
return
end
self.open_id_url = OpenIdAuthentication.normalize_identifier(open_id_url)
end
end

View file

@ -13,7 +13,7 @@
<div id="c_<%=context.id%>_target" class="context_target drop_target"></div>
<div id="c<%= context.id %>items" class="items toggle_target">
<div id="c<%= context.id %>empty-nd" style="display:<%= @not_done.empty? ? 'block' : 'none'%>;">
<div class="message"><p>Currently there are no incomplete actions in this context</p></div>
<div class="message"><p><%= t 'contexts.no_actions' %></p></div>
</div>
<%= render :partial => "todos/todo", :collection => @not_done, :locals => { :parent_container_type => "context" } %>
</div><!-- [end:items] -->

View file

@ -1,28 +1,36 @@
<% context = context_form
@context = context-%>
<% form_remote_tag(:url => context_path(context), :html => {:id => dom_id(context, 'edit_form'), :class => "inline-form "+dom_id(context, 'edit_form')+"-edit-context-form edit-context-form", :method => :put}) do -%>
<%= error_messages_for 'context' %>
@context = context
-%>
<% form_for(context, :html => {
:id => dom_id(context, 'edit_form'),
:class => "inline-form edit-project-form",
:method => :put }) do
-%>
<div id="edit_error_status"><%= error_messages_for("project") %></div>
<label for="context_name">Context name</label><br/>
<%= text_field('context', 'name', :class => 'context-name') %><br/>
<label for="context_hide">Hide from front page?</label>
<label for="context_hide">Hide from front page?</label>
<%= check_box('context', 'hide', :class => 'context-hide') %>
<input type="hidden" name="wants_render" value="true" />
<input type="hidden" name="wants_render" value="true" />
<div class="submit_box">
<div class="widgets">
<button type="submit" class="positive" id="<%= dom_id(context, 'submit') %>" tabindex="15">
<%=image_tag("accept.png", :alt => "") %>
Update
<%= t 'common.update' %>
</button>
<a href="" onclick="" class="negative">
<%=image_tag("cancel.png", :alt => "") %>
Cancel
<%= t 'common.cancel' %>
</a>
</div>
</div>
<br/><br/>
<% end %>
<% end %>

View file

@ -1,43 +1,28 @@
<% context = context_listing
suppress_drag_handle ||= false
suppress_edit_button ||= false
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:'';">
<% unless suppress_drag_handle -%>
<div class="position">
<span class="handle">DRAG</span>
<span class="handle"><%= t('common.drag_handle') %></span>
</div>
<% end -%>
<div class="data">
<%= link_to_context( context ) %> <%= " (" + count_undone_todos_phrase(context,"actions") + ")" %>
</div>
<div class="buttons">
<% if context.hide? %>
<span class="grey">HIDDEN</span>
<span class="grey"><%= t('states.hidden') %></span>
<% else %>
<span class="grey">VISIBLE</span>
<span class="grey"><%= t('states.visible') %></span>
<% end %>
<%= link_to_remote(
image_tag( "blank.png", :title => "Delete context", :class=>"delete_item"),
:url => {:controller => 'contexts', :action => 'destroy', :id => context.id},
:method => 'delete',
:with => "'_source_view=#{@source_view}'",
:before => "$('#{dom_id(context)}').block({message:null});",
:complete => "$('#{dom_id(context)}').unblock();",
:confirm => "Are you sure that you want to delete the context '#{context.name}'? Be aware that this will also delete all (repeating) actions in this context!",
:html => { :id => dom_id(context, 'delete') }
) %>
<%= link_to_remote(
image_tag( "blank.png", :title => "Edit context", :class=>"edit_item"),
:url => {:controller => 'contexts', :action => 'edit', :id => context.id},
:method => 'get',
:with => "'_source_view=#{@source_view}'",
:before => "$('#{dom_id(context)}').block({message:null});",
:complete => "$('#{dom_id(context)}').unblock();",
:html => {:id => "edit_context_#{context.id}_link"}
) %>
<%= link_to_delete_context(context, image_tag( "blank.png", :title => t('contexts.delete_context'), :class=>"delete_item")) %>
<%= suppress_edit_button ? "" : link_to_edit_context(context, image_tag( "blank.png", :title => t('contexts.edit_context'), :class=>"edit_item")) %>
</div>
</div>
<div id="<%= dom_id(context, 'edit') %>" class="edit-form" style="display:none;">

View file

@ -1,7 +1,7 @@
<div class="list-stategroup-contexts-container">
<h2><span id="<%= state %>-contexts-count" class="badge"><%= context_state_group.length %></span><%= state.titlecase %> Contexts</h2>
<div class="list-stategroup-contexts-container" id="list-<%= state %>-contexts-container">
<h2><span id="<%= state %>-contexts-count" class="badge"><%= context_state_group.length %></span><%= t("states."+ state +"_plural")%> <%= t('common.contexts') %></h2>
<div id="<%= state%>-contexts-empty-nd" style="<%= no_contexts ? 'display:block' : 'display:none'%>">
<div class="message"><p>Currently there are no <%= state %> contexts</p></div>
<div class="message"><p><%= t('contexts.no_contexts_' + state) %></p></div>
</div>
<div id="list-contexts-<%= state %>">
<%= render :partial => 'context_listing', :collection => context_state_group %>

View file

@ -0,0 +1,28 @@
<div id="context_new_container">
<div id="toggle_context_link" class="hide_form">
<a id="toggle_context_new" href="#" title="<%= t('contexts.hide_form_title') %>" accesskey="n"><%= t('contexts.hide_form') %></a>
</div>
<div id="context_new" class="context_new" style="display:block">
<% form_for(@new_context, :html => {:id => 'context-form',:name=>'context',:class => "inline-form", :method => :post }) do -%>
<div id="error_status"><%= error_messages_for('context') %></div>
<label for="context_name"><%= t 'contexts.context_name' %></label><br />
<%= text_field( "context", "name" ) %><br />
<label for="context_hide"><%= t 'contexts.context_hide' %></label>
<%= check_box( "context", "hide" ) %><br />
<div class="submit_box">
<div class="widgets">
<button type="submit" class="positive" id="context_new_submit">
<%= image_tag("accept.png", :alt => "") + 'Add Context' %>
</button>
</div>
</div>
<br/><br/>
<% end -%>
</div>
</div>

View file

@ -0,0 +1,30 @@
<% if @saved -%>
hide_empty_message();
TracksPages.hide_errors();
TracksPages.set_page_badge(<%= @down_count %>);
add_context("<%=@context.hidden? ? 'hidden' : 'active'%>");
clear_form();
<% else -%>
TracksPages.show_errors(html_for_error_messages());
<% end -%>
function hide_empty_message() {
$('contexts-empty-nd').hide();
}
function add_context(state) {
$('#list-contexts-'+state).append(html_for_context_listing());
}
function clear_form() {
$('#context-form').clearForm();
$('#context-form input:text:first').focus();
}
function html_for_context_listing() {
return "<%= @saved ? escape_javascript(render(:partial => 'context_listing', :object => @context )) : "" %>";
}
function html_for_error_messages() {
return "<%= escape_javascript(error_messages_for('context')) %>";
}

View file

@ -1,12 +0,0 @@
if @saved
container_name = 'list-contexts-' + (@context.hidden? ? 'hidden' : 'active')
page.hide 'contexts-empty-nd'
page.insert_html :bottom, container_name, :partial => 'context_listing', :locals => { :context_listing => @context }
page.hide 'status'
page['badge_count'].replace_html @down_count
page << '$("#context-form").clearForm();'
page << '$("#context-form input:text:first").focus();'
else
page.show 'status'
page.replace_html 'status', "#{error_messages_for('context')}"
end

View file

@ -0,0 +1,14 @@
remove_deleted_context();
ContextListPage.update_all_states_count(<%=@active_contexts_count%>, <%=@hidden_contexts_count%>)
ContextListPage.show_or_hide_all_state_containers(<%= @show_active_contexts %>, <%= @show_hidden_contexts %>);
TracksPages.set_page_badge(<%=@down_count%>);
TracksPages.page_notify('notice', "<%= t('contexts.context_deleted', :name=>@context.name)%>", 5);
/* TODO: refactor and move function to application.js */
function remove_deleted_context() {
$('div#<%=dom_id(@context, "container")%>').slideUp(1000, function() {
$('div#<%=dom_id(@context, "container")%>').remove();
});
}

View file

@ -1,6 +0,0 @@
page.visual_effect :fade, dom_id(@context, "container"), :duration => 0.5
page.delay(0.5) do
page[dom_id(@context, "container")].remove
end
page['badge_count'].replace_html @down_count
page.notify :notice, "Deleted context '#{@context.name}'", 5.0

View file

@ -0,0 +1,21 @@
replace_context_with_edit_form();
function replace_context_with_edit_form() {
$('div#<%=dom_id(@context)%>').fadeOut(250, function() {
show_edit_form();
set_focus();
});
}
function show_edit_form() {
$('div#<%=dom_id(@context, 'edit')%>').html(html_for_edit_form());
$('div#<%=dom_id(@context, 'edit')%>').fadeIn(500);
}
function set_focus() {
$('input.context-name').focus();
}
function html_for_edit_form() {
return "<%= escape_javascript(render(:partial => 'context_form', :object => @context)) %>"
}

View file

@ -1,4 +0,0 @@
page[dom_id(@context, 'edit')].replace_html :partial => 'context_form', :locals => { :context_form => @context }
page[@context].hide
page[dom_id(@context, 'edit')].show
page[dom_id(@context, 'edit_form')].find('input.context-name').focus

View file

@ -1 +1 @@
page.notify :error, @error_message || "An error occurred on the server.", 8.0
page.notify :error, @error_message || t('common.server_error'), 8.0

View file

@ -4,41 +4,5 @@
</div>
<div id="input_box">
<div id="context_new_container">
<div id="toggle_context_new" class="hide_form">
<a title="Hide new context form" accesskey="n">&laquo; Hide form</a>
</div>
<div id="context_new" class="context_new" style="display:block">
<% form_remote_tag(
:url => contexts_path,
:method => :post,
:html=> { :id => 'context-form', :name => 'context', :class => 'inline-form'},
:before => "$('#context_new_submit').block({message: null})",
:complete => "$('#context_new_submit').unblock()") do -%>
<div id="status"><%= error_messages_for('context') %></div>
<label for="context_name">Context name</label><br />
<%= text_field( "context", "name" ) %><br />
<label for="context_hide">Hide from front page?</label>
<%= check_box( "context", "hide" ) %><br />
<div class="submit_box">
<div class="widgets">
<button type="submit" class="positive" id="context_new_submit">
<%= image_tag("accept.png", :alt => "") + 'Add Context' %>
</button>
</div>
</div>
<br/><br/>
<% end -%>
</div>
</div>
</div>
<%
sortable_element 'list-contexts-active', get_listing_sortable_options
sortable_element 'list-contexts-hidden', get_listing_sortable_options
-%>
<%= render :partial => 'new_context_form' %>
</div>

View file

@ -1,5 +1,5 @@
<% current_user.contexts.each do |c| -%>
<% @all_contexts.each do |c| -%>
<%= c.name.upcase %>
<%= count_undone_todos_phrase_text(c)%>. Context is <%= c.hidden? ? "Hidden" : "Active" %>.
<%= count_undone_todos_phrase_text(c)%>. <%= c.hidden? ? t('contexts.status_hidden') : t('contexts.status_active') %>.
<% end -%>

View file

@ -1,2 +1,2 @@
<h2>Visible Contexts</h2><%= render :partial => 'mobile_context_listing', :collection => @active_contexts %>
<h2>Hidden Contexts</h2><%= render :partial => 'mobile_context_listing', :collection => @hidden_contexts %>
<h2><%= t('contexts.visible_contexts') %></h2><%= render :partial => 'mobile_context_listing', :collection => @active_contexts %>
<h2><%= t('contexts.hidden_contexts') %></h2><%= render :partial => 'mobile_context_listing', :collection => @hidden_contexts %>

View file

@ -11,5 +11,6 @@ if not @not_done.empty?
<%= render :partial => "todos/mobile_todo",
:collection => @not_done,
:locals => { :parent_container_type => "context" }-%>
</table>
</ul>
<% end -%>

View file

@ -1,9 +1,8 @@
<div id="display_box">
<%= render :partial => "contexts/context", :locals => { :context => @context, :collapsible => false } %>
<%= render :partial => "contexts/context", :object => @context, :locals => { :collapsible => false } %>
<% unless @max_completed==0 -%>
<%= render :partial => "todos/completed", :locals => { :done => @done, :suppress_context => true, :collapsible => false, :append_descriptor => "in this context (last #{prefs.show_number_completed})" } %>
<%= render :partial => "todos/completed", :object => @done, :locals => { :suppress_context => true, :collapsible => false, :append_descriptor => t('contexts.last_completed_in_context', :number=>prefs.show_number_completed) } %>
<% end -%>
</div><!-- [end:display_box] -->
<div id="input_box">

View file

@ -0,0 +1,42 @@
<% if @saved -%>
TracksPages.page_notify('notice', '<%= t('contexts.save_status_message') %>', 5);
<% if @state_changed -%>
remove_and_re_add_context();
<% else -%>
replace_context_form_with_updated_context();
<% end -%>
<% else -%>
TracksPages.show_edit_errors(html_for_error_messages());
<% end -%>
function remove_and_re_add_context() {
$('#<%=dom_id(@context, 'container')%>').slideUp(500, function() {
$('#<%=dom_id(@context, 'container')%>').remove();
$('#list-contexts-<%=@new_state%>').append(html_for_context_listing());
});
}
function replace_context_form_with_updated_context() {
$('#<%=dom_id(@context, 'container')%>').fadeOut(250, function() {
<%
# first add the updated context after the old one, then remove old one
# using html() does not work, because it will replace the _content_ of
# the container instead of the container itself, i.e. you will get
# a container within a container which will break drag-and-drop sorting
-%>
$('#<%=dom_id(@context, 'container')%>').after(html_for_context_listing());
$('#<%=dom_id(@context, 'container')%>').remove();
$('#<%=dom_id(@context, 'container')%>').fadeIn(500);
});
}
function html_for_error_messages() {
return "<%= escape_javascript(error_messages_for('context')) %>";
}
function html_for_context_listing() {
return "<%= escape_javascript(render(:partial => 'context_listing', :object => @context))%>";
}

View file

@ -1,9 +0,0 @@
status_message = 'Context saved'
page.notify :notice, status_message, 5.0
if @context_state_changed
page.remove dom_id(@context, 'container')
page.insert_html :bottom, "list-contexts-#{@new_state}", :partial => 'context_listing', :object => @context
else
page.replace_html dom_id(@context, 'container'), :partial => 'context_listing', :object => @context
end
page.visual_effect :highlight, dom_id(@context), :duration => 3

View file

@ -4,5 +4,5 @@ page['todo_context_name'].value = @context.name
# renew context auto complete array
page << "contextAutoCompleter.options.array = #{context_names_for_autocomplete}; contextAutoCompleter.changed = true"
status_message = "Name of context was changed"
status_message = t('contexts.update_status_message')
page.notify :notice, status_message, 5.0

View file

@ -0,0 +1,36 @@
<div id="display_box">
<div id="feeds">
<div id="feedlegend">
<h3>Daten exportieren</h3>
<p>Sie k&ouml;nnen zwischen den folgenden Formaten w&auml;hlen:</p>
<ul>
<li><strong>YAML: </strong>F&uuml;r den Daten-Import bevorzugt.<br/><i>Bitte beachten Sie, dass der YAML-Import zur Zeit noch experimentelle Funktionalit&auml;t darstellt. Nutzen Sie diese Option also nicht. um kritische Daten zu sichern.</i></li>
<li><strong>CSV: </strong>Am besten f&uuml;r den Export in eine Tabellen-Kalkulation oder &auml;hnliche Auswertungs-Software geeignet</li>
<li><strong>XML: </strong>Am besten f&uuml;r den Daten-Import oder automatische Weiterverarbeitung</li>
</ul>
</div>
<br/><br/>
<table class="export_table">
<tr>
<th>Beschreibung</th>
<th>Download link</th>
</tr>
<tr>
<td>YAML-Datei mit all Ihren Aktionen, Umgebungen, Projekten, Tags und Notizen</td>
<td><%= link_to "YAML Datei", :controller => 'data', :action => 'yaml_export' %></td>
</tr>
<tr>
<td>CSV-Datei mit all Ihren Aktionen, benannten Umgebungen und Projekten</td>
<td><%= link_to "CSV Dile (Aktionen, Umgebungen und Projekte)", :controller => 'data', :action => 'csv_actions' %></td>
</tr>
<tr>
<td>CSV-Datei mit all Ihren Notizen</td>
<td><%= link_to "CSV Datei (nur Notizen)", :controller => 'data', :action => 'csv_notes' %></td>
</tr>
<tr>
<td>XML-Datei mit all Ihren Aktionen, Umgebungen, Projekten, Tags und Notizen</td>
<td><%= link_to "XML file (actions only)", :controller => 'data', :action => 'xml_export' %></td>
</tr>
</table>
</div><!-- End of feeds -->
</div>

View file

@ -0,0 +1,17 @@
<div id="display_box">
<div id="feeds">
<div id="feedlegend">
<p><b>Vorsicht</b>: vor dem Import der YAML Datei werden alle Daten in Ihrer Datenbank gel&ouml;scht.
Falls Sie entsprechenden Zugriff auf Ihre Datenbank haben, empfiehlt es sich, ein Backup anzulegen,
bevor Sie fortfahren.
</p>
<p>F&uuml;gen Sie den Inhalt der kopierten YAML Datei in das untenstehende Formular ein:</p>
</div>
<p>
<% form_for :import, @import, :url => {:controller => 'data', :action => 'yaml_import'} do |f| %>
<%= f.text_area :yaml %><br />
<input type="submit" value="Daten importieren">
<% end %>
</p>
</div><!-- End of feeds -->
</div><!-- End of display_box -->

View file

@ -1,7 +1,5 @@
<% if !(@errmessage == '') %>
<p>There were these errors:
<pre><%= @errmessage %></pre>
</p>
<p><%= t('data.import_errors') %>:<pre><%= @errmessage %></pre></p>
<% else %>
<p>Import was successful.</p>
<p><%= t('data.import_successful') %></p>
<% end %>

View file

@ -1,6 +1,25 @@
<li>
<%= rss_formatted_link({ :controller=> 'todos', :action => 'index', :context_id => context.to_param }) %>
<%= text_formatted_link({ :controller=> 'todos', :action => 'index', :context_id => context.to_param }) %>
<%= ical_formatted_link({ :controller=> 'todos', :action => 'index', :context_id => context.to_param }) %>
<strong><%=h context.name %></strong>
</li>
<% context = @active_contexts.empty? ? @hidden_contexts.first : @active_contexts.first
-%>
<h4><%= t('feedlist.context_centric_actions') %>:</h4>
<% if @active_contexts.empty? && @hidden_contexts.empty? -%>
<ul><li><%= t('feedlist.context_needed') %></li></ul>
<% else -%>
<ul>
<li><%= t('common.numbered_step', :number => 1) %> - <%= t('feedlist.choose_context') %>:
<select name="feed-contexts" id="feed-contexts">
<%= options_from_collection_for_select(@active_contexts, "id", "name", @active_contexts.first.id) unless @active_contexts.empty?-%>
<%= options_from_collection_for_select(@hidden_contexts, "id", "name") -%>
</select>
</li>
<li><%= t('common.numbered_step', :number => 2) %> - <%= t('feedlist.select_feed_for_context') %>
<div id="feedicons-context">
<div id="feeds-for-context">
<li><%= all_feed_links_for_context(context) %></li>
</div>
</div>
</li>
</ul>
<% end -%>

View file

@ -1,6 +1,22 @@
<li>
<%= rss_formatted_link({ :controller=> 'todos', :action => 'index', :project_id => project.to_param }) %>
<%= text_formatted_link({ :controller=> 'todos', :action => 'index', :project_id => project.to_param }) %>
<%= ical_formatted_link({ :controller=> 'todos', :action => 'index', :project_id => project.to_param }) %>
<strong><%=h project.name %></strong>
</li>
<% project = @active_projects.empty? ? @hidden_projects.first : @active_projects.first -%>
<h4><%= t('feedlist.project_centric') %>:</h4>
<ul>
<% if @active_projects.empty? && @hidden_projects.empty? -%>
<li><%= t('feedlist.project_needed') %></li>
<% else -%>
<li><%= t('common.numbered_step', :number => 1) %> - <%= t('feedlist.choose_project') %>:
<select name="feed-projects" id="feed-projects">
<%= options_from_collection_for_select(@active_projects, "id", "name", @active_projects.first.id) unless @active_projects.empty?-%>
<%= options_from_collection_for_select(@hidden_projects, "id", "name") -%>
<%= options_from_collection_for_select(@completed_projects, "id", "name") -%>
</select>
</li>
<li><%= t('common.numbered_step', :number => 2) %> - <%= t('feedlist.select_feed_for_project') %>
<div id="feedicons-project">
<div id="feeds-for-project">
<li><%= all_feed_links_for_project(project) %></li>
</div>
</div>
</li>
<% end -%>
</ul>

View file

@ -0,0 +1,14 @@
<div id="feedlegend">
<h3><%= t('feedlist.legend') %></h3>
<dl>
<dt><%= image_tag("feed-icon.png", :size => "16X16", :border => 0)%></dt>
<dd><%= t('feedlist.rss_feed') %></dd>
<dt><span class="feed">TXT</span></dt>
<dd><%= t('feedlist.plain_text_feed') %></dd>
<dt><span class="feed">iCal</span></dt>
<dd><%= t('feedlist.ical_feed') %></dd>
</dl>
<p><%= t('feedlist.notice_incomplete_only') %></p>
</div>

View file

@ -0,0 +1 @@
<li><%= all_feed_links_for_context(@context) %></li>

View file

@ -0,0 +1 @@
<li><%= all_feed_links_for_project(@project) %></li>

View file

@ -1,115 +1,23 @@
<div id="display_box">
<div id="feeds">
<div id="feedlegend">
<h3>Legend:</h3>
<dl>
<dt><%= image_tag("feed-icon.png", :size => "16X16", :border => 0)%></dt><dd>RSS Feed</dd>
<dt><span class="feed">TXT</span></dt><dd>Plain Text Feed</dd>
<dt><span class="feed">iCal</span></dt><dd>iCal feed</dd>
</dl>
<p>Note: All feeds show only actions that have not been marked as done.</p>
</div>
<%= render :partial => 'legend' %>
<ul>
<li>
<%= rss_formatted_link({ :controller => 'todos', :action => 'index', :limit => 15 }) %>
<%= text_formatted_link({ :controller => 'todos', :action => 'index', :limit => 15 }) %>
<%= ical_formatted_link({ :controller => 'todos', :action => 'index', :limit => 15 }) %>
Last 15 actions
</li>
<li>
<%= rss_formatted_link( { :controller => 'todos', :action => 'index' } ) %>
<%= text_formatted_link( { :controller => 'todos', :action => 'index' } ) %>
<%= ical_formatted_link( { :controller => 'todos', :action => 'index' } ) %>
All actions
</li>
<li>
<%= rss_formatted_link({ :controller => 'todos', :action => 'index', :due => 0 }) %>
<%= text_formatted_link({ :controller => 'todos', :action => 'index', :due => 0 }) %>
<%= ical_formatted_link({ :controller => 'todos', :action => 'index', :due => 0 }) %>
Actions due today or earlier
</li>
<li>
<%= rss_formatted_link({ :controller => 'todos', :action => 'index', :due => 6 }) %>
<%= text_formatted_link({ :controller => 'todos', :action => 'index', :due => 6 }) %>
<%= ical_formatted_link({ :controller => 'todos', :action => 'index', :due => 6 }) %>
Actions due in 7 days or earlier
</li>
<li>
<%= rss_formatted_link({ :controller => 'todos', :action => 'index', :done => 7 }) %>
<%= text_formatted_link({ :controller => 'todos', :action => 'index', :done => 7 }) %>
Actions completed in the last 7 days
</li>
<li>
<%= rss_formatted_link({:controller => 'contexts', :action => 'index'}) %>
<%= text_formatted_link({:controller => 'contexts', :action => 'index'}) %>
All Contexts
</li>
<li>
<%= rss_formatted_link({:controller => 'projects', :action => 'index'}) %>
<%= text_formatted_link({:controller => 'projects', :action => 'index'}) %>
All Projects
</li>
<li>
<%= rss_formatted_link({:controller => 'projects', :action => 'index', :only_active_with_no_next_actions => true}) %>
<%= text_formatted_link({:controller => 'projects', :action => 'index', :only_active_with_no_next_actions => true}) %>
Active projects with no next actions
</li>
<li>
<%= rss_formatted_link({:controller => 'todos', :action => 'index', :tag => 'starred'}) %>
<%= text_formatted_link({:controller => 'todos', :action => 'index', :tag => 'starred'}) %>
All starred, active actions
</li>
<li>
<%= text_formatted_link({:controller => 'projects', :action => 'index', :projects_and_actions => true}) %>
Active projects with their actions
</li>
<li><h4>Feeds for incomplete actions in a specific context:</h4>
<% if @active_contexts.empty? && @hidden_contexts.empty? -%>
<ul><li>There need to be at least one context before you can request a feed</li></ul>
<% else -%>
<ul>
<li>Step 1 - Choose the context you want a feed of:
<select name="feed-contexts" id="feed-contexts">
<%= options_from_collection_for_select(@active_contexts, "id", "name", @active_contexts.first.id) unless @active_projects.empty?-%>
<%= options_from_collection_for_select(@hidden_contexts, "id", "name") -%>
</select>
</li>
<li>Step 2 - Select the feed for this context
<div id="feedicons-context">
<div id="feeds-for-context">
<%= render :partial => 'feed_for_context', :locals => { :context => @active_contexts.empty? ? @hidden_contexts.first : @active_contexts.first } %>
</div>
</div>
</li>
</ul>
<% end -%>
</li>
<li><h4>Feeds for incomplete actions in a specific project:</h4>
<% if @active_projects.empty? && @hidden_projects.empty? -%>
<ul><li>There need to be at least one project before you can request a feed</li></ul>
<% else -%>
<ul>
<li>Step 1 - Choose the project you want a feed of:
<select name="feed-projects" id="feed-projects">
<%= options_from_collection_for_select(@active_projects, "id", "name", @active_projects.first.id) unless @active_projects.empty?-%>
<%= options_from_collection_for_select(@hidden_projects, "id", "name") -%>
<%= options_from_collection_for_select(@completed_projects, "id", "name") -%>
</select>
</li>
<li>Step 2 - Select the feed for this project
<div id="feedicons-project">
<div id="feeds-for-project">
<%= render :partial => 'feed_for_project', :locals => { :project => @active_projects.empty? ? @hidden_projects.first : @active_projects.first } %>
</div>
</div>
</li>
</ul>
<% end -%>
</li>
<li><%= feed_links([:rss, :txt, :ical], { :controller => 'todos', :action => 'index', :limit => 15 }, t('feedlist.last_fixed_number', :number=>15)) %></li>
<li><%= feed_links([:rss, :txt, :ical], { :controller => 'todos', :action => 'index' }, t('feedlist.all_actions')) %></li>
<li><%= feed_links([:rss, :txt, :ical], { :controller => 'todos', :action => 'index', :due => 0 }, t('feedlist.actions_due_today')) %></li>
<li><%= feed_links([:rss, :txt, :ical], { :controller => 'todos', :action => 'index', :due => 6 }, t('feedlist.actions_due_next_week')) %></li>
<li><%= feed_links([:rss, :txt], { :controller => 'todos', :action => 'index', :done => 7 }, t('feedlist.actions_completed_last_week')) %></li>
<li><%= feed_links([:rss, :txt], { :controller => 'contexts', :action => 'index' }, t('feedlist.all_contexts')) %></li>
<li><%= feed_links([:rss, :txt], { :controller => 'projects', :action => 'index' }, t('feedlist.all_projects')) %></li>
<li><%= feed_links([:rss, :txt], { :controller => 'projects', :action => 'index', :only_active_with_no_next_actions => true }, t('feedlist.active_projects_wo_next')) %></li>
<li><%= feed_links([:rss, :txt], { :controller => 'todos', :action => 'index', :tag => 'starred' }, t('feedlist.active_starred_actions')) %></li>
<li><%= feed_links([:txt], {:controller => 'projects', :action => 'index', :projects_and_actions => true}, t('feedlist.projects_and_actions')) %></li>
<li><%= render :partial => 'feed_for_context' %></li>
<li><%= render :partial => 'feed_for_project' %></li>
</ul>
</div>
</div><!-- End of display_box -->
</div>
<div id="input_box">
<%= render :file => "sidebar/sidebar.html.erb" %>
</div><!-- End of input box -->
</div>

View file

@ -7,7 +7,7 @@ set myToken to "<%= current_user.token %>"
set myContextID to <%= context.id %> (* <%= context.name %> *)
-- Display dialog to enter your description
display dialog "Description of next action:" default answer ""
display dialog "<%= t('integrations.applescript_next_action_prompt') %>" default answer ""
set myDesc to text returned of the result
-- Now send all that info to Tracks
@ -17,4 +17,4 @@ tell application "<%= home_url %>backend/api"
end tell
-- Show the ID of the newly created next action
display dialog "New next action with id " & returnValue & " created"
display dialog "<%= t('integrations.applescript_success_before_id') %> " & returnValue & " <%= t('integrations.applescript_success_after_id') %>"

View file

@ -1,5 +1,5 @@
<Module>
<ModulePrefs title="Tracks" directory_title="Tracks" description="Gadget to add Tracks to Gmail as a gadget" author="Tracks" author_email="butshesagirl@rousette.org.uk" author_affiliation="Tracks" author_location="UK" title_url="http://www.getontracks.org/" screenshot="http://www.getontracks.org/images/uploads/tracks_home_thumb.png" thumbnail="http://www.getontracks.org/images/uploads/tracks_tickler.png" category="communication" category2="tools" height="300">
<ModulePrefs title="Tracks" directory_title="Tracks" description="<%= t('integrations.gmail_description') %>" author="Tracks" author_email="butshesagirl@rousette.org.uk" author_affiliation="Tracks" author_location="UK" title_url="http://www.getontracks.org/" screenshot="http://www.getontracks.org/images/uploads/tracks_home_thumb.png" thumbnail="http://www.getontracks.org/images/uploads/tracks_tickler.png" category="communication" category2="tools" height="300">
</ModulePrefs>
<Content type="url" href="<%= home_url %>mobile"/>
</Module>

View file

@ -0,0 +1,125 @@
<% has_contexts = !current_user.contexts.empty? -%>
<h1>Integration</h1>
<p>Tracks kann mit verschiedenen Werkzeugen zusammenarbeiten...
was immer Sie brauchen, um Ihre Aufgaben zu erledigen!
Auf dieser Seite finden Sie Informationen, um einige dieser Werkzeuge einzurichten.
Diese Beispiele sind nicht unbedingt auf Ihre Umgebung anwendbar oder bed&uuml;rfen mehr
technisches Wissen als andere.
Weitere Informationen finden Sie in der <%= link_to "Entwickler Documentation der Tracks' REST API", url_for(:action => 'rest_api') %> (englisch).</p>
<br/><p>Inhalt:</p>
<ul>
<li><a href="#applescript1-section">Eine Aktion mit Applescript hinzuf&uuml;gen</a></li>
<li><a href="#applescript2-section">Eine Aktion anhand der aktuell in Mail.app selektierten Nachricht erstellen</a></li>
<li><a href="#quicksilver-applescript-section">Aktionen mit Quicksilver und Applescript erstellen</a></li>
<li><a href="#email-cron-section">Anstehende Aufgaben automatisch sich via E-Mail zusenden lassen</a></li>
<li><a href="#message_gateway">Tracks mit einem Mail-Server integrieren, um Aufgaben via E-Mail zu erstellen</a></li>
<li><a href="#google_gadget">Tracks zu Ihrer Google Gmail Seite hinzuf&uuml;gen</a></li>
</ul><br/>
<p>Sie haben weitere Beispiele?
<a href="http://www.getontracks.org/forums/viewforum/10/" title="Tracks | Tips and Tricks">Berichten Sie uns
in unserem Tipps&amp;Tricks Forum</a>, damit wir es f&uuml;r die n&auml;chsten Versionen ber&uuml;cksichtigen k&ouml;nnen.
</p>
<a name="applescript1-section"> </a>
<h2>Eine Aktion mit Applescript hinzuf&uuml;gen</h2>
<p>Dieses Beispiel-Script zeigt einen Dialog, welcher nach einer Beschreibung fragt und die Aufgabe in einem festen Kontext anlegt.</p>
<% if has_contexts -%>
<ol>
<li>W&auml;hlen Sie den Kontext, f&uuml;r welchen die Aktion erstellt werden soll: <select name="applescript1-contexts" id="applescript1-contexts"><%= options_from_collection_for_select(current_user.contexts, "id", "name", current_user.contexts.first.id) %></select>
</li>
<li>Kopieren Sie das AppleScript in die Zwischenablage.<br />
<textarea id="applescript1" name="applescript1" rows="15"><%= render :partial => 'applescript1', :locals => { :context => current_user.contexts.first } %></textarea>
</li>
<li>&Ouml;ffnen Sie den Script Editor und f&uuml;gen die Daten in ein neues Script ein.</li>
<li>Kompilieren und speichern Sie das Script, um es bei Bedarf einzusetzen.</li>
</ol>
<% else %>
<br/><p id="no_context_msg"><i>Sie haben noch keinen Kontext angelegt. Dieses Script ist automatisch verf&uuml;gbar, sobald Sie Ihren ersten Kontext angelegt haben.</i></p>
<% end %>
<a name="applescript2-section"> </a>
<h2>Add an Action with Applescript based on the currently selected Email in Mail.app</h2>
<p>This script takes the sender and subject of the selected email(s) in Mail and creates a new action for each one, with the description, "Email [sender] about [subject]". The description gets truncated to 100 characters (the validation limit for the field) if it is longer than that. It also has Growl notifications if you have Growl installed.</p>
<% if has_contexts -%>
<ol>
<li>Choose the context you want to add actions to: <select name="applescript2-contexts" id="applescript2-contexts"><%= options_from_collection_for_select(current_user.contexts, "id", "name", current_user.contexts.first.id) %></select>
</li>
<li>Copy the Applescript below to the clipboard.<br />
<textarea id="applescript2" name="applescript2" rows="15"><%= render :partial => 'applescript2', :locals => { :context => current_user.contexts.first } %></textarea>
</li>
<li>Open Script Editor and paste the script into a new document.</li>
<li>Compile and save the script to the ~/Library/Scriipts/Mail Scripts directory.</li>
<li>For more information on using AppleScript with Mail.app, see <a href="http://www.apple.com/applescript/mail/" title="Scriptable Applications: Mail">this overview</a>.</li>
</ol>
<% else %>
<br/><p><i>You do not have any context yet. The script will be available after you add your first context</i></p>
<% end %>
<a name="quicksilver-applescript-section"></a>
<h2>Add Actions with Quicksilver and Applescript</h2>
<p>This integration will allow you to add actions to Tracks via <a href="http://quicksilver.blacktree.com/">Quicksilver</a>.</p>
<% if has_contexts -%>
<ol>
<li>Choose the context you want to add actions to: <select name="quicksilver-contexts" id="quicksilver-contexts"><%= options_from_collection_for_select(current_user.contexts, "id", "name", current_user.contexts.first.id) %></select>
</li>
<li>Copy the Applescript below to the clipboard.<br />
<textarea id="quicksilver" name="quicksilver" rows="15"><%= render :partial => 'quicksilver_applescript', :locals => { :context => current_user.contexts.first } %></textarea>
</li>
<li>Open Script Editor and paste the script into a new document.</li>
<li>Compile and save the script as "Add to Tracks.scpt" in ~/Library/Application Support/Quicksilver/Actions/ (you may need to create the Actions directory)</li>
<li>Restart Quicksilver</li>
<li>Activate Quicksilver (Ctrl+Space by default)</li>
<li>Press "." to put quicksilver into text mode</li>
<li>Type the description of the next action you want to add</li>
<li>Press tab to switch to the action pane.</li>
<li>By typing or scrolling, choose the "Add to Tracks" action.</li>
</ol>
<% else %>
<br/><p><i>You do not have any context yet. The script will be available after you add your first context</i></p>
<% end %>
<a name="email-cron-section"> </a>
<h2>Automatically Email Yourself Upcoming Actions</h2>
<p>If you enter the following entry to your crontab, you will receive email every day around 5 AM with a list of the upcoming actions which are due within the next 7 days.</p>
<textarea id="cron" name="cron">0 5 * * * /usr/bin/curl -0 "<%= home_url %>todos.txt?due=6&token=<%= current_user.token %>" | /usr/bin/mail -e -s 'Tracks actions due in the next 7 days' youremail@yourdomain.com</textarea>
<p>You can of course use other text <%= link_to 'feeds provided by Tracks', feeds_path %> -- why not email a list of next actions in a particular project to a group of colleagues who are working on the project?</p>
<a name="message_gateway"> </a>
<h2>Integrated email/SMS receiver</h2>
<p>
If Tracks is running on the same server as your mail server, you can use the integrated mail handler built into tracks. Steps to set it up:
</p>
<ul>
<li>Go to <%= link_to "Preferences", preferences_url %> and set your "From email" and "default email context" for todos sent in via email (which could come from an SMS message)</li>
<li>In sendmail/qmail/postfix/whatever, set up an email address alias to pipe messages to <pre >/PATH/TO/RUBY/ruby /PATH/TO/TRACKS/script/runner -e production 'MessageGateway.receive(STDIN.read)'</pre></li>
<li>Send an email to your newly configured address!</li>
</ul>
<p>You can also use the Rich Todo API to send in tasks like "do laundry @ Home"
or "Call Bill > project X". The subject of the message will fill description,
context, and project, while the body will populate the tasks's note.
</p>
<a name="google_gadget"> </a>
<h2>Add Tracks as a Google Gmail gadget</h2>
<p>
You can now manage your projects/actions inside Gmail using Tracks Gmail Gadget.
Add Tracks Gmail gadget to the sidebar of Gmail and track your next actions
or add new action without explicitly open new browser tab for Tracks. Steps to set it up:
</p>
<ul>
<li>Sign in to Gmail and click Settings in the top right of your Gmail page. In Gmail setting page, click Labs tab</li>
<li>Enable the "Add any gadget by URL" feature. You will find it at bottom of the list. Select Enable radio button and click Save Changes button.</li>
<li>Now you can see Gadgets tab added to Gmail Settings. Go to the Gadgets tab</li>
<li>Paste following link to the Add a gadget by its URL: and then click Add button:<br/>
<pre><%= integrations_url + "/google_gadget" %></pre></li>
</ul>

View file

@ -53,7 +53,7 @@
</li>
<li>Open Script Editor and paste the script into a new document.</li>
<li>Compile and save the script to the ~/Library/Scriipts/Mail Scripts directory.</li>
<li>For more information on using AppleScript with Mail.app, see <a href="http://www.apple.com/applescript/mail/" title="Scriptable Applications: Mail">this overview</a>.
<li>For more information on using AppleScript with Mail.app, see <a href="http://www.apple.com/applescript/mail/" title="Scriptable Applications: Mail">this overview</a>.</li>
</ol>
<% else %>
<br/><p><i>You do not have any context yet. The script will be available after you add your first context</i></p>
@ -98,6 +98,7 @@
<h2>Integrated email/SMS receiver</h2>
<p>
If Tracks is running on the same server as your mail server, you can use the integrated mail handler built into tracks. Steps to set it up:
</p>
<ul>
<li>Go to <%= link_to "Preferences", preferences_url %> and set your "From email" and "default email context" for todos sent in via email (which could come from an SMS message)</li>
<li>In sendmail/qmail/postfix/whatever, set up an email address alias to pipe messages to <pre >/PATH/TO/RUBY/ruby /PATH/TO/TRACKS/script/runner -e production 'MessageGateway.receive(STDIN.read)'</pre></li>
@ -121,10 +122,4 @@
<li>Now you can see Gadgets tab added to Gmail Settings. Go to the Gadgets tab</li>
<li>Paste following link to the Add a gadget by its URL: and then click Add button:<br/>
<pre><%= integrations_url + "/google_gadget" %></pre></li>
</ul>
<Module>
<ModulePrefs title="GTDify" directory_title="GTDify" description="Official gadget for GTDify service." author="GTDify" author_email="support@gtdify.com" author_affiliation="GTDify" author_location="NJ, USA" title_url="http://www.gtdify.com/" screenshot="http://www.gtdify.com/modules/gmail/ss.png" thumbnail="http://www.gtdify.com/modules/gmail/tn.png" category="communication" category2="tools" height="300">
</ModulePrefs>
<Content type="url" href="http://my.gtdify.com/mobile/"/>
</Module>
</ul>

View file

@ -3,7 +3,7 @@ xml.instruct!
xml.OpenSearchDescription 'xmlns' => "http://a9.com/-/spec/opensearch/1.1/" do
xml.ShortName Tracks
xml.Description 'Search in Tracks'
xml.Description t('integrations.opensearch_description')
xml.InputEncoding 'UTF-8'
xml.Image("data:image/x-icon;base64," + @icon_data,
'width' => '16', 'height' => '16')

View file

@ -3,8 +3,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<%= stylesheet_link_tag "scaffold" %>
<%= javascript_include_tag 'jquery' %>
<%= javascript_include_tag 'jquery.cookie' %>
<%= javascript_include_tag 'jquery-1.5.min', 'jquery.cookie' %>
<title><%= @page_title -%></title>

View file

@ -12,29 +12,29 @@
<title><%= @page_title %></title>
</head><body>
<% if !(@new_mobile || @edit_mobile)
if !@prefs.nil? -%>
if !current_user.prefs.nil? -%>
<h1><span class="count"><%= @down_count %></span> <%=
current_user.time.strftime(@prefs.title_date_format) -%></h1>
l(Date.today, :format => current_user.prefs.title_date_format) -%></h1>
<div class="nav">
<%= (link_to("0-New action", new_todo_path(new_todo_params))+" | ") unless @new_mobile -%>
<%= (link_to("1-Home", todos_path(:format => 'm'))+" | ") unless @home -%>
<%= (link_to("2-Contexts", contexts_path(:format => 'm'))+" | ") -%>
<%= (link_to("3-Projects", projects_path(:format => 'm'))+" | ") -%>
<%= (link_to("4-Starred", {:action => "tag", :controller => "todos", :id => "starred.m"})) -%>
<%= (link_to(t('layouts.mobile_navigation.new_action'), new_todo_path(new_todo_params))+" | ") unless @new_mobile -%>
<%= (link_to(t('layouts.mobile_navigation.home'), todos_path(:format => 'm'))+" | ") unless @home -%>
<%= (link_to(t('layouts.mobile_navigation.contexts'), contexts_path(:format => 'm'))+" | ") -%>
<%= (link_to(t('layouts.mobile_navigation.projects'), projects_path(:format => 'm'))+" | ") -%>
<%= (link_to(t('layouts.mobile_navigation.starred'), {:action => "tag", :controller => "todos", :id => "starred.m"})) -%>
<% end
end -%><%= render_flash -%>
</div>
<%= yield -%>
<hr/><% if !@prefs.nil? -%>
<hr/><% if !current_user.prefs.nil? -%>
<div class="nav">
<%= (link_to("Logout", logout_path(:format => 'm')) +" | ") -%>
<%= (link_to("0-New action", new_todo_path(new_todo_params), {:accesskey => "0"})+" | ") unless @new_mobile -%>
<%= (link_to("1-Home", todos_path(:format => 'm'), {:accesskey => "1"})+" | ") unless @home -%>
<%= (link_to("2-Contexts", contexts_path(:format => 'm'), {:accesskey => "2"})+" | ") -%>
<%= (link_to("3-Projects", projects_path(:format => '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"})) -%>
<%= (link_to(t('layouts.mobile_navigation.logout'), logout_path(:format => 'm')) +" | ") -%>
<%= (link_to(t('layouts.mobile_navigation.new_action'), new_todo_path(new_todo_params), {:accesskey => "0"})+" | ") unless @new_mobile -%>
<%= (link_to(t('layouts.mobile_navigation.home'), todos_path(:format => 'm'), {:accesskey => "1"})+" | ") unless @home -%>
<%= (link_to(t('layouts.mobile_navigation.contexts'), contexts_path(:format => 'm'), {:accesskey => "2"})+" | ") -%>
<%= (link_to(t('layouts.mobile_navigation.projects'), projects_path(:format => 'm'), {:accesskey => "3"})+" | ") -%>
<%= (link_to(t('layouts.mobile_navigation.starred'), {:action => "tag", :controller => "todos", :id => "starred.m"}, {:accesskey => "4"})+" | ") -%>
<%= (link_to(t('layouts.mobile_navigation.tickler'), {:action => "index", :controller => "tickler.m"})+" | ") -%>
<%= (link_to(t('layouts.mobile_navigation.feeds'), {:action => "index", :controller => "feeds.m"})) -%>
</div>
<% end -%>
<%= render :partial => "shared/mobile_footer" -%>

View file

@ -2,29 +2,36 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<%= stylesheet_link_tag 'standard','superfish','niftyCorners','jquery-ui',
'jquery.autocomplete', :cache => true %>
<%= stylesheet_link_tag 'standard','superfish','niftyCorners', 'jquery-ui-1.8.9.custom', :cache => 'tracks-cached' %>
<%= stylesheet_link_tag "print", :media => "print" %>
<%= javascript_include_tag 'jquery','jquery-ui','jquery.cookie',
'jquery.blockUI','jquery.jeditable','jquery.autocomplete',
'jquery.truncator', :cache => 'jquery-all' %>
<%= javascript_include_tag 'jquery-1.5.min', 'jquery-ui-1.8.9.custom.min',
'jquery.truncator','jquery.jeditable.mini', 'jquery.cookie', 'jquery.blockUI',
'jquery.form','jquery.ui.autocomplete.selectFirst',
:cache => 'jquery-cached' %>
<%= javascript_include_tag 'hoverIntent','superfish','application',
'accesskey-hints','niftycube','swfobject', :cache => 'tracks' %>
'accesskey-hints','niftycube','swfobject',
:cache => 'tracks-cached' %>
<%= javascript_tag "var AUTH_TOKEN = #{form_authenticity_token.inspect};" if protect_against_forgery? %>
<%= javascript_tag "var SOURCE_VIEW = '#{@source_view}';" %>
<%= javascript_tag "var TAG_NAME = '#{@tag_name}';" if @tag_name %>
<%= csrf_meta_tag %>
<script type="text/javascript">
var defaultContexts = <%= default_contexts_for_autocomplete rescue '{}' %>;
var defaultTags = <%= default_tags_for_autocomplete rescue '{}' %>;
var dateFormat = '<%= date_format_for_date_picker %>';
var weekStart = '<%= current_user.prefs.week_starts %>';
function relative_to_root(path) { return '<%= root_url %>'+path; };
<% if @prefs.refresh != 0 -%>
setup_auto_refresh(<%= @prefs["refresh"].to_i*60000 %>);
<% if current_user.prefs.refresh != 0 -%>
setup_auto_refresh(<%= current_user.prefs["refresh"].to_i*60000 %>);
<% end -%>
<% unless @controller_name == 'feed' or session['noexpiry'] == "on" -%>
setup_periodic_check("<%=url_for(:controller => "login", :action => "check_expiry")%>", 5*60);
<% end -%>
setup_periodic_check("<%=check_deferred_todos_path(:format => 'js')%>", 10*60, 'POST');
<%= generate_i18n_strings %>
</script>
<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"}) %>
<%= auto_discovery_link_tag(:rss, {:controller => "todos", :action => "index", :format => 'rss', :token => "#{current_user.token}"}, {:title => t('layouts.next_actions_rss_feed')}) %>
<link rel="search" type="application/opensearchdescription+xml" title="Tracks" href="<%= search_plugin_path %>" />
<title><%= @page_title %></title>
</head>
@ -36,64 +43,57 @@
<% if @count -%>
<span id="badge_count" class="badge"><%= @count %></span>
<% end -%>
<%= current_user.time.strftime(@prefs.title_date_format) %>
<%= l(Date.today, :format => current_user.prefs.title_date_format) %>
</h1>
</div>
<div id="minilinks">
<%= link_to("Toggle notes", "#", {:accesskey => "S", :title => "Toggle all notes", :id => "toggle-notes-nav"}) %>
<%= link_to(t('layouts.toggle_notes'), "#", {:accesskey => "S", :title => t('layouts.toggle_notes_title'), :id => "toggle-notes-nav"}) %>
&nbsp;|&nbsp;
<%= link_to "Logout (#{current_user.display_name}) »", logout_path %>
<%= link_to( t('common.logout') + " (#{current_user.display_name}) »", logout_path) %>
</div>
<div id="navcontainer">
<ul class="sf-menu">
<li><%= navigation_link("Home", home_path, {:accesskey => "t", :title => "Home"} ) %></li>
<li><%= navigation_link("Starred", tag_path("starred"), :title => "See your starred actions" ) %></li>
<li><%= navigation_link("Projects", projects_path, {:accesskey=>"p", :title=>"Projects"} ) %></li>
<li><%= navigation_link("Tickler", tickler_path, {:accesskey =>"k", :title => "Tickler"} ) %></li>
<li><a href="#">Organize</a>
<li><%= navigation_link(t('layouts.navigation.home'), home_path, {:accesskey => "t", :title => t('layouts.navigation.home_title')} ) %></li>
<li><%= navigation_link(t('layouts.navigation.starred'), tag_path("starred"), :title => t('layouts.navigation.starred_title')) %></li>
<li><%= navigation_link(t('common.projects'), projects_path, {:accesskey=>"p", :title=>t('layouts.navigation.projects_title')} ) %></li>
<li><%= navigation_link(t('layouts.navigation.tickler'), tickler_path, {:accesskey =>"k", :title => t('layouts.navigation.tickler_title')} ) %></li>
<li><a href="#"><%= t('layouts.navigation.organize') %></a>
<ul>
<li><%= navigation_link( "Contexts", contexts_path, {:accesskey=>"c", :title=>"Contexts"} ) %></li>
<li><%= navigation_link( "Notes", notes_path, {:accesskey => "o", :title => "Show all notes"} ) %></li>
<li><%= navigation_link( "Repeating todos", {:controller => "recurring_todos", :action => "index"}, :title => "Manage recurring actions" ) %></li>
<li><%= navigation_link( t('common.contexts'), contexts_path, {:accesskey=>"c", :title=>t('layouts.navigation.contexts_title')} ) %></li>
<li><%= navigation_link( t('common.notes'), notes_path, {:accesskey => "o", :title => t('layouts.navigation.notes_title')} ) %></li>
<li><%= navigation_link( t('layouts.navigation.recurring_todos'), {:controller => "recurring_todos", :action => "index"}, :title => t('layouts.navigation.recurring_todos_title')) %></li>
</ul>
</li>
<li><a href="#">View</a>
<li><a href="#"><%= t('layouts.navigation.view') %></a>
<ul>
<li><%= navigation_link( "Calendar", calendar_path, :title => "Calendar of due actions" ) %></li>
<li><%= navigation_link( "Done", done_path, {:accesskey=>"d", :title=>"Completed"} ) %></li>
<li><%= navigation_link( "Feeds", {:controller => "feedlist", :action => "index"}, :title => "See a list of available feeds" ) %></li>
<li><%= navigation_link( "Statistics", {:controller => "stats", :action => "index"}, :title => "See your statistics" ) %></li>
<li><%= navigation_link( t('layouts.navigation.calendar'), calendar_path, :title => t('layouts.navigation.calendar_title')) %></li>
<li><%= navigation_link( t('layouts.navigation.completed_tasks'), done_path, {:accesskey=>"d", :title=>t('layouts.navigation.completed_tasks_title')} ) %></li>
<li><%= navigation_link( t('layouts.navigation.feeds'), {:controller => "feedlist", :action => "index"}, :title => t('layouts.navigation.feeds_title')) %></li>
<li><%= navigation_link( t('layouts.navigation.stats'), {:controller => "stats", :action => "index"}, :title => t('layouts.navigation.stats_title')) %></li>
</ul>
</li>
<li><a href="#">Admin</a>
<ul>
<li><%= navigation_link( "Preferences", preferences_path, {:accesskey => "u", :title => "Show my preferences"} ) %></li>
<li><%= navigation_link( "Export", {:controller => "data", :action => "index"}, {:accesskey => "i", :title => "Import and export data"} ) %></li>
<li><%= navigation_link( t('layouts.navigation.preferences'), preferences_path, {:accesskey => "u", :title => t('layouts.navigation.preferences_title')} ) %></li>
<li><%= navigation_link( t('layouts.navigation.export'), {:controller => "data", :action => "index"}, {:accesskey => "i", :title => t('layouts.navigation.export_title')} ) %></li>
<% if current_user.is_admin? -%>
<li><%= navigation_link("Manage users", users_path, {:accesskey => "a", :title => "Add or delete users"} ) %></li>
<li><%= navigation_link(t('layouts.navigation.manage_users'), users_path, {:accesskey => "a", :title => t('layouts.navigation.manage_users_title')} ) %></li>
<% end -%>
</ul>
</li>
<li><a href="#">?</a>
<ul>
<li><%= link_to 'Integrate Tracks', integrations_path %></li>
<li><%= link_to 'REST API Docs', rest_api_docs_path %></li>
<li><%= link_to t('layouts.navigation.integrations_'), integrations_path %></li>
<li><%= link_to t('layouts.navigation.api_docs'), rest_api_docs_path %></li>
</ul>
</li>
<li><%= navigation_link(image_tag("system-search.png", :size => "16X16", :border => 0), {:controller => "search", :action => "index"}, :title => "Search All Items" ) %></li>
<li><%= navigation_link(image_tag("system-search.png", :size => "16X16", :border => 0), {:controller => "search", :action => "index"}, :title => t('layouts.navigation.search')) %></li>
</ul>
</div>
<%= render_flash %>
</div>
<div id="content" class="<%= @controller.controller_name %>">
<% unless @controller_name == 'feed' or session['noexpiry'] == "on" -%>
<%= periodically_call_remote( :url => {:controller => "login", :action => "check_expiry"},
:frequency => (5*60)) %>
<% end -%>
<%= periodically_call_remote( :url => check_deferred_todos_path(:format => 'js'),
:method => :post,
:frequency => (10*60)) %>
<%= yield %>
</div>

View file

@ -0,0 +1 @@
window.location.href = '<%= login_path %>';

View file

@ -1 +0,0 @@
page.redirect_to :controller => 'login', :action => 'login'

View file

@ -0,0 +1,8 @@
<% if @session_expired
theLink = link_to(t('login.log_in_again'), :controller => "login", :action => "login")
message = I18n.t('login.session_time_out', :link => theLink)
theHtml = escape_javascript(content_tag(:div, message, :"class" => "warning"))
-%>
$('div#navcontainer').hide();
$('div#content').html('<%=theHtml%>');
<% end -%>

View file

@ -1,3 +0,0 @@
unless @msg == ""
page.replace_html "info", content_tag("div", @msg + link_to("log in again.", :controller => "login", :action => "login"), "class" => "warning")
end

View file

@ -4,30 +4,30 @@
show_cas_form = auth_schemes.include?('cas')
-%>
<div title="Account login" id="loginform" class="form">
<div title="<%= t('login.account_login') %>" id="loginform" class="form">
<%= render_flash %>
<h3>Please log in to use Tracks:</h3>
<h3><%= t('login.please_login') %>:</h3>
<% if show_database_form %>
<div id="database_auth_form" style="display:<%=(@prefered_auth.eql?('database')) ? "block" : "none"%>">
<% form_tag :action=> 'login' do %>
<table>
<tr>
<td><label for="user_login">Login:</label></td>
<td><label for="user_login"><%= User.human_attribute_name('login') %>:</label></td>
<td><input type="text" name="user_login" id="user_login" value="" class="login_text" /></td>
</tr>
<tr>
<td><label for="user_password">Password:</label></td>
<td><label for="user_password"><%= User.human_attribute_name('password') %>:</label></td>
<td><input type="password" name="user_password" id="user_password" class="login_text" /></td>
</tr>
<tr>
<td><label for="user_noexpiry">Stay logged in:</label></td>
<td><label for="user_noexpiry"><%= t('login.user_no_expiry') %>:</label></td>
<td><input type="checkbox" name="user_noexpiry" id="user_noexpiry" checked /></td>
</tr>
<tr>
<td></td>
<td><input type="submit" name="login" value="Sign In &#187;" class="primary" /></td>
<td><input type="submit" name="login" value="<%= t('login.sign_in') %> &#187;" class="primary" /></td>
</tr>
</table>
<% end %>
@ -39,16 +39,16 @@
<% form_tag :action=> 'login' do %>
<table>
<tr>
<td><label for="openid_url">Identity URL:</label></td>
<td><label for="openid_url"><%= User.human_attribute_name('open_id_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><label for="user_noexpiry">Stay logged in:</label></td>
<td><label for="user_noexpiry"><%= t('login.user_no_expiry') %>:</label></td>
<td><input type="checkbox" name="user_noexpiry" id="user_noexpiry" checked /></td>
</tr>
<tr>
<td></td>
<td><input type="submit" name="login" value="Sign In &#187;" class="primary" /></td>
<td><input type="submit" name="login" value="<%= t('login.sign_in') %> &#187;" class="primary" /></td>
</tr>
</table>
<% end %>
@ -61,15 +61,15 @@
<tr>
<td>
<% if @username && @user%>
<p>Hello, <%= @username %>! You are authenticated.</p>
<p><%= t('login.cas_logged_in_greeting', :username => @username) %></p>
<% elsif @username %>
<p>Hello, <%= @username %>! You do not have an account on Tracks.
<p><%= t('login.cas_no_user_found', :username => @username) %>
<%if SITE_CONFIG['open_signups']%>
If you like to request on please go here to <%= link_to "Request Account" , signup_url %>
<%= t('login.cas_create_account', :signup_link => link_to(t('login.cas_signup_link'), signup_url)) %>
<%end%>
</p>
<% else %>
<p><%= link_to("CAS Login", login_cas_url) %> </p>
<p><%= link_to(t('login.cas_login'), login_cas_url) %> </p>
<% end %>
</td>
</tr>
@ -78,9 +78,9 @@
<% end %>
</div>
<% if show_openid_form %><p id="alternate_auth_openid" class="alternate_auth">or, <a href="#" onclick="Login.showOpenid();return false;">login with an OpenId</a></p><% end %>
<% if show_database_form %><p id="alternate_auth_database" class="alternate_auth">or, <a href="#" onclick="Login.showDatabase();return false;">go back to the standard login</a></p><% end %>
<% if show_cas_form %><p id="alternate_auth_cas" class="alternate_auth">or, <a href="#" onclick="Login.showCAS();return false;">go to the CAS</a></p><% end %>
<% if show_openid_form %><p id="alternate_auth_openid" class="alternate_auth"><%= t('login.option_separator') %> <a href="#" onclick="Login.showOpenid();return false;"><%= t('login.login_with_openid') %></a></p><% end %>
<% if show_database_form %><p id="alternate_auth_database" class="alternate_auth"><%= t('login.option_separator') %> <a href="#" onclick="Login.showDatabase();return false;"><%= t('login.login_standard') %></a></p><% end %>
<% if show_cas_form %><p id="alternate_auth_cas" class="alternate_auth"><%= t('login.option_separator') %> <a href="#" onclick="Login.showCAS();return false;"><%= t('login.login_cas')%></a></p><% end %>
<script type="text/javascript">
function showPreferredAuth() {

View file

@ -3,31 +3,31 @@
show_openid_form = auth_schemes.include?('open_id')
-%>
<div title="Account login" id="loginform" class="form">
<div title="<%= t('login.account_login') %>" id="loginform" class="form">
<%= render_flash %>
<h3>Please log in to use Tracks:</h3>
<h3><%= t('login.please_login') %>:</h3>
<% if show_database_form %>
<div id="database_auth_form">
<% form_tag login_path(:format => 'm') do %>
<table>
<tr>
<td><label for="user_login">Login:</label></td>
<td><label for="user_login"><%= User.human_attribute_name('login') %>:</label></td>
<td><input type="text" name="user_login" id="user_login" value="" class="login_text" /></td>
</tr>
<tr>
<td><label for="user_password">Password:</label></td>
<td><label for="user_password"><%= User.human_attribute_name('password') %>:</label></td>
<td><input type="password" name="user_password" id="user_password" class="login_text" /></td>
</tr>
<tr>
<td><label for="user_noexpiry">Stay logged in:</label></td>
<td><label for="user_noexpiry"><%= t('login.user_no_expiry') %>:</label></td>
<td><input type="checkbox" name="user_noexpiry" id="user_noexpiry" checked="checked" /></td>
</tr>
<tr>
<td>&nbsp;</td>
<td><input type="submit" name="login" value="Sign In &#187;" class="primary" /></td>
<td><input type="submit" name="login" value="<%= t('login.sign_in') %> &#187;" class="primary" /></td>
</tr>
</table>
<% end %>
@ -36,22 +36,22 @@
<% if show_openid_form %>
<h4>...or login with an Open ID:</h4>
<h4><%= t('login.mobile_use_openid') %>:</h4>
<div id="openid_auth_form">
<% form_tag login_path(:format => 'm') do %>
<table>
<tr>
<td width="100px"><label for="openid_url">Identity URL:</label></td>
<td width="100px"><label for="openid_url"><%= User.human_attribute_name('open_id_url') %>:</label></td>
<td width="100px"><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"><label for="user_noexpiry"><%= t('login.user_no_expiry') %>:</label></td>
<td width="100px"><input type="checkbox" name="user_noexpiry" id="user_noexpiry" checked /></td>
</tr>
<tr>
<td width="100px"></td>
<td><input type="submit" name="login" value="Sign In &#187;" class="primary" /></td>
<td><input type="submit" name="login" value="<%= t('login.sign_in') %> &#187;" class="primary" /></td>
</tr>
</table>
<% end %>

View file

@ -4,10 +4,10 @@
</div>
<div class="mobile_note_info">
<br/>
<%= link_to("In: " + note.project.name, project_path(note.project, :format => 'm')) %>
Created: <%= format_date(note.created_at) %>
<%= link_to(t('notes.note_location_link') + note.project.name, project_path(note.project, :format => 'm')) %>
<%= Note.human_attribute_name('created_at') %>: <%= format_date(note.created_at) %>
<% if note.updated_at? -%>
&nbsp;|&nbsp;Modified: <%= format_date(note.updated_at) %>
&nbsp;|&nbsp;<%= Note.human_attribute_name('updated_at') %>: <%= format_date(note.updated_at) %>
<% end -%>
</div>
<% note = nil -%>

View file

@ -0,0 +1,15 @@
<div class="container" id="note-<%= note.id %>-wrapper">
<div id="<%= dom_id(note, 'container') %>">
<h2><%= link_to(t('notes.note_header', :id => note.id.to_s), note, :title => t('notes.note_link_title', :id => note.id.to_s)) %></h2>
<div class="project_notes" id="<%= dom_id(note) %>">
<%= render :partial => "notes/note_details", :object => note %>
</div>
<div id="<%= dom_id(note, 'edit') %>" class="note-edit-form" style="display:none;">
<%= render :partial => "notes/note_edit_form", :object => note %>
</div>
</div>
</div>

View file

@ -0,0 +1,16 @@
<% note = note_details -%>
<div class="note_boby"><%= format_note(note.body) %></div>
<div class="note_footer">
<%= link_to_delete_note(note, image_tag( "blank.png",:title => t('notes.delete_item_title'), :class=>"delete_item")) %> &nbsp;
<%= link_to_edit_note(note, image_tag( "blank.png", :title => t('notes.edit_item_title'), :class=>"edit_item") ) %>
| <%= link_to("In: " + note.project.name, note.project, :class=>"footer_link" ) %>&nbsp;|&nbsp;
<%= Note.human_attribute_name('created_at') %>: <%= format_date(note.created_at) %>
<% if note.updated_at? -%>
&nbsp;|&nbsp;<%= Note.human_attribute_name('updated_at') %>: <%= format_date(note.updated_at) %>
<% end -%>
</div>

View file

@ -1,6 +1,29 @@
<% @note = note_edit_form %>
<%= hidden_field( "note", "project_id" ) %>
<%= text_area( "note", "body", "cols" => 70, "rows" => 15, "tabindex" => 1 ) %>
<br /><br />
<input type="submit" value="Update" tabindex="2" />
<% @note = nil %>
<%
submit_text ||= t('common.update')
form_for(note_edit_form, :html => {
:id => dom_id(note_edit_form, 'edit_form'),
:class => "inline-form edit-note-form"}) do |f|
-%>
<div id="error_status"><%= error_messages_for("note") %></div>
<%= f.hidden_field( "project_id" ) %>
<%= f.text_area( "body", "cols" => 70, "rows" => 15, "tabindex" => 1 ) %>
<div class="submit_box">
<div class="widgets">
<button type="submit" class="positive" id="<%= dom_id(note_edit_form, 'submit') %>" tabindex="15">
<%=image_tag("accept.png", :alt => "") %>
<%= submit_text %>
</button>
<a href="" class="negative" id="neg_<%=dom_id(note_edit_form, 'edit_form')%>">
<%=image_tag("cancel.png", :alt => "") %>
<%= t 'common.cancel' %>
</a>
</div>
</div>
<br/><br/>
<% end -%>

View file

@ -1,36 +0,0 @@
<% note = notes -%>
<div id="<%= dom_id(note, 'container') %>">
<h2><%= link_to("Note #{note.id}", note_path(note), :title => "Show note #{note.id}" ) %></h2>
<div class="project_notes" id="<%= dom_id(note) %>">
<%= format_note(note.body) %>
<div class="note_footer">
<%= link_to_remote(
image_tag("blank.png", :title =>"Delete this note", :class=>"delete_item", :id => "delete_note_"+note.id.to_s),
:url => note_path(note),
:html => {:class => 'delete_note', :title => "delete note"},
:method => :delete,
:confirm => "Are you sure that you want to delete the note \'#{note.id.to_s}\'?",
:before => visual_effect(:fade, dom_id(note, 'container'))) -%>&nbsp;
<%= link_to_function(image_tag( "blank.png", :title => "Edit item", :class=>"edit_item"),
"$('##{dom_id(note)}').toggle(); $('##{dom_id(note, 'edit')}').show(); $('##{dom_id(note, 'edit_form')} textarea').focus();" ) + " | " %>
<%= link_to("In: " + note.project.name, project_path(note.project), :class=>"footer_link" ) %>&nbsp;|&nbsp;
Created: <%= format_date(note.created_at) %>
<% if note.updated_at? -%>
&nbsp;|&nbsp;Modified: <%= format_date(note.updated_at) %>
<% end -%>
</div>
</div>
<div id="<%= dom_id(note, 'edit') %>" class="edit-form" style="display:none;">
<% form_remote_tag :url => note_path(note),
:method => :put,
:html => { :id => dom_id(note, 'edit_form'), :class => "inline-form" },
:update => dom_id(note, 'container'),
:complete => visual_effect(:appear, dom_id(note, 'container')) do -%>
<%= render :partial => "notes/note_edit_form", :object => note %>
<% end -%>
</div>
</div>
<% note = nil -%>

View file

@ -1,6 +1,11 @@
<% note = notes_summary -%>
<div class="note_wrapper" id="<%= dom_id(note) %>">
<%= link_to( image_tag("blank.png", :border => 0), note_path(note), :title => "Show note", :class => "link_to_notes icon") %>&nbsp;
<%= link_to(
image_tag("blank.png", :border => 0),
note,
:title => t('notes.show_note_title'),
:class => "link_to_notes icon",
:id => dom_id(note, "link")) %>&nbsp;
<%= rendered_note(note) %>
</div>
<% note = nil -%>

View file

@ -0,0 +1,25 @@
<% if @saved -%>
TracksPages.hide_errors();
add_note();
clear_form();
<% else -%>
TracksPages.show_errors(html_for_error_messages());
<% end -%>
function add_note() {
$('div#notes').append(html_for_note_summary());
$('#empty-n').hide();
}
function clear_form() {
$('#new-note').hide();
$('#edit-note-form').clearForm();
}
function html_for_error_messages() {
return "<%= escape_javascript(error_messages_for('project')) %>";
}
function html_for_note_summary() {
return "<%= @saved ? escape_javascript(render(:partial => 'notes_summary', :object => @note)) : "" %>";
}

View file

@ -0,0 +1,10 @@
remove_deleted_note();
TracksPages.set_page_badge(<%=@down_count%>);
TracksPages.page_notify('notice', "<%= t('notes.deleted_note', :id => @note.id)%>", 5);
function remove_deleted_note() {
$('div#note-<%=@note.id%>-wrapper').slideUp(1000,
function() {
$('div#note-<%=@note.id%>-wrapper').remove();
});
}

View file

@ -1,3 +0,0 @@
page.notify :notice, "Deleted note '#{@note.id}'", 5.0
page['badge_count'].replace_html @count
page.hide "busy"

View file

@ -1,11 +1,7 @@
<div id="display_box_projects">
<% if @all_notes.empty? -%>
<div class="message"><p>Currently there are no notes: add notes to projects from individual project pages.</p></div>
<div class="message"><p><%= t('notes.no_notes_available') %></p></div>
<% else -%>
<% for notes in @all_notes -%>
<div class="container" id="note-<%= notes.id %>-wrapper">
<%= render :partial => 'notes', :object => notes %>
</div>
<% end -%>
<%= render :partial => @all_notes %>
<% end -%>
</div>

View file

@ -1,5 +1,3 @@
<div id="display_box_projects">
<div class="container" id="note-<%= @note.id %>-wrapper">
<%= render :partial => 'notes', :object => @note %>
</div>
<%= render :partial => @note %>
</div>

View file

@ -0,0 +1,29 @@
<% if @saved -%>
TracksPages.hide_errors();
TracksPages.page_notify('notice', 'Note <%=@note.id %> saved', 5);
replace_note_form_with_updated_note();
<% else -%>
TracksPages.show_errors(html_for_error_messages());
<% end %>
function replace_note_form_with_updated_note() {
$('#<%= dom_id(@note, 'edit')%>').fadeOut(250, function() {
$('#<%= dom_id(@note, 'edit')%>').html(html_for_updated_note_form());
$('div.project_notes#<%= dom_id(@note)%>').html(html_for_updated_note_details());
$('#<%= dom_id(@note)%>').fadeIn(500);
});
}
function html_for_error_messages() {
return "<%= escape_javascript(error_messages_for('note')) %>";
}
function html_for_updated_note_form(){
return "<%= escape_javascript(render(:partial => 'note_edit_form', :object => @note)) %>";
}
function html_for_updated_note_details(){
return "<%= escape_javascript(render(:partial => 'note_details', :object => @note)) %>";
}

View file

@ -0,0 +1,22 @@
<h2>Help on preferences</h2>
<ul>
<li><strong>first name and last name:</strong> Used for display purposes if set</li>
<li><strong>date format:</strong> the format in which you'd like dates to be shown. For example, for the date 31st January 2006, %d/%m/%Y will show 31/01/2006, %b-%e-%y will show Jan-31-06. See the <a href="http://uk2.php.net/strftime" title="PHP strftime manual">strftime manual</a> for more formatting options for the date.</li>
<li><strong>title date format:</strong> same as above, but for the big date at the top of each page.</li>
<li><strong>time zone:</strong> your local time zone</li>
<li><strong>week starts:</strong> day of the week shown as the start of the week on the popup calendar.</li>
<li><strong>due style:</strong> style in which due dates are shown, e.g. "Due in 3 days", "Due on Wednesday"</li>
<li><strong>show completed projects in sidebar:</strong> whether or not projects marked as complete are shown in the sidebar on the home page and elsewhere</li>
<li><strong>show hidden contexts in sidebar:</strong> whether or not contexts marked as hidden are shown in the sidebar on the home page and elsewhere</li>
<li><strong>show project on todo done:</strong> whether or not to redirect to the project page when an action associated with a project is marked complete</li>
<% if current_user.is_admin? %>
<li><strong>admin email:</strong> email address for the admin user of Tracks (displayed on the signup page for users to contact to obtain an account)</li>
<% end %>
<li><strong>staleness starts:</strong> the number of days before items with no due date get marked as stale (with a yellow highlight)</li>
<li><strong>show number completed:</strong> number of completed actions to show on the page. If you set this to zero, the completed actions box will not be shown on the home page or on the individual context or project pages. You can still see all your completed items by clicking the 'Done' link in the navigation bar at the top of each page.</li>
<li><strong>refresh:</strong> automatic refresh interval for each of the pages (in minutes)</li>
<li><strong>verbose action descriptor:</strong> when true, show project/context name in action listing; when false show [P]/[C] with tool tips</li>
<li><strong>mobile todos per page:</strong> the maximum number of actions to show on a single page in the mobile view</li>
<li><strong>From email:</strong> the email address you use for sending todos as email or SMS messages to your Tracks account</li>
<li><strong>Default email context:</strong> the context to which tasks sent in via email or SMS should be added</li>
</ul>

View file

@ -1,43 +1,22 @@
<div id="display_box" class="container context">
<h2>Help on preferences</h2>
<ul>
<li><strong>first name and last name:</strong> Used for display purposes if set</li>
<li><strong>date format:</strong> the format in which you'd like dates to be shown. For example, for the date 31st January 2006, %d/%m/%Y will show 31/01/2006, %b-%e-%y will show Jan-31-06. See the <a href="http://uk2.php.net/strftime" title="PHP strftime manual">strftime manual</a> for more formatting options for the date.</li>
<li><strong>title date format:</strong> same as above, but for the big date at the top of each page.</li>
<li><strong>time zone:</strong> your local time zone</li>
<li><strong>week starts:</strong> day of the week shown as the start of the week on the popup calendar.</li>
<li><strong>due style:</strong> style in which due dates are shown, e.g. "Due in 3 days", "Due on Wednesday"</li>
<li><strong>show completed projects in sidebar:</strong> whether or not projects marked as complete are shown in the sidebar on the home page and elsewhere</li>
<li><strong>show hidden contexts in sidebar:</strong> whether or not contexts marked as hidden are shown in the sidebar on the home page and elsewhere</li>
<li><strong>show project on todo done:</strong> whether or not to redirect to the project page when an action associated with a project is marked complete</li>
<% if current_user.is_admin? %>
<li><strong>admin email:</strong> email address for the admin user of Tracks (displayed on the signup page for users to contact to obtain an account)</li>
<% end %>
<li><strong>staleness starts:</strong> the number of days before items with no due date get marked as stale (with a yellow highlight)</li>
<li><strong>show number completed:</strong> number of completed actions to show on the page. If you set this to zero, the completed actions box will not be shown on the home page or on the individual context or project pages. You can still see all your completed items by clicking the 'Done' link in the navigation bar at the top of each page.</li>
<li><strong>refresh:</strong> automatic refresh interval for each of the pages (in minutes)</li>
<li><strong>verbose action descriptor:</strong> when true, show project/context name in action listing; when false show [P]/[C] with tool tips</li>
<li><strong>mobile todos per page:</strong> the maximum number of actions to show on a single page in the mobile view</li>
<li><strong>From email:</string> the email address you use for sending todos as email or SMS messages to your Tracks account</li>
<li><string>Default email context:</string> the context to which tasks sent in via email or SMS should be added</li>
</ul>
<%= render :partial => 'help' %>
</div>
<div id="input_box" class="container context">
<% form_tag :action => 'update' do %>
<table>
<tr>
<td><label>first name:</label></td>
<td><label><%= User.human_attribute_name('first_name') %></label></td>
<td><%= text_field 'user', 'first_name' %></td>
</tr>
<tr>
<td><label>last name:</label></td>
<td><label><%= User.human_attribute_name('last_name') %></label></td>
<td><%= text_field 'user', 'last_name' %></td>
</tr>
<%
def table_row(pref_name, nowrap_label = false, &block)
nowrap_attribute = nowrap_label ? ' nowrap="nowrap"' : ''
s = %Q|<tr>\n<td#{nowrap_attribute}><label>#{pref_name.gsub(/_/,' ')}:</label></td>\n<td>\n|
s = %Q|<tr>\n<td#{nowrap_attribute}><label>#{Preference.human_attribute_name(pref_name)}:</label></td>\n<td>\n|
s << yield
s << "\n</td></tr>"
s
@ -51,12 +30,13 @@
table_row(pref_name, nowrap_label) { text_field('prefs', pref_name) }
end
%>
<%= row_with_select_field('locale', I18n.available_locales) %>
<%= row_with_text_field('date_format') %>
<%= row_with_text_field('title_date_format') %>
<%= table_row('time_zone', false) { time_zone_select('prefs','time_zone') } %>
<%= row_with_select_field("week_starts", Preference.day_number_to_name_map.invert.sort{|a,b| a[1]<=>b[1]})%>
<%= row_with_select_field("due_style", [['Due in ___ days',Preference.due_styles[:due_in_n_days]],['Due on _______',Preference.due_styles[:due_on]]]) %>
<%= row_with_select_field("week_starts", (0..6).to_a.map {|num| [t('date.day_names')[num], num] }) %>
<%= row_with_select_field("due_style", [[t('models.preference.due_styles')[0],Preference.due_styles[:due_in_n_days]],[t('models.preference.due_styles')[1],Preference.due_styles[:due_on]]]) %>
<%= row_with_select_field("show_completed_projects_in_sidebar") %>
<%= row_with_select_field("show_hidden_projects_in_sidebar") %>
<%= row_with_select_field("show_hidden_contexts_in_sidebar") %>
@ -71,8 +51,8 @@
<%= row_with_text_field("sms_email") %>
<%= table_row("sms_context", false) { select('prefs', 'sms_context_id', current_user.contexts.map{|c| [c.name, c.id]}) } %>
<tr><td><%= submit_tag "Update" %></td>
<td><%= link_to "Cancel", :action => 'index' %></td>
<tr><td><%= submit_tag t('common.update') %></td>
<td><%= link_to t('common.cancel'), :action => 'index' %></td>
</tr>
</table>
<% end %>

View file

@ -1,66 +1,67 @@
<div id="single_box" class="container context prefscontainer">
<h2>Your preferences</h2>
<h2><%= t('preferences.title') %></h2>
<ul id="prefs">
<li>First name: <span class="highlight"><%= current_user.first_name %></span></li>
<li>Last name: <span class="highlight"><%= current_user.last_name %></span></li>
<li>Date format: <span class="highlight"><%= prefs.date_format %></span> Your current date: <%= format_date(current_user.time) %></li>
<li>Title date format: <span class="highlight"><%= prefs.title_date_format %></span> Your current title date: <%= current_user.time.strftime(prefs.title_date_format) %></li>
<li>Time zone: <span class="highlight"><%= prefs.time_zone %></span> Your current time: <%= current_user.time.strftime('%I:%M %p') %></li>
<li>Week starts on: <span class="highlight"><%= Preference.day_number_to_name_map[prefs.week_starts] %></span></li>
<li>Show the last <span class="highlight"><%= prefs.show_number_completed %></span> completed items</li>
<li>Show completed projects in sidebar: <span class="highlight"><%= prefs.show_completed_projects_in_sidebar %></span></li>
<li>Show hidden projects in sidebar: <span class="highlight"><%= prefs.show_hidden_projects_in_sidebar %></span></li>
<li>Show hidden contexts in sidebar: <span class="highlight"><%= prefs.show_hidden_contexts_in_sidebar %></span></li>
<li>Go to project page on todo complete: <span class="highlight"><%= prefs.show_project_on_todo_done %></span></li>
<li>Staleness starts after <span class="highlight"><%= prefs.staleness_starts %></span> days</li>
<li>Due style: <span class="highlight">
<li><%= User.human_attribute_name('first_name') %>: <span class="highlight"><%= current_user.first_name %></span></li>
<li><%= User.human_attribute_name('last_name') %>: <span class="highlight"><%= current_user.last_name %></span></li>
<li><%= Preference.human_attribute_name('date_format') %>: <span class="highlight"><%= current_user.prefs.date_format %></span> Your current date: <%= format_date(current_user.time) %></li>
<li><%= Preference.human_attribute_name('locale') %>: <span class="highlight"><%= current_user.prefs.locale %></span></li>
<li><%= Preference.human_attribute_name('title_date_format') %>: <span class="highlight"><%= current_user.prefs.title_date_format %></span> Your current title date: <%= current_user.time.strftime(current_user.prefs.title_date_format) %></li>
<li><%= Preference.human_attribute_name('time_zone') %>: <span class="highlight"><%= current_user.prefs.time_zone %></span> Your current time: <%= current_user.time.strftime('%I:%M %p') %></li>
<li><%= Preference.human_attribute_name('week_starts') %>: <span class="highlight"><%= t('date.day_names')[current_user.prefs.week_starts] %></span></li>
<li><%= t('preferences.show_number_completed', :number=> "<span class=\"highlight\">#{current_user.prefs.show_number_completed}</span>")%></li>
<li><%= Preference.human_attribute_name('show_completed_projects_in_sidebar') %>: <span class="highlight"><%= current_user.prefs.show_completed_projects_in_sidebar %></span></li>
<li><%= Preference.human_attribute_name('show_hidden_projects_in_sidebar') %>: <span class="highlight"><%= current_user.prefs.show_hidden_projects_in_sidebar %></span></li>
<li><%= Preference.human_attribute_name('show_hidden_contexts_in_sidebar') %>: <span class="highlight"><%= current_user.prefs.show_hidden_contexts_in_sidebar %></span></li>
<li><%= Preference.human_attribute_name('show_project_on_todo_done') %>: <span class="highlight"><%= current_user.prefs.show_project_on_todo_done %></span></li>
<li><%= t('preferences.staleness_starts_after', :days => "<span class=\"highlight\">#{current_user.prefs.staleness_starts}</span>") %></li>
<li><%= Preference.human_attribute_name('due_style') %>: <span class="highlight">
<% if prefs.due_style == Preference.due_styles[:due_in_n_days] %>
Due in ___ days
<%= t('models.preference.due_styles')[0] %>
<% else %>
Due on ________
<%= t('models.preference.due_styles')[1] %>
<% end %>
</span></li>
<% if current_user.is_admin? %>
<li>Admin email: <span class="highlight"><%= prefs.admin_email %></span></li>
<li><%= Preference.human_attribute_name('admin_email') %>: <span class="highlight"><%= current_user.prefs.admin_email %></span></li>
<% end %>
<li>Refresh interval (in minutes): <span class="highlight"><%= prefs.refresh %></span></li>
<li>Verbose action descriptors: <span class="highlight"><%= prefs.verbose_action_descriptors %></span></li>
<li>Actions per page (Mobile View): <span class="highlight"><%= prefs.mobile_todos_per_page %></span></li>
<li>From email: <span class="highlight"><%= prefs.sms_email %></span></li>
<li>Default email context: <span class="highlight"><%= prefs.sms_context.nil? ? "None" : prefs.sms_context.name %></span></li>
<li><%= Preference.human_attribute_name('refresh') %>: <span class="highlight"><%= current_user.prefs.refresh %></span></li>
<li><%= Preference.human_attribute_name('verbose_action_descriptors') %>: <span class="highlight"><%= current_user.prefs.verbose_action_descriptors %></span></li>
<li><%= Preference.human_attribute_name('mobile_todos_per_page') %>: <span class="highlight"><%= current_user.prefs.mobile_todos_per_page %></span></li>
<li><%= Preference.human_attribute_name('sms_email') %>: <span class="highlight"><%= current_user.prefs.sms_email %></span></li>
<li><%= Preference.human_attribute_name('sms_context') %>: <span class="highlight"><%= current_user.prefs.sms_context.nil? ? t('preferences.sms_context_none') : current_user.prefs.sms_context.name %></span></li>
</ul>
<div class="actions">
<%= link_to "Edit preferences &raquo;", { :controller => 'preferences', :action => 'edit'}, :class => 'edit_link' %>
<%= link_to t('preferences.edit_preferences') + " &raquo;", { :controller => 'preferences', :action => 'edit'}, :class => 'edit_link' %>
</div>
<h2>Your token</h2>
<h2><%= t('preferences.token_header') %></h2>
<div id="token_area">
<div class="description">Token (for feeds and API use):</div>
<div id="token><span class="highlight"><%= current_user.token %></span></div>
<div class="description"><%= t('preferences.token_description') %>:</div>
<div id="token"><span class="highlight"><%= current_user.token %></span></div>
<div class="token_regenerate">
<%= button_to "Generate a new token", refresh_token_user_path(current_user),
:confirm => "Are you sure? Generating a new token will replace the existing one and break any external usages of this token." %>
<%= button_to t('preferences.generate_new_token'), refresh_token_user_path(current_user),
:confirm => t('preferences.generate_new_token_confirm') %>
</div>
</div>
<h2>Your authentication</h2>
<h2><%= t('preferences.authentication_header') %></h2>
<div id="authentication_area">
<% if Tracks::Config.auth_schemes.length > 1 %>
<p>Your authentication type is <span class="highlight"><%= current_user.auth_type %></span>.
<p><%= t('preferences.current_authentication_type', :auth_type => "<span class=\"highlight\">#{current_user.auth_type}</span>") %>.</p>
<div class="actions">
<%= link_to "Change your authentication type &raquo;", change_auth_type_user_path(current_user), :class => 'edit_link' %>
<%= link_to(t('preferences.change_authentication_type') + " &raquo;", change_auth_type_user_path(current_user), :class => 'edit_link') %>
</div>
<% end %>
<% if current_user.auth_type == 'database' %>
<div class="actions">
<%= link_to 'Change your password &raquo;', change_password_user_path(current_user) %>
<%= link_to(t('preferences.change_password') + ' &raquo;', change_password_user_path(current_user)) %>
</div>
<% end %>
<% if current_user.auth_type == 'open_id' %>
<p>Your Open ID URL is <span class="highlight"><%= current_user.open_id_url %></span>.
<p><%= t('preferences.open_id_url') %> <span class="highlight"><%= current_user.open_id_url %></span>.</p>
<div class="actions">
<%= link_to 'Change Your Identity URL &raquo;', change_auth_type_user_path(current_user) %></p>
<%= link_to(t('preferences.change_identity_url') + ' &raquo;', change_auth_type_user_path(current_user)) %>
</div>
<% end %>
</div>

View file

@ -0,0 +1,40 @@
<div id="project_new_project_container">
<div id="toggle_project_link" class="hide_form">
<a id="toggle_project_new" href="#" title="<%= t('projects.hide_form_title') %>" accesskey="n">&laquo; <%= t('projects.hide_form') %></a>
</div>
<div id="project_new" class="project_new" style="display:block">
<% form_for(@new_project, :html => {:id => 'project_form',:name=>'project',:class => "inline-form", :method => :post }) do -%>
<div id="error_status"><%= error_messages_for("project") %></div>
<label for="project_name"><%= Project.human_attribute_name(:name) %>:</label><br />
<%= text_field 'project', 'name', "tabindex" => 1 %><br />
<label for="project_description"><%= Project.human_attribute_name(:description) %> (<%= t('common.optional') %>):</label><br />
<%= text_area 'project', 'description', "cols" => 30, "rows" => 4, "tabindex" => 2 %><br />
<% unless @contexts.empty? -%>
<label for="default_context_name"><%= Project.human_attribute_name(:default_context_name) %> (<%= t('common.optional') %>):</label><br />
<%= text_field_tag("project[default_context_name]", @new_project.default_context.name, :tabindex => 3) %>
<br />
<% end -%>
<label for="default_tags"><%= Project.human_attribute_name(:default_tags) %> (<%= t('common.optional') %>):</label><br />
<%= text_field_tag("project[default_tags]", @new_project.default_tags, :tabindex => 4) %>
<br/>
<div class="submit_box">
<div class="widgets">
<button type="submit" class="positive" id="project_new_project_submit">
<%= image_tag("accept.png", :alt => "") + t('projects.add_project') %>
</button>
</div>
</div>
<input id="go_to_project" type="checkbox" tabindex="5" name="go_to_project"/><label for="go_to_project"><%= t('projects.to_new_project_page') %></label><br />
<% end -%>
</div>
</div>

View file

@ -5,7 +5,7 @@
<% end -%>
<%= project.name -%></h2>
<div id="<%= dom_id(project, "container")%>">
<%= render :partial => "projects/project_settings", :locals => { :project => project, :collapsible => collapsible } %>
<%= render :partial => "projects/project_settings", :object => project, :locals => { :collapsible => collapsible } %>
</div>
</div>

View file

@ -2,8 +2,12 @@
project = project_form
%>
<% form_remote_tag(:url => project_path(project), :html => { :id => dom_id(project, 'edit_form'), :class => "inline-form "+dom_id(project, 'edit_form')+"-edit-project-form", :method => :put }) do -%>
<div id="error_status"><%= error_messages_for("project") %></div>
<% form_for(project, :html => {
:id => dom_id(project, 'edit_form'),
:class => "inline-form edit-project-form",
:method => :put }) do
-%>
<div id="edit_error_status"><%= error_messages_for("project") %></div>
<%= source_view_tag( @source_view ) -%>
<label for="project_name">Name:</label><br/>
@ -39,6 +43,6 @@ project = project_form
</div>
</div>
<br/><br/>
<% end -%>
<%
end
-%>

View file

@ -1,40 +1,27 @@
<% project = project_listing
<%
project = project_listing
suppress_drag_handle ||= false
suppress_edit_button ||= false
-%>
<div id="<%= dom_id(project, "container") %>" class="list">
<div id="<%= dom_id(project) %>" class="project sortable_row" style="display:''">
<div id="<%= dom_id(project) %>" class="project sortable_row" style="display:block">
<% unless suppress_drag_handle -%>
<div class="position">
<span class="handle">DRAG</span>
<span class="handle"><%= t('common.drag_handle') %></span>
</div>
<% end -%>
<div class="data">
<%= link_to_project( project ) %><%= " (" + count_undone_todos_and_notes_phrase(project,"actions") + ")" %>
</div>
<div class="buttons">
<span class="grey"><%= project.current_state.to_s.upcase %></span>
<a class="delete_project_button"
href="<%= project_path(project, :format => 'js') %>"
title="delete the project '<%= project.name %>'"><%= image_tag( "blank.png",
:title => "Delete project",
:class=>"delete_item") %></a>
<% unless suppress_edit_button -%>
<%= link_to_remote(
image_tag( "blank.png", :title => "Edit project", :class=>"edit_item"),
:url => {:controller => 'projects', :action => 'edit', :id => project.id},
:method => 'get',
:with => "'_source_view=#{@source_view}'",
:before => "$('#{dom_id(project)}').block({message:null});",
:complete => "$('#{dom_id(project)}').unblock();enable_rich_interaction();",
:html => {:id => "link_edit_#{dom_id(project)}"}
) %>
<% end -%>
<%= link_to_delete_project(project, image_tag( "blank.png", :title => t('projects.delete_project_title'), :class=>"delete_item")) %>
<%= suppress_edit_button ? "" : link_to_edit_project(project, image_tag( "blank.png", :title => t('projects.edit_project_title'), :class=>"edit_item")) %>
</div>
</div>
<div id="<%= dom_id(project, 'edit') %>" class="edit-form" style="display:none;">
</div>
<div id="<%= dom_id(project, 'edit') %>" class="edit-form" style="display:none;"></div>
</div>

View file

@ -1,3 +1,4 @@
<% project = project_settings -%>
<div id="<%= dom_id(project) %>" class="project">
<div class="project_settings">This project
<% if project.completed? -%>has been marked as completed
@ -14,15 +15,7 @@
<% else -%>
'<%= project.default_tags -%>' as the default tags.
<% end -%>
<%= link_to_remote(
"Edit Project Settings",
:url => {:controller => 'projects', :action => 'edit', :id => project.id},
:method => 'get',
:with => "'_source_view=#{@source_view}'",
:before => "$('#{dom_id(project)}').block({message: null});",
:complete => "$('#{dom_id(project)}').unblock();enable_rich_interaction();",
:html => {:id => "link_edit_#{dom_id(project)}"}
) %>
<%= link_to_edit_project(project, "Edit Project Settings") %>
</div>
<% unless project.description.blank? -%>
<div class="project_description"><%= format_note(project.description) %></div>

View file

@ -1,12 +1,12 @@
<div class="project-state-group" id="list-<%= state %>-projects-container" <%= " style=\"display:none\"" if project_state_group.empty? %>>
<h2><span id="<%= state %>-projects-count" class="badge"><%= project_state_group.length %></span><%= state.titlecase %> Projects</h2>
<div class="menu_sort"><span class="sort_separator">Sort&nbsp;</span>
<h2><span id="<%= state %>-projects-count" class="badge"><%= project_state_group.length %></span><%= t('states.'+state+'_plural' )%> <%= t('common.projects') %></h2>
<div class="menu_sort"><span class="sort_separator"><%= t('common.sort.sort') %>&nbsp;</span>
<div class="alpha_sort">
<%= link_to("Alphabetically", alphabetize_projects_path(:state => state),
:class => "alphabetize_link", :title => "Sort these projects alphabetically") %>
:id => "#{state}_alphabetize_link", :class => "alphabetize_link", :title => t('common.sort.alphabetically_title'), :x_confirm_message => t('common.sort.alphabetically_confirm')) %>
</div><span class="sort_separator">&nbsp;|&nbsp;</span><div class="tasks_sort">
<%= link_to("By number of tasks", actionize_projects_path(:state => state),
:class => "actionize_link", :title => "Sort these projects by number of tasks") %>
:id => "#{state}_actionize_link", :class => "actionize_link", :title => t('common.sort.by_task_count_title'), :x_confirm_message => t('common.sort.by_task_count_title_confirm')) %>
</div>
</div>

View file

@ -0,0 +1,2 @@
new_html = "<%= escape_javascript(render(:partial => 'project_listing', :collection => @projects)) %>";
$("#list-<%=@state%>-projects").html(new_html);

View file

@ -1,6 +0,0 @@
list_id = "list-#{@state}-projects"
page.replace_html list_id,
:partial => 'project_listing',
:collection => @projects
page.sortable list_id, get_listing_sortable_options(list_id)

View file

@ -0,0 +1,2 @@
new_html = "<%= escape_javascript(render(:partial => 'project_listing', :collection => @projects)) %>";
$("#list-<%=@state%>-projects").html(new_html);

View file

@ -1,6 +0,0 @@
list_id = "list-#{@state}-projects"
page.replace_html list_id,
:partial => 'project_listing',
:collection => @projects
page.sortable list_id, get_listing_sortable_options(list_id)

View file

@ -0,0 +1,45 @@
<% if @saved -%>
<% if @go_to_project -%>
redirect_to("<%= project_path(@project) -%>")
<% else -%>
TracksPages.hide_errors();
hide_empty_message();
TracksPages.set_page_badge(<%= @down_count %>);
update_active_projects_container();
add_project();
clear_form();
TracksPages.page_notify('notice', "Created new project '<%= @project.name%>'", 5);
<% end -%>
<% else -%>
TracksPages.show_errors(html_for_error_messages());
<% end -%>
/* TODO: make this generic for all pages with lists */
function hide_empty_message() {
$('projects-empty-nd').hide();
}
/* TODO: refactor and move this to application.js */
function add_project() {
$('#list-active-projects').append(html_for_project_listing());
}
/* TODO: refactor and move this to application.js */
function clear_form() {
$('#project_form').clearForm();
$('#project_form input:text:first').focus();
}
/* TODO: refactor and move this to application.js */
function update_active_projects_container() {
ProjectListPage.set_state_container_visibility('active', true);
ProjectListPage.update_state_count('active', <%=@active_projects_count%>);
}
function html_for_error_messages() {
return "<%= escape_javascript(error_messages_for('project')) %>";
}
function html_for_project_listing() {
return "<%= @saved ? escape_javascript(render(:partial => 'project_listing', :object => @project)) : "" %>";
}

View file

@ -1,17 +0,0 @@
if @saved and @go_to_project
page.redirect_to project_path(@project)
elsif @saved
page.hide 'status'
page['badge_count'].replace_html @down_count
page.hide 'projects-empty-nd'
page.show 'list-active-projects-container'
page.replace_html "active-projects-count", @active_projects_count
page.insert_html :bottom, "list-active-projects", :partial => 'project_listing', :locals => { :project_listing => @project }
page.sortable "list-active-projects", get_listing_sortable_options('list-active-projects')
page << "$('#project-form').clearForm();"
page << "$('#project-form input:text:first').focus();"
else
page.show 'status'
page.replace_html 'status', "#{error_messages_for('project')}"
end
page.hide "busy"

View file

@ -0,0 +1,13 @@
remove_deleted_project();
ProjectListPage.update_all_states_count(<%=@active_projects_count%>, <%=@hidden_projects_count%>, <%=@completed_projects_count%>)
ProjectListPage.show_or_hide_all_state_containers(<%= @show_active_projects %>, <%= @show_hidden_projects %>, <%= @show_completed_projects %>);
TracksPages.page_notify('notice', "Deleted project '<%= @project.name%>'", 5);
TracksPages.set_page_badge(<%=@down_count%>);
/* TODO: refactor and move function to application.js */
function remove_deleted_project() {
$('div#<%=dom_id(@project, "container")%>').slideUp(1000,
function() {
$('div#<%=dom_id(@project, "container")%>').remove();
});
}

View file

@ -1,13 +0,0 @@
page.visual_effect :fade, dom_id(@project, "container"), :duration => 0.5
page.delay(0.5) do
page[dom_id(@project, "container")].remove
page.replace_html "active-projects-count", @active_projects_count
page.replace_html "hidden-projects-count", @hidden_projects_count
page.replace_html "completed-projects-count", @completed_projects_count
page.set_element_visible("list-hidden-projects-container", @hidden_projects_count > 0)
page.set_element_visible("list-active-projects-container", @active_projects_count > 0)
page.set_element_visible("list-completed-projects-container", @completed_projects_count > 0)
end
page.notify :notice, "Deleted project '#{@project.name}'", 5.0
page['badge_count'].replace_html @down_count
page.hide "busy"

View file

@ -0,0 +1,21 @@
replace_project_with_edit_form();
function replace_project_with_edit_form() {
$('div#<%=dom_id(@project)%>').fadeOut(250, function() {
show_edit_form();
set_focus();
});
}
function show_edit_form() {
$('div#<%=dom_id(@project, 'edit')%>').html(html_for_edit_form());
$('div#<%=dom_id(@project, 'edit')%>').fadeIn(500);
}
function set_focus() {
$('input.project-name').focus();
}
function html_for_edit_form() {
return "<%= escape_javascript(render(:partial => 'project_form', :object => @project)) %>"
}

Some files were not shown because too many files have changed in this diff Show more