mirror of
https://github.com/TracksApp/tracks.git
synced 2026-01-21 08:26:10 +01:00
Merge branch 'master' of https://github.com/TracksApp/tracks into upstream
This commit is contained in:
commit
92c7700639
2839 changed files with 10605 additions and 363513 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -2,6 +2,7 @@
|
|||
*.tmproj
|
||||
.dotest
|
||||
/.emacs-project
|
||||
/.redcar
|
||||
config/database.yml
|
||||
config/site.yml
|
||||
config/deploy.rb
|
||||
|
|
@ -20,3 +21,4 @@ public/javascripts/tracks-cached.js
|
|||
public/stylesheets/tracks-cached.css
|
||||
.idea
|
||||
.rvmrc
|
||||
.yardoc
|
||||
|
|
|
|||
3
.yardopts
Normal file
3
.yardopts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
--title "Tracks Documentation"
|
||||
--charset utf-8
|
||||
--markup="textile"
|
||||
56
Gemfile
Normal file
56
Gemfile
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
source :gemcutter
|
||||
source "http://gems.github.com/"
|
||||
|
||||
gem "rake", "~>0.8.7"
|
||||
gem "rails", "~>2.3.12"
|
||||
gem "highline", "~>1.5.0"
|
||||
gem "RedCloth", "4.2.8"
|
||||
gem "sanitize", "~>1.2.1"
|
||||
gem "rack", "1.1.0"
|
||||
gem "will_paginate", "~> 2.3.15"
|
||||
gem "has_many_polymorphs", "~> 2.13"
|
||||
gem "acts_as_list", "~>0.1.4"
|
||||
gem "aasm", "~>2.2.0"
|
||||
gem "rubyjedi-actionwebservice", :require => "actionwebservice"
|
||||
gem "rubycas-client", "~>2.2.1"
|
||||
gem "ruby-openid", :require => "openid"
|
||||
gem "sqlite3"
|
||||
gem 'bcrypt-ruby', '~> 2.1.4'
|
||||
gem 'htmlentities', '~> 4.3.0'
|
||||
gem "mail"
|
||||
|
||||
if RUBY_VERSION.to_f >= 1.9
|
||||
gem "soap4r-ruby1.9"
|
||||
else
|
||||
gem "soap4r", "~>1.5.8"
|
||||
end
|
||||
|
||||
gem "webrat", ">=0.7.0", :groups => [:cucumber, :test]
|
||||
gem "database_cleaner", ">=0.5.0", :groups => [:cucumber, :selenium]
|
||||
gem "cucumber-rails", "~>0.3.0", :groups => :cucumber
|
||||
|
||||
group :development do
|
||||
if RUBY_VERSION.to_f >= 1.9
|
||||
gem "ruby-debug19"
|
||||
gem "mongrel", "1.2.0.pre2"
|
||||
else
|
||||
gem "ruby-debug"
|
||||
gem "mongrel"
|
||||
end
|
||||
gem "yard"
|
||||
end
|
||||
|
||||
group :test do
|
||||
gem "test-unit", "1.2.3"
|
||||
gem "flexmock"
|
||||
gem "ZenTest", ">=4.0.0"
|
||||
gem "hpricot"
|
||||
gem "hoe"
|
||||
gem "rspec-rails", "~>1.3.3"
|
||||
gem "thoughtbot-factory_girl"
|
||||
gem 'memory_test_fix', '~>0.1.3'
|
||||
end
|
||||
|
||||
group :selenium do
|
||||
gem "selenium-client"
|
||||
end
|
||||
148
Gemfile.lock
Normal file
148
Gemfile.lock
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
GEM
|
||||
remote: http://rubygems.org/
|
||||
remote: http://gems.github.com/
|
||||
specs:
|
||||
RedCloth (4.2.8)
|
||||
ZenTest (4.6.1)
|
||||
aasm (2.2.0)
|
||||
actionmailer (2.3.14)
|
||||
actionpack (= 2.3.14)
|
||||
actionpack (2.3.14)
|
||||
activesupport (= 2.3.14)
|
||||
rack (~> 1.1.0)
|
||||
activerecord (2.3.14)
|
||||
activesupport (= 2.3.14)
|
||||
activeresource (2.3.14)
|
||||
activesupport (= 2.3.14)
|
||||
activesupport (2.3.14)
|
||||
acts_as_list (0.1.4)
|
||||
bcrypt-ruby (2.1.4)
|
||||
builder (3.0.0)
|
||||
cgi_multipart_eof_fix (2.5.0)
|
||||
columnize (0.3.4)
|
||||
cucumber (1.0.2)
|
||||
builder (>= 2.1.2)
|
||||
diff-lcs (>= 1.1.2)
|
||||
gherkin (~> 2.4.5)
|
||||
json (>= 1.4.6)
|
||||
term-ansicolor (>= 1.0.5)
|
||||
cucumber-rails (0.3.2)
|
||||
cucumber (>= 0.8.0)
|
||||
daemons (1.1.4)
|
||||
database_cleaner (0.6.7)
|
||||
diff-lcs (1.1.2)
|
||||
fastthread (1.0.7)
|
||||
flexmock (0.9.0)
|
||||
gem_plugin (0.2.3)
|
||||
gherkin (2.4.11)
|
||||
json (>= 1.4.6)
|
||||
has_many_polymorphs (2.13)
|
||||
activerecord
|
||||
highline (1.5.2)
|
||||
hoe (2.12.0)
|
||||
rake (~> 0.8)
|
||||
hpricot (0.8.4)
|
||||
htmlentities (4.3.0)
|
||||
httpclient (2.2.1)
|
||||
i18n (0.6.0)
|
||||
json (1.5.3)
|
||||
linecache (0.46)
|
||||
rbx-require-relative (> 0.0.4)
|
||||
mail (2.3.0)
|
||||
i18n (>= 0.4.0)
|
||||
mime-types (~> 1.16)
|
||||
treetop (~> 1.4.8)
|
||||
memory_test_fix (0.1.3)
|
||||
mime-types (1.16)
|
||||
mongrel (1.1.5)
|
||||
cgi_multipart_eof_fix (>= 2.4)
|
||||
daemons (>= 1.0.3)
|
||||
fastthread (>= 1.0.1)
|
||||
gem_plugin (>= 0.2.3)
|
||||
nokogiri (1.4.7)
|
||||
polyglot (0.3.2)
|
||||
rack (1.1.0)
|
||||
rack-test (0.6.1)
|
||||
rack (>= 1.0)
|
||||
rails (2.3.14)
|
||||
actionmailer (= 2.3.14)
|
||||
actionpack (= 2.3.14)
|
||||
activerecord (= 2.3.14)
|
||||
activeresource (= 2.3.14)
|
||||
activesupport (= 2.3.14)
|
||||
rake (>= 0.8.3)
|
||||
rake (0.8.7)
|
||||
rbx-require-relative (0.0.5)
|
||||
rspec (1.3.2)
|
||||
rspec-rails (1.3.4)
|
||||
rack (>= 1.0.0)
|
||||
rspec (~> 1.3.1)
|
||||
ruby-debug (0.10.4)
|
||||
columnize (>= 0.1)
|
||||
ruby-debug-base (~> 0.10.4.0)
|
||||
ruby-debug-base (0.10.4)
|
||||
linecache (>= 0.3)
|
||||
ruby-openid (2.1.8)
|
||||
rubycas-client (2.2.1)
|
||||
activesupport
|
||||
rubyjedi-actionwebservice (2.3.5.20100714122544)
|
||||
actionpack (~> 2.3.0)
|
||||
activerecord (~> 2.3.0)
|
||||
activesupport (~> 2.3.0)
|
||||
sanitize (1.2.1)
|
||||
nokogiri (~> 1.4.1)
|
||||
selenium-client (1.2.18)
|
||||
soap4r (1.5.8)
|
||||
httpclient (>= 2.1.1)
|
||||
sqlite3 (1.3.4)
|
||||
term-ansicolor (1.0.6)
|
||||
test-unit (1.2.3)
|
||||
hoe (>= 1.5.1)
|
||||
thoughtbot-factory_girl (1.2.2)
|
||||
treetop (1.4.10)
|
||||
polyglot
|
||||
polyglot (>= 0.3.1)
|
||||
webrat (0.7.3)
|
||||
nokogiri (>= 1.2.0)
|
||||
rack (>= 1.0)
|
||||
rack-test (>= 0.5.3)
|
||||
will_paginate (2.3.16)
|
||||
yard (0.7.3)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
RedCloth (= 4.2.8)
|
||||
ZenTest (>= 4.0.0)
|
||||
aasm (~> 2.2.0)
|
||||
acts_as_list (~> 0.1.4)
|
||||
bcrypt-ruby (~> 2.1.4)
|
||||
cucumber-rails (~> 0.3.0)
|
||||
database_cleaner (>= 0.5.0)
|
||||
flexmock
|
||||
has_many_polymorphs (~> 2.13)
|
||||
highline (~> 1.5.0)
|
||||
hoe
|
||||
hpricot
|
||||
htmlentities (~> 4.3.0)
|
||||
mail
|
||||
memory_test_fix (~> 0.1.3)
|
||||
mongrel
|
||||
rack (= 1.1.0)
|
||||
rails (~> 2.3.12)
|
||||
rake (~> 0.8.7)
|
||||
rspec-rails (~> 1.3.3)
|
||||
ruby-debug
|
||||
ruby-openid
|
||||
rubycas-client (~> 2.2.1)
|
||||
rubyjedi-actionwebservice
|
||||
sanitize (~> 1.2.1)
|
||||
selenium-client
|
||||
soap4r (~> 1.5.8)
|
||||
sqlite3
|
||||
test-unit (= 1.2.3)
|
||||
thoughtbot-factory_girl
|
||||
webrat (>= 0.7.0)
|
||||
will_paginate (~> 2.3.15)
|
||||
yard
|
||||
23
README
23
README
|
|
@ -1,24 +1,31 @@
|
|||
# Tracks: a GTD(TM) web application, built with Ruby on Rails
|
||||
|
||||
**IMPORTANT: Tracks is moving to a GitHub Organization to make it easier to continue administering the project. Development will soon cease at bsag/tracks and move to TracksApp/tracks. If you are currently pulling from bsag/tracks, please pull from TracksApp instead.**
|
||||
|
||||
`git clone git://github.com/TracksApp/tracks.git`
|
||||
|
||||
**The new home for Tracks is https://github.com/TracksApp/tracks**
|
||||
|
||||
* Project homepage: http://getontracks.org/
|
||||
* Manual: http://bsag.github.com/tracks/
|
||||
* Source at GitHub: http://github.com/bsag/tracks/
|
||||
* Manual: http://TracksApp.github.com/tracks/
|
||||
* Source at GitHub: http://github.com/TracksApp/tracks/
|
||||
* Assembla space (for bug reports and feature requests): http://www.assembla.com/spaces/tracks-tickets/tickets
|
||||
* Wiki (community contributed information): http://getontracks.org/wiki/
|
||||
* Wiki (community contributed information): https://github.com/TracksApp/tracks/wiki
|
||||
* Forum: http://getontracks.org/forums/
|
||||
* Mailing list: http://lists.rousette.org.uk/mailman/listinfo/tracks-discuss
|
||||
* Original developer: bsag (http://www.rousette.org.uk/)
|
||||
* Contributors: http://getontracks.org/wiki/Contributors
|
||||
* Version: 2.0devel
|
||||
* Copyright: (cc) 2004-2010 rousette.org.uk.
|
||||
* Contributors: https://github.com/TracksApp/tracks/wiki/Contributors
|
||||
* Version: 2.1devel
|
||||
* Copyright: (cc) 2004-2011 rousette.org.uk.
|
||||
* License: GNU GPL
|
||||
|
||||
All the documentation for Tracks can be found within the /doc directory and at http://bsag.github.com/tracks/
|
||||
The latter includes full instructions for both new installations and upgrades from older installations of Tracks.
|
||||
The instructions might appear long and intimidatingly complex, but that is mostly because of the number of different platforms supported, and the different configurations which can be used (e.g. running Tracks on your local computer or on a remote server). If you choose the appropriate section for your situation (installation vs. upgrade), and use the easiest (recommended) method, you should find the instructions easy to follow. If you encounter problems, try searching the wiki, forum or mailing list (URLs above), and ask a question if you cannot find a solution to your problem.
|
||||
The wiki has a lot of user contributed installation HOWTOs for various webhosts, specific OS's and more.
|
||||
|
||||
If you are thinking about contributing towards the development of Tracks, please read /doc/README_DEVELOPERS for general information, or /doc/tracks_api_wrapper.rb for information on Tracks' API.
|
||||
If you are thinking about contributing towards the development of Tracks, please read /doc/README_DEVELOPERS for general information, or /doc/tracks_api_wrapper.rb for information on Tracks' API. Also you can find some information on development on the wiki.
|
||||
|
||||
While fully usable for everyday use, Tracks is still a work in progress. Make sure that you take sensible precautions and back up all your data frequently, taking particular care when you are upgrading.
|
||||
|
||||
Enjoy being productive!
|
||||
Enjoy being productive!
|
||||
|
|
|
|||
2
Rakefile
2
Rakefile
|
|
@ -13,4 +13,4 @@ begin
|
|||
require 'test/rails/rake_tasks'
|
||||
rescue LoadError => e
|
||||
#It's ok if you don't have ZenTest installed if you're not a developer
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ class TodoApi < ActionWebService::API::Base
|
|||
:expects => [{:username => :string}, {:token => :string}],
|
||||
:returns => [[Context]]
|
||||
|
||||
api_method :list_projects,
|
||||
:expects => [{:username => :string}, {:token => :string}],
|
||||
:returns => [[Project]]
|
||||
api_method :list_projects,
|
||||
:expects => [{:username => :string}, {:token => :string}],
|
||||
:returns => [[Project]]
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ class ApplicationController < ActionController::Base
|
|||
|
||||
layout proc{ |controller| controller.mobile? ? "mobile" : "standard" }
|
||||
exempt_from_layout /\.js\.erb$/
|
||||
|
||||
|
||||
before_filter :check_for_deprecated_password_hash
|
||||
before_filter :set_session_expiration
|
||||
before_filter :set_time_zone
|
||||
before_filter :set_zindex_counter
|
||||
|
|
@ -23,12 +24,12 @@ class ApplicationController < ActionController::Base
|
|||
prepend_before_filter :login_required
|
||||
prepend_before_filter :enable_mobile_content_negotiation
|
||||
after_filter :set_charset
|
||||
|
||||
|
||||
# By default, sets the charset to UTF-8 if it isn't already set
|
||||
def set_charset
|
||||
headers["Content-Type"] ||= "text/html; charset=UTF-8"
|
||||
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
|
||||
|
|
@ -36,7 +37,7 @@ class ApplicationController < ActionController::Base
|
|||
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
|
||||
|
|
@ -58,11 +59,20 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Redirects to change_password_user_path if the current user uses a
|
||||
# deprecated password hashing algorithm.
|
||||
def check_for_deprecated_password_hash
|
||||
if current_user and current_user.uses_deprecated_password?
|
||||
notify :warning, t('users.you_have_to_reset_your_password')
|
||||
redirect_to change_password_user_path current_user
|
||||
end
|
||||
end
|
||||
|
||||
def render_failure message, status = 404
|
||||
render :text => message, :status => status
|
||||
end
|
||||
|
||||
|
||||
# def rescue_action(exception)
|
||||
# log_error(exception) if logger
|
||||
# respond_to do |format|
|
||||
|
|
@ -74,21 +84,24 @@ class ApplicationController < ActionController::Base
|
|||
# format.xml { render :text => 'An error occurred on the server.' + $! }
|
||||
# end
|
||||
# end
|
||||
|
||||
|
||||
# Returns a count of next actions in the given context or project The result
|
||||
# is count and a string descriptor, correctly pluralised if there are no
|
||||
# actions or multiple actions
|
||||
#
|
||||
def count_undone_todos_phrase(todos_parent, string="actions")
|
||||
count = count_undone_todos(todos_parent)
|
||||
if count == 1
|
||||
word = string.singularize
|
||||
deferred_count = count_deferred_todos(todos_parent)
|
||||
if count == 0 && deferred_count > 0
|
||||
word = deferred_count == 1 ? string.singularize : string.pluralize
|
||||
word = "deferred " + word
|
||||
deferred_count.to_s + " " + word
|
||||
else
|
||||
word = string.pluralize
|
||||
word = count == 1 ? string.singularize : string.pluralize
|
||||
count.to_s + " " + word
|
||||
end
|
||||
return count.to_s + " " + word
|
||||
end
|
||||
|
||||
|
||||
def count_undone_todos(todos_parent)
|
||||
if todos_parent.nil?
|
||||
count = 0
|
||||
|
|
@ -100,6 +113,14 @@ class ApplicationController < ActionController::Base
|
|||
count || 0
|
||||
end
|
||||
|
||||
def count_deferred_todos(todos_parent)
|
||||
if todos_parent.nil?
|
||||
count = 0
|
||||
else
|
||||
count = todos_parent.todos.deferred.count
|
||||
end
|
||||
end
|
||||
|
||||
# Convert a date object to the format specified in the user's preferences in
|
||||
# config/settings.yml
|
||||
#
|
||||
|
|
@ -156,11 +177,11 @@ class ApplicationController < ActionController::Base
|
|||
def create_todo_from_recurring_todo(rt, date=nil)
|
||||
# create todo and initialize with data from recurring_todo rt
|
||||
todo = current_user.todos.build( { :description => rt.description, :notes => rt.notes, :project_id => rt.project_id, :context_id => rt.context_id})
|
||||
|
||||
|
||||
# set dates
|
||||
todo.recurring_todo_id = rt.id
|
||||
todo.due = rt.get_due_date(date)
|
||||
|
||||
|
||||
show_from_date = rt.get_show_from_date(date)
|
||||
if show_from_date.nil?
|
||||
todo.show_from=nil
|
||||
|
|
@ -168,20 +189,20 @@ class ApplicationController < ActionController::Base
|
|||
# make sure that show_from is not in the past
|
||||
todo.show_from = show_from_date < Time.zone.now ? nil : show_from_date
|
||||
end
|
||||
|
||||
|
||||
saved = todo.save
|
||||
if saved
|
||||
todo.tag_with(rt.tag_list)
|
||||
todo.tags.reload
|
||||
todo.tags.reload
|
||||
end
|
||||
|
||||
# increate number of occurences created from recurring todo
|
||||
rt.inc_occurences
|
||||
|
||||
|
||||
# mark recurring todo complete if there are no next actions left
|
||||
checkdate = todo.due.nil? ? todo.show_from : todo.due
|
||||
rt.toggle_completion! unless rt.has_next_todo(checkdate)
|
||||
|
||||
|
||||
return saved ? todo : nil
|
||||
end
|
||||
|
||||
|
|
@ -192,21 +213,21 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
|
||||
protected
|
||||
|
||||
|
||||
def admin_login_required
|
||||
unless User.find_by_id_and_is_admin(session['user_id'], true)
|
||||
render :text => t('errors.user_unauthorized'), :status => 401
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def redirect_back_or_home
|
||||
respond_to do |format|
|
||||
format.html { redirect_back_or_default home_url }
|
||||
format.m { redirect_back_or_default mobile_url }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def boolean_param(param_name)
|
||||
return false if param_name.blank?
|
||||
s = params[param_name]
|
||||
|
|
@ -214,11 +235,11 @@ class ApplicationController < ActionController::Base
|
|||
return true if s == true || s =~ /^true$/i
|
||||
raise ArgumentError.new("invalid value for Boolean: \"#{s}\"")
|
||||
end
|
||||
|
||||
|
||||
def self.openid_enabled?
|
||||
Tracks::Config.openid_enabled?
|
||||
end
|
||||
|
||||
|
||||
def openid_enabled?
|
||||
self.class.openid_enabled?
|
||||
end
|
||||
|
|
@ -239,12 +260,30 @@ class ApplicationController < ActionController::Base
|
|||
self.class.prefered_auth?
|
||||
end
|
||||
|
||||
def get_done_today(completed_todos, includes = {:include => Todo::DEFAULT_INCLUDES})
|
||||
start_of_this_day = Time.zone.now.beginning_of_day
|
||||
completed_todos.completed_after(start_of_this_day).all(includes)
|
||||
end
|
||||
|
||||
def get_done_this_week(completed_todos, includes = {:include => Todo::DEFAULT_INCLUDES})
|
||||
start_of_this_week = Time.zone.now.beginning_of_week
|
||||
start_of_this_day = Time.zone.now.beginning_of_day
|
||||
completed_todos.completed_after(start_of_this_week).completed_before(start_of_this_day).all(includes)
|
||||
end
|
||||
|
||||
def get_done_this_month(completed_todos, includes = {:include => Todo::DEFAULT_INCLUDES})
|
||||
start_of_this_month = Time.zone.now.beginning_of_month
|
||||
start_of_this_week = Time.zone.now.beginning_of_week
|
||||
completed_todos.completed_after(start_of_this_month).completed_before(start_of_this_week).all(includes)
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
|
||||
def parse_date_per_user_prefs( s )
|
||||
prefs.parse_date(s)
|
||||
end
|
||||
|
||||
|
||||
def init_data_for_sidebar
|
||||
@completed_projects = current_user.projects.completed
|
||||
@hidden_projects = current_user.projects.hidden
|
||||
|
|
@ -258,19 +297,19 @@ class ApplicationController < ActionController::Base
|
|||
init_project_hidden_todo_counts(['project'])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def init_not_done_counts(parents = ['project','context'])
|
||||
parents.each do |parent|
|
||||
eval("@#{parent}_not_done_counts = @#{parent}_not_done_counts || current_user.todos.active.count(:group => :#{parent}_id)")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def init_project_hidden_todo_counts(parents = ['project','context'])
|
||||
parents.each do |parent|
|
||||
eval("@#{parent}_project_hidden_todo_counts = @#{parent}_project_hidden_todo_counts || current_user.todos.count(:conditions => ['state = ? or state = ?', 'project_hidden', 'active'], :group => :#{parent}_id)")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Set the contents of the flash message from a controller Usage: notify
|
||||
# :warning, "This is the message" Sets the flash of type 'warning' to "This is
|
||||
# the message"
|
||||
|
|
@ -278,7 +317,7 @@ class ApplicationController < ActionController::Base
|
|||
flash[type] = message
|
||||
logger.error("ERROR: #{message}") if type == :error
|
||||
end
|
||||
|
||||
|
||||
def set_time_zone
|
||||
Time.zone = current_user.prefs.time_zone if logged_in?
|
||||
end
|
||||
|
|
@ -287,5 +326,5 @@ class ApplicationController < ActionController::Base
|
|||
# this counter can be used to handle the IE z-index bug
|
||||
@z_index_counter = 500
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
class CannotAccessContext < RuntimeError; end
|
||||
|
||||
class BackendController < ApplicationController
|
||||
acts_as_web_service
|
||||
wsdl_service_name 'Backend'
|
||||
web_service_api TodoApi
|
||||
web_service_scaffold :invoke
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ class ContextsController < ApplicationController
|
|||
def index
|
||||
# #true is passed here to force an immediate load so that size and empty?
|
||||
# checks later don't result in separate SQL queries
|
||||
@active_contexts = current_user.contexts.active(true)
|
||||
@active_contexts = current_user.contexts.active(true)
|
||||
@hidden_contexts = current_user.contexts.hidden(true)
|
||||
@new_context = current_user.contexts.build
|
||||
|
||||
|
|
@ -19,8 +19,8 @@ class ContextsController < ApplicationController
|
|||
@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
|
||||
|
|
@ -34,10 +34,10 @@ class ContextsController < ApplicationController
|
|||
format.autocomplete { render :text => for_autocomplete(@active_contexts + @hidden_contexts, params[:term])}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def show
|
||||
@contexts = current_user.contexts(true)
|
||||
if (@context.nil?)
|
||||
if @context.nil?
|
||||
respond_to do |format|
|
||||
format.html { render :text => 'Context not found', :status => 404 }
|
||||
format.xml { render :xml => '<error>Context not found</error>', :status => 404 }
|
||||
|
|
@ -51,7 +51,7 @@ class ContextsController < ApplicationController
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Example XML usage: curl -H 'Accept: application/xml' -H 'Content-Type:
|
||||
# application/xml'
|
||||
# -u username:password
|
||||
|
|
@ -86,14 +86,14 @@ class ContextsController < ApplicationController
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Edit the details of the context
|
||||
#
|
||||
def update
|
||||
params['context'] ||= {}
|
||||
success_text = if params['field'] == 'name' && params['value']
|
||||
params['context']['id'] = params['id']
|
||||
params['context']['name'] = params['value']
|
||||
params['context']['id'] = params['id']
|
||||
params['context']['name'] = params['value']
|
||||
end
|
||||
|
||||
@original_context_hidden = @context.hidden?
|
||||
|
|
@ -110,7 +110,7 @@ class ContextsController < ApplicationController
|
|||
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'
|
||||
|
|
@ -121,6 +121,13 @@ class ContextsController < ApplicationController
|
|||
else
|
||||
respond_to do |format|
|
||||
format.js
|
||||
format.xml {
|
||||
if @saved
|
||||
render :xml => @context.to_xml( :except => :user_id )
|
||||
else
|
||||
render :text => "Error on update: #{@context.errors.full_messages.inject("") {|v, e| v + e + " " }}", :status => 409
|
||||
end
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -138,7 +145,7 @@ class ContextsController < ApplicationController
|
|||
def destroy
|
||||
# make sure the deleted recurring patterns are removed from associated todos
|
||||
@context.recurring_todos.each { |rt| rt.clear_todos_association } unless @context.recurring_todos.nil?
|
||||
|
||||
|
||||
@context.destroy
|
||||
respond_to do |format|
|
||||
format.js do
|
||||
|
|
@ -159,7 +166,32 @@ class ContextsController < ApplicationController
|
|||
notify :error, $!
|
||||
redirect_to :action => 'index'
|
||||
end
|
||||
|
||||
|
||||
def done_todos
|
||||
@source_view = 'context'
|
||||
@context = current_user.contexts.find(params[:id])
|
||||
@page_title = t('contexts.completed_tasks_title', :context_name => @context.name)
|
||||
|
||||
completed_todos = @context.todos.completed
|
||||
|
||||
@done_today = get_done_today(completed_todos)
|
||||
@done_this_week = get_done_this_week(completed_todos)
|
||||
@done_this_month = get_done_this_month(completed_todos)
|
||||
@count = @done_today.size + @done_this_week.size + @done_this_month.size
|
||||
|
||||
render :template => 'todos/done'
|
||||
end
|
||||
|
||||
def all_done_todos
|
||||
@source_view = 'context'
|
||||
@context = current_user.contexts.find(params[:id])
|
||||
@page_title = t('contexts.all_completed_tasks_title', :context_name => @context.name)
|
||||
|
||||
@done = @context.todos.completed.paginate :page => params[:page], :per_page => 20, :order => 'completed_at DESC', :include => Todo::DEFAULT_INCLUDES
|
||||
@count = @done.size
|
||||
render :template => 'todos/all_done'
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def update_state_counts
|
||||
|
|
@ -179,23 +211,23 @@ class ContextsController < ApplicationController
|
|||
render
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def render_contexts_mobile
|
||||
lambda do
|
||||
@page_title = "TRACKS::List Contexts"
|
||||
@active_contexts = current_user.contexts.active
|
||||
@hidden_contexts = current_user.contexts.hidden
|
||||
@down_count = @active_contexts.size + @hidden_contexts.size
|
||||
@down_count = @active_contexts.size + @hidden_contexts.size
|
||||
cookies[:mobile_url]= {:value => request.request_uri, :secure => SITE_CONFIG['secure_cookies']}
|
||||
render :action => 'index_mobile'
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def render_context_mobile
|
||||
lambda do
|
||||
@page_title = "TRACKS::List actions in "+@context.name
|
||||
@not_done = @not_done_todos.select {|t| t.context_id == @context.id }
|
||||
@down_count = @not_done.size
|
||||
@not_done = @not_done_todos.select {|t| t.context_id == @context.id }
|
||||
@down_count = @not_done.size
|
||||
cookies[:mobile_url]= {:value => request.request_uri, :secure => SITE_CONFIG['secure_cookies']}
|
||||
@mobile_from_context = @context.id
|
||||
render :action => 'mobile_show_context'
|
||||
|
|
@ -205,18 +237,18 @@ class ContextsController < ApplicationController
|
|||
def render_contexts_rss_feed
|
||||
lambda do
|
||||
render_rss_feed_for current_user.contexts.all, :feed => feed_options,
|
||||
:item => { :description => lambda { |c| c.summary(count_undone_todos_phrase(c)) } }
|
||||
:item => { :description => lambda { |c| @template.summary(c, count_undone_todos_phrase(c)) } }
|
||||
end
|
||||
end
|
||||
|
||||
def render_contexts_atom_feed
|
||||
lambda do
|
||||
render_atom_feed_for current_user.contexts.all, :feed => feed_options,
|
||||
:item => { :description => lambda { |c| c.summary(count_undone_todos_phrase(c)) },
|
||||
:item => { :description => lambda { |c| @template.summary(c, count_undone_todos_phrase(c)) },
|
||||
:author => lambda { |c| nil } }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def feed_options
|
||||
Context.feed_options(current_user)
|
||||
end
|
||||
|
|
@ -226,7 +258,7 @@ class ContextsController < ApplicationController
|
|||
rescue
|
||||
@context = nil
|
||||
end
|
||||
|
||||
|
||||
def init
|
||||
@source_view = params['_source_view'] || 'context'
|
||||
init_data_for_sidebar
|
||||
|
|
@ -235,21 +267,19 @@ class ContextsController < ApplicationController
|
|||
def init_todos
|
||||
set_context_from_params
|
||||
unless @context.nil?
|
||||
@context.todos.send :with_scope, :find => { :include => [:project, :tags] } do
|
||||
@context.todos.send :with_scope, :find => { :include => Todo::DEFAULT_INCLUDES } do
|
||||
@done = @context.done_todos
|
||||
end
|
||||
|
||||
@max_completed = current_user.prefs.show_number_completed
|
||||
|
||||
|
||||
# @not_done_todos = @context.not_done_todos TODO: Temporarily doing this
|
||||
# search manually until I can work out a way to do the same thing using
|
||||
# not_done_todos acts_as_todo_container method Hides actions in hidden
|
||||
# projects from context.
|
||||
@not_done_todos = @context.todos.find(
|
||||
:all,
|
||||
:conditions => ['todos.state = ? AND (todos.project_id IS ? OR projects.state = ?)', 'active', nil, 'active'],
|
||||
:order => "todos.due IS NULL, todos.due ASC, todos.created_at ASC",
|
||||
:include => [:project, :tags])
|
||||
@not_done_todos = @context.todos.active(
|
||||
:order => "todos.due IS NULL, todos.due ASC, todos.created_at ASC",
|
||||
:include => Todo::DEFAULT_INCLUDES)
|
||||
|
||||
@projects = current_user.projects
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
class IntegrationsController < ApplicationController
|
||||
|
||||
skip_before_filter :login_required, :only => [:search_plugin, :google_gadget]
|
||||
require 'mail'
|
||||
|
||||
skip_before_filter :login_required, :only => [:cloudmailin, :search_plugin, :google_gadget]
|
||||
|
||||
def index
|
||||
@page_title = 'TRACKS::Integrations'
|
||||
|
|
@ -26,14 +27,59 @@ class IntegrationsController < ApplicationController
|
|||
end
|
||||
|
||||
def search_plugin
|
||||
@icon_data = [File.open(RAILS_ROOT + '/public/images/done.png').read].
|
||||
pack('m').gsub(/\n/, '')
|
||||
|
||||
render :layout => false
|
||||
@icon_data = [File.open(RAILS_ROOT + '/public/images/done.png').read].
|
||||
pack('m').gsub(/\n/, '')
|
||||
|
||||
render :layout => false
|
||||
end
|
||||
|
||||
def google_gadget
|
||||
render :layout => false, :content_type => Mime::XML
|
||||
end
|
||||
|
||||
def cloudmailin
|
||||
# verify cloudmailin signature
|
||||
provided = request.request_parameters.delete(:signature)
|
||||
signature = Digest::MD5.hexdigest(request.request_parameters.sort{|a,b| a[0].to_s <=> b[0].to_s}.map{|k,v| v}.join + SITE_CONFIG['cloudmailin'])
|
||||
|
||||
# if signature does not match, return 403
|
||||
if provided != signature
|
||||
render :text => "Message signature verification failed.", :status => 403
|
||||
return false
|
||||
end
|
||||
|
||||
# parse message
|
||||
message = Mail.new(params[:message])
|
||||
|
||||
# find user
|
||||
user = User.find(:first, :include => [:preference], :conditions => ["preferences.sms_email = ?", message.from])
|
||||
if user.nil?
|
||||
render :text => "No user found", :status => 404
|
||||
return false
|
||||
end
|
||||
|
||||
# load user settings
|
||||
context = user.prefs.sms_context
|
||||
|
||||
# prepare body
|
||||
if message.body.multipart?
|
||||
body = message.body.preamble
|
||||
else
|
||||
body = message.body.to_s
|
||||
end
|
||||
|
||||
# parse mail
|
||||
if message.subject.to_s.empty?
|
||||
description = body
|
||||
notes = nil
|
||||
else
|
||||
description = message.subject.to_s
|
||||
notes = body
|
||||
end
|
||||
|
||||
# create todo
|
||||
todo = Todo.from_rich_message(user, context.id, description, notes)
|
||||
todo.save!
|
||||
render :text => 'success', :status => 200
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -84,6 +84,12 @@ class LoginController < ApplicationController
|
|||
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
|
||||
|
||||
@user.forget_me if logged_in?
|
||||
cookies.delete :auth_token
|
||||
session['user_id'] = nil
|
||||
reset_session
|
||||
|
||||
unless Rails.env.production?
|
||||
session['expiry_time'] = Time.now
|
||||
respond_to do |format|
|
||||
|
|
|
|||
|
|
@ -1,23 +1,31 @@
|
|||
class PreferencesController < ApplicationController
|
||||
|
||||
|
||||
def index
|
||||
@page_title = t('preferences.page_title')
|
||||
@prefs = current_user.prefs
|
||||
@user = current_user
|
||||
end
|
||||
|
||||
def edit
|
||||
@page_title = t('preferences.page_title_edit')
|
||||
@prefs = current_user.prefs
|
||||
end
|
||||
|
||||
def update
|
||||
@prefs = current_user.prefs
|
||||
@user = current_user
|
||||
user_updated = current_user.update_attributes(params['user'])
|
||||
prefs_updated = current_user.preference.update_attributes(params['prefs'])
|
||||
if user_updated && prefs_updated
|
||||
if (user_updated && prefs_updated)
|
||||
notify :notice, "Preferences updated"
|
||||
redirect_to :action => 'index'
|
||||
else
|
||||
render :action => 'edit'
|
||||
msg = "Preferences could not be updated: "
|
||||
msg += "User model errors; " unless user_updated
|
||||
msg += "Prefs model errors; " unless prefs_updated
|
||||
notify :warning, msg
|
||||
render 'index'
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def render_date_format
|
||||
format = params[:date_format]
|
||||
render :text => l(Date.today, :format => format)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ class ProjectsController < ApplicationController
|
|||
|
||||
helper :application, :todos, :notes
|
||||
before_filter :set_source_view
|
||||
before_filter :set_project_from_params, :only => [:update, :destroy, :show, :edit]
|
||||
before_filter :set_project_from_params, :only => [:update, :destroy, :show, :edit, :set_reviewed]
|
||||
before_filter :default_context_filter, :only => [:create, :update]
|
||||
skip_before_filter :login_required, :only => [:index]
|
||||
prepend_before_filter :login_or_feed_token_required, :only => [:index]
|
||||
|
|
@ -12,15 +12,15 @@ class ProjectsController < ApplicationController
|
|||
@new_project = current_user.projects.build
|
||||
if params[:projects_and_actions]
|
||||
projects_and_actions
|
||||
else
|
||||
else
|
||||
@contexts = current_user.contexts.all
|
||||
init_not_done_counts(['project'])
|
||||
init_project_hidden_todo_counts(['project'])
|
||||
if params[:only_active_with_no_next_actions]
|
||||
@projects = current_user.projects.active.select { |p| count_undone_todos(p) == 0 }
|
||||
@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|
|
||||
format.html &render_projects_html
|
||||
format.m &render_projects_mobile
|
||||
|
|
@ -33,10 +33,53 @@ class ProjectsController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def review
|
||||
@page_title = t('projects.list_reviews')
|
||||
@projects = current_user.projects.all
|
||||
@contexts = current_user.contexts.all
|
||||
@projects_to_review = current_user.projects.select {|p| p.needs_review?(current_user)}
|
||||
@stalled_projects = current_user.projects.select {|p| p.stalled?}
|
||||
@blocked_projects = current_user.projects.select {|p| p.blocked?}
|
||||
@current_projects = current_user.projects.uncompleted.select {|p| not(p.needs_review?(current_user))}
|
||||
|
||||
init_not_done_counts(['project'])
|
||||
init_project_hidden_todo_counts(['project'])
|
||||
current_user.projects.cache_note_counts
|
||||
|
||||
@page_title = t('projects.list_reviews')
|
||||
@count = @projects_to_review.count + @blocked_projects.count + @stalled_projects.count + @current_projects.count
|
||||
|
||||
@no_projects = current_user.projects.empty?
|
||||
@new_project = current_user.projects.build
|
||||
end
|
||||
|
||||
def done
|
||||
@source_view = params['_source_view'] || 'project_list'
|
||||
@page_title = t('projects.list_completed_projects')
|
||||
|
||||
page = params[:page] || 1
|
||||
projects_per_page = 20
|
||||
@projects = current_user.projects.completed.paginate :page => page, :per_page => projects_per_page
|
||||
@count = @projects.count
|
||||
@total = current_user.projects.completed.count
|
||||
@no_projects = @projects.empty?
|
||||
|
||||
@range_low = (page.to_i-1) * projects_per_page + 1
|
||||
@range_high = @range_low + @projects.size - 1
|
||||
|
||||
init_not_done_counts(['project'])
|
||||
end
|
||||
|
||||
def set_reviewed
|
||||
@project.last_reviewed = Time.zone.now
|
||||
@project.save
|
||||
redirect_to :action => 'show'
|
||||
end
|
||||
|
||||
def projects_and_actions
|
||||
@projects = current_user.projects.active
|
||||
respond_to do |format|
|
||||
format.text {
|
||||
format.text {
|
||||
render :action => 'index_text_projects_and_actions', :layout => false, :content_type => Mime::TEXT
|
||||
}
|
||||
end
|
||||
|
|
@ -46,12 +89,12 @@ class ProjectsController < ApplicationController
|
|||
@max_completed = current_user.prefs.show_number_completed
|
||||
init_data_for_sidebar unless mobile?
|
||||
@page_title = t('projects.page_title', :project => @project.name)
|
||||
|
||||
@not_done = @project.todos.active_or_hidden(:include => [:tags, :context, :predecessors])
|
||||
@deferred = @project.deferred_todos(:include => [:tags, :context, :predecessors])
|
||||
@pending = @project.pending_todos(:include => [:tags, :context, :predecessors])
|
||||
|
||||
@not_done = @project.todos.active_or_hidden(:include => Todo::DEFAULT_INCLUDES)
|
||||
@deferred = @project.todos.deferred(:include => Todo::DEFAULT_INCLUDES)
|
||||
@pending = @project.todos.pending(:include => Todo::DEFAULT_INCLUDES)
|
||||
@done = @project.todos.find_in_state(:all, :completed,
|
||||
:order => "todos.completed_at DESC", :limit => current_user.prefs.show_number_completed, :include => [:context, :tags, :predecessors])
|
||||
:order => "todos.completed_at DESC", :limit => current_user.prefs.show_number_completed, :include => Todo::DEFAULT_INCLUDES)
|
||||
|
||||
@count = @not_done.size
|
||||
@down_count = @count + @deferred.size + @pending.size
|
||||
|
|
@ -64,10 +107,17 @@ class ProjectsController < ApplicationController
|
|||
respond_to do |format|
|
||||
format.html
|
||||
format.m &render_project_mobile
|
||||
format.xml { render :xml => @project.to_xml( :except => :user_id ) }
|
||||
format.xml {
|
||||
render :xml => @project.to_xml(:except => :user_id) { |xml|
|
||||
xml.not_done { @not_done.each { |child| child.to_xml(:builder => xml, :skip_instruct => true) } }
|
||||
xml.deferred { @deferred.each { |child| child.to_xml(:builder => xml, :skip_instruct => true) } }
|
||||
xml.pending { @pending.each { |child| child.to_xml(:builder => xml, :skip_instruct => true) } }
|
||||
xml.done { @done.each { |child| child.to_xml(:builder => xml, :skip_instruct => true) } }
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Example XML usage: curl -H 'Accept: application/xml' -H 'Content-Type:
|
||||
# application/xml'
|
||||
# -u username:password
|
||||
|
|
@ -111,6 +161,8 @@ class ProjectsController < ApplicationController
|
|||
# Edit the details of the project
|
||||
#
|
||||
def update
|
||||
template = ""
|
||||
|
||||
params['project'] ||= {}
|
||||
if params['project']['state']
|
||||
@new_state = params['project']['state']
|
||||
|
|
@ -118,8 +170,8 @@ class ProjectsController < ApplicationController
|
|||
params['project'].delete('state')
|
||||
end
|
||||
success_text = if params['field'] == 'name' && params['value']
|
||||
params['project']['id'] = params['id']
|
||||
params['project']['name'] = params['value']
|
||||
params['project']['id'] = params['id']
|
||||
params['project']['name'] = params['value']
|
||||
end
|
||||
|
||||
@project.attributes = params['project']
|
||||
|
|
@ -137,43 +189,50 @@ class ProjectsController < ApplicationController
|
|||
@contexts = current_user.contexts
|
||||
update_state_counts
|
||||
init_data_for_sidebar
|
||||
render :template => 'projects/update.js.erb'
|
||||
return
|
||||
|
||||
template = 'projects/update.js.erb'
|
||||
|
||||
# TODO: are these params ever set? or is this dead code?
|
||||
|
||||
elsif boolean_param('update_status')
|
||||
render :template => 'projects/update_status.js.rjs'
|
||||
return
|
||||
template = 'projects/update_status.js.rjs'
|
||||
elsif boolean_param('update_default_context')
|
||||
@initial_context_name = @project.default_context.name
|
||||
render :template => 'projects/update_default_context.js.rjs'
|
||||
return
|
||||
@initial_context_name = @project.default_context.name
|
||||
template = 'projects/update_default_context.js.rjs'
|
||||
elsif boolean_param('update_default_tags')
|
||||
render :template => 'projects/update_default_tags.js.rjs'
|
||||
return
|
||||
template = 'projects/update_default_tags.js.rjs'
|
||||
elsif boolean_param('update_project_name')
|
||||
@projects = current_user.projects
|
||||
render :template => 'projects/update_project_name.js.rjs'
|
||||
return
|
||||
template = 'projects/update_project_name.js.rjs'
|
||||
else
|
||||
render :text => success_text || 'Success'
|
||||
return
|
||||
end
|
||||
else
|
||||
init_data_for_sidebar
|
||||
render :template => 'projects/update.js.erb'
|
||||
return
|
||||
template = 'projects/update.js.erb'
|
||||
end
|
||||
render :template => 'projects/update.js.erb'
|
||||
|
||||
respond_to do |format|
|
||||
format.js { render :template => template }
|
||||
format.html { redirect_to :action => 'index'}
|
||||
format.xml {
|
||||
if @saved
|
||||
render :xml => @project.to_xml( :except => :user_id )
|
||||
else
|
||||
render :text => "Error on update: #{@project.errors.full_messages.inject("") {|v, e| v + e + " " }}", :status => 409
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
def edit
|
||||
respond_to do |format|
|
||||
format.js
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def destroy
|
||||
@project.recurring_todos.each {|rt| rt.remove_from_project!}
|
||||
@project.destroy
|
||||
|
|
@ -186,7 +245,7 @@ class ProjectsController < ApplicationController
|
|||
format.xml { render :text => "Deleted project #{@project.name}" }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def order
|
||||
project_ids = params["container_project"]
|
||||
@projects = current_user.projects.update_positions( project_ids )
|
||||
|
|
@ -195,23 +254,46 @@ class ProjectsController < ApplicationController
|
|||
notify :error, $!
|
||||
redirect_to :action => 'index'
|
||||
end
|
||||
|
||||
|
||||
def alphabetize
|
||||
@state = params['state']
|
||||
@projects = current_user.projects.alphabetize(:state => @state) if @state
|
||||
@contexts = current_user.contexts
|
||||
init_not_done_counts(['project'])
|
||||
init_project_hidden_todo_counts(['project']) if @state == 'hidden'
|
||||
end
|
||||
|
||||
|
||||
def actionize
|
||||
@state = params['state']
|
||||
@projects = current_user.projects.actionize(current_user.id, :state => @state) if @state
|
||||
@projects = current_user.projects.actionize(:state => @state) if @state
|
||||
@contexts = current_user.contexts
|
||||
init_not_done_counts(['project'])
|
||||
init_project_hidden_todo_counts(['project']) if @state == 'hidden'
|
||||
end
|
||||
|
||||
|
||||
def done_todos
|
||||
@source_view = 'project'
|
||||
@project = current_user.projects.find(params[:id])
|
||||
@page_title = t('projects.completed_tasks_title', :project_name => @project.name)
|
||||
|
||||
completed_todos = @project.todos.completed
|
||||
|
||||
@done_today = get_done_today(completed_todos)
|
||||
@done_this_week = get_done_this_week(completed_todos)
|
||||
@done_this_month = get_done_this_month(completed_todos)
|
||||
@count = @done_today.size + @done_this_week.size + @done_this_month.size
|
||||
|
||||
render :template => 'todos/done'
|
||||
end
|
||||
|
||||
def all_done_todos
|
||||
@source_view = 'project'
|
||||
@project = current_user.projects.find(params[:id])
|
||||
@page_title = t('projects.all_completed_tasks_title', :project_name => @project.name)
|
||||
|
||||
@done = @project.todos.completed.paginate :page => params[:page], :per_page => 20, :order => 'completed_at DESC', :include => Todo::DEFAULT_INCLUDES
|
||||
@count = @done.size
|
||||
render :template => 'todos/all_done'
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def update_state_counts
|
||||
|
|
@ -229,7 +311,8 @@ class ProjectsController < ApplicationController
|
|||
@count = current_user.projects.count
|
||||
@active_projects = current_user.projects.active
|
||||
@hidden_projects = current_user.projects.hidden
|
||||
@completed_projects = current_user.projects.completed
|
||||
@completed_projects = current_user.projects.completed.find(:all, :limit => 10)
|
||||
@completed_count = current_user.projects.completed.count
|
||||
@no_projects = current_user.projects.empty?
|
||||
current_user.projects.cache_note_counts
|
||||
@new_project = current_user.projects.build
|
||||
|
|
@ -242,12 +325,12 @@ class ProjectsController < ApplicationController
|
|||
@active_projects = current_user.projects.active
|
||||
@hidden_projects = current_user.projects.hidden
|
||||
@completed_projects = current_user.projects.completed
|
||||
@down_count = @active_projects.size + @hidden_projects.size + @completed_projects.size
|
||||
@down_count = @active_projects.size + @hidden_projects.size + @completed_projects.size
|
||||
cookies[:mobile_url]= {:value => request.request_uri, :secure => SITE_CONFIG['secure_cookies']}
|
||||
render :action => 'index_mobile'
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def render_project_mobile
|
||||
lambda do
|
||||
if @project.default_context.nil?
|
||||
|
|
@ -265,38 +348,37 @@ class ProjectsController < ApplicationController
|
|||
lambda do
|
||||
render_rss_feed_for @projects, :feed => feed_options,
|
||||
:title => :name,
|
||||
:item => { :description => lambda { |p| summary(p) } }
|
||||
:item => { :description => lambda { |p| @template.summary(p) } }
|
||||
end
|
||||
end
|
||||
|
||||
def render_atom_feed
|
||||
lambda do
|
||||
render_atom_feed_for @projects, :feed => feed_options,
|
||||
:item => { :description => lambda { |p| summary(p) },
|
||||
:item => { :description => lambda { |p| @template.summary(p) },
|
||||
:title => :name,
|
||||
:author => lambda { |p| nil } }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def feed_options
|
||||
Project.feed_options(current_user)
|
||||
end
|
||||
|
||||
def render_text_feed
|
||||
lambda do
|
||||
init_project_hidden_todo_counts(['project'])
|
||||
render :action => 'index', :layout => false, :content_type => Mime::TEXT
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def set_project_from_params
|
||||
@project = current_user.projects.find_by_params(params)
|
||||
end
|
||||
|
||||
|
||||
def set_source_view
|
||||
@source_view = params['_source_view'] || 'project'
|
||||
end
|
||||
|
||||
|
||||
def default_context_filter
|
||||
p = params['project']
|
||||
p = params['request']['project'] if p.nil? && params['request']
|
||||
|
|
@ -310,13 +392,4 @@ class ProjectsController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def summary(project)
|
||||
project_description = ''
|
||||
project_description += sanitize(markdown( project.description )) unless project.description.blank?
|
||||
project_description += "<p>#{count_undone_todos_phrase(p)}. "
|
||||
project_description += t('projects.project_state', :state => project.state)
|
||||
project_description += "</p>"
|
||||
project_description
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@ class RecurringTodosController < ApplicationController
|
|||
|
||||
def index
|
||||
@page_title = t('todos.recurring_actions_title')
|
||||
|
||||
@source_view = params['_source_view'] || 'recurring_todo'
|
||||
find_and_inactivate
|
||||
@recurring_todos = current_user.recurring_todos.active
|
||||
@completed_recurring_todos = current_user.recurring_todos.completed
|
||||
@completed_recurring_todos = current_user.recurring_todos.completed.find(:all, :limit => 10)
|
||||
|
||||
@no_recurring_todos = @recurring_todos.size == 0
|
||||
@no_completed_recurring_todos = @completed_recurring_todos.size == 0
|
||||
|
|
@ -24,6 +24,17 @@ class RecurringTodosController < ApplicationController
|
|||
|
||||
def show
|
||||
end
|
||||
|
||||
def done
|
||||
@page_title = t('todos.completed_recurring_actions_title')
|
||||
@source_view = params['_source_view'] || 'recurring_todo'
|
||||
items_per_page = 20
|
||||
page = params[:page] || 1
|
||||
@completed_recurring_todos = current_user.recurring_todos.completed.paginate :page => params[:page], :per_page => items_per_page
|
||||
@total = @count = current_user.recurring_todos.completed.count
|
||||
@range_low = (page.to_i-1) * items_per_page + 1
|
||||
@range_high = @range_low + @completed_recurring_todos.size - 1
|
||||
end
|
||||
|
||||
def edit
|
||||
respond_to do |format|
|
||||
|
|
@ -131,7 +142,6 @@ class RecurringTodosController < ApplicationController
|
|||
end
|
||||
|
||||
def destroy
|
||||
|
||||
# remove all references to this recurring todo
|
||||
@todos = @recurring_todo.todos
|
||||
@number_of_todos = @todos.size
|
||||
|
|
@ -176,7 +186,6 @@ class RecurringTodosController < ApplicationController
|
|||
@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]]})
|
||||
@active_todos = @recurring_todo.todos.active.count
|
||||
# create todo if there is no active todo belonging to the activated
|
||||
# recurring_todo
|
||||
|
|
|
|||
|
|
@ -1,12 +1,22 @@
|
|||
class SearchController < ApplicationController
|
||||
|
||||
helper :todos, :application, :notes, :projects
|
||||
|
||||
helper :todos, :application, :notes, :projects
|
||||
|
||||
def results
|
||||
@source_view = params['_source_view'] || 'search'
|
||||
@page_title = "TRACKS::Search Results for #{params[:search]}"
|
||||
terms = '%' + params[:search] + '%'
|
||||
@found_todos = current_user.todos.find(:all, :conditions => ["todos.description LIKE ? OR todos.notes LIKE ?", terms, terms], :include => [:tags, :project, :context])
|
||||
|
||||
@found_not_complete_todos = current_user.todos.find(:all,
|
||||
:conditions => ["(todos.description LIKE ? OR todos.notes LIKE ?) AND todos.completed_at IS NULL", terms, terms],
|
||||
:include => Todo::DEFAULT_INCLUDES,
|
||||
:order => "todos.due IS NULL, todos.due ASC, todos.created_at ASC")
|
||||
@found_complete_todos = current_user.todos.find(:all,
|
||||
:conditions => ["(todos.description LIKE ? OR todos.notes LIKE ?) AND NOT (todos.completed_at IS NULL)", terms, terms],
|
||||
:include => Todo::DEFAULT_INCLUDES,
|
||||
:order => "todos.completed_at DESC")
|
||||
@found_todos = @found_not_complete_todos + @found_complete_todos
|
||||
|
||||
@found_projects = current_user.projects.find(:all, :conditions => ["name LIKE ? OR description LIKE ?", terms, terms])
|
||||
@found_notes = current_user.notes.find(:all, :conditions => ["body LIKE ?", terms])
|
||||
@found_contexts = current_user.contexts.find(:all, :conditions => ["name LIKE ?", terms])
|
||||
|
|
@ -18,17 +28,17 @@ class SearchController < ApplicationController
|
|||
"LEFT JOIN todos ON taggings.taggable_id = todos.id "+
|
||||
"WHERE todos.user_id=? "+
|
||||
"AND tags.name LIKE ? ", current_user.id, terms])
|
||||
|
||||
|
||||
@count = @found_todos.size + @found_projects.size + @found_notes.size + @found_contexts.size + @found_tags.size
|
||||
|
||||
|
||||
init_not_done_counts
|
||||
init_project_hidden_todo_counts
|
||||
end
|
||||
|
||||
def index
|
||||
@page_title = "TRACKS::Search"
|
||||
@page_title = "TRACKS::Search"
|
||||
end
|
||||
|
||||
|
||||
def init
|
||||
@source_view = params['_source_view'] || 'search'
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
class StatsController < ApplicationController
|
||||
|
||||
helper :todos
|
||||
helper :todos, :projects, :recurring_todos
|
||||
|
||||
append_before_filter :init, :exclude => []
|
||||
|
||||
|
|
@ -643,6 +643,18 @@ class StatsController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def done
|
||||
@source_view = 'done'
|
||||
|
||||
init_not_done_counts
|
||||
|
||||
@done_recently = current_user.todos.completed.all(:limit => 10, :order => 'completed_at DESC', :include => Todo::DEFAULT_INCLUDES)
|
||||
@last_completed_projects = current_user.projects.completed.all(:limit => 10, :order => 'completed_at DESC', :include => [:todos, :notes])
|
||||
@last_completed_contexts = []
|
||||
@last_completed_recurring_todos = current_user.recurring_todos.completed.all(:limit => 10, :order => 'completed_at DESC', :include => [:tags, :taggings])
|
||||
#TODO: @last_completed_contexts = current_user.contexts.completed.all(:limit => 10, :order => 'completed_at DESC')
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def get_unique_tags_of_user
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,11 +1,12 @@
|
|||
class UsersController < ApplicationController
|
||||
before_filter :admin_login_required, :only => [ :index, :show, :destroy ]
|
||||
skip_before_filter :login_required, :only => [ :new, :create ]
|
||||
skip_before_filter :check_for_deprecated_password_hash,
|
||||
:only => [ :change_password, :update_password ]
|
||||
prepend_before_filter :login_optional, :only => [ :new, :create ]
|
||||
|
||||
|
||||
# GET /users GET /users.xml
|
||||
def index
|
||||
@users = User.find(:all, :order => 'login')
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
@page_title = "TRACKS::Manage Users"
|
||||
|
|
@ -15,10 +16,13 @@ class UsersController < ApplicationController
|
|||
# we get returned here when signup is successful
|
||||
store_location
|
||||
end
|
||||
format.xml { render :xml => @users.to_xml(:except => [ :password ]) }
|
||||
format.xml do
|
||||
@users = User.find(:all, :order => 'login')
|
||||
render :xml => @users.to_xml(:except => [ :password ])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# GET /users/id GET /users/id.xml
|
||||
def show
|
||||
@user = User.find_by_id(params[:id])
|
||||
|
|
@ -50,7 +54,7 @@ class UsersController < ApplicationController
|
|||
end
|
||||
render :layout => "login"
|
||||
end
|
||||
|
||||
|
||||
# Example usage: curl -H 'Accept: application/xml' -H 'Content-Type:
|
||||
# application/xml'
|
||||
# -u admin:up2n0g00d
|
||||
|
|
@ -128,14 +132,14 @@ class UsersController < ApplicationController
|
|||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# DELETE /users/id DELETE /users/id.xml
|
||||
def destroy
|
||||
@deleted_user = User.find_by_id(params[:id])
|
||||
@saved = @deleted_user.destroy
|
||||
@total_users = User.find(:all).size
|
||||
|
||||
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
if @saved
|
||||
|
|
@ -149,14 +153,15 @@ class UsersController < ApplicationController
|
|||
format.xml { head :ok }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
def change_password
|
||||
@page_title = t('users.change_password_title')
|
||||
end
|
||||
|
||||
|
||||
def update_password
|
||||
@user.change_password(params[:updateuser][:password], params[:updateuser][:password_confirmation])
|
||||
# is used for focing password change after sha->bcrypt upgrade
|
||||
@user.change_password(params[:user][:password], params[:user][:password_confirmation])
|
||||
notify :notice, t('users.password_updated')
|
||||
redirect_to preferences_path
|
||||
rescue Exception => error
|
||||
|
|
@ -167,7 +172,7 @@ class UsersController < ApplicationController
|
|||
def change_auth_type
|
||||
@page_title = t('users.change_auth_type_title')
|
||||
end
|
||||
|
||||
|
||||
def update_auth_type
|
||||
if (params[:open_id_complete] || (params[:user][:auth_type] == 'open_id')) && openid_enabled?
|
||||
authenticate_with_open_id do |result, identity_url|
|
||||
|
|
@ -199,16 +204,16 @@ class UsersController < ApplicationController
|
|||
redirect_to :action => 'change_auth_type'
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def refresh_token
|
||||
@user.generate_token
|
||||
@user.save!
|
||||
notify :notice, t('users.new_token_generated')
|
||||
redirect_to preferences_path
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
|
||||
def get_new_user
|
||||
if session['new_user']
|
||||
user = session['new_user']
|
||||
|
|
@ -218,7 +223,7 @@ class UsersController < ApplicationController
|
|||
end
|
||||
user
|
||||
end
|
||||
|
||||
|
||||
def check_create_user_params
|
||||
return false unless params.has_key?(:request)
|
||||
return false unless params[:request].has_key?(:login)
|
||||
|
|
@ -227,5 +232,5 @@ class UsersController < ApplicationController
|
|||
return false if params[:request][:password].empty?
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -27,33 +27,42 @@ module ApplicationHelper
|
|||
# a 'traffic light' colour code
|
||||
#
|
||||
def due_date(due)
|
||||
if due == nil
|
||||
return ""
|
||||
end
|
||||
return "" if due.nil?
|
||||
|
||||
days = days_from_today(due)
|
||||
|
||||
case days
|
||||
when 0
|
||||
"<a title='#{format_date(due)}'><span class=\"amber\">Due Today</span></a> "
|
||||
when 1
|
||||
"<a title='#{format_date(due)}'><span class=\"amber\">Due Tomorrow</span></a> "
|
||||
# due 2-7 days away
|
||||
when 2..7
|
||||
if prefs.due_style == Preference.due_styles[:due_on]
|
||||
"<a title='#{format_date(due)}'><span class=\"orange\">Due on #{due.strftime("%A")}</span></a> "
|
||||
else
|
||||
"<a title='#{format_date(due)}'><span class=\"orange\">Due in #{pluralize(days, 'day')}</span></a> "
|
||||
end
|
||||
else
|
||||
# overdue or due very soon! sound the alarm!
|
||||
if days < 0
|
||||
"<a title='#{format_date(due)}'><span class=\"red\">Overdue by #{pluralize(days * -1, 'day')}</span></a> "
|
||||
else
|
||||
# more than a week away - relax
|
||||
"<a title='#{format_date(due)}'><span class=\"green\">Due in #{pluralize(days, 'day')}</span></a> "
|
||||
end
|
||||
end
|
||||
|
||||
colors = ['amber','amber','orange','orange','orange','orange','orange','orange']
|
||||
color = :red if days < 0
|
||||
color = :green if days > 7
|
||||
color = colors[days] if color.nil?
|
||||
|
||||
return content_tag(:a, {:title => format_date(due)}) {
|
||||
content_tag(:span, {:class => color}) {
|
||||
case days
|
||||
when 0
|
||||
t('todos.next_actions_due_date.due_today')
|
||||
when 1
|
||||
t('todos.next_actions_due_date.due_tomorrow')
|
||||
when 2..7
|
||||
if prefs.due_style == Preference.due_styles[:due_on]
|
||||
# TODO: internationalize strftime here
|
||||
t('models.preference.due_on', :date => due.strftime("%A"))
|
||||
else
|
||||
t('models.preference.due_in', :days => days)
|
||||
end
|
||||
else
|
||||
# overdue or due very soon! sound the alarm!
|
||||
if days == -1
|
||||
t('todos.next_actions_due_date.overdue_by', :days => days * -1)
|
||||
elsif days < -1
|
||||
t('todos.next_actions_due_date.overdue_by_plural', :days => days * -1)
|
||||
else
|
||||
# more than a week away - relax
|
||||
t('models.preference.due_in', :days => days)
|
||||
end
|
||||
end
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
# Check due date in comparison to today's date Flag up date appropriately with
|
||||
|
|
@ -152,12 +161,12 @@ module ApplicationHelper
|
|||
def recurrence_time_span(rt)
|
||||
case rt.ends_on
|
||||
when "no_end_date"
|
||||
return rt.start_from.nil? ? "" : "from " + format_date(rt.start_from)
|
||||
return rt.start_from.nil? ? "" : I18n.t("todos.recurrence.pattern.from") + " " + format_date(rt.start_from)
|
||||
when "ends_on_number_of_times"
|
||||
return "for "+rt.number_of_occurences.to_s + " times"
|
||||
return I18n.t("todos.recurrence.pattern.times", :number => rt.number_of_occurences)
|
||||
when "ends_on_end_date"
|
||||
starts = rt.start_from.nil? ? "" : "from " + format_date(rt.start_from)
|
||||
ends = rt.end_date.nil? ? "" : " until " + format_date(rt.end_date)
|
||||
starts = rt.start_from.nil? ? "" : I18n.t("todos.recurrence.pattern.from") + " " + format_date(rt.start_from)
|
||||
ends = rt.end_date.nil? ? "" : " " + I18n.t("todos.recurrence.pattern.until") + " " + format_date(rt.end_date)
|
||||
return starts+ends
|
||||
else
|
||||
raise Exception.new, "unknown recurrence time span selection (#{rt.ends_on})"
|
||||
|
|
@ -252,7 +261,7 @@ module ApplicationHelper
|
|||
contexts.show_form contexts.show_form_title
|
||||
contexts.new_context_pre contexts.new_context_post
|
||||
common.cancel common.ok
|
||||
common.ajaxError
|
||||
common.ajaxError todos.unresolved_dependency
|
||||
}.each do |s|
|
||||
js << "i18n['#{s}'] = '#{ t(s).gsub(/'/, "\\\\'") }';\n"
|
||||
end
|
||||
|
|
@ -266,5 +275,39 @@ module ApplicationHelper
|
|||
javascript_include_tag("i18n/jquery.ui.datepicker-#{locale}.js")
|
||||
end
|
||||
end
|
||||
|
||||
def determine_done_path
|
||||
case @controller.controller_name
|
||||
when "contexts"
|
||||
done_todos_context_path(@context)
|
||||
when "projects"
|
||||
done_todos_project_path(@project)
|
||||
when "todos"
|
||||
if source_view_is(:tag)
|
||||
done_tag_path(@tag_name)
|
||||
else
|
||||
done_todos_path
|
||||
end
|
||||
else
|
||||
done_todos_path
|
||||
end
|
||||
end
|
||||
|
||||
def determine_all_done_path
|
||||
case @controller.controller_name
|
||||
when "contexts"
|
||||
all_done_todos_context_path(@context)
|
||||
when "projects"
|
||||
all_done_todos_project_path(@project)
|
||||
when "todos"
|
||||
if source_view_is(:tag)
|
||||
all_done_tag_path(@tag_name)
|
||||
else
|
||||
all_done_todos_path
|
||||
end
|
||||
else
|
||||
all_done_todos_path
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,25 +1,30 @@
|
|||
module ContextsHelper
|
||||
|
||||
def get_listing_sortable_options
|
||||
{
|
||||
:tag => 'div',
|
||||
:handle => 'handle',
|
||||
:complete => visual_effect(:highlight, 'list-contexts'),
|
||||
:url => order_contexts_path
|
||||
}
|
||||
end
|
||||
def get_listing_sortable_options
|
||||
{
|
||||
:tag => 'div',
|
||||
:handle => 'handle',
|
||||
:complete => visual_effect(:highlight, 'list-contexts'),
|
||||
:url => order_contexts_path
|
||||
}
|
||||
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
|
||||
|
||||
def summary(context, undone_todo_count)
|
||||
content_tag(:p, "#{undone_todo_count}. Context is #{context.hidden? ? 'Hidden' : 'Active'}.")
|
||||
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
|
||||
|
|
|
|||
|
|
@ -1,2 +1,18 @@
|
|||
module PreferencesHelper
|
||||
|
||||
def pref(model, pref_name, &block)
|
||||
s = "<label for #{model+pref_name}>#{Preference.human_attribute_name(pref_name)}:</label><br/>"
|
||||
s << yield
|
||||
s << "<br/><br/>"
|
||||
s
|
||||
end
|
||||
|
||||
def pref_with_select_field(model, pref_name, collection = [ [t('preferences.is_true'),true], [t('preferences.is_false'), false] ])
|
||||
pref(model, pref_name) { select(model, pref_name, collection) }
|
||||
end
|
||||
|
||||
def pref_with_text_field(model, pref_name)
|
||||
pref(model, pref_name) { text_field(model, pref_name) }
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ module ProjectsHelper
|
|||
:url => order_projects_path
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
def set_element_visible(id,test)
|
||||
if (test)
|
||||
page.show id
|
||||
|
|
@ -30,7 +30,7 @@ module ProjectsHelper
|
|||
end
|
||||
html
|
||||
end
|
||||
|
||||
|
||||
def project_next_prev_mobile
|
||||
html = ''
|
||||
unless @previous_project.nil?
|
||||
|
|
@ -57,5 +57,19 @@ module ProjectsHelper
|
|||
}
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
def summary(project)
|
||||
project_description = ''
|
||||
project_description += sanitize(markdown( project.description )) unless project.description.blank?
|
||||
project_description += content_tag(:p,
|
||||
"#{count_undone_todos_phrase(p)}. " + t('projects.project_state', :state => project.state)
|
||||
)
|
||||
project_description
|
||||
end
|
||||
|
||||
def needsreview_class(item)
|
||||
raise "item must be a Project " unless item.kind_of? Project
|
||||
return item.needs_review?(current_user) ? "needsreview" : "needsnoreview"
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,9 +3,8 @@ module RecurringTodosHelper
|
|||
def recurring_todo_tag_list
|
||||
tags_except_starred = @recurring_todo.tags.reject{|t| t.name == Todo::STARRED_TAG_NAME}
|
||||
tag_list = tags_except_starred.collect{|t| "<span class=\"tag #{t.name.gsub(' ','-')}\">" +
|
||||
# link_to(t.name, :controller => "todos", :action => "tag", :id =>
|
||||
# t.name) + TODO: tag view for recurring_todos (yet?)
|
||||
t.name +
|
||||
link_to(t.name, :controller => "todos", :action => "tag", :id =>
|
||||
t.name) + #TODO: tag view for recurring_todos (yet?)
|
||||
"</span>"}.join('')
|
||||
"<span class='tags'>#{tag_list}</span>"
|
||||
end
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ module TodosHelper
|
|||
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},
|
||||
{: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),
|
||||
|
|
@ -30,7 +30,7 @@ module TodosHelper
|
|||
:_source_view => (@source_view.underscore.gsub(/\s+/,'_') rescue "")}
|
||||
url[:_tag_name] = @tag_name if @source_view == 'tag'
|
||||
|
||||
options = {:x_defer_alert => false, :class => "icon_defer_item" }
|
||||
options = {:x_defer_alert => false, :class => "icon_defer_item", :id => "defer_#{days}_#{dom_id(todo)}" }
|
||||
if todo.due
|
||||
futuredate = (todo.show_from || todo.user.date) + days.days
|
||||
if futuredate > todo.due
|
||||
|
|
@ -55,18 +55,13 @@ 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")+" " + t('todos.convert_to_project'), url)
|
||||
return link_to(image_tag("to_project_off.png", :align => "absmiddle")+" " + t('todos.convert_to_project'), url, {:id => "to_project_#{dom_id(todo)}"})
|
||||
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 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) }
|
||||
|
|
@ -88,24 +83,25 @@ module TodosHelper
|
|||
{:controller => "recurring_todos", :action => "index"},
|
||||
:class => "recurring_icon", :title => recurrence_pattern_as_text(todo.recurring_todo))
|
||||
end
|
||||
|
||||
|
||||
def remote_toggle_checkbox(todo=@todo)
|
||||
check_box_tag("mark_complete_#{todo.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(todo=@todo)
|
||||
if todo.completed?
|
||||
"<span class=\"grey\">#{format_date( todo.completed_at )}</span>"
|
||||
content_tag(:span, {:class => :grey}) { format_date( todo.completed_at ) }
|
||||
elsif todo.pending?
|
||||
"<a title='#{t('todos.depends_on')}: #{todo.uncompleted_predecessors.map(&:description).join(', ')}'><span class=\"orange\">#{t('todos.pending')}</span></a> "
|
||||
title = t('todos.depends_on')+ ": " + todo.uncompleted_predecessors.map(&:description).join(', ')
|
||||
content_tag(:a, {:title => title}) { content_tag(:span, {:class => :orange}) { t('todos.pending') } }
|
||||
elsif todo.deferred?
|
||||
show_date( todo.show_from )
|
||||
else
|
||||
due_date( todo.due )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def successors_span(todo=@todo)
|
||||
unless todo.pending_successors.empty?
|
||||
pending_count = todo.pending_successors.length
|
||||
|
|
@ -113,41 +109,41 @@ module TodosHelper
|
|||
image_tag( 'successor_off.png', :width=>'10', :height=>'16', :border=>'0', :title => title )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def grip_span(todo=@todo)
|
||||
unless todo.completed?
|
||||
image_tag('grip.png', :width => '7', :height => '16', :border => '0',
|
||||
image_tag('grip.png', :width => '7', :height => '16', :border => '0',
|
||||
:title => t('todos.drag_action_title'),
|
||||
:class => 'grip')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def tag_list_text(todo=@todo)
|
||||
todo.tags.collect{|t| t.name}.join(', ')
|
||||
end
|
||||
|
||||
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>"
|
||||
|
||||
def tag_span (tag, mobile=false)
|
||||
content_tag(:span, :class => "tag #{tag.name.gsub(' ','-')}") { link_to(tag.name, (mobile ? mobile_tag_path(tag.name) : tag_path(tag.name))) }
|
||||
end
|
||||
|
||||
|
||||
def tag_list(todo=@todo, mobile=false)
|
||||
content_tag(:span, :class => 'tags') { todo.tags.all_except_starred.collect{|tag| tag_span(tag, mobile)}.join('') }
|
||||
end
|
||||
|
||||
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\">" +
|
||||
link_to(t.name, {:action => "tag", :controller => "todos", :id => t.name+".m"}) +
|
||||
"</span>"}.join('')
|
||||
if tag_list.empty? then "" else "<span class=\"tags\">#{tag_list}</span>" end
|
||||
unless todo.tags.all_except_starred.empty?
|
||||
return tag_list(todo, true)
|
||||
else
|
||||
return ""
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
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(todo, parent_container_type, opts = {})
|
||||
str = ''
|
||||
if todo.completed?
|
||||
|
|
@ -166,7 +162,7 @@ module TodosHelper
|
|||
end
|
||||
return str
|
||||
end
|
||||
|
||||
|
||||
# Uses the 'staleness_starts' value from settings.yml (in days) to colour the
|
||||
# background of the action appropriately according to the age of the creation
|
||||
# date:
|
||||
|
|
@ -188,37 +184,41 @@ module TodosHelper
|
|||
end
|
||||
end
|
||||
|
||||
def show_date_tag(date, the_class, text)
|
||||
content_tag(:a, :title => format_date(date)) do
|
||||
content_tag(:span, :class => the_class) { text + " "}
|
||||
end
|
||||
end
|
||||
|
||||
# Check show_from date in comparison to today's date Flag up date
|
||||
# appropriately with a 'traffic light' colour code
|
||||
#
|
||||
def show_date(d)
|
||||
if d == nil
|
||||
return ""
|
||||
end
|
||||
return "" if d == nil
|
||||
|
||||
days = days_from_today(d)
|
||||
|
||||
|
||||
case days
|
||||
# overdue or due very soon! sound the alarm!
|
||||
when -1000..-1
|
||||
"<a title=\"" + format_date(d) + "\"><span class=\"red\">#{t('todos.scheduled_overdue', :days => (days * -1).to_s)}</span></a> "
|
||||
show_date_tag(d, :red, t('todos.scheduled_overdue', :days => (days * -1).to_s))
|
||||
when 0
|
||||
"<a title=\"" + format_date(d) + "\"><span class=\"amber\">#{t('todos.show_today')}</span></a> "
|
||||
show_date_tag(d, :amber, t('todos.show_today'))
|
||||
when 1
|
||||
"<a title=\"" + format_date(d) + "\"><span class=\"amber\">#{t('todos.show_tomorrow')}</span></a> "
|
||||
show_date_tag(d, :amber, t('todos.show_tomorrow'))
|
||||
# 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\">#{t('todos.show_on_date', :date => d.strftime("%A"))}</span></a> "
|
||||
show_date_tag(d, :orange, t('todos.show_on_date', :date => d.strftime("%A")) )
|
||||
else
|
||||
"<a title=\"" + format_date(d) + "\"><span class=\"orange\">#{t('todos.show_in_days', :days => days.to_s)}</span></a> "
|
||||
show_date_tag(d, :orange, t('todos.show_in_days', :days => days.to_s) )
|
||||
end
|
||||
# more than a week away - relax
|
||||
else
|
||||
"<a title=\"" + format_date(d) + "\"><span class=\"green\">#{t('todos.show_in_days', :days => days.to_s)}</span></a> "
|
||||
show_date_tag(d, :green, t('todos.show_in_days', :days => days.to_s) )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def should_show_new_item
|
||||
source_view do |page|
|
||||
page.todo { return !@todo.hidden? }
|
||||
|
|
@ -250,7 +250,7 @@ module TodosHelper
|
|||
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
|
||||
|
|
@ -258,18 +258,18 @@ module TodosHelper
|
|||
return 'tag' if source_view_is :tag
|
||||
return 'context'
|
||||
end
|
||||
|
||||
|
||||
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
|
||||
projects = current_user.uncompleted.projects.find(:all, :include => [:context], :conditions => ['default_context_id is not null'])
|
||||
Hash[*projects.map{ |p| [escape_javascript(p.name), escape_javascript(p.default_context.name)] }.flatten].to_json
|
||||
end
|
||||
|
||||
|
||||
def default_tags_for_autocomplete
|
||||
projects = current_user.projects.uncompleted.find(:all, :conditions => ["default_tags != ''"])
|
||||
Hash[*projects.map{ |p| [escape_javascript(p.name), p.default_tags] }.flatten].to_json
|
||||
|
|
@ -282,7 +282,7 @@ module TodosHelper
|
|||
end
|
||||
joined_notes || ""
|
||||
end
|
||||
|
||||
|
||||
def formatted_pagination(total)
|
||||
s = will_paginate(@todos)
|
||||
(s.gsub(/(<\/[^<]+>)/, '\1 ')).chomp(' ')
|
||||
|
|
@ -295,6 +295,7 @@ module TodosHelper
|
|||
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 && @tag_was_removed) ||
|
||||
(@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_one_of(:project, :calendar)
|
||||
|
|
@ -304,13 +305,14 @@ module TodosHelper
|
|||
|
||||
def update_needs_to_remove_todo_from_container
|
||||
source_view do |page|
|
||||
page.context { return @context_changed || @todo.deferred? || @todo.pending? }
|
||||
page.context { return @context_changed || @todo.deferred? || @todo.pending? || @todo_should_be_hidden }
|
||||
page.project { return @todo_deferred_state_changed || @todo_pending_state_changed || @project_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?}
|
||||
page.search { return false }
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
|
@ -324,6 +326,7 @@ module TodosHelper
|
|||
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 }
|
||||
page.search { return true }
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
|
@ -356,11 +359,21 @@ module TodosHelper
|
|||
|
||||
source_view do |page|
|
||||
page.project {
|
||||
return "tickler-empty-nd" if @todo_was_deferred_from_active_state || @todo_was_blocked_from_active_state || @todo_was_destroyed_from_deferred_state || @todo_was_created_deferred
|
||||
return "tickler-empty-nd" if
|
||||
@todo_was_deferred_from_active_state ||
|
||||
@todo_was_blocked_from_active_state ||
|
||||
@todo_was_destroyed_from_deferred_state ||
|
||||
@todo_was_created_deferred ||
|
||||
@todo_was_blocked_from_completed_state
|
||||
return "p#{todo.project_id}empty-nd"
|
||||
}
|
||||
page.tag {
|
||||
return "tickler-empty-nd" if @todo_was_deferred_from_active_state || @todo_was_destroyed_from_deferred_state || @todo_was_created_deferred
|
||||
return "tickler-empty-nd" if
|
||||
@todo_was_deferred_from_active_state ||
|
||||
@todo_was_blocked_from_active_state ||
|
||||
@todo_was_destroyed_from_deferred_state ||
|
||||
@todo_was_created_deferred ||
|
||||
@todo_was_blocked_from_completed_state
|
||||
return "hidden-empty-nd" if @todo.hidden?
|
||||
return "c#{todo.context_id}empty-nd"
|
||||
}
|
||||
|
|
@ -372,22 +385,27 @@ module TodosHelper
|
|||
return "c#{todo.context_id}empty-nd"
|
||||
end
|
||||
|
||||
def todo_was_removed_from_deferred_or_blocked_container
|
||||
return @todo_was_activated_from_deferred_state ||
|
||||
@todo_was_activated_from_pending_state ||
|
||||
@todo_was_destroyed_from_deferred_or_pending_state ||
|
||||
@todo_was_completed_from_deferred_or_blocked_state
|
||||
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?
|
||||
container_id = "tickler-empty-nd" if todo_was_removed_from_deferred_or_blocked_container && @remaining_deferred_or_pending_count == 0
|
||||
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) ||
|
||||
container_id = "tickler-empty-nd" if (todo_was_removed_from_deferred_or_blocked_container && @remaining_deferred_or_pending_count == 0) ||
|
||||
(@original_item_was_deferred && @remaining_deferred_or_pending_count == 0 && (@todo.completed? || @tag_was_removed))
|
||||
container_id = "empty-d" if @completed_count && @completed_count == 0 && !@todo.completed?
|
||||
}
|
||||
|
|
@ -411,11 +429,22 @@ module TodosHelper
|
|||
return html + ";"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def image_tag_for_star(todo)
|
||||
class_str = todo.starred? ? "starred_todo" : "unstarred_todo"
|
||||
image_tag("blank.png", :title =>t('todos.star_action'), :class => class_str, :id => "star_img_"+todo.id.to_s)
|
||||
def reset_tab_index
|
||||
$tracks_tab_index = 0
|
||||
end
|
||||
|
||||
|
||||
def next_tab_index
|
||||
# make sure it exists if reset was not called. Set to 20 to avoid clashes with existing form in sidebar
|
||||
$tracks_tab_index ||= 20
|
||||
|
||||
$tracks_tab_index = $tracks_tab_index + 1
|
||||
return $tracks_tab_index
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def image_tag_for_star(todo)
|
||||
image_tag("blank.png", :title =>t('todos.star_action'), :class => "todo_star"+(todo.starred? ? " starred":""), :id => "star_img_"+todo.id.to_s)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
class Context < ActiveRecord::Base
|
||||
|
||||
has_many :todos, :dependent => :delete_all, :include => :project, :order => "todos.completed_at DESC"
|
||||
has_many :todos, :dependent => :delete_all, :include => :project,
|
||||
:order => 'todos.due IS NULL, todos.due ASC, todos.created_at ASC'
|
||||
has_many :recurring_todos, :dependent => :delete_all
|
||||
belongs_to :user
|
||||
|
||||
named_scope :active, :conditions => { :hide => false }
|
||||
named_scope :hidden, :conditions => { :hide => true }
|
||||
|
||||
acts_as_list :scope => :user
|
||||
acts_as_list :scope => :user, :top_of_list => 0
|
||||
extend NamePartFinder
|
||||
include Tracks::TodoList
|
||||
|
||||
|
|
@ -19,12 +20,13 @@ class Context < ActiveRecord::Base
|
|||
validates_does_not_contain :name, :string => ',', :message => "cannot contain the comma (',') character"
|
||||
|
||||
def self.feed_options(user)
|
||||
# TODO: move to view or helper
|
||||
{
|
||||
:title => 'Tracks Contexts',
|
||||
:description => "Lists all the contexts for #{user.display_name}"
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
def self.null_object
|
||||
NullContext.new
|
||||
end
|
||||
|
|
@ -32,36 +34,29 @@ class Context < ActiveRecord::Base
|
|||
def hidden?
|
||||
self.hide == true || self.hide == 1
|
||||
end
|
||||
|
||||
|
||||
def title
|
||||
name
|
||||
end
|
||||
|
||||
def summary(undone_todo_count)
|
||||
s = "<p>#{undone_todo_count}. "
|
||||
s += "Context is #{hidden? ? 'Hidden' : 'Active'}."
|
||||
s += "</p>"
|
||||
s
|
||||
end
|
||||
|
||||
|
||||
def new_record_before_save?
|
||||
@new_record_before_save
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class NullContext
|
||||
|
||||
|
||||
def nil?
|
||||
true
|
||||
end
|
||||
|
||||
|
||||
def id
|
||||
nil
|
||||
end
|
||||
|
||||
|
||||
def name
|
||||
''
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
|
@ -1,28 +1,5 @@
|
|||
class Project < ActiveRecord::Base
|
||||
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 :done_todos,
|
||||
:include => [:context,:tags,:project],
|
||||
:class_name => 'Todo',
|
||||
:order => "todos.due IS NULL, todos.due ASC, todos.created_at ASC",
|
||||
:conditions => ["todos.state = ?", 'completed']
|
||||
has_many :deferred_todos,
|
||||
:include => [:context,:tags,:project],
|
||||
:class_name => 'Todo',
|
||||
:conditions => ["todos.state = ? ", "deferred"],
|
||||
:order => "show_from"
|
||||
has_many :pending_todos,
|
||||
:include => [:context,:tags,:project],
|
||||
:class_name => 'Todo',
|
||||
:conditions => ["todos.state = ? ", "pending"],
|
||||
:order => "show_from"
|
||||
|
||||
has_many :notes, :dependent => :delete_all, :order => "created_at DESC"
|
||||
has_many :recurring_todos
|
||||
|
||||
|
|
@ -32,48 +9,51 @@ 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']
|
||||
|
||||
named_scope :uncompleted, :conditions => ["NOT(state = ?)", 'completed']
|
||||
|
||||
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'
|
||||
acts_as_list :scope => 'user_id = #{user_id} AND state = \'#{state}\'', :top_of_list => 0
|
||||
|
||||
include AASM
|
||||
aasm_column :state
|
||||
aasm_initial_state :active
|
||||
|
||||
extend NamePartFinder
|
||||
#include Tracks::TodoList
|
||||
|
||||
state :active
|
||||
state :hidden, :enter => :hide_todos, :exit => :unhide_todos
|
||||
state :completed, :enter => Proc.new { |p| p.completed_at = Time.zone.now }, :exit => Proc.new { |p| p.completed_at = nil }
|
||||
|
||||
event :activate do
|
||||
transitions :to => :active, :from => [:hidden, :completed]
|
||||
aasm_state :active
|
||||
aasm_state :hidden, :enter => :hide_todos, :exit => :unhide_todos
|
||||
aasm_state :completed, :enter => :set_completed_at_date, :exit => :clear_completed_at_date
|
||||
|
||||
aasm_event :activate do
|
||||
transitions :to => :active, :from => [:active, :hidden, :completed]
|
||||
end
|
||||
|
||||
event :hide do
|
||||
|
||||
aasm_event :hide do
|
||||
transitions :to => :hidden, :from => [:active, :completed]
|
||||
end
|
||||
|
||||
event :complete do
|
||||
|
||||
aasm_event :complete do
|
||||
transitions :to => :completed, :from => [:active, :hidden]
|
||||
end
|
||||
|
||||
|
||||
attr_protected :user
|
||||
attr_accessor :cached_note_count
|
||||
|
||||
def self.null_object
|
||||
NullProject.new
|
||||
end
|
||||
|
||||
|
||||
def self.feed_options(user)
|
||||
{
|
||||
:title => I18n.t('models.project.feed_title'),
|
||||
:description => I18n.t('models.project.feed_description', :username => user.display_name)
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
def hide_todos
|
||||
todos.each do |t|
|
||||
unless t.completed? || t.deferred?
|
||||
|
|
@ -82,7 +62,7 @@ class Project < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def unhide_todos
|
||||
todos.each do |t|
|
||||
if t.project_hidden?
|
||||
|
|
@ -91,22 +71,32 @@ class Project < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def set_completed_at_date
|
||||
self.completed_at = Time.zone.now
|
||||
end
|
||||
|
||||
def clear_completed_at_date
|
||||
self.completed_at = nil
|
||||
end
|
||||
|
||||
def note_count
|
||||
# TODO: test this for eager and not eager loading!!!
|
||||
return 0 if notes.size == 0
|
||||
cached_note_count || notes.count
|
||||
end
|
||||
|
||||
|
||||
alias_method :original_default_context, :default_context
|
||||
|
||||
def default_context
|
||||
original_default_context.nil? ? Context.null_object : original_default_context
|
||||
end
|
||||
|
||||
|
||||
# would prefer to call this method state=(), but that causes an endless loop
|
||||
# as a result of acts_as_state_machine calling state=() to update the attribute
|
||||
def transition_to(candidate_state)
|
||||
case candidate_state.to_sym
|
||||
when current_state
|
||||
when aasm_current_state
|
||||
return
|
||||
when :hidden
|
||||
hide!
|
||||
|
|
@ -116,29 +106,48 @@ class Project < ActiveRecord::Base
|
|||
complete!
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def needs_review?(current_user)
|
||||
return active? && ( last_reviewed.nil? ||
|
||||
(last_reviewed < current_user.time - current_user.prefs.review_period.days))
|
||||
end
|
||||
|
||||
def blocked?
|
||||
## mutually exclusive for stalled and blocked
|
||||
# blocked is uncompleted project with deferred or pending todos, but no next actions
|
||||
return false if self.completed?
|
||||
return !self.todos.deferred_or_blocked.empty? && self.todos.not_deferred_or_blocked.empty?
|
||||
end
|
||||
|
||||
def stalled?
|
||||
# stalled is active/hidden project with no active todos
|
||||
return false if self.completed?
|
||||
return self.todos.deferred_or_blocked.empty? && self.todos.not_deferred_or_blocked.empty?
|
||||
end
|
||||
|
||||
|
||||
def name=(value)
|
||||
self[:name] = value.gsub(/\s{2,}/, " ").strip
|
||||
end
|
||||
|
||||
|
||||
def new_record_before_save?
|
||||
@new_record_before_save
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class NullProject
|
||||
|
||||
|
||||
def hidden?
|
||||
false
|
||||
end
|
||||
|
||||
|
||||
def nil?
|
||||
true
|
||||
end
|
||||
|
||||
|
||||
def id
|
||||
nil
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,20 +10,19 @@ class RecurringTodo < ActiveRecord::Base
|
|||
named_scope :completed, :conditions => { :state => 'completed'}
|
||||
|
||||
attr_protected :user
|
||||
|
||||
acts_as_state_machine :initial => :active, :column => 'state'
|
||||
|
||||
state :active, :enter => Proc.new { |t|
|
||||
t[:show_from], t.completed_at = nil, nil
|
||||
t.occurences_count = 0
|
||||
}
|
||||
state :completed, :enter => Proc.new { |t| t.completed_at = Time.zone.now }, :exit => Proc.new { |t| t.completed_at = nil }
|
||||
include AASM
|
||||
aasm_column :state
|
||||
aasm_initial_state :active
|
||||
|
||||
aasm_state :active, :enter => Proc.new { |t| t.occurences_count = 0 }
|
||||
aasm_state :completed, :enter => Proc.new { |t| t.completed_at = Time.zone.now }, :exit => Proc.new { |t| t.completed_at = nil }
|
||||
|
||||
event :complete do
|
||||
aasm_event :complete do
|
||||
transitions :to => :completed, :from => [:active]
|
||||
end
|
||||
|
||||
event :activate do
|
||||
aasm_event :activate do
|
||||
transitions :to => :active, :from => [:completed]
|
||||
end
|
||||
|
||||
|
|
@ -41,8 +40,7 @@ class RecurringTodo < ActiveRecord::Base
|
|||
validate :set_recurrence_on_validations
|
||||
|
||||
def period_specific_validations
|
||||
periods = %W[daily weekly monthly yearly]
|
||||
if periods.include?(recurring_period)
|
||||
if %W[daily weekly monthly yearly].include?(recurring_period)
|
||||
self.send("validate_#{recurring_period}")
|
||||
else
|
||||
errors.add(:recurring_period, "is an unknown recurrence pattern: '#{self.recurring_period}'")
|
||||
|
|
@ -94,7 +92,6 @@ class RecurringTodo < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
def starts_and_ends_on_validations
|
||||
errors.add_to_base("The start date needs to be filled in") if start_from.nil? || start_from.blank?
|
||||
case self.ends_on
|
||||
|
|
@ -388,9 +385,9 @@ class RecurringTodo < ActiveRecord::Base
|
|||
def recurring_target_as_text
|
||||
case self.target
|
||||
when 'due_date'
|
||||
return "due"
|
||||
return I18n.t("todos.recurrence.pattern.due")
|
||||
when 'show_from_date'
|
||||
return "show"
|
||||
return I18n.t("todos.recurrence.pattern.show")
|
||||
else
|
||||
raise Exception.new, "unexpected value of recurrence target '#{self.target}'"
|
||||
end
|
||||
|
|
@ -403,38 +400,51 @@ class RecurringTodo < ActiveRecord::Base
|
|||
def recurring_show_always=(value)
|
||||
self.show_always=value
|
||||
end
|
||||
|
||||
|
||||
def recurrence_pattern
|
||||
return "invalid repeat pattern" if every_other1.nil?
|
||||
case recurring_period
|
||||
when 'daily'
|
||||
if only_work_days
|
||||
return "on work days"
|
||||
return I18n.t("todos.recurrence.pattern.on_work_days")
|
||||
else
|
||||
if every_other1 > 1
|
||||
return "every #{every_other1} days"
|
||||
return I18n.t("todos.recurrence.pattern.every_n", :n => every_other1) + " " + I18n.t("common.days")
|
||||
else
|
||||
return "every day"
|
||||
return I18n.t("todos.recurrence.pattern.every_day")
|
||||
end
|
||||
end
|
||||
when 'weekly'
|
||||
if every_other1 > 1
|
||||
return "every #{every_other1} weeks"
|
||||
return I18n.t("todos.recurrence.pattern.every_n", :n => every_other1) + " " + I18n.t("common.weeks")
|
||||
else
|
||||
return 'weekly'
|
||||
return I18n.t('todos.recurrence.pattern.weekly')
|
||||
end
|
||||
when 'monthly'
|
||||
return "invalid repeat pattern" if every_other2.nil?
|
||||
if self.recurrence_selector == 0
|
||||
return "every #{self.every_other2} month#{self.every_other2>1?'s':''} on day #{self.every_other1}"
|
||||
on_day = " " + I18n.t('todos.recurrence.pattern.on_day_n', :n => self.every_other1)
|
||||
if self.every_other2>1
|
||||
return I18n.t("todos.recurrence.pattern.every_n", :n => self.every_other2) + " " + I18n.t('common.months') + on_day
|
||||
else
|
||||
return I18n.t("todos.recurrence.pattern.every_month") + on_day
|
||||
end
|
||||
else
|
||||
return "every #{self.xth} #{self.day_of_week} of every #{self.every_other2} month#{self.every_other2>1?'s':''}"
|
||||
if self.every_other2>1
|
||||
n_months = "#{self.every_other2} " + I18n.t('common.months')
|
||||
else
|
||||
n_months = I18n.t('common.month')
|
||||
end
|
||||
return I18n.t('todos.recurrence.pattern.every_xth_day_of_every_n_months',
|
||||
:x => self.xth, :day => self.day_of_week, :n_months => n_months)
|
||||
end
|
||||
when 'yearly'
|
||||
if self.recurrence_selector == 0
|
||||
return "every year on #{self.month_of_year} #{self.every_other1}"
|
||||
return I18n.t("todos.recurrence.pattern.every_year_on",
|
||||
:date => I18n.l(DateTime.new(Time.zone.now.year, self.every_other2, self.every_other1), :format => :month_day))
|
||||
else
|
||||
return "every year on the #{self.xth} #{self.day_of_week} of #{self.month_of_year}"
|
||||
return I18n.t("todos.recurrence.pattern.every_year_on",
|
||||
:date => I18n.t("todos.recurrence.pattern.the_xth_day_of_month", :x => self.xth, :day => self.day_of_week, :month => self.month_of_year))
|
||||
end
|
||||
else
|
||||
return 'unknown recurrence pattern: period unknown'
|
||||
|
|
@ -442,18 +452,18 @@ class RecurringTodo < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def xth
|
||||
xth_day = ['first','second','third','fourth','last']
|
||||
xth_day = [
|
||||
I18n.t('todos.recurrence.pattern.first'),I18n.t('todos.recurrence.pattern.second'),I18n.t('todos.recurrence.pattern.third'),
|
||||
I18n.t('todos.recurrence.pattern.fourth'),I18n.t('todos.recurrence.pattern.last')]
|
||||
return self.every_other3.nil? ? '??' : xth_day[self.every_other3-1]
|
||||
end
|
||||
|
||||
def day_of_week
|
||||
days_of_week = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday']
|
||||
return (self.every_count.nil? ? '??' : days_of_week[self.every_count])
|
||||
return (self.every_count.nil? ? '??' : I18n.t('todos.recurrence.pattern.day_names')[self.every_count])
|
||||
end
|
||||
|
||||
def month_of_year
|
||||
months_of_year = ['January','Februari','March','April','May','June','July','August','September','October','November','December']
|
||||
return self.every_other2.nil? ? '??' : months_of_year[self.every_other2-1]
|
||||
return self.every_other2.nil? ? '??' : I18n.t('todos.recurrence.pattern.month_names')[self.every_other2]
|
||||
end
|
||||
|
||||
def starred?
|
||||
|
|
@ -692,13 +702,7 @@ class RecurringTodo < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def toggle_completion!
|
||||
saved = false
|
||||
if completed?
|
||||
saved = activate!
|
||||
else
|
||||
saved = complete!
|
||||
end
|
||||
return saved
|
||||
return completed? ? activate! : complete!
|
||||
end
|
||||
|
||||
def toggle_star!
|
||||
|
|
|
|||
|
|
@ -11,38 +11,41 @@ class Tag < ActiveRecord::Base
|
|||
# rescue the ActiveRecord database constraint errors instead.
|
||||
validates_presence_of :name
|
||||
validates_uniqueness_of :name, :case_sensitive => false
|
||||
|
||||
|
||||
# Change this validation if you need more complex tag names.
|
||||
# validates_format_of :name, :with => /^[a-zA-Z0-9\_\-]+$/, :message => "can not contain special characters"
|
||||
|
||||
|
||||
# Set up the polymorphic relationship.
|
||||
has_many_polymorphs :taggables,
|
||||
:from => [:todos, :recurring_todos],
|
||||
:through => :taggings,
|
||||
has_many_polymorphs :taggables,
|
||||
:from => [:todos, :recurring_todos],
|
||||
:through => :taggings,
|
||||
:dependent => :destroy,
|
||||
:skip_duplicates => false,
|
||||
:skip_duplicates => false,
|
||||
:parent_extend => proc {
|
||||
# Defined on the taggable models, not on Tag itself. Return the tagnames
|
||||
# associated with this record as a string.
|
||||
def to_s
|
||||
self.map(&:name).sort.join(Tag::JOIN_DELIMITER)
|
||||
end
|
||||
def all_except_starred
|
||||
self.reject{|tag| tag.name == Todo::STARRED_TAG_NAME}
|
||||
end
|
||||
}
|
||||
|
||||
|
||||
# Callback to strip extra spaces from the tagname before saving it. If you
|
||||
# allow tags to be renamed later, you might want to use the
|
||||
# <tt>before_save</tt> callback instead.
|
||||
def before_create
|
||||
def before_create
|
||||
self.name = name.downcase.strip.squeeze(" ")
|
||||
end
|
||||
|
||||
def on(taggable, user)
|
||||
taggings.create :taggable => taggable, :user => user
|
||||
end
|
||||
|
||||
|
||||
# Tag::Error class. Raised by ActiveRecord::Base::TaggingExtensions if
|
||||
# something goes wrong.
|
||||
class Error < StandardError
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
class Todo < ActiveRecord::Base
|
||||
|
||||
after_save :save_predecessors
|
||||
|
||||
# relations
|
||||
belongs_to :context
|
||||
belongs_to :project
|
||||
belongs_to :user
|
||||
belongs_to :recurring_todo
|
||||
|
||||
|
||||
has_many :predecessor_dependencies, :foreign_key => 'predecessor_id', :class_name => 'Dependency', :dependent => :destroy
|
||||
has_many :successor_dependencies, :foreign_key => 'successor_id', :class_name => 'Dependency', :dependent => :destroy
|
||||
has_many :predecessors, :through => :successor_dependencies
|
||||
|
|
@ -13,21 +16,18 @@ class Todo < ActiveRecord::Base
|
|||
:source => :predecessor, :conditions => ['NOT (todos.state = ?)', 'completed']
|
||||
has_many :pending_successors, :through => :predecessor_dependencies,
|
||||
:source => :successor, :conditions => ['todos.state = ?', 'pending']
|
||||
|
||||
after_save :save_predecessors
|
||||
|
||||
# scopes for states of this todo
|
||||
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 todos.completed_at IS NULL"]
|
||||
named_scope :are_due, :conditions => ['NOT (todos.due IS NULL)']
|
||||
named_scope :deferred, :conditions => ["todos.completed_at IS NULL AND NOT todos.show_from IS NULL"]
|
||||
named_scope :not_completed, :conditions => ['NOT (todos.state = ?)', 'completed']
|
||||
named_scope :completed, :conditions => ["NOT (todos.completed_at 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,
|
||||
named_scope :pending, :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 :hidden,
|
||||
:joins => :context,
|
||||
:conditions => ["todos.state = ? OR (contexts.hide = ? AND (todos.state = ? OR todos.state = ? OR todos.state = ?))",
|
||||
'project_hidden', true, 'active', 'deferred', 'pending']
|
||||
|
|
@ -36,82 +36,100 @@ class Todo < ActiveRecord::Base
|
|||
: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"
|
||||
# other scopes
|
||||
named_scope :are_due, :conditions => ['NOT (todos.due IS NULL)']
|
||||
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 :completed_after, lambda { |date| {:conditions => ["todos.completed_at > ? ", date] } }
|
||||
named_scope :completed_before, lambda { |date| {:conditions => ["todos.completed_at < ? ", date] } }
|
||||
|
||||
# regular expressions for dependencies
|
||||
STARRED_TAG_NAME = "starred"
|
||||
DEFAULT_INCLUDES = [ :project, :context, :tags, :taggings, :pending_successors, :uncompleted_predecessors, :recurring_todo ]
|
||||
|
||||
# regular expressions for dependencies. TODO: are these still used?
|
||||
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'
|
||||
|
||||
# when entering active state, also remove completed_at date. Looks like :exit
|
||||
# of state completed is not run, see #679
|
||||
state :active, :enter => Proc.new { |t| t[:show_from], t.completed_at = nil, nil }
|
||||
state :project_hidden
|
||||
state :completed, :enter => Proc.new { |t| t.completed_at = Time.zone.now }, :exit => Proc.new { |t| t.completed_at = nil }
|
||||
state :deferred
|
||||
state :pending
|
||||
|
||||
event :defer do
|
||||
# state machine
|
||||
include AASM
|
||||
aasm_column :state
|
||||
aasm_initial_state Proc.new { |t| (t.show_from && t.user && (t.show_from > t.user.date)) ? :deferred : :active}
|
||||
|
||||
aasm_state :active
|
||||
aasm_state :project_hidden
|
||||
aasm_state :completed, :enter => Proc.new { |t| t.completed_at = Time.zone.now }, :exit => Proc.new { |t| t.completed_at = nil}
|
||||
aasm_state :deferred, :exit => Proc.new { |t| t[:show_from] = nil }
|
||||
aasm_state :pending
|
||||
|
||||
aasm_event :defer do
|
||||
transitions :to => :deferred, :from => [:active]
|
||||
end
|
||||
|
||||
event :complete do
|
||||
transitions :to => :completed, :from => [:active, :project_hidden, :deferred]
|
||||
|
||||
aasm_event :complete do
|
||||
transitions :to => :completed, :from => [:active, :project_hidden, :deferred, :pending]
|
||||
end
|
||||
|
||||
event :activate do
|
||||
transitions :to => :active, :from => [:project_hidden, :completed, :deferred]
|
||||
transitions :to => :active, :from => [:pending], :guard => :no_uncompleted_predecessors_or_deferral?
|
||||
|
||||
aasm_event :activate do
|
||||
transitions :to => :active, :from => [:project_hidden, :deferred]
|
||||
transitions :to => :active, :from => [:completed], :guard => :no_uncompleted_predecessors?
|
||||
transitions :to => :active, :from => [:pending], :guard => :no_uncompleted_predecessors_or_deferral?
|
||||
transitions :to => :pending, :from => [:completed], :guard => :uncompleted_predecessors?
|
||||
transitions :to => :deferred, :from => [:pending], :guard => :no_uncompleted_predecessors?
|
||||
end
|
||||
|
||||
event :hide do
|
||||
transitions :to => :project_hidden, :from => [:active, :deferred]
|
||||
|
||||
aasm_event :hide do
|
||||
transitions :to => :project_hidden, :from => [:active, :deferred, :pending]
|
||||
end
|
||||
|
||||
event :unhide do
|
||||
|
||||
aasm_event :unhide do
|
||||
transitions :to => :deferred, :from => [:project_hidden], :guard => Proc.new{|t| !t.show_from.blank? }
|
||||
transitions :to => :pending, :from => [:project_hidden], :guard => :uncompleted_predecessors?
|
||||
transitions :to => :active, :from => [:project_hidden]
|
||||
end
|
||||
|
||||
event :block do
|
||||
|
||||
aasm_event :block do
|
||||
transitions :to => :pending, :from => [:active, :deferred]
|
||||
end
|
||||
|
||||
|
||||
attr_protected :user
|
||||
|
||||
# Description field can't be empty, and must be < 100 bytes Notes must be <
|
||||
# 60,000 bytes (65,000 actually, but I'm being cautious)
|
||||
validates_presence_of :description
|
||||
validates_length_of :description, :maximum => 100
|
||||
validates_length_of :notes, :maximum => 60000, :allow_nil => true
|
||||
validates_length_of :notes, :maximum => 60000, :allow_nil => true
|
||||
validates_presence_of :show_from, :if => :deferred?
|
||||
validates_presence_of :context
|
||||
|
||||
|
||||
def initialize(*args)
|
||||
super(*args)
|
||||
@predecessor_array = nil # Used for deferred save of predecessors
|
||||
@removed_predecessors = nil
|
||||
end
|
||||
|
||||
|
||||
def no_uncompleted_predecessors_or_deferral?
|
||||
return (show_from.blank? or Time.zone.now > show_from and uncompleted_predecessors.empty?)
|
||||
no_deferral = show_from.blank? or Time.zone.now > show_from
|
||||
no_uncompleted_predecessors = uncompleted_predecessors.all(true).empty?
|
||||
return (no_deferral && no_uncompleted_predecessors)
|
||||
end
|
||||
|
||||
|
||||
def no_uncompleted_predecessors?
|
||||
return uncompleted_predecessors.empty?
|
||||
return uncompleted_predecessors.all(true).empty?
|
||||
end
|
||||
|
||||
|
||||
def uncompleted_predecessors?
|
||||
return !uncompleted_predecessors.all(true).empty?
|
||||
end
|
||||
|
||||
# Returns a string with description <context, project>
|
||||
def specification
|
||||
project_name = self.project.is_a?(NullProject) ? "(none)" : self.project.name
|
||||
return "\'#{self.description}\' <\'#{self.context.title}\'; \'#{project_name}\'>"
|
||||
end
|
||||
|
||||
|
||||
def validate
|
||||
if !show_from.blank? && show_from < user.date
|
||||
errors.add("show_from", I18n.t('models.todo.error_date_must_be_future'))
|
||||
|
|
@ -123,7 +141,7 @@ class Todo < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def save_predecessors
|
||||
unless @predecessor_array.nil? # Only save predecessors if they changed
|
||||
current_array = self.predecessors
|
||||
|
|
@ -145,21 +163,19 @@ class Todo < ActiveRecord::Base
|
|||
logger.error "Could not find #{todo.description}" # Unexpected since validation passed
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def removed_predecessors
|
||||
return @removed_predecessors
|
||||
end
|
||||
|
||||
|
||||
def remove_predecessor(predecessor)
|
||||
puts "@@@ before delete"
|
||||
# remove predecessor and activate myself
|
||||
self.predecessors.delete(predecessor)
|
||||
puts "@@@ before activate"
|
||||
self.activate!
|
||||
end
|
||||
|
||||
|
||||
# Returns true if t is equal to self or a successor of self
|
||||
def is_successor?(todo)
|
||||
if self == todo
|
||||
|
|
@ -176,6 +192,10 @@ class Todo < ActiveRecord::Base
|
|||
return false
|
||||
end
|
||||
|
||||
def has_pending_successors
|
||||
return !pending_successors.empty?
|
||||
end
|
||||
|
||||
def has_tag?(tag)
|
||||
return self.tags.select{|t| t.name==tag }.size > 0
|
||||
end
|
||||
|
|
@ -196,27 +216,26 @@ class Todo < ActiveRecord::Base
|
|||
end
|
||||
self.save!
|
||||
end
|
||||
|
||||
|
||||
def toggle_completion!
|
||||
saved = false
|
||||
if completed?
|
||||
saved = activate!
|
||||
else
|
||||
saved = complete!
|
||||
end
|
||||
return saved
|
||||
return completed? ? activate! : complete!
|
||||
end
|
||||
|
||||
|
||||
def show_from
|
||||
self[:show_from]
|
||||
end
|
||||
|
||||
|
||||
def show_from=(date)
|
||||
# parse Date objects into the proper timezone
|
||||
date = user.at_midnight(date) if (date.is_a? Date)
|
||||
|
||||
# show_from needs to be set before state_change because of "bug" in aasm.
|
||||
# If show_from is not set, the todo will not validate and thus aasm will not save
|
||||
# (see http://stackoverflow.com/questions/682920/persisting-the-state-column-on-transition-using-rubyist-aasm-acts-as-state-machi)
|
||||
self[:show_from] = date
|
||||
|
||||
activate! if deferred? && date.blank?
|
||||
defer! if active? && !date.blank? && date > user.date
|
||||
self[:show_from] = date
|
||||
end
|
||||
|
||||
alias_method :original_project, :project
|
||||
|
|
@ -225,46 +244,28 @@ class Todo < ActiveRecord::Base
|
|||
original_project.nil? ? Project.null_object : original_project
|
||||
end
|
||||
|
||||
alias_method :original_set_initial_state, :set_initial_state
|
||||
|
||||
def set_initial_state
|
||||
if show_from && (show_from > user.date)
|
||||
write_attribute self.class.state_column, 'deferred'
|
||||
else
|
||||
original_set_initial_state
|
||||
end
|
||||
end
|
||||
|
||||
alias_method :original_run_initial_state_actions, :run_initial_state_actions
|
||||
|
||||
def run_initial_state_actions
|
||||
# only run the initial state actions if the standard initial state hasn't
|
||||
# been changed
|
||||
if self.class.initial_state.to_sym == current_state
|
||||
original_run_initial_state_actions
|
||||
end
|
||||
end
|
||||
|
||||
def self.feed_options(user)
|
||||
{
|
||||
:title => 'Tracks Actions',
|
||||
:description => "Actions for #{user.display_name}"
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
def starred?
|
||||
tags.any? {|tag| tag.name == STARRED_TAG_NAME}
|
||||
end
|
||||
|
||||
|
||||
def toggle_star!
|
||||
if starred?
|
||||
_remove_tags STARRED_TAG_NAME
|
||||
tags.reload
|
||||
self.starred= !starred?
|
||||
end
|
||||
|
||||
def starred=(starred)
|
||||
if starred
|
||||
_add_tags STARRED_TAG_NAME unless starred?
|
||||
else
|
||||
_add_tags(STARRED_TAG_NAME)
|
||||
tags.reload
|
||||
end
|
||||
starred?
|
||||
_remove_tags STARRED_TAG_NAME
|
||||
end
|
||||
starred
|
||||
end
|
||||
|
||||
def from_recurring_todo?
|
||||
|
|
@ -284,20 +285,24 @@ class Todo < ActiveRecord::Base
|
|||
|
||||
return @predecessor_array
|
||||
end
|
||||
|
||||
|
||||
def add_predecessor(t)
|
||||
@predecessor_array = predecessors
|
||||
@predecessor_array << t
|
||||
end
|
||||
|
||||
# Return todos that should be activated if the current todo is completed
|
||||
def pending_to_activate
|
||||
return successors.find_all {|t| t.uncompleted_predecessors.empty?}
|
||||
|
||||
# activate todos that should be activated if the current todo is completed
|
||||
def activate_pending_todos
|
||||
pending_todos = successors.find_all {|t| t.uncompleted_predecessors.empty?}
|
||||
pending_todos.each {|t| t.activate! }
|
||||
return pending_todos
|
||||
end
|
||||
|
||||
|
||||
# Return todos that should be blocked if the current todo is undone
|
||||
def active_to_block
|
||||
return successors.find_all {|t| t.active? or t.deferred?}
|
||||
def block_successors
|
||||
active_successors = successors.find_all {|t| t.active? or t.deferred?}
|
||||
active_successors.each {|t| t.block!}
|
||||
return active_successors
|
||||
end
|
||||
|
||||
def raw_notes=(value)
|
||||
|
|
@ -305,27 +310,27 @@ class Todo < ActiveRecord::Base
|
|||
end
|
||||
|
||||
# Rich Todo API
|
||||
|
||||
|
||||
def self.from_rich_message(user, default_context_id, description, notes)
|
||||
fields = description.match(/([^>@]*)@?([^>]*)>?(.*)/)
|
||||
description = fields[1].strip
|
||||
context = fields[2].strip
|
||||
project = fields[3].strip
|
||||
|
||||
|
||||
context = nil if context == ""
|
||||
project = nil if project == ""
|
||||
|
||||
context_id = default_context_id
|
||||
unless(context.nil?)
|
||||
found_context = user.active_contexts.find_by_namepart(context)
|
||||
found_context = user.contexts.active.find_by_namepart(context)
|
||||
found_context = user.contexts.find_by_namepart(context) if found_context.nil?
|
||||
context_id = found_context.id unless found_context.nil?
|
||||
end
|
||||
|
||||
|
||||
unless user.contexts.exists? context_id
|
||||
raise(CannotAccessContext, "Cannot access a context that does not belong to this user.")
|
||||
end
|
||||
|
||||
|
||||
project_id = nil
|
||||
unless(project.blank?)
|
||||
if(project[0..3].downcase == "new:")
|
||||
|
|
@ -333,12 +338,12 @@ class Todo < ActiveRecord::Base
|
|||
found_project.name = project[4..255+4].strip
|
||||
found_project.save!
|
||||
else
|
||||
found_project = user.active_projects.find_by_namepart(project)
|
||||
found_project = user.projects.active.find_by_namepart(project)
|
||||
found_project = user.projects.find_by_namepart(project) if found_project.nil?
|
||||
end
|
||||
project_id = found_project.id unless found_project.nil?
|
||||
end
|
||||
|
||||
|
||||
todo = user.todos.build
|
||||
todo.description = description
|
||||
todo.raw_notes = notes
|
||||
|
|
@ -346,4 +351,5 @@ class Todo < ActiveRecord::Base
|
|||
todo.project_id = project_id unless project_id.nil?
|
||||
return todo
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
require 'digest/sha1'
|
||||
require 'bcrypt'
|
||||
|
||||
class User < ActiveRecord::Base
|
||||
# Virtual attribute for the unencrypted password
|
||||
|
|
@ -59,35 +60,23 @@ class User < ActiveRecord::Base
|
|||
self.update_positions(projects.map{ |p| p.id })
|
||||
return projects
|
||||
end
|
||||
def actionize(user_id, scope_conditions = {})
|
||||
@state = scope_conditions[:state]
|
||||
query_state = ""
|
||||
query_state = "AND project.state = '" + @state +"' "if @state
|
||||
projects = Project.find_by_sql([
|
||||
"SELECT project.id, count(todo.id) as p_count " +
|
||||
"FROM projects as project " +
|
||||
"LEFT OUTER JOIN todos as todo ON todo.project_id = project.id "+
|
||||
"WHERE project.user_id = ? AND NOT (todo.state='completed') " +
|
||||
query_state +
|
||||
" GROUP BY project.id ORDER by p_count DESC",user_id])
|
||||
self.update_positions(projects.map{ |p| p.id })
|
||||
projects = find(:all, :conditions => scope_conditions)
|
||||
return projects
|
||||
def actionize(scope_conditions = {})
|
||||
todos_in_project = find(:all, :conditions => scope_conditions, :include => [:todos])
|
||||
todos_in_project.sort!{ |x, y| -(x.todos.active.count <=> y.todos.active.count) }
|
||||
todos_in_project.reject{ |p| p.todos.active.count > 0 }
|
||||
sorted_project_ids = todos_in_project.map {|p| p.id}
|
||||
|
||||
all_project_ids = find(:all).map {|p| p.id}
|
||||
other_project_ids = all_project_ids - sorted_project_ids
|
||||
|
||||
update_positions(sorted_project_ids + other_project_ids)
|
||||
|
||||
return find(:all, :conditions => scope_conditions)
|
||||
end
|
||||
end
|
||||
has_many :active_projects,
|
||||
:class_name => 'Project',
|
||||
:order => 'projects.position ASC',
|
||||
:conditions => [ 'state = ?', 'active' ]
|
||||
has_many :active_contexts,
|
||||
:class_name => 'Context',
|
||||
:order => 'position ASC',
|
||||
:conditions => [ 'hide = ?', false ]
|
||||
has_many :todos,
|
||||
:order => 'todos.completed_at DESC, todos.created_at DESC',
|
||||
:dependent => :delete_all
|
||||
has_many :project_hidden_todos,
|
||||
:conditions => ['(state = ? OR state = ?)', 'project_hidden', 'active']
|
||||
has_many :recurring_todos,
|
||||
:order => 'recurring_todos.completed_at DESC, recurring_todos.created_at DESC',
|
||||
:dependent => :delete_all
|
||||
|
|
@ -99,33 +88,16 @@ class User < ActiveRecord::Base
|
|||
find(:all, :conditions => ['show_from <= ?', Time.zone.now ]).collect { |t| t.activate! }
|
||||
end
|
||||
end
|
||||
has_many :pending_todos,
|
||||
:class_name => 'Todo',
|
||||
:conditions => [ 'state = ?', 'pending' ],
|
||||
:order => 'show_from ASC, todos.created_at DESC'
|
||||
has_many :completed_todos,
|
||||
:class_name => 'Todo',
|
||||
:conditions => ['todos.state = ? AND NOT(todos.completed_at IS NULL)', 'completed'],
|
||||
:order => 'todos.completed_at DESC',
|
||||
:include => [ :project, :context ] do
|
||||
def completed_within( date )
|
||||
reject { |x| x.completed_at < date }
|
||||
end
|
||||
|
||||
def completed_more_than( date )
|
||||
reject { |x| x.completed_at > date }
|
||||
end
|
||||
end
|
||||
has_many :notes, :order => "created_at DESC", :dependent => :delete_all
|
||||
has_one :preference, :dependent => :destroy
|
||||
|
||||
|
||||
attr_protected :is_admin
|
||||
|
||||
validates_presence_of :login
|
||||
validates_presence_of :password, :if => :password_required?
|
||||
validates_length_of :password, :within => 5..40, :if => :password_required?
|
||||
validates_presence_of :password_confirmation, :if => :password_required?
|
||||
validates_confirmation_of :password
|
||||
validates_confirmation_of :password
|
||||
validates_length_of :login, :within => 3..80
|
||||
validates_uniqueness_of :login, :on => :create
|
||||
validates_presence_of :open_id_url, :if => :using_openid?
|
||||
|
|
@ -137,7 +109,7 @@ class User < ActiveRecord::Base
|
|||
#for will_paginate plugin
|
||||
cattr_accessor :per_page
|
||||
@@per_page = 5
|
||||
|
||||
|
||||
def validate
|
||||
unless Tracks::Config.auth_schemes.include?(auth_type)
|
||||
errors.add("auth_type", "not a valid authentication type (#{auth_type})")
|
||||
|
|
@ -152,43 +124,44 @@ class User < ActiveRecord::Base
|
|||
return nil if candidate.nil?
|
||||
|
||||
if Tracks::Config.auth_schemes.include?('database')
|
||||
return candidate if candidate.auth_type == 'database' && candidate.crypted_password == sha1(pass)
|
||||
return candidate if candidate.auth_type == 'database' and
|
||||
candidate.password_matches? 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')
|
||||
# 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
|
||||
|
||||
|
||||
def self.find_by_open_id_url(raw_identity_url)
|
||||
normalized_open_id_url = OpenIdAuthentication.normalize_identifier(raw_identity_url)
|
||||
find(:first, :conditions => ['open_id_url = ?', normalized_open_id_url])
|
||||
end
|
||||
|
||||
|
||||
def self.no_users_yet?
|
||||
count == 0
|
||||
end
|
||||
|
||||
|
||||
def self.find_admin
|
||||
find(:first, :conditions => [ "is_admin = ?", true ])
|
||||
find(:first, :conditions => [ "is_admin = ?", true ])
|
||||
end
|
||||
|
||||
|
||||
def to_param
|
||||
login
|
||||
end
|
||||
|
||||
|
||||
def display_name
|
||||
if first_name.blank? && last_name.blank?
|
||||
return login
|
||||
|
|
@ -199,13 +172,13 @@ class User < ActiveRecord::Base
|
|||
end
|
||||
"#{first_name} #{last_name}"
|
||||
end
|
||||
|
||||
|
||||
def change_password(pass,pass_confirm)
|
||||
self.password = pass
|
||||
self.password_confirmation = pass_confirm
|
||||
save!
|
||||
end
|
||||
|
||||
|
||||
def time
|
||||
Time.now.in_time_zone(prefs.time_zone)
|
||||
end
|
||||
|
|
@ -213,23 +186,23 @@ class User < ActiveRecord::Base
|
|||
def date
|
||||
time.midnight
|
||||
end
|
||||
|
||||
|
||||
def at_midnight(date)
|
||||
return ActiveSupport::TimeZone[prefs.time_zone].local(date.year, date.month, date.day, 0, 0, 0)
|
||||
end
|
||||
|
||||
|
||||
def generate_token
|
||||
self.token = Digest::SHA1.hexdigest "#{Time.now.to_i}#{rand}"
|
||||
self.token = sha1 "#{Time.now.to_i}#{rand}"
|
||||
end
|
||||
|
||||
|
||||
def remember_token?
|
||||
remember_token_expires_at && Time.now.utc < remember_token_expires_at
|
||||
remember_token_expires_at && Time.now.utc < remember_token_expires_at
|
||||
end
|
||||
|
||||
|
||||
# These create and unset the fields required for remembering users between browser closes
|
||||
def remember_me
|
||||
self.remember_token_expires_at = 2.weeks.from_now.utc
|
||||
self.remember_token ||= self.class.sha1("#{login}--#{remember_token_expires_at}")
|
||||
self.remember_token ||= sha1("#{login}--#{remember_token_expires_at}")
|
||||
save(false)
|
||||
end
|
||||
|
||||
|
|
@ -239,38 +212,55 @@ class User < ActiveRecord::Base
|
|||
save(false)
|
||||
end
|
||||
|
||||
# Returns true if the user has a password hashed using SHA-1.
|
||||
def uses_deprecated_password?
|
||||
crypted_password =~ /^[a-f0-9]{40}$/i
|
||||
end
|
||||
|
||||
def password_matches?(pass)
|
||||
if uses_deprecated_password?
|
||||
crypted_password == sha1(pass)
|
||||
else
|
||||
BCrypt::Password.new(crypted_password) == pass
|
||||
end
|
||||
end
|
||||
|
||||
def salted(s)
|
||||
"#{Tracks::Config.salt}--#{s}--"
|
||||
end
|
||||
|
||||
def sha1(s)
|
||||
Digest::SHA1.hexdigest salted s
|
||||
end
|
||||
|
||||
def hash(s)
|
||||
BCrypt::Password.create s
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def self.sha1(s)
|
||||
Digest::SHA1.hexdigest("#{Tracks::Config.salt}--#{s}--")
|
||||
end
|
||||
|
||||
def crypt_password
|
||||
return if password.blank?
|
||||
write_attribute("crypted_password", self.class.sha1(password)) if password == password_confirmation
|
||||
write_attribute("crypted_password", hash(password)) if password == password_confirmation
|
||||
end
|
||||
|
||||
|
||||
def password_required?
|
||||
auth_type == 'database' && crypted_password.blank? || !password.blank?
|
||||
end
|
||||
|
||||
|
||||
def using_openid?
|
||||
auth_type == 'open_id'
|
||||
end
|
||||
|
||||
def password_matches?(pass)
|
||||
crypted_password == sha1(pass)
|
||||
end
|
||||
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -12,15 +12,15 @@
|
|||
|
||||
|
||||
<label for="context_name">Context name</label><br/>
|
||||
<%= text_field('context', 'name', :class => 'context-name') %><br/>
|
||||
<%= text_field('context', 'name', :class => 'context-name', :tabindex => next_tab_index) %><br/>
|
||||
|
||||
<label for="context_hide">Hide from front page?</label>
|
||||
<%= check_box('context', 'hide', :class => 'context-hide') %>
|
||||
<%= check_box('context', 'hide', {:class => 'context-hide', :tabindex => next_tab_index}) %>
|
||||
<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">
|
||||
<button type="submit" class="positive" id="<%= dom_id(context, 'submit') %>" tabindex="<%=next_tab_index%>">
|
||||
<%=image_tag("accept.png", :alt => "") %>
|
||||
<%= t 'common.update' %>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
<%- reset_tab_index %>
|
||||
<div id="context_new_container">
|
||||
|
||||
<div id="toggle_context_link" class="hide_form">
|
||||
|
|
@ -10,10 +11,10 @@
|
|||
<div id="error_status"><%= error_messages_for('context') %></div>
|
||||
|
||||
<label for="context_name"><%= t 'contexts.context_name' %></label><br />
|
||||
<%= text_field( "context", "name" ) %><br />
|
||||
<%= text_field( "context", "name", :tabindex => next_tab_index ) %><br />
|
||||
|
||||
<label for="context_hide"><%= t 'contexts.context_hide' %></label>
|
||||
<%= check_box( "context", "hide" ) %><br />
|
||||
<%= check_box( "context", "hide", {:tabindex => next_tab_index} ) %><br />
|
||||
|
||||
<div class="submit_box">
|
||||
<div class="widgets">
|
||||
|
|
|
|||
|
|
@ -56,6 +56,10 @@
|
|||
<ul>
|
||||
<li>/todos.xml</li>
|
||||
<li>/todos/<code>ID</code>.xml</li>
|
||||
<li>/tickler.xml</li>
|
||||
<li>/done.xml</li>
|
||||
<li>/hidden.xml</li>
|
||||
<li>/calendar.xml</li>
|
||||
<li>/contexts.xml</li>
|
||||
<li>/contexts/<code>ID</code>.xml</li>
|
||||
<li>/contexts/<code>ID</code>/todos.xml</li>
|
||||
|
|
@ -64,6 +68,17 @@
|
|||
<li>/projects/<code>ID</code>/todos.xml</li>
|
||||
</ul>
|
||||
|
||||
<p>For the todo resources (todos, tickler, done, hidden and calendar) you can limit the returned
|
||||
field to <code>ID, created_at, modified_at, completed_at</code> by adding the parameter
|
||||
<code>limit_fields</code> and setting it to <code>index</code>. For example:</p>
|
||||
|
||||
<pre>
|
||||
<code>
|
||||
$ curl -u username:p4ssw0rd -H "Content-Type: text/xml" \
|
||||
<%= home_url %>tickler.xml?limit_fields=index
|
||||
</code>
|
||||
</pre>
|
||||
|
||||
<h2>Writing to the API</h2>
|
||||
|
||||
<p>The API provides mechanisms for adding, updating and deleting resources using the HTTP methods <code>PUT</code>, <code>POST</code> and <code>DELETE</code> in combination with the content.</p>
|
||||
|
|
@ -173,17 +188,17 @@ $ curl -u username:p4ssw0rd -H "Content-Type: text/xml" \
|
|||
|
||||
<pre>
|
||||
<code>
|
||||
$ script/console
|
||||
$ script/console
|
||||
Loading development environment (Rails 1.2.4)
|
||||
>> class Context < ActiveResource::Base; end
|
||||
=> nil
|
||||
>> Context.site = "<%= home_url %>"
|
||||
=> "<%= home_url %>"
|
||||
>> Context.site.user = "username"
|
||||
=> "username"
|
||||
=> "<%= home_url %>"
|
||||
>> Context.site.user = "username"
|
||||
=> "username"
|
||||
|
||||
>> Context.site.password = CGI.escape "p4ssw0rd"
|
||||
=> "p4ssw0rd"
|
||||
>> Context.site.password = CGI.escape "p4ssw0rd"
|
||||
=> "p4ssw0rd"
|
||||
>> Context.find :first
|
||||
=> #<Context:0x262396c @prefix_options={}, @attributes={...}>
|
||||
>> >> Context.find :all
|
||||
|
|
@ -201,7 +216,7 @@ $ SITE="http://username:p4ssw0rd@<%= request.host_with_port %>" irb \
|
|||
|
||||
irb(main):001:0> inbox = Tracks::Context.find :first
|
||||
irb(main):002:0> inbox.name
|
||||
=> "@inbox"
|
||||
=> "@inbox"
|
||||
irb(main):003:0>
|
||||
</code>
|
||||
</pre>
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<%= stylesheet_link_tag "scaffold" %>
|
||||
<%= javascript_include_tag 'jquery-1.5.2.min', 'jquery.cookie' %>
|
||||
|
||||
<%= javascript_include_tag 'jquery-1.6.2.min', 'jquery.cookie' %>
|
||||
|
||||
<title><%= @page_title -%></title>
|
||||
|
||||
</head>
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
<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-1.8.11.custom', :cache => 'tracks-cached' %>
|
||||
<%= stylesheet_link_tag 'standard','superfish','niftyCorners', 'jquery-ui-1.8.15.custom', :cache => 'tracks-cached' %>
|
||||
<%= stylesheet_link_tag "print", :media => "print" %>
|
||||
<%= javascript_include_tag 'jquery-1.5.2.min', 'jquery-ui-1.8.11.custom.min',
|
||||
<%= javascript_include_tag 'jquery-1.6.2.min', 'jquery-ui-1.8.15.custom.min',
|
||||
'jquery.truncator','jquery.jeditable.mini', 'jquery.cookie', 'jquery.blockUI',
|
||||
'jquery.form',
|
||||
:cache => 'jquery-cached' %>
|
||||
|
|
@ -48,7 +48,9 @@
|
|||
</h1>
|
||||
</div>
|
||||
<div id="minilinks">
|
||||
<%= link_to(t('layouts.toggle_notes'), "#", {:accesskey => "S", :title => t('layouts.toggle_notes_title'), :id => "toggle-notes-nav"}) %>
|
||||
<%= link_to(t('layouts.toggle_contexts'), "#", {:title => t('layouts.toggle_contexts_title'), :id => "toggle-contexts-nav"}) %>
|
||||
|
|
||||
<%= link_to(t('layouts.toggle_notes'), "#", {:accesskey => "S", :title => t('layouts.toggle_notes_title'), :id => "toggle-notes-nav"}) %>
|
||||
|
|
||||
<%= link_to( t('common.logout') + " (#{current_user.display_name}) »", logout_path) %>
|
||||
</div>
|
||||
|
|
@ -62,13 +64,14 @@
|
|||
<ul>
|
||||
<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('common.review'), review_path, {:accesskey => "r", :title => t('layouts.navigation.review_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="#"><%= t('layouts.navigation.view') %></a>
|
||||
<ul>
|
||||
<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.completed_tasks'), done_overview_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>
|
||||
|
|
|
|||
|
|
@ -5,4 +5,5 @@
|
|||
-%>
|
||||
$('div#navcontainer').hide();
|
||||
$('div#content').html('<%=theHtml%>');
|
||||
refresh_page(); // refresh the page. if it fails, the message above remains
|
||||
<% end -%>
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
<%
|
||||
submit_text ||= t('common.update')
|
||||
note = note_edit_form
|
||||
|
||||
form_for(note_edit_form, :html => {
|
||||
:id => dom_id(note_edit_form, 'edit_form'),
|
||||
form_for(note, :html => {
|
||||
:id => dom_id(note, 'edit_form'),
|
||||
:class => "inline-form edit-note-form"}) do |f|
|
||||
-%>
|
||||
|
||||
|
|
@ -13,11 +14,11 @@ form_for(note_edit_form, :html => {
|
|||
|
||||
<div class="submit_box">
|
||||
<div class="widgets">
|
||||
<button type="submit" class="positive" id="<%= dom_id(note_edit_form, 'submit') %>" tabindex="15">
|
||||
<button type="submit" class="positive" id="<%= dom_id(note, 'submit') %>" tabindex="15">
|
||||
<%=image_tag("accept.png", :alt => "") %>
|
||||
<%= submit_text %>
|
||||
</button>
|
||||
<a href="" class="negative" id="neg_<%=dom_id(note_edit_form, 'edit_form')%>">
|
||||
<a href="" class="negative" id="neg_<%=dom_id(note, 'edit_form')%>">
|
||||
<%=image_tag("cancel.png", :alt => "") %>
|
||||
<%= t 'common.cancel' %>
|
||||
</a>
|
||||
|
|
|
|||
37
app/views/preferences/_authentication.html.erb
Normal file
37
app/views/preferences/_authentication.html.erb
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<label><%= t('preferences.token_header') %></label><br/><br/>
|
||||
<%= t('preferences.token_description') %>: <span class="highlight"><%= current_user.token %></span>
|
||||
<br/><br/>
|
||||
|
||||
<div class="pref_new_token">
|
||||
|
||||
<% # TODO: make remote AJAX call for new token %>
|
||||
|
||||
<%= link_to(
|
||||
t('preferences.generate_new_token'),
|
||||
refresh_token_user_path( current_user ),
|
||||
:method => :post,
|
||||
:confirm => t('preferences.generate_new_token_confirm'),
|
||||
:id=>'prefs_new_token') %>
|
||||
|
||||
</div>
|
||||
<br/>
|
||||
|
||||
<% if Tracks::Config.auth_schemes.length > 1 %>
|
||||
<label for="user_auth_type"><%= t('users.label_auth_type') %>:</label><br/>
|
||||
<% Tracks::Config.auth_schemes.each do |scheme| %>
|
||||
<%= radio_button_tag('user[auth_type]', scheme, current_user.auth_type == scheme) %><%=scheme%> <br/>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<br/>
|
||||
|
||||
<div id="open_id" style="display:<%= current_user.auth_type == 'open_id' ? 'block' : 'none' %>">
|
||||
<label for="openid_url"><%= t('users.identity_url') %>:</label><br/>
|
||||
<input type="text" name="user[open_id_url]" value="<%= current_user.open_id_url %>" class="open_id" />
|
||||
</div>
|
||||
|
||||
<div id="database" style="display:<%= current_user.auth_type == 'database' ? 'block' : 'none' %>">
|
||||
<%= render :partial => 'users/update_password' %>
|
||||
</div>
|
||||
|
||||
|
||||
23
app/views/preferences/_date_and_time.html.erb
Normal file
23
app/views/preferences/_date_and_time.html.erb
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<%= pref_with_text_field('prefs', 'date_format') %>
|
||||
|
||||
<div class='prefs_example'>This will result in: <span id='prefs.date_format'><%= l(Date.today, :format => current_user.prefs.date_format) %></span></div>
|
||||
<br/>
|
||||
Or pick one of the following:<br/>
|
||||
<% %w{default short long longer}.each do |format| %>
|
||||
<%= radio_button_tag("date_picker1", t("date.formats.#{format}")) %> <%= l(Date.today, :format => format.to_sym) %> <br/>
|
||||
<% end %>
|
||||
<br/>
|
||||
|
||||
<%= pref_with_text_field('prefs', 'title_date_format') %>
|
||||
<div class='prefs_example'>This will result in: <span id='prefs.title_date_format'><%= l(Date.today, :format => current_user.prefs.title_date_format) %></span></div>
|
||||
<br/>
|
||||
Or pick one of the following:<br/>
|
||||
<% %w{default short long longer}.each do |format| %>
|
||||
<%= radio_button_tag("date_picker2", t("date.formats.#{format}")) %> <%= l(Date.today, :format => format.to_sym) %> <br/>
|
||||
<% end %>
|
||||
<br/>
|
||||
|
||||
<%= pref('prefs', 'time_zone') { time_zone_select('prefs','time_zone') } %>
|
||||
|
||||
<%= pref_with_select_field('prefs', "week_starts", (0..6).to_a.map {|num| [t('date.day_names')[num], num] }) %>
|
||||
|
||||
6
app/views/preferences/_profile.html.erb
Normal file
6
app/views/preferences/_profile.html.erb
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<%= pref_with_text_field 'user', 'first_name' %>
|
||||
<%= pref_with_text_field 'user', 'last_name' %>
|
||||
<%= pref_with_select_field('prefs', 'locale', I18n.available_locales.map {|l| l.to_s}) %>
|
||||
<% if current_user.is_admin? %>
|
||||
<%= pref_with_text_field('prefs', 'admin_email') %>
|
||||
<% end %>
|
||||
14
app/views/preferences/_tracks_behavior.html.erb
Normal file
14
app/views/preferences/_tracks_behavior.html.erb
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
<%= pref_with_select_field('prefs', "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]]]) %>
|
||||
<%= pref_with_select_field('prefs', "show_completed_projects_in_sidebar") %>
|
||||
<%= pref_with_select_field('prefs', "show_hidden_projects_in_sidebar") %>
|
||||
<%= pref_with_select_field('prefs', "show_hidden_contexts_in_sidebar") %>
|
||||
<%= pref_with_select_field('prefs', "show_project_on_todo_done") %>
|
||||
<%= pref_with_text_field('prefs', 'staleness_starts') %>
|
||||
<%= pref_with_text_field('prefs', 'review_period') %>
|
||||
<%= pref_with_text_field('prefs', 'show_number_completed') %>
|
||||
<%= pref_with_text_field('prefs', 'refresh') %>
|
||||
<%= pref_with_select_field('prefs', "verbose_action_descriptors") %>
|
||||
<%= pref_with_text_field('prefs', "mobile_todos_per_page") %>
|
||||
<%= pref_with_text_field('prefs', "sms_email") %>
|
||||
<%= pref('prefs', "sms_context") { select('prefs', 'sms_context_id', current_user.contexts.map{|c| [c.name, c.id]}) } %>
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
<div id="display_box" class="container context">
|
||||
<%= render :partial => 'help' %>
|
||||
</div>
|
||||
|
||||
<div id="input_box" class="container context">
|
||||
<% form_tag :action => 'update' do %>
|
||||
<table>
|
||||
<tr>
|
||||
<td><label><%= User.human_attribute_name('first_name') %></label></td>
|
||||
<td><%= text_field 'user', 'first_name' %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<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>#{Preference.human_attribute_name(pref_name)}:</label></td>\n<td>\n|
|
||||
s << yield
|
||||
s << "\n</td></tr>"
|
||||
s
|
||||
end
|
||||
|
||||
def row_with_select_field(pref_name, collection = [ [t('preferences.is_true'),true], [t('preferences.is_false'), false] ], nowrap_label = false)
|
||||
table_row(pref_name, nowrap_label) { select('prefs', pref_name, collection) }
|
||||
end
|
||||
|
||||
def row_with_text_field(pref_name, nowrap_label = false)
|
||||
table_row(pref_name, nowrap_label) { text_field('prefs', pref_name) }
|
||||
end
|
||||
%>
|
||||
<%= row_with_select_field('locale', I18n.available_locales.map {|l| l.to_s}) %>
|
||||
<%= 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", (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") %>
|
||||
<%= row_with_select_field("show_project_on_todo_done") %>
|
||||
|
||||
<% if current_user.is_admin? %> <%= row_with_text_field('admin_email') %> <% end %>
|
||||
<%= row_with_text_field('staleness_starts', false) %>
|
||||
<%= row_with_text_field('show_number_completed') %>
|
||||
<%= row_with_text_field('refresh') %>
|
||||
<%= row_with_select_field("verbose_action_descriptors") %>
|
||||
<%= row_with_text_field("mobile_todos_per_page") %>
|
||||
<%= 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 t('common.update') %></td>
|
||||
<td><%= link_to t('common.cancel'), :action => 'index' %></td>
|
||||
</tr>
|
||||
</table>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
@ -1,68 +1,32 @@
|
|||
<div id="single_box" class="container context prefscontainer">
|
||||
<div id="display_box">
|
||||
|
||||
<h2><%= t('preferences.title') %></h2>
|
||||
<div id="edit_error_status"><%= error_messages_for(:user) + error_messages_for(:prefs) %></div>
|
||||
|
||||
<ul id="prefs">
|
||||
<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] %>
|
||||
<%= t('models.preference.due_styles')[0] %>
|
||||
<% else %>
|
||||
<%= t('models.preference.due_styles')[1] %>
|
||||
<% end %>
|
||||
</span></li>
|
||||
<% if current_user.is_admin? %>
|
||||
<li><%= Preference.human_attribute_name('admin_email') %>: <span class="highlight"><%= current_user.prefs.admin_email %></span></li>
|
||||
<% end %>
|
||||
<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 t('preferences.edit_preferences') + " »", { :controller => 'preferences', :action => 'edit'}, :class => 'edit_link' %>
|
||||
</div>
|
||||
|
||||
<h2><%= t('preferences.token_header') %></h2>
|
||||
<div id="token_area">
|
||||
<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 t('preferences.generate_new_token'), refresh_token_user_path(current_user),
|
||||
:confirm => t('preferences.generate_new_token_confirm') %>
|
||||
<% form_tag :action => 'update' do %>
|
||||
<div id="tabs">
|
||||
<ul>
|
||||
<li><a href="#tabs-1"><%= t('preferences.tabs.profile')%></a></li>
|
||||
<li><a href="#tabs-2"><%= t('preferences.tabs.authentication')%></a></li>
|
||||
<li><a href="#tabs-3"><%= t('preferences.tabs.date_and_time')%></a></li>
|
||||
<li><a href="#tabs-4"><%= t('preferences.tabs.tracks_behavior')%></a></li>
|
||||
</ul>
|
||||
<div id="tabs-1">
|
||||
<%= render :partial => 'profile'%>
|
||||
</div>
|
||||
<div id="tabs-2">
|
||||
<%= render :partial => 'authentication'%>
|
||||
</div>
|
||||
<div id="tabs-3">
|
||||
<%= render :partial => 'date_and_time'%>
|
||||
</div>
|
||||
<div id="tabs-4">
|
||||
<%= render :partial => 'tracks_behavior'%>
|
||||
</div>
|
||||
</div>
|
||||
<h2><%= t('preferences.authentication_header') %></h2>
|
||||
<div id="authentication_area">
|
||||
<% if Tracks::Config.auth_schemes.length > 1 %>
|
||||
<p><%= t('preferences.current_authentication_type', :auth_type => "<span class=\"highlight\">#{current_user.auth_type}</span>") %>.</p>
|
||||
<div class="actions">
|
||||
<%= link_to(t('preferences.change_authentication_type') + " »", change_auth_type_user_path(current_user), :class => 'edit_link') %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% if current_user.auth_type == 'database' %>
|
||||
<div class="actions">
|
||||
<%= link_to(t('preferences.change_password') + ' »', change_password_user_path(current_user)) %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% if current_user.auth_type == 'open_id' %>
|
||||
<p><%= t('preferences.open_id_url') %> <span class="highlight"><%= current_user.open_id_url %></span>.</p>
|
||||
<div class="actions">
|
||||
<%= link_to(t('preferences.change_identity_url') + ' »', change_auth_type_user_path(current_user)) %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
|
||||
<button type="submit" id="prefs_submit"><%= t('common.update') %></button>
|
||||
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
<%= hidden_field( "project", "id" ) %>
|
||||
<label for="project_name">Project name</label><br />
|
||||
<%= text_field( "project", "name" ) %>
|
||||
<br />
|
||||
<br />
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
<%- reset_tab_index %>
|
||||
<div id="project_new_project_container">
|
||||
|
||||
<div id="toggle_project_link" class="hide_form">
|
||||
|
|
@ -9,19 +10,19 @@
|
|||
<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 />
|
||||
<%= text_field 'project', 'name', "tabindex" => next_tab_index %><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 />
|
||||
<%= text_area 'project', 'description', "cols" => 30, "rows" => 4, "tabindex" => next_tab_index %><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) %>
|
||||
<%= text_field_tag("project[default_context_name]", @new_project.default_context.name, :tabindex => next_tab_index) %>
|
||||
<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) %>
|
||||
<%= text_field_tag("project[default_tags]", @new_project.default_tags, :tabindex => next_tab_index) %>
|
||||
|
||||
<br/>
|
||||
|
||||
|
|
@ -33,7 +34,7 @@
|
|||
</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 />
|
||||
<input id="go_to_project" type="checkbox" tabindex="<%= next_tab_index%>" name="go_to_project"/><label for="go_to_project"><%= t('projects.to_new_project_page') %></label><br />
|
||||
|
||||
<% end -%>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
<div class="container">
|
||||
<h2 id="project_name">
|
||||
<h2 id="project_name_container">
|
||||
<% if collapsible -%>
|
||||
<a href="#" class="container_toggle" id="toggle_p<%= project.id %>"><%= image_tag("collapse.png") %></a>
|
||||
<% end -%>
|
||||
<%= project.name -%></h2>
|
||||
<div id="project_name" style="width: 100%;"><%= project.name -%></div>
|
||||
</h2>
|
||||
<div id="<%= dom_id(project, "container")%>" class="list"><%-# list needs to be here for edit form to work -%>
|
||||
<%= render :partial => "projects/project_settings", :object => project, :locals => { :collapsible => collapsible } %>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -11,28 +11,28 @@ project = project_form
|
|||
<%= source_view_tag( @source_view ) -%>
|
||||
|
||||
<label for="project_name">Name:</label><br/>
|
||||
<%= text_field :project, 'name', :class => 'project-name' %><br/>
|
||||
<%= text_field :project, 'name', :class => 'project-name', :tabindex => next_tab_index %><br/>
|
||||
|
||||
<label for="project_description">Description (optional):</label><br/>
|
||||
<%= text_area :project, 'description', "cols" => 30, "rows" => 4, :class => 'project-description' %><br/>
|
||||
<%= text_area :project, 'description', "cols" => 30, "rows" => 4, :class => 'project-description', :tabindex => next_tab_index %><br/>
|
||||
|
||||
<label for="project_done">Project status:</label><br/>
|
||||
<% ['active', 'hidden', 'completed'].each do | state | %>
|
||||
<%= radio_button(:project, 'state', state) %> <%= state.titlecase %>
|
||||
<%= radio_button(:project, 'state', state, {:tabindex => next_tab_index}) %> <%= state.titlecase %>
|
||||
<% end %><br/>
|
||||
|
||||
<label for="project[default_context_name]">Default Context</label><br/>
|
||||
<%= text_field_tag("project[default_context_name]", project.default_context.name, {:tabindex=>1,:size=> 25}) %>
|
||||
<%= text_field_tag("project[default_context_name]", project.default_context.name, {:tabindex=>next_tab_index,:size=> 25}) %>
|
||||
<br/>
|
||||
|
||||
<label for="project[default_tags]">Default Tags</label><br/>
|
||||
<%= text_field_tag("project[default_tags]", project.default_tags, {:tabindex=>2,:size=> 25}) %>
|
||||
<%= text_field_tag("project[default_tags]", project.default_tags, {:tabindex=>next_tab_index,:size=> 25}) %>
|
||||
<br/>
|
||||
|
||||
<input type="hidden" name="wants_render" value="true" />
|
||||
<div class="submit_box">
|
||||
<div class="widgets" id="<%= dom_id(project, 'widgets') %>">
|
||||
<button type="submit" class="positive" id="<%= dom_id(project, 'submit') %>" tabindex="15">
|
||||
<button type="submit" class="positive" id="<%= dom_id(project, 'submit') %>" tabindex="<%=next_tab_index%>">
|
||||
<%=image_tag("accept.png", :alt => "") %>
|
||||
Update
|
||||
</button>
|
||||
|
|
@ -40,6 +40,10 @@ project = project_form
|
|||
<%=image_tag("cancel.png", :alt => "") %>
|
||||
Cancel
|
||||
</a>
|
||||
<a href="<%=set_reviewed_project_path(project)%>" id="<%= dom_id(project, 'reviewed') %>" class="reviewed">
|
||||
<%=image_tag("reviewed.png", :alt => "") %>
|
||||
Reviewed
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<br/><br/>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
project = project_listing
|
||||
suppress_drag_handle ||= false
|
||||
suppress_edit_button ||= false
|
||||
suppress_delete_button ||= false
|
||||
-%>
|
||||
<div id="<%= dom_id(project, "container") %>" class="list">
|
||||
<div id="<%= dom_id(project) %>" class="project sortable_row" style="display:block">
|
||||
|
|
@ -12,13 +13,17 @@ suppress_edit_button ||= false
|
|||
</div>
|
||||
<% end -%>
|
||||
|
||||
|
||||
<div class="data">
|
||||
<%= link_to_project( project ) %><%= " (" + count_undone_todos_and_notes_phrase(project,"actions") + ")" %>
|
||||
<span class="<%= needsreview_class( project ) %>">
|
||||
<%= link_to_project( project ) %>
|
||||
<%= " (" + count_undone_todos_and_notes_phrase(project,"actions") + ")" %>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="buttons">
|
||||
<span class="grey"><%= project.current_state.to_s.upcase %></span>
|
||||
<%= link_to_delete_project(project, image_tag( "blank.png", :title => t('projects.delete_project_title'), :class=>"delete_item")) %>
|
||||
<span class="grey"><%= project.aasm_current_state.to_s.upcase %></span>
|
||||
<%= suppress_delete_button ? "" : 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>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,31 @@
|
|||
<%-
|
||||
total_count ||= -1
|
||||
total_count_string = total_count!=-1 ? " / #{total_count}" : ""
|
||||
suppress_sort_menu ||= false
|
||||
suppress_drag_handle ||= false
|
||||
-%>
|
||||
<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><%= t('states.'+state+'_plural' )%> <%= t('common.projects') %></h2>
|
||||
<h2>
|
||||
<span id="<%= state %>-projects-count" class="badge"><%= project_state_group.length%><%= total_count_string%></span>
|
||||
|
||||
<%= t('common.last' ) unless ( ['review','stalled','blocked','current'].include?(state) )%>
|
||||
<%= t('states.'+state+'_plural' )%>
|
||||
<%= t('common.projects') %><%= total_count==-1 ? "" : " ("+link_to("Show all", done_projects_path)+")"%>
|
||||
|
||||
</h2>
|
||||
<% unless suppress_sort_menu %>
|
||||
<div class="menu_sort"><span class="sort_separator"><%= t('common.sort.sort') %> </span>
|
||||
<div class="alpha_sort">
|
||||
<%= link_to("Alphabetically", alphabetize_projects_path(:state => state),
|
||||
<%= link_to(t("common.sort.alphabetically"), alphabetize_projects_path(:state => state),
|
||||
: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"> | </span><div class="tasks_sort">
|
||||
<%= link_to("By number of tasks", actionize_projects_path(:state => state),
|
||||
<%= link_to(t("common.sort.by_task_count"), actionize_projects_path(:state => state),
|
||||
: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>
|
||||
<% end %>
|
||||
|
||||
<div id="list-<%= state %>-projects" class="project-list">
|
||||
<%= render :partial => 'project_listing', :collection => project_state_group %>
|
||||
<%= render :partial => 'projects/project_listing', :collection => project_state_group, :locals => {:suppress_drag_handle => suppress_drag_handle} %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
37
app/views/projects/done.html.erb
Normal file
37
app/views/projects/done.html.erb
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<%
|
||||
paginate_options = {
|
||||
:class => :add_note_link,
|
||||
:previous_label => '« '+ t('common.previous'),
|
||||
:next_label => t('common.next')+' »',
|
||||
:inner_window => 2
|
||||
}
|
||||
%>
|
||||
<div id="display_box">
|
||||
<div id="projects-empty-nd" style="<%= @no_projects ? 'display:block' : 'display:none'%>">
|
||||
<div class="message"><p><%= t('projects.no_projects') %></p></div>
|
||||
</div>
|
||||
|
||||
<div class="project-state-group" id="list-completed-projects-container" <%= " style=\"display:none\"" if @no_projects %>>
|
||||
<%= will_paginate @projects, paginate_options %>
|
||||
<h2>
|
||||
<span id="completed-projects-count" class="badge"><%= "#{@total} (#{@range_low}-#{@range_high})" %></span>
|
||||
<%= t('states.completed_plural' )%> <%= t('common.projects') %>
|
||||
</h2>
|
||||
<div id="list-completed-projects" class="project-list">
|
||||
<%= render :partial => 'project_listing', :collection => @projects %>
|
||||
</div>
|
||||
</div>
|
||||
<%= will_paginate @projects, paginate_options %>
|
||||
</div>
|
||||
|
||||
<div id="input_box">
|
||||
<div class="menu_sort"><h2><br/><%= t('common.sort.sort') %> <%= t('states.completed_plural' )%> <%= t('common.projects') %></h2>
|
||||
<div class="alpha_sort">
|
||||
<%= link_to(t("common.sort.alphabetically"), alphabetize_projects_path(:state => :completed),
|
||||
:id => "completed_alphabetize_link", :class => "alphabetize_link", :title => t('common.sort.alphabetically_title'), :x_confirm_message => t('common.sort.alphabetically_confirm')) %>
|
||||
</div><span class="sort_separator"> | </span><div class="tasks_sort">
|
||||
<%= link_to(t("common.sort.by_task_count"), actionize_projects_path(:state => :completed),
|
||||
:id => "completed_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>
|
||||
</div>
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
</div>
|
||||
<%= render :partial => 'project_state_group', :object => @active_projects, :locals => { :state => 'active'} %>
|
||||
<%= render :partial => 'project_state_group', :object => @hidden_projects, :locals => { :state => 'hidden'} %>
|
||||
<%= render :partial => 'project_state_group', :object => @completed_projects, :locals => { :state => 'completed'} %>
|
||||
<%= render :partial => 'project_state_group', :object => @completed_projects, :locals => { :state => 'completed', :total_count => @completed_count} %>
|
||||
</div>
|
||||
|
||||
<div id="input_box">
|
||||
|
|
|
|||
|
|
@ -24,4 +24,4 @@
|
|||
<% else -%><%= render :partial => "notes/mobile_notes_summary", :collection => @project.notes %>
|
||||
<% end -%>
|
||||
<h2><%= t('projects.settings') %></h2>
|
||||
<%= t('projects.state', :state => project.current_state.to_s) %>. <%= @project_default_context %>
|
||||
<%= t('projects.state', :state => project.aasm_current_state.to_s) %>. <%= @project_default_context %>
|
||||
7
app/views/projects/review.html.erb
Normal file
7
app/views/projects/review.html.erb
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<div id="projects-empty-nd" style="<%= @no_projects ? 'display:block' : 'display:none'%>">
|
||||
<div class="message"><p><%= t('projects.no_projects') %></p></div>
|
||||
</div>
|
||||
<%= render :partial => 'project_state_group', :object => @projects_to_review, :locals => { :state => 'review', :suppress_sort_menu => true, :suppress_drag_handle => true} %>
|
||||
<%= render :partial => 'project_state_group', :object => @stalled_projects, :locals => { :state => 'stalled', :suppress_sort_menu => true, :suppress_drag_handle => true} %>
|
||||
<%= render :partial => 'project_state_group', :object => @blocked_projects, :locals => { :state => 'blocked', :suppress_sort_menu => true, :suppress_drag_handle => true} %>
|
||||
<%= render :partial => 'project_state_group', :object => @current_projects, :locals => { :state => 'current', :suppress_sort_menu => true, :suppress_drag_handle => true} %>
|
||||
|
|
@ -6,7 +6,6 @@
|
|||
-%>
|
||||
update_project_page();
|
||||
<% end %>
|
||||
TracksForm.set_project_name_and_default_project_name("<%= escape_javascript(@project.name)%>");
|
||||
<% else -%>
|
||||
TracksPages.show_edit_errors(html_for_error_messages());
|
||||
<% end %>
|
||||
|
|
@ -24,12 +23,14 @@ function update_project_list_page() {
|
|||
|
||||
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 %>);
|
||||
TracksForm.set_project_name_and_default_project_name("<%= escape_javascript(@project.name)%>");
|
||||
}
|
||||
|
||||
function update_project_page() {
|
||||
remove_project_edit_form();
|
||||
update_and_show_project_settings();
|
||||
TracksForm.set_project_name("<%= escape_javascript(@project.name)%>");
|
||||
$("h2#project_name").html("<%= escape_javascript(@project.name)%>");
|
||||
<% if @project.default_context %>
|
||||
TracksForm.set_context_name_and_default_context_name("<%= escape_javascript(@project.default_context.name)%>");
|
||||
<% end %>
|
||||
|
|
@ -75,7 +76,7 @@ function remove_and_re_add_project() {
|
|||
<%
|
||||
# the following functions return empty string if rendering the partial is not
|
||||
# necessary, for example the sidebar is not on the project list page, so do not
|
||||
# render it into the function.
|
||||
# render it into the function.
|
||||
-%>
|
||||
function html_for_project_listing() {
|
||||
return "<%= source_view_is(:project_list) ? escape_javascript(render(:partial => 'project_listing', :object => @project )) : "" %>";
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
# TODO: is this dead code?
|
||||
page.select('#project_status .active span').each do |element|
|
||||
element.className = @project.current_state == :active ? 'active_state' : 'inactive_state'
|
||||
element.className = @project.aasm_current_state == :active ? 'active_state' : 'inactive_state'
|
||||
end
|
||||
page.select('#project_status .hidden span').each do |element|
|
||||
element.className = @project.current_state == :hidden ? 'active_state' : 'inactive_state'
|
||||
element.className = @project.aasm_current_state == :hidden ? 'active_state' : 'inactive_state'
|
||||
end
|
||||
page.select('#project_status .completed span').each do |element|
|
||||
element.className = @project.current_state == :completed ? 'active_state' : 'inactive_state'
|
||||
element.className = @project.aasm_current_state == :completed ? 'active_state' : 'inactive_state'
|
||||
end
|
||||
page.notify :notice, "Set project status to #{@project.current_state}", 5.0
|
||||
page.notify :notice, "Set project status to #{@project.aasm_current_state}", 5.0
|
||||
|
|
|
|||
|
|
@ -12,101 +12,100 @@
|
|||
<div id="recurring_todo_form_container">
|
||||
<div id="recurring_todo">
|
||||
<label for="recurring_todo_description"><%= Todo.human_attribute_name('description') %></label><%=
|
||||
text_field_tag( "recurring_todo[description]", @recurring_todo.description, "size" => 30, "tabindex" => 1, "maxlength" => 100, :id => "edit_recurring_todo_description") -%>
|
||||
text_field_tag( "recurring_todo[description]", @recurring_todo.description, "size" => 30, "tabindex" => next_tab_index, "maxlength" => 100, :id => "edit_recurring_todo_description") -%>
|
||||
|
||||
<label for="recurring_todo_notes"><%= Todo.human_attribute_name('notes') %></label><%=
|
||||
text_area_tag( "recurring_todo[notes]", @recurring_todo.notes, {:cols => 29, :rows => 6, :tabindex => 2}) -%>
|
||||
text_area_tag( "recurring_todo[notes]", @recurring_todo.notes, {:cols => 29, :rows => 6, :tabindex => next_tab_index}) -%>
|
||||
|
||||
<label for="edit_recurring_todo_project_name"><%= Todo.human_attribute_name('project') %></label>
|
||||
<input id="edit_recurring_todo_project_name" name="project_name" autocomplete="off" tabindex="3" size="30" type="text" value="<%= @recurring_todo.project.nil? ? 'None' : @recurring_todo.project.name.gsub(/"/,""") %>" />
|
||||
<input id="edit_recurring_todo_project_name" name="project_name" autocomplete="off" tabindex="<%=next_tab_index%>" size="30" type="text" value="<%= @recurring_todo.project.nil? ? 'None' : @recurring_todo.project.name.gsub(/"/,""") %>" />
|
||||
<div class="page_name_auto_complete" id="edit_project_list" style="display:none"></div>
|
||||
|
||||
<label for="edit_recurring_todo_context_name"><%= Todo.human_attribute_name('context') %></label>
|
||||
<input id="edit_recurring_todo_context_name" name="context_name" autocomplete="off" tabindex="4" size="30" type="text" value="<%= @recurring_todo.context.name %>" />
|
||||
<input id="edit_recurring_todo_context_name" name="context_name" autocomplete="off" tabindex="<%=next_tab_index%>" size="30" type="text" value="<%= @recurring_todo.context.name %>" />
|
||||
<div class="page_name_auto_complete" id="edit_context_list" style="display:none"></div>
|
||||
|
||||
<label for="edit_recurring_todo_tag_list"><%= "#{Todo.human_attribute_name('tags')} #{t('shared.separate_tags_with_commas')}"%></label>
|
||||
<%= text_field_tag "edit_recurring_todo_tag_list", @recurring_todo.tag_list, :size => 30, :tabindex => 5 -%>
|
||||
<%= text_field_tag "edit_recurring_todo_tag_list", @recurring_todo.tag_list, :size => 30, :tabindex => next_tab_index -%>
|
||||
</div>
|
||||
</div>
|
||||
<div id="recurring_edit_period_id">
|
||||
<div id="recurring_edit_period">
|
||||
<label><%= t('todos.recurrence_period') %></label><br/>
|
||||
<%= radio_button_tag('recurring_edit_todo[recurring_period]', 'daily', @recurring_todo.recurring_period == 'daily')%> <%= t('todos.recurrence.daily') %><br/>
|
||||
<%= radio_button_tag('recurring_edit_todo[recurring_period]', 'weekly', @recurring_todo.recurring_period == 'weekly')%> <%= t('todos.recurrence.weekly') %><br/>
|
||||
<%= radio_button_tag('recurring_edit_todo[recurring_period]', 'monthly', @recurring_todo.recurring_period == 'monthly')%> <%= t('todos.recurrence.monthly') %><br/>
|
||||
<%= radio_button_tag('recurring_edit_todo[recurring_period]', 'yearly', @recurring_todo.recurring_period == 'yearly')%> <%= t('todos.recurrence.yearly') %><br/>
|
||||
<%- #behaviour is set in index because behaviours in partials are not generated -%>
|
||||
<%= radio_button_tag('recurring_edit_todo[recurring_period]', 'daily', @recurring_todo.recurring_period == 'daily', {:tabindex => next_tab_index})%> <%= t('todos.recurrence.daily') %><br/>
|
||||
<%= radio_button_tag('recurring_edit_todo[recurring_period]', 'weekly', @recurring_todo.recurring_period == 'weekly', {:tabindex => next_tab_index})%> <%= t('todos.recurrence.weekly') %><br/>
|
||||
<%= radio_button_tag('recurring_edit_todo[recurring_period]', 'monthly', @recurring_todo.recurring_period == 'monthly', {:tabindex => next_tab_index})%> <%= t('todos.recurrence.monthly') %><br/>
|
||||
<%= radio_button_tag('recurring_edit_todo[recurring_period]', 'yearly', @recurring_todo.recurring_period == 'yearly', {:tabindex => next_tab_index})%> <%= t('todos.recurrence.yearly') %><br/>
|
||||
</div>
|
||||
<div id="recurring_timespan">
|
||||
<br/>
|
||||
<label for="recurring_todo[start_from]"><%= t('todos.recurrence.starts_on') %>: </label><%=
|
||||
text_field_tag("recurring_todo_edit_start_from", format_date(@recurring_todo.start_from), "size" => 12, "class" => "Date", "tabindex" => 6, "autocomplete" => "off") %><br/>
|
||||
text_field_tag("recurring_todo_edit_start_from", format_date(@recurring_todo.start_from), "size" => 12, "class" => "Date", "tabindex" => next_tab_index, "autocomplete" => "off") %><br/>
|
||||
<br/>
|
||||
<label for="recurring_todo[ends_on]"><%= t('todos.recurrence.ends_on') %>:</label><br/>
|
||||
<%= radio_button_tag('recurring_todo[ends_on]', 'no_end_date', @recurring_todo.ends_on == 'no_end_date')%> <%= t('todos.recurrence.no_end_date') %><br/>
|
||||
<%= radio_button_tag('recurring_todo[ends_on]', 'ends_on_number_of_times', @recurring_todo.ends_on == 'ends_on_number_of_times')%>
|
||||
<%= t('todos.recurrence.ends_on_number_times', :number => text_field( :recurring_todo, :number_of_occurences, "size" => 3, "tabindex" => 7)) %><br/>
|
||||
<%= radio_button_tag('recurring_todo[ends_on]', 'ends_on_end_date', @recurring_todo.ends_on == 'ends_on_end_date')%>
|
||||
<%= t('todos.recurrence.ends_on_date', :date => text_field_tag('recurring_todo_edit_end_date', format_date(@recurring_todo.end_date), "size" => 12, "class" => "Date", "tabindex" => 8, "autocomplete" => "off")) %><br/>
|
||||
<%= radio_button_tag('recurring_todo[ends_on]', 'no_end_date', @recurring_todo.ends_on == 'no_end_date', {:tabindex => next_tab_index})%> <%= t('todos.recurrence.no_end_date') %><br/>
|
||||
<%= radio_button_tag('recurring_todo[ends_on]', 'ends_on_number_of_times', @recurring_todo.ends_on == 'ends_on_number_of_times', {:tabindex => next_tab_index})%>
|
||||
<%= t('todos.recurrence.ends_on_number_times', :number => text_field( :recurring_todo, :number_of_occurences, "size" => 3, "tabindex" => next_tab_index)) %><br/>
|
||||
<%= radio_button_tag('recurring_todo[ends_on]', 'ends_on_end_date', @recurring_todo.ends_on == 'ends_on_end_date', {:tabindex => next_tab_index})%>
|
||||
<%= t('todos.recurrence.ends_on_date', :date => text_field_tag('recurring_todo_edit_end_date', format_date(@recurring_todo.end_date), "size" => 12, "class" => "Date", "tabindex" => next_tab_index, "autocomplete" => "off")) %><br/>
|
||||
</div></div>
|
||||
<div id="recurring_edit_daily" style="display:<%= @recurring_todo.recurring_period == 'daily' ? 'block' : 'none' %> ">
|
||||
<label><%= t('todos.recurrence.daily_options') %></label><br/>
|
||||
<%= radio_button_tag('recurring_todo[daily_selector]', 'daily_every_x_day', !@recurring_todo.only_work_days)%>
|
||||
<%= t('todos.recurrence.daily_every_number_day', :number=> text_field_tag( 'recurring_todo[daily_every_x_days]', @recurring_todo.daily_every_x_days, {"size" => 3, "tabindex" => 9})) %><br/>
|
||||
<%= radio_button_tag('recurring_todo[daily_selector]', 'daily_every_work_day', @recurring_todo.only_work_days)%> <%= t('todos.recurrence.every_work_day') %><br/>
|
||||
<%= radio_button_tag('recurring_todo[daily_selector]', 'daily_every_x_day', !@recurring_todo.only_work_days, {:tabindex => next_tab_index})%>
|
||||
<%= t('todos.recurrence.daily_every_number_day', :number=> text_field_tag( 'recurring_todo[daily_every_x_days]', @recurring_todo.daily_every_x_days, {"size" => 3, "tabindex" => next_tab_index})) %><br/>
|
||||
<%= radio_button_tag('recurring_todo[daily_selector]', 'daily_every_work_day', @recurring_todo.only_work_days, {:tabindex => next_tab_index})%> <%= t('todos.recurrence.every_work_day') %><br/>
|
||||
</div>
|
||||
<div id="recurring_edit_weekly" style="display:<%= @recurring_todo.recurring_period == 'weekly' ? 'block' : 'none' %>">
|
||||
<label><%= t('todos.recurrence.weekly_options') %></label><br/>
|
||||
<%= t('todos.recurrence.weekly_every_number_week', :number => text_field_tag('recurring_todo[weekly_every_x_week]', @recurring_todo.weekly_every_x_week, {"size" => 3, "tabindex" => 9})) %><br/>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_monday]', 'm', @recurring_todo.on_monday ) %> <%= t('date.day_names')[1] %>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_tuesday]', 't', @recurring_todo.on_tuesday) %> <%= t('date.day_names')[2] %>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_wednesday]', 'w', @recurring_todo.on_wednesday) %> <%= t('date.day_names')[3] %>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_thursday]', 't', @recurring_todo.on_thursday) %> <%= t('date.day_names')[4] %><br/>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_friday]', 'f', @recurring_todo.on_friday) %> <%= t('date.day_names')[5] %>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_saturday]', 's', @recurring_todo.on_saturday) %> <%= t('date.day_names')[6] %>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_sunday]', 's', @recurring_todo.on_sunday) %> <%= t('date.day_names')[0] %><br/>
|
||||
<%= t('todos.recurrence.weekly_every_number_week', :number => text_field_tag('recurring_todo[weekly_every_x_week]', @recurring_todo.weekly_every_x_week, {"size" => 3, "tabindex" => next_tab_index})) %><br/>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_monday]', 'm', @recurring_todo.on_monday, {:tabindex => next_tab_index} ) %> <%= t('date.day_names')[1] %>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_tuesday]', 't', @recurring_todo.on_tuesday, {:tabindex => next_tab_index}) %> <%= t('date.day_names')[2] %>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_wednesday]', 'w', @recurring_todo.on_wednesday, {:tabindex => next_tab_index}) %> <%= t('date.day_names')[3] %>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_thursday]', 't', @recurring_todo.on_thursday, {:tabindex => next_tab_index}) %> <%= t('date.day_names')[4] %><br/>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_friday]', 'f', @recurring_todo.on_friday, {:tabindex => next_tab_index}) %> <%= t('date.day_names')[5] %>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_saturday]', 's', @recurring_todo.on_saturday, {:tabindex => next_tab_index}) %> <%= t('date.day_names')[6] %>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_sunday]', 's', @recurring_todo.on_sunday, {:tabindex => next_tab_index}) %> <%= t('date.day_names')[0] %><br/>
|
||||
</div>
|
||||
<div id="recurring_edit_monthly" style="display:<%= @recurring_todo.recurring_period == 'monthly' ? 'block' : 'none' %>">
|
||||
<label><%= t('todos.recurrence.monthly_options') %></label><br/>
|
||||
<%= radio_button_tag('recurring_todo[monthly_selector]', 'monthly_every_x_day', @recurring_todo.is_monthly_every_x_day || @recurring_todo.recurring_period == 'weekly')%>
|
||||
<%= radio_button_tag('recurring_todo[monthly_selector]', 'monthly_every_x_day', @recurring_todo.is_monthly_every_x_day || @recurring_todo.recurring_period == 'weekly', {:tabindex => next_tab_index})%>
|
||||
<%= t('todos.recurrence.day_x_on_every_x_month',
|
||||
:day => text_field_tag('recurring_todo[monthly_every_x_day]', @recurring_todo.monthly_every_x_day, {"size" => 3, "tabindex" => 9}),
|
||||
:month => text_field_tag('recurring_todo[monthly_every_x_month]', @recurring_todo.monthly_every_x_month, {"size" => 3, "tabindex" => 10})) %><br/>
|
||||
<%= radio_button_tag('recurring_todo[monthly_selector]', 'monthly_every_xth_day', @recurring_todo.is_monthly_every_xth_day)%>
|
||||
:day => text_field_tag('recurring_todo[monthly_every_x_day]', @recurring_todo.monthly_every_x_day, {"size" => 3, "tabindex" => next_tab_index}),
|
||||
:month => text_field_tag('recurring_todo[monthly_every_x_month]', @recurring_todo.monthly_every_x_month, {"size" => 3, "tabindex" => next_tab_index})) %><br/>
|
||||
<%= radio_button_tag('recurring_todo[monthly_selector]', 'monthly_every_xth_day', @recurring_todo.is_monthly_every_xth_day, {:tabindex => next_tab_index})%>
|
||||
<%= t('todos.recurrence.monthly_every_xth_day',
|
||||
:day => select_tag('recurring_todo[monthly_every_xth_day]', options_for_select(@xth_day, @xth_day[@recurring_todo.monthly_every_xth_day(1)-1][1])),
|
||||
:day_of_week => select_tag('recurring_todo[monthly_day_of_week]' , options_for_select(@days_of_week, @recurring_todo.monthly_day_of_week), {}),
|
||||
:month => text_field_tag('recurring_todo[monthly_every_x_month2]', @recurring_todo.monthly_every_x_month2, {"size" => 3, "tabindex" => 11})) %><br/>
|
||||
:day => select_tag('recurring_todo[monthly_every_xth_day]', options_for_select(@xth_day, @xth_day[@recurring_todo.monthly_every_xth_day(1)-1][1]), {:tabindex => next_tab_index}),
|
||||
:day_of_week => select_tag('recurring_todo[monthly_day_of_week]' , options_for_select(@days_of_week, @recurring_todo.monthly_day_of_week), {:tabindex => next_tab_index}),
|
||||
:month => text_field_tag('recurring_todo[monthly_every_x_month2]', @recurring_todo.monthly_every_x_month2, {"size" => 3, "tabindex" => next_tab_index})) %><br/>
|
||||
</div>
|
||||
<div id="recurring_edit_yearly" style="display:<%= @recurring_todo.recurring_period == 'yearly' ? 'block' : 'none' %>">
|
||||
<label><%= t('todos.recurrence.yearly_options') %></label><br/>
|
||||
<%= radio_button_tag('recurring_todo[yearly_selector]', 'yearly_every_x_day', @recurring_todo.recurrence_selector == 0)%>
|
||||
<%= radio_button_tag('recurring_todo[yearly_selector]', 'yearly_every_x_day', @recurring_todo.recurrence_selector == 0, {:tabindex => next_tab_index})%>
|
||||
<%= t('todos.recurrence.yearly_every_x_day',
|
||||
:month => select_tag('recurring_todo[yearly_month_of_year]', options_for_select(@months_of_year, @recurring_todo.yearly_month_of_year), {}),
|
||||
:day => text_field_tag('recurring_todo[yearly_every_x_day]', @recurring_todo.yearly_every_x_day, "size" => 3, "tabindex" => 9)) %><br/>
|
||||
<%= radio_button_tag('recurring_todo[yearly_selector]', 'yearly_every_xth_day', @recurring_todo.recurrence_selector == 1)%>
|
||||
:month => select_tag('recurring_todo[yearly_month_of_year]', options_for_select(@months_of_year, @recurring_todo.yearly_month_of_year), {:tabindex => next_tab_index}),
|
||||
:day => text_field_tag('recurring_todo[yearly_every_x_day]', @recurring_todo.yearly_every_x_day, "size" => 3, "tabindex" => next_tab_index)) %><br/>
|
||||
<%= radio_button_tag('recurring_todo[yearly_selector]', 'yearly_every_xth_day', @recurring_todo.recurrence_selector == 1, {:tabindex => next_tab_index})%>
|
||||
<%= t('todos.recurrence.yearly_every_xth_day',
|
||||
:day => select_tag('recurring_todo[yearly_every_xth_day]', options_for_select(@xth_day, @recurring_todo.yearly_every_xth_day), {}),
|
||||
:day_of_week => select_tag('recurring_todo[yearly_day_of_week]', options_for_select(@days_of_week, @recurring_todo.yearly_day_of_week), {}),
|
||||
:month => select_tag('recurring_todo[yearly_month_of_year2]', options_for_select(@months_of_year, @recurring_todo.yearly_month_of_year2), {})) %><br/>
|
||||
:day => select_tag('recurring_todo[yearly_every_xth_day]', options_for_select(@xth_day, @recurring_todo.yearly_every_xth_day), {:tabindex => next_tab_index}),
|
||||
:day_of_week => select_tag('recurring_todo[yearly_day_of_week]', options_for_select(@days_of_week, @recurring_todo.yearly_day_of_week), {:tabindex => next_tab_index}),
|
||||
:month => select_tag('recurring_todo[yearly_month_of_year2]', options_for_select(@months_of_year, @recurring_todo.yearly_month_of_year2), {:tabindex => next_tab_index})) %><br/>
|
||||
</div>
|
||||
<div id="recurring_target">
|
||||
<label><%= t('todos.recurrence.recurrence_on_options') %></label><br/>
|
||||
<%= radio_button_tag('recurring_todo[recurring_target]', 'due_date', @recurring_todo.target == 'due_date')%> <%= t('todos.recurrence.recurrence_on_due_date') %>. <%= t('todos.recurrence.show_options') %>:
|
||||
<%= radio_button_tag('recurring_todo[recurring_show_always]', '1', @recurring_todo.show_always?)%> <%= t('todos.recurrence.show_option_always') %>
|
||||
<%= radio_button_tag('recurring_todo[recurring_show_always]', '0', !@recurring_todo.show_always?)%>
|
||||
<%= t('todos.recurrence.show_days_before', :days => text_field_tag( 'recurring_todo[recurring_show_days_before]', @recurring_todo.show_from_delta, {"size" => 3, "tabindex" => 12})) %><br/>
|
||||
<%= radio_button_tag('recurring_todo[recurring_target]', 'show_from_date', @recurring_todo.target == 'show_from_date')%> <%= t('todos.recurrence.from_tickler') %><br/>
|
||||
<%= radio_button_tag('recurring_todo[recurring_target]', 'due_date', @recurring_todo.target == 'due_date', {:tabindex => next_tab_index})%> <%= t('todos.recurrence.recurrence_on_due_date') %>. <%= t('todos.recurrence.show_options') %>:
|
||||
<%= radio_button_tag('recurring_todo[recurring_show_always]', '1', @recurring_todo.show_always?, {:tabindex => next_tab_index})%> <%= t('todos.recurrence.show_option_always') %>
|
||||
<%= radio_button_tag('recurring_todo[recurring_show_always]', '0', !@recurring_todo.show_always?, {:tabindex => next_tab_index})%>
|
||||
<%= t('todos.recurrence.show_days_before', :days => text_field_tag( 'recurring_todo[recurring_show_days_before]', @recurring_todo.show_from_delta, {"size" => 3, "tabindex" => next_tab_index})) %><br/>
|
||||
<%= radio_button_tag('recurring_todo[recurring_target]', 'show_from_date', @recurring_todo.target == 'show_from_date', {:tabindex => next_tab_index})%> <%= t('todos.recurrence.from_tickler') %><br/>
|
||||
<br/>
|
||||
</div>
|
||||
<div class="recurring_submit_box">
|
||||
<div class="widgets">
|
||||
<button type="submit" class="positive" id="recurring_todo_edit_action_submit" tabindex="15">
|
||||
<button type="submit" class="positive" id="recurring_todo_edit_action_submit" tabindex="<%=next_tab_index%>">
|
||||
<%=image_tag("accept.png", :alt => "") %>
|
||||
<%= t('common.update') %>
|
||||
</button>
|
||||
<button type="button" class="positive" id="recurring_todo_edit_action_cancel" tabindex="15">
|
||||
<button type="button" class="positive" id="recurring_todo_edit_action_cancel" tabindex="<%=next_tab_index%>">
|
||||
<%=image_tag("cancel.png", :alt => "") %>
|
||||
<%= t('common.cancel') %>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
<%- reset_tab_index %>
|
||||
<div class="recurring_container">
|
||||
<%
|
||||
form_for(@new_recurring_todo, :html=> { :id=>'recurring-todo-form-new-action', :name=>'recurring_todo', :class => 'inline-form' }) do
|
||||
|
|
@ -7,60 +8,60 @@
|
|||
<div id="recurring_todo_form_container">
|
||||
<div id="recurring_todo">
|
||||
<label for="recurring_todo_description"><%= Todo.human_attribute_name('description') %></label><%=
|
||||
text_field_tag( "recurring_todo[description]", "", "size" => 30, "tabindex" => 1, "maxlength" => 100) -%>
|
||||
text_field_tag( "recurring_todo[description]", "", "size" => 30, "tabindex" => next_tab_index, "maxlength" => 100) -%>
|
||||
<label for="recurring_todo_notes"><%= Todo.human_attribute_name('notes') %></label><%=
|
||||
text_area_tag( "recurring_todo[notes]", nil, {:cols => 29, :rows => 6, :tabindex => 2}) -%>
|
||||
text_area_tag( "recurring_todo[notes]", nil, {:cols => 29, :rows => 6, :tabindex => next_tab_index}) -%>
|
||||
<label for="recurring_todo_project_name"><%= Todo.human_attribute_name('project') %></label>
|
||||
<input id="recurring_todo_project_name" name="project_name" autocomplete="off" tabindex="3" size="30" type="text" value="" />
|
||||
<input id="recurring_todo_project_name" name="project_name" autocomplete="off" tabindex="<%=next_tab_index%>" size="30" type="text" value="" />
|
||||
<div class="page_name_auto_complete" id="project_list" style="display:none"></div>
|
||||
|
||||
<label for="recurring_todo_context_name"><%= Todo.human_attribute_name('context') %></label>
|
||||
<input id="recurring_todo_context_name" name="context_name" autocomplete="off" tabindex="4" size="30" type="text" value="<%= current_user.contexts.first.name unless current_user.contexts.first.nil?%>" />
|
||||
<input id="recurring_todo_context_name" name="context_name" autocomplete="off" tabindex="<%=next_tab_index%>" size="30" type="text" value="<%= current_user.contexts.first.name unless current_user.contexts.first.nil?%>" />
|
||||
<div class="page_name_auto_complete" id="context_list" style="display:none"></div>
|
||||
<label for="tag_list"><%= "#{Todo.human_attribute_name('tags')} #{t('shared.separate_tags_with_commas')}"%></label>
|
||||
<%= text_field_tag "tag_list", nil, :size => 30, :tabindex => 5 -%>
|
||||
<%= text_field_tag "tag_list", nil, :size => 30, :tabindex => next_tab_index -%>
|
||||
</div>
|
||||
</div>
|
||||
<div id="recurring_period_id">
|
||||
<div id="recurring_period">
|
||||
<label><%= t('todos.recurrence_period') %></label><br/>
|
||||
<%= radio_button_tag('recurring_todo[recurring_period]', 'daily', true)%> <%= t('todos.recurrence.daily') %><br/>
|
||||
<%= radio_button_tag('recurring_todo[recurring_period]', 'weekly')%> <%= t('todos.recurrence.weekly') %><br/>
|
||||
<%= radio_button_tag('recurring_todo[recurring_period]', 'monthly')%> <%= t('todos.recurrence.monthly') %><br/>
|
||||
<%= radio_button_tag('recurring_todo[recurring_period]', 'yearly')%> <%= t('todos.recurrence.yearly') %><br/>
|
||||
<%= radio_button_tag('recurring_todo[recurring_period]', 'daily', true, {:tabindex => next_tab_index})%> <%= t('todos.recurrence.daily') %><br/>
|
||||
<%= radio_button_tag('recurring_todo[recurring_period]', 'weekly', false, {:tabindex => next_tab_index})%> <%= t('todos.recurrence.weekly') %><br/>
|
||||
<%= radio_button_tag('recurring_todo[recurring_period]', 'monthly', false, {:tabindex => next_tab_index})%> <%= t('todos.recurrence.monthly') %><br/>
|
||||
<%= radio_button_tag('recurring_todo[recurring_period]', 'yearly', false, {:tabindex => next_tab_index})%> <%= t('todos.recurrence.yearly') %><br/>
|
||||
</div>
|
||||
<div id="recurring_timespan">
|
||||
<br/>
|
||||
<label for="recurring_todo[start_from]"><%= t('todos.recurrence.starts_on') %>:</label><%=
|
||||
text_field(:recurring_todo, :start_from, "value" => format_date(current_user.time), "size" => 12, "class" => "Date", "tabindex" => 6, "autocomplete" => "off") %><br/>
|
||||
text_field(:recurring_todo, :start_from, "value" => format_date(current_user.time), "size" => 12, "class" => "Date", "tabindex" => next_tab_index, "autocomplete" => "off") %><br/>
|
||||
<br/>
|
||||
<label for="recurring_todo[ends_on]"><%= t('todos.recurrence.ends_on') %>:</label><br/>
|
||||
<%= radio_button_tag('recurring_todo[ends_on]', 'no_end_date', true)%> <%= t('todos.recurrence.no_end_date') %><br/>
|
||||
<%= radio_button_tag('recurring_todo[ends_on]', 'ends_on_number_of_times')%> <%= t('todos.recurrence.ends_on_number_times', :number => text_field( :recurring_todo, :number_of_occurences, "size" => 3, "tabindex" => 7)) %> <br/>
|
||||
<%= radio_button_tag('recurring_todo[ends_on]', 'ends_on_end_date')%> <%= t('todos.recurrence.ends_on_date', :date => text_field(:recurring_todo, :end_date, "size" => 12, "class" => "Date", "tabindex" => 8, "autocomplete" => "off", "value" => "")) %><br/>
|
||||
<%= radio_button_tag('recurring_todo[ends_on]', 'no_end_date', true, {:tabindex => next_tab_index})%> <%= t('todos.recurrence.no_end_date') %><br/>
|
||||
<%= radio_button_tag('recurring_todo[ends_on]', 'ends_on_number_of_times', false, {:tabindex => next_tab_index})%> <%= t('todos.recurrence.ends_on_number_times', :number => text_field( :recurring_todo, :number_of_occurences, "size" => 3, "tabindex" => next_tab_index)) %> <br/>
|
||||
<%= radio_button_tag('recurring_todo[ends_on]', 'ends_on_end_date', false, {:tabindex => next_tab_index})%> <%= t('todos.recurrence.ends_on_date', :date => text_field(:recurring_todo, :end_date, "size" => 12, "class" => "Date", "tabindex" => next_tab_index, "autocomplete" => "off", "value" => "")) %><br/>
|
||||
</div></div>
|
||||
<div id="recurring_daily" style="display:block">
|
||||
<label><%= t('todos.recurrence.daily_options') %></label><br/>
|
||||
<%= radio_button_tag('recurring_todo[daily_selector]', 'daily_every_x_day', true)%> <%= t('todos.recurrence.daily_every_number_day', :number=> text_field_tag( 'recurring_todo[daily_every_x_days]', "1", {"size" => 3, "tabindex" => 9})) %><br/>
|
||||
<%= radio_button_tag('recurring_todo[daily_selector]', 'daily_every_work_day')%> <%= t('todos.recurrence.every_work_day') %><br/>
|
||||
<%= radio_button_tag('recurring_todo[daily_selector]', 'daily_every_x_day', true, {:tabindex => next_tab_index})%> <%= t('todos.recurrence.daily_every_number_day', :number=> text_field_tag( 'recurring_todo[daily_every_x_days]', "1", {"size" => 3, "tabindex" => next_tab_index})) %><br/>
|
||||
<%= radio_button_tag('recurring_todo[daily_selector]', 'daily_every_work_day', false, {:tabindex => next_tab_index})%> <%= t('todos.recurrence.every_work_day') %><br/>
|
||||
</div>
|
||||
<div id="recurring_weekly" style="display:none">
|
||||
<label><%= t('todos.recurrence.weekly_options') %></label><br/>
|
||||
<%= t('todos.recurrence.weekly_every_number_week', :number => text_field_tag('recurring_todo[weekly_every_x_week]', 1, {"size" => 3, "tabindex" => 9})) %><br/>
|
||||
<%= t('todos.recurrence.weekly_every_number_week', :number => text_field_tag('recurring_todo[weekly_every_x_week]', 1, {"size" => 3, "tabindex" => next_tab_index})) %><br/>
|
||||
<% week_day = Time.new.wday -%>
|
||||
<%# TODO: this should ideally use the 'week starts on' preferences setting, too? %>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_monday]', 'm', week_day == 1 ? true : false) %> <%= t('date.day_names')[1] %>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_tuesday]', 't', week_day == 2 ? true : false) %> <%= t('date.day_names')[2] %>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_wednesday]', 'w', week_day == 3 ? true : false) %> <%= t('date.day_names')[3] %>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_thursday]', 't', week_day == 4 ? true : false) %> <%= t('date.day_names')[4] %>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_friday]', 'f', week_day == 5 ? true : false) %> <%= t('date.day_names')[5] %>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_saturday]', 's', week_day == 6 ? true : false) %> <%= t('date.day_names')[6] %>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_sunday]', 's', week_day == 0 ? true : false) %> <%= t('date.day_names')[0] %>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_monday]', 'm', week_day == 1 ? true : false, {:tabindex => next_tab_index}) %> <%= t('date.day_names')[1] %>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_tuesday]', 't', week_day == 2 ? true : false, {:tabindex => next_tab_index}) %> <%= t('date.day_names')[2] %>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_wednesday]', 'w', week_day == 3 ? true : false, {:tabindex => next_tab_index}) %> <%= t('date.day_names')[3] %>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_thursday]', 't', week_day == 4 ? true : false, {:tabindex => next_tab_index}) %> <%= t('date.day_names')[4] %>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_friday]', 'f', week_day == 5 ? true : false, {:tabindex => next_tab_index}) %> <%= t('date.day_names')[5] %>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_saturday]', 's', week_day == 6 ? true : false, {:tabindex => next_tab_index}) %> <%= t('date.day_names')[6] %>
|
||||
<%= check_box_tag('recurring_todo[weekly_return_sunday]', 's', week_day == 0 ? true : false, {:tabindex => next_tab_index}) %> <%= t('date.day_names')[0] %>
|
||||
</div>
|
||||
<div id="recurring_monthly" style="display:none">
|
||||
<label><%= t('todos.recurrence.monthly_options') %></label><br/>
|
||||
<%= radio_button_tag('recurring_todo[monthly_selector]', 'monthly_every_x_day', true)%> <%= t('todos.recurrence.day_x_on_every_x_month',
|
||||
:day => text_field_tag('recurring_todo[monthly_every_x_day]', Time.zone.now.mday, {"size" => 3, "tabindex" => 9}),
|
||||
<%= radio_button_tag('recurring_todo[monthly_selector]', 'monthly_every_x_day', true, {:tabindex => next_tab_index})%> <%= t('todos.recurrence.day_x_on_every_x_month',
|
||||
:day => text_field_tag('recurring_todo[monthly_every_x_day]', Time.zone.now.mday, {"size" => 3, "tabindex" => next_tab_index}),
|
||||
:month => text_field_tag('recurring_todo[monthly_every_x_month]', 1, {"size" => 3, "tabindex" => 10})) %><br/>
|
||||
<%= radio_button_tag('recurring_todo[monthly_selector]', 'monthly_every_xth_day')%> <%= t('todos.recurrence.monthly_every_xth_day',
|
||||
:day => select_tag('recurring_todo[monthly_every_xth_day]', options_for_select(@xth_day), {}),
|
||||
|
|
@ -69,31 +70,31 @@
|
|||
</div>
|
||||
<div id="recurring_yearly" style="display:none">
|
||||
<label><%= t('todos.recurrence.yearly_options') %></label><br/>
|
||||
<%= radio_button_tag('recurring_todo[yearly_selector]', 'yearly_every_x_day', true)%> <%= t('todos.recurrence.yearly_every_x_day',
|
||||
:month => select_tag('recurring_todo[yearly_month_of_year]', options_for_select(@months_of_year, Time.zone.now.month), {}),
|
||||
:day => text_field_tag('recurring_todo[yearly_every_x_day]', Time.zone.now.day, "size" => 3, "tabindex" => 9)) %><br/>
|
||||
<%= radio_button_tag('recurring_todo[yearly_selector]', 'yearly_every_xth_day')%> <%= t('todos.recurrence.yearly_every_xth_day',
|
||||
:day => select_tag('recurring_todo[yearly_every_xth_day]', options_for_select(@xth_day), {}),
|
||||
:day_of_week => select_tag('recurring_todo[yearly_day_of_week]', options_for_select(@days_of_week, Time.zone.now.wday), {}),
|
||||
:month => select_tag('recurring_todo[yearly_month_of_year2]', options_for_select(@months_of_year, Time.zone.now.month), {})) %><br/>
|
||||
<%= radio_button_tag('recurring_todo[yearly_selector]', 'yearly_every_x_day', true, {:tabindex => next_tab_index})%> <%= t('todos.recurrence.yearly_every_x_day',
|
||||
:month => select_tag('recurring_todo[yearly_month_of_year]', options_for_select(@months_of_year, Time.zone.now.month), {:tabindex => next_tab_index}),
|
||||
:day => text_field_tag('recurring_todo[yearly_every_x_day]', Time.zone.now.day, "size" => 3, "tabindex" => next_tab_index)) %><br/>
|
||||
<%= radio_button_tag('recurring_todo[yearly_selector]', 'yearly_every_xth_day', false, {:tabindex => next_tab_index})%> <%= t('todos.recurrence.yearly_every_xth_day',
|
||||
:day => select_tag('recurring_todo[yearly_every_xth_day]', options_for_select(@xth_day), {:tabindex => next_tab_index}),
|
||||
:day_of_week => select_tag('recurring_todo[yearly_day_of_week]', options_for_select(@days_of_week, Time.zone.now.wday), {:tabindex => next_tab_index}),
|
||||
:month => select_tag('recurring_todo[yearly_month_of_year2]', options_for_select(@months_of_year, Time.zone.now.month), {:tabindex => next_tab_index})) %><br/>
|
||||
</div>
|
||||
<div id="recurring_target">
|
||||
<label><%= t('todos.recurrence.recurrence_on_options') %></label><br/>
|
||||
<%= radio_button_tag('recurring_todo[recurring_target]', 'due_date', true)%> <%= t('todos.recurrence.recurrence_on_due_date') %>. <%= t('todos.recurrence.show_options') %>:
|
||||
<%= radio_button_tag('recurring_todo[recurring_show_always]', '1', true)%> <%= t('todos.recurrence.show_option_always') %>
|
||||
<%= radio_button_tag('recurring_todo[recurring_show_always]', '0', false)%>
|
||||
<%= t('todos.recurrence.show_days_before', :days => text_field_tag( 'recurring_todo[recurring_show_days_before]', "0", {"size" => 3, "tabindex" => 12})) %>
|
||||
<%= radio_button_tag('recurring_todo[recurring_target]', 'due_date', true, {:tabindex => next_tab_index})%> <%= t('todos.recurrence.recurrence_on_due_date') %>. <%= t('todos.recurrence.show_options') %>:
|
||||
<%= radio_button_tag('recurring_todo[recurring_show_always]', '1', true, {:tabindex => next_tab_index})%> <%= t('todos.recurrence.show_option_always') %>
|
||||
<%= radio_button_tag('recurring_todo[recurring_show_always]', '0', false, {:tabindex => next_tab_index})%>
|
||||
<%= t('todos.recurrence.show_days_before', :days => text_field_tag( 'recurring_todo[recurring_show_days_before]', "0", {"size" => 3, "tabindex" => next_tab_index})) %>
|
||||
<br/>
|
||||
<%= radio_button_tag('recurring_todo[recurring_target]', 'show_from_date', false)%> <%= t('todos.recurrence.from_tickler') %><br/>
|
||||
<%= radio_button_tag('recurring_todo[recurring_target]', 'show_from_date', false, {:tabindex => next_tab_index})%> <%= t('todos.recurrence.from_tickler') %><br/>
|
||||
<br/>
|
||||
</div>
|
||||
<div class="recurring_submit_box">
|
||||
<div class="widgets">
|
||||
<button type="submit" class="positive" id="recurring_todo_new_action_submit" tabindex="15">
|
||||
<button type="submit" class="positive" id="recurring_todo_new_action_submit" tabindex="<%=next_tab_index%>">
|
||||
<%=image_tag("accept.png", :alt => "") %>
|
||||
<%= t('common.create') %>
|
||||
</button>
|
||||
<button type="button" class="positive" id="recurring_todo_new_action_cancel" tabindex="15">
|
||||
<button type="button" class="positive" id="recurring_todo_new_action_cancel" tabindex="<%=next_tab_index%>">
|
||||
<%=image_tag("cancel.png", :alt => "") %>
|
||||
<%= t('common.cancel') %>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<%- if @saved -%>
|
||||
show_empty_messages();
|
||||
TracksPages.page_notify('notice', '<%= escape_javascript(t('todos.recurring_deleted_success') + t(:todo_removed, :count => @number_of_todos)) %>', 5);
|
||||
TracksPages.page_notify('notice', '<%= escape_javascript(t('todos.recurring_deleted_success') + t('todos.recurring_pattern_removed', :count => pluralize(@number_of_todos,t('common.todo')))) %>', 5);
|
||||
remove_recurring_todo_from_page();
|
||||
<%- else -%>
|
||||
TracksPages.page_notify('error', '<%= t('todos.error_deleting_recurring', :description => @recurring_todo.description) %>', 8);
|
||||
|
|
|
|||
24
app/views/recurring_todos/done.html.erb
Normal file
24
app/views/recurring_todos/done.html.erb
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<%
|
||||
paginate_options = {
|
||||
:class => :add_note_link,
|
||||
:previous_label => '« '+ t('common.previous'),
|
||||
:next_label => t('common.next')+' »',
|
||||
:inner_window => 2
|
||||
}
|
||||
%>
|
||||
<div id="display_box">
|
||||
<div class="container" id="completed_recurring_todos_container">
|
||||
<%= will_paginate @completed_recurring_todos, paginate_options %>
|
||||
<h2>
|
||||
<span id="completed-projects-count" class="badge"><%= "#{@total} (#{@range_low}-#{@range_high})" %></span>
|
||||
<%= t('todos.completed_recurring') %>
|
||||
</h2>
|
||||
<div id="completed_recurring_todos_container">
|
||||
<div id="completed-empty-nd" style="<%= @no_completed_recurring_todos ? 'display:block' : 'display:none'%>">
|
||||
<div class="message"><p><%= t('todos.no_completed_recurring') %></p></div>
|
||||
</div>
|
||||
<%= render :partial => @completed_recurring_todos %>
|
||||
</div>
|
||||
<%= will_paginate @completed_recurring_todos, paginate_options %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -10,7 +10,8 @@
|
|||
</div>
|
||||
|
||||
<div class="container" id="completed_recurring_todos_container">
|
||||
<h2><%= t('todos.completed_recurring') %></h2>
|
||||
<div class=add_note_link><%= link_to "Show all", done_recurring_todos_path%></div>
|
||||
<h2><%= t('common.last') %> <%= t('todos.completed_recurring') %></h2>
|
||||
<div id="completed_recurring_todos_container">
|
||||
<div id="completed-empty-nd" style="<%= @no_completed_recurring_todos ? 'display:block' : 'display:none'%>">
|
||||
<div class="message"><p><%= t('todos.no_completed_recurring') %></p></div>
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
<h1>RecurringTodo#show</h1>
|
||||
<p>Find me in app/views/recurring_todo/show.html.erb</p>
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
<%- if @saved -%>
|
||||
$('div#recurring_todo_<%= @recurring_todo.id %> a.star_item img').toggleClass('starred_todo').toggleClass('unstarred_todo');
|
||||
$('div#recurring_todo_<%= @recurring_todo.id %> a.star_item img').toggleClass('starred');
|
||||
<%- else -%>
|
||||
TracksPages.page_notify('error', '<%= t('todos.error_starring_recurring', :description => @recurring_todo.description) %>', 8);
|
||||
<%- end -%>
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@
|
|||
<% else -%>
|
||||
|
||||
<% render :layout => 'show_results_collection', :object => @found_todos, :locals => { :collection_name => "found-todos", :collection_title => t('search.todos_matching_query')} do %>
|
||||
<%= render :partial => "todos/todo", :collection => @found_todos, :locals => { :parent_container_type => 'search', :suppress_context => false, :suppress_project => false, :suppress_edit_button => true } %>
|
||||
<%= render :partial => "todos/todo", :collection => @found_todos, :locals => { :parent_container_type => 'search', :suppress_context => false, :suppress_project => false, :suppress_edit_button => false } %>
|
||||
<% end -%>
|
||||
|
||||
<% render :layout => 'show_results_collection', :object => @found_projects, :locals => { :collection_name => "found-project", :collection_title => t('search.projects_matching_query')} do %>
|
||||
<%= render :partial => "projects/project_listing", :collection => @found_projects, :locals => { :suppress_drag_handle => true, :suppress_edit_button => true } %>
|
||||
<%= render :partial => "projects/project_listing", :collection => @found_projects, :locals => { :suppress_drag_handle => true, :suppress_edit_button => true, :suppress_delete_button => true } %>
|
||||
<% end -%>
|
||||
|
||||
<% render :layout => 'show_results_collection', :object => @found_notes, :locals => { :collection_name => "found-notes", :collection_title => t('search.notes_matching_query')} do %>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@
|
|||
@initial_context_name ||= @project.default_context.name unless @project.nil? || @project.default_context.nil?
|
||||
@initial_context_name ||= @contexts.first.name unless @contexts.first.nil?
|
||||
@initial_project_name = @project.name unless @project.nil?
|
||||
@initial_tags ||= @default_tags
|
||||
@initial_tags ||= @project.default_tags unless @project.nil?
|
||||
reset_tab_index
|
||||
-%>
|
||||
<div id="todo_new_action_container">
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<div id="footer">
|
||||
<p><%= t('footer.send_feedback', :version => TRACKS_VERSION) %>: <a href="http://www.assembla.com/spaces/tracks-tickets/tickets"><%= t('common.bugs')%></a> |
|
||||
<p><%= t('footer.send_feedback', :version => TRACKS_VERSION) %>: <a href="http://www.assembla.com/spaces/tracks-tickets/tickets"><%= t('common.bugs')%></a> |
|
||||
<a href="http://www.getontracks.org/forums/"><%= t('common.forum')%></a> |
|
||||
<a href="http://www.getontracks.org/wiki/"><%= t('common.wiki')%></a> |
|
||||
<a href="https://github.com/TracksApp/tracks/wiki"><%= t('common.wiki')%></a> |
|
||||
<a href="mailto:butshesagirl@rousette.org.uk?subject=Tracks feedback"><%= t('common.email')%></a> |
|
||||
<a href="http://www.getontracks.org/"><%= t('common.website')%></a> |
|
||||
<a href="http://getontracks.org/tracks/contribute"><%= t('common.contribute')%></a></p>
|
||||
|
|
|
|||
45
app/views/stats/done.html.erb
Normal file
45
app/views/stats/done.html.erb
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
<div id="display_box">
|
||||
<div class="container">
|
||||
<div class=add_note_link><%= link_to "Show all", done_todos_path%></div>
|
||||
<h2>
|
||||
<%= t('common.last') %> <%= t('states.completed_plural' )%> <%= t('common.actions') %>
|
||||
</h2>
|
||||
<% if @done_recently.empty? -%>
|
||||
<div class="message"><p><%= t('todos.no_last_completed_actions') %></p></div>
|
||||
<% else -%>
|
||||
<%= render :partial => "todos/todo", :collection => @done_recently, :locals => { :parent_container_type => "completed", :suppress_context => false, :suppress_project => false } %>
|
||||
<% end -%>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class=add_note_link><%= link_to "Show all", done_projects_path%></div>
|
||||
<h2>
|
||||
<%= t('common.last') %> <%= t('states.completed_plural' )%> <%= t('common.projects') %>
|
||||
</h2>
|
||||
<% if @last_completed_projects.empty? -%>
|
||||
<div class="message"><p><%= t('projects.no_last_completed_projects') %></p></div>
|
||||
<% else -%>
|
||||
<div id="list-completed-projects" class="project-list">
|
||||
<%= render :partial => '/projects/project_listing',
|
||||
:collection => @last_completed_projects,
|
||||
:locals => {:suppress_drag_handle => true}
|
||||
%>
|
||||
</div>
|
||||
<% end -%>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class=add_note_link><%= link_to "Show all", done_recurring_todos_path%></div>
|
||||
<h2>
|
||||
<%= t('common.last') %> <%= t('states.completed_plural' )%> <%= t('common.recurring_todos') %>
|
||||
</h2>
|
||||
<% if @last_completed_recurring_todos.empty? -%>
|
||||
<div class="message"><p><%= t('projects.no_last_completed_recurring_todos') %></p></div>
|
||||
<% else -%>
|
||||
<%= render :partial => '/recurring_todos/recurring_todo', :collection => @last_completed_recurring_todos %>
|
||||
<% end -%>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div><!-- End of display_box -->
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
suppress_project ||= false
|
||||
-%>
|
||||
<div class="container completed" id="completed_container">
|
||||
<div class=add_note_link><%= link_to "Show all", determine_done_path%></div>
|
||||
<h2>
|
||||
<% if collapsible %>
|
||||
<a href="#" class="container_toggle" id="toggle_completed"><%= image_tag("collapse.png") %></a>
|
||||
|
|
|
|||
|
|
@ -1,34 +1,34 @@
|
|||
<%
|
||||
todo = edit_form
|
||||
form_for(todo, :html=> { :name=>'todo', :id => dom_id(@todo, 'form'), :class => 'inline-form edit_todo_form' }) do |t|%>
|
||||
<div id="error_status"><%= error_messages_for("todo", :object_name => 'action') %></div>
|
||||
<div id="edit_error_status"><%= error_messages_for("todo", :object_name => 'action') %></div>
|
||||
|
||||
<%= t.hidden_field( "id" ) -%>
|
||||
<%= source_view_tag( @source_view ) -%>
|
||||
<%= content_tag(:input, "", :type=>"hidden", :name=>"_tag_name", :value=>"#{@tag_name}") if @tag_name -%>
|
||||
|
||||
<label for="<%= dom_id(@todo, 'description') %>"><%= t('common.description') %></label>
|
||||
<%= t.text_field( "description", "size" => 30, "tabindex" => 8, "maxlength" => 100) %>
|
||||
<%= t.text_field( "description", "size" => 30, "tabindex" => next_tab_index, "maxlength" => 100) %>
|
||||
|
||||
<label for="<%= dom_id(@todo, 'notes') %>"><%= t('common.notes') %></label>
|
||||
<%= t.text_area( "notes", "cols" => 29, "rows" => 4, "tabindex" => 9) %>
|
||||
<%= t.text_area( "notes", "cols" => 29, "rows" => 4, "tabindex" => next_tab_index) %>
|
||||
|
||||
<div class="project_input">
|
||||
<label for="<%= dom_id(@todo, 'project_name') %>"><%= t('common.project') %></label>
|
||||
<input id="<%= dom_id(@todo, 'project_name') %>" name="project_name" autocomplete="off" tabindex="10" size="30" type="text" value="<%= @todo.project.nil? ? 'None' : h(@todo.project.name) %>" />
|
||||
<input id="<%= dom_id(@todo, 'project_name') %>" name="project_name" autocomplete="off" tabindex="<%= next_tab_index%>" size="30" type="text" value="<%= @todo.project.nil? ? 'None' : h(@todo.project.name) %>" />
|
||||
</div>
|
||||
|
||||
<div class="context_input">
|
||||
<label for="<%= dom_id(@todo, 'context_name') %>"><%= t('common.context') %></label>
|
||||
<input id="<%= dom_id(@todo, 'context_name') %>" name="context_name" autocomplete="off" tabindex="11" size="30" type="text" value="<%= h @todo.context.name %>" />
|
||||
<input id="<%= dom_id(@todo, 'context_name') %>" name="context_name" autocomplete="off" tabindex="<%= next_tab_index%>" size="30" type="text" value="<%= h @todo.context.name %>" />
|
||||
</div>
|
||||
|
||||
<label class="tag_list_label" for="<%= dom_id(@todo, 'tag_list') %>"><%= t('todos.tags') %></label>
|
||||
<%= text_field_tag 'tag_list', tag_list_text, :id => dom_id(@todo, 'tag_list'), :size => 30, :tabindex => 12 %>
|
||||
<%= text_field_tag 'tag_list', tag_list_text, :id => dom_id(@todo, 'tag_list'), :size => 30, :tabindex => next_tab_index %>
|
||||
|
||||
<div class="due_input">
|
||||
<label for="<%= dom_id(@todo, 'due_label') %>">Due</label>
|
||||
<%= date_field_tag("todo[due]", dom_id(@todo, 'due'), format_date(@todo.due), "tabindex" => 13) %>
|
||||
<label for="<%= dom_id(@todo, 'due_label') %>"><%= Todo.human_attribute_name('due') %></label>
|
||||
<%= date_field_tag("todo[due]", dom_id(@todo, 'due'), format_date(@todo.due), "tabindex" => next_tab_index) %>
|
||||
<a href="#" id="<%= dom_id(@todo, 'due_x') %>" class="date_clear" title="<%= t('todos.clear_due_date') %>">
|
||||
<%= image_tag("delete_off.png", :alt => "Clear due date") %>
|
||||
</a>
|
||||
|
|
@ -36,7 +36,7 @@ form_for(todo, :html=> { :name=>'todo', :id => dom_id(@todo, 'form'), :class =>
|
|||
|
||||
<div class="show_from_input">
|
||||
<label for="<%= dom_id(@todo, 'show_from') %>"><%= t('todos.show_from') %></label>
|
||||
<%= date_field_tag("todo[show_from]", dom_id(@todo, 'show_from'), format_date(@todo.show_from), "tabindex" => 14) %>
|
||||
<%= date_field_tag("todo[show_from]", dom_id(@todo, 'show_from'), format_date(@todo.show_from), "tabindex" => next_tab_index) %>
|
||||
<a href="#" id="<%= dom_id(@todo, 'show_from_x') %>" class="date_clear" title="<%= t('todos.clear_show_from_date') %>">
|
||||
<%= image_tag("delete_off.png", :alt => "Clear show from date") %>
|
||||
</a>
|
||||
|
|
@ -49,20 +49,20 @@ form_for(todo, :html=> { :name=>'todo', :id => dom_id(@todo, 'form'), :class =>
|
|||
</ul>
|
||||
</div>
|
||||
<label id="label_for_predecessor_input" for="predecessor_input" style="display:none"><%= t('todos.add_another_dependency')%></label>
|
||||
<%= text_field_tag "predecessor_input", nil, :size => 30, :tabindex => 8 %>
|
||||
<%= text_field_tag "predecessor_input", nil, :size => 30, :tabindex => next_tab_index %>
|
||||
<%= hidden_field_tag "predecessor_list", @todo.predecessors.map{|t| t.id.to_s}.join(', ') %>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="submit_box">
|
||||
<div class="widgets">
|
||||
<button type="submit" class="positive" id="<%= dom_id(@todo, 'submit') %>" tabindex="16">
|
||||
<button type="submit" class="positive" id="<%= dom_id(@todo, 'submit') %>" tabindex="<%= next_tab_index %>">
|
||||
<%=image_tag("accept.png", :alt => "") %>
|
||||
Update
|
||||
<%= t('common.update') %>
|
||||
</button>
|
||||
<a href="#" class="negative">
|
||||
<%=image_tag("cancel.png", :alt => "") %>
|
||||
Cancel
|
||||
<%= t('common.cancel') %>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
<% @tag_list_text = ""
|
||||
<% @tag_list_text = ""
|
||||
@tag_list_text = tag_list_text if @todo -%>
|
||||
<span class="errors">
|
||||
<%= error_messages_for("todo") %>
|
||||
</span>
|
||||
<% this_year = current_user.time.to_date.strftime("%Y").to_i
|
||||
if parent_container_type == 'show_mobile' -%>
|
||||
<% this_year = current_user.time.to_date.strftime("%Y").to_i -%>
|
||||
<% if parent_container_type == 'show_mobile' -%>
|
||||
<p><label for="todo_done"><%= t('todos.done') %></label> <%= check_box_tag("done", 1, @todo && @todo.completed?, "tabindex" => 1, "onClick" => "document.mobileEdit.submit()") %></p>
|
||||
<% end -%>
|
||||
<h2><label for="todo_description"><%= t('common.description') %></label></h2>
|
||||
|
|
@ -13,10 +13,10 @@ if parent_container_type == 'show_mobile' -%>
|
|||
<%= text_area( "todo", "notes", "cols" => 40, "rows" => 3, "tabindex" => 3) %>
|
||||
<h2><label for="todo_context_id"><%= t('common.context') %></label></h2>
|
||||
<%= unless @mobile_from_context
|
||||
collection_select( "todo", "context_id", @contexts, "id", "name", {}, {"tabindex" => 4} )
|
||||
collection_select( "todo", "context_id", @contexts, "id", "name", {}, {"tabindex" => 4} )
|
||||
else
|
||||
select_tag("todo[context_id]", options_from_collection_for_select(
|
||||
@contexts, "id", "name", @mobile_from_context.id),
|
||||
@contexts, "id", "name", @mobile_from_context.id),
|
||||
{"id" => :todo_context_id, :tabindex => 4} )
|
||||
end %>
|
||||
<h2><label for="todo_project_id"><%= t('common.project') %></label></h2>
|
||||
|
|
@ -24,10 +24,10 @@ end %>
|
|||
collection_select( "todo", "project_id", @projects, "id", "name",
|
||||
{:include_blank => t('todos.no_project')}, {"tabindex" => 5} )
|
||||
else
|
||||
# manually add blank option since :include_blank does not work
|
||||
# manually add blank option since :include_blank does not work
|
||||
# with options_from_collection_for_select
|
||||
select_tag("todo[project_id]", "<option value=\"\"></option>"+options_from_collection_for_select(
|
||||
@projects, "id", "name", @mobile_from_project.id),
|
||||
@projects, "id", "name", @mobile_from_project.id),
|
||||
{"id" => :todo_project_id, :tabindex => 5} )
|
||||
end %>
|
||||
<h2><label for="tag_list"><%= t('todos.tags') %></label></h2>
|
||||
|
|
@ -36,5 +36,5 @@ end %>
|
|||
<%= date_select("todo", "due", {:order => [:day, :month, :year],
|
||||
:start_year => this_year, :include_blank => '--'}, :tabindex => 7) %>
|
||||
<h2><label for="todo_show_from"><%= t('todos.show_from') %></label></h2>
|
||||
<%= date_select("todo", "show_from", {:order => [:day, :month, :year],
|
||||
<%= date_select("todo", "show_from", {:order => [:day, :month, :year],
|
||||
:start_year => this_year, :include_blank => true}, :tabindex => 8) %>
|
||||
|
|
@ -13,7 +13,7 @@ end -%>
|
|||
-%><span class="m_t">
|
||||
<% end -%>
|
||||
<%= date_span -%> <%= link_to mobile_todo.description, todo_path(mobile_todo, :format => 'm') -%>
|
||||
<% if mobile_todo.notes? %>
|
||||
<% unless mobile_todo.notes.blank? %>
|
||||
<%= link_to(image_tag("mobile_notes.png", :border => "0"), mobile_todo_show_notes_path(mobile_todo, :format => 'm')) -%>
|
||||
<% end %>
|
||||
<% if parent_container_type == 'context' or parent_container_type == 'tag' -%>
|
||||
|
|
|
|||
|
|
@ -8,23 +8,27 @@
|
|||
<div id="multiple_error_status"><%= error_messages_for("item", :object_name => 'action') %></div>
|
||||
|
||||
<label for="todo_notes"><%= t('shared.multiple_next_actions') %></label>
|
||||
<%= text_area_tag( "todo[multiple_todos]", "", :cols => 29, :rows => 6, :tabindex => 2) %>
|
||||
<%= text_area_tag( "todo[multiple_todos]", "", :cols => 29, :rows => 6, :tabindex => next_tab_index) %>
|
||||
|
||||
<label for="todo_project_name"><%= t('shared.project_for_all_actions') %></label>
|
||||
<input id="multi_todo_project_name" name="project_name" autocomplete="off" tabindex="3" size="30" type="text" value="<%=h @initial_project_name %>" />
|
||||
<input id="multi_todo_project_name" name="project_name" autocomplete="off" tabindex="<%= next_tab_index%>" size="30" type="text" value="<%=h @initial_project_name %>" />
|
||||
<div class="page_name_auto_complete" id="project_list" style="display:none"></div>
|
||||
|
||||
<label for="todo_context_name"><%= t('shared.context_for_all_actions') %></label>
|
||||
<input id="multi_todo_context_name" name="context_name" autocomplete="off" tabindex="4" size="30" type="text" value="<%=h @initial_context_name %>" />
|
||||
<input id="multi_todo_context_name" name="context_name" autocomplete="off" tabindex="<%= next_tab_index%>" size="30" type="text" value="<%=h @initial_context_name %>" />
|
||||
<div class="page_name_auto_complete" id="context_list" style="display:none"></div>
|
||||
|
||||
<label for="tag_list"><%= t('shared.tags_for_all_actions') %></label>
|
||||
<%= text_field_tag "multi_tag_list", @default_tags, :name=>:tag_list, :size => 30, :tabindex => 5 %>
|
||||
<%= hidden_field_tag "initial_tag_list", @initial_tags%>
|
||||
<%= text_field_tag "multi_tag_list", @initial_tags, :name=>:tag_list, :size => 30, :tabindex => next_tab_index %>
|
||||
<%= content_tag("div", "", :id => "tag_list_auto_complete", :class => "auto_complete") %>
|
||||
|
||||
<%= check_box_tag('todos_sequential', 'true', false, {:tabindex => next_tab_index}) %>
|
||||
<label for="todos_sequential"><%= t('shared.make_actions_dependent') %></label>
|
||||
|
||||
<div class="submit_box">
|
||||
<div class="widgets">
|
||||
<button type="submit" class="positive" id="todo_multi_new_action_submit" tabindex="8">
|
||||
<button type="submit" class="positive" id="todo_multi_new_action_submit" tabindex="<%= next_tab_index%>">
|
||||
<%= image_tag("accept.png", :alt => "") %><%= t('shared.add_actions') %>
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,34 +4,37 @@
|
|||
<% form_for(todo, :html=> { :id=>'todo-form-new-action', :name=>'todo', :class => 'inline-form new_todo_form' }) do |t|%>
|
||||
<input id="default_project_name_id" name="default_project_name" type="hidden" value="<%= h(@initial_project_name)-%>" />
|
||||
<input id="default_context_name_id" name="default_context_name" type="hidden" value="<%= h(@initial_context_name)-%>" />
|
||||
<input type="hidden" id="new_todo_starred" name="new_todo_starred" value="false" />
|
||||
|
||||
<div id="error_status"><%= error_messages_for("item", :object_name => 'action') %></div>
|
||||
|
||||
<label for="todo_description"><%= Todo.human_attribute_name('description') %></label>
|
||||
<%= t.text_field("description", "size" => 30, "tabindex" => 1, "maxlength" => 100, "autocomplete" => "off", :autofocus => 1) %>
|
||||
<label for="todo_description" style="float:left"><%= Todo.human_attribute_name('description') %></label>
|
||||
<a href="#" id="new_todo_starred_link" class="undecorated_link" ><%= image_tag("blank.png", :title =>t('todos.star_action'), :class => "todo_star", :style=> "float: right")%></a>
|
||||
<%= t.text_field("description", "size" => 30, "tabindex" => next_tab_index, "maxlength" => 100, "autocomplete" => "off", :autofocus => 1) %>
|
||||
|
||||
<label for="todo_notes"><%= Todo.human_attribute_name('notes') %></label>
|
||||
<%= t.text_area("notes", "cols" => 29, "rows" => 6, "tabindex" => 2) %>
|
||||
<%= t.text_area("notes", "cols" => 29, "rows" => 6, "tabindex" => next_tab_index) %>
|
||||
|
||||
<label for="todo_project_name"><%= Todo.human_attribute_name('project') %></label>
|
||||
<input id="todo_project_name" name="project_name" autocomplete="off" tabindex="3" size="30" type="text" value="<%= h(@initial_project_name) %>" />
|
||||
<input id="todo_project_name" name="project_name" autocomplete="off" tabindex="<%= next_tab_index%>" size="30" type="text" value="<%= h(@initial_project_name) %>" />
|
||||
<div class="page_name_auto_complete" id="project_list" style="display:none"></div>
|
||||
|
||||
<label for="todo_context_name"><%= Todo.human_attribute_name('context') %></label>
|
||||
<input id="todo_context_name" name="context_name" autocomplete="off" tabindex="4" size="30" type="text" value="<%= h(@initial_context_name) %>" />
|
||||
<input id="todo_context_name" name="context_name" autocomplete="off" tabindex="<%= next_tab_index%>" size="30" type="text" value="<%= h(@initial_context_name) %>" />
|
||||
|
||||
<label for="tag_list"><%= Todo.human_attribute_name('tags') + ' (' + t('shared.separate_tags_with_commas') + ')' %></label>
|
||||
<%= text_field_tag "tag_list", @default_tags, :size => 30, :tabindex => 5 %>
|
||||
<label for="todo_tag_list"><%= Todo.human_attribute_name('tags') + ' (' + t('shared.separate_tags_with_commas') + ')' %></label>
|
||||
<%= hidden_field_tag "initial_tag_list", @initial_tags%>
|
||||
<%= text_field_tag "todo_tag_list", @initial_tags, :size => 30, :tabindex => next_tab_index %>
|
||||
<%= content_tag("div", "", :id => "tag_list_auto_complete", :class => "auto_complete") %>
|
||||
|
||||
<div class="due_input">
|
||||
<label for="todo_due"><%= Todo.human_attribute_name('due') %></label>
|
||||
<%= t.text_field("due", "size" => 12, "class" => "Date", "tabindex" => 6, "autocomplete" => "off") %>
|
||||
<%= t.text_field("due", "size" => 12, "class" => "Date", "tabindex" => next_tab_index, "autocomplete" => "off") %>
|
||||
</div>
|
||||
|
||||
<div class="show_from_input">
|
||||
<label for="todo_show_from"><%= Todo.human_attribute_name('show_from') %></label>
|
||||
<%= t.text_field("show_from", "size" => 12, "class" => "Date", "tabindex" => 7, "autocomplete" => "off") %>
|
||||
<%= t.text_field("show_from", "size" => 12, "class" => "Date", "tabindex" => next_tab_index, "autocomplete" => "off") %>
|
||||
</div>
|
||||
|
||||
<div class="depends_on">
|
||||
|
|
@ -41,7 +44,7 @@
|
|||
</ul>
|
||||
</div>
|
||||
<label id="label_for_predecessor_input" for="predecessor_input" style="display:none"><%= t('todos.add_another_dependency')%></label>
|
||||
<%= text_field_tag "predecessor_input", nil, :size => 30, :tabindex => 8 %>
|
||||
<%= text_field_tag "predecessor_input", nil, :size => 30, :tabindex => next_tab_index %>
|
||||
<%= hidden_field_tag "predecessor_list", ""%>
|
||||
</div>
|
||||
|
||||
|
|
@ -50,11 +53,11 @@
|
|||
|
||||
<div class="submit_box">
|
||||
<div class="widgets">
|
||||
<button type="submit" class="positive" id="todo_new_action_submit" tabindex="8">
|
||||
<button type="submit" class="positive" id="todo_new_action_submit" tabindex="<%= next_tab_index%>">
|
||||
<%= image_tag("accept.png", :alt => "") + t('shared.add_action') %>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% end # form_for -%>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -13,14 +13,6 @@ parameters += "&_tag_name=#{@tag_name}" if @source_view == 'tag'
|
|||
|
||||
<%= remote_delete_dependency(successor, predecessor) %>
|
||||
|
||||
<%# link_to_remote(
|
||||
image_tag("blank.png", :title => t('todos.remove_dependency'), :align => "absmiddle", :class => "delete_item"),
|
||||
{:url => {:controller => 'todos', :action => 'remove_predecessor', :id => successor.id},
|
||||
:method => 'delete',
|
||||
:with => "'#{parameters}&predecessor=#{predecessor.id}'",
|
||||
:before => successor_start_waiting_js(successor)},
|
||||
{:style => "background: transparent;"}) %>
|
||||
|
||||
<% unless successor.pending_successors.empty? %>
|
||||
<div class="todo_successors" id="<%= dom_id(successor, 'successors') %>">
|
||||
<%= render :partial => "todos/successor",
|
||||
|
|
@ -34,5 +26,4 @@ parameters += "&_tag_name=#{@tag_name}" if @source_view == 'tag'
|
|||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
@ -1,4 +1,7 @@
|
|||
<%
|
||||
require 'htmlentities'
|
||||
htmlentities = HTMLEntities.new
|
||||
|
||||
todo = text_todo
|
||||
|
||||
if (todo.starred?)
|
||||
|
|
@ -8,11 +11,11 @@ else
|
|||
end
|
||||
|
||||
if (todo.completed?) && todo.completed_at
|
||||
result_string << "["+ t('todos.completed') +": " + format_date(todo.completed_at) + "] "
|
||||
result_string << "["+ htmlentities.decode(t('todos.completed')) +": " + format_date(todo.completed_at) + "] "
|
||||
end
|
||||
|
||||
if todo.due
|
||||
result_string << "[" + t('todos.due') + ": " + format_date(todo.due) + "] "
|
||||
result_string << "[" + htmlentities.decode(t('todos.due')) + ": " + format_date(todo.due) + "] "
|
||||
result_string << todo.description + " "
|
||||
else
|
||||
result_string << todo.description + " "
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ parameters += "&_tag_name=#{@tag_name}" if @source_view == 'tag'
|
|||
<div id="<%= dom_id(todo) %>" class="item-container">
|
||||
<div id="<%= dom_id(todo, 'line') %>" class="item-show">
|
||||
<%= remote_star_icon(todo) %>
|
||||
<%= remote_toggle_checkbox(todo) unless source_view_is :deferred %>
|
||||
<%= remote_toggle_checkbox(todo) %>
|
||||
<%= remote_edit_button(todo) unless suppress_edit_button %>
|
||||
<ul class="sf-menu sf-item-menu">
|
||||
<li style="z-index:<%=@z_index_counter%>"><%= image_tag "downarrow.png", :alt=> "" %>
|
||||
|
|
@ -18,8 +18,8 @@ parameters += "&_tag_name=#{@tag_name}" if @source_view == 'tag'
|
|||
<% unless todo.completed? || todo.deferred? -%>
|
||||
<li><%= remote_defer_menu_item(1, todo) %></li>
|
||||
<li><%= remote_defer_menu_item(7, todo) %></li>
|
||||
<li><%= remote_promote_to_project_menu_item(todo) %></li>
|
||||
<% end -%>
|
||||
<li><%= remote_promote_to_project_menu_item(todo) %></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -31,12 +31,12 @@ parameters += "&_tag_name=#{@tag_name}" if @source_view == 'tag'
|
|||
<%= tag_list(todo) %>
|
||||
<%= deferred_due_date(todo) %>
|
||||
<%= project_and_context_links( todo, parent_container_type, :suppress_context => suppress_context, :suppress_project => suppress_project ) %>
|
||||
<%= collapsed_notes_image(todo) if todo.notes? %>
|
||||
<%= collapsed_successors_image(todo) unless todo.pending_successors.empty? %>
|
||||
<%= collapsed_notes_image(todo) unless todo.notes.blank? %>
|
||||
<%= collapsed_successors_image(todo) if todo.has_pending_successors %>
|
||||
</div>
|
||||
</div>
|
||||
<div id="<%= dom_id(todo, 'edit') %>" class="edit-form" style="display:none">
|
||||
<% #note: edit form will load here remotely -%>
|
||||
<div class="placeholder"> </div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<% if !@saved
|
||||
if @predecessor.completed? -%>
|
||||
TracksPages.page_notify('error', "<%= t('todos.cannot_add_dependency_to_completed_todo') %>", 8);
|
||||
TracksPages.page_notify('error', "<%= t('todos.cannot_add_dependency_to_completed_todo') %>", 8);
|
||||
$('#<%=dom_id(@todo)%>').html(html_for_todo());
|
||||
<% else -%>
|
||||
TracksPages.page_notify('error', "<%= t('todos.unable_to_add_dependency') %>", 8);
|
||||
|
|
@ -29,7 +29,7 @@ function show_in_tickler_box() {
|
|||
|
||||
function regenerate_predecessor_family() {
|
||||
<%
|
||||
parents = @predecessor.predecessors
|
||||
parents = @predecessors
|
||||
until parents.empty?
|
||||
parent = parents.pop
|
||||
parents += parent.predecessors -%>
|
||||
|
|
|
|||
22
app/views/todos/all_done.html.erb
Normal file
22
app/views/todos/all_done.html.erb
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<%
|
||||
paginate_options = {
|
||||
:class => :add_note_link,
|
||||
:previous_label => '« '+ t('common.previous'),
|
||||
:next_label => t('common.next')+' »',
|
||||
:inner_window => 2
|
||||
}
|
||||
%>
|
||||
<div id="display_box_projects">
|
||||
<div class="container">
|
||||
<%= will_paginate @done, paginate_options %>
|
||||
<h2><%= t('todos.all_completed') %></h2>
|
||||
<% if @done.empty? -%>
|
||||
<div class="message"><p><%= t('todos.no_completed_actions') %></p></div>
|
||||
<% else -%>
|
||||
<%= render :partial => "todos/todo", :collection => @done, :locals => { :parent_container_type => "completed", :suppress_context => false, :suppress_project => false } %>
|
||||
<% end -%>
|
||||
</div>
|
||||
|
||||
<%= will_paginate @done, paginate_options %>
|
||||
|
||||
</div><!-- End of display_box -->
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
</div>
|
||||
|
||||
<div class="container">
|
||||
<h2><%= t('todos.calendar.due_this_month', :month => Time.zone.now.strftime("%B")) %></h2>
|
||||
<h2><%= t('todos.calendar.due_this_month', :month => l(Time.zone.now, :format => "%B")) %></h2>
|
||||
<div id="empty_due_this_month" <%= "style=\"display:none\"" unless @due_this_month.empty? %>>
|
||||
<%= t('todos.calendar.no_actions_due_this_month') %>
|
||||
</div>
|
||||
|
|
@ -41,7 +41,7 @@
|
|||
</div>
|
||||
|
||||
<div class="container">
|
||||
<h2><%= t('todos.calendar.due_next_month_and_later', :month => (Time.zone.now+1.month).strftime("%B")) %></h2>
|
||||
<h2><%= t('todos.calendar.due_next_month_and_later', :month => l(Time.zone.now+1.month, :format => "%B")) %></h2>
|
||||
<div id="empty_due_after_this_month" <%= "style=\"display:none\"" unless @due_after_this_month.empty? %>>
|
||||
<%= t('todos.calendar.no_actions_due_after_this_month') %>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
<% unless @due_tickles.empty? -%>
|
||||
TracksPages.page_notify('notice', "<%=t('todos.tickler_items_due', :count => @due_tickles.length)%>", 5);
|
||||
TracksPages.page_notify('notice', "<%=t('todos.tickler_items_due', :count => @due_tickles.length)%>", 8);
|
||||
<% end -%>
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
<div id="display_box_projects">
|
||||
<p><%= t('todos.completed_today', :count => @due_tickles.nil? ? 0 : @due_tickles.length) %></p>
|
||||
<div class="container">
|
||||
<h2><%= t('todos.completed_last_day') %></h2>
|
||||
<table class="next_actions" border="0">
|
||||
<%= render :partial => "done", :collection => @done_today %>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<h2><%= t('todos.completed_last_x_days', :count => 7) %></h2>
|
||||
<table class="next_actions" border="0">
|
||||
<%= render :partial => "done", :collection => @done_this_week %>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<h2><%= t('todos.completed_last_x_days', :count => 28) %></h2>
|
||||
<table class="next_actions" border="0">
|
||||
<%= render :partial => "done", :collection => @done_this_month %>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<p><%= t('todos.older_completed_items') %>: <%= link_to( t('todos.older_than_days', :count => 31), done_archive_path ) %></p>
|
||||
</div><!-- End of display_box -->
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
<div id="display_box_projects">
|
||||
|
||||
<p><%= t('todos.completed_in_archive', :count => @done_archive.length) %></p>
|
||||
<div class="container">
|
||||
<h2><%= t('todos.completed_more_than_x_days_ago', :count => 31) %></h2>
|
||||
<table class="next_actions" cellspacing="5" cellpadding="0" border="0">
|
||||
<%= render :partial => "done", :collection => @done_archive %>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div><!-- End of display_box -->
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
<% if @saved -%>
|
||||
TracksPages.page_notify('notice', "<%=escape_javascript @status_message%>", 5);
|
||||
TracksPages.page_notify('notice', "<%=escape_javascript @status_message%>", 8);
|
||||
TracksPages.hide_errors();
|
||||
TracksPages.set_page_badge(<%= @down_count %>);
|
||||
<% if should_show_new_item -%>
|
||||
|
|
@ -20,20 +20,27 @@ function clear_form() {
|
|||
$('#todo-form-new-action').clearDeps();
|
||||
TracksForm.set_context_name('<%=escape_javascript @initial_context_name%>');
|
||||
TracksForm.set_project_name('<%=escape_javascript @initial_project_name%>');
|
||||
TracksForm.set_tag_list('<%=escape_javascript @default_tags%>');
|
||||
TracksForm.set_tag_list('<%=escape_javascript @initial_tags%>');
|
||||
$('#todo-form-new-action input:text:first').focus();
|
||||
$('#new_todo_starred_link .todo_star').removeClass('starred');
|
||||
$('#new_todo_starred').val('false');
|
||||
}
|
||||
|
||||
function insert_new_context_with_new_todo() {
|
||||
$('#no_todos_in_view').slideUp(100);
|
||||
<%-
|
||||
empty_id = '#no_todos_in_view'
|
||||
empty_id = '#tickler-empty-nd' if source_view_is :tickler
|
||||
-%>
|
||||
$('<%=empty_id%>').slideUp(100);
|
||||
$('#display_box').prepend(html_for_new_context());
|
||||
}
|
||||
|
||||
function add_todo_to_existing_context() {
|
||||
<% if source_view_is_one_of(:todo, :deferred, :tag) -%>
|
||||
<% unless source_view_is_one_of(:todo, :tag) && @todo.deferred? -%>
|
||||
<% unless source_view_is_one_of(:todo, :tag) && (@todo.deferred?||@todo.hidden?) -%>
|
||||
$('#c<%= @todo.context_id %>').fadeIn(500, function() {});
|
||||
$('#no_todos_in_view').slideUp(100);
|
||||
<%= "$('#tickler-empty-nd').slideUp(100);" if source_view_is(:deferred) && @todo.deferred? %>
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
$('#<%=empty_container_msg_div_id%>').hide();
|
||||
|
|
@ -59,4 +66,4 @@ function html_for_new_context() {
|
|||
|
||||
function html_for_new_todo() {
|
||||
return "<%= @saved ? escape_javascript(render(:partial => @todo, :locals => { :parent_container_type => parent_container_type, :source_view => @source_view })) : "" %>";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ function clear_form() {
|
|||
$('#todo-form-multi-new-action').clearForm();
|
||||
TracksForm.set_context_name_for_multi_add('<%=escape_javascript @initial_context_name%>');
|
||||
TracksForm.set_project_name_for_multi_add('<%=escape_javascript @initial_project_name%>');
|
||||
TracksForm.set_tag_list_for_multi_add('<%=escape_javascript @default_tags%>');
|
||||
TracksForm.set_tag_list_for_multi_add('<%=escape_javascript @initial_tags%>');
|
||||
$('#todo-form-multi-new-action input:text:first').focus();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,12 +4,13 @@
|
|||
remove_todo_from_page();
|
||||
show_new_todo_if_todo_was_recurring();
|
||||
activate_pending_todos();
|
||||
update_predecessors();
|
||||
show_empty_messages();
|
||||
<%- else -%>
|
||||
TracksPages.page_notify('error', "<%= t('todos.error_deleting_item', :description => @todo.description) %>", 8);
|
||||
<%- end -%>
|
||||
|
||||
<% if @saved
|
||||
<% if @saved
|
||||
# do not send the js in case of an error
|
||||
-%>
|
||||
|
||||
|
|
@ -32,19 +33,24 @@ function show_empty_messages() {
|
|||
|
||||
function remove_todo_from_page() {
|
||||
<% if (@remaining_in_context == 0) && update_needs_to_hide_context
|
||||
# remove context with deleted todo
|
||||
# remove context with deleted todo
|
||||
-%>
|
||||
$('#c<%=@todo.context_id%>').fadeOut(400, function() {
|
||||
$('#<%=dom_id(@todo)%>').remove();
|
||||
});
|
||||
<%= show_empty_message_in_source_container -%>
|
||||
$('#c<%=@todo.context_id%>').fadeOut(400, function() {
|
||||
$('#<%=dom_id(@todo)%>').remove();
|
||||
});
|
||||
<%= show_empty_message_in_source_container -%>
|
||||
<% else
|
||||
# remove only the todo
|
||||
# remove only the todo
|
||||
-%>
|
||||
<%= show_empty_message_in_source_container %>
|
||||
$('#<%=dom_id(@todo)%>').slideUp(400, function() {
|
||||
$('#<%=dom_id(@todo)%>').remove();
|
||||
});
|
||||
<%= show_empty_message_in_source_container %>
|
||||
$('#<%=dom_id(@todo)%>').slideUp(400, function() {
|
||||
$('#<%=dom_id(@todo)%>').remove();
|
||||
<% if source_view_is :calendar
|
||||
# in calendar view it is possible to have a todo twice on the page
|
||||
-%>
|
||||
$('#<%=dom_id(@todo)%>').remove();
|
||||
<% end %>
|
||||
});
|
||||
<% end -%>
|
||||
}
|
||||
|
||||
|
|
@ -64,7 +70,7 @@ function show_new_todo_if_todo_was_recurring() {
|
|||
}
|
||||
|
||||
function activate_pending_todos() {
|
||||
<% # Activate pending todos that are successors of the completed
|
||||
<% # Activate pending todos that are successors of the deleted
|
||||
if @saved && @pending_to_activate
|
||||
# do not render the js in case of an error or if no todos to activate
|
||||
@pending_to_activate.each do |t|
|
||||
|
|
@ -84,10 +90,22 @@ function activate_pending_todos() {
|
|||
<% end -%>
|
||||
}
|
||||
|
||||
function update_predecessors() {
|
||||
<%
|
||||
if @todo_was_destroyed_from_pending_state
|
||||
@uncompleted_predecessors.each do |p| -%>
|
||||
if ($('#<%=item_container_id(p)%>')) {
|
||||
$('#<%=dom_id(p)%>').html('<%=escape_javascript(render(:partial => p, :locals => { :parent_container_type => parent_container_type }))%>');
|
||||
}
|
||||
<% end
|
||||
end
|
||||
%>
|
||||
}
|
||||
|
||||
function html_for_new_recurring_todo() {
|
||||
return "<%= @saved && @new_recurring_todo ? escape_javascript(render(:partial => @new_recurring_todo, :locals => { :parent_container_type => parent_container_type })) : "" %>";
|
||||
}
|
||||
|
||||
<% end
|
||||
<% end
|
||||
# if @saved
|
||||
-%>
|
||||
|
|
|
|||
31
app/views/todos/done.html.erb
Normal file
31
app/views/todos/done.html.erb
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<div id="display_box_projects">
|
||||
<div class="container">
|
||||
<h2><%= t('todos.completed_today') %></h2>
|
||||
<% if @done_today.empty? -%>
|
||||
<div class="message"><p><%= t('todos.no_completed_actions') %></p></div>
|
||||
<% else -%>
|
||||
<%= render :partial => "todos/todo", :collection => @done_today, :locals => { :parent_container_type => "completed", :suppress_context => false, :suppress_project => false } %>
|
||||
<% end -%>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<h2><%= t('todos.completed_rest_of_week') %></h2>
|
||||
<% if @done_this_week.empty? -%>
|
||||
<div class="message"><p><%= t('todos.no_completed_actions') %></p></div>
|
||||
<% else -%>
|
||||
<%= render :partial => "todos/todo", :collection => @done_this_week, :locals => { :parent_container_type => "completed", :suppress_context => false, :suppress_project => false } %>
|
||||
<% end -%>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<h2><%= t('todos.completed_rest_of_month') %></h2>
|
||||
<% if @done_this_month.empty? -%>
|
||||
<div class="message"><p><%= t('todos.no_completed_actions') %></p></div>
|
||||
<% else -%>
|
||||
<%= render :partial => "todos/todo", :collection => @done_this_month, :locals => { :parent_container_type => "completed", :suppress_context => false, :suppress_project => false } %>
|
||||
<% end -%>
|
||||
</div>
|
||||
|
||||
<p>You can see all completed actions <%= link_to "here", determine_all_done_path %></p>
|
||||
|
||||
</div><!-- End of display_box -->
|
||||
5
app/views/todos/edit_mobile.html.erb
Normal file
5
app/views/todos/edit_mobile.html.erb
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<% form_tag todo_path(@todo, :format => 'm'), :name => 'mobileEdit', :method => :put do %>
|
||||
<%= render :partial => 'edit_mobile_form', :locals => { :parent_container_type => "show_mobile" } %>
|
||||
<p><input type="submit" value="<%= t('common.update') %>" tabindex="6" accesskey="#" /></p>
|
||||
<% end -%>
|
||||
<%= link_to t('common.cancel'), @return_path %>
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
<% form_tag todos_path(:format => 'm'), :method => :post do %>
|
||||
<%= render :partial => 'edit_mobile' %>
|
||||
<%= render :partial => 'edit_mobile_form' %>
|
||||
<p><input type="submit" value="<%= t('common.create') %>" tabindex="12" accesskey="#" /></p>
|
||||
<% end -%>
|
||||
<%= link_to t('common.back'), @return_path %>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<% # TODO: lots of overlap with add_predecessor --> helpers?
|
||||
if @removed -%>
|
||||
TracksPages.page_notify('notice', "<%= t('todos.removed_predecessor', :successor => @successor.description, :predecessor => @predecessor.description) %>", 8);
|
||||
|
||||
|
||||
replace_updated_predecessor();
|
||||
regenerate_predecessor_family();
|
||||
update_successor();
|
||||
|
|
@ -15,7 +15,7 @@ function replace_updated_predecessor() {
|
|||
|
||||
function regenerate_predecessor_family() {
|
||||
<%
|
||||
parents = @predecessor.predecessors
|
||||
parents = @predecessors
|
||||
until parents.empty?
|
||||
parent = parents.pop
|
||||
parents += parent.predecessors -%>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,29 @@
|
|||
<% form_tag todo_path(@todo, :format => 'm'), :name => 'mobileEdit', :method => :put do %>
|
||||
<%= render :partial => 'edit_mobile', :locals => { :parent_container_type => "show_mobile" } %>
|
||||
<p><input type="submit" value="<%= t('common.update') %>" tabindex="6" accesskey="#" /></p>
|
||||
<% end -%>
|
||||
<%= link_to t('common.cancel'), @return_path %>
|
||||
<h2>Description</h2>
|
||||
<%= @todo.description %><br/>
|
||||
|
||||
<h2>Actions</h2>
|
||||
|
||||
<form method="get" action="<%= edit_todo_path(@todo, :format => :m)%>">
|
||||
<button>Edit this action</button>
|
||||
<input type="hidden" name="_method" value="put" />
|
||||
</form><br/>
|
||||
|
||||
<form method="post" action="<%=toggle_star_todo_path(@todo, :format=>:m)%>">
|
||||
<button>Toggle Star</button>
|
||||
<input type="hidden" name="_method" value="put" />
|
||||
</form><br/>
|
||||
|
||||
<form method="post" action="<%=toggle_check_todo_path(@todo, :format=>:m)%>">
|
||||
<button>Mark complete</button>
|
||||
<input type="hidden" name="_method" value="put" />
|
||||
</form><br/>
|
||||
|
||||
<form method="post" action="<%=defer_todo_path(@todo, :format=>:m, :days => 1)%>">
|
||||
<button>Defer 1 day</button>
|
||||
<input type="hidden" name="_method" value="put" />
|
||||
</form><br/>
|
||||
|
||||
<form method="post" action="<%=defer_todo_path(@todo, :format=>:m, :days => 7)%>">
|
||||
<button>Defer 7 days</button>
|
||||
<input type="hidden" name="_method" value="put" />
|
||||
</form><br/>
|
||||
|
|
@ -5,17 +5,22 @@
|
|||
redirect_after_complete();
|
||||
<% else
|
||||
animation = []
|
||||
animation << "remove_todo"
|
||||
if @todo.completed?
|
||||
animation << "add_to_completed_container" unless source_view_is(:calendar)
|
||||
animation << "add_new_recurring_todo"
|
||||
animation << "activate_pending_todos"
|
||||
animation << "remove_source_container"
|
||||
unless source_view_is(:search)
|
||||
animation << "remove_todo"
|
||||
if @todo.completed?
|
||||
animation << "add_to_completed_container" unless source_view_is_one_of(:calendar, :deferred)
|
||||
animation << "add_new_recurring_todo"
|
||||
animation << "activate_pending_todos"
|
||||
animation << "remove_source_container"
|
||||
else
|
||||
animation << "add_todo_to_context" unless source_view_is(:done)
|
||||
animation << "block_predecessors"
|
||||
end
|
||||
animation << "update_empty_container" if source_view_is_one_of(:tag, :todo)
|
||||
animation << "regenerate_predecessor_family"
|
||||
else
|
||||
animation << "add_todo_to_context"
|
||||
animation << "block_predecessors"
|
||||
end
|
||||
animation << "update_empty_container" if source_view_is_one_of(:tag, :todo) -%>
|
||||
animation << "replace_todo"
|
||||
end -%>
|
||||
<%= render_animation(animation) %>
|
||||
TracksPages.set_page_badge(<%= @down_count %>);
|
||||
<% end -%>
|
||||
|
|
@ -54,6 +59,11 @@ function add_to_completed_container(next_steps) {
|
|||
<% end -%>
|
||||
}
|
||||
|
||||
function replace_todo(next_steps) {
|
||||
$('#<%= dom_id(@todo) %>').html(html_for_todo());
|
||||
next_steps.go();
|
||||
}
|
||||
|
||||
function add_todo_to_context(next_steps) {
|
||||
$('#<%= item_container_id(@todo) %>').append(html_for_todo());
|
||||
<% if should_make_context_visible -%>
|
||||
|
|
@ -65,12 +75,15 @@ function add_todo_to_context(next_steps) {
|
|||
$("#<%= empty_container_msg_div_id(@todo) %>").slideUp(100);
|
||||
highlight_updated_todo(next_steps);
|
||||
<% end -%>
|
||||
<% if @completed_count == 0 -%>
|
||||
$("#empty-d").slideDown(100);
|
||||
<% end -%>
|
||||
}
|
||||
|
||||
function add_new_recurring_todo(next_steps) {
|
||||
<% # show new todo if the completed todo was recurring
|
||||
if @todo.from_recurring_todo?
|
||||
unless @new_recurring_todo.nil? || @new_recurring_todo.deferred? -%>
|
||||
unless @new_recurring_todo.nil? || (@new_recurring_todo.deferred? && !source_view_is(:deferred)) -%>
|
||||
$('#<%= item_container_id(@new_recurring_todo) %>').append(html_for_recurring_todo());
|
||||
$('#c<%= @new_recurring_todo.context_id %>').fadeIn(500, function() {
|
||||
highlight_updated_recurring_todo(next_steps);
|
||||
|
|
@ -108,7 +121,7 @@ function highlight_updated_todo(next_steps) {
|
|||
|
||||
function activate_pending_todos(next_steps) {
|
||||
<% # Activate pending todos that are successors of the completed
|
||||
if @saved && @pending_to_activate
|
||||
if @saved && @pending_to_activate
|
||||
# do not render the js in case of an error or if no todos to activate
|
||||
@pending_to_activate.each do |t|
|
||||
html = escape_javascript(render(:partial => t, :locals => { :parent_container_type => parent_container_type }))
|
||||
|
|
@ -121,7 +134,7 @@ function activate_pending_todos(next_steps) {
|
|||
});
|
||||
<% else -%>
|
||||
$('#<%= item_container_id(t) %>').append("<%= html%>");
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
TodoItems.highlight_todo('#<%= dom_id(t)%>');
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
|
|
@ -129,7 +142,7 @@ function activate_pending_todos(next_steps) {
|
|||
}
|
||||
|
||||
function block_predecessors(next_steps) {
|
||||
<% # Activate pending todos that are successors of the completed
|
||||
<% # Block active todos that are successors of the uncompleted
|
||||
if @saved && @active_to_block
|
||||
# do not render the js in case of an error or if no todos to block
|
||||
@active_to_block.each do |t| %>
|
||||
|
|
@ -145,6 +158,20 @@ function block_predecessors(next_steps) {
|
|||
next_steps.go();
|
||||
}
|
||||
|
||||
function regenerate_predecessor_family(next_steps) {
|
||||
<%
|
||||
if @predecessors
|
||||
parents = @predecessors
|
||||
until parents.empty?
|
||||
parent = parents.pop
|
||||
parents += parent.predecessors -%>
|
||||
$('#<%= dom_id(parent) %>').html("<%= escape_javascript(render(:partial => parent, :locals => { :parent_container_type => parent_container_type })) %>");
|
||||
<%end
|
||||
end
|
||||
-%>
|
||||
next_steps.go();
|
||||
}
|
||||
|
||||
function remove_source_container(next_steps) {
|
||||
<% if (@remaining_in_context == 0 && source_view_is_one_of(:todo, :tag))
|
||||
# remove context with deleted todo
|
||||
|
|
@ -158,7 +185,7 @@ function remove_source_container(next_steps) {
|
|||
}
|
||||
|
||||
function html_for_todo() {
|
||||
return "<%= @saved ? escape_javascript(render(:partial => @todo, :locals => {
|
||||
return "<%= @saved && !source_view_is(:done) ? escape_javascript(render(:partial => @todo, :locals => {
|
||||
:parent_container_type => parent_container_type,
|
||||
:suppress_project => source_view_is(:project),
|
||||
:suppress_context => source_view_is(:context)
|
||||
|
|
@ -167,4 +194,4 @@ function html_for_todo() {
|
|||
|
||||
function html_for_recurring_todo() {
|
||||
return "<%= @saved ? escape_javascript(render(:partial => @new_recurring_todo, :locals => { :parent_container_type => parent_container_type })) : "" %>";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
<%- if @saved -%>
|
||||
$('div#line_todo_<%= @todo.id %> a.star_item img').toggleClass('starred_todo').toggleClass('unstarred_todo');
|
||||
$('div#line_todo_<%= @todo.id %> a.star_item img').toggleClass('starred');
|
||||
<%- else -%>
|
||||
TracksPages.page_notify('error', '<%= t('todos.error_starring', :description => @todo.description) %>', 8);
|
||||
<%- end -%>
|
||||
|
|
|
|||
|
|
@ -27,6 +27,11 @@
|
|||
function remove_todo(next_steps) {
|
||||
$('#<%= dom_id(@todo) %>').fadeOut(400, function() {
|
||||
$('#<%= dom_id(@todo) %>').remove();
|
||||
<% if source_view_is :calendar
|
||||
# in calendar view it is possible to have a todo twice on the page
|
||||
-%>
|
||||
$('#<%= dom_id(@todo) %>').remove();
|
||||
<% end %>
|
||||
<%= show_empty_message_in_source_container -%>
|
||||
next_steps.go();
|
||||
});
|
||||
|
|
@ -41,7 +46,7 @@ function add_to_existing_container(next_steps) {
|
|||
<% end -%>
|
||||
<% else -%>
|
||||
<% unless (@todo_hidden_state_changed && @todo.hidden?) || @todo_was_deferred_from_active_state -%>
|
||||
$('#c<%= @todo.context_id %>').fadeIn(500, function() {
|
||||
$('#c<%= @todo.context_id %>').fadeIn(500, function() {
|
||||
next_steps.go();
|
||||
<% if @target_context_count==1 -%>
|
||||
$("#<%= empty_container_msg_div_id %>").slideUp(100);
|
||||
|
|
@ -64,6 +69,7 @@ function replace_todo(next_steps) {
|
|||
function hide_context(next_steps) {
|
||||
<% context_id = @context_changed ? @original_item_context_id : @todo.context_id -%>
|
||||
$('#c<%= context_id %>').fadeOut(400, function(){ next_steps.go(); });
|
||||
<%= "$('#tickler-empty-nd').slideDown(400);" if source_view_is(:deferred) && @down_count == 0 %>
|
||||
}
|
||||
|
||||
function highlight_updated_todo(next_steps) {
|
||||
|
|
@ -104,7 +110,7 @@ function html_for_error_messages() {
|
|||
return "<%= escape_javascript(error_messages_for('todo')) %>";
|
||||
}
|
||||
|
||||
function update_predecessors() {
|
||||
function update_predecessors(next_steps) {
|
||||
<% @todo.uncompleted_predecessors.each do |p| -%>
|
||||
if ($('#<%=item_container_id(p)%>')) {
|
||||
$('#<%=dom_id(p)%>').html('<%=escape_javascript(render(:partial => p, :locals => { :parent_container_type => parent_container_type }))%>');
|
||||
|
|
@ -117,4 +123,5 @@ function update_predecessors() {
|
|||
}
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
next_steps.go();
|
||||
}
|
||||
4
app/views/users/_update_password.html.erb
Normal file
4
app/views/users/_update_password.html.erb
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<label for="user[password]"><%= t('users.new_password_label') %>:</label><br/>
|
||||
<%= password_field "user", "password", :size => 40 %><br/>
|
||||
<label for="user[password_confirmation]"><%= t('users.password_confirmation_label') %>:</label><br/>
|
||||
<%= password_field "user", "password_confirmation", :size => 40 %><br/>
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
<div id="single_box" class="container context">
|
||||
|
||||
|
||||
<h2><%= @page_title %></h2>
|
||||
|
||||
<%= error_messages_for 'user' %>
|
||||
|
|
@ -7,20 +7,10 @@
|
|||
<p><%= t('users.change_password_prompt') %></p>
|
||||
|
||||
<% form_tag :action => 'update_password' do %>
|
||||
<table width="440px">
|
||||
<tr>
|
||||
<td><label for="updateuser_password"><%= t('users.new_password_label') %>:</label></td>
|
||||
<td><%= password_field "updateuser", "password", :size => 40 %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="updateuser_password_confirmation"><%= t('users.password_confirmation_label') %>:</label></td>
|
||||
<td><%= password_field "updateuser", "password_confirmation", :size => 40 %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><%= link_to t('common.cancel'), preferences_path %></td>
|
||||
<td><%= submit_tag t('users.change_password_submit') %></td>
|
||||
</tr>
|
||||
</table>
|
||||
<%= render :partial => 'update_password' %>
|
||||
<br/>
|
||||
<%= link_to t('common.cancel'), preferences_path %>
|
||||
<%= submit_tag t('users.change_password_submit') %>
|
||||
<% end %>
|
||||
|
||||
</div>
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
<% if @saved -%>
|
||||
remove_user_from_page();
|
||||
TracksPages.set_page_badge(<%= @total_users %>);
|
||||
TracksPages.page_notify('notice', '<%= t('users.destroy_successful', :login => @deleted_user.login) %>', 5);
|
||||
TracksPages.page_notify('notice', '<%= t('users.destroy_successful', :login => @deleted_user.login) %>', 8);
|
||||
<% else -%>
|
||||
TracksPages.page_notify('error', '<%= t('users.destroy_error', :login => @deleted_user.login) %>', 8);
|
||||
<% end -%>
|
||||
|
|
|
|||
|
|
@ -110,5 +110,19 @@ module Rails
|
|||
end
|
||||
end
|
||||
|
||||
class Rails::Boot
|
||||
def run
|
||||
load_initializer
|
||||
|
||||
Rails::Initializer.class_eval do
|
||||
def load_gems
|
||||
@bundler_loaded ||= Bundler.require :default, Rails.env
|
||||
end
|
||||
end
|
||||
|
||||
Rails::Initializer.run(:set_load_path)
|
||||
end
|
||||
end
|
||||
|
||||
# All that for this:
|
||||
Rails.boot!
|
||||
|
|
|
|||
|
|
@ -21,15 +21,6 @@ Rails::Initializer.run do |config|
|
|||
# config.frameworks -= [ :action_web_service, :action_mailer ]
|
||||
config.autoload_paths += %W( #{RAILS_ROOT}/app/apis )
|
||||
|
||||
config.gem "highline"
|
||||
config.gem "RedCloth"
|
||||
config.gem "soap4r", :lib => false
|
||||
config.gem 'datanoise-actionwebservice', :lib => 'actionwebservice', :source => "http://gems.github.com"
|
||||
config.gem 'sanitize', :version => '~> 1.2.1'
|
||||
config.gem 'rack', :version => '1.1.0'
|
||||
config.gem 'will_paginate', :version => '~> 2.3.15'
|
||||
config.gem 'has_many_polymorphs'
|
||||
|
||||
config.action_controller.use_accept_header = true
|
||||
|
||||
# Use the database for sessions instead of the file system
|
||||
|
|
@ -69,12 +60,7 @@ Rails::Initializer.run do |config|
|
|||
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
|
||||
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
|
||||
# config.i18n.default_locale = :de
|
||||
|
||||
# See Rails::Configuration for more options
|
||||
if ( SITE_CONFIG['authentication_schemes'].include? 'cas')
|
||||
#requires rubycas-client gem to be installed
|
||||
config.gem "rubycas-client", :lib => 'casclient'
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Add new inflection rules using the following format
|
||||
|
|
@ -121,7 +107,7 @@ if ( SITE_CONFIG['authentication_schemes'].include? 'cas')
|
|||
end
|
||||
end
|
||||
|
||||
tracks_version='2.0devel'
|
||||
tracks_version='2.1devel'
|
||||
# comment out next two lines if you do not want (or can not) the date of the
|
||||
# last git commit in the footer
|
||||
info=`git log --pretty=format:"%ai" -1`
|
||||
|
|
|
|||
|
|
@ -26,8 +26,3 @@ config.action_mailer.delivery_method = :test
|
|||
config.action_controller.session_store = :cookie_store
|
||||
config.action_controller.session = { :key => 'TracksCucumber', :secret => SITE_CONFIG['salt'] * (30.0 / SITE_CONFIG['salt'].length).ceil }
|
||||
|
||||
config.gem 'cucumber', :lib => false, :version => '<0.10.0' unless File.directory?(File.join(Rails.root, 'vendor/plugins/cucumber'))
|
||||
config.gem 'cucumber-rails', :lib => false, :version => '>=0.3.2' unless File.directory?(File.join(Rails.root, 'vendor/plugins/cucumber-rails'))
|
||||
config.gem 'gherkin', :lib => false, :version => '2.2.9' unless File.directory?(File.join(Rails.root, 'vendor/plugins/gherkin'))
|
||||
config.gem 'database_cleaner', :lib => false, :version => '>=0.5.0' unless File.directory?(File.join(Rails.root, 'vendor/plugins/database_cleaner'))
|
||||
config.gem 'webrat', :lib => false, :version => '>=0.7.0' unless File.directory?(File.join(Rails.root, 'vendor/plugins/webrat'))
|
||||
|
|
@ -24,6 +24,3 @@ config.action_mailer.delivery_method = :test
|
|||
# Unique cookies
|
||||
config.action_controller.session = { :key => 'TracksSelenium' }
|
||||
|
||||
config.gem 'database_cleaner', :lib => false, :version => '>=0.5.0' unless File.directory?(File.join(Rails.root, 'vendor/plugins/database_cleaner'))
|
||||
config.gem 'selenium-client', :lib => false unless File.directory?(File.join(Rails.root, 'vendor/plugins/selenium-client'))
|
||||
config.gem 'mongrel' # required by webrat for selenium
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue