Arg. Branching never seems to "just work". Going to delete and recopy. Here's the delete step.

git-svn-id: http://www.rousette.org.uk/svn/tracks-repos/trunk@500 a4c988fc-2ded-0310-b66e-134b36920a42
This commit is contained in:
lukemelia 2007-03-30 04:36:14 +00:00
parent 20de5ac1a9
commit c34d9faa38
3433 changed files with 0 additions and 399153 deletions

View file

@ -1,709 +0,0 @@
*0.14.1* (October 19th, 2005)
* Don't clean RAILS_ROOT on windows
* Remove trailing '/' from RAILS_ROOT [Nicholas Seckar]
* Upgraded to Active Record 1.12.1 and Action Pack 1.10.1
*0.14.0* (October 16th, 2005)
* Moved generator folder from RAILS_ROOT/generators to RAILS_ROOT/lib/generators [Tobias Luetke]
* Fix rake dev and related commands [Nicholas Seckar]
* The rails command tries to deduce your MySQL socket by running `mysql_config
--socket`. If it fails, default to /path/to/your/mysql.sock
* Made the rails command use the application name for database names in the tailored database.yml file. Example: "rails ~/projects/blog" will use "blog_development" instead of "rails_development". [Florian Weber]
* Added Rails framework freezing tasks: freeze_gems (freeze to current gems), freeze_edge (freeze to Rails SVN trunk), unfreeze_rails (float with newest gems on system)
* Added update_javascripts task which will fetch all the latest js files from your current rails install. Use after updating rails. [Tobias Luetke]
* Added cleaning of RAILS_ROOT to useless elements such as '../non-dot-dot/'. Provides cleaner backtraces and error messages. [Nicholas Seckar]
* Made the instantiated/transactional fixtures settings be controlled through Rails::Initializer. Transactional and non-instantiated fixtures are default from now on. [Florian Weber]
* Support using different database adapters for development and test with ActiveRecord::Base.schema_format = :ruby [Sam Stephenson]
* Make webrick work with session(:off)
* Add --version, -v option to the Rails command. Closes #1840. [stancell]
* Update Prototype to V1.4.0_pre11, script.aculo.us to V1.5_rc3 [2504] and fix the rails generator to include the new .js files [Thomas Fuchs]
* Make the generator skip a file if it already exists and is identical to the new file.
* Add experimental plugin support #2335
* Made Rakefile aware of new .js files in script.aculo.us [Thomas Fuchs]
* Make table_name and controller_name in generators honor AR::Base.pluralize_table_names. #1216 #2213 [kazuhiko@fdiary.net]
* Clearly label functional and unit tests in rake stats output. #2297 [lasse.koskela@gmail.com]
* Make the migration generator only check files ending in *.rb when calculating the next file name #2317 [Chad Fowler]
* Added prevention of duplicate migrations from the generator #2240 [fbeausoleil@ftml.net]
* Add db_schema_dump and db_schema_import rake tasks to work with the new ActiveRecord::SchemaDumper (for dumping a schema to and reading a schema from a ruby file).
* Reformed all the config/environments/* files to conform to the new Rails::Configuration approach. Fully backwards compatible.
* Added create_sessions_table, drop_sessions_table, and purge_sessions_table as rake tasks for databases that supports migrations (MySQL, PostgreSQL, SQLite) to get a table for use with CGI::Session::ActiveRecordStore
* Added dump of schema version to the db_structure_dump task for databases that support migrations #1835 [Rick Olson]
* Fixed script/profiler for Ruby 1.8.2 #1863 [Rick Olson]
* Fixed clone_structure_to_test task for SQLite #1864 [jon@burningbush.us]
* Added -m/--mime-types option to the WEBrick server, so you can specify a Apache-style mime.types file to load #2059 [ask@develooper.com]
* Added -c/--svn option to the generator that'll add new files and remove destroyed files using svn add/revert/remove as appropriate #2064 [kevin.clark@gmail.com]
* Added -c/--charset option to WEBrick server, so you can specify a default charset (which without changes is UTF-8) #2084 [wejn@box.cz]
* Make the default stats task extendable by modifying the STATS_DIRECTORIES constant
* Allow the selected environment to define RAILS_DEFAULT_LOGGER, and have Rails::Initializer use it if it exists.
* Moved all the shared tasks from Rakefile into Rails, so that the Rakefile is empty and doesn't require updating.
* Added Rails::Initializer and Rails::Configuration to abstract all of the common setup out of config/environment.rb (uses config/boot.rb to bootstrap the initializer and paths)
* Fixed the scaffold generator to fail right away if the database isn't accessible instead of in mid-air #1169 [Chad Fowler]
* Corrected project-local generator location in scripts.rb #2010 [Michael Schuerig]
* Don't require the environment just to clear the logs #2093 [Scott Barron]
* Make the default rakefile read *.rake files from config/tasks (for easy extension of the rakefile by e.g. generators)
* Only load breakpoint in development mode and when BREAKPOINT_SERVER_PORT is defined.
* Allow the --toggle-spin switch on process/reaper to be negated
* Replace render_partial with render :partial in scaffold generator [Nicholas Seckar]
* Added -w flag to ps in process/reaper #1934 [Scott Barron]
* Allow ERb in the database.yml file (just like with fixtures), so you can pull out the database configuration in environment variables #1822 [Duane Johnson]
* Added convenience controls for FCGI processes (especially when managed remotely): spinner, spawner, and reaper. They reside in script/process. More details can be had by calling them with -h/--help.
* Added load_fixtures task to the Rakefile, which will load all the fixtures into the database for the current environment #1791 [Marcel Molina]
* Added an empty robots.txt to public/, so that web servers asking for it won't trigger a dynamic call, like favicon.ico #1738 [michael@schubert]
* Dropped the 'immediate close-down' of FCGI processes since it didn't work consistently and produced bad responses when it didn't. So now a TERM ensures exit after the next request (just as if the process is handling a request when it receives the signal). This means that you'll have to 'nudge' all FCGI processes with a request in order to ensure that they have all reloaded. This can be done by something like ./script/process/repear --nudge 'http://www.myapp.com' --instances 10, which will load the myapp site 10 times (and thus hit all of the 10 FCGI processes once, enough to shut down).
*0.13.1* (11 July, 2005)
* Look for app-specific generators in RAILS_ROOT/generators rather than the clunky old RAILS_ROOT/script/generators. Nobody really uses this feature except for the unit tests, so it's a negligible-impact change. If you want to work with third-party generators, drop them in ~/.rails/generators or simply install gems.
* Fixed that each request with the WEBrick adapter would open a new database connection #1685 [Sam Stephenson]
* Added support for SQL Server in the database rake tasks #1652 [ken.barker@gmail.com] Note: osql and scptxfr may need to be installed on your development environment. This involves getting the .exes and a .rll (scptxfr) from a production SQL Server (not developer level SQL Server). Add their location to your Environment PATH and you are all set.
* Added a VERSION parameter to the migrate task that allows you to do "rake migrate VERSION=34" to migrate to the 34th version traveling up or down depending on the current version
* Extend Ruby version check to include RUBY_RELEASE_DATE >= '2005-12-25', the final Ruby 1.8.2 release #1674 [court3nay@gmail.com]
* Improved documentation for environment config files #1625 [court3nay@gmail.com]
*0.13.0* (6 July, 2005)
* Changed the default logging level in config/environment.rb to INFO for production (so SQL statements won't be logged)
* Added migration generator: ./script/generate migration add_system_settings
* Added "migrate" as rake task to execute all the pending migrations from db/migrate
* Fixed that model generator would make fixtures plural, even if ActiveRecord::Base.pluralize_table_names was false #1185 [Marcel Molina]
* Added a DOCTYPE of HTML transitional to the HTML files generated by Rails #1124 [Michael Koziarski]
* SIGTERM also gracefully exits dispatch.fcgi. Ignore SIGUSR1 on Windows.
* Add the option to manually manage garbage collection in the FastCGI dispatcher. Set the number of requests between GC runs in your public/dispatch.fcgi [skaes@web.de]
* Allow dynamic application reloading for dispatch.fcgi processes by sending a SIGHUP. If the process is currently handling a request, the request will be allowed to complete first. This allows production fcgi's to be reloaded without having to restart them.
* RailsFCGIHandler (dispatch.fcgi) no longer tries to explicitly flush $stdout (CgiProcess#out always calls flush)
* Fixed rakefile actions against PostgreSQL when the password is all numeric #1462 [michael@schubert.cx]
* ActionMailer::Base subclasses are reloaded with the other rails components #1262
* Made the WEBrick adapter not use a mutex around action performance if ActionController::Base.allow_concurrency is true (default is false)
* Fixed that mailer generator generated fixtures/plural while units expected fixtures/singular #1457 [Scott Barron]
* Added a 'whiny nil' that's aim to ensure that when users pass nil to methods where that isn't appropriate, instead of NoMethodError? and the name of some method used by the framework users will see a message explaining what type of object was expected. Only active in test and development environments by default #1209 [Michael Koziarski]
* Fixed the test_helper.rb to be safe for requiring controllers from multiple spots, like app/controllers/article_controller.rb and app/controllers/admin/article_controller.rb, without reloading the environment twice #1390 [Nicholas Seckar]
* Fixed Webrick to escape + characters in URL's the same way that lighttpd and apache do #1397 [Nicholas Seckar]
* Added -e/--environment option to script/runner #1408 [fbeausoleil@ftml.net]
* Modernize the scaffold generator to use the simplified render and test methods and to change style from @params["id"] to params[:id]. #1367
* Added graceful exit from pressing CTRL-C during the run of the rails command #1150 [Caleb Tennis]
* Allow graceful exits for dispatch.fcgi processes by sending a SIGUSR1. If the process is currently handling a request, the request will be allowed to complete and then will terminate itself. If a request is not being handled, the process is terminated immediately (via #exit). This basically works like restart graceful on Apache. [Jamis Buck]
* Made dispatch.fcgi more robust by catching fluke errors and retrying unless its a permanent condition. [Jamis Buck]
* Added console --profile for profiling an IRB session #1154 [Jeremy Kemper]
* Changed console_sandbox into console --sandbox #1154 [Jeremy Kemper]
*0.12.1* (20th April, 2005)
* Upgraded to Active Record 1.10.1, Action Pack 1.8.1, Action Mailer 0.9.1, Action Web Service 0.7.1
*0.12.0* (19th April, 2005)
* Fixed that purge_test_database would use database settings from the development environment when recreating the test database #1122 [rails@cogentdude.com]
* Added script/benchmarker to easily benchmark one or more statement a number of times from within the environment. Examples:
# runs the one statement 10 times
script/benchmarker 10 'Person.expensive_method(10)'
# pits the two statements against each other with 50 runs each
script/benchmarker 50 'Person.expensive_method(10)' 'Person.cheap_method(10)'
* Added script/profiler to easily profile a single statement from within the environment. Examples:
script/profiler 'Person.expensive_method(10)'
script/profiler 'Person.expensive_method(10)' 10 # runs the statement 10 times
* Added Rake target clear_logs that'll truncate all the *.log files in log/ to zero #1079 [Lucas Carlson]
* Added lazy typing for generate, such that ./script/generate cn == ./script/generate controller and the likes #1051 [k@v2studio.com]
* Fixed that ownership is brought over in pg_dump during tests for PostgreSQL #1060 [pburleson@gmail.com]
* Upgraded to Active Record 1.10.0, Action Pack 1.8.0, Action Mailer 0.9.0, Action Web Service 0.7.0, Active Support 1.0.4
*0.11.1* (27th March, 2005)
* Fixed the dispatch.fcgi use of a logger
* Upgraded to Active Record 1.9.1, Action Pack 1.7.0, Action Mailer 0.8.1, Action Web Service 0.6.2, Active Support 1.0.3
*0.11.0* (22th March, 2005)
* Removed SCRIPT_NAME from the WEBrick environment to prevent conflicts with PATH_INFO #896 [Nicholas Seckar]
* Removed ?$1 from the dispatch.f/cgi redirect line to get rid of 'complete/path/from/request.html' => nil being in the @params now that the ENV["REQUEST_URI"] is used to determine the path #895 [dblack/Nicholas Seckar]
* Added additional error handling to the FastCGI dispatcher to catch even errors taking down the entire process
* Improved the generated scaffold code a lot to take advantage of recent Rails developments #882 [Tobias Luetke]
* Combined the script/environment.rb used for gems and regular files version. If vendor/rails/* has all the frameworks, then files version is used, otherwise gems #878 [Nicholas Seckar]
* Changed .htaccess to allow dispatch.* to be called from a sub-directory as part of the push with Action Pack to make Rails work on non-vhost setups #826 [Nicholas Seckar/Tobias Luetke]
* Added script/runner which can be used to run code inside the environment by eval'ing the first parameter. Examples:
./script/runner 'ReminderService.deliver'
./script/runner 'Mailer.receive(STDIN.read)'
This makes it easier to do CRON and postfix scripts without actually making a script just to trigger 1 line of code.
* Fixed webrick_server cookie handling to allow multiple cookes to be set at once #800, #813 [dave@cherryville.org]
* Fixed the Rakefile's interaction with postgresql to:
1. Use PGPASSWORD and PGHOST in the environment to fix prompting for
passwords when connecting to a remote db and local socket connections.
2. Add a '-x' flag to pg_dump which stops it dumping privileges #807 [rasputnik]
3. Quote the user name and use template0 when dumping so the functions doesn't get dumped too #855 [pburleson]
4. Use the port if available #875 [madrobby]
* Upgraded to Active Record 1.9.0, Action Pack 1.6.0, Action Mailer 0.8.0, Action Web Service 0.6.1, Active Support 1.0.2
*0.10.1* (7th March, 2005)
* Fixed rake stats to ignore editor backup files like model.rb~ #791 [skanthak]
* Added exception shallowing if the DRb server can't be started (not worth making a fuss about to distract new users) #779 [Tobias Luetke]
* Added an empty favicon.ico file to the public directory of new applications (so the logs are not spammed by its absence)
* Fixed that scaffold generator new template should use local variable instead of instance variable #778 [Dan Peterson]
* Allow unit tests to run on a remote server for PostgreSQL #781 [adamm@galacticasoftware.com]
* Added web_service generator (run ./script/generate web_service for help) #776 [Leon Bredt]
* Added app/apis and components to code statistics report #729 [Scott Barron]
* Fixed WEBrick server to use ABSOLUTE_RAILS_ROOT instead of working_directory #687 [Nicholas Seckar]
* Fixed rails_generator to be usable without RubyGems #686 [Cristi BALAN]
* Fixed -h/--help for generate and destroy generators #331
* Added begin/rescue around the FCGI dispatcher so no uncaught exceptions can bubble up to kill the process (logs to log/fastcgi.crash.log)
* Fixed that association#count would produce invalid sql when called sequentialy #659 [kanis@comcard.de]
* Fixed test/mocks/testing to the correct test/mocks/test #740
* Added early failure if the Ruby version isn't 1.8.2 or above #735
* Removed the obsolete -i/--index option from the WEBrick servlet #743
* Upgraded to Active Record 1.8.0, Action Pack 1.5.1, Action Mailer 0.7.1, Action Web Service 0.6.0, Active Support 1.0.1
*0.10.0* (24th February, 2005)
* Changed default IP binding for WEBrick from 127.0.0.1 to 0.0.0.0 so that the server is accessible both locally and remotely #696 [Marcel]
* Fixed that script/server -d was broken so daemon mode couldn't be used #687 [Nicholas Seckar]
* Upgraded to breakpoint 92 which fixes:
* overload IRB.parse_opts(), fixes #443
=> breakpoints in tests work even when running them via rake
* untaint handlers, might fix an issue discussed on the Rails ML
* added verbose mode to breakpoint_client
* less noise caused by breakpoint_client by default
* ignored TerminateLineInput exception in signal handler
=> quiet exit on Ctrl-C
* Added support for independent components residing in /components. Example:
Controller: components/list/items_controller.rb
(holds a List::ItemsController class with uses_component_template_root called)
Model : components/list/item.rb
(namespace is still shared, so an Item model in app/models will take precedence)
Views : components/list/items/show.rhtml
* Added --sandbox option to script/console that'll roll back all changes made to the database when you quit #672 [Jeremy Kemper]
* Added 'recent' as a rake target that'll run tests for files that changed in the last 10 minutes #612 [Jeremy Kemper]
* Changed script/console to default to development environment and drop --no-inspect #650 [Jeremy Kemper]
* Added that the 'fixture :posts' syntax can be used for has_and_belongs_to_many fixtures where a model doesn't exist #572 [Jeremy Kemper]
* Added that running test_units and test_functional now performs the clone_structure_to_test as well #566 [rasputnik]
* Added new generator framework that informs about its doings on generation and enables updating and destruction of generated artifacts. See the new script/destroy and script/update for more details #487 [Jeremy Kemper]
* Added Action Web Service as a new add-on framework for Action Pack [Leon Bredt]
* Added Active Support as an independent utility and standard library extension bundle
* Upgraded to Active Record 1.7.0, Action Pack 1.5.0, Action Mailer 0.7.0
*0.9.5* (January 25th, 2005)
* Fixed dependency reloading by switching to a remove_const approach where all Active Records, Active Record Observers, and Action Controllers are reloading by undefining their classes. This enables you to remove methods in all three types and see the change reflected immediately and it fixes #539. This also means that only those three types of classes will benefit from the const_missing and reloading approach. If you want other classes (like some in lib/) to reload, you must use require_dependency to do it.
* Added Florian Gross' latest version of Breakpointer and friends that fixes a variaty of bugs #441 [Florian Gross]
* Fixed skeleton Rakefile to work with sqlite3 out of the box #521 [rasputnik]
* Fixed that script/breakpointer didn't get the Ruby path rewritten as the other scripts #523 [brandt@kurowski.net]
* Fixed handling of syntax errors in models that had already been succesfully required once in the current interpreter
* Fixed that models that weren't referenced in associations weren't being reloaded in the development mode by reinstating the reload
* Fixed that generate scaffold would produce bad functional tests
* Fixed that FCGI can also display SyntaxErrors
* Upgraded to Active Record 1.6.0, Action Pack 1.4.0
*0.9.4.1* (January 18th, 2005)
* Added 5-second timeout to WordNet alternatives on creating reserved-word models #501 [Marcel Molina]
* Fixed binding of caller #496 [Alexey]
* Upgraded to Active Record 1.5.1, Action Pack 1.3.1, Action Mailer 0.6.1
*0.9.4* (January 17th, 2005)
* Added that ApplicationController will catch a ControllerNotFound exception if someone attempts to access a url pointing to an unexisting controller [Tobias Luetke]
* Flipped code-to-test ratio around to be more readable #468 [Scott Baron]
* Fixed log file permissions to be 666 instead of 777 (so they're not executable) #471 [Lucas Carlson]
* Fixed that auto reloading would some times not work or would reload the models twice #475 [Tobias Luetke]
* Added rewrite rules to deal with caching to public/.htaccess
* Added the option to specify a controller name to "generate scaffold" and made the default controller name the plural form of the model.
* Added that rake clone_structure_to_test, db_structure_dump, and purge_test_database tasks now pick up the source database to use from
RAILS_ENV instead of just forcing development #424 [Tobias Luetke]
* Fixed script/console to work with Windows (that requires the use of irb.bat) #418 [octopod]
* Fixed WEBrick servlet slowdown over time by restricting the load path reloading to mod_ruby
* Removed Fancy Indexing as a default option on the WEBrick servlet as it made it harder to use various caching schemes
* Upgraded to Active Record 1.5, Action Pack 1.3, Action Mailer 0.6
*0.9.3* (January 4th, 2005)
* Added support for SQLite in the auto-dumping/importing of schemas for development -> test #416
* Added automated rewriting of the shebang lines on installs through the gem rails command #379 [Manfred Stienstra]
* Added ActionMailer::Base.deliver_method = :test to the test environment so that mail objects are available in ActionMailer::Base.deliveries
for functional testing.
* Added protection for creating a model through the generators with a name of an existing class, like Thread or Date.
It'll even offer you a synonym using wordnet.princeton.edu as a look-up. No, I'm not kidding :) [Florian Gross]
* Fixed dependency management to happen in a unified fashion for Active Record and Action Pack using the new Dependencies module. This means that
the environment options needs to change from:
Before in development.rb:
ActionController::Base.reload_dependencies = true  
ActiveRecord::Base.reload_associations     = true
Now in development.rb:
Dependencies.mechanism = :load
Before in production.rb and test.rb:
ActionController::Base.reload_dependencies = false
ActiveRecord::Base.reload_associations     = false
Now in production.rb and test.rb:
Dependencies.mechanism = :require
* Fixed problems with dependency caching and controller hierarchies on Ruby 1.8.2 in development mode #351
* Fixed that generated action_mailers doesnt need to require the action_mailer since thats already done in the environment #382 [Lucas Carlson]
* Upgraded to Action Pack 1.2.0 and Active Record 1.4.0
*0.9.2*
* Fixed CTRL-C exists from the Breakpointer to be a clean affair without error dumping [Kent Sibilev]
* Fixed "rake stats" to work with sub-directories in models and controllers and to report the code to test ration [Scott Baron]
* Added that Active Record associations are now reloaded instead of cleared to work with the new const_missing hook in Active Record.
* Added graceful handling of an inaccessible log file by redirecting output to STDERR with a warning #330 [rainmkr]
* Added support for a -h/--help parameter in the generator #331 [Ulysses]
* Fixed that File.expand_path in config/environment.rb would fail when dealing with symlinked public directories [mjobin]
* Upgraded to Action Pack 1.1.0 and Active Record 1.3.0
*0.9.1*
* Upgraded to Action Pack 1.0.1 for important bug fix
* Updated gem dependencies
*0.9.0*
* Renamed public/dispatch.servlet to script/server -- it wasn't really dispatching anyway as its delegating calls to public/dispatch.rb
* Renamed AbstractApplicationController and abstract_application.rb to ApplicationController and application.rb, so that it will be possible
for the framework to automatically pick up on app/views/layouts/application.rhtml and app/helpers/application.rb
* Added script/console that makes it even easier to start an IRB session for interacting with the domain model. Run with no-args to
see help.
* Added breakpoint support through the script/breakpointer client. This means that you can break out of execution at any point in
the code, investigate and change the model, AND then resume execution! Example:
class WeblogController < ActionController::Base
def index
@posts = Post.find_all
breakpoint "Breaking out from the list"
end
end
So the controller will accept the action, run the first line, then present you with a IRB prompt in the breakpointer window.
Here you can do things like:
Executing breakpoint "Breaking out from the list" at .../webrick_server.rb:16 in 'breakpoint'
>> @posts.inspect
=> "[#<Post:0x14a6be8 @attributes={\"title\"=>nil, \"body\"=>nil, \"id\"=>\"1\"}>,
#<Post:0x14a6620 @attributes={\"title\"=>\"Rails you know!\", \"body\"=>\"Only ten..\", \"id\"=>\"2\"}>]"
>> @posts.first.title = "hello from a breakpoint"
=> "hello from a breakpoint"
...and even better is that you can examine how your runtime objects actually work:
>> f = @posts.first
=> #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>
>> f.
Display all 152 possibilities? (y or n)
Finally, when you're ready to resume execution, you press CTRL-D
* Changed environments to be configurable through an environment variable. By default, the environment is "development", but you
can change that and set your own by configuring the Apache vhost with a string like (mod_env must be available on the server):
SetEnv RAILS_ENV production
...if you're using WEBrick, you can pick the environment to use with the command-line parameters -e/--environment, like this:
ruby public/dispatcher.servlet -e production
* Added a new default environment called "development", which leaves the production environment to be tuned exclusively for that.
* Added a start_server in the root of the Rails application to make it even easier to get started
* Fixed public/.htaccess to use RewriteBase and share the same rewrite rules for all the dispatch methods
* Fixed webrick_server to handle requests in a serialized manner (the Rails reloading infrastructure is not thread-safe)
* Added support for controllers in directories. So you can have:
app/controllers/account_controller.rb # URL: /account/
app/controllers/admin/account_controller.rb # URL: /admin/account/
NOTE: You need to update your public/.htaccess with the new rules to pick it up
* Added reloading for associations and dependencies under cached environments like FastCGI and mod_ruby. This makes it possible to use
those environments for development. This is turned on by default, but can be turned off with
ActiveRecord::Base.reload_associations = false and ActionController::Base.reload_dependencies = false in production environments.
* Added support for sub-directories in app/models. So now you can have something like Basecamp with:
app/models/accounting
app/models/project
app/models/participants
app/models/settings
It's poor man's namespacing, but only for file-system organization. You still require files just like before.
Nothing changes inside the files themselves.
* Fixed a few references in the tests generated by new_mailer [Jeremy Kemper]
* Added support for mocks in testing with test/mocks
* Cleaned up the environments a bit and added global constant RAILS_ROOT
*0.8.5* (9)
* Made dev-util available to all tests, so you can insert breakpoints in any test case to get an IRB prompt at that point [Jeremy Kemper]:
def test_complex_stuff
@david.projects << @new_project
breakpoint "Let's have a closer look at @david"
end
You need to install dev-utils yourself for this to work ("gem install dev-util").
* Added shared generator behavior so future upgrades should be possible without manually copying over files [Jeremy Kemper]
* Added the new helper style to both controller and helper templates [Jeremy Kemper]
* Added new_crud generator for creating a model and controller at the same time with explicit scaffolding [Jeremy Kemper]
* Added configuration of Test::Unit::TestCase.fixture_path to test_helper to concide with the new AR fixtures style
* Fixed that new_model was generating singular table/fixture names
* Upgraded to Action Mailer 0.4.0
* Upgraded to Action Pack 0.9.5
* Upgraded to Active Record 1.1.0
*0.8.0 (15)*
* Removed custom_table_name option for new_model now that the Inflector is as powerful as it is
* Changed the default rake action to just do testing and separate API generation and coding statistics into a "doc" task.
* Fixed WEBrick dispatcher to handle missing slashes in the URLs gracefully [alexey]
* Added user option for all postgresql tool calls in the rakefile [elvstone]
* Fixed problem with running "ruby public/dispatch.servlet" instead of "cd public; ruby dispatch.servlet" [alexey]
* Fixed WEBrick server so that it no longer hardcodes the ruby interpreter used to "ruby" but will get the one used based
on the Ruby runtime configuration. [Marcel Molina Jr.]
* Fixed Dispatcher so it'll route requests to magic_beans to MagicBeansController/magic_beans_controller.rb [Caio Chassot]
* "new_controller MagicBeans" and "new_model SubscriptionPayments" will now both behave properly as they use the new Inflector.
* Fixed problem with MySQL foreign key constraint checks in Rake :clone_production_structure_to_test target [Andreas Schwarz]
* Changed WEBrick server to by default be auto-reloading, which is slower but makes source changes instant.
Class compilation cache can be turned on with "-c" or "--cache-classes".
* Added "-b/--binding" option to WEBrick dispatcher to bind the server to a specific IP address (default: 127.0.0.1) [Kevin Temp]
* dispatch.fcgi now DOESN'T set FCGI_PURE_RUBY as it was slowing things down for now reason [Andreas Schwarz]
* Added new_mailer generator to work with Action Mailer
* Included new framework: Action Mailer 0.3
* Upgraded to Action Pack 0.9.0
* Upgraded to Active Record 1.0.0
*0.7.0*
* Added an optional second argument to the new_model script that allows the programmer to specify the table name,
which will used to generate a custom table_name method in the model and will also be used in the creation of fixtures.
[Kevin Radloff]
* script/new_model now turns AccountHolder into account_holder instead of accountholder [Kevin Radloff]
* Fixed the faulty handleing of static files with WEBrick [Andreas Schwarz]
* Unified function_test_helper and unit_test_helper into test_helper
* Fixed bug with the automated production => test database dropping on PostgreSQL [dhawkins]
* create_fixtures in both the functional and unit test helper now turns off the log during fixture generation
and can generate more than one fixture at a time. Which makes it possible for assignments like:
@people, @projects, @project_access, @companies, @accounts =
create_fixtures "people", "projects", "project_access", "companies", "accounts"
* Upgraded to Action Pack 0.8.5 (locally-scoped variables, partials, advanced send_file)
* Upgraded to Active Record 0.9.5 (better table_name guessing, cloning, find_all_in_collection)
*0.6.5*
* No longer specifies a template for rdoc, so it'll use whatever is default (you can change it in the rakefile)
* The new_model generator will now use the same rules for plural wordings as Active Record
(so Category will give categories, not categorys) [Kevin Radloff]
* dispatch.fcgi now sets FCGI_PURE_RUBY to true to ensure that it's the Ruby version that's loaded [danp]
* Made the GEM work with Windows
* Fixed bug where mod_ruby would "forget" the load paths added when switching between controllers
* PostgreSQL are now supported for the automated production => test database dropping [Kevin Radloff]
* Errors thrown by the dispatcher are now properly handled in FCGI.
* Upgraded to Action Pack 0.8.0 (lots and lots and lots of fixes)
* Upgraded to Active Record 0.9.4 (a bunch of fixes)
*0.6.0*
* Added AbstractionApplicationController as a superclass for all controllers generated. This class can be used
to carry filters and methods that are to be shared by all. It has an accompanying ApplicationHelper that all
controllers will also automatically have available.
* Added environments that can be included from any script to get the full Active Record and Action Controller
context running. This can be used by maintenance scripts or to interact with the model through IRB. Example:
require 'config/environments/production'
for account in Account.find_all
account.recalculate_interests
end
A short migration script for an account model that had it's interest calculation strategy changed.
* Accessing the index of a controller with "/weblog" will now redirect to "/weblog/" (only on Apache, not WEBrick)
* Simplified the default Apache config so even remote requests are served off CGI as a default.
You'll now have to do something specific to activate mod_ruby and FCGI (like using the force urls).
This should make it easier for new comers that start on an external server.
* Added more of the necessary Apache options to .htaccess to make it easier to setup
* Upgraded to Action Pack 0.7.9 (lots of fixes)
* Upgraded to Active Record 0.9.3 (lots of fixes)
*0.5.7*
* Fixed bug in the WEBrick dispatcher that prevented it from getting parameters from the URL
(through GET requests or otherwise)
* Added lib in root as a place to store app specific libraries
* Added lib and vendor to load_path, so anything store within can be loaded directly.
Hence lib/redcloth.rb can be loaded with require "redcloth"
* Upgraded to Action Pack 0.7.8 (lots of fixes)
* Upgraded to Active Record 0.9.2 (minor upgrade)
*0.5.6*
* Upgraded to Action Pack 0.7.7 (multipart form fix)
* Updated the generated template stubs to valid XHTML files
* Ensure that controllers generated are capitalized, so "new_controller TodoLists"
gives the same as "new_controller Todolists" and "new_controller todolists".
*0.5.5*
* Works on Windows out of the box! (Dropped symlinks)
* Added webrick dispatcher: Try "ruby public/dispatch.servlet --help" [Florian Gross]
* Report errors about initialization to browser (instead of attempting to use uninitialized logger)
* Upgraded to Action Pack 0.7.6
* Upgraded to Active Record 0.9.1
* Added distinct 500.html instead of reusing 404.html
* Added MIT license
*0.5.0*
* First public release

View file

@ -1,11 +0,0 @@
To run selenium tests, start Tracks in test mode using
script/server -e test
Then open a browser to
http://localhost:3000/selenium/
and interact with the test runner.
For more information about Selenium on Rails, see vendor/plugins/selenium-on-rails/README

View file

@ -1,190 +0,0 @@
== Welcome to Rails
Rails is a web-application and persistance framework that includes everything
needed to create database-backed web-applications according to the
Model-View-Control pattern of separation. This pattern splits the view (also
called the presentation) into "dumb" templates that are primarily responsible
for inserting pre-build data in between HTML tags. The model contains the
"smart" domain objects (such as Account, Product, Person, Post) that holds all
the business logic and knows how to persist themselves to a database. The
controller handles the incoming requests (such as Save New Account, Update
Product, Show Post) by manipulating the model and directing data to the view.
In Rails, the model is handled by what's called a object-relational mapping
layer entitled Active Record. This layer allows you to present the data from
database rows as objects and embellish these data objects with business logic
methods. You can read more about Active Record in
link:files/vendor/rails/activerecord/README.html.
The controller and view is handled by the Action Pack, which handles both
layers by its two parts: Action View and Action Controller. These two layers
are bundled in a single package due to their heavy interdependence. This is
unlike the relationship between the Active Record and Action Pack that is much
more separate. Each of these packages can be used independently outside of
Rails. You can read more about Action Pack in
link:files/vendor/rails/actionpack/README.html.
== Requirements
* Database and driver (MySQL, PostgreSQL, or SQLite)
* Rake[http://rake.rubyforge.org] for running tests and the generating documentation
== Optionals
* Apache 1.3.x or 2.x or lighttpd 1.3.11+ (or any FastCGI-capable webserver with a
mod_rewrite-like module)
* FastCGI (or mod_ruby) for better performance on Apache
== Getting started
1. Run the WEBrick servlet: <tt>ruby script/server</tt>
(run with --help for options)
2. Go to http://localhost:3000/ and get "Congratulations, you've put Ruby on Rails!"
3. Follow the guidelines on the "Congratulations, you've put Ruby on Rails!" screen
== Example for Apache conf
<VirtualHost *:80>
ServerName rails
DocumentRoot /path/application/public/
ErrorLog /path/application/log/server.log
<Directory /path/application/public/>
Options ExecCGI FollowSymLinks
AllowOverride all
Allow from all
Order allow,deny
</Directory>
</VirtualHost>
NOTE: Be sure that CGIs can be executed in that directory as well. So ExecCGI
should be on and ".cgi" should respond. All requests from 127.0.0.1 goes
through CGI, so no Apache restart is necessary for changes. All other requests
goes through FCGI (or mod_ruby) that requires restart to show changes.
== Example for lighttpd conf (with FastCGI)
server.port = 8080
server.bind = "127.0.0.1"
# server.event-handler = "freebsd-kqueue" # needed on OS X
server.modules = ( "mod_rewrite", "mod_fastcgi" )
url.rewrite = ( "^/$" => "index.html", "^([^.]+)$" => "$1.html" )
server.error-handler-404 = "/dispatch.fcgi"
server.document-root = "/path/application/public"
server.errorlog = "/path/application/log/server.log"
fastcgi.server = ( ".fcgi" =>
( "localhost" =>
(
"min-procs" => 1,
"max-procs" => 5,
"socket" => "/tmp/application.fcgi.socket",
"bin-path" => "/path/application/public/dispatch.fcgi",
"bin-environment" => ( "RAILS_ENV" => "development" )
)
)
)
== Debugging Rails
Have "tail -f" commands running on both the server.log, production.log, and
test.log files. Rails will automatically display debugging and runtime
information to these files. Debugging info will also be shown in the browser
on requests from 127.0.0.1.
== Breakpoints
Breakpoint support is available through the script/breakpointer client. This
means that you can break out of execution at any point in the code, investigate
and change the model, AND then resume execution! Example:
class WeblogController < ActionController::Base
def index
@posts = Post.find_all
breakpoint "Breaking out from the list"
end
end
So the controller will accept the action, run the first line, then present you
with a IRB prompt in the breakpointer window. Here you can do things like:
Executing breakpoint "Breaking out from the list" at .../webrick_server.rb:16 in 'breakpoint'
>> @posts.inspect
=> "[#<Post:0x14a6be8 @attributes={\"title\"=>nil, \"body\"=>nil, \"id\"=>\"1\"}>,
#<Post:0x14a6620 @attributes={\"title\"=>\"Rails you know!\", \"body\"=>\"Only ten..\", \"id\"=>\"2\"}>]"
>> @posts.first.title = "hello from a breakpoint"
=> "hello from a breakpoint"
...and even better is that you can examine how your runtime objects actually work:
>> f = @posts.first
=> #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>
>> f.
Display all 152 possibilities? (y or n)
Finally, when you're ready to resume execution, you press CTRL-D
== Console
You can interact with the domain model by starting the console through script/console.
Here you'll have all parts of the application configured, just like it is when the
application is running. You can inspect domain models, change values, and save to the
database. Start the script without arguments will launch it in the development environment.
Passing an argument will specify a different environment, like <tt>console production</tt>.
== Description of contents
app
Holds all the code that's specific to this particular application.
app/controllers
Holds controllers that should be named like weblog_controller.rb for
automated URL mapping. All controllers should descend from
ActionController::Base.
app/models
Holds models that should be named like post.rb.
Most models will descent from ActiveRecord::Base.
app/views
Holds the template files for the view that should be named like
weblog/index.rhtml for the WeblogController#index action. All views uses eRuby
syntax. This directory can also be used to keep stylesheets, images, and so on
that can be symlinked to public.
app/helpers
Holds view helpers that should be named like weblog_helper.rb.
config
Configuration files for the Rails environment, the routing map, the database, and other dependencies.
components
Self-contained mini-applications that can bundle controllers, models, and views together.
lib
Application specific libraries. Basically, any kind of custom code that doesn't
belong controllers, models, or helpers. This directory is in the load path.
public
The directory available for the web server. Contains sub-directories for images, stylesheets,
and javascripts. Also contains the dispatchers and the default HTML files.
script
Helper scripts for automation and generation.
test
Unit and functional tests along with fixtures.
vendor
External libraries that the application depend on. This directory is in the load path.

View file

@ -1,10 +0,0 @@
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
require(File.join(File.dirname(__FILE__), 'config', 'boot'))
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
require 'tasks/rails'

View file

@ -1,18 +0,0 @@
class TodoApi < ActionWebService::API::Base
api_method :new_todo,
:expects => [{:username => :string}, {:token => :string}, {:context_id => :int}, {:description => :string}],
:returns => [:int]
api_method :new_rich_todo,
:expects => [{:username => :string}, {:token => :string}, {:default_context_id => :int}, {:description => :string}],
:returns => [:int]
api_method :list_contexts,
:expects => [{:username => :string}, {:token => :string}],
:returns => [[Context]]
api_method :list_projects,
:expects => [{:username => :string}, {:token => :string}],
:returns => [[Project]]
end

View file

@ -1,176 +0,0 @@
# The filters added to this controller will be run for all controllers in the application.
# Likewise will all the methods added be available for all controllers.
require_dependency "login_system"
require_dependency "source_view"
require "redcloth"
require 'date'
require 'time'
Tag # We need this in development mode, or you get 'method missing' errors
class ApplicationController < ActionController::Base
helper :application
include LoginSystem
layout 'standard'
before_filter :set_session_expiration
prepend_before_filter :login_required
after_filter :set_charset
include ActionView::Helpers::TextHelper
helper_method :format_date, :markdown
# 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"
end
def set_session_expiration
# http://wiki.rubyonrails.com/rails/show/HowtoChangeSessionOptions
unless session == nil
return if @controller_name == 'feed' or session['noexpiry'] == "on"
# If the method is called by the feed controller (which we don't have under session control)
# or if we checked the box to keep logged in on login
# don't set the session expiry time.
if session
# Get expiry time (allow ten seconds window for the case where we have none)
expiry_time = session['expiry_time'] || Time.now + 10
if expiry_time < Time.now
# Too late, matey... bang goes your session!
reset_session
else
# Okay, you get another hour
session['expiry_time'] = Time.now + (60*60)
end
end
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 |wants|
wants.html do
notify :warning, "An error occurred on the server."
render :action => "index"
end
wants.js { render :action => 'error' }
wants.xml { render :text => 'An error occurred on the server.' + $! }
end
end
# 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
else
word = string.pluralize
end
return count.to_s + "&nbsp;" + word
end
def count_undone_todos(todos_parent)
if todos_parent.nil?
count = 0
elsif (todos_parent.is_a?(Project) && todos_parent.hidden?)
count = eval "@project_project_hidden_todo_counts[#{todos_parent.id}]"
else
count = eval "@#{todos_parent.class.to_s.downcase}_not_done_counts[#{todos_parent.id}]"
end
count || 0
end
# Convert a date object to the format specified
# in config/settings.yml
#
def format_date(date)
if date
date_format = @user.prefs.date_format
formatted_date = date.strftime("#{date_format}")
else
formatted_date = ''
end
formatted_date
end
# Uses RedCloth to transform text using either Textile or Markdown
# Need to require redcloth above
# RedCloth 3.0 or greater is needed to use Markdown, otherwise it only handles Textile
#
def markdown(text)
RedCloth.new(text).to_html
end
def build_default_project_context_name_map(projects)
Hash[*projects.reject{ |p| p.default_context.nil? }.map{ |p| [p.name, p.default_context.name] }.flatten].to_json
end
protected
def admin_login_required
unless User.find_by_id_and_is_admin(session['user_id'], true)
render :text => "401 Unauthorized: Only admin users are allowed access to this function.", :status => 401
return false
end
end
def redirect_back_or_home
redirect_back_or_default home_url
end
def boolean_param(param_name)
return false if param_name.blank?
s = params[param_name]
return false if s.blank? || s == false || s =~ /^false$/i
return true if s == true || s =~ /^true$/i
raise ArgumentError.new("invalid value for Boolean: \"#{s}\"")
end
private
def parse_date_per_user_prefs( s )
return nil if s.blank?
Date.strptime(s, @user.prefs.date_format)
end
def init_data_for_sidebar
@projects = @user.projects
@contexts = @user.contexts
init_not_done_counts
if @prefs.show_hidden_projects_in_sidebar
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 = Todo.count(:conditions => ['user_id = ? and state = ?', @user.id, 'active'], :group => :#{parent}_id)")
end
end
def init_project_hidden_todo_counts(parents = ['project','context'])
parents.each do |parent|
eval("@#{parent}_project_hidden_todo_counts = Todo.count(:conditions => ['user_id = ? and state = ?', @user.id, 'project_hidden'], :group => :#{parent}_id)")
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"
def notify(type, message)
flash[type] = message
logger.error("ERROR: #{message}") if type == :error
end
end

View file

@ -1,96 +0,0 @@
class BackendController < ApplicationController
wsdl_service_name 'Backend'
web_service_api TodoApi
web_service_scaffold :invoke
skip_before_filter :login_required
def new_todo(username, token, context_id, description)
check_token_against_user_word(username, token)
check_context_belongs_to_user(context_id)
item = create_todo(description, context_id)
item.id
end
def new_rich_todo(username, token, default_context_id, description)
check_token_against_user_word(username,token)
description,context = split_by_char('@',description)
description,project = split_by_char('>',description)
if(!context.nil? && project.nil?)
context,project = split_by_char('>',context)
end
context_id = default_context_id
unless(context.nil?)
found_context = @user.contexts.find_by_namepart(context)
context_id = found_context.id unless found_context.nil?
end
check_context_belongs_to_user(context_id)
project_id = nil
unless(project.blank?)
if(project[0..3].downcase == "new:")
found_project = @user.projects.build
found_project.name = project[4..255+4].strip
found_project.save!
else
found_project = @user.projects.find_by_namepart(project)
end
project_id = found_project.id unless found_project.nil?
end
todo = create_todo(description, context_id, project_id)
todo.id
end
def list_contexts(username, token)
check_token_against_user_word(username, token)
@user.contexts
end
def list_projects(username, token)
check_token_against_user_word(username, token)
@user.projects
end
private
# Check whether the token in the URL matches the word in the User's table
def check_token_against_user_word(username, token)
@user = User.find_by_login( username )
unless (token == @user.word)
raise(InvalidToken, "Sorry, you don't have permission to perform this action.")
end
end
def check_context_belongs_to_user(context_id)
unless @user.contexts.exists? context_id
raise(CannotAccessContext, "Cannot access a context that does not belong to this user.")
end
end
def create_todo(description, context_id, project_id = nil)
item = @user.todos.build
item.description = description
item.context_id = context_id
item.project_id = project_id unless project_id.nil?
item.save
raise item.errors.full_messages.to_s if item.new_record?
item
end
def split_by_char(separator,string)
parts = string.split(separator)
return safe_strip(parts[0]), safe_strip(parts[1])
end
def safe_strip(s)
s.strip! unless s.nil?
s
end
end
class InvalidToken < RuntimeError; end
class CannotAccessContext < RuntimeError; end

View file

@ -1,150 +0,0 @@
class ContextsController < ApplicationController
helper :todos
before_filter :init, :except => [:create, :destroy, :order]
before_filter :init_todos, :only => :show
before_filter :set_context_from_params, :only => [:update, :destroy]
skip_before_filter :login_required, :only => [:index]
prepend_before_filter :login_or_feed_token_required, :only => [:index]
session :off, :only => :index, :if => Proc.new { |req| ['rss','atom','txt'].include?(req.parameters[:format]) }
def index
respond_to do |format|
format.html &render_contexts_html
format.xml { render :xml => @contexts.to_xml( :except => :user_id ) }
format.rss &render_contexts_rss_feed
format.atom &render_contexts_atom_feed
format.text { render :action => 'index_text', :layout => false, :content_type => Mime::TEXT }
end
end
def show
@page_title = "TRACKS::Context: #{@context.name}"
end
# Example XML usage: curl -H 'Accept: application/xml' -H 'Content-Type: application/xml'
# -u username:password
# -d '<request><context><name>new context_name</name></context></request>'
# http://our.tracks.host/contexts
#
def create
if params[:format] == 'application/xml' && params['exception']
render_failure "Expected post format is valid xml like so: <request><context><name>context name</name></context></request>."
return
end
@context = @user.contexts.build
params_are_invalid = true
if (params['context'] || (params['request'] && params['request']['context']))
@context.attributes = params['context'] || params['request']['context']
params_are_invalid = false
end
@saved = @context.save
@context_not_done_counts = { @context.id => 0 }
respond_to do |wants|
wants.js
wants.xml do
if @context.new_record? && params_are_invalid
render_failure "Expected post format is valid xml like so: <request><context><name>context name</name></context></request>."
elsif @context.new_record?
render_failure @context.errors.to_xml
else
render :xml => @context.to_xml( :except => :user_id )
end
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']
end
@context.attributes = params["context"]
if @context.save
if params['wants_render']
render
else
render :text => success_text || 'Success'
end
else
notify :warning, "Couldn't update new context"
render :text => ""
end
end
# Fairly self-explanatory; deletes the context
# If the context contains actions, you'll get a warning dialogue.
# If you choose to go ahead, any actions in the context will also be deleted.
def destroy
@context.destroy
respond_to do |format|
format.js
format.xml { render :text => "Deleted context #{@context.name}" }
end
end
# Methods for changing the sort order of the contexts in the list
#
def order
params["list-contexts"].each_with_index do |id, position|
@user.contexts.update(id, :position => position + 1)
end
render :nothing => true
end
protected
def render_contexts_html
lambda do
@page_title = "TRACKS::List Contexts"
@no_contexts = @contexts.empty?
render
end
end
def render_contexts_rss_feed
lambda do
render_rss_feed_for @contexts, :feed => Context.feed_options(@user),
:item => { :description => lambda { |c| c.summary(count_undone_todos_phrase(c)) } }
end
end
def render_contexts_atom_feed
lambda do
render_atom_feed_for @contexts, :feed => Context.feed_options(@user),
:item => { :description => lambda { |c| c.summary(count_undone_todos_phrase(c)) },
:author => lambda { |c| nil } }
end
end
def set_context_from_params
@context = @user.contexts.find_by_params(params)
end
def init
@source_view = params['_source_view'] || 'context'
# If we exclude completed projects, then we can't display them in the sidebar
# if the user sets the preference for them to be shown
# @projects = @user.projects.reject { |x| x.completed? }
init_data_for_sidebar
@todos = @user.todos
@done = @user.todos.find_in_state(:all, :completed, :order => "todos.completed_at DESC")
end
def init_todos
set_context_from_params
@done = @context.done_todos
# @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 = ?', 'active'], :order => "todos.due IS NULL, todos.due ASC, todos.created_at ASC", :include => :project)
@count = @not_done_todos.size
@default_project_context_name_map = build_default_project_context_name_map(@projects).to_json
end
end

View file

@ -1,87 +0,0 @@
class DataController < ApplicationController
require 'csv'
def index
end
def import
end
def export
# Show list of formats for export
end
# Thanks to a tip by Gleb Arshinov
# <http://lists.rubyonrails.org/pipermail/rails/2004-November/000199.html>
def yaml_export
all_tables = {}
all_tables['todos'] = @user.todos.find(:all)
all_tables['contexts'] = @user.contexts.find(:all)
all_tables['projects'] = @user.projects.find(:all)
all_tables['notes'] = @user.notes.find(:all)
result = all_tables.to_yaml
result.gsub!(/\n/, "\r\n") # TODO: general functionality for line endings
send_data(result, :filename => "tracks_backup.yml", :type => 'text/plain')
end
def csv_actions
content_type = 'text/csv'
CSV::Writer.generate(result = "") do |csv|
csv << ["ID", "Context", "Project", "Description", "Notes",
"Created at", "Due", "Completed at", "User ID", "Show from",
"state"]
@user.todos.find(:all, :include => [:context, :project]).each do |todo|
# Format dates in ISO format for easy sorting in spreadsheet
# Print context and project names for easy viewing
csv << [todo.id, todo.context.name,
todo.project_id = todo.project_id.nil? ? "" : todo.project.name,
todo.description,
todo.notes, todo.created_at.to_formatted_s(:db),
todo.due = todo.due? ? todo.due.to_formatted_s(:db) : "",
todo.completed_at = todo.completed_at? ? todo.completed_at.to_formatted_s(:db) : "",
todo.user_id,
todo.show_from = todo.show_from? ? todo.show_from.to_formatted_s(:db) : "",
todo.state]
end
end
send_data(result, :filename => "todos.csv", :type => content_type)
end
def csv_notes
content_type = 'text/csv'
CSV::Writer.generate(result = "") do |csv|
csv << ["ID", "User ID", "Project", "Note",
"Created at", "Updated at"]
@user.notes.find(:all, :include => [:project]).each do |note|
# Format dates in ISO format for easy sorting in spreadsheet
# Print context and project names for easy viewing
csv << [note.id, note.user_id,
note.project_id = note.project_id.nil? ? "" : note.project.name,
note.body, note.created_at.to_formatted_s(:db),
note.updated_at.to_formatted_s(:db)]
end
end
send_data(result, :filename => "notes.csv", :type => content_type)
end
def xml_export
result = ""
result << @user.todos.find(:all).to_xml
result << @user.contexts.find(:all).to_xml(:skip_instruct => true)
result << @user.projects.find(:all).to_xml(:skip_instruct => true)
result << @user.notes.find(:all).to_xml(:skip_instruct => true)
send_data(result, :filename => "tracks_backup.xml", :type => 'text/xml')
end
def yaml_form
# Draw the form to input the YAML text data
end
def yaml_import
# Logic to load the YAML text file and create new records from data
end
end

View file

@ -1,11 +0,0 @@
class FeedlistController < ApplicationController
helper :feedlist
def index
@page_title = 'TRACKS::Feeds'
init_data_for_sidebar
render :layout => 'standard'
end
end

View file

@ -1,129 +0,0 @@
class LoginController < ApplicationController
layout 'login'
skip_before_filter :set_session_expiration
skip_before_filter :login_required
before_filter :get_current_user
open_id_consumer if Tracks::Config.openid_enabled?
def login
@page_title = "TRACKS::Login"
@openid_url = cookies[:openid_url] if Tracks::Config.openid_enabled?
case request.method
when :post
if @user = User.authenticate(params['user_login'], params['user_password'])
session['user_id'] = @user.id
# If checkbox on login page checked, we don't expire the session after 1 hour
# of inactivity
session['noexpiry'] = params['user_noexpiry']
msg = (should_expire_sessions?) ? "will expire after 1 hour of inactivity." : "will not expire."
notify :notice, "Login successful: session #{msg}"
cookies[:tracks_login] = { :value => @user.login, :expires => Time.now + 1.year }
redirect_back_or_home
else
@login = params['user_login']
notify :warning, "Login unsuccessful"
end
when :get
if User.no_users_yet?
redirect_to :controller => 'users', :action => 'new'
end
end
end
def begin
# If the URL was unusable (either because of network conditions,
# a server error, or that the response returned was not an OpenID
# identity page), the library will return HTTP_FAILURE or PARSE_ERROR.
# Let the user know that the URL is unusable.
case open_id_response.status
when OpenID::SUCCESS
session['openid_url'] = params[:openid_url]
session['user_noexpiry'] = params[:user_noexpiry]
# The URL was a valid identity URL. Now we just need to send a redirect
# to the server using the redirect_url the library created for us.
# redirect to the server
redirect_to open_id_response.redirect_url((request.protocol + request.host_with_port + "/"), url_for(:action => 'complete'))
else
notify :warning, "Unable to find openid server for <q>#{openid_url}</q>"
redirect_to :action => 'login'
end
end
def complete
openid_url = session['openid_url']
if openid_url.blank?
notify :error, "expected an openid_url"
end
case open_id_response.status
when OpenID::FAILURE
# In the case of failure, if info is non-nil, it is the
# URL that we were verifying. We include it in the error
# message to help the user figure out what happened.
if open_id_response.identity_url
msg = "Verification of #{openid_url}(#{open_id_response.identity_url}) failed. "
else
msg = "Verification failed. "
end
notify :error, open_id_response.msg.to_s + msg
when OpenID::SUCCESS
# Success means that the transaction completed without
# error. If info is nil, it means that the user cancelled
# the verification.
@user = User.find_by_open_id_url(openid_url)
unless (@user.nil?)
session['user_id'] = @user.id
session['noexpiry'] = session['user_noexpiry']
msg = (should_expire_sessions?) ? "will expire after 1 hour of inactivity." : "will not expire."
notify :notice, "You have successfully verified #{openid_url} as your identity. Login successful: session #{msg}"
cookies[:tracks_login] = { :value => @user.login, :expires => Time.now + 1.year }
cookies[:openid_url] = { :value => openid_url, :expires => Time.now + 1.year }
redirect_back_or_home
else
notify :warning, "You have successfully verified #{openid_url} as your identity, but you do not have a Tracks account. Please ask your administrator to sign you up."
end
when OpenID::CANCEL
notify :warning, "Verification cancelled."
else
notify :warning, "Unknown response status: #{open_id_response.status}"
end
redirect_to :action => 'login' unless performed?
end
def logout
session['user_id'] = nil
reset_session
notify :notice, "You have been logged out of Tracks."
redirect_to :action => "login"
end
def check_expiry
# Gets called by periodically_call_remote to check whether
# the session has timed out yet
unless session == nil
if session
return unless should_expire_sessions?
# Get expiry time (allow ten seconds window for the case where we have none)
expiry_time = session['expiry_time'] || Time.now + 10
@time_left = expiry_time - Time.now
if @time_left < (10*60) # Session will time out before the next check
@msg = "Session has timed out. Please "
else
@msg = ""
end
end
end
end
private
def should_expire_sessions?
session['noexpiry'] != "on"
end
end

View file

@ -1,89 +0,0 @@
class MobileController < ApplicationController
layout 'mobile'
before_filter :init, :except => :update
# Plain list of all next actions, paginated 6 per page
# Sorted by due date, then creation date
#
def index
@page_title = @desc = "All actions"
@todos_pages, @todos = paginate( :todos, :order => 'due IS NULL, due ASC, created_at ASC',
:conditions => ['user_id = ? and state = ?', @user.id, "active"],
:per_page => 6 )
@count = @all_todos.reject { |x| !x.active? || x.context.hide? }.size
end
def detail
@item = check_user_return_item
@place = @item.context.id
end
def update
if params[:id]
@item = check_user_return_item
@item.update_attributes params[:todo]
if params[:todo][:state] == "1"
@item.state = "completed"
else
@item.state = "active"
end
else
params[:todo][:user_id] = @user.id
@item = Todo.new(params[:todo]) if params[:todo]
end
if @item.save
redirect_to :action => 'index'
else
self.init
if params[:id]
render :partial => 'mobile_edit'
else
render :action => 'show_add_form'
end
end
end
def show_add_form
# Just render the view
end
def filter
@type = params[:type]
case params[:type]
when 'context'
@context = Context.find( params[:context][:id] )
@page_title = @desc = "#{@context.name}"
@todos = Todo.find( :all, :order => 'due IS NULL, due ASC, created_at ASC',
:conditions => ['user_id = ? and state = ? and context_id = ?', @user.id, "active", @context.id] )
@count = @all_todos.reject { |x| x.completed? || x.context_id != @context.id }.size
when 'project'
@project = Project.find( params[:project][:id] )
@page_title = @desc = "#{@project.name}"
@todos = Todo.find( :all, :order => 'due IS NULL, due ASC, created_at ASC',
:conditions => ['user_id = ? and state = ? and project_id = ?', @user.id, "active", @project.id] )
@count = @all_todos.reject { |x| x.completed? || x.project_id != @project.id }.size
end
end
protected
def check_user_return_item
item = Todo.find( params['id'] )
if @user == item.user
return item
else
notify :warning, "Item and session user mis-match: #{item.user.name} and #{@user.name}!"
render_text ""
end
end
def init
@contexts = @user.contexts.find(:all, :order => 'position ASC')
@projects = @user.projects.find_in_state(:all, :active, :order => 'position ASC')
@all_todos = @user.todos.find(:all, :conditions => ['state = ? or state = ?', "active", "completed"])
end
end

View file

@ -1,61 +0,0 @@
class NotesController < ApplicationController
def index
@all_notes = @user.notes
@page_title = "TRACKS::All notes"
respond_to do |wants|
wants.html
wants.xml { render :xml => @all_notes.to_xml( :except => :user_id ) }
end
end
def show
@note = check_user_return_note
@page_title = "TRACKS::Note " + @note.id.to_s
end
# Add a new note to this project
#
def create
note = @user.notes.build
note.attributes = params["new_note"]
if note.save
render :partial => 'notes_summary', :object => note
else
render :text => ''
end
end
def destroy
note = check_user_return_note
if note.destroy
render :text => ''
else
notify :warning, "Couldn't delete note \"#{note.id.to_s}\""
render :text => ''
end
end
def update
note = check_user_return_note
note.attributes = params["note"]
if note.save
render :partial => 'notes', :object => note
else
notify :warning, "Couldn't update note \"#{note.id.to_s}\""
render :text => ''
end
end
protected
def check_user_return_note
note = Note.find_by_id( params['id'] )
if @user == note.user
return note
else
render :text => ''
end
end
end

View file

@ -1,25 +0,0 @@
class PreferencesController < ApplicationController
def index
@page_title = "TRACKS::Preferences"
@prefs = @user.preference
end
def edit
@page_title = "TRACKS::Edit Preferences"
@prefs = @user.preference
render :object => @prefs
end
def update
user_success = @user.update_attributes(params['user'])
prefs_success = @user.preference.update_attributes(params['prefs'])
if user_success && prefs_success
redirect_to :action => 'index'
else
render :action => 'edit'
end
end
end

View file

@ -1,204 +0,0 @@
class ProjectsController < ApplicationController
helper :application, :todos, :notes
before_filter :init, :except => [:create, :destroy, :order]
before_filter :set_project_from_params, :only => [:update, :destroy, :show]
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]
session :off, :only => :index, :if => Proc.new { |req| ['rss','atom','txt'].include?(req.parameters[:format]) }
def index
if params[:only_active_with_no_next_actions]
@projects = @projects.select { |p| p.active? && count_undone_todos(p) == 0 }
end
respond_to do |format|
format.html &render_projects_html
format.xml { render :xml => @projects.to_xml( :except => :user_id ) }
format.rss &render_rss_feed
format.atom &render_atom_feed
format.text &render_text_feed
end
end
def show
@page_title = "TRACKS::Project: #{@project.name}"
@not_done = @project.not_done_todos(:include_project_hidden_todos => true)
@deferred = @project.deferred_todos
@done = @project.done_todos
@count = @not_done.size
@next_project = @user.projects.next_from(@project)
@previous_project = @user.projects.previous_from(@project)
@default_project_context_name_map = build_default_project_context_name_map(@projects).to_json
end
# Example XML usage: curl -H 'Accept: application/xml' -H 'Content-Type: application/xml'
# -u username:password
# -d '<request><project><name>new project_name</name></project></request>'
# http://our.tracks.host/projects
#
def create
if params[:format] == 'application/xml' && params['exception']
render_failure "Expected post format is valid xml like so: <request><project><name>project name</name></project></request>."
return
end
@project = @user.projects.build
params_are_invalid = true
if (params['project'] || (params['request'] && params['request']['project']))
@project.attributes = params['project'] || params['request']['project']
params_are_invalid = false
end
@go_to_project = params['go_to_project']
@saved = @project.save
@project_not_done_counts = { @project.id => 0 }
@active_projects_count = @user.projects.count(:conditions => "state = 'active'")
@contexts = @user.contexts
respond_to do |wants|
wants.js
wants.xml do
if @project.new_record? && params_are_invalid
render_failure "Expected post format is valid xml like so: <request><project><name>project name</name></project></request>."
elsif @project.new_record?
render_failure @project.errors.full_messages.join(', ')
else
render :xml => @project.to_xml( :except => :user_id )
end
end
end
end
# Edit the details of the project
#
def update
params['project'] ||= {}
if params['project']['state']
@state_changed = @project.state != params['project']['state']
logger.info "@state_changed: #{@project.state} == #{params['project']['state']} != #{@state_changed}"
@project.transition_to(params['project']['state'])
params['project'].delete('state')
end
success_text = if params['field'] == 'name' && params['value']
params['project']['id'] = params['id']
params['project']['name'] = params['value']
end
@project.attributes = params['project']
if @project.save
if boolean_param('wants_render')
if (@project.hidden?)
@project_project_hidden_todo_counts = Hash.new
@project_project_hidden_todo_counts[@project.id] = @project.reload().not_done_todo_count(:include_project_hidden_todos => true)
else
@project_not_done_counts[@project.id] = @project.reload().not_done_todo_count(:include_project_hidden_todos => true)
end
@active_projects_count = @user.projects.count(:conditions => "state = 'active'")
@hidden_projects_count = @user.projects.count(:conditions => "state = 'hidden'")
@completed_projects_count = @user.projects.count(:conditions => "state = 'completed'")
render
elsif boolean_param('update_status')
render :action => 'update_status'
elsif boolean_param('update_default_context')
render :action => 'update_default_context'
else
render :text => success_text || 'Success'
end
else
notify :warning, "Couldn't update project"
render :text => ''
end
end
def destroy
@project.destroy
@active_projects_count = @user.projects.count(:conditions => "state = 'active'")
@hidden_projects_count = @user.projects.count(:conditions => "state = 'hidden'")
@completed_projects_count = @user.projects.count(:conditions => "state = 'completed'")
respond_to do |format|
format.js
format.xml { render :text => "Deleted project #{@project.name}" }
end
end
def order
project_ids = params["list-active-projects"] || params["list-hidden-projects"] || params["list-completed-projects"]
projects = @user.projects.update_positions( project_ids )
render :nothing => true
rescue
notify :error, $!
redirect_to :action => 'index'
end
protected
def render_projects_html
lambda do
init_project_hidden_todo_counts
@page_title = "TRACKS::List Projects"
@active_projects = @projects.select{ |p| p.active? }
@hidden_projects = @projects.select{ |p| p.hidden? }
@completed_projects = @projects.select{ |p| p.completed? }
@no_projects = @projects.empty?
@projects.cache_note_counts
@new_project = @user.projects.build
render
end
end
def render_rss_feed
lambda do
render_rss_feed_for @projects, :feed => Project.feed_options(@user),
:item => { :title => :name, :description => lambda { |p| summary(p) } }
end
end
def render_atom_feed
lambda do
render_atom_feed_for @projects, :feed => Project.feed_options(@user),
:item => { :description => lambda { |p| summary(p) },
:title => :name,
:author => lambda { |p| nil } }
end
end
def render_text_feed
lambda do
init_project_hidden_todo_counts(['project'])
render :action => 'index_text', :layout => false, :content_type => Mime::TEXT
end
end
def set_project_from_params
@project = @user.projects.find_by_params(params)
end
def init
@source_view = params['_source_view'] || 'project'
@projects = @user.projects
@contexts = @user.contexts
@todos = @user.todos
@done = @user.todos.find_in_state(:all, :completed, :order => "completed_at DESC")
init_data_for_sidebar
end
def default_context_filter
p = params['project']
p = params['request']['project'] if p.nil? && params['request']
p = {} if p.nil?
default_context_name = p['default_context_name']
p.delete('default_context_name')
unless default_context_name.blank?
default_context = Context.find_or_create_by_name(default_context_name)
p['default_context_id'] = default_context.id
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 += "Project is #{project.state}."
project_description += "</p>"
project_description
end
end

View file

@ -1,490 +0,0 @@
class TodosController < ApplicationController
helper :todos
append_before_filter :init, :except => [ :destroy, :completed, :completed_archive, :check_deferred ]
append_before_filter :get_todo_from_params, :only => [ :edit, :toggle_check, :show, :update, :destroy ]
skip_before_filter :login_required, :only => [:index]
prepend_before_filter :login_or_feed_token_required, :only => [:index]
session :off, :only => :index, :if => Proc.new { |req| is_feed_request(req) }
layout 'standard'
def index
@projects = @user.projects.find(:all, :include => [ :todos ])
@contexts = @user.contexts.find(:all, :include => [ :todos ])
@contexts_to_show = @contexts.reject {|x| x.hide? }
respond_to do |format|
format.html &render_todos_html
format.xml { render :action => 'list.rxml', :layout => false }
format.rss &render_rss_feed
format.atom &render_atom_feed
format.text &render_text_feed
format.ics &render_ical_feed
end
end
def create
@todo = @user.todos.build
p = params['request'] || params
if p['todo']['show_from']
p['todo']['show_from'] = parse_date_per_user_prefs(p['todo']['show_from'])
end
@todo.attributes = p['todo']
if p['todo']['project_id'].blank? && !p['project_name'].blank? && p['project_name'] != 'None'
project = @user.projects.find_by_name(p['project_name'].strip)
unless project
project = @user.projects.build
project.name = p['project_name'].strip
project.save
@new_project_created = true
end
@todo.project_id = project.id
end
if p['todo']['context_id'].blank? && !p['context_name'].blank?
context = @user.contexts.find_by_name(p['context_name'].strip)
unless context
context = @user.contexts.build
context.name = p['context_name'].strip
context.save
@new_context_created = true
@not_done_todos = [@todo]
end
@todo.context_id = context.id
end
if @todo.due?
@todo.due = parse_date_per_user_prefs(p['todo']['due'])
else
@todo.due = ""
end
@saved = @todo.save
if @saved
@todo.tag_with(params[:tag_list],@user)
@todo.reload
end
respond_to do |wants|
wants.html { redirect_to :action => "index" }
wants.js do
if @saved
determine_down_count
end
render :action => 'create'
end
wants.xml { render :xml => @todo.to_xml( :root => 'todo', :except => :user_id ) }
end
end
def edit
end
def show
respond_to do |format|
format.xml { render :xml => @todo.to_xml( :root => 'todo', :except => :user_id ) }
end
end
# Toggles the 'done' status of the action
#
def toggle_check
@todo.toggle_completion!
@saved = @todo.save
respond_to do |format|
format.js do
if @saved
@remaining_undone_in_context = @user.contexts.find(@todo.context_id).not_done_todo_count
determine_down_count
determine_completed_count
end
render
end
format.html do
if @saved
# TODO: I think this will work, but can't figure out how to test it
notify :notice, "The action <strong>'#{@todo.description}'</strong> was marked as <strong>#{@todo.completed? ? 'complete' : 'incomplete' }</strong>"
redirect_to :action => "index"
else
notify :notice, "The action <strong>'#{@todo.description}'</strong> was NOT marked as <strong>#{@todo.completed? ? 'complete' : 'incomplete' } due to an error on the server.</strong>", "index"
redirect_to :action => "index"
end
end
end
end
def update
@todo.tag_with(params[:tag_list],@user)
@original_item_context_id = @todo.context_id
@original_item_project_id = @todo.project_id
@original_item_was_deferred = @todo.deferred?
if params['todo']['project_id'].blank? && !params['project_name'].nil?
if params['project_name'] == 'None'
project = Project.null_object
else
project = @user.projects.find_by_name(params['project_name'].strip)
unless project
project = @user.projects.build
project.name = params['project_name'].strip
project.save
@new_project_created = true
end
end
params["todo"]["project_id"] = project.id
end
if params['todo']['context_id'].blank? && !params['context_name'].blank?
context = @user.contexts.find_by_name(params['context_name'].strip)
unless context
context = @user.contexts.build
context.name = params['context_name'].strip
context.save
@new_context_created = true
end
params["todo"]["context_id"] = context.id
end
if params["todo"].has_key?("due")
params["todo"]["due"] = parse_date_per_user_prefs(params["todo"]["due"])
else
params["todo"]["due"] = ""
end
if params['todo']['show_from']
params['todo']['show_from'] = parse_date_per_user_prefs(params['todo']['show_from'])
end
@saved = @todo.update_attributes params["todo"]
@context_changed = @original_item_context_id != @todo.context_id
@todo_was_activated_from_deferred_state = @original_item_was_deferred && @todo.active?
if @context_changed then @remaining_undone_in_context = @user.contexts.find(@original_item_context_id).not_done_todo_count; end
@project_changed = @original_item_project_id != @todo.project_id
if (@project_changed && !@original_item_project_id.nil?) then @remaining_undone_in_project = @user.projects.find(@original_item_project_id).not_done_todo_count; end
determine_down_count
end
def destroy
@todo = get_todo_from_params
@context_id = @todo.context_id
@project_id = @todo.project_id
@saved = @todo.destroy
respond_to do |wants|
wants.html do
if @saved
notify :notice, "Successfully deleted next action", 2.0
redirect_to :action => 'index'
else
notify :error, "Failed to delete the action", 2.0
redirect_to :action => 'index'
end
end
wants.js do
if @saved
determine_down_count
source_view do |from|
from.todo do
@remaining_undone_in_context = @user.contexts.find(@context_id).not_done_todo_count
end
end
end
render
end
wants.xml { render :text => '200 OK. Action deleted.', :status => 200 }
end
end
def completed
@page_title = "TRACKS::Completed tasks"
@done = @user.completed_todos
@done_today = @done.completed_within @user.time - 1.day
@done_this_week = @done.completed_within @user.time - 1.week
@done_this_month = @done.completed_within @user.time - 4.week
end
def completed_archive
@page_title = "TRACKS::Archived completed tasks"
@done = @user.completed_todos
@done_archive = @done.completed_more_than @user.time - 28.days
end
def list_deferred
@source_view = 'deferred'
@page_title = "TRACKS::Tickler"
@tickles = @user.deferred_todos
@count = @tickles.size
@default_project_context_name_map = build_default_project_context_name_map(@projects).to_json
end
# Check for any due tickler items, activate them
# Called by periodically_call_remote
def check_deferred
@due_tickles = @user.deferred_todos.find_and_activate_ready
respond_to do |format|
format.html { redirect_to home_path }
format.js
end
end
# /todos/tag/[tag_name] shows all the actions tagged with tag_name
#
def tag
@tag = tag_name = params[:name]
if Tag.find_by_name(tag_name).nil?
# TODO: This doesn't work - you get kicked back to the index
# with a generic "Error occured on the server error"
notify :error, "Tag \'#{@tag}\' does not exist", 2.0
@not_done_todos = []
else
tag_collection = Tag.find_by_name(tag_name).todos
@not_done_todos = tag_collection.find(:all, :conditions => ['taggings.user_id = ? and state = ?', @user.id, 'active'])
end
@contexts = @user.contexts.find(:all, :include => [ :todos ])
@contexts_to_show = @contexts.reject {|x| x.hide? }
@page_title = "TRACKS::Tagged with \'#{@tag}\'"
# If you've set no_completed to zero, the completed items box
# isn't shown on the home page
max_completed = @user.prefs.show_number_completed
@done = @user.completed_todos.find(:all, :limit => max_completed, :include => [ :context, :project, :tags ]) unless max_completed == 0
# Set count badge to number of items with this tag
@not_done_todos.empty? ? @count = 0 : @count = @not_done_todos.size
@default_project_context_name_map = build_default_project_context_name_map(@projects).to_json
end
private
def get_todo_from_params
@todo = @user.todos.find(params['id'])
end
def init
@source_view = params['_source_view'] || 'todo'
init_data_for_sidebar
init_todos
end
def with_feed_query_scope(&block)
unless TodosController.is_feed_request(request)
yield
return
end
condition_builder = FindConditionBuilder.new
options = Hash.new
if params.key?('done')
condition_builder.add 'todos.state = ?', 'completed'
else
condition_builder.add 'todos.state = ?', 'active'
end
@title = "Tracks - Next Actions"
@description = "Filter: "
if params.key?('due')
due_within = params['due'].to_i
due_within_when = @user.time + due_within.days
condition_builder.add('todos.due <= ?', due_within_when)
due_within_date_s = due_within_when.strftime("%Y-%m-%d")
@title << " due today" if (due_within == 0)
@title << " due within a week" if (due_within == 6)
@description << " with a due date #{due_within_date_s} or earlier"
end
if params.key?('done')
done_in_last = params['done'].to_i
condition_builder.add('todos.completed_at >= ?', @user.time - done_in_last.days)
@title << " actions completed"
@description << " in the last #{done_in_last.to_s} days"
end
Todo.with_scope :find => {:conditions => condition_builder.to_conditions} do
yield
end
end
def with_parent_resource_scope(&block)
if (params[:context_id])
context = @user.contexts.find_by_params(params)
Todo.with_scope :find => {:conditions => ['todos.context_id = ?', context.id]} do
yield
end
elsif (params[:project_id])
project = @user.projects.find_by_params(params)
Todo.with_scope :find => {:conditions => ['todos.project_id = ?', project.id]} do
yield
end
else
yield
end
end
def with_limit_scope(&block)
if params.key?('limit')
Todo.with_scope :find => {:limit => params['limit']} do
yield
end
#@description = limit ? "Lists the last #{limit} incomplete next actions" : "Lists incomplete next actions"
else
yield
end
end
def init_todos
with_feed_query_scope do
with_parent_resource_scope do
with_limit_scope do
# Exclude hidden projects from count on home page
@todos = @user.todos.find(:all, :conditions => ['todos.state = ? or todos.state = ?', 'active', 'complete'], :include => [ :project, :context, :tags ])
# Exclude hidden projects from the home page
@not_done_todos = @user.todos.find(:all, :conditions => ['todos.state = ?', 'active'], :order => "todos.due IS NULL, todos.due ASC, todos.created_at ASC", :include => [ :project, :context, :tags ])
end
end
end
end
def determine_down_count
source_view do |from|
from.todo do
@down_count = Todo.count_by_sql(['SELECT COUNT(*) FROM todos, contexts WHERE todos.context_id = contexts.id and todos.user_id = ? and todos.state = ? and contexts.hide = ?', @user.id, 'active', false])
end
from.context do
@down_count = @user.contexts.find(@todo.context_id).not_done_todo_count
end
from.project do
unless @todo.project_id == nil
@down_count = @user.projects.find(@todo.project_id).not_done_todo_count
@deferred_count = @user.projects.find(@todo.project_id).deferred_todo_count
end
end
from.deferred do
@down_count = @user.todos.count_in_state(:deferred)
end
end
end
def determine_completed_count
source_view do |from|
from.todo do
@completed_count = Todo.count_by_sql(['SELECT COUNT(*) FROM todos, contexts WHERE todos.context_id = contexts.id and todos.user_id = ? and todos.state = ? and contexts.hide = ?', @user.id, 'completed', false])
end
from.context do
@completed_count = @user.contexts.find(@todo.context_id).done_todo_count
end
from.project do
unless @todo.project_id == nil
@completed_count = @user.projects.find(@todo.project_id).done_todo_count
end
end
end
end
def render_todos_html
lambda do
@page_title = "TRACKS::List tasks"
# If you've set no_completed to zero, the completed items box
# isn't shown on the home page
max_completed = @user.prefs.show_number_completed
@done = @user.completed_todos.find(:all, :limit => max_completed, :include => [ :context, :project, :tags ]) unless max_completed == 0
# Set count badge to number of not-done, not hidden context items
@count = @todos.reject { |x| !x.active? || x.context.hide? }.size
@default_project_context_name_map = build_default_project_context_name_map(@projects).to_json
render
end
end
def render_rss_feed
lambda do
render_rss_feed_for @todos, :feed => Todo.feed_options(@user),
:item => {
:title => :description,
:link => lambda { |t| context_url(t.context) },
:description => todo_feed_content
}
end
end
def todo_feed_content
lambda do |i|
item_notes = sanitize(markdown( i.notes )) if i.notes?
due = "<div>Due: #{format_date(i.due)}</div>\n" if i.due?
done = "<div>Completed: #{format_date(i.completed_at)}</div>\n" if i.completed?
context_link = "<a href=\"#{ context_url(i.context) }\">#{ i.context.name }</a>"
if i.project_id?
project_link = "<a href=\"#{ project_url(i.project) }\">#{ i.project.name }</a>"
else
project_link = "<em>none</em>"
end
"#{done||''}#{due||''}#{item_notes||''}\n<div>Project: #{project_link}</div>\n<div>Context: #{context_link}</div>"
end
end
def render_atom_feed
lambda do
render_atom_feed_for @todos, :feed => Todo.feed_options(@user),
:item => {
:title => :description,
:link => lambda { |t| context_url(t.context) },
:description => todo_feed_content,
:author => lambda { |p| nil }
}
end
end
def render_text_feed
lambda do
render :action => 'index_text', :layout => false, :content_type => Mime::TEXT
end
end
def render_ical_feed
lambda do
render :action => 'index_ical', :layout => false, :content_type => Mime::ICS
end
end
def self.is_feed_request(req)
['rss','atom','txt','ics'].include?(req.parameters[:format])
end
class FindConditionBuilder
def initialize
@queries = Array.new
@params = Array.new
end
def add(query, param)
@queries << query
@params << param
end
def to_conditions
[@queries.join(' AND ')] + @params
end
end
end

View file

@ -1,251 +0,0 @@
class UsersController < ApplicationController
if Tracks::Config.openid_enabled?
open_id_consumer
before_filter :begin_open_id_auth, :only => :update_auth_type
end
before_filter :admin_login_required, :only => [ :index, :show, :destroy ]
skip_before_filter :login_required, :only => [ :new, :create ]
prepend_before_filter :login_optional, :only => [ :new, :create ]
# 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"
@user_pages, @users = paginate :users, :order => 'login ASC', :per_page => 10
@total_users = User.count
# When we call users/signup from the admin page
# we store the URL so that we get returned here when signup is successful
store_location
end
format.xml { render :xml => @users.to_xml(:except => [ :password ]) }
end
end
# GET /users/somelogin
# GET /users/somelogin.xml
def show
@user = User.find_by_login(params[:id])
render :xml => @user.to_xml(:except => [ :password ])
end
# GET /users/new
def new
if User.no_users_yet?
@page_title = "TRACKS::Sign up as the admin user"
@heading = "Welcome to TRACKS. To get started, please create an admin account:"
@user = get_new_user
elsif @user && @user.is_admin?
@page_title = "TRACKS::Sign up a new user"
@heading = "Sign up a new user:"
@user = get_new_user
else # all other situations (i.e. a non-admin is logged in, or no one is logged in, but we have some users)
@page_title = "TRACKS::No signups"
@admin_email = User.find_admin.preference.admin_email
render :action => "nosignup", :layout => "login"
return
end
render :layout => "login"
end
# Example usage: curl -H 'Accept: application/xml' -H 'Content-Type: application/xml'
# -u admin:up2n0g00d
# -d '<request><login>username</login><password>abc123</password></request>'
# http://our.tracks.host/users
#
# POST /users
# POST /users.xml
def create
if params['exception']
render_failure "Expected post format is valid xml like so: <request><login>username</login><password>abc123</password></request>."
return
end
respond_to do |format|
format.html do
unless User.no_users_yet? || (@user && @user.is_admin?)
@page_title = "No signups"
@admin_email = User.find_admin.preference.admin_email
render :action => "nosignup", :layout => "login"
return
end
user = User.new(params['user'])
unless user.valid?
session['new_user'] = user
redirect_to :action => 'new'
return
end
first_user_signing_up = User.no_users_yet?
user.is_admin = true if first_user_signing_up
if user.save
@user = User.authenticate(user.login, params['user']['password'])
@user.create_preference
@user.save
session['user_id'] = @user.id if first_user_signing_up
notify :notice, "Signup successful for user #{@user.login}."
redirect_back_or_home
end
return
end
format.xml do
unless User.find_by_id_and_is_admin(session['user_id'], true)
render :text => "401 Unauthorized: Only admin users are allowed access to this function.", :status => 401
return
end
unless check_create_user_params
render_failure "Expected post format is valid xml like so: <request><login>username</login><password>abc123</password></request>."
return
end
user = User.new(params[:request])
user.password_confirmation = params[:request][:password]
if user.save
render :text => "User created.", :status => 200
else
render_failure user.errors.to_xml
end
return
end
end
end
# DELETE /users/somelogin
# DELETE /users/somelogin.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
notify :notice, "Successfully deleted user #{@deleted_user.login}", 2.0
else
notify :error, "Failed to delete user #{@deleted_user.login}", 2.0
end
redirect_to users_url
end
format.js
format.xml { head :ok }
end
end
def change_password
@page_title = "TRACKS::Change password"
end
def update_password
@user.change_password(params[:updateuser][:password], params[:updateuser][:password_confirmation])
notify :notice, "Password updated."
redirect_to :controller => 'preferences'
rescue Exception => error
notify :error, error.message
redirect_to :action => 'change_password'
end
def change_auth_type
@page_title = "TRACKS::Change authentication type"
end
def update_auth_type
if (params[:user][:auth_type] == 'open_id') && Tracks::Config.openid_enabled?
case open_id_response.status
when OpenID::SUCCESS
# The URL was a valid identity URL. Now we just need to send a redirect
# to the server using the redirect_url the library created for us.
session['openid_url'] = params[:openid_url]
# redirect to the server
redirect_to open_id_response.redirect_url((request.protocol + request.host_with_port + "/"), url_for(:action => 'complete'))
else
notify :warning, "Unable to find openid server for <q>#{openid_url}</q>"
redirect_to :action => 'change_auth_type'
end
return
end
@user.auth_type = params[:user][:auth_type]
if @user.save
notify :notice, "Authentication type updated."
redirect_to :controller => 'preferences'
else
notify :warning, "There was a problem updating your authentication type: #{ @user.errors.full_messages.join(', ')}"
redirect_to :action => 'change_auth_type'
end
end
def complete
return unless Tracks::Config.openid_enabled?
openid_url = session['openid_url']
if openid_url.blank?
notify :error, "expected an openid_url"
end
case open_id_response.status
when OpenID::FAILURE
# In the case of failure, if info is non-nil, it is the
# URL that we were verifying. We include it in the error
# message to help the user figure out what happened.
if open_id_response.identity_url
msg = "Verification of #{openid_url}(#{open_id_response.identity_url}) failed. "
else
msg = "Verification failed. "
end
notify :error, open_id_response.msg.to_s + msg
when OpenID::SUCCESS
# Success means that the transaction completed without
# error. If info is nil, it means that the user cancelled
# the verification.
@user.auth_type = 'open_id'
@user.open_id_url = openid_url
if @user.save
notify :notice, "You have successfully verified #{openid_url} as your identity and set your authentication type to Open ID."
else
notify :warning, "You have successfully verified #{openid_url} as your identity but there was a problem saving your authentication preferences."
end
redirect_to :controller => 'preferences', :action => 'index'
when OpenID::CANCEL
notify :warning, "Verification cancelled."
else
notify :warning, "Unknown response status: #{open_id_response.status}"
end
redirect_to :action => 'change_auth_type' unless performed?
end
def refresh_token
@user.crypt_word
@user.save
notify :notice, "New token successfully generated"
redirect_to :controller => 'preferences', :action => 'index'
end
private
def get_new_user
if session['new_user']
user = session['new_user']
session['new_user'] = nil
else
user = User.new
end
user
end
def check_create_user_params
return false unless params.has_key?(:request)
return false unless params[:request].has_key?(:login)
return false if params[:request][:login].empty?
return false unless params[:request].has_key?(:password)
return false if params[:request][:password].empty?
return true
end
end

View file

@ -1,140 +0,0 @@
# The methods added to this helper will be available to all templates in the application.
module ApplicationHelper
def user_time
@user.time
end
# Replicates the link_to method but also checks request.request_uri to find
# current page. If that matches the url, the link is marked
# id = "current"
#
def navigation_link(name, options = {}, html_options = nil, *parameters_for_method_reference)
if html_options
html_options = html_options.stringify_keys
convert_options_to_javascript!(html_options)
tag_options = tag_options(html_options)
else
tag_options = nil
end
url = options.is_a?(String) ? options : self.url_for(options, *parameters_for_method_reference)
id_tag = (request.request_uri == url) ? " id=\"current\"" : ""
"<a href=\"#{url}\"#{tag_options}#{id_tag}>#{name || url}</a>"
end
def days_from_today(date)
date.to_date - user_time.to_date
end
# Check due date in comparison to today's date
# Flag up date appropriately with a 'traffic light' colour code
#
def due_date(due)
if due == nil
return ""
end
days = days_from_today(due)
case days
# overdue or due very soon! sound the alarm!
when -1000..-1
"<a title='#{format_date(due)}'><span class=\"red\">Overdue by #{pluralize(days * -1, 'day')}</span></a> "
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 @user.prefs.due_style == "1"
"<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
# more than a week away - relax
else
"<a title='#{format_date(due)}'><span class=\"green\">Due in #{pluralize(days, 'day')}</span></a> "
end
end
# Check due date in comparison to today's date
# Flag up date appropriately with a 'traffic light' colour code
# Modified method for mobile screen
#
def due_date_mobile(due)
if due == nil
return ""
end
days = days_from_today(due)
case days
# overdue or due very soon! sound the alarm!
when -1000..-1
"<span class=\"red\">" + format_date(due) +"</span>"
when 0
"<span class=\"amber\">"+ format_date(due) + "</span>"
when 1
"<span class=\"amber\">" + format_date(due) + "</span>"
# due 2-7 days away
when 2..7
"<span class=\"orange\">" + format_date(due) + "</span>"
# more than a week away - relax
else
"<span class=\"green\">" + format_date(due) + "</span>"
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")
@controller.count_undone_todos_phrase(todos_parent, string)
end
def count_undone_todos_phrase_text(todos_parent, string="actions")
count_undone_todos_phrase(todos_parent, string).gsub("&nbsp;"," ")
end
def count_undone_todos_and_notes_phrase(project, string="actions")
s = count_undone_todos_phrase(project, string)
s += ", #{pluralize(project.notes_count, 'note')}" unless project.notes_count == 0
s
end
def link_to_context(context, descriptor = sanitize(context.name))
link_to( descriptor, context_path(context), :title => "View context: #{context.name}" )
end
def link_to_project(project, descriptor = sanitize(project.name))
link_to( descriptor, project_path(project), :title => "View project: #{project.name}" )
end
def item_link_to_context(item)
descriptor = "[C]"
descriptor = "[#{item.context.name}]" if (@user.prefs.verbose_action_descriptors)
link_to_context( item.context, descriptor )
end
def item_link_to_project(item)
descriptor = "[P]"
descriptor = "[#{item.project.name}]" if (@user.prefs.verbose_action_descriptors)
link_to_project( item.project, descriptor )
end
def render_flash
render :partial => 'shared/flash', :locals => { :flash => flash }
end
# Display a flash message in RJS templates
# Usage: page.notify :warning, "This is the message", 5.0
# Puts the message into a flash of type 'warning', fades over 5 secs
def notify(type, message, fade_duration)
type = type.to_s # symbol to string
page.replace 'flash', "<h4 id='flash' class='alert #{type}'>#{message}</h4>"
page.visual_effect :fade, 'flash', :duration => fade_duration
end
end

View file

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

View file

@ -1,12 +0,0 @@
module ContextsHelper
def get_listing_sortable_options
{
:tag => 'div',
:handle => 'handle',
:complete => visual_effect(:highlight, 'list-contexts'),
:url => order_contexts_path
}
end
end

View file

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

View file

@ -1,22 +0,0 @@
module FeedlistHelper
def rss_formatted_link(options = {})
image_tag = image_tag("feed-icon.png", :size => "16X16", :border => 0, :class => "rss-icon")
linkoptions = { :token => @user.word, :format => 'rss' }
linkoptions.merge!(options)
link_to(image_tag, linkoptions, :title => "RSS feed")
end
def text_formatted_link(options = {})
linkoptions = { :token => @user.word, :format => 'txt' }
linkoptions.merge!(options)
link_to('<span class="feed">TXT</span>', linkoptions, :title => "Plain text feed" )
end
def ical_formatted_link(options = {})
linkoptions = { :token => @user.word, :format => 'ics' }
linkoptions.merge!(options)
link_to('<span class="feed">iCal</span>', linkoptions, :title => "iCal feed" )
end
end

View file

@ -1,3 +0,0 @@
module LoginHelper
end

View file

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

View file

@ -1,5 +0,0 @@
module NotesHelper
def truncated_note(note, characters = 50)
sanitize(textilize(truncate(note.body, characters, "...")))
end
end

View file

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

View file

@ -1,34 +0,0 @@
module ProjectsHelper
def get_listing_sortable_options(list_container_id)
{
:tag => 'div',
:handle => 'handle',
:complete => visual_effect(:highlight, list_container_id),
:url => order_projects_path
}
end
def set_element_visible(id,test)
if (test)
page.show id
else
page.hide id
end
end
def project_next_prev
html = ''
unless @previous_project.nil?
project_name = truncate(@previous_project.name, 40, "...")
html << link_to_project(@previous_project, "&laquo; #{project_name}")
end
html << ' | ' if @previous_project && @next_project
unless @next_project.nil?
project_name = truncate(@next_project.name, 40, "...")
html << link_to_project(@next_project, "#{project_name} &raquo;")
end
html
end
end

View file

@ -1,199 +0,0 @@
module TodosHelper
require 'users_controller'
# Counts the number of incomplete items in the specified context
#
def count_items(context)
count = Todo.find_all("done=0 AND context_id=#{context.id}").length
end
def form_remote_tag_edit_todo( &block )
form_tag( todo_path(@todo), {:method => :put, :id => dom_id(@todo, 'form'), :class => "edit_todo_form inline-form" }, &block )
apply_behavior 'form.edit_todo_form', make_remote_form(:method => :put), :prevent_default => true
end
def remote_delete_icon
str = link_to( image_tag_for_delete,
todo_path(@todo),
:class => "icon delete_icon", :title => "delete the action '#{@todo.description}'")
apply_behavior '.item-container a.delete_icon:click', :prevent_default => true do |page|
page << "if (confirm('Are you sure that you want to ' + this.title + '?')) {"
page << " new Ajax.Request(this.href, { asynchronous : true, evalScripts : true, method : 'delete', parameters : { '_source_view' : '#{@source_view}' }})"
page << "}"
end
str
end
def remote_edit_icon
if !@todo.completed?
str = link_to( image_tag_for_edit,
edit_todo_path(@todo),
:class => "icon edit_icon")
apply_behavior '.item-container a.edit_icon:click', :prevent_default => true do |page|
page << "new Ajax.Request(this.href, { asynchronous : true, evalScripts : true, method : 'get', parameters : { '_source_view' : '#{@source_view}' }, onLoading: function(request){ Effect.Pulsate(this)}});"
end
else
str = '<a class="icon">' + image_tag("blank.png") + "</a> "
end
str
end
def remote_toggle_checkbox
str = check_box_tag('item_id', toggle_check_todo_path(@todo), @todo.completed?, :class => 'item-checkbox')
apply_behavior '.item-container input.item-checkbox:click',
remote_function(:url => javascript_variable('this.value'),
:with => "{ method : 'post', _source_view : '#{@source_view}' }")
str
end
def date_span
if @todo.completed?
"<span class=\"grey\">#{format_date( @todo.completed_at )}</span>"
elsif @todo.deferred?
show_date( @todo.show_from )
else
due_date( @todo.due )
end
end
def tag_list
@todo.tags.collect{|t| "<span class=\"tag\">" + link_to(t.name, :action => "tag", :id => t.name) + "</span>"}.join('')
end
def deferred_due_date
if @todo.deferred? && @todo.due
"(action due on #{format_date(@todo.due)})"
end
end
def project_and_context_links(parent_container_type)
if @todo.completed?
"(#{@todo.context.name}#{", " + @todo.project.name unless @todo.project.nil?})"
else
str = ''
if (['project', 'tickler', 'tag'].include?(parent_container_type))
str << item_link_to_context( @todo )
end
if (['context', 'tickler', 'tag'].include?(parent_container_type)) && @todo.project_id
str << item_link_to_project( @todo )
end
str
end
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:
# * l1: created more than 1 x staleness_starts, but < 2 x staleness_starts
# * l2: created more than 2 x staleness_starts, but < 3 x staleness_starts
# * l3: created more than 3 x staleness_starts
#
def staleness_class(item)
if item.due || item.completed?
return ""
elsif item.created_at < user_time - (@user.prefs.staleness_starts * 3).days
return " stale_l3"
elsif item.created_at < user_time - (@user.prefs.staleness_starts * 2).days
return " stale_l2"
elsif item.created_at < user_time - (@user.prefs.staleness_starts).days
return " stale_l1"
else
return ""
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(due)
if due == nil
return ""
end
days = days_from_today(due)
case days
# overdue or due very soon! sound the alarm!
when -1000..-1
"<a title='" + format_date(due) + "'><span class=\"red\">Shown on " + (days * -1).to_s + " days</span></a> "
when 0
"<a title='" + format_date(due) + "'><span class=\"amber\">Show Today</span></a> "
when 1
"<a title='" + format_date(due) + "'><span class=\"amber\">Show Tomorrow</span></a> "
# due 2-7 days away
when 2..7
if @user.prefs.due_style == 1
"<a title='" + format_date(due) + "'><span class=\"orange\">Show on " + due.strftime("%A") + "</span></a> "
else
"<a title='" + format_date(due) + "'><span class=\"orange\">Show in " + days.to_s + " days</span></a> "
end
# more than a week away - relax
else
"<a title='" + format_date(due) + "'><span class=\"green\">Show in " + days.to_s + " days</span></a> "
end
end
def calendar_setup( input_field )
date_format = @user.prefs.date_format
week_starts = @user.prefs.week_starts
str = "Calendar.setup({ ifFormat:\"#{date_format}\""
str << ",firstDay:#{week_starts},showOthers:true,range:[2004, 2010]"
str << ",step:1,inputField:\"" + input_field + "\",cache:true,align:\"TR\" })\n"
javascript_tag str
end
def item_container_id
return "tickler-items" if source_view_is :deferred
if source_view_is :project
return "p#{@todo.project_id}" if @todo.active?
return "tickler" if @todo.deferred?
end
return "c#{@todo.context_id}"
end
def should_show_new_item
return true if source_view_is(:deferred) && @todo.deferred?
return true if source_view_is(:project) && @todo.project.hidden? && @todo.project_hidden?
return true if source_view_is(:project) && @todo.deferred?
return true if !source_view_is(:deferred) && @todo.active?
return false
end
def parent_container_type
return 'tickler' if source_view_is :deferred
return 'project' if source_view_is :project
return 'context'
end
def empty_container_msg_div_id
return "tickler-empty-nd" if source_view_is(:project) && @todo.deferred?
return "p#{@todo.project_id}empty-nd" if source_view_is :project
return "tickler-empty-nd" if source_view_is :deferred
return "c#{@todo.context_id}empty-nd"
end
def project_names_for_autocomplete
array_or_string_for_javascript( ['None'] + @projects.select{ |p| p.active? }.collect{|p| escape_javascript(p.name) } )
end
def context_names_for_autocomplete
return array_or_string_for_javascript(['Create a new context']) if @contexts.empty?
array_or_string_for_javascript( @contexts.collect{|c| escape_javascript(c.name) } )
end
def format_ical_notes(notes)
split_notes = notes.split(/\n/)
joined_notes = split_notes.join("\\n")
end
private
def image_tag_for_delete
image_tag("blank.png", :title =>"Delete action", :class=>"delete_item")
end
def image_tag_for_edit
image_tag("blank.png", :title =>"Edit action", :class=>"edit_item", :id=> dom_id(@todo, 'edit_icon'))
end
end

View file

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

View file

@ -1,65 +0,0 @@
class Context < ActiveRecord::Base
has_many :todos, :dependent => :delete_all, :include => :project, :order => "completed_at DESC"
belongs_to :user
acts_as_list :scope => :user
extend NamePartFinder
include Tracks::TodoList
include UrlFriendlyName
attr_protected :user
validates_presence_of :name, :message => "context must have a name"
validates_length_of :name, :maximum => 255, :message => "context name must be less than 256 characters"
validates_uniqueness_of :name, :message => "already exists", :scope => "user_id"
validates_does_not_contain :name, :string => '/', :message => "cannot contain the slash ('/') character"
validates_does_not_contain :name, :string => ',', :message => "cannot contain the comma (',') character"
def self.feed_options(user)
{
:title => 'Tracks Contexts',
:description => "Lists all the contexts for #{user.display_name}"
}
end
def self.null_object
NullContext.new
end
def hidden?
self.hide == true || self.hide == 1
end
def to_param
url_friendly_name
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
end
class NullContext
def nil?
true
end
def id
nil
end
def name
''
end
end

View file

@ -1,7 +0,0 @@
class Note < ActiveRecord::Base
belongs_to :user
belongs_to :project
attr_protected :user
end

View file

@ -1,21 +0,0 @@
class Preference < ActiveRecord::Base
belongs_to :user
composed_of :tz,
:class_name => 'TimeZone',
:mapping => %w(time_zone name)
def self.day_number_to_name_map
{ 0 => "Sunday",
1 => "Monday",
2 => "Tuesday",
3 => "Wednesday",
4 => "Thursday",
5 => "Friday",
6 => "Saturday"}
end
def hide_completed_actions?
return show_number_completed == 0
end
end

View file

@ -1,112 +0,0 @@
class Project < ActiveRecord::Base
has_many :todos, :dependent => :delete_all, :include => :context
has_many :notes, :dependent => :delete_all, :order => "created_at DESC"
belongs_to :default_context, :dependent => :nullify, :class_name => "Context", :foreign_key => "default_context_id"
belongs_to :user
validates_presence_of :name, :message => "project must have a name"
validates_length_of :name, :maximum => 255, :message => "project name must be less than 256 characters"
validates_uniqueness_of :name, :message => "already exists", :scope =>"user_id"
validates_does_not_contain :name, :string => '/', :message => "cannot contain the slash ('/') character"
validates_does_not_contain :name, :string => ',', :message => "cannot contain the comma (',') character"
acts_as_list :scope => 'user_id = #{user_id} AND state = \'#{state}\''
acts_as_state_machine :initial => :active, :column => 'state'
extend NamePartFinder
include Tracks::TodoList
include UrlFriendlyName
state :active
state :hidden, :enter => :hide_todos, :exit => :unhide_todos
state :completed
event :activate do
transitions :to => :active, :from => [:hidden, :completed]
end
event :hide do
transitions :to => :hidden, :from => [:active, :completed]
end
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 => 'Tracks Projects',
:description => "Lists all the projects for #{user.display_name}"
}
end
def to_param
url_friendly_name
end
def hide_todos
todos.each do |t|
unless t.completed? || t.deferred?
t.hide!
t.save
end
end
end
def unhide_todos
todos.each do |t|
if t.project_hidden?
t.unhide!
t.save
end
end
end
def note_count
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
return
when :hidden
hide!
when :active
activate!
when :completed
complete!
end
end
end
class NullProject
def hidden?
false
end
def nil?
true
end
def id
nil
end
end

View file

@ -1,11 +0,0 @@
class Tag < ActiveRecord::Base
has_many_polymorphs :taggables,
:from => [:todos],
:through => :taggings,
:dependent => :destroy
def on(taggable, user)
tagging = taggings.create :taggable => taggable, :user => user
end
end

View file

@ -1,11 +0,0 @@
class Tagging < ActiveRecord::Base
belongs_to :tag
belongs_to :taggable, :polymorphic => true
belongs_to :user
# def before_destroy
# # disallow orphaned tags
# # TODO: this doesn't seem to be working
# tag.destroy if tag.taggings.count < 2
# end
end

View file

@ -1,94 +0,0 @@
class Todo < ActiveRecord::Base
belongs_to :context, :order => 'name'
belongs_to :project
belongs_to :user
acts_as_state_machine :initial => :active, :column => 'state'
state :active, :enter => Proc.new { |t| t[:show_from] = nil }
state :project_hidden
state :completed, :enter => Proc.new { |t| t.completed_at = Time.now.utc }, :exit => Proc.new { |t| t.completed_at = nil }
state :deferred
event :defer do
transitions :to => :deferred, :from => [:active]
end
event :complete do
transitions :to => :completed, :from => [:active, :project_hidden, :deferred]
end
event :activate do
transitions :to => :active, :from => [:project_hidden, :completed, :deferred]
end
event :hide do
transitions :to => :project_hidden, :from => [:active, :deferred]
end
event :unhide do
transitions :to => :deferred, :from => [:project_hidden], :guard => Proc.new{|t| !t.show_from.blank? }
transitions :to => :active, :from => [:project_hidden]
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_chronic_date :due, :allow_nil => true
validates_presence_of :show_from, :if => :deferred?
validates_presence_of :context
def validate
if !show_from.blank? && show_from < user.date
errors.add("show_from", "must be a date in the future")
end
end
def toggle_completion!
if completed?
activate!
else
complete!
end
end
def activate_and_save!
activate!
save!
end
def 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
def project
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
def self.feed_options(user)
{
:title => 'Tracks Actions',
:description => "Actions for #{user.display_name}"
}
end
end

View file

@ -1,182 +0,0 @@
require 'digest/sha1'
class User < ActiveRecord::Base
has_many :contexts,
:order => 'position ASC',
:dependent => :delete_all do
def find_by_params(params)
if params['url_friendly_name']
find_by_url_friendly_name(params['url_friendly_name'])
elsif params['id'] && params['id'] =~ /^\d+$/
find(params['id'])
elsif params['id']
find_by_url_friendly_name(params['id'])
elsif params['context']
find_by_url_friendly_name(params['context'])
elsif params['context_id']
find_by_url_friendly_name(params['context_id'])
end
end
end
has_many :projects,
:order => 'position ASC',
:dependent => :delete_all do
def find_by_params(params)
if params['url_friendly_name']
find_by_url_friendly_name(params['url_friendly_name'])
elsif params['id'] && params['id'] =~ /^\d+$/
find(params['id'])
elsif params['id']
find_by_url_friendly_name(params['id'])
elsif params['project']
find_by_url_friendly_name(params['project'])
elsif params['project_id']
find_by_url_friendly_name(params['project_id'])
end
end
def update_positions(project_ids)
project_ids.each_with_index do |id, position|
project = self.detect { |p| p.id == id.to_i }
raise "Project id #{id} not associated with user id #{@user.id}." if project.nil?
project.update_attribute(:position, position + 1)
end
end
def projects_in_state_by_position(state)
self.sort{ |a,b| a.position <=> b.position }.select{ |p| p.state == state }
end
def next_from(project)
self.offset_from(project, 1)
end
def previous_from(project)
self.offset_from(project, -1)
end
def offset_from(project, offset)
projects = self.projects_in_state_by_position(project.state)
position = projects.index(project)
return nil if position == 0 && offset < 0
projects.at( position + offset)
end
def cache_note_counts
project_note_counts = Note.count(:group => 'project_id')
self.each do |project|
project.cached_note_count = project_note_counts[project.id] || 0
end
end
end
has_many :todos,
:order => 'completed_at DESC, todos.created_at DESC',
:dependent => :delete_all
has_many :deferred_todos,
:class_name => 'Todo',
:conditions => [ 'state = ?', 'deferred' ],
:order => 'show_from ASC, todos.created_at DESC' do
def find_and_activate_ready
find(:all, :conditions => ['show_from <= ?', Time.now.utc.to_date.to_time ]).collect { |t| t.activate_and_save! }
end
end
has_many :completed_todos,
:class_name => 'Todo',
:conditions => ['todos.state = ? and todos.completed_at is not 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
has_many :taggings
has_many :tags, :through => :taggings, :select => "DISTINCT tags.*"
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_confirmation_of :password
validates_length_of :login, :within => 3..80
validates_uniqueness_of :login, :on => :create
validates_presence_of :open_id_url, :if => Proc.new{|user| user.auth_type == 'open_id'}
def validate
unless Tracks::Config.auth_schemes.include?(auth_type)
errors.add("auth_type", "not a valid authentication type")
end
end
alias_method :prefs, :preference
def self.authenticate(login, pass)
candidate = find(:first, :conditions => ["login = ?", login])
return nil if candidate.nil?
if candidate.auth_type == 'database'
return candidate if candidate.password == sha1(pass)
elsif candidate.auth_type == 'ldap' && Tracks::Config.auth_schemes.include?('ldap')
return candidate if SimpleLdapAuthenticator.valid?(login, pass)
end
nil
end
def self.no_users_yet?
count == 0
end
def self.find_admin
find(:first, :conditions => [ "is_admin = ?", true ])
end
def to_param
login
end
def display_name
if first_name.blank? && last_name.blank?
return login
elsif first_name.blank?
return last_name
elsif last_name.blank?
return first_name
end
"#{first_name} #{last_name}"
end
def change_password(pass,pass_confirm)
self.password = pass
self.password_confirmation = pass_confirm
save!
end
def crypt_word
write_attribute("word", self.class.sha1(login + Time.now.to_i.to_s + rand.to_s))
end
def time
prefs.tz.adjust(Time.now.utc)
end
def date
time.to_date
end
protected
def self.sha1(pass)
Digest::SHA1.hexdigest("#{Tracks::Config.salt}--#{pass}--")
end
before_create :crypt_password, :crypt_word
before_update :crypt_password
def crypt_password
write_attribute("password", self.class.sha1(password)) if password == @password_confirmation
end
def password_required?
auth_type == 'database'
end
end

View file

@ -1,35 +0,0 @@
<% @not_done = @not_done_todos.select {|t| t.context_id == context.id } %>
<div id="c<%= context.id %>" class="container context" <%= "style=\"display:none\"" if collapsible && @not_done.empty? %>>
<h2>
<% if collapsible -%>
<a href="#" class="container_toggle" id="toggle_c<%= context.id %>"><%= image_tag("collapse.png") %></a>
<% apply_behavior '.container_toggle:click', :prevent_default => true do |page|
page << "containerElem = this.up('.container')
toggleTarget = containerElem.down('.toggle_target')
if (Element.visible(toggleTarget))
{
todoItems.collapseNextActionListing(this, toggleTarget);
todoItems.contextCollapseCookieManager.setCookie(todoItems.buildCookieName(containerElem), true)
}
else
{
todoItems.expandNextActionListing(this, toggleTarget);
todoItems.contextCollapseCookieManager.clearCookie(todoItems.buildCookieName(containerElem))
}
"
end
%>
<% end -%>
<% if source_view_is :context %>
<%= in_place_editor_field :context, :name, {}, { :url => url_for(:controller => 'context', :action => 'update', :id => context.id, :field => 'name', :wants_render => false) } %>
<% else %>
<%= link_to_context( context ) %>
<% end %>
</h2>
<div id="c<%= context.id %>items" class="items toggle_target">
<div id="c<%= context.id %>empty-nd" style="display:<%= @not_done.empty? ? 'block' : 'none'%>;">
<div class="message"><p>Currently there are no incomplete actions in this context</p></div>
</div>
<%= render :partial => "todos/todo", :collection => @not_done, :locals => { :parent_container_type => "context" } %>
</div><!-- [end:items] -->
</div><!-- [end:c<%= context.id %>] -->

View file

@ -1,13 +0,0 @@
<%
@context = context_form
%>
<%= error_messages_for 'context' %>
<tr>
<td width="150"><label for="context_name">Name</label></td>
<td width="300"><%= text_field 'context', 'name', :class => 'context-name' %></td>
</tr>
<tr>
<td width="150"><label for="context_hide">Hidden?</label></td>
<td width="300"><%= check_box 'context', 'hide', :class => 'context-hide' %></td>
</tr>
<% @context = nil %>

View file

@ -1,56 +0,0 @@
<% context = context_listing %>
<div id="<%= dom_id(context, "container") %>" class="list">
<div id="<%= dom_id(context) %>" class="context sortable_row" style="display:'';">
<div class="position">
<span class="handle">DRAG</span>
</div>
<div class="data">
<%= link_to_context( context ) %> <%= " (" + count_undone_todos_phrase(context,"actions") + ")" %>
</div>
<div class="buttons">
<% if context.hide? %>
<span class="grey">HIDDEN</span>
<% else %>
<span class="grey">VISIBLE</span>
<% end %>
<a class="delete_context_button" href="<%= formatted_context_path(context, :js) %>" title="delete the context '<%= context.name %>'"><%= image_tag( "blank.png", :title => "Delete context", :class=>"delete_item") %></a>
<%= apply_behavior "a.delete_context_button:click", { :prevent_default => true, :external => true} do |page|
page << "if (confirm('Are you sure that you want to ' + this.title + '?')) {"
page << " new Ajax.Request(this.href, {asynchronous:true,"
page << " evalScripts:true, method:'delete'}); };"
end -%>
<a class="edit_context_button" href="#"><%= image_tag( "blank.png", :title => "Edit context", :class=>"edit_item") %></a>
<%= apply_behavior 'a.edit_context_button:click', :prevent_default => true do |page, element|
element.up('.context').toggle
editform = element.up('.list').down('.edit-form')
editform.toggle
editform.visual_effect(:appear)
editform.down('input').focus
end
-%>
</div>
</div>
<div id="<%= dom_id(context, 'edit') %>" class="edit-form" style="display:none;">
<% form_tag context_path(context), { :id => dom_id(context, 'edit_form'), :class => "inline-form edit-context-form", :method => :put } do -%>
<table style="table-layout: fixed;" width="450">
<%= render :partial => 'context_form', :object => context %>
<tr>
<td width="150">&nbsp; <input type="hidden" name="wants_render" value="true" /> </td>
<td width="300"><input type="submit" value="Update" />&nbsp;<a href="#" class="form_reset">Cancel</a></td>
</tr>
</table>
<% end -%>
<%= apply_behavior ".edit-context-form", make_remote_form(:complete => "Effect.Appear($(this).up('.list'));" ), :external => true %>
<%= apply_behavior "a.form_reset:click", :prevent_default => true do |page, element|
element.up('.list').down('.context').toggle
element.up('.edit-form').toggle
element.up('form').reset
end %>
</div>
</div>
<% if controller.action_name == 'create' %>
<script>
new Effect.Appear('<%= dom_id(context) %>');
</script>
<% end %>

View file

@ -1,8 +0,0 @@
<%
context = text_context
todos_in_context = todos.select { |t| t.context_id == context.id }
if todos_in_context.length > 0
%>
<%= context.name.upcase %>:
<% end -%>
<%= render :partial => "todos/text_todo", :collection => todos_in_context -%>

View file

@ -1,10 +0,0 @@
if @saved
page.hide 'contexts-empty-nd'
page.insert_html :bottom, "list-contexts", :partial => 'context_listing', :locals => { :context_listing => @context }
page.sortable "list-contexts", get_listing_sortable_options
page.call "Form.reset", "context-form"
page.call "Form.focusFirstElement", "context-form"
else
page.show 'status'
page.replace_html 'status', "#{error_messages_for('context')}"
end

View file

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

View file

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

View file

@ -1,35 +0,0 @@
<div id="display_box">
<div id="list-contexts">
<div id="contexts-empty-nd" style="display:<%= @no_contexts ? 'block' : 'none'%>;">
<div class="message"><p>Currently there are no contexts</p></div>
</div>
<%= render :partial => 'context_listing', :collection => @contexts %>
</div>
</div>
<div id="input_box">
<a id="toggle-new-context-form" href="#" accesskey="n" title="Create a new context">Create new context &#187;</a>
<div id="context_new" class="context_new" style="display:none">
<% form_remote_tag :url => contexts_path, :method => :post, :html=> { :id => 'context-form', :name => 'context', :class => 'inline-form' } do -%>
<div id="status"><%= error_messages_for('context') %></div>
<label for="context_name">Context name</label><br />
<%= text_field( "context", "name" ) %><br />
<label for="new_context_on_front">Hide from front page?</label>
<%= check_box( "context", "hide" ) %><br />
<input type="submit" value="Add" />
<% end -%>
</div>
</div>
<%
sortable_element 'list-contexts', get_listing_sortable_options
apply_behavior '#toggle-new-context-form:click', :prevent_default => true do |page|
page['context_new'].toggle
page['context-form'].down('input').focus
#page << "Form.focusFirstElement('context-form');"
end
-%>

View file

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

View file

@ -1,10 +0,0 @@
<div id="display_box">
<%= render :partial => "contexts/context", :locals => { :context => @context, :collapsible => false } %>
<%= render :partial => "todos/completed", :locals => { :done => @done, :collapsible => false, :append_descriptor => "in this context (last #{@user.prefs.show_number_completed})" } %>
</div><!-- [end:display_box] -->
<div id="input_box">
<%= render :partial => "shared/add_new_item_form" %>
<%= render "sidebar/sidebar" %>
</div><!-- End of input box -->

View file

@ -1,2 +0,0 @@
page.replace_html dom_id(@context, 'container'), :partial => 'context_listing', :object => @context
page.sortable "list-contexts", get_listing_sortable_options

View file

@ -1,37 +0,0 @@
<div id="feeds">
<div id="feedlegend">
<h3>Exporting data</h3>
<p>You can choose between the following formats:</p>
<ul>
<li><strong>YAML: </strong>Best for porting data between Tracks installations</li>
<li><strong>CSV: </strong>Best for importing into spreadsheet or data analysis software</li>
<li><strong>XML: </strong>Best for importing or repurposing the data</li>
</ul
</div>
<p>
<table class="users_table">
<tr>
<th>Description</th>
<th>Download link</th>
</tr>
<tr>
<td>YAML file containing all your actions, contexts, projects and notes</td>
<td><%= link_to "YAML file", :controller => 'data', :action => 'yaml_export' %></td>
</tr>
<tr>
<td>CSV file containing all of your actions, with named contexts and projects</td>
<td><%= link_to "CSV file (actions, contexts and projects)", :controller => 'data', :action => 'csv_actions' %></td>
</tr>
<tr>
<td>CSV file containing all your notes</td>
<td><%= link_to "CSV file (notes only)", :controller => 'data', :action => 'csv_notes' %></td>
</tr>
<tr>
<td>XML file containing all your actions, contexts, projects and notes</td>
<td><%= link_to "XML file (actions only)", :controller => 'data', :action => 'xml_export' %></td>
</tr>
</table>
</p>
</div><!-- End of feeds -->

View file

@ -1,18 +0,0 @@
<div id="display_box">
<div id="feeds">
<div id="feedlegend">
<h3>Importing data</h3>
<p>You can choose between the following formats:</p>
<ul>
<li><strong>YAML: </strong>Best for porting data between Tracks installations</li>
<li><strong>CSV: </strong>Best for importing into spreadsheet or data analysis software</li>
</ul
</div>
<ul>
<li>YAML</li>
<li>CSV</li>
</ul>
</div><!-- End of feeds -->
</div><!-- End of display_box -->

View file

@ -1,15 +0,0 @@
<div id="display_box">
<div id="feeds">
<div id="feedlegend">
<h3>Importing and exporting data into Tracks</h3>
<p>You can export your data in a number of different forms. Note: you can only export/import your own data (i.e. the data available when you are logged in).</p>
</div>
<ul>
<li>Import</li>
<li>
<%= link_to "Export", :controller => 'data', :action => 'export' %>
</li>
</ul>
</div><!-- End of feeds -->
</div><!-- End of display_box -->

View file

@ -1,19 +0,0 @@
<div id="display_box">
<div id="feeds">
<div id="feedlegend">
<p>Paste the contents of the YAML file you exported into the text box below:</p>
</div>
<p>
<% form_for :import, @import, :url => {:controller => 'data', :action => 'yaml_import'} do |f| %>
<%= f.text_area :yaml %><br />
<input type="submit" value="Import data">
<% end %>
</p>
</div><!-- End of feeds -->
</div><!-- End of display_box -->
<div id="input_box">
</div><!-- End of input box -->

View file

@ -1 +0,0 @@
<p>Import was successful</p>

View file

@ -1,87 +0,0 @@
<div id="display_box">
<div id="feeds">
<div id="feedlegend">
<h3>Legend:</h3>
<dl>
<dt><%= image_tag("feed-icon.png", :size => "16X16", :border => 0)%></dt><dd>RSS Feed</dd>
<dt><span class="feed">TXT</span></dt><dd>Plain Text Feed</dd>
<dt><span class="feed">iCal</span></dt><dd>iCal feed</dd>
</dl>
<p>Note: All feeds show only actions that have not been marked as done.</p>
</div>
<ul>
<li>
<%= rss_formatted_link({ :controller => 'todos', :action => 'index', :limit => 15 }) %>
<%= text_formatted_link({ :controller => 'todos', :action => 'index', :limit => 15 }) %>
<%= ical_formatted_link({ :controller => 'todos', :action => 'index', :limit => 15 }) %>
Last 15 actions
</li>
<li>
<%= rss_formatted_link( { :controller => 'todos', :action => 'index' } ) %>
<%= text_formatted_link( { :controller => 'todos', :action => 'index' } ) %>
<%= ical_formatted_link( { :controller => 'todos', :action => 'index' } ) %>
All actions
</li>
<li>
<%= rss_formatted_link({ :controller => 'todos', :action => 'index', :due => 0 }) %>
<%= text_formatted_link({ :controller => 'todos', :action => 'index', :due => 0 }) %>
<%= ical_formatted_link({ :controller => 'todos', :action => 'index', :due => 0 }) %>
Actions due today or earlier
</li>
<li>
<%= rss_formatted_link({ :controller => 'todos', :action => 'index', :due => 6 }) %>
<%= text_formatted_link({ :controller => 'todos', :action => 'index', :due => 6 }) %>
<%= ical_formatted_link({ :controller => 'todos', :action => 'index', :due => 6 }) %>
Actions due in 7 days or earlier
</li>
<li>
<%= rss_formatted_link({ :controller => 'todos', :action => 'index', :done => 7 }) %>
<%= text_formatted_link({ :controller => 'todos', :action => 'index', :done => 7 }) %>
Actions completed in the last 7 days
</li>
<li>
<%= rss_formatted_link({:controller => 'contexts', :action => 'index'}) %>
<%= text_formatted_link({:controller => 'contexts', :action => 'index'}) %>
All Contexts
</li>
<li>
<%= rss_formatted_link({:controller => 'projects', :action => 'index'}) %>
<%= text_formatted_link({:controller => 'projects', :action => 'index'}) %>
All Projects
</li>
<li>
<%= rss_formatted_link({:controller => 'projects', :action => 'index', :only_active_with_no_next_actions => true}) %>
<%= text_formatted_link({:controller => 'projects', :action => 'index', :only_active_with_no_next_actions => true}) %>
Active projects with no next actions
</li>
<li><h4>Feeds for incomplete actions in a specific context:</h4>
<ul>
<% for context in @contexts %>
<li>
<%= rss_formatted_link({ :controller=> 'todos', :action => 'index', :context_id => context.to_param }) %>
<%= text_formatted_link({ :controller=> 'todos', :action => 'index', :context_id => context.to_param }) %>
<%= ical_formatted_link({ :controller=> 'todos', :action => 'index', :context_id => context.to_param }) %>
Next actions in <strong><%=h context.name %></strong>
</li>
<% end %>
</ul>
</li>
<li><h4>Feeds for incomplete actions in a specific project:</h4>
<ul>
<% for project in @projects %>
<li>
<%= rss_formatted_link({ :controller=> 'todos', :action => 'index', :project_id => project.to_param }) %>
<%= text_formatted_link({ :controller=> 'todos', :action => 'index', :project_id => project.to_param }) %>
<%= ical_formatted_link({ :controller=> 'todos', :action => 'index', :project_id => project.to_param }) %>
Next actions for <strong><%=h project.name %></strong>
</li>
<% end %>
</ul>
</li>
</ul>
</div>
</div><!-- End of display_box -->
<div id="input_box">
<%= render "sidebar/sidebar" %>
</div><!-- End of input box -->

View file

@ -1,24 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<%= stylesheet_link_tag "scaffold" %>
<%= javascript_include_tag :defaults %>
<script type="text/javascript">
function setfocus() {
var f = $('user_login');
if (!f) { f = $('openid_url'); }
if (f) { f.focus() };
}
Event.observe(window, 'load', setfocus);
</script>
<title><%= @page_title -%></title>
</head>
<body>
<%= yield %>
<%= render :partial => "shared/footer" %>
</body>
</html>

View file

@ -1,15 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<%= stylesheet_link_tag "mobile" %>
<title><%= @page_title %></title>
</head>
<body>
<%= yield %>
</body>
</html>

View file

@ -1,10 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Login</title>
<%= stylesheet_link_tag "scaffold" %>
</head>
<body>
<%= yield %>
</body>
</html>

View file

@ -1,75 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<% if @prefs.refresh != 0 -%>
<meta http-equiv="Refresh" content="<%= @prefs["refresh"].to_i*60 %>;url=<%= request.request_uri %>">
<% end -%>
<%= stylesheet_link_tag "standard" %>
<%= stylesheet_link_tag "print", :media => "print" %>
<%= javascript_include_tag :defaults, :unobtrusive %>
<%= javascript_include_tag "selector-addon-v1" %>
<%= stylesheet_link_tag 'calendar-system.css' %>
<%= javascript_include_tag 'calendar', 'calendar-en', 'calendar-setup' %>
<%= javascript_include_tag "accesskey-hints" %>
<%= javascript_include_tag "todo-items" %>
<link rel="shortcut icon" href="<%= url_for(:controller => 'favicon.ico') %>" />
<%= auto_discovery_link_tag(:rss,{:controller => "feed", :action => "na_feed", :name => "#{@user.login}", :token => "#{@user.word}"}, {:title => "RSS feed of next actions"}) %>
<title><%= @page_title %></title>
</head>
<body>
<div id="topbar">
<div id="date">
<h1>
<% if @count %>
<span id="badge_count" class="badge"><%= @count %></span>
<% end %>
<%= user_time.strftime(@prefs.title_date_format) %> <%= image_tag("spinner.gif", :size => "16X16", :border => 0, :id => 'busy', :style => 'display:none' ) %>
</h1>
</div>
<div id="minilinks">
<%= link_to_function("Toggle notes", nil, {:accesskey => "S", :title => "Toggle all notes"}) do |page|
page.select('.notes').each { |e| e.toggle }
end
-%>&nbsp;|&nbsp;
<%= link_to "Logout (#{@user.display_name}) »", :controller => "login", :action=>"logout"%>
</div>
<div id="navcontainer">
<ul id="navlist">
<li><%= navigation_link("Home", home_path, {:accesskey => "t", :title => "Home"} ) %></li>
<li><%= navigation_link( "Contexts", contexts_path, {:accesskey=>"c", :title=>"Contexts"} ) %></li>
<li><%= navigation_link( "Projects", projects_path, {:accesskey=>"p", :title=>"Projects"} ) %></li>
<li><%= navigation_link( "Tickler", tickler_path, :title => "Tickler" ) %></li>
<li><%= navigation_link( "Done", done_path, {:accesskey=>"d", :title=>"Completed"} ) %></li>
<li><%= navigation_link( "Notes", notes_path, {:accesskey => "o", :title => "Show all notes"} ) %></li>
<li><%= navigation_link( "Preferences", {:controller => "preferences", :action => "index"}, {:accesskey => "u", :title => "Show my preferences"} ) %></li>
<li><%= navigation_link( "Import/Export", {:controller => "data", :action => "index"}, {:accesskey => "i", :title => "Import and export data"} ) %></li>
<% if @user.is_admin? -%>
<li><%= navigation_link("Admin", users_path, {:accesskey => "a", :title => "Add or delete users"} ) %></li>
<% end -%>
<li><%= navigation_link(image_tag("feed-icon.png", :size => "16X16", :border => 0), {:controller => "feedlist", :action => "index"}, :title => "See a list of available feeds" ) %></li>
</ul>
</div>
<%= render_flash %>
</div>
<div id="content">
<% unless @controller_name == 'feed' or session['noexpiry'] == "on" -%>
<%= periodically_call_remote( :url => {:controller => "login", :action => "check_expiry"},
:frequency => (5*60)) %>
<% end -%>
<%= periodically_call_remote( :url => formatted_check_deferred_todos_path(:js),
:method => :post,
:frequency => (10*60)) %>
<%= yield %>
</div>
<%= render :partial => "shared/footer" %>
</body>
</html>

View file

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

View file

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

View file

@ -1,52 +0,0 @@
<% auth_schemes = Tracks::Config.auth_schemes -%>
<div title="Account login" id="loginform" class="form">
<%= render_flash %>
<h3>Please log in to use Tracks:</h3>
<% if auth_schemes.include?('database') || auth_schemes.include?('open_id') %>
<% form_tag :action=> 'login' do %>
<table>
<tr>
<td width="100px"><label for="user_login">Login:</label></td>
<td width="100px"><input type="text" name="user_login" id="user_login" value="" class="login_text" /></td>
</tr>
<tr>
<td width="100px"><label for="user_password">Password:</label></td>
<td width="100px"><input type="password" name="user_password" id="user_password" class="login_text" /></td>
</tr>
<tr>
<td width="100px"><label for="user_noexpiry">Stay logged in:</label></td>
<td width="100px"><input type="checkbox" name="user_noexpiry" id="user_noexpiry" checked /></td>
</tr>
<tr>
<td width="100px"></td>
<td><input type="submit" name="login" value="Login &#187;" class="primary" /></td>
</tr>
</table>
<% end %>
<% end %>
<% if auth_schemes.include?('open_id') %>
<% form_tag :action=> 'login', :action => 'begin' do %>
<table>
<tr>
<td width="100px"><label for="openid_url">Identity URL:</label></td>
<td width="100px"><input type="text" name="openid_url" id="openid_url" value="<%= @openid_url %>" class="login_text open_id" /></td>
</tr>
<tr>
<td width="100px"><label for="user_noexpiry">Stay logged in:</label></td>
<td width="100px"><input type="checkbox" name="user_noexpiry" id="user_noexpiry" checked /></td>
</tr>
<tr>
<td width="100px"></td>
<td><input type="submit" name="login" value="Verify &#187;" class="primary" /></td>
</tr>
</table>
<% end %>
<% end %>
</div>

View file

@ -1,35 +0,0 @@
<%= render_flash %>
<% if @todos.length == 0 -%>
<p>There are no incomplete actions in this <%= @type %></p>
<% else -%>
<ul>
<% for todo in @todos -%>
<li>
<%= link_to "&raquo;", :controller => 'mobile', :action => 'detail', :id => todo.id %>
<% if todo.due? -%>
<%= due_date_mobile(todo.due) %>
<% end -%>
<%= todo.description %>
(<em><%= todo.context.name %></em>)
<% end -%>
</li>
<ul>
<% if !@todos_pages.nil? -%>
<% if @todos_pages.length > 1 -%>
<hr />
Pages: <%= pagination_links( @todos_pages, :always_show_anchors => true ) %>
<% end -%>
<% end -%>
<% end -%>
<hr />
<% form_tag( { :action => "filter", :type => "context" } ) do -%>
<%= collection_select( "context", "id", @contexts, "id", "name",
{ :include_blank => true } ) %>
<%= submit_tag( value = "Go" ) %>
<% end -%>
<% form_tag( {:action => "filter", :type => "project" }) do -%>
<%= collection_select( "project", "id", @projects, "id", "name",
{ :include_blank => true } ) %>
<%= submit_tag( value = "Go" ) %>
<% end -%>

View file

@ -1,21 +0,0 @@
<span class="errors">
<%= error_messages_for("todo") %>
</span>
<% this_year = user_time.to_date.strftime("%Y").to_i -%>
<p><label for="todo_state">Done?</label></p>
<p><%= check_box( "todo", "state", "tabindex" => 1) %></p>
<p><label for="todo_description">Next action</label></p>
<p><%= text_field( "todo", "description", "tabindex" => 2) %></p>
<p><label for="todo_notes">Notes</label></p>
<p><%= text_area( "todo", "notes", "cols" => 30, "rows" => 5, "tabindex" => 3) %></p>
<p><label for="todo_context_id">Context</label></p>
<p><%= collection_select( "todo", "context_id", @contexts, "id", "name", {"tabindex" => 4} ) %></p> <p><label for="todo_project_id">Project</label></p>
<p><%= collection_select( "todo", "project_id", @projects, "id", "name",
{:include_blank => true}, {"tabindex" => 5} ) %></p>
<p><label for="todo_due">Due</label></p>
<p><%= date_select("todo", "due", :order => [:day, :month, :year],
:start_year => this_year, :include_blank => true) %></p>
<p><label for="todo_show_from">Show from</label></p>
<p><%= date_select("todo", "show_from", :order => [:day, :month, :year],
:start_year => this_year, :include_blank => true) %></p>
<p><input type="submit" value="Update" tabindex="6" /></p>

View file

@ -1,4 +0,0 @@
<% form_tag :action => 'update', :id => @item.id do -%>
<%= render :partial => 'mobile_edit' %>
<% end -%>
<%= button_to "Back", :controller => 'mobile', :action => 'index' %>

View file

@ -1,6 +0,0 @@
<h1><span class="count"><%= @count.to_s %></span> <%= @desc %>
<%= link_to "+", :controller => 'mobile', :action => 'add_action' %></h1>
<hr />
<%= render :partial => 'mobile_actions' %>
<%= link_to "View All", :controller => 'mobile', :action => 'index' %>

View file

@ -1,5 +0,0 @@
<h1><span class="count"><%= @count.to_s %></span> <%= @desc %>
<%= link_to "+", :controller => 'mobile', :action => 'add_action' %></h1>
<hr />
<%= render :partial => 'mobile_actions' %>
<%= link_to "Logout", :controller => 'login', :action => 'logout' %>

View file

@ -1,4 +0,0 @@
<% form_tag :action => 'update' do %>
<%= render :partial => 'mobile_edit' %>
<% end -%>
<%= button_to "Back", :controller => 'mobile', :action => 'index' %>

View file

@ -1,6 +0,0 @@
<% @note = note_edit_form %>
<%= hidden_field( "note", "project_id" ) %>
<%= text_area( "note", "body", "cols" => 70, "rows" => 15, "tabindex" => 1 ) %>
<br /><br />
<input type="submit" value="Update" tabindex="2" />
<% @note = nil %>

View file

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

View file

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

View file

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

View file

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

View file

@ -1,74 +0,0 @@
<div id="display_box" class="container context">
<h2>Help on preferences</h2>
<p>The preference settings should mostly be self-explanatory, but some hints are included below: </p>
<ul>
<li><strong>first name and last name:</strong> Used for display purposes if set</li>
<li><strong>date format:</strong> the format in which you'd like dates to be shown. For example, for the date 31st January 2006, %d/%m/%Y will show 31/01/2006, %b-%e-%y will show Jan-31-06. See the <a href="http://uk2.php.net/strftime" title="PHP strftime manual">strftime manual</a> for more formatting options for the date.</li>
<li><strong>title date format:</strong> same as above, but for the big date at the top of each page.</li>
<li><strong>time zone:</strong> your local time zone</li>
<li><strong>week starts:</strong> day of the week shown as the start of the week on the popup calendar.</li>
<li><strong>due style:</strong> style in which due dates are shown, e.g. "Due in 3 days", "Due on Wednesday"</li>
<li><strong>show completed projects in sidebar:</strong> whether or not projects marked as complete are shown in the sidebar on the home page and elsewhere</li>
<li><strong>show hidden contexts in sidebar:</strong> whether or not contexts marked as hidden are shown in the sidebar on the home page and elsewhere</li>
<li><strong>show project on todo done:</strong> whether or not to redirect to the project page when an action associated with a project is marked complete</li>
<% if @user.is_admin? %>
<li><strong>admin email:</strong> email address for the admin user of Tracks (displayed on the signup page for users to contact to obtain an account)</li>
<% end %>
<li><strong>staleness starts:</strong> the number of days before items with no due date get marked as stale (with a yellow highlight)</li>
<li><strong>show number completed:</strong> number of completed actions to show on the home page. If you set this to zero, the completed actions box will not be shown on the home page or on the individual context or project pages. You can still see all your completed items by clicking the 'Done' link in the navigation bar at the top of each page.</li>
<li><strong>refresh:</strong> automatic refresh interval for each of the pages (in minutes)</li>
<li><strong>verbose action descriptor:</strong> when true, show project/context name in action listing; when false show [P]/[C] with tool tips</li>
</ul>
</div>
<div id="input_box" class="container context">
<% form_tag :action => 'update' do %>
<table>
<tr>
<td><label>first name:</label></td>
<td><%= text_field 'user', 'first_name' %></td>
</tr>
<tr>
<td><label>last name:</label></td>
<td><%= text_field 'user', 'last_name' %></td>
</tr>
<%
def table_row(pref_name, nowrap_label = false, &block)
nowrap_attribute = nowrap_label ? ' nowrap="nowrap"' : ''
s = %Q|<tr>\n<td#{nowrap_attribute}><label>#{pref_name.gsub(/_/,' ')}:</label></td>\n<td>\n|
s << yield
s << "\n</td></tr>"
s
end
def row_with_select_field(pref_name, collection = [true,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_text_field('date_format') %>
<%= row_with_text_field('title_date_format') %>
<%= table_row('time_zone', false) { time_zone_select('prefs','time_zone') } %>
<%= row_with_select_field("week_starts", Preference.day_number_to_name_map.invert.sort{|a,b| a[1]<=>b[1]})%>
<%= row_with_select_field("due_style", [['Due in ___ days',0],['Due on _______',1]]) %>
<%= 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 @user.is_admin? %> <%= row_with_text_field('admin_email') %> <% end %>
<%= row_with_text_field('staleness_starts', true) %>
<%= row_with_text_field('show_number_completed') %>
<%= row_with_text_field('refresh') %>
<%= row_with_select_field("verbose_action_descriptors") %>
<tr><td><%= submit_tag "Update" %></td>
<td><%= link_to "Cancel", :action => 'index' %></td>
</tr>
</table>
<% end %>
</div>

View file

@ -1,64 +0,0 @@
<div id="single_box" class="container context prefscontainer">
<h2>Your preferences</h2>
<ul id="prefs">
<li>First name: <span class="highlight"><%= @user.first_name %></span></li>
<li>Last name: <span class="highlight"><%= @user.last_name %></span></li>
<li>Date format: <span class="highlight"><%= @prefs.date_format %></span> Your current date: <%= format_date(user_time) %></li>
<li>Title date format: <span class="highlight"><%= @prefs.title_date_format %></span> Your current title date: <%= user_time.strftime(@prefs.title_date_format) %></li>
<li>Time zone: <span class="highlight"><%= @prefs.tz %></span> Your current time: <%= user_time.strftime('%I:%M %p') %></li>
<li>Week starts on: <span class="highlight"><%= Preference.day_number_to_name_map[@prefs.week_starts] %></span></li>
<li>Show the last <span class="highlight"><%= @prefs.show_number_completed %></span> completed items on the home page</li>
<li>Show completed projects in sidebar: <span class="highlight"><%= @prefs.show_completed_projects_in_sidebar %></span></li>
<li>Show hidden projects in sidebar: <span class="highlight"><%= @prefs.show_hidden_projects_in_sidebar %></span></li>
<li>Show hidden contexts in sidebar: <span class="highlight"><%= @prefs.show_hidden_contexts_in_sidebar %></span></li>
<li>Go to project page on todo complete: <span class="highlight"><%= @prefs.show_project_on_todo_done %></span></li>
<li>Staleness starts after <span class="highlight"><%= @prefs.staleness_starts %></span> days</li>
<li>Due style: <span class="highlight">
<% if @prefs.due_style == "0" %>
Due in ___ days
<% else %>
Due on ________
<% end %>
</span></li>
<% if @user.is_admin? %>
<li>Admin email: <span class="highlight"><%= @prefs.admin_email %></span></li>
<% end %>
<li>Refresh interval (in minutes): <span class="highlight"><%= @prefs.refresh %></span></li>
<li>Verbose action descriptors: <span class="highlight"><%= @prefs.verbose_action_descriptors %></span></li>
</ul>
<div class="actions">
<%= link_to "Edit preferences &raquo;", { :controller => 'preferences', :action => 'edit'}, :class => 'edit_link' %>
</div>
<h2>Your token</h2>
<div id="token_area">
<div class="description">Token (for feeds and API use):</div>
<div id="token><span class="highlight"><%= @user.word %></span></div>
<div class="token_regenerate">
<%= button_to "Generate a new token", refresh_token_user_path(@user),
:confirm => "Are you sure? Generating a new token will replace the existing one and break any external usages of this token." %>
</div>
</div>
<h2>Your authentication</h2>
<div id="authentication_area">
<% if Tracks::Config.auth_schemes.length > 1 %>
<p>Your authentication type is <span class="highlight"><%= @user.auth_type %></span>.
<div class="actions">
<%= link_to "Change your authentication type &raquo;", change_auth_type_user_path(@user), :class => 'edit_link' %>
</div>
<% end %>
<% if @user.auth_type == 'database' %>
<div class="actions">
<%= link_to 'Change your password &raquo;', change_password_user_path(@user) %>
</div>
<% end %>
<% if @user.auth_type == 'open_id' %>
<p>Your Open ID URL is <span class="highlight"><%= @user.open_id_url %></span>.
<div class="actions">
<%= link_to 'Change Your Identity URL &raquo;', change_auth_type_user_path(@user) %></p>
</div>
<% end %>
</div>
</div>

View file

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

View file

@ -1,5 +0,0 @@
<%= hidden_field( "project", "id" ) %>
<label for="project_name">Project name</label><br />
<%= text_field( "project", "name" ) %>
<br />
<br />

View file

@ -1,25 +0,0 @@
<% @not_done = project.not_done_todos -%>
<div id="p<%= project.id %>" class="container project">
<h2>
<% if collapsible %>
<a href="#" class="container_toggle" id="toggle_p<%= project.id %>"><%= image_tag("collapse.png") %></a>
<% end %>
<%= in_place_editor_field :project, :name, {}, { :url => url_for(:controller => 'project', :action => 'update', :id => project.id, :field => 'name', :wants_render => false) } %>
</h2>
<% if @project.description -%>
<div class="project_description"><%= sanitize(@project.description) %></div>
<% end -%>
<% if @project.completed? -%>
<p class="project_completed">Project has been marked as completed</p>
<% elsif @project.completed? -%>
<p class="project_completed">Project has been marked as hidden</p>
<% end -%>
<div class="items toggle_target">
<div id="p<%= project.id %>empty-nd" style="display:<%= @not_done.empty? ? 'block' : 'none'%>;">
<div class="message"><p>Currently there are no incomplete actions in this project</p></div>
</div>
<%= render :partial => "todos/todo", :collection => @not_done, :locals => { :parent_container_type => "project" } %>
</div><!-- [end:items] -->
</div><!-- [end:p<%= project.id %>] -->

View file

@ -1,26 +0,0 @@
<%
@project = project_form
%>
<tr>
<td width="150"><label for="project_name">Name:</label></td>
<td width="300"><%= text_field :project, 'name', :class => 'project-name' %></td>
</tr>
<tr>
<td width="150"><label for="project_description">Description (optional):</label></td>
<td width="300"><%= text_area :project, 'description', "cols" => 30, "rows" => 4, :class => 'project-description' %></td>
</tr>
<tr>
<td width="150"><label for="project_done">Project status:</label></td>
<td width="300">
<% ['active', 'hidden', 'completed'].each do | state | %>
<%= radio_button(:project, 'state', state) %> <%= state.titlecase %>
<% end %>
</td>
</tr>
<tr>
<td width="150"><label for="project[default_context_name]">Default Context</label></td>
<td width="300">
<%= text_field_tag("project[default_context_name]", @project.default_context.name, {:tabindex=>1,:size=> 25}) %>
<%= render :partial => 'default_context_autocomplete' %>
</td>
</tr>

View file

@ -1,54 +0,0 @@
<% project = project_listing
@project_listing_zindex = @project_listing_zindex.nil? ? 200 : @project_listing_zindex - 1
-%>
<div id="<%= dom_id(project, "container") %>" class="list" style="z-index:<%= @project_listing_zindex %>">
<div id="<%= dom_id(project) %>" class="project sortable_row" style="display:''">
<div class="position">
<span class="handle">DRAG</span>
</div>
<div class="data">
<%= link_to_project( project ) %><%= " (" + count_undone_todos_and_notes_phrase(project,"actions") + ")" %>
</div>
<div class="buttons">
<span class="grey"><%= project.current_state.to_s.upcase %></span>
<a class="delete_project_button" href="<%= formatted_project_path(project, :js) %>" title="delete the project '<%= project.name %>'"><%= image_tag( "blank.png", :title => "Delete project", :class=>"delete_item") %></a>
<%= apply_behavior "a.delete_project_button:click", { :prevent_default => true, :external => true} do |page|
page << "if (confirm('Are you sure that you want to ' + this.title + '?')) {"
page << " new Ajax.Request(this.href, {asynchronous:true,"
page << " evalScripts:true, method:'delete'}); };"
end -%>
<a class="edit_project_button" href="#"><%= image_tag( "blank.png", :title => "Edit project", :class=>"edit_item") %></a>
<%= apply_behavior 'a.edit_project_button:click', {:prevent_default => true, :external => true} do |page, element|
element.up('.project').toggle
editform = element.up('.list').down('.edit-form')
editform.toggle
editform.visual_effect(:appear)
editform.down('input').focus
end
-%>
</div>
</div>
<div id="<%= dom_id(project, 'edit') %>" class="edit-form" style="display:none;">
<% form_tag project_path(project), { :id => dom_id(project, 'edit_form'), :class => "inline-form edit-project-form", :method => :put } do -%>
<table style="table-layout: fixed;" width="450">
<%= render :partial => 'project_form', :object => project %>
<tr>
<td width="150">&nbsp; <input type="hidden" name="wants_render" value="true" /></td>
<td width="300"><input type="submit" value="Update" />&nbsp;<a href="#" class="form_reset">Cancel</a></td>
</tr>
</table>
<% end -%>
<%= apply_behavior ".edit-project-form", make_remote_form(:complete => "Effect.Appear($(this).up('.list'));" ), :external => true %>
<%= apply_behavior "a.form_reset:click", :prevent_default => true do |page, element|
element.up('.list').down('.project').toggle
element.up('.edit-form').toggle
element.up('form').reset
end %>
</div>
</div>
<% if controller.action_name == 'create' %>
<script>
new Effect.Appear('<%= dom_id(project) %>');
</script>
<% end %>

View file

@ -1,7 +0,0 @@
<div class="project-state-group" id="list-<%= state %>-projects-container" <%= " style=\"display:none\"" if project_state_group.empty? %>>
<h2><span id="<%= state %>-projects-count" class="badge"><%= project_state_group.length %></span><%= state.titlecase %> Projects</h2>
<div id="list-<%= state %>-projects">
<%= render :partial => 'project_listing', :collection => project_state_group %>
</div>
<%= sortable_element "list-#{state}-projects", get_listing_sortable_options("list-#{state}-projects") %>
</div>

View file

@ -1,15 +0,0 @@
if @saved and @go_to_project
page.redirect_to project_path(@project)
elsif @saved
page.hide 'projects-empty-nd'
page.show 'list-active-projects-container'
page.replace_html "active-projects-count", @active_projects_count
page.insert_html :bottom, "list-active-projects", :partial => 'project_listing', :locals => { :project_listing => @project }
page.sortable "list-active-projects", get_listing_sortable_options('list-active-projects')
page.call "Form.reset", "project-form"
page.call "Form.focusFirstElement", "project-form"
else
page.show 'status'
page.replace_html 'status', "#{error_messages_for('project')}"
end
page.hide "busy"

View file

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

View file

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

View file

@ -1,39 +0,0 @@
<div id="display_box">
<div id="projects-empty-nd" style="display:<%= @no_projects ? 'block' : 'none'%>;">
<div class="message"><p>Currently there are no projects</p></div>
</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'} %>
</div>
<% @project = @new_project -%>
<div id="input_box">
<%= link_to_function("Create a new project &#187;",
"Element.toggle('project_new');Form.focusFirstElement('project-form');",
{:title => "Add a next action", :accesskey => "n"}) %>
<div id="project_new" class="project_new" style="display:none">
<% form_remote_tag :url => projects_path, :method => :post,
:html=> { :id=>'project-form', :name=>'project', :class => 'inline-form' } do -%>
<div id="status"><%= error_messages_for('project') %></div>
<label for="project_name">Name:</label><br />
<%= text_field 'project', 'name', "tabindex" => 1 %><br />
<label for="project_description">Description (optional):</label><br />
<%= text_area 'project', 'description', "cols" => 30, "rows" => 4, "tabindex" => 2 %><br />
<label for="default_context_name">Default Context (optional):</label><br />
<%= text_field_tag("project[default_context_name]", @project.default_context.name, :tabindex => 3) %>
<%= render :partial => 'default_context_autocomplete' %>
<br />
<input type="submit" value="Add Project" tabindex="4" /><br />
<input id="go_to_project" type="checkbox" tabindex="5" name="go_to_project"/><label for="go_to_project"> Take me to the new project page</label><br />
<% end -%>
</div>
</div>

View file

@ -1,6 +0,0 @@
<% @projects.each do |p| -%>
<%= p.name.upcase %>
<%= p.description + "\n" unless p.description.blank? -%>
<%= count_undone_todos_phrase_text(p)%>. Project is <%= p.state %>.
<% end -%>

View file

@ -1,76 +0,0 @@
<div id="display_box">
<div id="project-next-prev">
<%= project_next_prev %>
</div>
<%= render :partial => "projects/project", :locals => { :project => @project, :collapsible => false } %>
<%= render :partial => "todos/deferred", :locals => { :deferred => @deferred, :collapsible => false, :append_descriptor => "in this project" } %>
<%= render :partial => "todos/completed", :locals => { :done => @done, :collapsible => false, :append_descriptor => "in this project" } %>
<div class="container">
<div id="notes">
<div class="add_note_link"><%= link_to_function( "Add a note", "Element.toggle('new-note'); Form.focusFirstElement('form-new-note');") %></div>
<h2>Notes</h2>
<div id="empty-n" style="display:<%= @project.notes.empty? ? 'block' : 'none'%>;">
<%= render :partial => "shared/empty",
:locals => { :message => "Currently there are no notes attached to this project"} %>
</div>
<%= render :partial => "notes/notes_summary", :collection => @project.notes %>
</div>
</div>
<div id="new-note" style="display:none;">
<% form_remote_tag :url => notes_path,
:method => :post,
:update => "notes",
:position => "bottom",
:complete => "new Effect.Highlight('notes');$('empty-n').hide();",
:html => {:id=>'form-new-note', :class => 'inline-form'} do %>
<%= hidden_field( "new_note", "project_id", "value" => "#{@project.id}" ) %>
<%= text_area( "new_note", "body", "cols" => 50, "rows" => 3, "tabindex" => 1 ) %>
<br /><br />
<input type="submit" value="Add note" tabindex="2" />
<% end -%>
</div>
<div class="container">
<div id="project_status">
<h2>Status</h2>
<div>
<% ['active', 'hidden', 'completed'].each do | state | %>
<% span_class = @project.current_state.to_s == state ? 'active_state' : 'inactive_state' %>
<span class="<%= state %>"><%= radio_button(:project, 'state', state) %> <span class="<%= span_class %>"><%= state.titlecase %></span></span>
<% end %>
<% apply_behavior "#project_status input:click",
remote_function(:url => project_path(@project), :method => :put,
:with => "{wants_render: false, update_status: true, 'project[state]' : this.value}" )
%>
</div>
</div>
</div>
<div class="container">
<div id="default_context">
<h2>Default Context</h2>
<div>
<% form_remote_tag( :url => project_path(@project), :method => :put,
:html=> { :id => 'set-default-context-action',
:name => 'default_context',
:class => 'inline-form' }) do -%>
<%= hidden_field_tag("update_default_context", true) %>
<%= text_field_tag("project[default_context_name]",
@project.default_context.name,
{ :tabindex => 9,:size => 25 }) %>
<%= submit_tag "Set Default Context for this Project", { :tabindex => 10 } %>
<%= render :partial => 'default_context_autocomplete' %>
<% end -%>
</div>
</div>
</div>
</div><!-- [end:display_box] -->
<div id="input_box">
<%= render :partial => "shared/add_new_item_form" %>
<%= render "sidebar/sidebar" %>
</div><!-- End of input box -->

View file

@ -1,18 +0,0 @@
status_message = 'Project saved'
page.notify :notice, status_message, 5.0
if @state_changed
page[dom_id(@project, 'container')].remove
page.insert_html :bottom, "list-#{@project.state}-projects", :partial => 'project_listing', :object => @project
else
page.replace_html dom_id(@project, 'container'), :partial => 'project_listing', :object => @project
end
page.sortable "list-#{@project.state}-projects", get_listing_sortable_options("list-#{@project.state}-projects")
page.replace_html "active-projects-count", @active_projects_count
page.replace_html "hidden-projects-count", @hidden_projects_count
page.replace_html "completed-projects-count", @completed_projects_count
page.set_element_visible ("list-hidden-projects-container", @hidden_projects_count > 0)
page.set_element_visible ("list-active-projects-container", @active_projects_count > 0)
page.set_element_visible ("list-completed-projects-container", @completed_projects_count > 0)
page.hide "busy"

View file

@ -1,10 +0,0 @@
if @project.default_context.nil?
page.notify :notice, "Removed default context", 5.0
else
if source_view_is :project
page['todo_context_name'].value = @project.default_context.name
end
page.notify :notice, "Set project's default context to #{@project.default_context.name}", 5.0
end
page.hide "busy"

View file

@ -1,11 +0,0 @@
page.select('#project_status .active span').each do |element|
element.className = @project.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'
end
page.select('#project_status .completed span').each do |element|
element.className = @project.current_state == :completed ? 'active_state' : 'inactive_state'
end
page.notify :notice, "Set project status to #{@project.current_state}", 5.0
page.hide 'busy'

View file

@ -1,74 +0,0 @@
<%
@todo = nil
@initial_context_name = @context.name unless @context.nil?
@initial_context_name ||= @project.default_context.name unless @project.nil? || @project.default_context.nil?
@initial_context_name ||= @contexts[0].name unless @contexts[0].nil?
@initial_project_name = @project.name unless @project.nil?
%>
<%= link_to_function("Add a next action &#187;",
"Element.toggle('todo_new_action');Form.focusFirstElement('todo-form-new-action');",
{:title => "Add a next action", :accesskey => "n"}) %>
<div id="todo_new_action" class="context_new" style="display:block">
<!--[form:todo]-->
<% form_remote_tag(
:url => todos_path, :method => :post,
:html=> { :id=>'todo-form-new-action', :name=>'todo', :class => 'inline-form' }) do -%>
<div id="status"><%= error_messages_for("item") %></div>
<label for="todo_description">Description</label>
<%= text_field( "todo", "description", "size" => 25, "tabindex" => 1) %>
<label for="todo_notes">Notes</label>
<%= text_area( "todo", "notes", "cols" => 25, "rows" => 6, "tabindex" => 2) %>
<label for="todo_project_name">Project</label>
<input id="todo_project_name" name="project_name" autocomplete="off" tabindex="3" size="25" type="text" value="<%= @initial_project_name %>" />
<div class="page_name_auto_complete" id="project_list" style="display:none"></div>
<script type="text/javascript">
projectAutoCompleter = new Autocompleter.Local('todo_project_name', 'project_list', <%= project_names_for_autocomplete %>, {choices:100,autoSelect:false});
function selectDefaultContext() {
todoContextNameElement = $('todo_context_name');
defaultContextName = todoContextNameElement.projectDefaultContextsMap[this.value];
if (defaultContextName && !todoContextNameElement.editedByTracksUser) {
todoContextNameElement.value = defaultContextName;
}
}
Event.observe($('todo_project_name'), "focus", projectAutoCompleter.activate.bind(projectAutoCompleter));
Event.observe($('todo_project_name'), "click", projectAutoCompleter.activate.bind(projectAutoCompleter));
Event.observe($('todo_project_name'), "blur", selectDefaultContext.bind($('todo_project_name')));
</script>
<label for="todo_context_name">Context</label>
<input id="todo_context_name" name="context_name" autocomplete="off" tabindex="4" size="25" type="text" value="<%= @initial_context_name %>" />
<div class="page_name_auto_complete" id="context_list" style="display:none"></div>
<script type="text/javascript">
contextAutoCompleter = new Autocompleter.Local('todo_context_name', 'context_list', <%= context_names_for_autocomplete %>, {choices:100,autoSelect:false});
$('todo_context_name').projectDefaultContextsMap = <%= @default_project_context_name_map %>;
Event.observe($('todo_context_name'), "focus", function(){ $('todo_context_name').editedByTracksUser = true; });
Event.observe($('todo_context_name'), "focus", contextAutoCompleter.activate.bind(contextAutoCompleter));
Event.observe($('todo_context_name'), "click", contextAutoCompleter.activate.bind(contextAutoCompleter));
</script>
<label for="tag_list">Tags (separate with commas)</label>
<%= text_field_tag "tag_list", nil, :size => 40, :tabindex => 5 %>
<label for="todo_due">Due</label>
<%= text_field("todo", "due", "size" => 10, "class" => "Date", "onfocus" => "Calendar.setup", "tabindex" => 6, "autocomplete" => "off") %>
<label for="todo_show_from">Show from</label>
<%= text_field("todo", "show_from", "size" => 10, "class" => "Date", "onfocus" => "Calendar.setup", "tabindex" => 7, "autocomplete" => "off") %>
<%= source_view_tag( @source_view ) %>
<div class="submit_box"><input type="submit" value="Add item" tabindex="8" /></div>
<% end -%><!--[eoform:todo]-->
<%= calendar_setup( "todo_due" ) %>
<%= calendar_setup( "todo_show_from" ) %>
</div><!-- [end:todo-new-action] -->

View file

@ -1,3 +0,0 @@
<div class="message">
<p><%= message %></p>
</div>

View file

@ -1,11 +0,0 @@
<div id="message_holder">
<% if flash.empty? %>
<h4 id="flash" class="alert" style="display:none"></h4>
<% else %>
<% flash.each do |key,value| -%>
<h4 id="flash" class='alert <%= key %>'>
<%= value %>
</h4>
<% end -%>
<% end %>
</div>

View file

@ -1,3 +0,0 @@
<div id="footer">
<p>Send feedback: <a href="http://dev.rousette.org.uk/report/6">Trac</a> | <a href="http://www.rousette.org.uk/projects/forums/">Forum</a> | <a href="http://www.rousette.org.uk/projects/wiki/index">Wiki</a> | <a href="mailto:butshesagirl@rousette.org.uk?subject=Tracks feedback">Email</a> | <a href="http://www.rousette.org.uk/projects/">Website</a></p>
</div>

View file

@ -1 +0,0 @@
<li><%= link_to_context( context ) + " (" + count_undone_todos_phrase(context,"actions") + ")"%></li>

View file

@ -1,8 +0,0 @@
<h3><%= list_name %> (<%= contexts.length %>)</h3>
<ul>
<% if contexts.empty? -%>
<li>None</li>
<% else -%>
<%= render :partial => "sidebar/context", :collection => contexts -%>
<% end -%>
</ul>

View file

@ -1 +0,0 @@
<li><%= link_to_project( project ) + " (" + count_undone_todos_phrase(project,"actions") + ")" %></li>

View file

@ -1,8 +0,0 @@
<h3><%= list_name %> (<%= projects.length %>)</h3>
<ul>
<% if projects.empty? %>
<li>None</li>
<% else %>
<%= render :partial => "sidebar/project", :collection => projects %>
<% end %>
</ul>

View file

@ -1,29 +0,0 @@
<div id="sidebar">
<%= render :partial => "sidebar/project_list",
:locals => { :list_name => 'Active Projects',
:projects => @projects.select{|p| p.active? } } -%>
<% if @user.prefs.show_hidden_projects_in_sidebar -%>
<%= render :partial => "sidebar/project_list",
:locals => { :list_name => 'Hidden Projects',
:projects => @projects.select{|p| p.hidden? } } -%>
<% end -%>
<% if @user.prefs.show_completed_projects_in_sidebar -%>
<%= render :partial => "sidebar/project_list",
:locals => { :list_name => 'Completed Projects',
:projects => @projects.select{|p| p.completed? } } -%>
<% end -%>
<%= render :partial => "sidebar/context_list",
:locals => { :list_name => 'Active Contexts',
:contexts => @contexts.reject{|c| c.hide? } } -%>
<% if @user.prefs.show_hidden_contexts_in_sidebar -%>
<%= render :partial => "sidebar/context_list",
:locals => { :list_name => 'Hidden Contexts',
:contexts => @contexts.select{|c| c.hide? } } -%>
<% end -%>
</div>

View file

@ -1,17 +0,0 @@
<% suffix = append_descriptor ? append_descriptor : '' -%>
<div class="container completed" id="completed_container">
<h2>
<% if collapsible %>
<a href="#" class="container_toggle" id="toggle_completed"><%= image_tag("collapse.png") %></a>
<% end %>
Completed actions <%= append_descriptor ? append_descriptor : '' %>
</h2>
<div id="completed" class="items toggle_target">
<div id="empty-d" style="display:<%= @done.empty? ? 'block' : 'none' %>">
<div class="message"><p>Currently there are no completed actions.</p></div>
</div>
<%= render :partial => "todos/todo", :collection => done, :locals => { :parent_container_type => "completed" } %>
</div>
</div><!-- [end:next_actions] -->

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